From 596fa6e71896e632832804a9648aa123af4afef9 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 9 Jun 2022 12:31:13 +0200 Subject: media: rockchip: rkisp1: Set DPCC methods enable bits inside loop The rkisp1_dpcc_config() function looks over methods sets to configure them, but sets the RKISP1_CIF_ISP_DPCC_METHODS_SET_* registers outside of the loop with hand-unrolled code. Move this to the loop to simplify the code. Signed-off-by: Laurent Pinchart Reviewed-by: Paul Elder Reviewed-by: Dafna Hirschfeld Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rockchip/rkisp1/rkisp1-params.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c index 9da7dc1bc690..ee91cb36c44b 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c @@ -18,6 +18,8 @@ #define RKISP1_ISP_PARAMS_REQ_BUFS_MIN 2 #define RKISP1_ISP_PARAMS_REQ_BUFS_MAX 8 +#define RKISP1_ISP_DPCC_METHODS_SET(n) \ + (RKISP1_CIF_ISP_DPCC_METHODS_SET_1 + 0x4 * (n)) #define RKISP1_ISP_DPCC_LINE_THRESH(n) \ (RKISP1_CIF_ISP_DPCC_LINE_THRESH_1 + 0x14 * (n)) #define RKISP1_ISP_DPCC_LINE_MAD_FAC(n) \ @@ -66,13 +68,9 @@ static void rkisp1_dpcc_config(struct rkisp1_params *params, rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPCC_SET_USE, arg->set_use); - rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPCC_METHODS_SET_1, - arg->methods[0].method); - rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPCC_METHODS_SET_2, - arg->methods[1].method); - rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPCC_METHODS_SET_3, - arg->methods[2].method); for (i = 0; i < RKISP1_CIF_ISP_DPCC_METHODS_MAX; i++) { + rkisp1_write(params->rkisp1, RKISP1_ISP_DPCC_METHODS_SET(i), + arg->methods[i].method); rkisp1_write(params->rkisp1, RKISP1_ISP_DPCC_LINE_THRESH(i), arg->methods[i].line_thresh); rkisp1_write(params->rkisp1, RKISP1_ISP_DPCC_LINE_MAD_FAC(i), -- cgit From 9daa2b843f046de6d7113890838155f02c2e60a5 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 9 Jun 2022 12:31:13 +0200 Subject: media: rockchip: rkisp1: Mask invalid bits in DPCC parameters Restrict the DPCC configuration that can be set by userspace to valid register bits. To do so, reorganize the related register macros to define valid bitmasks, as well as bits of the DPCC mode register. Signed-off-by: Laurent Pinchart Reviewed-by: Paul Elder Reviewed-by: Dafna Hirschfeld Signed-off-by: Mauro Carvalho Chehab --- .../media/platform/rockchip/rkisp1/rkisp1-params.c | 44 ++++++++++++++-------- .../media/platform/rockchip/rkisp1/rkisp1-regs.h | 26 ++++++------- 2 files changed, 41 insertions(+), 29 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c index ee91cb36c44b..8b4eea77af0d 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c @@ -58,35 +58,47 @@ static void rkisp1_dpcc_config(struct rkisp1_params *params, unsigned int i; u32 mode; - /* avoid to override the old enable value */ + /* + * The enable bit is controlled in rkisp1_isp_isr_other_config() and + * must be preserved. The grayscale mode should be configured + * automatically based on the media bus code on the ISP sink pad, so + * only the STAGE1_ENABLE bit can be set by userspace. + */ mode = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_DPCC_MODE); - mode &= RKISP1_CIF_ISP_DPCC_ENA; - mode |= arg->mode & ~RKISP1_CIF_ISP_DPCC_ENA; + mode &= RKISP1_CIF_ISP_DPCC_MODE_DPCC_ENABLE; + mode |= arg->mode & RKISP1_CIF_ISP_DPCC_MODE_STAGE1_ENABLE; rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPCC_MODE, mode); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPCC_OUTPUT_MODE, - arg->output_mode); + arg->output_mode & RKISP1_CIF_ISP_DPCC_OUTPUT_MODE_MASK); rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPCC_SET_USE, - arg->set_use); + arg->set_use & RKISP1_CIF_ISP_DPCC_SET_USE_MASK); for (i = 0; i < RKISP1_CIF_ISP_DPCC_METHODS_MAX; i++) { rkisp1_write(params->rkisp1, RKISP1_ISP_DPCC_METHODS_SET(i), - arg->methods[i].method); + arg->methods[i].method & + RKISP1_CIF_ISP_DPCC_METHODS_SET_MASK); rkisp1_write(params->rkisp1, RKISP1_ISP_DPCC_LINE_THRESH(i), - arg->methods[i].line_thresh); + arg->methods[i].line_thresh & + RKISP1_CIF_ISP_DPCC_LINE_THRESH_MASK); rkisp1_write(params->rkisp1, RKISP1_ISP_DPCC_LINE_MAD_FAC(i), - arg->methods[i].line_mad_fac); + arg->methods[i].line_mad_fac & + RKISP1_CIF_ISP_DPCC_LINE_MAD_FAC_MASK); rkisp1_write(params->rkisp1, RKISP1_ISP_DPCC_PG_FAC(i), - arg->methods[i].pg_fac); + arg->methods[i].pg_fac & + RKISP1_CIF_ISP_DPCC_PG_FAC_MASK); rkisp1_write(params->rkisp1, RKISP1_ISP_DPCC_RND_THRESH(i), - arg->methods[i].rnd_thresh); + arg->methods[i].rnd_thresh & + RKISP1_CIF_ISP_DPCC_RND_THRESH_MASK); rkisp1_write(params->rkisp1, RKISP1_ISP_DPCC_RG_FAC(i), - arg->methods[i].rg_fac); + arg->methods[i].rg_fac & + RKISP1_CIF_ISP_DPCC_RG_FAC_MASK); } rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPCC_RND_OFFS, - arg->rnd_offs); + arg->rnd_offs & RKISP1_CIF_ISP_DPCC_RND_OFFS_MASK); rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPCC_RO_LIMITS, - arg->ro_limits); + arg->ro_limits & RKISP1_CIF_ISP_DPCC_RO_LIMIT_MASK); } /* ISP black level subtraction interface function */ @@ -1214,11 +1226,11 @@ rkisp1_isp_isr_other_config(struct rkisp1_params *params, if (module_ens & RKISP1_CIF_ISP_MODULE_DPCC) rkisp1_param_set_bits(params, RKISP1_CIF_ISP_DPCC_MODE, - RKISP1_CIF_ISP_DPCC_ENA); + RKISP1_CIF_ISP_DPCC_MODE_DPCC_ENABLE); else rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_DPCC_MODE, - RKISP1_CIF_ISP_DPCC_ENA); + RKISP1_CIF_ISP_DPCC_MODE_DPCC_ENABLE); } /* update bls config */ @@ -1580,7 +1592,7 @@ void rkisp1_params_configure(struct rkisp1_params *params, void rkisp1_params_disable(struct rkisp1_params *params) { rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_DPCC_MODE, - RKISP1_CIF_ISP_DPCC_ENA); + RKISP1_CIF_ISP_DPCC_MODE_DPCC_ENABLE); rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_LSC_CTRL, RKISP1_CIF_ISP_LSC_CTRL_ENA); rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_BLS_CTRL, diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h index dd3e6c38be67..dc01f968c19d 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h @@ -618,19 +618,19 @@ #define RKISP1_CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA_READ(x) (((x) >> 11) & 1) /* DPCC */ -/* ISP_DPCC_MODE */ -#define RKISP1_CIF_ISP_DPCC_ENA BIT(0) -#define RKISP1_CIF_ISP_DPCC_MODE_MAX 0x07 -#define RKISP1_CIF_ISP_DPCC_OUTPUTMODE_MAX 0x0F -#define RKISP1_CIF_ISP_DPCC_SETUSE_MAX 0x0F -#define RKISP1_CIF_ISP_DPCC_METHODS_SET_RESERVED 0xFFFFE000 -#define RKISP1_CIF_ISP_DPCC_LINE_THRESH_RESERVED 0xFFFF0000 -#define RKISP1_CIF_ISP_DPCC_LINE_MAD_FAC_RESERVED 0xFFFFC0C0 -#define RKISP1_CIF_ISP_DPCC_PG_FAC_RESERVED 0xFFFFC0C0 -#define RKISP1_CIF_ISP_DPCC_RND_THRESH_RESERVED 0xFFFF0000 -#define RKISP1_CIF_ISP_DPCC_RG_FAC_RESERVED 0xFFFFC0C0 -#define RKISP1_CIF_ISP_DPCC_RO_LIMIT_RESERVED 0xFFFFF000 -#define RKISP1_CIF_ISP_DPCC_RND_OFFS_RESERVED 0xFFFFF000 +#define RKISP1_CIF_ISP_DPCC_MODE_DPCC_ENABLE BIT(0) +#define RKISP1_CIF_ISP_DPCC_MODE_GRAYSCALE_MODE BIT(1) +#define RKISP1_CIF_ISP_DPCC_MODE_STAGE1_ENABLE BIT(2) +#define RKISP1_CIF_ISP_DPCC_OUTPUT_MODE_MASK GENMASK(3, 0) +#define RKISP1_CIF_ISP_DPCC_SET_USE_MASK GENMASK(3, 0) +#define RKISP1_CIF_ISP_DPCC_METHODS_SET_MASK 0x00001f1f +#define RKISP1_CIF_ISP_DPCC_LINE_THRESH_MASK 0x0000ffff +#define RKISP1_CIF_ISP_DPCC_LINE_MAD_FAC_MASK 0x00003f3f +#define RKISP1_CIF_ISP_DPCC_PG_FAC_MASK 0x00003f3f +#define RKISP1_CIF_ISP_DPCC_RND_THRESH_MASK 0x0000ffff +#define RKISP1_CIF_ISP_DPCC_RG_FAC_MASK 0x00003f3f +#define RKISP1_CIF_ISP_DPCC_RO_LIMIT_MASK 0x00000fff +#define RKISP1_CIF_ISP_DPCC_RND_OFFS_MASK 0x00000fff /* BLS */ /* ISP_BLS_CTRL */ -- cgit From 8e2b7442d27ca2a56a116d44d597e77ca21dfed3 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 9 Jun 2022 12:31:13 +0200 Subject: media: rockchip: rkisp1: Define macros for DPCC configurations in UAPI Extend the UAPI rkisp1-config.h header with macros for all DPCC configuration fields. While at it, clarify of fix issues in the DPCC documentation. Signed-off-by: Laurent Pinchart Reviewed-by: Paul Elder Reviewed-by: Dafna Hirschfeld Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h index dc01f968c19d..a931f7216e9b 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h @@ -620,7 +620,6 @@ /* DPCC */ #define RKISP1_CIF_ISP_DPCC_MODE_DPCC_ENABLE BIT(0) #define RKISP1_CIF_ISP_DPCC_MODE_GRAYSCALE_MODE BIT(1) -#define RKISP1_CIF_ISP_DPCC_MODE_STAGE1_ENABLE BIT(2) #define RKISP1_CIF_ISP_DPCC_OUTPUT_MODE_MASK GENMASK(3, 0) #define RKISP1_CIF_ISP_DPCC_SET_USE_MASK GENMASK(3, 0) #define RKISP1_CIF_ISP_DPCC_METHODS_SET_MASK 0x00001f1f -- cgit From 87bfaa1a167be995d6dfacde08adb7e32f06d558 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 13 Aug 2022 00:44:14 +0200 Subject: media: rkisp1: Initialize color space on ISP sink and source pads Initialize the four color space fields on the sink and source video pads of the ISP in the .init_cfg() operation. As the main use case for the ISP is to convert Bayer data to YUV, select a raw color space on the sink pad and a limited range quantization of SYCC on the source pad by default. Signed-off-by: Laurent Pinchart Reviewed-by: Dafna Hirschfeld Reviewed-by: Paul Elder Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c index 383a3ec83ca9..9fcf272734ee 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c @@ -431,12 +431,17 @@ static int rkisp1_isp_init_config(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *sink_fmt, *src_fmt; struct v4l2_rect *sink_crop, *src_crop; + /* Video. */ sink_fmt = v4l2_subdev_get_try_format(sd, sd_state, RKISP1_ISP_PAD_SINK_VIDEO); sink_fmt->width = RKISP1_DEFAULT_WIDTH; sink_fmt->height = RKISP1_DEFAULT_HEIGHT; sink_fmt->field = V4L2_FIELD_NONE; sink_fmt->code = RKISP1_DEF_SINK_PAD_FMT; + sink_fmt->colorspace = V4L2_COLORSPACE_RAW; + sink_fmt->xfer_func = V4L2_XFER_FUNC_NONE; + sink_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; + sink_fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; sink_crop = v4l2_subdev_get_try_crop(sd, sd_state, RKISP1_ISP_PAD_SINK_VIDEO); @@ -449,11 +454,16 @@ static int rkisp1_isp_init_config(struct v4l2_subdev *sd, RKISP1_ISP_PAD_SOURCE_VIDEO); *src_fmt = *sink_fmt; src_fmt->code = RKISP1_DEF_SRC_PAD_FMT; + src_fmt->colorspace = V4L2_COLORSPACE_SRGB; + src_fmt->xfer_func = V4L2_XFER_FUNC_SRGB; + src_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; + src_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE; src_crop = v4l2_subdev_get_try_crop(sd, sd_state, RKISP1_ISP_PAD_SOURCE_VIDEO); *src_crop = *sink_crop; + /* Parameters and statistics. */ sink_fmt = v4l2_subdev_get_try_format(sd, sd_state, RKISP1_ISP_PAD_SINK_PARAMS); src_fmt = v4l2_subdev_get_try_format(sd, sd_state, -- cgit From 6844cebbf60ac61296a96f1bf57966f98d8d2d6a Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 13 Aug 2022 00:44:14 +0200 Subject: media: rkisp1: Allow setting color space on ISP sink pad The ISP accepts different color spaces on its input: for YUV input, it doesn't set any restrictions, and for Bayer inputs, any color primaries or transfer function can be accepted (YCbCr encoding isn't applicable there, and quantization range can only be full). Allow setting a color space on the ISP sink pad, with the aforementioned restrictions. The settings don't influence hardware yet (only the YUV quantization range will, anything else has no direct effect on the ISP configuration), but can already be set to allow color space information to be coherent across the ISP sink link. Signed-off-by: Laurent Pinchart Reviewed-by: Paul Elder Reviewed-by: Dafna Hirschfeld Signed-off-by: Mauro Carvalho Chehab --- .../media/platform/rockchip/rkisp1/rkisp1-isp.c | 31 ++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c index 9fcf272734ee..d3e13abcddb1 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c @@ -583,6 +583,7 @@ static void rkisp1_isp_set_sink_fmt(struct rkisp1_isp *isp, const struct rkisp1_mbus_info *mbus_info; struct v4l2_mbus_framefmt *sink_fmt; struct v4l2_rect *sink_crop; + bool is_yuv; sink_fmt = rkisp1_isp_get_pad_fmt(isp, sd_state, RKISP1_ISP_PAD_SINK_VIDEO, @@ -603,6 +604,36 @@ static void rkisp1_isp_set_sink_fmt(struct rkisp1_isp *isp, RKISP1_ISP_MIN_HEIGHT, RKISP1_ISP_MAX_HEIGHT); + /* + * Adjust the color space fields. Accept any color primaries and + * transfer function for both YUV and Bayer. For YUV any YCbCr encoding + * and quantization range is also accepted. For Bayer formats, the YCbCr + * encoding isn't applicable, and the quantization range can only be + * full. + */ + is_yuv = mbus_info->pixel_enc == V4L2_PIXEL_ENC_YUV; + + sink_fmt->colorspace = format->colorspace ? : + (is_yuv ? V4L2_COLORSPACE_SRGB : + V4L2_COLORSPACE_RAW); + sink_fmt->xfer_func = format->xfer_func ? : + V4L2_MAP_XFER_FUNC_DEFAULT(sink_fmt->colorspace); + if (is_yuv) { + sink_fmt->ycbcr_enc = format->ycbcr_enc ? : + V4L2_MAP_YCBCR_ENC_DEFAULT(sink_fmt->colorspace); + sink_fmt->quantization = format->quantization ? : + V4L2_MAP_QUANTIZATION_DEFAULT(false, sink_fmt->colorspace, + sink_fmt->ycbcr_enc); + } else { + /* + * The YCbCr encoding isn't applicable for non-YUV formats, but + * V4L2 has no "no encoding" value. Hardcode it to Rec. 601, it + * should be ignored by userspace. + */ + sink_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; + sink_fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; + } + *format = *sink_fmt; /* Propagate to in crop */ -- cgit From cb00f3a4421d5c7d7155bd4bded7fb2ff8eec211 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 13 Aug 2022 00:44:14 +0200 Subject: media: rkisp1: Fix source pad format configuration The ISP converts Bayer data to YUV when operating normally, and can also operate in pass-through mode where the input and output formats must match. Converting from YUV to Bayer isn't possible. If such an invalid configuration is attempted, adjust it by copying the sink pad media bus code to the source pad. Signed-off-by: Laurent Pinchart Reviewed-by: Dafna Hirschfeld Reviewed-by: Paul Elder Signed-off-by: Mauro Carvalho Chehab --- .../media/platform/rockchip/rkisp1/rkisp1-isp.c | 40 +++++++++++++++++----- 1 file changed, 32 insertions(+), 8 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c index d3e13abcddb1..e6359f9b5b26 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c @@ -482,23 +482,43 @@ static void rkisp1_isp_set_src_fmt(struct rkisp1_isp *isp, struct v4l2_mbus_framefmt *format, unsigned int which) { - const struct rkisp1_mbus_info *mbus_info; + const struct rkisp1_mbus_info *sink_info; + const struct rkisp1_mbus_info *src_info; + struct v4l2_mbus_framefmt *sink_fmt; struct v4l2_mbus_framefmt *src_fmt; const struct v4l2_rect *src_crop; + sink_fmt = rkisp1_isp_get_pad_fmt(isp, sd_state, + RKISP1_ISP_PAD_SINK_VIDEO, which); src_fmt = rkisp1_isp_get_pad_fmt(isp, sd_state, RKISP1_ISP_PAD_SOURCE_VIDEO, which); src_crop = rkisp1_isp_get_pad_crop(isp, sd_state, RKISP1_ISP_PAD_SOURCE_VIDEO, which); + /* + * Media bus code. The ISP can operate in pass-through mode (Bayer in, + * Bayer out or YUV in, YUV out) or process Bayer data to YUV, but + * can't convert from YUV to Bayer. + */ + sink_info = rkisp1_mbus_info_get_by_code(sink_fmt->code); + src_fmt->code = format->code; - mbus_info = rkisp1_mbus_info_get_by_code(src_fmt->code); - if (!mbus_info || !(mbus_info->direction & RKISP1_ISP_SD_SRC)) { + src_info = rkisp1_mbus_info_get_by_code(src_fmt->code); + if (!src_info || !(src_info->direction & RKISP1_ISP_SD_SRC)) { src_fmt->code = RKISP1_DEF_SRC_PAD_FMT; - mbus_info = rkisp1_mbus_info_get_by_code(src_fmt->code); + src_info = rkisp1_mbus_info_get_by_code(src_fmt->code); } - if (which == V4L2_SUBDEV_FORMAT_ACTIVE) - isp->src_fmt = mbus_info; + + if (sink_info->pixel_enc == V4L2_PIXEL_ENC_YUV && + src_info->pixel_enc == V4L2_PIXEL_ENC_BAYER) { + src_fmt->code = sink_fmt->code; + src_info = sink_info; + } + + /* + * The source width and height must be identical to the source crop + * size. + */ src_fmt->width = src_crop->width; src_fmt->height = src_crop->height; @@ -508,14 +528,18 @@ static void rkisp1_isp_set_src_fmt(struct rkisp1_isp *isp, */ if (format->flags & V4L2_MBUS_FRAMEFMT_SET_CSC && format->quantization == V4L2_QUANTIZATION_FULL_RANGE && - mbus_info->pixel_enc == V4L2_PIXEL_ENC_YUV) + src_info->pixel_enc == V4L2_PIXEL_ENC_YUV) src_fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; - else if (mbus_info->pixel_enc == V4L2_PIXEL_ENC_YUV) + else if (src_info->pixel_enc == V4L2_PIXEL_ENC_YUV) src_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE; else src_fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; *format = *src_fmt; + + /* Store the source format info when setting the active format. */ + if (which == V4L2_SUBDEV_FORMAT_ACTIVE) + isp->src_fmt = src_info; } static void rkisp1_isp_set_src_crop(struct rkisp1_isp *isp, -- cgit From c1ec5efba08079820b0bfc5149891f364934440d Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 13 Aug 2022 00:56:22 +0200 Subject: media: rkisp1: Allow setting all color space fields on ISP source pad The ISP output color space is configured through the ISP source pad. At the moment, only the quantization can be set. Extend it to the three other color space fields: - The ycbcr_enc field will be used to configure the RGB to YUV matrix (currently hardcoded to Rec. 601). - The colorspace (which controls the color primaries) and xfer_func fields will not be used to configure the ISP, as the corresponding hardware blocks (the cross-talk RGB to RGB matrix and the tone mapping curve) are programmed directly by applications through ISP parameters. Nonetheless, those two fields should be set by applications to match the ISP configuration, in order to propagate the correct color space down the pipeline up to the capture video nodes. Signed-off-by: Laurent Pinchart Reviewed-by: Paul Elder Reviewed-by: Dafna Hirschfeld Signed-off-by: Mauro Carvalho Chehab --- .../media/platform/rockchip/rkisp1/rkisp1-isp.c | 55 +++++++++++++++++++--- 1 file changed, 48 insertions(+), 7 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c index e6359f9b5b26..1798ef852950 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c @@ -487,6 +487,7 @@ static void rkisp1_isp_set_src_fmt(struct rkisp1_isp *isp, struct v4l2_mbus_framefmt *sink_fmt; struct v4l2_mbus_framefmt *src_fmt; const struct v4l2_rect *src_crop; + bool set_csc; sink_fmt = rkisp1_isp_get_pad_fmt(isp, sd_state, RKISP1_ISP_PAD_SINK_VIDEO, which); @@ -523,20 +524,60 @@ static void rkisp1_isp_set_src_fmt(struct rkisp1_isp *isp, src_fmt->height = src_crop->height; /* - * The CSC API is used to allow userspace to force full - * quantization on YUV formats. + * Copy the color space for the sink pad. When converting from Bayer to + * YUV, default to a limited quantization range. */ - if (format->flags & V4L2_MBUS_FRAMEFMT_SET_CSC && - format->quantization == V4L2_QUANTIZATION_FULL_RANGE && + src_fmt->colorspace = sink_fmt->colorspace; + src_fmt->xfer_func = sink_fmt->xfer_func; + src_fmt->ycbcr_enc = sink_fmt->ycbcr_enc; + + if (sink_info->pixel_enc == V4L2_PIXEL_ENC_BAYER && src_info->pixel_enc == V4L2_PIXEL_ENC_YUV) - src_fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; - else if (src_info->pixel_enc == V4L2_PIXEL_ENC_YUV) src_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE; else - src_fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; + src_fmt->quantization = sink_fmt->quantization; + + /* + * Allow setting the source color space fields when the SET_CSC flag is + * set and the source format is YUV. If the sink format is YUV, don't + * set the color primaries, transfer function or YCbCr encoding as the + * ISP is bypassed in that case and passes YUV data through without + * modifications. + * + * The color primaries and transfer function are configured through the + * cross-talk matrix and tone curve respectively. Settings for those + * hardware blocks are conveyed through the ISP parameters buffer, as + * they need to combine color space information with other image tuning + * characteristics and can't thus be computed by the kernel based on the + * color space. The source pad colorspace and xfer_func fields are thus + * ignored by the driver, but can be set by userspace to propagate + * accurate color space information down the pipeline. + */ + set_csc = format->flags & V4L2_MBUS_FRAMEFMT_SET_CSC; + + if (set_csc && src_info->pixel_enc == V4L2_PIXEL_ENC_YUV) { + if (sink_info->pixel_enc == V4L2_PIXEL_ENC_BAYER) { + if (format->colorspace != V4L2_COLORSPACE_DEFAULT) + src_fmt->colorspace = format->colorspace; + if (format->xfer_func != V4L2_XFER_FUNC_DEFAULT) + src_fmt->xfer_func = format->xfer_func; + if (format->ycbcr_enc != V4L2_YCBCR_ENC_DEFAULT) + src_fmt->ycbcr_enc = format->ycbcr_enc; + } + + if (format->quantization != V4L2_QUANTIZATION_DEFAULT) + src_fmt->quantization = format->quantization; + } *format = *src_fmt; + /* + * Restore the SET_CSC flag if it was set to indicate support for the + * CSC setting API. + */ + if (set_csc) + format->flags |= V4L2_MBUS_FRAMEFMT_SET_CSC; + /* Store the source format info when setting the active format. */ if (which == V4L2_SUBDEV_FORMAT_ACTIVE) isp->src_fmt = src_info; -- cgit From 81303962da12a1dbb7f81779c2847d055779c46b Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 13 Aug 2022 00:44:14 +0200 Subject: media: rkisp1: Configure quantization using ISP source pad The rkisp1_config_isp() function uses the format on the sink pad of the ISP to configure quantization at the output of the ISP. This is incorrect, as hinted by the src_frm variable name that stores the format. Fix it by using the source pad. Signed-off-by: Laurent Pinchart Reviewed-by: Dafna Hirschfeld Reviewed-by: Paul Elder Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c index 1798ef852950..51134f642ef9 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c @@ -231,7 +231,7 @@ static int rkisp1_config_isp(struct rkisp1_isp *isp, struct v4l2_mbus_framefmt *src_frm; src_frm = rkisp1_isp_get_pad_fmt(isp, NULL, - RKISP1_ISP_PAD_SINK_VIDEO, + RKISP1_ISP_PAD_SOURCE_VIDEO, V4L2_SUBDEV_FORMAT_ACTIVE); rkisp1_params_configure(&rkisp1->params, sink_fmt->bayer_pat, src_frm->quantization); -- cgit From 711d91497e203b058cf0a08c0f7d41c04efbde76 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 13 Aug 2022 00:44:14 +0200 Subject: media: rkisp1: Don't pass the quantization to rkisp1_csm_config() The rkisp1_csm_config() function takes a pointer to the rkisp1_params structure which contains the quantization value. There's no need to pass it separately to the function. Drop it from the function parameters. Signed-off-by: Laurent Pinchart Reviewed-by: Dafna Hirschfeld Reviewed-by: Paul Elder Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rockchip/rkisp1/rkisp1-params.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c index 8b4eea77af0d..163419624370 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c @@ -1076,7 +1076,7 @@ static void rkisp1_ie_enable(struct rkisp1_params *params, bool en) } } -static void rkisp1_csm_config(struct rkisp1_params *params, bool full_range) +static void rkisp1_csm_config(struct rkisp1_params *params) { static const u16 full_range_coeff[] = { 0x0026, 0x004b, 0x000f, @@ -1090,7 +1090,7 @@ static void rkisp1_csm_config(struct rkisp1_params *params, bool full_range) }; unsigned int i; - if (full_range) { + if (params->quantization == V4L2_QUANTIZATION_FULL_RANGE) { for (i = 0; i < ARRAY_SIZE(full_range_coeff); i++) rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CC_COEFF_0 + i * 4, @@ -1562,11 +1562,7 @@ static void rkisp1_params_config_parameter(struct rkisp1_params *params) rkisp1_param_set_bits(params, RKISP1_CIF_ISP_HIST_PROP_V10, rkisp1_hst_params_default_config.mode); - /* set the range */ - if (params->quantization == V4L2_QUANTIZATION_FULL_RANGE) - rkisp1_csm_config(params, true); - else - rkisp1_csm_config(params, false); + rkisp1_csm_config(params); spin_lock_irq(¶ms->config_lock); -- cgit From f7aa2d234377c8e69bfcc52d7384b784ab513460 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 13 Aug 2022 00:44:14 +0200 Subject: media: rkisp1: Configure CSM based on YCbCr encoding The driver currently only implements the Rec. 601 YCbCr encoding, extend it with support for the other encodings defined by V4L2 (Rec. 709, Rec. 2020 and SMPTE240m). The coefficients have been calculated by rounding the floating point values to the nearest Q1.7 fixed-point value, adjusting the rounding to ensure that the sum of each line in the matrix is preserved to avoid overflows. At the hardware level, the RGB to YUV conversion matrix is fully configurable, custom encoding could be supported by extending the ISP parameters if desired. Signed-off-by: Laurent Pinchart Reviewed-by: Dafna Hirschfeld Reviewed-by: Paul Elder Signed-off-by: Mauro Carvalho Chehab --- .../media/platform/rockchip/rkisp1/rkisp1-common.h | 5 +- .../media/platform/rockchip/rkisp1/rkisp1-isp.c | 3 +- .../media/platform/rockchip/rkisp1/rkisp1-params.c | 97 +++++++++++++++++----- 3 files changed, 84 insertions(+), 21 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h index 8056997d5c29..b704e955cb28 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h @@ -378,6 +378,7 @@ struct rkisp1_params { struct v4l2_format vdev_fmt; enum v4l2_quantization quantization; + enum v4l2_ycbcr_encoding ycbcr_encoding; enum rkisp1_fmt_raw_pat_type raw_type; }; @@ -563,10 +564,12 @@ const struct rkisp1_mbus_info *rkisp1_mbus_info_get_by_code(u32 mbus_code); * @params: pointer to rkisp1_params. * @bayer_pat: the bayer pattern on the isp video sink pad * @quantization: the quantization configured on the isp's src pad + * @ycbcr_encoding: the ycbcr_encoding configured on the isp's src pad */ void rkisp1_params_configure(struct rkisp1_params *params, enum rkisp1_fmt_raw_pat_type bayer_pat, - enum v4l2_quantization quantization); + enum v4l2_quantization quantization, + enum v4l2_ycbcr_encoding ycbcr_encoding); /* rkisp1_params_disable - disable all parameters. * This function is called by the isp entity upon stream start diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c index 51134f642ef9..f19c0718963f 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c @@ -234,7 +234,8 @@ static int rkisp1_config_isp(struct rkisp1_isp *isp, RKISP1_ISP_PAD_SOURCE_VIDEO, V4L2_SUBDEV_FORMAT_ACTIVE); rkisp1_params_configure(&rkisp1->params, sink_fmt->bayer_pat, - src_frm->quantization); + src_frm->quantization, + src_frm->ycbcr_enc); } return 0; diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c index 163419624370..246a6faa1fc1 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c @@ -1078,37 +1078,94 @@ static void rkisp1_ie_enable(struct rkisp1_params *params, bool en) static void rkisp1_csm_config(struct rkisp1_params *params) { - static const u16 full_range_coeff[] = { - 0x0026, 0x004b, 0x000f, - 0x01ea, 0x01d6, 0x0040, - 0x0040, 0x01ca, 0x01f6 + struct csm_coeffs { + u16 limited[9]; + u16 full[9]; }; - static const u16 limited_range_coeff[] = { - 0x0021, 0x0040, 0x000d, - 0x01ed, 0x01db, 0x0038, - 0x0038, 0x01d1, 0x01f7, + static const struct csm_coeffs rec601_coeffs = { + .limited = { + 0x0021, 0x0042, 0x000d, + 0x01ed, 0x01db, 0x0038, + 0x0038, 0x01d1, 0x01f7, + }, + .full = { + 0x0026, 0x004b, 0x000f, + 0x01ea, 0x01d6, 0x0040, + 0x0040, 0x01ca, 0x01f6, + }, }; + static const struct csm_coeffs rec709_coeffs = { + .limited = { + 0x0018, 0x0050, 0x0008, + 0x01f3, 0x01d5, 0x0038, + 0x0038, 0x01cd, 0x01fb, + }, + .full = { + 0x001b, 0x005c, 0x0009, + 0x01f1, 0x01cf, 0x0040, + 0x0040, 0x01c6, 0x01fa, + }, + }; + static const struct csm_coeffs rec2020_coeffs = { + .limited = { + 0x001d, 0x004c, 0x0007, + 0x01f0, 0x01d8, 0x0038, + 0x0038, 0x01cd, 0x01fb, + }, + .full = { + 0x0022, 0x0057, 0x0008, + 0x01ee, 0x01d2, 0x0040, + 0x0040, 0x01c5, 0x01fb, + }, + }; + static const struct csm_coeffs smpte240m_coeffs = { + .limited = { + 0x0018, 0x004f, 0x000a, + 0x01f3, 0x01d5, 0x0038, + 0x0038, 0x01ce, 0x01fa, + }, + .full = { + 0x001b, 0x005a, 0x000b, + 0x01f1, 0x01cf, 0x0040, + 0x0040, 0x01c7, 0x01f9, + }, + }; + + const struct csm_coeffs *coeffs; + const u16 *csm; unsigned int i; - if (params->quantization == V4L2_QUANTIZATION_FULL_RANGE) { - for (i = 0; i < ARRAY_SIZE(full_range_coeff); i++) - rkisp1_write(params->rkisp1, - RKISP1_CIF_ISP_CC_COEFF_0 + i * 4, - full_range_coeff[i]); + switch (params->ycbcr_encoding) { + case V4L2_YCBCR_ENC_601: + default: + coeffs = &rec601_coeffs; + break; + case V4L2_YCBCR_ENC_709: + coeffs = &rec709_coeffs; + break; + case V4L2_YCBCR_ENC_BT2020: + coeffs = &rec2020_coeffs; + break; + case V4L2_YCBCR_ENC_SMPTE240M: + coeffs = &smpte240m_coeffs; + break; + } + if (params->quantization == V4L2_QUANTIZATION_FULL_RANGE) { + csm = coeffs->full; rkisp1_param_set_bits(params, RKISP1_CIF_ISP_CTRL, RKISP1_CIF_ISP_CTRL_ISP_CSM_Y_FULL_ENA | RKISP1_CIF_ISP_CTRL_ISP_CSM_C_FULL_ENA); } else { - for (i = 0; i < ARRAY_SIZE(limited_range_coeff); i++) - rkisp1_write(params->rkisp1, - RKISP1_CIF_ISP_CC_COEFF_0 + i * 4, - limited_range_coeff[i]); - + csm = coeffs->limited; rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL, RKISP1_CIF_ISP_CTRL_ISP_CSM_Y_FULL_ENA | RKISP1_CIF_ISP_CTRL_ISP_CSM_C_FULL_ENA); } + + for (i = 0; i < 9; i++) + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CC_COEFF_0 + i * 4, + csm[i]); } /* ISP De-noise Pre-Filter(DPF) function */ @@ -1574,9 +1631,11 @@ static void rkisp1_params_config_parameter(struct rkisp1_params *params) void rkisp1_params_configure(struct rkisp1_params *params, enum rkisp1_fmt_raw_pat_type bayer_pat, - enum v4l2_quantization quantization) + enum v4l2_quantization quantization, + enum v4l2_ycbcr_encoding ycbcr_encoding) { params->quantization = quantization; + params->ycbcr_encoding = ycbcr_encoding; params->raw_type = bayer_pat; rkisp1_params_config_parameter(params); } -- cgit From 83b9296e399367862845d3b19984444fc756bd61 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 13 Aug 2022 00:44:14 +0200 Subject: media: rkisp1: Initialize color space on resizer sink and source pads Initialize the four color space fields on the sink and source video pads of the resizer in the .init_cfg() operation. The resizer can't perform any color space conversion, so set the sink and source color spaces to the same defaults, which match the ISP source video pad default. Signed-off-by: Laurent Pinchart Reviewed-by: Paul Elder Reviewed-by: Dafna Hirschfeld Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c index f4caa8f684aa..a2dc6f60d9cf 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c @@ -411,6 +411,10 @@ static int rkisp1_rsz_init_config(struct v4l2_subdev *sd, sink_fmt->height = RKISP1_DEFAULT_HEIGHT; sink_fmt->field = V4L2_FIELD_NONE; sink_fmt->code = RKISP1_DEF_FMT; + sink_fmt->colorspace = V4L2_COLORSPACE_SRGB; + sink_fmt->xfer_func = V4L2_XFER_FUNC_SRGB; + sink_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; + sink_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE; sink_crop = v4l2_subdev_get_try_crop(sd, sd_state, RKISP1_RSZ_PAD_SINK); -- cgit From faab2929515224f32a3cc080e8a6d44ae6e0d4ec Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 13 Aug 2022 00:44:14 +0200 Subject: media: rkisp1: Allow setting color space on resizer sink pad The resizer doesn't deal with color spaces, so it can accept any color space on its input, and propagates it unchanged to its output. When operating with a Bayer input format (in pass-through mode) further restrict the YCbCr encoding and quantization to Rec 601 and full range respectively, as for raw data the former ought to be ignored and the latter is always full range. Signed-off-by: Laurent Pinchart Reviewed-by: Paul Elder Reviewed-by: Dafna Hirschfeld Signed-off-by: Mauro Carvalho Chehab --- .../platform/rockchip/rkisp1/rkisp1-resizer.c | 41 ++++++++++++++++++++-- 1 file changed, 38 insertions(+), 3 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c index a2dc6f60d9cf..f76afd8112b2 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c @@ -507,6 +507,7 @@ static void rkisp1_rsz_set_sink_fmt(struct rkisp1_resizer *rsz, const struct rkisp1_mbus_info *mbus_info; struct v4l2_mbus_framefmt *sink_fmt, *src_fmt; struct v4l2_rect *sink_crop; + bool is_yuv; sink_fmt = rkisp1_rsz_get_pad_fmt(rsz, sd_state, RKISP1_RSZ_PAD_SINK, which); @@ -528,9 +529,6 @@ static void rkisp1_rsz_set_sink_fmt(struct rkisp1_resizer *rsz, if (which == V4L2_SUBDEV_FORMAT_ACTIVE) rsz->pixel_enc = mbus_info->pixel_enc; - /* Propagete to source pad */ - src_fmt->code = sink_fmt->code; - sink_fmt->width = clamp_t(u32, format->width, RKISP1_ISP_MIN_WIDTH, RKISP1_ISP_MAX_WIDTH); @@ -538,8 +536,45 @@ static void rkisp1_rsz_set_sink_fmt(struct rkisp1_resizer *rsz, RKISP1_ISP_MIN_HEIGHT, RKISP1_ISP_MAX_HEIGHT); + /* + * Adjust the color space fields. Accept any color primaries and + * transfer function for both YUV and Bayer. For YUV any YCbCr encoding + * and quantization range is also accepted. For Bayer formats, the YCbCr + * encoding isn't applicable, and the quantization range can only be + * full. + */ + is_yuv = mbus_info->pixel_enc == V4L2_PIXEL_ENC_YUV; + + sink_fmt->colorspace = format->colorspace ? : + (is_yuv ? V4L2_COLORSPACE_SRGB : + V4L2_COLORSPACE_RAW); + sink_fmt->xfer_func = format->xfer_func ? : + V4L2_MAP_XFER_FUNC_DEFAULT(sink_fmt->colorspace); + if (is_yuv) { + sink_fmt->ycbcr_enc = format->ycbcr_enc ? : + V4L2_MAP_YCBCR_ENC_DEFAULT(sink_fmt->colorspace); + sink_fmt->quantization = format->quantization ? : + V4L2_MAP_QUANTIZATION_DEFAULT(false, sink_fmt->colorspace, + sink_fmt->ycbcr_enc); + } else { + /* + * The YCbCr encoding isn't applicable for non-YUV formats, but + * V4L2 has no "no encoding" value. Hardcode it to Rec. 601, it + * should be ignored by userspace. + */ + sink_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; + sink_fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; + } + *format = *sink_fmt; + /* Propagate the media bus code and color space to the source pad. */ + src_fmt->code = sink_fmt->code; + src_fmt->colorspace = sink_fmt->colorspace; + src_fmt->xfer_func = sink_fmt->xfer_func; + src_fmt->ycbcr_enc = sink_fmt->ycbcr_enc; + src_fmt->quantization = sink_fmt->quantization; + /* Update sink crop */ rkisp1_rsz_set_sink_crop(rsz, sd_state, sink_crop, which); } -- cgit From cf655faff5815986bb4393c303590f6f432644bb Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 17 Aug 2022 01:53:57 +0200 Subject: media: rkisp1: Clean up LSC configuration code Clean up the LSC configuration code to improve its readability by shortening lines, using extra local variables and renaming long variables. No functional change intended. Signed-off-by: Laurent Pinchart Reviewed-by: Dafna Hirschfeld Signed-off-by: Mauro Carvalho Chehab --- .../media/platform/rockchip/rkisp1/rkisp1-params.c | 199 +++++++++------------ 1 file changed, 86 insertions(+), 113 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c index 246a6faa1fc1..fbbaf5505291 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c @@ -198,149 +198,129 @@ static void rkisp1_lsc_matrix_config_v10(struct rkisp1_params *params, const struct rkisp1_cif_isp_lsc_config *pconfig) { - unsigned int isp_lsc_status, sram_addr, isp_lsc_table_sel, i, j, data; + struct rkisp1_device *rkisp1 = params->rkisp1; + unsigned int lsc_status, sram_addr, lsc_table_sel, i, j; - isp_lsc_status = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_LSC_STATUS); + lsc_status = rkisp1_read(rkisp1, RKISP1_CIF_ISP_LSC_STATUS); /* RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_153 = ( 17 * 18 ) >> 1 */ - sram_addr = (isp_lsc_status & RKISP1_CIF_ISP_LSC_ACTIVE_TABLE) ? + sram_addr = lsc_status & RKISP1_CIF_ISP_LSC_ACTIVE_TABLE ? RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_0 : RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_153; - rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_R_TABLE_ADDR, sram_addr); - rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_GR_TABLE_ADDR, sram_addr); - rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_GB_TABLE_ADDR, sram_addr); - rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_B_TABLE_ADDR, sram_addr); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_R_TABLE_ADDR, sram_addr); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_GR_TABLE_ADDR, sram_addr); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_GB_TABLE_ADDR, sram_addr); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_B_TABLE_ADDR, sram_addr); /* program data tables (table size is 9 * 17 = 153) */ for (i = 0; i < RKISP1_CIF_ISP_LSC_SAMPLES_MAX; i++) { + const __u16 *r_tbl = pconfig->r_data_tbl[i]; + const __u16 *gr_tbl = pconfig->gr_data_tbl[i]; + const __u16 *gb_tbl = pconfig->gb_data_tbl[i]; + const __u16 *b_tbl = pconfig->b_data_tbl[i]; + /* * 17 sectors with 2 values in one DWORD = 9 * DWORDs (2nd value of last DWORD unused) */ for (j = 0; j < RKISP1_CIF_ISP_LSC_SAMPLES_MAX - 1; j += 2) { - data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->r_data_tbl[i][j], - pconfig->r_data_tbl[i][j + 1]); - rkisp1_write(params->rkisp1, - RKISP1_CIF_ISP_LSC_R_TABLE_DATA, data); - - data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->gr_data_tbl[i][j], - pconfig->gr_data_tbl[i][j + 1]); - rkisp1_write(params->rkisp1, - RKISP1_CIF_ISP_LSC_GR_TABLE_DATA, data); - - data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->gb_data_tbl[i][j], - pconfig->gb_data_tbl[i][j + 1]); - rkisp1_write(params->rkisp1, - RKISP1_CIF_ISP_LSC_GB_TABLE_DATA, data); - - data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->b_data_tbl[i][j], - pconfig->b_data_tbl[i][j + 1]); - rkisp1_write(params->rkisp1, - RKISP1_CIF_ISP_LSC_B_TABLE_DATA, data); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_R_TABLE_DATA, + RKISP1_CIF_ISP_LSC_TABLE_DATA_V10( + r_tbl[j], r_tbl[j + 1])); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_GR_TABLE_DATA, + RKISP1_CIF_ISP_LSC_TABLE_DATA_V10( + gr_tbl[j], gr_tbl[j + 1])); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_GB_TABLE_DATA, + RKISP1_CIF_ISP_LSC_TABLE_DATA_V10( + gb_tbl[j], gb_tbl[j + 1])); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_B_TABLE_DATA, + RKISP1_CIF_ISP_LSC_TABLE_DATA_V10( + b_tbl[j], b_tbl[j + 1])); } - data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->r_data_tbl[i][j], 0); - rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_R_TABLE_DATA, - data); - data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->gr_data_tbl[i][j], 0); - rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_GR_TABLE_DATA, - data); - - data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->gb_data_tbl[i][j], 0); - rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_GB_TABLE_DATA, - data); - - data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->b_data_tbl[i][j], 0); - rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_B_TABLE_DATA, - data); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_R_TABLE_DATA, + RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(r_tbl[j], 0)); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_GR_TABLE_DATA, + RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(gr_tbl[j], 0)); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_GB_TABLE_DATA, + RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(gb_tbl[j], 0)); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_B_TABLE_DATA, + RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(b_tbl[j], 0)); } - isp_lsc_table_sel = (isp_lsc_status & RKISP1_CIF_ISP_LSC_ACTIVE_TABLE) ? - RKISP1_CIF_ISP_LSC_TABLE_0 : - RKISP1_CIF_ISP_LSC_TABLE_1; - rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_TABLE_SEL, - isp_lsc_table_sel); + + lsc_table_sel = lsc_status & RKISP1_CIF_ISP_LSC_ACTIVE_TABLE ? + RKISP1_CIF_ISP_LSC_TABLE_0 : RKISP1_CIF_ISP_LSC_TABLE_1; + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_TABLE_SEL, lsc_table_sel); } static void rkisp1_lsc_matrix_config_v12(struct rkisp1_params *params, const struct rkisp1_cif_isp_lsc_config *pconfig) { - unsigned int isp_lsc_status, sram_addr, isp_lsc_table_sel, i, j, data; + struct rkisp1_device *rkisp1 = params->rkisp1; + unsigned int lsc_status, sram_addr, lsc_table_sel, i, j; - isp_lsc_status = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_LSC_STATUS); + lsc_status = rkisp1_read(rkisp1, RKISP1_CIF_ISP_LSC_STATUS); /* RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_153 = ( 17 * 18 ) >> 1 */ - sram_addr = (isp_lsc_status & RKISP1_CIF_ISP_LSC_ACTIVE_TABLE) ? - RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_0 : - RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_153; - rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_R_TABLE_ADDR, sram_addr); - rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_GR_TABLE_ADDR, sram_addr); - rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_GB_TABLE_ADDR, sram_addr); - rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_B_TABLE_ADDR, sram_addr); + sram_addr = lsc_status & RKISP1_CIF_ISP_LSC_ACTIVE_TABLE ? + RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_0 : + RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_153; + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_R_TABLE_ADDR, sram_addr); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_GR_TABLE_ADDR, sram_addr); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_GB_TABLE_ADDR, sram_addr); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_B_TABLE_ADDR, sram_addr); /* program data tables (table size is 9 * 17 = 153) */ for (i = 0; i < RKISP1_CIF_ISP_LSC_SAMPLES_MAX; i++) { + const __u16 *r_tbl = pconfig->r_data_tbl[i]; + const __u16 *gr_tbl = pconfig->gr_data_tbl[i]; + const __u16 *gb_tbl = pconfig->gb_data_tbl[i]; + const __u16 *b_tbl = pconfig->b_data_tbl[i]; + /* * 17 sectors with 2 values in one DWORD = 9 * DWORDs (2nd value of last DWORD unused) */ for (j = 0; j < RKISP1_CIF_ISP_LSC_SAMPLES_MAX - 1; j += 2) { - data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12( - pconfig->r_data_tbl[i][j], - pconfig->r_data_tbl[i][j + 1]); - rkisp1_write(params->rkisp1, - RKISP1_CIF_ISP_LSC_R_TABLE_DATA, data); - - data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12( - pconfig->gr_data_tbl[i][j], - pconfig->gr_data_tbl[i][j + 1]); - rkisp1_write(params->rkisp1, - RKISP1_CIF_ISP_LSC_GR_TABLE_DATA, data); - - data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12( - pconfig->gb_data_tbl[i][j], - pconfig->gb_data_tbl[i][j + 1]); - rkisp1_write(params->rkisp1, - RKISP1_CIF_ISP_LSC_GB_TABLE_DATA, data); - - data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12( - pconfig->b_data_tbl[i][j], - pconfig->b_data_tbl[i][j + 1]); - rkisp1_write(params->rkisp1, - RKISP1_CIF_ISP_LSC_B_TABLE_DATA, data); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_R_TABLE_DATA, + RKISP1_CIF_ISP_LSC_TABLE_DATA_V12( + r_tbl[j], r_tbl[j + 1])); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_GR_TABLE_DATA, + RKISP1_CIF_ISP_LSC_TABLE_DATA_V12( + gr_tbl[j], gr_tbl[j + 1])); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_GB_TABLE_DATA, + RKISP1_CIF_ISP_LSC_TABLE_DATA_V12( + gb_tbl[j], gb_tbl[j + 1])); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_B_TABLE_DATA, + RKISP1_CIF_ISP_LSC_TABLE_DATA_V12( + b_tbl[j], b_tbl[j + 1])); } - data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12(pconfig->r_data_tbl[i][j], 0); - rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_R_TABLE_DATA, - data); - - data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12(pconfig->gr_data_tbl[i][j], 0); - rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_GR_TABLE_DATA, - data); - - data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12(pconfig->gb_data_tbl[i][j], 0); - rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_GB_TABLE_DATA, - data); - - data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12(pconfig->b_data_tbl[i][j], 0); - rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_B_TABLE_DATA, - data); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_R_TABLE_DATA, + RKISP1_CIF_ISP_LSC_TABLE_DATA_V12(r_tbl[j], 0)); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_GR_TABLE_DATA, + RKISP1_CIF_ISP_LSC_TABLE_DATA_V12(gr_tbl[j], 0)); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_GB_TABLE_DATA, + RKISP1_CIF_ISP_LSC_TABLE_DATA_V12(gb_tbl[j], 0)); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_B_TABLE_DATA, + RKISP1_CIF_ISP_LSC_TABLE_DATA_V12(b_tbl[j], 0)); } - isp_lsc_table_sel = (isp_lsc_status & RKISP1_CIF_ISP_LSC_ACTIVE_TABLE) ? - RKISP1_CIF_ISP_LSC_TABLE_0 : - RKISP1_CIF_ISP_LSC_TABLE_1; - rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_TABLE_SEL, - isp_lsc_table_sel); + + lsc_table_sel = lsc_status & RKISP1_CIF_ISP_LSC_ACTIVE_TABLE ? + RKISP1_CIF_ISP_LSC_TABLE_0 : RKISP1_CIF_ISP_LSC_TABLE_1; + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_TABLE_SEL, lsc_table_sel); } static void rkisp1_lsc_config(struct rkisp1_params *params, const struct rkisp1_cif_isp_lsc_config *arg) { + struct rkisp1_device *rkisp1 = params->rkisp1; unsigned int i, data; u32 lsc_ctrl; /* To config must be off , store the current status firstly */ - lsc_ctrl = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_LSC_CTRL); + lsc_ctrl = rkisp1_read(rkisp1, RKISP1_CIF_ISP_LSC_CTRL); rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_LSC_CTRL, RKISP1_CIF_ISP_LSC_CTRL_ENA); params->ops->lsc_matrix_config(params, arg); @@ -349,38 +329,31 @@ static void rkisp1_lsc_config(struct rkisp1_params *params, /* program x size tables */ data = RKISP1_CIF_ISP_LSC_SECT_SIZE(arg->x_size_tbl[i * 2], arg->x_size_tbl[i * 2 + 1]); - rkisp1_write(params->rkisp1, - RKISP1_CIF_ISP_LSC_XSIZE_01 + i * 4, data); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_XSIZE_01 + i * 4, data); /* program x grad tables */ data = RKISP1_CIF_ISP_LSC_SECT_SIZE(arg->x_grad_tbl[i * 2], arg->x_grad_tbl[i * 2 + 1]); - rkisp1_write(params->rkisp1, - RKISP1_CIF_ISP_LSC_XGRAD_01 + i * 4, data); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_XGRAD_01 + i * 4, data); /* program y size tables */ data = RKISP1_CIF_ISP_LSC_SECT_SIZE(arg->y_size_tbl[i * 2], arg->y_size_tbl[i * 2 + 1]); - rkisp1_write(params->rkisp1, - RKISP1_CIF_ISP_LSC_YSIZE_01 + i * 4, data); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_YSIZE_01 + i * 4, data); /* program y grad tables */ data = RKISP1_CIF_ISP_LSC_SECT_SIZE(arg->y_grad_tbl[i * 2], arg->y_grad_tbl[i * 2 + 1]); - rkisp1_write(params->rkisp1, - RKISP1_CIF_ISP_LSC_YGRAD_01 + i * 4, data); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_YGRAD_01 + i * 4, data); } /* restore the lsc ctrl status */ - if (lsc_ctrl & RKISP1_CIF_ISP_LSC_CTRL_ENA) { - rkisp1_param_set_bits(params, - RKISP1_CIF_ISP_LSC_CTRL, + if (lsc_ctrl & RKISP1_CIF_ISP_LSC_CTRL_ENA) + rkisp1_param_set_bits(params, RKISP1_CIF_ISP_LSC_CTRL, RKISP1_CIF_ISP_LSC_CTRL_ENA); - } else { - rkisp1_param_clear_bits(params, - RKISP1_CIF_ISP_LSC_CTRL, + else + rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_LSC_CTRL, RKISP1_CIF_ISP_LSC_CTRL_ENA); - } } /* ISP Filtering function */ -- cgit From da57dffa098c8d8e46cda4c891e106bdc849712d Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 17 Aug 2022 01:53:57 +0200 Subject: media: rkisp1: Store LSC register values in u32 variables Use the u32 type instead of unsigned int to store register values in the LSC configuration code, to make the variables' size more explicit. No functional change intended. Signed-off-by: Laurent Pinchart Reviewed-by: Dafna Hirschfeld Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rockchip/rkisp1/rkisp1-params.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c index fbbaf5505291..dbe826fd02d2 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c @@ -199,7 +199,8 @@ rkisp1_lsc_matrix_config_v10(struct rkisp1_params *params, const struct rkisp1_cif_isp_lsc_config *pconfig) { struct rkisp1_device *rkisp1 = params->rkisp1; - unsigned int lsc_status, sram_addr, lsc_table_sel, i, j; + u32 lsc_status, sram_addr, lsc_table_sel; + unsigned int i, j; lsc_status = rkisp1_read(rkisp1, RKISP1_CIF_ISP_LSC_STATUS); @@ -258,7 +259,8 @@ rkisp1_lsc_matrix_config_v12(struct rkisp1_params *params, const struct rkisp1_cif_isp_lsc_config *pconfig) { struct rkisp1_device *rkisp1 = params->rkisp1; - unsigned int lsc_status, sram_addr, lsc_table_sel, i, j; + u32 lsc_status, sram_addr, lsc_table_sel; + unsigned int i, j; lsc_status = rkisp1_read(rkisp1, RKISP1_CIF_ISP_LSC_STATUS); @@ -316,8 +318,8 @@ static void rkisp1_lsc_config(struct rkisp1_params *params, const struct rkisp1_cif_isp_lsc_config *arg) { struct rkisp1_device *rkisp1 = params->rkisp1; - unsigned int i, data; - u32 lsc_ctrl; + u32 lsc_ctrl, data; + unsigned int i; /* To config must be off , store the current status firstly */ lsc_ctrl = rkisp1_read(rkisp1, RKISP1_CIF_ISP_LSC_CTRL); -- cgit From 10e36b2191401ffe98373e144580e0a9288e71e9 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 17 Aug 2022 01:53:57 +0200 Subject: media: rkisp1: Simplify LSC x/y size and grad register macros The LSC module x/y size and grad configuration is stored in a set of 4 indexed registers each. The rkisp1-regs.h header defines all those registers, but only the first one in each set is used, with manual calculation of addresses of subsequent registers. Simplifies this by merging all 4 register macros into one that takes the index as a parameter. No functional change intended. Signed-off-by: Laurent Pinchart Reviewed-by: Dafna Hirschfeld Signed-off-by: Mauro Carvalho Chehab --- .../media/platform/rockchip/rkisp1/rkisp1-params.c | 8 ++++---- drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h | 20 ++++---------------- 2 files changed, 8 insertions(+), 20 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c index dbe826fd02d2..aa6efa4c6e9e 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c @@ -331,22 +331,22 @@ static void rkisp1_lsc_config(struct rkisp1_params *params, /* program x size tables */ data = RKISP1_CIF_ISP_LSC_SECT_SIZE(arg->x_size_tbl[i * 2], arg->x_size_tbl[i * 2 + 1]); - rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_XSIZE_01 + i * 4, data); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_XSIZE(i), data); /* program x grad tables */ data = RKISP1_CIF_ISP_LSC_SECT_SIZE(arg->x_grad_tbl[i * 2], arg->x_grad_tbl[i * 2 + 1]); - rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_XGRAD_01 + i * 4, data); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_XGRAD(i), data); /* program y size tables */ data = RKISP1_CIF_ISP_LSC_SECT_SIZE(arg->y_size_tbl[i * 2], arg->y_size_tbl[i * 2 + 1]); - rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_YSIZE_01 + i * 4, data); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_YSIZE(i), data); /* program y grad tables */ data = RKISP1_CIF_ISP_LSC_SECT_SIZE(arg->y_grad_tbl[i * 2], arg->y_grad_tbl[i * 2 + 1]); - rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_YGRAD_01 + i * 4, data); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_YGRAD(i), data); } /* restore the lsc ctrl status */ diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h index a931f7216e9b..b3d8c10163d4 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h @@ -1072,22 +1072,10 @@ #define RKISP1_CIF_ISP_LSC_GR_TABLE_DATA (RKISP1_CIF_ISP_LSC_BASE + 0x00000018) #define RKISP1_CIF_ISP_LSC_B_TABLE_DATA (RKISP1_CIF_ISP_LSC_BASE + 0x0000001C) #define RKISP1_CIF_ISP_LSC_GB_TABLE_DATA (RKISP1_CIF_ISP_LSC_BASE + 0x00000020) -#define RKISP1_CIF_ISP_LSC_XGRAD_01 (RKISP1_CIF_ISP_LSC_BASE + 0x00000024) -#define RKISP1_CIF_ISP_LSC_XGRAD_23 (RKISP1_CIF_ISP_LSC_BASE + 0x00000028) -#define RKISP1_CIF_ISP_LSC_XGRAD_45 (RKISP1_CIF_ISP_LSC_BASE + 0x0000002C) -#define RKISP1_CIF_ISP_LSC_XGRAD_67 (RKISP1_CIF_ISP_LSC_BASE + 0x00000030) -#define RKISP1_CIF_ISP_LSC_YGRAD_01 (RKISP1_CIF_ISP_LSC_BASE + 0x00000034) -#define RKISP1_CIF_ISP_LSC_YGRAD_23 (RKISP1_CIF_ISP_LSC_BASE + 0x00000038) -#define RKISP1_CIF_ISP_LSC_YGRAD_45 (RKISP1_CIF_ISP_LSC_BASE + 0x0000003C) -#define RKISP1_CIF_ISP_LSC_YGRAD_67 (RKISP1_CIF_ISP_LSC_BASE + 0x00000040) -#define RKISP1_CIF_ISP_LSC_XSIZE_01 (RKISP1_CIF_ISP_LSC_BASE + 0x00000044) -#define RKISP1_CIF_ISP_LSC_XSIZE_23 (RKISP1_CIF_ISP_LSC_BASE + 0x00000048) -#define RKISP1_CIF_ISP_LSC_XSIZE_45 (RKISP1_CIF_ISP_LSC_BASE + 0x0000004C) -#define RKISP1_CIF_ISP_LSC_XSIZE_67 (RKISP1_CIF_ISP_LSC_BASE + 0x00000050) -#define RKISP1_CIF_ISP_LSC_YSIZE_01 (RKISP1_CIF_ISP_LSC_BASE + 0x00000054) -#define RKISP1_CIF_ISP_LSC_YSIZE_23 (RKISP1_CIF_ISP_LSC_BASE + 0x00000058) -#define RKISP1_CIF_ISP_LSC_YSIZE_45 (RKISP1_CIF_ISP_LSC_BASE + 0x0000005C) -#define RKISP1_CIF_ISP_LSC_YSIZE_67 (RKISP1_CIF_ISP_LSC_BASE + 0x00000060) +#define RKISP1_CIF_ISP_LSC_XGRAD(n) (RKISP1_CIF_ISP_LSC_BASE + 0x00000024 + (n) * 4) +#define RKISP1_CIF_ISP_LSC_YGRAD(n) (RKISP1_CIF_ISP_LSC_BASE + 0x00000034 + (n) * 4) +#define RKISP1_CIF_ISP_LSC_XSIZE(n) (RKISP1_CIF_ISP_LSC_BASE + 0x00000044 + (n) * 4) +#define RKISP1_CIF_ISP_LSC_YSIZE(n) (RKISP1_CIF_ISP_LSC_BASE + 0x00000054 + (n) * 4) #define RKISP1_CIF_ISP_LSC_TABLE_SEL (RKISP1_CIF_ISP_LSC_BASE + 0x00000064) #define RKISP1_CIF_ISP_LSC_STATUS (RKISP1_CIF_ISP_LSC_BASE + 0x00000068) -- cgit From 4c3501f13e8e60f6e7e7308c77ac4404e1007c18 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 17 Aug 2022 01:53:57 +0200 Subject: media: rkisp1: Use correct macro for gradient registers The rkisp1_lsc_config() function incorrectly uses the RKISP1_CIF_ISP_LSC_SECT_SIZE() macro for the gradient registers. Replace it with the correct macro, and rename it from RKISP1_CIF_ISP_LSC_GRAD_SIZE() to RKISP1_CIF_ISP_LSC_SECT_GRAD() as the corresponding registers store the gradients for each sector, not a size. This doesn't cause any functional change as the two macros are defined identically (the size and gradient registers store fields in the same number of bits at the same positions). Signed-off-by: Laurent Pinchart Reviewed-by: Dafna Hirschfeld Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rockchip/rkisp1/rkisp1-params.c | 4 ++-- drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c index aa6efa4c6e9e..123c26fc1679 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c @@ -334,7 +334,7 @@ static void rkisp1_lsc_config(struct rkisp1_params *params, rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_XSIZE(i), data); /* program x grad tables */ - data = RKISP1_CIF_ISP_LSC_SECT_SIZE(arg->x_grad_tbl[i * 2], + data = RKISP1_CIF_ISP_LSC_SECT_GRAD(arg->x_grad_tbl[i * 2], arg->x_grad_tbl[i * 2 + 1]); rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_XGRAD(i), data); @@ -344,7 +344,7 @@ static void rkisp1_lsc_config(struct rkisp1_params *params, rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_YSIZE(i), data); /* program y grad tables */ - data = RKISP1_CIF_ISP_LSC_SECT_SIZE(arg->y_grad_tbl[i * 2], + data = RKISP1_CIF_ISP_LSC_SECT_GRAD(arg->y_grad_tbl[i * 2], arg->y_grad_tbl[i * 2 + 1]); rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_YGRAD(i), data); } diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h index b3d8c10163d4..421cc73355db 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h @@ -576,7 +576,7 @@ (((v0) & 0x1FFF) | (((v1) & 0x1FFF) << 13)) #define RKISP1_CIF_ISP_LSC_SECT_SIZE(v0, v1) \ (((v0) & 0xFFF) | (((v1) & 0xFFF) << 16)) -#define RKISP1_CIF_ISP_LSC_GRAD_SIZE(v0, v1) \ +#define RKISP1_CIF_ISP_LSC_SECT_GRAD(v0, v1) \ (((v0) & 0xFFF) | (((v1) & 0xFFF) << 16)) /* LSC: ISP_LSC_TABLE_SEL */ -- cgit From 4b07e2b8f7b53e929a483320cd6c9c1cbd76e329 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 17 Aug 2022 01:53:57 +0200 Subject: media: rkisp1: Configure LSC after enabling the ISP The ISP8000Nano v18.02 (found in the i.MX8MP) requires the ISP to be enabled (as indicated by the ISP_CTRL.ISP_ENABLE bit) to configure the lens shading table in internal RAM. The driver currently configures all ISP initial parameters before enabling the ISP, which causes the LSC RAM to not be initialized properly. To fix this, split the rkisp1_params_configure() function into a rkisp1_params_pre_configure() and a rkisp1_params_post_configure(). The former configures all ISP parameters but LSC, while the latter configures LSC. To implement this, the rkisp1_params_apply_params_cfg() function is deconstructed, with two small helpers created to deal with the parameters buffers, which are then used in rkisp1_params_isr(), rkisp1_params_pre_configure() and rkisp1_params_post_configure(). While this initialization ordering is only needed for the ISP8000Nano v18.02, it doesn't affect other ISP versions negatively, and can thus be followed unconditionally. Signed-off-by: Laurent Pinchart Reviewed-by: Dafna Hirschfeld Signed-off-by: Mauro Carvalho Chehab --- .../media/platform/rockchip/rkisp1/rkisp1-common.h | 29 +++- .../media/platform/rockchip/rkisp1/rkisp1-isp.c | 9 +- .../media/platform/rockchip/rkisp1/rkisp1-params.c | 169 ++++++++++++++------- 3 files changed, 143 insertions(+), 64 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h index b704e955cb28..a1293c45aae1 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h @@ -557,19 +557,32 @@ void rkisp1_sd_adjust_crop(struct v4l2_rect *crop, */ const struct rkisp1_mbus_info *rkisp1_mbus_info_get_by_code(u32 mbus_code); -/* rkisp1_params_configure - configure the params when stream starts. - * This function is called by the isp entity upon stream starts. - * The function applies the initial configuration of the parameters. +/* + * rkisp1_params_pre_configure - Configure the params before stream start * - * @params: pointer to rkisp1_params. + * @params: pointer to rkisp1_params * @bayer_pat: the bayer pattern on the isp video sink pad * @quantization: the quantization configured on the isp's src pad * @ycbcr_encoding: the ycbcr_encoding configured on the isp's src pad + * + * This function is called by the ISP entity just before the ISP gets started. + * It applies the initial ISP parameters from the first params buffer, but + * skips LSC as it needs to be configured after the ISP is started. + */ +void rkisp1_params_pre_configure(struct rkisp1_params *params, + enum rkisp1_fmt_raw_pat_type bayer_pat, + enum v4l2_quantization quantization, + enum v4l2_ycbcr_encoding ycbcr_encoding); + +/* + * rkisp1_params_post_configure - Configure the params after stream start + * + * @params: pointer to rkisp1_params + * + * This function is called by the ISP entity just after the ISP gets started. + * It applies the initial ISP LSC parameters from the first params buffer. */ -void rkisp1_params_configure(struct rkisp1_params *params, - enum rkisp1_fmt_raw_pat_type bayer_pat, - enum v4l2_quantization quantization, - enum v4l2_ycbcr_encoding ycbcr_encoding); +void rkisp1_params_post_configure(struct rkisp1_params *params); /* rkisp1_params_disable - disable all parameters. * This function is called by the isp entity upon stream start diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c index f19c0718963f..585cf3f53469 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c @@ -233,9 +233,9 @@ static int rkisp1_config_isp(struct rkisp1_isp *isp, src_frm = rkisp1_isp_get_pad_fmt(isp, NULL, RKISP1_ISP_PAD_SOURCE_VIDEO, V4L2_SUBDEV_FORMAT_ACTIVE); - rkisp1_params_configure(&rkisp1->params, sink_fmt->bayer_pat, - src_frm->quantization, - src_frm->ycbcr_enc); + rkisp1_params_pre_configure(&rkisp1->params, sink_fmt->bayer_pat, + src_frm->quantization, + src_frm->ycbcr_enc); } return 0; @@ -341,6 +341,9 @@ static void rkisp1_isp_start(struct rkisp1_isp *isp) RKISP1_CIF_ISP_CTRL_ISP_ENABLE | RKISP1_CIF_ISP_CTRL_ISP_INFORM_ENABLE; rkisp1_write(rkisp1, RKISP1_CIF_ISP_CTRL, val); + + if (isp->src_fmt->pixel_enc != V4L2_PIXEL_ENC_BAYER) + rkisp1_params_post_configure(&rkisp1->params); } /* ---------------------------------------------------------------------------- diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c index 123c26fc1679..d8731ebbf479 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c @@ -1297,22 +1297,6 @@ rkisp1_isp_isr_other_config(struct rkisp1_params *params, RKISP1_CIF_ISP_CTRL_ISP_GAMMA_IN_ENA); } - /* update lsc config */ - if (module_cfg_update & RKISP1_CIF_ISP_MODULE_LSC) - rkisp1_lsc_config(params, - &new_params->others.lsc_config); - - if (module_en_update & RKISP1_CIF_ISP_MODULE_LSC) { - if (module_ens & RKISP1_CIF_ISP_MODULE_LSC) - rkisp1_param_set_bits(params, - RKISP1_CIF_ISP_LSC_CTRL, - RKISP1_CIF_ISP_LSC_CTRL_ENA); - else - rkisp1_param_clear_bits(params, - RKISP1_CIF_ISP_LSC_CTRL, - RKISP1_CIF_ISP_LSC_CTRL_ENA); - } - /* update awb gains */ if (module_cfg_update & RKISP1_CIF_ISP_MODULE_AWB_GAIN) params->ops->awb_gain_config(params, &new_params->others.awb_gain_config); @@ -1429,6 +1413,33 @@ rkisp1_isp_isr_other_config(struct rkisp1_params *params, } } +static void +rkisp1_isp_isr_lsc_config(struct rkisp1_params *params, + const struct rkisp1_params_cfg *new_params) +{ + unsigned int module_en_update, module_cfg_update, module_ens; + + module_en_update = new_params->module_en_update; + module_cfg_update = new_params->module_cfg_update; + module_ens = new_params->module_ens; + + /* update lsc config */ + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_LSC) + rkisp1_lsc_config(params, + &new_params->others.lsc_config); + + if (module_en_update & RKISP1_CIF_ISP_MODULE_LSC) { + if (module_ens & RKISP1_CIF_ISP_MODULE_LSC) + rkisp1_param_set_bits(params, + RKISP1_CIF_ISP_LSC_CTRL, + RKISP1_CIF_ISP_LSC_CTRL_ENA); + else + rkisp1_param_clear_bits(params, + RKISP1_CIF_ISP_LSC_CTRL, + RKISP1_CIF_ISP_LSC_CTRL_ENA); + } +} + static void rkisp1_isp_isr_meas_config(struct rkisp1_params *params, struct rkisp1_params_cfg *new_params) { @@ -1490,47 +1501,60 @@ static void rkisp1_isp_isr_meas_config(struct rkisp1_params *params, } } -static void rkisp1_params_apply_params_cfg(struct rkisp1_params *params, - unsigned int frame_sequence) +static bool rkisp1_params_get_buffer(struct rkisp1_params *params, + struct rkisp1_buffer **buf, + struct rkisp1_params_cfg **cfg) { - struct rkisp1_params_cfg *new_params; - struct rkisp1_buffer *cur_buf = NULL; - if (list_empty(¶ms->params)) - return; - - cur_buf = list_first_entry(¶ms->params, - struct rkisp1_buffer, queue); + return false; - new_params = (struct rkisp1_params_cfg *)vb2_plane_vaddr(&cur_buf->vb.vb2_buf, 0); + *buf = list_first_entry(¶ms->params, struct rkisp1_buffer, queue); + *cfg = vb2_plane_vaddr(&(*buf)->vb.vb2_buf, 0); - rkisp1_isp_isr_other_config(params, new_params); - rkisp1_isp_isr_meas_config(params, new_params); - - /* update shadow register immediately */ - rkisp1_param_set_bits(params, RKISP1_CIF_ISP_CTRL, RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD); + return true; +} - list_del(&cur_buf->queue); +static void rkisp1_params_complete_buffer(struct rkisp1_params *params, + struct rkisp1_buffer *buf, + unsigned int frame_sequence) +{ + list_del(&buf->queue); - cur_buf->vb.sequence = frame_sequence; - vb2_buffer_done(&cur_buf->vb.vb2_buf, VB2_BUF_STATE_DONE); + buf->vb.sequence = frame_sequence; + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); } void rkisp1_params_isr(struct rkisp1_device *rkisp1) { - /* - * This isr is called when the ISR finishes processing a frame (RKISP1_CIF_ISP_FRAME). - * Configurations performed here will be applied on the next frame. - * Since frame_sequence is updated on the vertical sync signal, we should use - * frame_sequence + 1 here to indicate to userspace on which frame these parameters - * are being applied. - */ - unsigned int frame_sequence = rkisp1->isp.frame_sequence + 1; struct rkisp1_params *params = &rkisp1->params; + struct rkisp1_params_cfg *new_params; + struct rkisp1_buffer *cur_buf; spin_lock(¶ms->config_lock); - rkisp1_params_apply_params_cfg(params, frame_sequence); + if (!rkisp1_params_get_buffer(params, &cur_buf, &new_params)) + goto unlock; + + rkisp1_isp_isr_other_config(params, new_params); + rkisp1_isp_isr_lsc_config(params, new_params); + rkisp1_isp_isr_meas_config(params, new_params); + + /* update shadow register immediately */ + rkisp1_param_set_bits(params, RKISP1_CIF_ISP_CTRL, + RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD); + + /* + * This isr is called when the ISR finishes processing a frame + * (RKISP1_CIF_ISP_FRAME). Configurations performed here will be + * applied on the next frame. Since frame_sequence is updated on the + * vertical sync signal, we should use frame_sequence + 1 here to + * indicate to userspace on which frame these parameters are being + * applied. + */ + rkisp1_params_complete_buffer(params, cur_buf, + rkisp1->isp.frame_sequence + 1); + +unlock: spin_unlock(¶ms->config_lock); } @@ -1573,9 +1597,18 @@ static const struct rkisp1_cif_isp_afc_config rkisp1_afc_params_default_config = 14 }; -static void rkisp1_params_config_parameter(struct rkisp1_params *params) +void rkisp1_params_pre_configure(struct rkisp1_params *params, + enum rkisp1_fmt_raw_pat_type bayer_pat, + enum v4l2_quantization quantization, + enum v4l2_ycbcr_encoding ycbcr_encoding) { struct rkisp1_cif_isp_hst_config hst = rkisp1_hst_params_default_config; + struct rkisp1_params_cfg *new_params; + struct rkisp1_buffer *cur_buf; + + params->quantization = quantization; + params->ycbcr_encoding = ycbcr_encoding; + params->raw_type = bayer_pat; params->ops->awb_meas_config(params, &rkisp1_awb_params_default_config); params->ops->awb_meas_enable(params, &rkisp1_awb_params_default_config, @@ -1599,20 +1632,50 @@ static void rkisp1_params_config_parameter(struct rkisp1_params *params) spin_lock_irq(¶ms->config_lock); /* apply the first buffer if there is one already */ - rkisp1_params_apply_params_cfg(params, 0); + if (!rkisp1_params_get_buffer(params, &cur_buf, &new_params)) + goto unlock; + + rkisp1_isp_isr_other_config(params, new_params); + rkisp1_isp_isr_meas_config(params, new_params); + + /* update shadow register immediately */ + rkisp1_param_set_bits(params, RKISP1_CIF_ISP_CTRL, + RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD); + +unlock: spin_unlock_irq(¶ms->config_lock); } -void rkisp1_params_configure(struct rkisp1_params *params, - enum rkisp1_fmt_raw_pat_type bayer_pat, - enum v4l2_quantization quantization, - enum v4l2_ycbcr_encoding ycbcr_encoding) +void rkisp1_params_post_configure(struct rkisp1_params *params) { - params->quantization = quantization; - params->ycbcr_encoding = ycbcr_encoding; - params->raw_type = bayer_pat; - rkisp1_params_config_parameter(params); + struct rkisp1_params_cfg *new_params; + struct rkisp1_buffer *cur_buf; + + spin_lock_irq(¶ms->config_lock); + + /* + * Apply LSC parameters from the first buffer (if any is already + * available. This must be done after the ISP gets started in the + * ISP8000Nano v18.02 (found in the i.MX8MP) as access to the LSC RAM + * is gated by the ISP_CTRL.ISP_ENABLE bit. As this initialization + * ordering doesn't affect other ISP versions negatively, do so + * unconditionally. + */ + + if (!rkisp1_params_get_buffer(params, &cur_buf, &new_params)) + goto unlock; + + rkisp1_isp_isr_lsc_config(params, new_params); + + /* update shadow register immediately */ + rkisp1_param_set_bits(params, RKISP1_CIF_ISP_CTRL, + RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD); + + rkisp1_params_complete_buffer(params, cur_buf, 0); + +unlock: + spin_unlock_irq(¶ms->config_lock); } /* -- cgit From c53e3a049f35978a150526671587fd46b1ae7ca1 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 23 Aug 2022 17:11:36 +0200 Subject: media: rkisp1: Zero v4l2_subdev_format fields in when validating links The local sd_fmt variable in rkisp1_capture_link_validate() has uninitialized fields, which causes random failures when calling the subdev .get_fmt() operation. Fix it by initializing the variable when declaring it, which zeros all other fields. Signed-off-by: Laurent Pinchart Reviewed-by: Paul Elder Reviewed-by: Dafna Hirschfeld Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c index d5904c96ff3f..c66963a2ccd9 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c @@ -1273,11 +1273,12 @@ static int rkisp1_capture_link_validate(struct media_link *link) struct rkisp1_capture *cap = video_get_drvdata(vdev); const struct rkisp1_capture_fmt_cfg *fmt = rkisp1_find_fmt_cfg(cap, cap->pix.fmt.pixelformat); - struct v4l2_subdev_format sd_fmt; + struct v4l2_subdev_format sd_fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + .pad = link->source->index, + }; int ret; - sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; - sd_fmt.pad = link->source->index; ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &sd_fmt); if (ret) return ret; -- cgit From cfeacb5d46ed9c747cad7fdffc254afced50c1ef Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 25 Aug 2022 12:41:49 +0200 Subject: media: coda: jpeg: drop coda9_jpeg_dec_huff_setup() return value coda9_jpeg_dec_huff_setup() never returns anything but 0. Drop return value and superfluous error handling at the call site. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/chips-media/coda-jpeg.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/chips-media/coda-jpeg.c b/drivers/media/platform/chips-media/coda-jpeg.c index a0b22b07f69a..435e7030fc2a 100644 --- a/drivers/media/platform/chips-media/coda-jpeg.c +++ b/drivers/media/platform/chips-media/coda-jpeg.c @@ -421,7 +421,7 @@ static inline void coda9_jpeg_write_huff_values(struct coda_dev *dev, u8 *bits, coda_write(dev, (s32)values[i], CODA9_REG_JPEG_HUFF_DATA); } -static int coda9_jpeg_dec_huff_setup(struct coda_ctx *ctx) +static void coda9_jpeg_dec_huff_setup(struct coda_ctx *ctx) { struct coda_huff_tab *huff_tab = ctx->params.jpeg_huff_tab; struct coda_dev *dev = ctx->dev; @@ -455,7 +455,6 @@ static int coda9_jpeg_dec_huff_setup(struct coda_ctx *ctx) coda9_jpeg_write_huff_values(dev, huff_tab->luma_ac, 162); coda9_jpeg_write_huff_values(dev, huff_tab->chroma_ac, 162); coda_write(dev, 0x000, CODA9_REG_JPEG_HUFF_CTRL); - return 0; } static inline void coda9_jpeg_write_qmat_tab(struct coda_dev *dev, @@ -1394,14 +1393,8 @@ static int coda9_jpeg_prepare_decode(struct coda_ctx *ctx) coda_write(dev, ctx->params.jpeg_restart_interval, CODA9_REG_JPEG_RST_INTVAL); - if (ctx->params.jpeg_huff_tab) { - ret = coda9_jpeg_dec_huff_setup(ctx); - if (ret < 0) { - v4l2_err(&dev->v4l2_dev, - "failed to set up Huffman tables: %d\n", ret); - return ret; - } - } + if (ctx->params.jpeg_huff_tab) + coda9_jpeg_dec_huff_setup(ctx); coda9_jpeg_qmat_setup(ctx); -- cgit From d91d7bc85062309aae6d8064563ddf17947cb6bc Mon Sep 17 00:00:00 2001 From: Ming Qian Date: Mon, 29 Aug 2022 07:33:16 +0200 Subject: media: amphion: release m2m ctx when releasing vpu instance release m2m ctx in the callback function that release the vpu instance, then there is no need to add lock around releasing m2m ctx. Fixes: 3cd084519c6f ("media: amphion: add vpu v4l2 m2m support") Signed-off-by: Ming Qian Reviewed-by: Tommaso Merciai Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/amphion/vpu_v4l2.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/amphion/vpu_v4l2.c b/drivers/media/platform/amphion/vpu_v4l2.c index 8a3eed957ae6..b779e0ba916c 100644 --- a/drivers/media/platform/amphion/vpu_v4l2.c +++ b/drivers/media/platform/amphion/vpu_v4l2.c @@ -603,6 +603,10 @@ static int vpu_v4l2_release(struct vpu_inst *inst) inst->workqueue = NULL; } + if (inst->fh.m2m_ctx) { + v4l2_m2m_ctx_release(inst->fh.m2m_ctx); + inst->fh.m2m_ctx = NULL; + } v4l2_ctrl_handler_free(&inst->ctrl_handler); mutex_destroy(&inst->lock); v4l2_fh_del(&inst->fh); @@ -685,13 +689,6 @@ int vpu_v4l2_close(struct file *file) vpu_trace(vpu->dev, "tgid = %d, pid = %d, inst = %p\n", inst->tgid, inst->pid, inst); - vpu_inst_lock(inst); - if (inst->fh.m2m_ctx) { - v4l2_m2m_ctx_release(inst->fh.m2m_ctx); - inst->fh.m2m_ctx = NULL; - } - vpu_inst_unlock(inst); - call_void_vop(inst, release); vpu_inst_unregister(inst); vpu_inst_put(inst); -- cgit From cd75981ec93a3abf717d0182ff5d56b650873215 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 29 Aug 2022 16:05:14 +0200 Subject: media: v4l2-ctrls: drop 'elems' argument from control type ops. The type ops for equal, init and validate have an elems argument, but this can be taken from struct v4l2_ctrl: ctrl->elems for equal and init, and ctrl->new_elems for validate (since you are validating a new control value). So drop this argument and update all callers. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/nxp/dw100/dw100.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/nxp/dw100/dw100.c b/drivers/media/platform/nxp/dw100/dw100.c index b3b057798ab6..f6d48c36f386 100644 --- a/drivers/media/platform/nxp/dw100/dw100.c +++ b/drivers/media/platform/nxp/dw100/dw100.c @@ -373,7 +373,7 @@ static const struct v4l2_ctrl_ops dw100_ctrl_ops = { * The coordinates are saved in UQ12.4 fixed point format. */ static void dw100_ctrl_dewarping_map_init(const struct v4l2_ctrl *ctrl, - u32 from_idx, u32 elems, + u32 from_idx, union v4l2_ctrl_ptr ptr) { struct dw100_ctx *ctx = @@ -398,7 +398,7 @@ static void dw100_ctrl_dewarping_map_init(const struct v4l2_ctrl *ctrl, ctx->map_height = mh; ctx->map_size = mh * mw * sizeof(u32); - for (idx = from_idx; idx < elems; idx++) { + for (idx = from_idx; idx < ctrl->elems; idx++) { qy = min_t(u32, (idx / mw) * qdy, qsh); qx = min_t(u32, (idx % mw) * qdx, qsw); map[idx] = dw100_map_format_coordinates(qx, qy); -- cgit From 74869a88f9d551add870412b53c2be8a192b8d12 Mon Sep 17 00:00:00 2001 From: Moudy Ho Date: Wed, 31 Aug 2022 10:56:04 +0200 Subject: media: platform: mtk-mdp3: add pointer checks and use devm_kfree Fix two errors reported by smatch: drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c:292 mdp_probe() error: we previously assumed 'mdp' could be null drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c:460 mdp_cmdq_send() error: we previously assumed 'cmd' could be null Also, avoid warnings reported by smatch: drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c:872 mdp_comp_create() warn: passing devm_ allocated variable to kfree. 'comp' [hverkuil: fix devm_kfree call] Signed-off-by: Moudy Ho Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c | 2 +- drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c | 2 +- drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c index 29f6c1cd3de7..86c054600a08 100644 --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c @@ -457,7 +457,7 @@ err_cmdq_data: kfree(path); atomic_dec(&mdp->job_count); wake_up(&mdp->callback_wq); - if (cmd->pkt.buf_size > 0) + if (cmd && cmd->pkt.buf_size > 0) mdp_cmdq_pkt_destroy(&cmd->pkt); kfree(comps); kfree(cmd); diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c index e62abf3587bf..43455755a5ac 100644 --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c @@ -869,7 +869,7 @@ static struct mdp_comp *mdp_comp_create(struct mdp_dev *mdp, ret = mdp_comp_init(mdp, node, comp, id); if (ret) { - kfree(comp); + devm_kfree(dev, comp); return ERR_PTR(ret); } mdp->comp[id] = comp; diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c index cde59579b7ae..c413e59d4286 100644 --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c @@ -289,7 +289,8 @@ err_deinit_comp: mdp_comp_destroy(mdp); err_return: for (i = 0; i < MDP_PIPE_MAX; i++) - mtk_mutex_put(mdp->mdp_mutex[i]); + if (mdp) + mtk_mutex_put(mdp->mdp_mutex[i]); kfree(mdp); dev_dbg(dev, "Errno %d\n", ret); return ret; -- cgit From dec7920e55db35ac429b002025aa1fafc0ec7d57 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 1 Sep 2022 16:47:48 +0200 Subject: media: platform: mtk-mdp3: fix error code in mdp_vpu_dev_init() Return a negative error code if mdp_vpu_shared_mem_alloc() fails. Fixes: 61890ccaefaf ("media: platform: mtk-mdp3: add MediaTek MDP3 driver") Signed-off-by: Dan Carpenter Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Matthias Brugger Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mediatek/mdp3/mtk-mdp3-vpu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-vpu.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-vpu.c index 9f5844385c8f..a72bed927bb6 100644 --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-vpu.c +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-vpu.c @@ -173,7 +173,8 @@ int mdp_vpu_dev_init(struct mdp_vpu_dev *vpu, struct mtk_scp *scp, /* vpu work_size was set in mdp_vpu_ipi_handle_init_ack */ mem_size = vpu_alloc_size; - if (mdp_vpu_shared_mem_alloc(vpu)) { + err = mdp_vpu_shared_mem_alloc(vpu); + if (err) { dev_err(&mdp->pdev->dev, "VPU memory alloc fail!"); goto err_mem_alloc; } -- cgit From ff464745e4576ed8670bc2fc8da27e022f0ea56c Mon Sep 17 00:00:00 2001 From: Sun Ke Date: Fri, 2 Sep 2022 10:58:19 +0200 Subject: media: platform: mtk-mdp3: fix PM reference leak in mdp_comp_clock_on() mdp_comp_clock_on will increase runtime PM usage counter, and mdp_comp_clock_off will decrease the runtime PM usage counter. so, if mdp_comp_clock_on failed after increment runtime PM usage counter, it should decrease it before return a error code. pm_runtime_get_sync will increment pm usage counter even it failed. Forgetting to putting operation will result in reference leak here. Fix it by replacing it with pm_runtime_resume_and_get to keep usage counter balanced. And if failed to enable clk, add pm_runtime_put() to decrease the runtime PM usage counter. Fixes: 61890ccaefaf ("media: platform: mtk-mdp3: add MediaTek MDP3 driver") Signed-off-by: Sun Ke Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c index 43455755a5ac..d3eaf8884412 100644 --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c @@ -682,7 +682,7 @@ int mdp_comp_clock_on(struct device *dev, struct mdp_comp *comp) int i, ret; if (comp->comp_dev) { - ret = pm_runtime_get_sync(comp->comp_dev); + ret = pm_runtime_resume_and_get(comp->comp_dev); if (ret < 0) { dev_err(dev, "Failed to get power, err %d. type:%d id:%d\n", @@ -699,6 +699,7 @@ int mdp_comp_clock_on(struct device *dev, struct mdp_comp *comp) dev_err(dev, "Failed to enable clk %d. type:%d id:%d\n", i, comp->type, comp->id); + pm_runtime_put(comp->comp_dev); return ret; } } @@ -930,7 +931,7 @@ void mdp_comp_destroy(struct mdp_dev *mdp) if (mdp->comp[i]) { pm_runtime_disable(mdp->comp[i]->comp_dev); mdp_comp_deinit(mdp->comp[i]); - kfree(mdp->comp[i]); + devm_kfree(mdp->comp[i]->comp_dev, mdp->comp[i]); mdp->comp[i] = NULL; } } -- cgit From 4bec03301ecd81760c159402467dbb2cfd527684 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Mon, 29 Aug 2022 18:21:53 +0200 Subject: media: hantro: Store HEVC bit depth in context Store HEVC bit depth in context. Bit depth is equal to hevc sps bit_depth_luma_minus8 + 8. Signed-off-by: Benjamin Gaignard Reviewed-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/verisilicon/hantro_drv.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/verisilicon/hantro_drv.c b/drivers/media/platform/verisilicon/hantro_drv.c index 2036f72eeb4a..1dd8312d824c 100644 --- a/drivers/media/platform/verisilicon/hantro_drv.c +++ b/drivers/media/platform/verisilicon/hantro_drv.c @@ -251,6 +251,11 @@ queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) static int hantro_try_ctrl(struct v4l2_ctrl *ctrl) { + struct hantro_ctx *ctx; + + ctx = container_of(ctrl->handler, + struct hantro_ctx, ctrl_handler); + if (ctrl->id == V4L2_CID_STATELESS_H264_SPS) { const struct v4l2_ctrl_h264_sps *sps = ctrl->p_new.p_h264_sps; @@ -272,6 +277,8 @@ static int hantro_try_ctrl(struct v4l2_ctrl *ctrl) if (sps->bit_depth_luma_minus8 != 0) /* Only 8-bit is supported */ return -EINVAL; + + ctx->bit_depth = sps->bit_depth_luma_minus8 + 8; } else if (ctrl->id == V4L2_CID_STATELESS_VP9_FRAME) { const struct v4l2_ctrl_vp9_frame *dec_params = ctrl->p_new.p_vp9_frame; -- cgit From 8a438580a09ecef78cd6c5825d628b4d5ae1c127 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Mon, 29 Aug 2022 18:21:54 +0200 Subject: media: hantro: HEVC: Fix auxilary buffer size calculation SAO and FILTER buffers size depend of the bit depth. Make sure we have enough space for 10bit bitstreams. Signed-off-by: Benjamin Gaignard Reviewed-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/verisilicon/hantro_hevc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/verisilicon/hantro_hevc.c b/drivers/media/platform/verisilicon/hantro_hevc.c index b990bc98164c..9383fb7081f6 100644 --- a/drivers/media/platform/verisilicon/hantro_hevc.c +++ b/drivers/media/platform/verisilicon/hantro_hevc.c @@ -104,7 +104,7 @@ static int tile_buffer_reallocate(struct hantro_ctx *ctx) hevc_dec->tile_bsd.cpu = NULL; } - size = VERT_FILTER_RAM_SIZE * height64 * (num_tile_cols - 1); + size = (VERT_FILTER_RAM_SIZE * height64 * (num_tile_cols - 1) * ctx->bit_depth) / 8; hevc_dec->tile_filter.cpu = dma_alloc_coherent(vpu->dev, size, &hevc_dec->tile_filter.dma, GFP_KERNEL); @@ -112,7 +112,7 @@ static int tile_buffer_reallocate(struct hantro_ctx *ctx) goto err_free_tile_buffers; hevc_dec->tile_filter.size = size; - size = VERT_SAO_RAM_SIZE * height64 * (num_tile_cols - 1); + size = (VERT_SAO_RAM_SIZE * height64 * (num_tile_cols - 1) * ctx->bit_depth) / 8; hevc_dec->tile_sao.cpu = dma_alloc_coherent(vpu->dev, size, &hevc_dec->tile_sao.dma, GFP_KERNEL); -- cgit From f64853ad7f964b3bf7c1d63b27ca7ef972797a1c Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Mon, 29 Aug 2022 18:21:55 +0200 Subject: media: hantro: HEVC: Fix chroma offset computation The chroma offset depends of the bitstream depth. Make sure that ctx->bit_depth is used to compute it. Signed-off-by: Benjamin Gaignard Reviewed-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c b/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c index 233ecd863d5f..a917079a6ed3 100644 --- a/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c +++ b/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c @@ -12,7 +12,7 @@ static size_t hantro_hevc_chroma_offset(struct hantro_ctx *ctx) { - return ctx->dst_fmt.width * ctx->dst_fmt.height; + return ctx->dst_fmt.width * ctx->dst_fmt.height * ctx->bit_depth / 8; } static size_t hantro_hevc_motion_vectors_offset(struct hantro_ctx *ctx) -- cgit From 5aa24d729999c3d80034b29fc48f9957ad61fce8 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Mon, 29 Aug 2022 18:21:56 +0200 Subject: media: hantro: postproc: Configure output regs to support 10bit Move output format setting in postproc and make sure that 8/10bit configuration is correctly set. Signed-off-by: Benjamin Gaignard Reviewed-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c | 2 -- drivers/media/platform/verisilicon/hantro_postproc.c | 7 ++++++- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c b/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c index a917079a6ed3..a9d4ac84a8d8 100644 --- a/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c +++ b/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c @@ -167,8 +167,6 @@ static void set_params(struct hantro_ctx *ctx) hantro_reg_write(vpu, &g2_bit_depth_y_minus8, sps->bit_depth_luma_minus8); hantro_reg_write(vpu, &g2_bit_depth_c_minus8, sps->bit_depth_chroma_minus8); - hantro_reg_write(vpu, &g2_output_8_bits, 0); - hantro_reg_write(vpu, &g2_hdr_skip_length, compute_header_skip_length(ctx)); min_log2_cb_size = sps->log2_min_luma_coding_block_size_minus3 + 3; diff --git a/drivers/media/platform/verisilicon/hantro_postproc.c b/drivers/media/platform/verisilicon/hantro_postproc.c index a0928c508434..09d8cf942689 100644 --- a/drivers/media/platform/verisilicon/hantro_postproc.c +++ b/drivers/media/platform/verisilicon/hantro_postproc.c @@ -114,6 +114,7 @@ static void hantro_postproc_g2_enable(struct hantro_ctx *ctx) struct hantro_dev *vpu = ctx->dev; struct vb2_v4l2_buffer *dst_buf; int down_scale = down_scale_factor(ctx); + int out_depth; size_t chroma_offset; dma_addr_t dst_dma; @@ -132,8 +133,9 @@ static void hantro_postproc_g2_enable(struct hantro_ctx *ctx) hantro_write_addr(vpu, G2_RS_OUT_LUMA_ADDR, dst_dma); hantro_write_addr(vpu, G2_RS_OUT_CHROMA_ADDR, dst_dma + chroma_offset); } + + out_depth = hantro_get_format_depth(ctx->dst_fmt.pixelformat); if (ctx->dev->variant->legacy_regs) { - int out_depth = hantro_get_format_depth(ctx->dst_fmt.pixelformat); u8 pp_shift = 0; if (out_depth > 8) @@ -141,6 +143,9 @@ static void hantro_postproc_g2_enable(struct hantro_ctx *ctx) hantro_reg_write(ctx->dev, &g2_rs_out_bit_depth, out_depth); hantro_reg_write(ctx->dev, &g2_pp_pix_shift, pp_shift); + } else { + hantro_reg_write(vpu, &g2_output_8_bits, out_depth > 8 ? 0 : 1); + hantro_reg_write(vpu, &g2_output_format, out_depth > 8 ? 1 : 0); } hantro_reg_write(vpu, &g2_out_rs_e, 1); } -- cgit From d040a24b5aaede6049fe27f2ea29773ada16a9e3 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Mon, 29 Aug 2022 18:21:57 +0200 Subject: media: Hantro: HEVC: Allows 10-bit bitstream Stop limiting HEVC support to 8-bits bitstreams also accept 10-bits bitstreams. Signed-off-by: Benjamin Gaignard Reviewed-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/verisilicon/hantro_drv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/verisilicon/hantro_drv.c b/drivers/media/platform/verisilicon/hantro_drv.c index 1dd8312d824c..7c75922e2e98 100644 --- a/drivers/media/platform/verisilicon/hantro_drv.c +++ b/drivers/media/platform/verisilicon/hantro_drv.c @@ -274,8 +274,8 @@ static int hantro_try_ctrl(struct v4l2_ctrl *ctrl) if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8) /* Luma and chroma bit depth mismatch */ return -EINVAL; - if (sps->bit_depth_luma_minus8 != 0) - /* Only 8-bit is supported */ + if (sps->bit_depth_luma_minus8 != 0 && sps->bit_depth_luma_minus8 != 2) + /* Only 8-bit and 10-bit are supported */ return -EINVAL; ctx->bit_depth = sps->bit_depth_luma_minus8 + 8; -- cgit From dc39473d0340071bc04c07ba95c40f2bcf9f8ded Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Mon, 29 Aug 2022 18:21:58 +0200 Subject: media: hantro: imx8m: Enable 10bit decoding Expose 10bit pixel formats to enable 10bit decoding in IMX8M SoCs. Signed-off-by: Benjamin Gaignard Reviewed-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/verisilicon/imx8m_vpu_hw.c | 27 +++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/verisilicon/imx8m_vpu_hw.c b/drivers/media/platform/verisilicon/imx8m_vpu_hw.c index 77f574fdfa77..b390228fd3b4 100644 --- a/drivers/media/platform/verisilicon/imx8m_vpu_hw.c +++ b/drivers/media/platform/verisilicon/imx8m_vpu_hw.c @@ -162,12 +162,39 @@ static const struct hantro_fmt imx8m_vpu_g2_postproc_fmts[] = { .step_height = MB_DIM, }, }, + { + .fourcc = V4L2_PIX_FMT_P010, + .codec_mode = HANTRO_MODE_NONE, + .postprocessed = true, + .frmsize = { + .min_width = FMT_MIN_WIDTH, + .max_width = FMT_UHD_WIDTH, + .step_width = MB_DIM, + .min_height = FMT_MIN_HEIGHT, + .max_height = FMT_UHD_HEIGHT, + .step_height = MB_DIM, + }, + }, }; static const struct hantro_fmt imx8m_vpu_g2_dec_fmts[] = { { .fourcc = V4L2_PIX_FMT_NV12_4L4, .codec_mode = HANTRO_MODE_NONE, + .match_depth = true, + .frmsize = { + .min_width = FMT_MIN_WIDTH, + .max_width = FMT_UHD_WIDTH, + .step_width = TILE_MB_DIM, + .min_height = FMT_MIN_HEIGHT, + .max_height = FMT_UHD_HEIGHT, + .step_height = TILE_MB_DIM, + }, + }, + { + .fourcc = V4L2_PIX_FMT_P010_4L4, + .codec_mode = HANTRO_MODE_NONE, + .match_depth = true, .frmsize = { .min_width = FMT_MIN_WIDTH, .max_width = FMT_UHD_WIDTH, -- cgit From 39434d42e87fe23bff9f39d7b7485ad7764297d1 Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Mon, 29 Aug 2022 18:21:59 +0200 Subject: media: hantro: Allows luma and chroma depth to be different Luma and chroma depth are set on different hardware registers. Even if they aren't identical the bitstream can be compliant to HEVC specifications and decoded by the hardware. With this patch TSUNEQBD_A_MAIN10_Technicolor_2 conformance test is successfully decoded. Signed-off-by: Benjamin Gaignard Reviewed-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/verisilicon/hantro_drv.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/verisilicon/hantro_drv.c b/drivers/media/platform/verisilicon/hantro_drv.c index 7c75922e2e98..8cb4a68c9119 100644 --- a/drivers/media/platform/verisilicon/hantro_drv.c +++ b/drivers/media/platform/verisilicon/hantro_drv.c @@ -271,9 +271,6 @@ static int hantro_try_ctrl(struct v4l2_ctrl *ctrl) } else if (ctrl->id == V4L2_CID_STATELESS_HEVC_SPS) { const struct v4l2_ctrl_hevc_sps *sps = ctrl->p_new.p_hevc_sps; - if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8) - /* Luma and chroma bit depth mismatch */ - return -EINVAL; if (sps->bit_depth_luma_minus8 != 0 && sps->bit_depth_luma_minus8 != 2) /* Only 8-bit and 10-bit are supported */ return -EINVAL; -- cgit From ff37bc8c7099b673e9838bfbd0de78eff740316b Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 5 Sep 2022 11:52:35 +0200 Subject: media: sun6i-mipi-csi2: Depend on PHY_SUN6I_MIPI_DPHY PHY_SUN6I_MIPI_DPHY is not a freely selectable option and so may not always be available. Depend on it instead. Fixes: 94d7fd9692b5 ("media: sunxi: Depend on GENERIC_PHY_MIPI_DPHY") Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig b/drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig index eb982466abd3..4d072abdfb70 100644 --- a/drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig +++ b/drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig @@ -4,10 +4,10 @@ config VIDEO_SUN6I_MIPI_CSI2 depends on V4L_PLATFORM_DRIVERS && VIDEO_DEV depends on ARCH_SUNXI || COMPILE_TEST depends on PM && COMMON_CLK + depends on PHY_SUN6I_MIPI_DPHY select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE - select PHY_SUN6I_MIPI_DPHY select GENERIC_PHY_MIPI_DPHY select REGMAP_MMIO help -- cgit From b7319e2bd7bd7740a405719727e6fc01be1363ef Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 31 Aug 2022 16:13:27 +0200 Subject: media: mc: entity: Rename streaming_count -> start_count 'streaming_count' is a bit misleading name, as the count is increased with media_pipeline_start(). Let's rename it to 'start_count' instead. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c index c66963a2ccd9..6ef09579dc21 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c @@ -926,7 +926,7 @@ static void rkisp1_pipeline_stream_disable(struct rkisp1_capture *cap) * If the other capture is streaming, isp and sensor nodes shouldn't * be disabled, skip them. */ - if (rkisp1->pipe.streaming_count < 2) + if (rkisp1->pipe.start_count < 2) v4l2_subdev_call(&rkisp1->isp.sd, video, s_stream, false); v4l2_subdev_call(&rkisp1->resizer_devs[cap->id].sd, video, s_stream, @@ -956,7 +956,7 @@ static int rkisp1_pipeline_stream_enable(struct rkisp1_capture *cap) * If the other capture is streaming, isp and sensor nodes are already * enabled, skip them. */ - if (rkisp1->pipe.streaming_count > 1) + if (rkisp1->pipe.start_count > 1) return 0; ret = v4l2_subdev_call(&rkisp1->isp.sd, video, s_stream, true); -- cgit From 72b603357ae461c0f19ca05d6624b4afd5c74b47 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 31 Aug 2022 16:13:31 +0200 Subject: media: mc: entity: Add media_entity_pipeline() to access the media pipeline Replace direct access to the pipe field in drivers with a new helper function. This will allow easier refactoring of media pipeline handling in the MC core behind the scenes without affecting drivers. Signed-off-by: Laurent Pinchart Signed-off-by: Tomi Valkeinen Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/renesas/rcar-vin/rcar-core.c | 5 ++--- drivers/media/platform/renesas/rcar-vin/rcar-dma.c | 2 +- drivers/media/platform/ti/omap3isp/isp.c | 4 +--- drivers/media/platform/ti/omap3isp/ispvideo.c | 3 +-- drivers/media/platform/ti/omap3isp/ispvideo.h | 11 +++++++++-- drivers/media/platform/xilinx/xilinx-dma.c | 3 +-- drivers/media/platform/xilinx/xilinx-dma.h | 7 ++++++- 7 files changed, 21 insertions(+), 14 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-core.c b/drivers/media/platform/renesas/rcar-vin/rcar-core.c index 968a74234e92..2f7daa853ed8 100644 --- a/drivers/media/platform/renesas/rcar-vin/rcar-core.c +++ b/drivers/media/platform/renesas/rcar-vin/rcar-core.c @@ -786,9 +786,8 @@ static int rvin_csi2_link_notify(struct media_link *link, u32 flags, return 0; /* - * Don't allow link changes if any entity in the graph is - * streaming, modifying the CHSEL register fields can disrupt - * running streams. + * Don't allow link changes if any stream in the graph is active as + * modifying the CHSEL register fields can disrupt running streams. */ media_device_for_each_entity(entity, &group->mdev) if (media_entity_is_streaming(entity)) diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-dma.c b/drivers/media/platform/renesas/rcar-vin/rcar-dma.c index 8d37fbdc266a..e72bc6fa049f 100644 --- a/drivers/media/platform/renesas/rcar-vin/rcar-dma.c +++ b/drivers/media/platform/renesas/rcar-vin/rcar-dma.c @@ -1281,7 +1281,7 @@ static int rvin_set_stream(struct rvin_dev *vin, int on) */ mdev = vin->vdev.entity.graph_obj.mdev; mutex_lock(&mdev->graph_mutex); - pipe = sd->entity.pipe ? sd->entity.pipe : &vin->vdev.pipe; + pipe = media_entity_pipeline(&sd->entity) ? : &vin->vdev.pipe; ret = __media_pipeline_start(&vin->vdev.entity, pipe); mutex_unlock(&mdev->graph_mutex); if (ret) diff --git a/drivers/media/platform/ti/omap3isp/isp.c b/drivers/media/platform/ti/omap3isp/isp.c index a6052df9bb19..24d2383400b0 100644 --- a/drivers/media/platform/ti/omap3isp/isp.c +++ b/drivers/media/platform/ti/omap3isp/isp.c @@ -937,10 +937,8 @@ static int isp_pipeline_is_last(struct media_entity *me) struct isp_pipeline *pipe; struct media_pad *pad; - if (!me->pipe) - return 0; pipe = to_isp_pipeline(me); - if (pipe->stream_state == ISP_PIPELINE_STREAM_STOPPED) + if (!pipe || pipe->stream_state == ISP_PIPELINE_STREAM_STOPPED) return 0; pad = media_pad_remote_pad_first(&pipe->output->pad); return pad->entity == me; diff --git a/drivers/media/platform/ti/omap3isp/ispvideo.c b/drivers/media/platform/ti/omap3isp/ispvideo.c index cc9a97d5d505..2e7f90603a5a 100644 --- a/drivers/media/platform/ti/omap3isp/ispvideo.c +++ b/drivers/media/platform/ti/omap3isp/ispvideo.c @@ -1093,8 +1093,7 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) /* Start streaming on the pipeline. No link touching an entity in the * pipeline can be activated or deactivated once streaming is started. */ - pipe = video->video.entity.pipe - ? to_isp_pipeline(&video->video.entity) : &video->pipe; + pipe = to_isp_pipeline(&video->video.entity) ? : &video->pipe; ret = media_entity_enum_init(&pipe->ent_enum, &video->isp->media_dev); if (ret) diff --git a/drivers/media/platform/ti/omap3isp/ispvideo.h b/drivers/media/platform/ti/omap3isp/ispvideo.h index a0908670c0cf..1d23df576e6b 100644 --- a/drivers/media/platform/ti/omap3isp/ispvideo.h +++ b/drivers/media/platform/ti/omap3isp/ispvideo.h @@ -99,8 +99,15 @@ struct isp_pipeline { unsigned int external_width; }; -#define to_isp_pipeline(__e) \ - container_of((__e)->pipe, struct isp_pipeline, pipe) +static inline struct isp_pipeline *to_isp_pipeline(struct media_entity *entity) +{ + struct media_pipeline *pipe = media_entity_pipeline(entity); + + if (!pipe) + return NULL; + + return container_of(pipe, struct isp_pipeline, pipe); +} static inline int isp_pipeline_ready(struct isp_pipeline *pipe) { diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c index 2d1ef7a25c33..3a4d62be0f27 100644 --- a/drivers/media/platform/xilinx/xilinx-dma.c +++ b/drivers/media/platform/xilinx/xilinx-dma.c @@ -402,8 +402,7 @@ static int xvip_dma_start_streaming(struct vb2_queue *vq, unsigned int count) * Use the pipeline object embedded in the first DMA object that starts * streaming. */ - pipe = dma->video.entity.pipe - ? to_xvip_pipeline(&dma->video.entity) : &dma->pipe; + pipe = to_xvip_pipeline(&dma->video.entity) ? : &dma->pipe; ret = media_pipeline_start(&dma->video.entity, &pipe->pipe); if (ret < 0) diff --git a/drivers/media/platform/xilinx/xilinx-dma.h b/drivers/media/platform/xilinx/xilinx-dma.h index 2378bdae57ae..3ea10f6b0bb9 100644 --- a/drivers/media/platform/xilinx/xilinx-dma.h +++ b/drivers/media/platform/xilinx/xilinx-dma.h @@ -47,7 +47,12 @@ struct xvip_pipeline { static inline struct xvip_pipeline *to_xvip_pipeline(struct media_entity *e) { - return container_of(e->pipe, struct xvip_pipeline, pipe); + struct media_pipeline *pipe = media_entity_pipeline(e); + + if (!pipe) + return NULL; + + return container_of(pipe, struct xvip_pipeline, pipe); } /** -- cgit From 12cecbf9150f67b0ce7d88bc2e243e67637726c2 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 31 Aug 2022 16:13:33 +0200 Subject: media: drivers: use video device pipeline start/stop Convert the media drivers to use video device based pipeline start/stop where possible. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/camss/camss-video.c | 6 +++--- drivers/media/platform/renesas/rcar-vin/rcar-dma.c | 6 +++--- drivers/media/platform/renesas/vsp1/vsp1_video.c | 6 +++--- drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c | 10 +++++----- drivers/media/platform/samsung/exynos4-is/fimc-capture.c | 9 ++++----- drivers/media/platform/samsung/exynos4-is/fimc-isp-video.c | 9 ++++----- drivers/media/platform/samsung/exynos4-is/fimc-lite.c | 9 ++++----- drivers/media/platform/st/stm32/stm32-dcmi.c | 6 +++--- drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c | 6 +++--- drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c | 6 +++--- drivers/media/platform/ti/cal/cal-video.c | 6 +++--- drivers/media/platform/ti/omap3isp/ispvideo.c | 6 +++--- drivers/media/platform/xilinx/xilinx-dma.c | 6 +++--- 13 files changed, 44 insertions(+), 47 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c index 290df04c4d02..81fb3a5bc1d5 100644 --- a/drivers/media/platform/qcom/camss/camss-video.c +++ b/drivers/media/platform/qcom/camss/camss-video.c @@ -493,7 +493,7 @@ static int video_start_streaming(struct vb2_queue *q, unsigned int count) struct v4l2_subdev *subdev; int ret; - ret = media_pipeline_start(&vdev->entity, &video->pipe); + ret = video_device_pipeline_start(vdev, &video->pipe); if (ret < 0) return ret; @@ -522,7 +522,7 @@ static int video_start_streaming(struct vb2_queue *q, unsigned int count) return 0; error: - media_pipeline_stop(&vdev->entity); + video_device_pipeline_stop(vdev); video->ops->flush_buffers(video, VB2_BUF_STATE_QUEUED); @@ -553,7 +553,7 @@ static void video_stop_streaming(struct vb2_queue *q) v4l2_subdev_call(subdev, video, s_stream, 0); } - media_pipeline_stop(&vdev->entity); + video_device_pipeline_stop(vdev); video->ops->flush_buffers(video, VB2_BUF_STATE_ERROR); } diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-dma.c b/drivers/media/platform/renesas/rcar-vin/rcar-dma.c index e72bc6fa049f..879dd02bbb55 100644 --- a/drivers/media/platform/renesas/rcar-vin/rcar-dma.c +++ b/drivers/media/platform/renesas/rcar-vin/rcar-dma.c @@ -1265,7 +1265,7 @@ static int rvin_set_stream(struct rvin_dev *vin, int on) sd = media_entity_to_v4l2_subdev(pad->entity); if (!on) { - media_pipeline_stop(&vin->vdev.entity); + video_device_pipeline_stop(&vin->vdev); return v4l2_subdev_call(sd, video, s_stream, 0); } @@ -1282,7 +1282,7 @@ static int rvin_set_stream(struct rvin_dev *vin, int on) mdev = vin->vdev.entity.graph_obj.mdev; mutex_lock(&mdev->graph_mutex); pipe = media_entity_pipeline(&sd->entity) ? : &vin->vdev.pipe; - ret = __media_pipeline_start(&vin->vdev.entity, pipe); + ret = __video_device_pipeline_start(&vin->vdev, pipe); mutex_unlock(&mdev->graph_mutex); if (ret) return ret; @@ -1291,7 +1291,7 @@ static int rvin_set_stream(struct rvin_dev *vin, int on) if (ret == -ENOIOCTLCMD) ret = 0; if (ret) - media_pipeline_stop(&vin->vdev.entity); + video_device_pipeline_stop(&vin->vdev); return ret; } diff --git a/drivers/media/platform/renesas/vsp1/vsp1_video.c b/drivers/media/platform/renesas/vsp1/vsp1_video.c index df1606b49d77..9d24647c8f32 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_video.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_video.c @@ -927,7 +927,7 @@ static void vsp1_video_stop_streaming(struct vb2_queue *vq) } mutex_unlock(&pipe->lock); - media_pipeline_stop(&video->video.entity); + video_device_pipeline_stop(&video->video); vsp1_video_release_buffers(video); vsp1_video_pipeline_put(pipe); } @@ -1046,7 +1046,7 @@ vsp1_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) return PTR_ERR(pipe); } - ret = __media_pipeline_start(&video->video.entity, &pipe->pipe); + ret = __video_device_pipeline_start(&video->video, &pipe->pipe); if (ret < 0) { mutex_unlock(&mdev->graph_mutex); goto err_pipe; @@ -1070,7 +1070,7 @@ vsp1_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) return 0; err_stop: - media_pipeline_stop(&video->video.entity); + video_device_pipeline_stop(&video->video); err_pipe: vsp1_video_pipeline_put(pipe); return ret; diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c index 6ef09579dc21..d4540684ea9a 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c @@ -913,7 +913,7 @@ static void rkisp1_cap_stream_disable(struct rkisp1_capture *cap) * * Call s_stream(false) in the reverse order from * rkisp1_pipeline_stream_enable() and disable the DMA engine. - * Should be called before media_pipeline_stop() + * Should be called before video_device_pipeline_stop() */ static void rkisp1_pipeline_stream_disable(struct rkisp1_capture *cap) __must_hold(&cap->rkisp1->stream_lock) @@ -937,7 +937,7 @@ static void rkisp1_pipeline_stream_disable(struct rkisp1_capture *cap) * rkisp1_pipeline_stream_enable - enable nodes in the pipeline * * Enable the DMA Engine and call s_stream(true) through the pipeline. - * Should be called after media_pipeline_start() + * Should be called after video_device_pipeline_start() */ static int rkisp1_pipeline_stream_enable(struct rkisp1_capture *cap) __must_hold(&cap->rkisp1->stream_lock) @@ -994,7 +994,7 @@ static void rkisp1_vb2_stop_streaming(struct vb2_queue *queue) rkisp1_dummy_buf_destroy(cap); - media_pipeline_stop(&node->vdev.entity); + video_device_pipeline_stop(&node->vdev); mutex_unlock(&cap->rkisp1->stream_lock); } @@ -1008,7 +1008,7 @@ rkisp1_vb2_start_streaming(struct vb2_queue *queue, unsigned int count) mutex_lock(&cap->rkisp1->stream_lock); - ret = media_pipeline_start(entity, &cap->rkisp1->pipe); + ret = video_device_pipeline_start(&cap->vnode.vdev, &cap->rkisp1->pipe); if (ret) { dev_err(cap->rkisp1->dev, "start pipeline failed %d\n", ret); goto err_ret_buffers; @@ -1044,7 +1044,7 @@ err_pipe_pm_put: err_destroy_dummy: rkisp1_dummy_buf_destroy(cap); err_pipeline_stop: - media_pipeline_stop(entity); + video_device_pipeline_stop(&cap->vnode.vdev); err_ret_buffers: rkisp1_return_all_buffers(cap, VB2_BUF_STATE_QUEUED); mutex_unlock(&cap->rkisp1->stream_lock); diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-capture.c b/drivers/media/platform/samsung/exynos4-is/fimc-capture.c index 03638c8f772d..e3b95a2b7e04 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-capture.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-capture.c @@ -524,7 +524,7 @@ static int fimc_capture_release(struct file *file) mutex_lock(&fimc->lock); if (close && vc->streaming) { - media_pipeline_stop(&vc->ve.vdev.entity); + video_device_pipeline_stop(&vc->ve.vdev); vc->streaming = false; } @@ -1176,7 +1176,6 @@ static int fimc_cap_streamon(struct file *file, void *priv, { struct fimc_dev *fimc = video_drvdata(file); struct fimc_vid_cap *vc = &fimc->vid_cap; - struct media_entity *entity = &vc->ve.vdev.entity; struct fimc_source_info *si = NULL; struct v4l2_subdev *sd; int ret; @@ -1184,7 +1183,7 @@ static int fimc_cap_streamon(struct file *file, void *priv, if (fimc_capture_active(fimc)) return -EBUSY; - ret = media_pipeline_start(entity, &vc->ve.pipe->mp); + ret = video_device_pipeline_start(&vc->ve.vdev, &vc->ve.pipe->mp); if (ret < 0) return ret; @@ -1218,7 +1217,7 @@ static int fimc_cap_streamon(struct file *file, void *priv, } err_p_stop: - media_pipeline_stop(entity); + video_device_pipeline_stop(&vc->ve.vdev); return ret; } @@ -1234,7 +1233,7 @@ static int fimc_cap_streamoff(struct file *file, void *priv, return ret; if (vc->streaming) { - media_pipeline_stop(&vc->ve.vdev.entity); + video_device_pipeline_stop(&vc->ve.vdev); vc->streaming = false; } diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-isp-video.c b/drivers/media/platform/samsung/exynos4-is/fimc-isp-video.c index 8f12240b0eb7..f6a302fa8d37 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-isp-video.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-isp-video.c @@ -312,7 +312,7 @@ static int isp_video_release(struct file *file) is_singular_file = v4l2_fh_is_singular_file(file); if (is_singular_file && ivc->streaming) { - media_pipeline_stop(entity); + video_device_pipeline_stop(&ivc->ve.vdev); ivc->streaming = 0; } @@ -490,10 +490,9 @@ static int isp_video_streamon(struct file *file, void *priv, { struct fimc_isp *isp = video_drvdata(file); struct exynos_video_entity *ve = &isp->video_capture.ve; - struct media_entity *me = &ve->vdev.entity; int ret; - ret = media_pipeline_start(me, &ve->pipe->mp); + ret = video_device_pipeline_start(&ve->vdev, &ve->pipe->mp); if (ret < 0) return ret; @@ -508,7 +507,7 @@ static int isp_video_streamon(struct file *file, void *priv, isp->video_capture.streaming = 1; return 0; p_stop: - media_pipeline_stop(me); + video_device_pipeline_stop(&ve->vdev); return ret; } @@ -523,7 +522,7 @@ static int isp_video_streamoff(struct file *file, void *priv, if (ret < 0) return ret; - media_pipeline_stop(&video->ve.vdev.entity); + video_device_pipeline_stop(&video->ve.vdev); video->streaming = 0; return 0; } diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-lite.c b/drivers/media/platform/samsung/exynos4-is/fimc-lite.c index 41b0a4a5929a..e185a40305a8 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-lite.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-lite.c @@ -516,7 +516,7 @@ static int fimc_lite_release(struct file *file) if (v4l2_fh_is_singular_file(file) && atomic_read(&fimc->out_path) == FIMC_IO_DMA) { if (fimc->streaming) { - media_pipeline_stop(entity); + video_device_pipeline_stop(&fimc->ve.vdev); fimc->streaming = false; } fimc_lite_stop_capture(fimc, false); @@ -812,13 +812,12 @@ static int fimc_lite_streamon(struct file *file, void *priv, enum v4l2_buf_type type) { struct fimc_lite *fimc = video_drvdata(file); - struct media_entity *entity = &fimc->ve.vdev.entity; int ret; if (fimc_lite_active(fimc)) return -EBUSY; - ret = media_pipeline_start(entity, &fimc->ve.pipe->mp); + ret = video_device_pipeline_start(&fimc->ve.vdev, &fimc->ve.pipe->mp); if (ret < 0) return ret; @@ -835,7 +834,7 @@ static int fimc_lite_streamon(struct file *file, void *priv, } err_p_stop: - media_pipeline_stop(entity); + video_device_pipeline_stop(&fimc->ve.vdev); return 0; } @@ -849,7 +848,7 @@ static int fimc_lite_streamoff(struct file *file, void *priv, if (ret < 0) return ret; - media_pipeline_stop(&fimc->ve.vdev.entity); + video_device_pipeline_stop(&fimc->ve.vdev); fimc->streaming = false; return 0; } diff --git a/drivers/media/platform/st/stm32/stm32-dcmi.c b/drivers/media/platform/st/stm32/stm32-dcmi.c index 2ca95ab2b0fe..37458d4d9564 100644 --- a/drivers/media/platform/st/stm32/stm32-dcmi.c +++ b/drivers/media/platform/st/stm32/stm32-dcmi.c @@ -751,7 +751,7 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) goto err_unlocked; } - ret = media_pipeline_start(&dcmi->vdev->entity, &dcmi->pipeline); + ret = video_device_pipeline_start(dcmi->vdev, &dcmi->pipeline); if (ret < 0) { dev_err(dcmi->dev, "%s: Failed to start streaming, media pipeline start error (%d)\n", __func__, ret); @@ -865,7 +865,7 @@ err_pipeline_stop: dcmi_pipeline_stop(dcmi); err_media_pipeline_stop: - media_pipeline_stop(&dcmi->vdev->entity); + video_device_pipeline_stop(dcmi->vdev); err_pm_put: pm_runtime_put(dcmi->dev); @@ -892,7 +892,7 @@ static void dcmi_stop_streaming(struct vb2_queue *vq) dcmi_pipeline_stop(dcmi); - media_pipeline_stop(&dcmi->vdev->entity); + video_device_pipeline_stop(dcmi->vdev); spin_lock_irq(&dcmi->irqlock); diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c index 0912a1b6d525..17ad9a3caaa5 100644 --- a/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c +++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c @@ -266,7 +266,7 @@ static int sun4i_csi_start_streaming(struct vb2_queue *vq, unsigned int count) goto err_clear_dma_queue; } - ret = media_pipeline_start(&csi->vdev.entity, &csi->vdev.pipe); + ret = video_device_pipeline_start(&csi->vdev, &csi->vdev.pipe); if (ret < 0) goto err_free_scratch_buffer; @@ -330,7 +330,7 @@ err_disable_device: sun4i_csi_capture_stop(csi); err_disable_pipeline: - media_pipeline_stop(&csi->vdev.entity); + video_device_pipeline_stop(&csi->vdev); err_free_scratch_buffer: dma_free_coherent(csi->dev, csi->scratch.size, csi->scratch.vaddr, @@ -359,7 +359,7 @@ static void sun4i_csi_stop_streaming(struct vb2_queue *vq) return_all_buffers(csi, VB2_BUF_STATE_ERROR); spin_unlock_irqrestore(&csi->qlock, flags); - media_pipeline_stop(&csi->vdev.entity); + video_device_pipeline_stop(&csi->vdev); dma_free_coherent(csi->dev, csi->scratch.size, csi->scratch.vaddr, csi->scratch.paddr); diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c index 74d64a20ba5b..a6873fdb8438 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c @@ -141,7 +141,7 @@ static int sun6i_video_start_streaming(struct vb2_queue *vq, unsigned int count) video->sequence = 0; - ret = media_pipeline_start(&video->vdev.entity, &video->vdev.pipe); + ret = video_device_pipeline_start(&video->vdev, &video->vdev.pipe); if (ret < 0) goto clear_dma_queue; @@ -207,7 +207,7 @@ static int sun6i_video_start_streaming(struct vb2_queue *vq, unsigned int count) stop_csi_stream: sun6i_csi_set_stream(video->csi, false); stop_media_pipeline: - media_pipeline_stop(&video->vdev.entity); + video_device_pipeline_stop(&video->vdev); clear_dma_queue: spin_lock_irqsave(&video->dma_queue_lock, flags); list_for_each_entry(buf, &video->dma_queue, list) @@ -231,7 +231,7 @@ static void sun6i_video_stop_streaming(struct vb2_queue *vq) sun6i_csi_set_stream(video->csi, false); - media_pipeline_stop(&video->vdev.entity); + video_device_pipeline_stop(&video->vdev); /* Release all active buffers */ spin_lock_irqsave(&video->dma_queue_lock, flags); diff --git a/drivers/media/platform/ti/cal/cal-video.c b/drivers/media/platform/ti/cal/cal-video.c index 21e3d0aabf70..0ac54d7618e3 100644 --- a/drivers/media/platform/ti/cal/cal-video.c +++ b/drivers/media/platform/ti/cal/cal-video.c @@ -708,7 +708,7 @@ static int cal_start_streaming(struct vb2_queue *vq, unsigned int count) dma_addr_t addr; int ret; - ret = media_pipeline_start(&ctx->vdev.entity, &ctx->phy->pipe); + ret = video_device_pipeline_start(&ctx->vdev, &ctx->phy->pipe); if (ret < 0) { ctx_err(ctx, "Failed to start media pipeline: %d\n", ret); goto error_release_buffers; @@ -761,7 +761,7 @@ error_stop: cal_ctx_unprepare(ctx); error_pipeline: - media_pipeline_stop(&ctx->vdev.entity); + video_device_pipeline_stop(&ctx->vdev); error_release_buffers: cal_release_buffers(ctx, VB2_BUF_STATE_QUEUED); @@ -782,7 +782,7 @@ static void cal_stop_streaming(struct vb2_queue *vq) cal_release_buffers(ctx, VB2_BUF_STATE_ERROR); - media_pipeline_stop(&ctx->vdev.entity); + video_device_pipeline_stop(&ctx->vdev); } static const struct vb2_ops cal_video_qops = { diff --git a/drivers/media/platform/ti/omap3isp/ispvideo.c b/drivers/media/platform/ti/omap3isp/ispvideo.c index 2e7f90603a5a..3e5348c63773 100644 --- a/drivers/media/platform/ti/omap3isp/ispvideo.c +++ b/drivers/media/platform/ti/omap3isp/ispvideo.c @@ -1103,7 +1103,7 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) pipe->l3_ick = clk_get_rate(video->isp->clock[ISP_CLK_L3_ICK]); pipe->max_rate = pipe->l3_ick; - ret = media_pipeline_start(&video->video.entity, &pipe->pipe); + ret = video_device_pipeline_start(&video->video, &pipe->pipe); if (ret < 0) goto err_pipeline_start; @@ -1160,7 +1160,7 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) return 0; err_check_format: - media_pipeline_stop(&video->video.entity); + video_device_pipeline_stop(&video->video); err_pipeline_start: /* TODO: Implement PM QoS */ /* The DMA queue must be emptied here, otherwise CCDC interrupts that @@ -1227,7 +1227,7 @@ isp_video_streamoff(struct file *file, void *fh, enum v4l2_buf_type type) video->error = false; /* TODO: Implement PM QoS */ - media_pipeline_stop(&video->video.entity); + video_device_pipeline_stop(&video->video); media_entity_enum_cleanup(&pipe->ent_enum); diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c index 3a4d62be0f27..9a177337e934 100644 --- a/drivers/media/platform/xilinx/xilinx-dma.c +++ b/drivers/media/platform/xilinx/xilinx-dma.c @@ -404,7 +404,7 @@ static int xvip_dma_start_streaming(struct vb2_queue *vq, unsigned int count) */ pipe = to_xvip_pipeline(&dma->video.entity) ? : &dma->pipe; - ret = media_pipeline_start(&dma->video.entity, &pipe->pipe); + ret = video_device_pipeline_start(&dma->video, &pipe->pipe); if (ret < 0) goto error; @@ -430,7 +430,7 @@ static int xvip_dma_start_streaming(struct vb2_queue *vq, unsigned int count) return 0; error_stop: - media_pipeline_stop(&dma->video.entity); + video_device_pipeline_stop(&dma->video); error: /* Give back all queued buffers to videobuf2. */ @@ -458,7 +458,7 @@ static void xvip_dma_stop_streaming(struct vb2_queue *vq) /* Cleanup the pipeline and mark it as being stopped. */ xvip_pipeline_cleanup(pipe); - media_pipeline_stop(&dma->video.entity); + video_device_pipeline_stop(&dma->video); /* Give back all queued buffers to videobuf2. */ spin_lock_irq(&dma->queued_lock); -- cgit From 98d79dc34798cb5b3bdbc49cfc17ff63b3044b64 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 31 Aug 2022 16:13:34 +0200 Subject: media: drivers: use video_device_pipeline() Use video_device_pipeline() in the drivers instead of media_entity_pipeline(). Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/xilinx/xilinx-dma.c | 4 ++-- drivers/media/platform/xilinx/xilinx-dma.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c index 9a177337e934..0a7fd8642a65 100644 --- a/drivers/media/platform/xilinx/xilinx-dma.c +++ b/drivers/media/platform/xilinx/xilinx-dma.c @@ -402,7 +402,7 @@ static int xvip_dma_start_streaming(struct vb2_queue *vq, unsigned int count) * Use the pipeline object embedded in the first DMA object that starts * streaming. */ - pipe = to_xvip_pipeline(&dma->video.entity) ? : &dma->pipe; + pipe = to_xvip_pipeline(&dma->video) ? : &dma->pipe; ret = video_device_pipeline_start(&dma->video, &pipe->pipe); if (ret < 0) @@ -447,7 +447,7 @@ error: static void xvip_dma_stop_streaming(struct vb2_queue *vq) { struct xvip_dma *dma = vb2_get_drv_priv(vq); - struct xvip_pipeline *pipe = to_xvip_pipeline(&dma->video.entity); + struct xvip_pipeline *pipe = to_xvip_pipeline(&dma->video); struct xvip_dma_buffer *buf, *nbuf; /* Stop the pipeline. */ diff --git a/drivers/media/platform/xilinx/xilinx-dma.h b/drivers/media/platform/xilinx/xilinx-dma.h index 3ea10f6b0bb9..9c6d4c18d1a9 100644 --- a/drivers/media/platform/xilinx/xilinx-dma.h +++ b/drivers/media/platform/xilinx/xilinx-dma.h @@ -45,9 +45,9 @@ struct xvip_pipeline { struct xvip_dma *output; }; -static inline struct xvip_pipeline *to_xvip_pipeline(struct media_entity *e) +static inline struct xvip_pipeline *to_xvip_pipeline(struct video_device *vdev) { - struct media_pipeline *pipe = media_entity_pipeline(e); + struct media_pipeline *pipe = video_device_pipeline(vdev); if (!pipe) return NULL; -- cgit From 6eaff06ad064f5182eda361c3615a0e10c032f74 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 31 Aug 2022 16:13:36 +0200 Subject: media: drivers: use video_device_pipeline_alloc_start() Use video_device_pipeline_alloc_start() instead of manually allocating/managing the media pipeline storage. Signed-off-by: Tomi Valkeinen Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/renesas/rcar-vin/rcar-dma.c | 14 +------------- drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c | 2 +- drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c | 2 +- drivers/media/platform/ti/cal/cal-video.c | 2 +- drivers/media/platform/ti/cal/cal.h | 1 - 5 files changed, 4 insertions(+), 17 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-dma.c b/drivers/media/platform/renesas/rcar-vin/rcar-dma.c index 879dd02bbb55..3aea96d85165 100644 --- a/drivers/media/platform/renesas/rcar-vin/rcar-dma.c +++ b/drivers/media/platform/renesas/rcar-vin/rcar-dma.c @@ -1244,8 +1244,6 @@ static int rvin_mc_validate_format(struct rvin_dev *vin, struct v4l2_subdev *sd, static int rvin_set_stream(struct rvin_dev *vin, int on) { - struct media_pipeline *pipe; - struct media_device *mdev; struct v4l2_subdev *sd; struct media_pad *pad; int ret; @@ -1273,17 +1271,7 @@ static int rvin_set_stream(struct rvin_dev *vin, int on) if (ret) return ret; - /* - * The graph lock needs to be taken to protect concurrent - * starts of multiple VIN instances as they might share - * a common subdevice down the line and then should use - * the same pipe. - */ - mdev = vin->vdev.entity.graph_obj.mdev; - mutex_lock(&mdev->graph_mutex); - pipe = media_entity_pipeline(&sd->entity) ? : &vin->vdev.pipe; - ret = __video_device_pipeline_start(&vin->vdev, pipe); - mutex_unlock(&mdev->graph_mutex); + ret = video_device_pipeline_alloc_start(&vin->vdev); if (ret) return ret; diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c index 17ad9a3caaa5..a3e826a755fc 100644 --- a/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c +++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c @@ -266,7 +266,7 @@ static int sun4i_csi_start_streaming(struct vb2_queue *vq, unsigned int count) goto err_clear_dma_queue; } - ret = video_device_pipeline_start(&csi->vdev, &csi->vdev.pipe); + ret = video_device_pipeline_alloc_start(&csi->vdev); if (ret < 0) goto err_free_scratch_buffer; diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c index a6873fdb8438..da4b7f9557a1 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c @@ -141,7 +141,7 @@ static int sun6i_video_start_streaming(struct vb2_queue *vq, unsigned int count) video->sequence = 0; - ret = video_device_pipeline_start(&video->vdev, &video->vdev.pipe); + ret = video_device_pipeline_alloc_start(&video->vdev); if (ret < 0) goto clear_dma_queue; diff --git a/drivers/media/platform/ti/cal/cal-video.c b/drivers/media/platform/ti/cal/cal-video.c index 0ac54d7618e3..4eade409d5d3 100644 --- a/drivers/media/platform/ti/cal/cal-video.c +++ b/drivers/media/platform/ti/cal/cal-video.c @@ -708,7 +708,7 @@ static int cal_start_streaming(struct vb2_queue *vq, unsigned int count) dma_addr_t addr; int ret; - ret = video_device_pipeline_start(&ctx->vdev, &ctx->phy->pipe); + ret = video_device_pipeline_alloc_start(&ctx->vdev); if (ret < 0) { ctx_err(ctx, "Failed to start media pipeline: %d\n", ret); goto error_release_buffers; diff --git a/drivers/media/platform/ti/cal/cal.h b/drivers/media/platform/ti/cal/cal.h index 80f2c9c73c71..de73d6d21b6f 100644 --- a/drivers/media/platform/ti/cal/cal.h +++ b/drivers/media/platform/ti/cal/cal.h @@ -174,7 +174,6 @@ struct cal_camerarx { struct device_node *source_ep_node; struct device_node *source_node; struct v4l2_subdev *source; - struct media_pipeline pipe; struct v4l2_subdev subdev; struct media_pad pads[CAL_CAMERARX_NUM_PADS]; -- cgit From 9e3576a1ae2bb67c4d09d5e6c002fb793c300b58 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 31 Aug 2022 16:13:39 +0200 Subject: media: mc: convert pipeline funcs to take media_pad Now that the pipeline is stored into pads instead of entities, we can change the relevant functions to take pads instead of entities. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/samsung/s3c-camif/camif-capture.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/samsung/s3c-camif/camif-capture.c b/drivers/media/platform/samsung/s3c-camif/camif-capture.c index c2d8f1e425d8..db106ebdf870 100644 --- a/drivers/media/platform/samsung/s3c-camif/camif-capture.c +++ b/drivers/media/platform/samsung/s3c-camif/camif-capture.c @@ -848,13 +848,13 @@ static int s3c_camif_streamon(struct file *file, void *priv, if (s3c_vp_active(vp)) return 0; - ret = media_pipeline_start(sensor, camif->m_pipeline); + ret = media_pipeline_start(sensor->pads, camif->m_pipeline); if (ret < 0) return ret; ret = camif_pipeline_validate(camif); if (ret < 0) { - media_pipeline_stop(sensor); + media_pipeline_stop(sensor->pads); return ret; } @@ -878,7 +878,7 @@ static int s3c_camif_streamoff(struct file *file, void *priv, ret = vb2_streamoff(&vp->vb_queue, type); if (ret == 0) - media_pipeline_stop(&camif->sensor.sd->entity); + media_pipeline_stop(camif->sensor.sd->entity.pads); return ret; } -- cgit From 466c1e6d05003707e8baa16668e7bc287d875d5e Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Tue, 23 Aug 2022 09:42:01 +0200 Subject: media: sunxi: Fix some error handling path of sun8i_a83t_mipi_csi2_probe() Release some resources in the error handling path of the probe and of sun8i_a83t_mipi_csi2_resources_setup(), as already done in the remove function. Fixes: 576d196c522b ("media: sunxi: Add support for the A83T MIPI CSI-2 controller") Signed-off-by: Christophe JAILLET Acked-by: Paul Kocialkowski Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c | 23 +++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c index d052ee77ef0a..b032ec13a683 100644 --- a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c +++ b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c @@ -719,13 +719,15 @@ sun8i_a83t_mipi_csi2_resources_setup(struct sun8i_a83t_mipi_csi2_device *csi2_de csi2_dev->clock_mipi = devm_clk_get(dev, "mipi"); if (IS_ERR(csi2_dev->clock_mipi)) { dev_err(dev, "failed to acquire mipi clock\n"); - return PTR_ERR(csi2_dev->clock_mipi); + ret = PTR_ERR(csi2_dev->clock_mipi); + goto error_clock_rate_exclusive; } csi2_dev->clock_misc = devm_clk_get(dev, "misc"); if (IS_ERR(csi2_dev->clock_misc)) { dev_err(dev, "failed to acquire misc clock\n"); - return PTR_ERR(csi2_dev->clock_misc); + ret = PTR_ERR(csi2_dev->clock_misc); + goto error_clock_rate_exclusive; } /* Reset */ @@ -733,7 +735,8 @@ sun8i_a83t_mipi_csi2_resources_setup(struct sun8i_a83t_mipi_csi2_device *csi2_de csi2_dev->reset = devm_reset_control_get_shared(dev, NULL); if (IS_ERR(csi2_dev->reset)) { dev_err(dev, "failed to get reset controller\n"); - return PTR_ERR(csi2_dev->reset); + ret = PTR_ERR(csi2_dev->reset); + goto error_clock_rate_exclusive; } /* D-PHY */ @@ -741,7 +744,7 @@ sun8i_a83t_mipi_csi2_resources_setup(struct sun8i_a83t_mipi_csi2_device *csi2_de ret = sun8i_a83t_dphy_register(csi2_dev); if (ret) { dev_err(dev, "failed to initialize MIPI D-PHY\n"); - return ret; + goto error_clock_rate_exclusive; } /* Runtime PM */ @@ -749,6 +752,11 @@ sun8i_a83t_mipi_csi2_resources_setup(struct sun8i_a83t_mipi_csi2_device *csi2_de pm_runtime_enable(dev); return 0; + +error_clock_rate_exclusive: + clk_rate_exclusive_put(csi2_dev->clock_mod); + + return ret; } static void @@ -778,9 +786,14 @@ static int sun8i_a83t_mipi_csi2_probe(struct platform_device *platform_dev) ret = sun8i_a83t_mipi_csi2_bridge_setup(csi2_dev); if (ret) - return ret; + goto error_resources; return 0; + +error_resources: + sun8i_a83t_mipi_csi2_resources_cleanup(csi2_dev); + + return ret; } static int sun8i_a83t_mipi_csi2_remove(struct platform_device *platform_dev) -- cgit From 51e1440d309a74a3e4e252019a00f9d0df329945 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Tue, 23 Aug 2022 09:42:11 +0200 Subject: media: sunxi: Fix some error handling path of sun6i_mipi_csi2_probe() Release some resources in the error handling path of the probe and of sun6i_mipi_csi2_resources_setup(), as already done in the remove function. Fixes: af54b4f4c17f ("media: sunxi: Add support for the A31 MIPI CSI-2 controller") Signed-off-by: Christophe JAILLET Acked-by: Paul Kocialkowski Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c index a4e3f9a6b2ff..30d6c0c5161f 100644 --- a/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c +++ b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c @@ -661,7 +661,8 @@ sun6i_mipi_csi2_resources_setup(struct sun6i_mipi_csi2_device *csi2_dev, csi2_dev->reset = devm_reset_control_get_shared(dev, NULL); if (IS_ERR(csi2_dev->reset)) { dev_err(dev, "failed to get reset controller\n"); - return PTR_ERR(csi2_dev->reset); + ret = PTR_ERR(csi2_dev->reset); + goto error_clock_rate_exclusive; } /* D-PHY */ @@ -669,13 +670,14 @@ sun6i_mipi_csi2_resources_setup(struct sun6i_mipi_csi2_device *csi2_dev, csi2_dev->dphy = devm_phy_get(dev, "dphy"); if (IS_ERR(csi2_dev->dphy)) { dev_err(dev, "failed to get MIPI D-PHY\n"); - return PTR_ERR(csi2_dev->dphy); + ret = PTR_ERR(csi2_dev->dphy); + goto error_clock_rate_exclusive; } ret = phy_init(csi2_dev->dphy); if (ret) { dev_err(dev, "failed to initialize MIPI D-PHY\n"); - return ret; + goto error_clock_rate_exclusive; } /* Runtime PM */ @@ -683,6 +685,11 @@ sun6i_mipi_csi2_resources_setup(struct sun6i_mipi_csi2_device *csi2_dev, pm_runtime_enable(dev); return 0; + +error_clock_rate_exclusive: + clk_rate_exclusive_put(csi2_dev->clock_mod); + + return ret; } static void @@ -712,9 +719,14 @@ static int sun6i_mipi_csi2_probe(struct platform_device *platform_dev) ret = sun6i_mipi_csi2_bridge_setup(csi2_dev); if (ret) - return ret; + goto error_resources; return 0; + +error_resources: + sun6i_mipi_csi2_resources_cleanup(csi2_dev); + + return ret; } static int sun6i_mipi_csi2_remove(struct platform_device *platform_dev) -- cgit From 06a2da340f762addc5935bf851d95b14d4692db2 Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Tue, 26 Jul 2022 04:14:54 +0200 Subject: media: venus: dec: Handle the case where find_format fails Debugging the decoder on msm8916 I noticed the vdec probe was crashing if the fmt pointer was NULL. A similar fix from Colin Ian King found by Coverity was implemented for the encoder. Implement the same fix on the decoder. Fixes: 7472c1c69138 ("[media] media: venus: vdec: add video decoder files") Cc: stable@vger.kernel.org # v4.13+ Signed-off-by: Bryan O'Donoghue Signed-off-by: Stanimir Varbanov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/vdec.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c index ac0bb45d07f4..4ceaba37e2e5 100644 --- a/drivers/media/platform/qcom/venus/vdec.c +++ b/drivers/media/platform/qcom/venus/vdec.c @@ -183,6 +183,8 @@ vdec_try_fmt_common(struct venus_inst *inst, struct v4l2_format *f) else return NULL; fmt = find_format(inst, pixmp->pixelformat, f->type); + if (!fmt) + return NULL; } pixmp->width = clamp(pixmp->width, frame_width_min(inst), -- cgit From 7f77fa9f378c528edb38dbf23ff1273c81429d49 Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Tue, 26 Jul 2022 04:14:55 +0200 Subject: media: venus: Fix NV12 decoder buffer discovery on HFI_VERSION_1XX HFI_VERSION_1XX uses HFI_BUFFER_OUTPUT not HFI_BUFFER_OUTPUT2 for decoder buffers. venus_helper_check_format() places a constraint on an output buffer to be of type HFI_BUFFER_OUTPUT2. HFI_1XX uses HFI_BUFFER_OUTPUT though. Switching to the logic used in venus_helper_get_out_fmts() first checking for HFI_BUFFER_OUTPUT and then HFI_BUFFER_OUTPUT2 resolves on HFI_1XX. db410c before: root@linaro-alip:~# v4l2-ctl -d /dev/video0 --list-formats ioctl: VIDIOC_ENUM_FMT Type: Video Capture Multiplanar [0]: 'MPG4' (MPEG-4 Part 2 ES, compressed) [1]: 'H263' (H.263, compressed) [2]: 'H264' (H.264, compressed) [3]: 'VP80' (VP8, compressed) root@linaro-alip:~# v4l2-ctl -d /dev/video1 --list-formats ioctl: VIDIOC_ENUM_FMT Type: Video Capture Multiplanar db410c after: root@linaro-alip:~# v4l2-ctl -d /dev/video0 --list-formats ioctl: VIDIOC_ENUM_FMT Type: Video Capture Multiplanar [0]: 'MPG4' (MPEG-4 Part 2 ES, compressed) [1]: 'H263' (H.263, compressed) [2]: 'H264' (H.264, compressed) [3]: 'VP80' (VP8, compressed) root@linaro-alip:~# v4l2-ctl -d /dev/video1 --list-formats ioctl: VIDIOC_ENUM_FMT Type: Video Capture Multiplanar [0]: 'NV12' (Y/CbCr 4:2:0) Validated playback with ffplay on db410c with h264 and vp8 decoding. Fixes: 9593126dae3e ("media: venus: Add a handling of QC08C compressed format") Cc: stable@vger.kernel.org # v5.19 Signed-off-by: Bryan O'Donoghue Signed-off-by: Stanimir Varbanov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/helpers.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/qcom/venus/helpers.c b/drivers/media/platform/qcom/venus/helpers.c index 60de4200375d..ab6a29ffc81e 100644 --- a/drivers/media/platform/qcom/venus/helpers.c +++ b/drivers/media/platform/qcom/venus/helpers.c @@ -1800,7 +1800,7 @@ bool venus_helper_check_format(struct venus_inst *inst, u32 v4l2_pixfmt) struct venus_core *core = inst->core; u32 fmt = to_hfi_raw_fmt(v4l2_pixfmt); struct hfi_plat_caps *caps; - u32 buftype; + bool found; if (!fmt) return false; @@ -1809,12 +1809,13 @@ bool venus_helper_check_format(struct venus_inst *inst, u32 v4l2_pixfmt) if (!caps) return false; - if (inst->session_type == VIDC_SESSION_TYPE_DEC) - buftype = HFI_BUFFER_OUTPUT2; - else - buftype = HFI_BUFFER_OUTPUT; + found = find_fmt_from_caps(caps, HFI_BUFFER_OUTPUT, fmt); + if (found) + goto done; - return find_fmt_from_caps(caps, buftype, fmt); + found = find_fmt_from_caps(caps, HFI_BUFFER_OUTPUT2, fmt); +done: + return found; } EXPORT_SYMBOL_GPL(venus_helper_check_format); -- cgit From 014a6b274bfe051fadf8ec7e99ac5eb95653e248 Mon Sep 17 00:00:00 2001 From: Stanimir Varbanov Date: Mon, 8 Aug 2022 11:28:28 +0200 Subject: media: venus : Add default values for the control V4l2 encoder compliance expecting default values of colorimetry for the control. Signed-off-by: Vikash Garodia Signed-off-by: Viswanath Boma Signed-off-by: Stanimir Varbanov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/venc_ctrls.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/qcom/venus/venc_ctrls.c b/drivers/media/platform/qcom/venus/venc_ctrls.c index ed44e5800759..52bbc544e9cb 100644 --- a/drivers/media/platform/qcom/venus/venc_ctrls.c +++ b/drivers/media/platform/qcom/venus/venc_ctrls.c @@ -355,6 +355,10 @@ static const struct v4l2_ctrl_ops venc_ctrl_ops = { int venc_ctrl_init(struct venus_inst *inst) { int ret; + struct v4l2_ctrl_hdr10_mastering_display p_hdr10_mastering = { + { 34000, 13250, 7500 }, + { 16000, 34500, 3000 }, 15635, 16450, 10000000, 500, + }; ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, 58); if (ret) @@ -583,7 +587,7 @@ int venc_ctrl_init(struct venus_inst *inst) v4l2_ctrl_new_std_compound(&inst->ctrl_handler, &venc_ctrl_ops, V4L2_CID_COLORIMETRY_HDR10_MASTERING_DISPLAY, - v4l2_ctrl_ptr_create(NULL)); + v4l2_ctrl_ptr_create((void *)&p_hdr10_mastering)); v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops, V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE, -- cgit From 096573e4c0c7eb21d5e22a9411aa2ba65ef96d96 Mon Sep 17 00:00:00 2001 From: Viswanath Boma Date: Mon, 8 Aug 2022 11:28:29 +0200 Subject: media: venus : Addition of control support - V4L2_CID_MIN_BUFFERS_FOR_OUTPUT V4l2 encoder compliance expecting minimum buffers support for the application to allocate buffers as per the control support values. Signed-off-by: Viswanath Boma Signed-off-by: Vikash Garodia Signed-off-by: Stanimir Varbanov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/venc_ctrls.c | 27 +++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/qcom/venus/venc_ctrls.c b/drivers/media/platform/qcom/venus/venc_ctrls.c index 52bbc544e9cb..27779c79bf9d 100644 --- a/drivers/media/platform/qcom/venus/venc_ctrls.c +++ b/drivers/media/platform/qcom/venus/venc_ctrls.c @@ -8,6 +8,7 @@ #include "core.h" #include "venc.h" +#include "helpers.h" #define BITRATE_MIN 32000 #define BITRATE_MAX 160000000 @@ -348,8 +349,29 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl) return 0; } +static int venc_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl) +{ + struct venus_inst *inst = ctrl_to_inst(ctrl); + struct hfi_buffer_requirements bufreq; + enum hfi_version ver = inst->core->res->hfi_version; + int ret; + + switch (ctrl->id) { + case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT: + ret = venus_helper_get_bufreq(inst, HFI_BUFFER_INPUT, &bufreq); + if (!ret) + ctrl->val = HFI_BUFREQ_COUNT_MIN(&bufreq, ver); + break; + default: + return -EINVAL; + } + + return 0; +} + static const struct v4l2_ctrl_ops venc_ctrl_ops = { .s_ctrl = venc_op_s_ctrl, + .g_volatile_ctrl = venc_op_g_volatile_ctrl, }; int venc_ctrl_init(struct venus_inst *inst) @@ -360,7 +382,7 @@ int venc_ctrl_init(struct venus_inst *inst) { 16000, 34500, 3000 }, 15635, 16450, 10000000, 500, }; - ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, 58); + ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, 59); if (ret) return ret; @@ -440,6 +462,9 @@ int venc_ctrl_init(struct venus_inst *inst) V4L2_MPEG_VIDEO_VP8_PROFILE_3, 0, V4L2_MPEG_VIDEO_VP8_PROFILE_0); + v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, + V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, 4, 11, 1, 4); + v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, V4L2_CID_MPEG_VIDEO_BITRATE, BITRATE_MIN, BITRATE_MAX, BITRATE_STEP, BITRATE_DEFAULT); -- cgit From c260bf4bd3a3f40b480a1eb1ea57ce26263c2f85 Mon Sep 17 00:00:00 2001 From: Stanimir Varbanov Date: Mon, 8 Aug 2022 11:28:30 +0200 Subject: media: venus : CAPTURE Plane width/height alignment with OUT plane. V4l2 encoder compliance set-format test cases failing as Capture plane width/height not aligned to OUT plane . Signed-off-by: Viswanath Boma Signed-off-by: Vikash Garodia Signed-off-by: Dikshita Agarwal Signed-off-by: Stanimir Varbanov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/venc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c index 86918aea1d24..037cbfccf336 100644 --- a/drivers/media/platform/qcom/venus/venc.c +++ b/drivers/media/platform/qcom/venus/venc.c @@ -192,10 +192,8 @@ venc_try_fmt_common(struct venus_inst *inst, struct v4l2_format *f) pixmp->height = clamp(pixmp->height, frame_height_min(inst), frame_height_max(inst)); - if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - pixmp->width = ALIGN(pixmp->width, 128); - pixmp->height = ALIGN(pixmp->height, 32); - } + pixmp->width = ALIGN(pixmp->width, 128); + pixmp->height = ALIGN(pixmp->height, 32); pixmp->width = ALIGN(pixmp->width, 2); pixmp->height = ALIGN(pixmp->height, 2); -- cgit From 70b2a5463dcdc18cd94d41f6dc170aa29cfcb922 Mon Sep 17 00:00:00 2001 From: Viswanath Boma Date: Mon, 8 Aug 2022 11:28:31 +0200 Subject: media: venus : Addition of EOS Event support for Encoder V4l2 encoder compliance expecting End of stream Event registration support for Encoder. Signed-off-by: Viswanath Boma Signed-off-by: Vikash Garodia Signed-off-by: Dikshita Agarwal Signed-off-by: Stanimir Varbanov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/venc.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c index 037cbfccf336..0c464ef89a22 100644 --- a/drivers/media/platform/qcom/venus/venc.c +++ b/drivers/media/platform/qcom/venus/venc.c @@ -507,6 +507,19 @@ static int venc_enum_frameintervals(struct file *file, void *fh, return 0; } +static int venc_subscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + switch (sub->type) { + case V4L2_EVENT_EOS: + return v4l2_event_subscribe(fh, sub, 2, NULL); + case V4L2_EVENT_CTRL: + return v4l2_ctrl_subscribe_event(fh, sub); + default: + return -EINVAL; + } +} + static const struct v4l2_ioctl_ops venc_ioctl_ops = { .vidioc_querycap = venc_querycap, .vidioc_enum_fmt_vid_cap = venc_enum_fmt, @@ -532,7 +545,7 @@ static const struct v4l2_ioctl_ops venc_ioctl_ops = { .vidioc_g_parm = venc_g_parm, .vidioc_enum_framesizes = venc_enum_framesizes, .vidioc_enum_frameintervals = venc_enum_frameintervals, - .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_subscribe_event = venc_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; -- cgit From 2f2d6fe83d0346923f0247e15dd51f3257e65edd Mon Sep 17 00:00:00 2001 From: Dikshita Agarwal Date: Mon, 8 Aug 2022 11:28:32 +0200 Subject: media: venus : Addition of support for VIDIOC_TRY_ENCODER_CMD v4l2 compliance expecting support for vidioc_try_encoder_cmd . error details : test VIDIOC_(TRY_)ENCODER_CMD: FAIL Signed-off-by: Viswanath Boma Signed-off-by: Dikshita Agarwal Signed-off-by: Vikash Garodia Signed-off-by: Stanimir Varbanov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/venc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c index 0c464ef89a22..167ee8ba8fc4 100644 --- a/drivers/media/platform/qcom/venus/venc.c +++ b/drivers/media/platform/qcom/venus/venc.c @@ -547,6 +547,7 @@ static const struct v4l2_ioctl_ops venc_ioctl_ops = { .vidioc_enum_frameintervals = venc_enum_frameintervals, .vidioc_subscribe_event = venc_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + .vidioc_try_encoder_cmd = v4l2_m2m_ioctl_try_encoder_cmd, }; static int venc_pm_get(struct venus_inst *inst) -- cgit From 2d5dbc7ff664ba320b1b4ed622c0b4c0d3d5b472 Mon Sep 17 00:00:00 2001 From: Viswanath Boma Date: Mon, 8 Aug 2022 11:28:33 +0200 Subject: media: venus : Remove the capture plane settings for venc_g_parm/venc_s_parm v4l2 compliance expecting settings for out buffer only and the same values will be propagated to capture buffer setting by h/w encoder . settings on cpature plane are optional , required only if offline-encoding supports. error details : fail: v4l2-test-formats.cpp(1350): !ret Signed-off-by: Viswanath Boma Signed-off-by: Vikash Garodia Signed-off-by: Stanimir Varbanov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/venc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c index 167ee8ba8fc4..cc08a3c8cd39 100644 --- a/drivers/media/platform/qcom/venus/venc.c +++ b/drivers/media/platform/qcom/venus/venc.c @@ -390,7 +390,7 @@ static int venc_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) struct v4l2_fract *timeperframe = &out->timeperframe; u64 us_per_frame, fps; - if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && + if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) return -EINVAL; @@ -422,7 +422,7 @@ static int venc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) { struct venus_inst *inst = to_inst(file); - if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && + if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) return -EINVAL; -- cgit From 1d600444f7f811bd554c18195fa7200a9254a24f Mon Sep 17 00:00:00 2001 From: Vikash Garodia Date: Mon, 8 Aug 2022 11:28:34 +0200 Subject: media: venus : Allow MIN/MAX settings for the v4l2 encoder controls defined range. Control MIN/MAX range defined as 0 to 1, as MIN value setting enabled for V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM. error details: fail: v4l2-test-controls.cpp(516): invalid maximum range check Signed-off-by: Viswanath Boma Signed-off-by: Vikash Garodia Signed-off-by: Dikshita Agarwal Signed-off-by: Stanimir Varbanov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/venc_ctrls.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/qcom/venus/venc_ctrls.c b/drivers/media/platform/qcom/venus/venc_ctrls.c index 27779c79bf9d..cfcacdb797db 100644 --- a/drivers/media/platform/qcom/venus/venc_ctrls.c +++ b/drivers/media/platform/qcom/venus/venc_ctrls.c @@ -337,8 +337,6 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl) * if we disable 8x8 transform for HP. */ - if (ctrl->val == 0) - return -EINVAL; ctr->h264_8x8_transform = ctrl->val; break; -- cgit From 61a70c9702da10296cebe4ab7d654da4bcb893b5 Mon Sep 17 00:00:00 2001 From: Stanimir Varbanov Date: Fri, 2 Sep 2022 12:00:31 +0200 Subject: media: venus: venc_ctrls: Add default value for CLL info Add default value for CLL info when creating compound control. Signed-off-by: Stanimir Varbanov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/venc_ctrls.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/qcom/venus/venc_ctrls.c b/drivers/media/platform/qcom/venus/venc_ctrls.c index cfcacdb797db..7468e43800a9 100644 --- a/drivers/media/platform/qcom/venus/venc_ctrls.c +++ b/drivers/media/platform/qcom/venus/venc_ctrls.c @@ -379,6 +379,7 @@ int venc_ctrl_init(struct venus_inst *inst) { 34000, 13250, 7500 }, { 16000, 34500, 3000 }, 15635, 16450, 10000000, 500, }; + struct v4l2_ctrl_hdr10_cll_info p_hdr10_cll = { 1000, 400 }; ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, 59); if (ret) @@ -606,7 +607,7 @@ int venc_ctrl_init(struct venus_inst *inst) v4l2_ctrl_new_std_compound(&inst->ctrl_handler, &venc_ctrl_ops, V4L2_CID_COLORIMETRY_HDR10_CLL_INFO, - v4l2_ctrl_ptr_create(NULL)); + v4l2_ctrl_ptr_create(&p_hdr10_cll)); v4l2_ctrl_new_std_compound(&inst->ctrl_handler, &venc_ctrl_ops, V4L2_CID_COLORIMETRY_HDR10_MASTERING_DISPLAY, -- cgit From f5218c71098dcf51772b6509184c02ce1cef37b8 Mon Sep 17 00:00:00 2001 From: Stanimir Varbanov Date: Fri, 2 Sep 2022 12:01:58 +0200 Subject: media: venus: venc: Set HDR10 PQ SEI property only for MAIN10 profile The HDR10 PQ SEI should be set only when the codec is HEVC and the profile is MAIN10, otherwise some artefacts could be produced on the encoded bitstream. Signed-off-by: Stanimir Varbanov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/venc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c index cc08a3c8cd39..cdb12546c4fa 100644 --- a/drivers/media/platform/qcom/venus/venc.c +++ b/drivers/media/platform/qcom/venus/venc.c @@ -698,7 +698,8 @@ static int venc_set_properties(struct venus_inst *inst) return ret; } - if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_HEVC) { + if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_HEVC && + ctr->profile.hevc == V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10) { struct hfi_hdr10_pq_sei hdr10; unsigned int c; -- cgit From 265f2fc52f5873ae3fa653ce1f2dbc47afef6344 Mon Sep 17 00:00:00 2001 From: ye xingchen Date: Tue, 30 Aug 2022 10:37:53 +0200 Subject: media: venus: hfi: Remove the unneeded result variable Return the value venus_hfi_create() directly instead of storing it in another redundant variable. Signed-off-by: ye xingchen Signed-off-by: Stanimir Varbanov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/hfi.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/qcom/venus/hfi.c b/drivers/media/platform/qcom/venus/hfi.c index 1968f09ad177..e00aedb41d16 100644 --- a/drivers/media/platform/qcom/venus/hfi.c +++ b/drivers/media/platform/qcom/venus/hfi.c @@ -569,8 +569,6 @@ irqreturn_t hfi_isr(int irq, void *dev) int hfi_create(struct venus_core *core, const struct hfi_core_ops *ops) { - int ret; - if (!ops) return -EINVAL; @@ -579,9 +577,8 @@ int hfi_create(struct venus_core *core, const struct hfi_core_ops *ops) core->state = CORE_UNINIT; init_completion(&core->done); pkt_set_version(core->res->hfi_version); - ret = venus_hfi_create(core); - return ret; + return venus_hfi_create(core); } void hfi_destroy(struct venus_core *core) -- cgit From d0734dab5480325fd67548aa51ee126570d48574 Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Thu, 25 Aug 2022 12:20:29 +0200 Subject: media: sun6i-mipi-csi2: Add a Kconfig dependency on RESET_CONTROLLER The driver relies on the reset controller API to work, so add RESET_CONTROLLER as one of its Kconfig dependencies. It also selects PHY_SUN6I_MIPI_DPHY, which depends on RESET_CONTROLLER. Fixes: af54b4f4c17f ("media: sunxi: Add support for the A31 MIPI CSI-2 controller") Signed-off-by: Paul Kocialkowski Reported-by: kernel test robot Acked-by: Jernej Skrabec Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig b/drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig index 4d072abdfb70..08852f63692b 100644 --- a/drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig +++ b/drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig @@ -3,7 +3,7 @@ config VIDEO_SUN6I_MIPI_CSI2 tristate "Allwinner A31 MIPI CSI-2 Controller Driver" depends on V4L_PLATFORM_DRIVERS && VIDEO_DEV depends on ARCH_SUNXI || COMPILE_TEST - depends on PM && COMMON_CLK + depends on PM && COMMON_CLK && RESET_CONTROLLER depends on PHY_SUN6I_MIPI_DPHY select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API -- cgit From 398c479234894c3d3347d83869760db3c406c269 Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Thu, 25 Aug 2022 12:20:30 +0200 Subject: media: sun8i-a83t-mipi-csi2: Add a Kconfig dependency on RESET_CONTROLLER The driver relies on the reset controller API to work, so add RESET_CONTROLLER as one of its Kconfig dependencies. Fixes: 576d196c522b ("media: sunxi: Add support for the A83T MIPI CSI-2 controller") Signed-off-by: Paul Kocialkowski Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Kconfig b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Kconfig index 789d58ee12ea..47a8c0fb7eb9 100644 --- a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Kconfig +++ b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Kconfig @@ -3,7 +3,7 @@ config VIDEO_SUN8I_A83T_MIPI_CSI2 tristate "Allwinner A83T MIPI CSI-2 Controller and D-PHY Driver" depends on V4L_PLATFORM_DRIVERS && VIDEO_DEV depends on ARCH_SUNXI || COMPILE_TEST - depends on PM && COMMON_CLK + depends on PM && COMMON_CLK && RESET_CONTROLLER select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE -- cgit From 6a720df702db764e2b3bbdaaa217e9d344efcfb2 Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Thu, 25 Aug 2022 12:20:31 +0200 Subject: media: sun6i-csi: Add a Kconfig dependency on RESET_CONTROLLER The driver relies on the reset controller API to work, so add RESET_CONTROLLER as one of its Kconfig dependencies. Fixes: 5cc7522d8965 ("media: sun6i: Add support for Allwinner CSI V3s") Signed-off-by: Paul Kocialkowski Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sunxi/sun6i-csi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/sunxi/sun6i-csi/Kconfig b/drivers/media/platform/sunxi/sun6i-csi/Kconfig index 0345901617d4..e5b6991ce7f0 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/Kconfig +++ b/drivers/media/platform/sunxi/sun6i-csi/Kconfig @@ -2,7 +2,7 @@ config VIDEO_SUN6I_CSI tristate "Allwinner V3s Camera Sensor Interface driver" depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_DEV && COMMON_CLK && HAS_DMA + depends on VIDEO_DEV && COMMON_CLK && RESET_CONTROLLER && HAS_DMA depends on ARCH_SUNXI || COMPILE_TEST select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API -- cgit From 140a9b57d3a306ca77a92e903facbdc4a31ccd51 Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Thu, 25 Aug 2022 12:20:32 +0200 Subject: media: sun4i-csi: Add a Kconfig dependency on RESET_CONTROLLER The driver relies on the reset controller API to work, so add RESET_CONTROLLER as one of its Kconfig dependencies. Fixes: 577bbf23b758 ("media: sunxi: Add A10 CSI driver") Signed-off-by: Paul Kocialkowski Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sunxi/sun4i-csi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/sunxi/sun4i-csi/Kconfig b/drivers/media/platform/sunxi/sun4i-csi/Kconfig index 7960e6836f41..60610c04d6a7 100644 --- a/drivers/media/platform/sunxi/sun4i-csi/Kconfig +++ b/drivers/media/platform/sunxi/sun4i-csi/Kconfig @@ -3,7 +3,7 @@ config VIDEO_SUN4I_CSI tristate "Allwinner A10 CMOS Sensor Interface Support" depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_DEV && COMMON_CLK && HAS_DMA + depends on VIDEO_DEV && COMMON_CLK && RESET_CONTROLLER && HAS_DMA depends on ARCH_SUNXI || COMPILE_TEST select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API -- cgit From c2a46b19f0340e6647168f4ceac4e5e4cb9197d8 Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Thu, 25 Aug 2022 12:20:33 +0200 Subject: media: sun8i-di: Add a Kconfig dependency on RESET_CONTROLLER The driver relies on the reset controller API to work, so add RESET_CONTROLLER as one of its Kconfig dependencies. Fixes: a4260ea49547 ("media: sun4i: Add H3 deinterlace driver") Signed-off-by: Paul Kocialkowski Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sunxi/sun8i-di/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/sunxi/sun8i-di/Kconfig b/drivers/media/platform/sunxi/sun8i-di/Kconfig index ff71e06ee2df..f688396913b7 100644 --- a/drivers/media/platform/sunxi/sun8i-di/Kconfig +++ b/drivers/media/platform/sunxi/sun8i-di/Kconfig @@ -4,7 +4,7 @@ config VIDEO_SUN8I_DEINTERLACE depends on V4L_MEM2MEM_DRIVERS depends on VIDEO_DEV depends on ARCH_SUNXI || COMPILE_TEST - depends on COMMON_CLK && OF + depends on COMMON_CLK && RESET_CONTROLLER && OF depends on PM select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV -- cgit From b9273150b8b7f8b02ac961463057191d243f953d Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Thu, 25 Aug 2022 12:20:34 +0200 Subject: media: sun8i-rotate: Add a Kconfig dependency on RESET_CONTROLLER The driver relies on the reset controller API to work, so add RESET_CONTROLLER as one of its Kconfig dependencies. Fixes: d77182ada3d4 ("media: sun8i: Add Allwinner A83T Rotate driver") Signed-off-by: Paul Kocialkowski Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sunxi/sun8i-rotate/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/sunxi/sun8i-rotate/Kconfig b/drivers/media/platform/sunxi/sun8i-rotate/Kconfig index cfba29072d75..ee2c1f248c64 100644 --- a/drivers/media/platform/sunxi/sun8i-rotate/Kconfig +++ b/drivers/media/platform/sunxi/sun8i-rotate/Kconfig @@ -5,7 +5,7 @@ config VIDEO_SUN8I_ROTATE depends on V4L_MEM2MEM_DRIVERS depends on VIDEO_DEV depends on ARCH_SUNXI || COMPILE_TEST - depends on COMMON_CLK && OF + depends on COMMON_CLK && RESET_CONTROLLER && OF depends on PM select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV -- cgit From 6f4d0849be9beefc457a8ec95818ff36309d273a Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Fri, 26 Aug 2022 20:31:58 +0200 Subject: media: sun6i-csi: Define and use driver name and (reworked) description Add proper defines for driver name and description instead of MODULE_NAME and hardcoding (cosmetics). Also rework the description while at it to mention the hardware generation that the driver supports and remove the video capture mentions since it applies to the whole media device. Signed-off-by: Paul Kocialkowski Reviewed-by: Maxime Ripard Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c | 14 ++++++-------- drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h | 3 +++ 2 files changed, 9 insertions(+), 8 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index a971587dbbd1..5ca05f348021 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -27,8 +27,6 @@ #include "sun6i_csi.h" #include "sun6i_csi_reg.h" -#define MODULE_NAME "sun6i-csi" - struct sun6i_csi_dev { struct sun6i_csi csi; struct device *dev; @@ -730,7 +728,7 @@ static int sun6i_csi_v4l2_init(struct sun6i_csi *csi) int ret; csi->media_dev.dev = csi->dev; - strscpy(csi->media_dev.model, "Allwinner Video Capture Device", + strscpy(csi->media_dev.model, SUN6I_CSI_DESCRIPTION, sizeof(csi->media_dev.model)); csi->media_dev.hw_revision = 0; @@ -753,7 +751,7 @@ static int sun6i_csi_v4l2_init(struct sun6i_csi *csi) goto free_ctrl; } - ret = sun6i_video_init(&csi->video, csi, "sun6i-csi"); + ret = sun6i_video_init(&csi->video, csi, SUN6I_CSI_NAME); if (ret) goto unreg_v4l2; @@ -868,8 +866,8 @@ static int sun6i_csi_resource_request(struct sun6i_csi_dev *sdev, if (irq < 0) return -ENXIO; - ret = devm_request_irq(&pdev->dev, irq, sun6i_csi_isr, 0, MODULE_NAME, - sdev); + ret = devm_request_irq(&pdev->dev, irq, sun6i_csi_isr, 0, + SUN6I_CSI_NAME, sdev); if (ret) { dev_err(&pdev->dev, "Cannot request csi IRQ\n"); return ret; @@ -922,12 +920,12 @@ static struct platform_driver sun6i_csi_platform_driver = { .probe = sun6i_csi_probe, .remove = sun6i_csi_remove, .driver = { - .name = MODULE_NAME, + .name = SUN6I_CSI_NAME, .of_match_table = of_match_ptr(sun6i_csi_of_match), }, }; module_platform_driver(sun6i_csi_platform_driver); -MODULE_DESCRIPTION("Allwinner V3s Camera Sensor Interface driver"); +MODULE_DESCRIPTION("Allwinner A31 Camera Sensor Interface driver"); MODULE_AUTHOR("Yong Deng "); MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h index 3a38d107ae3f..e04f3c3fa27b 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h @@ -14,6 +14,9 @@ #include "sun6i_video.h" +#define SUN6I_CSI_NAME "sun6i-csi" +#define SUN6I_CSI_DESCRIPTION "Allwinner A31 CSI Device" + struct sun6i_csi; /** -- cgit From 0b11253f36e8d6697e3eea81a9a87a704edfcf65 Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Wed, 7 Sep 2022 12:00:38 +0200 Subject: media: sun6i-csi: Refactor main driver data structures Merge contents of structs sun6i_csi and sun6i_csi_dev into a main sun6i_csi_device structure holding a sun6i_csi_v4l2 struct for things related to v4l2, as well as the already-existing sun6i_csi_video and sun6i_csi_config which are left unchanged. This mostly simplifies accessing stuff by having a single main structure accessible to every part of the code instead of a private definition. Also solve some kerneldoc warnings by describing return codes while at it. No functional change is intended in this commit, variables are just moved around (cosmetics). Signed-off-by: Paul Kocialkowski Reviewed-by: Maxime Ripard Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c | 346 ++++++++++----------- drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h | 50 +-- .../media/platform/sunxi/sun6i-csi/sun6i_video.c | 52 ++-- .../media/platform/sunxi/sun6i-csi/sun6i_video.h | 8 +- 4 files changed, 229 insertions(+), 227 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index 5ca05f348021..0e2b4d38e81c 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -27,37 +27,20 @@ #include "sun6i_csi.h" #include "sun6i_csi_reg.h" -struct sun6i_csi_dev { - struct sun6i_csi csi; - struct device *dev; - - struct regmap *regmap; - struct clk *clk_mod; - struct clk *clk_ram; - struct reset_control *rstc_bus; - - int planar_offset[3]; -}; - -static inline struct sun6i_csi_dev *sun6i_csi_to_dev(struct sun6i_csi *csi) -{ - return container_of(csi, struct sun6i_csi_dev, csi); -} - /* TODO add 10&12 bit YUV, RGB support */ -bool sun6i_csi_is_format_supported(struct sun6i_csi *csi, +bool sun6i_csi_is_format_supported(struct sun6i_csi_device *csi_dev, u32 pixformat, u32 mbus_code) { - struct sun6i_csi_dev *sdev = sun6i_csi_to_dev(csi); + struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2; /* * Some video receivers have the ability to be compatible with * 8bit and 16bit bus width. * Identify the media bus format from device tree. */ - if ((sdev->csi.v4l2_ep.bus_type == V4L2_MBUS_PARALLEL - || sdev->csi.v4l2_ep.bus_type == V4L2_MBUS_BT656) - && sdev->csi.v4l2_ep.bus.parallel.bus_width == 16) { + if ((v4l2->v4l2_ep.bus_type == V4L2_MBUS_PARALLEL + || v4l2->v4l2_ep.bus_type == V4L2_MBUS_BT656) + && v4l2->v4l2_ep.bus.parallel.bus_width == 16) { switch (pixformat) { case V4L2_PIX_FMT_NV12_16L16: case V4L2_PIX_FMT_NV12: @@ -74,13 +57,14 @@ bool sun6i_csi_is_format_supported(struct sun6i_csi *csi, case MEDIA_BUS_FMT_YVYU8_1X16: return true; default: - dev_dbg(sdev->dev, "Unsupported mbus code: 0x%x\n", + dev_dbg(csi_dev->dev, + "Unsupported mbus code: 0x%x\n", mbus_code); break; } break; default: - dev_dbg(sdev->dev, "Unsupported pixformat: 0x%x\n", + dev_dbg(csi_dev->dev, "Unsupported pixformat: 0x%x\n", pixformat); break; } @@ -137,7 +121,7 @@ bool sun6i_csi_is_format_supported(struct sun6i_csi *csi, case MEDIA_BUS_FMT_YVYU8_2X8: return true; default: - dev_dbg(sdev->dev, "Unsupported mbus code: 0x%x\n", + dev_dbg(csi_dev->dev, "Unsupported mbus code: 0x%x\n", mbus_code); break; } @@ -152,50 +136,50 @@ bool sun6i_csi_is_format_supported(struct sun6i_csi *csi, return (mbus_code == MEDIA_BUS_FMT_JPEG_1X8); default: - dev_dbg(sdev->dev, "Unsupported pixformat: 0x%x\n", pixformat); + dev_dbg(csi_dev->dev, "Unsupported pixformat: 0x%x\n", + pixformat); break; } return false; } -int sun6i_csi_set_power(struct sun6i_csi *csi, bool enable) +int sun6i_csi_set_power(struct sun6i_csi_device *csi_dev, bool enable) { - struct sun6i_csi_dev *sdev = sun6i_csi_to_dev(csi); - struct device *dev = sdev->dev; - struct regmap *regmap = sdev->regmap; + struct device *dev = csi_dev->dev; + struct regmap *regmap = csi_dev->regmap; int ret; if (!enable) { regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN, 0); - clk_disable_unprepare(sdev->clk_ram); + clk_disable_unprepare(csi_dev->clk_ram); if (of_device_is_compatible(dev->of_node, "allwinner,sun50i-a64-csi")) - clk_rate_exclusive_put(sdev->clk_mod); - clk_disable_unprepare(sdev->clk_mod); - reset_control_assert(sdev->rstc_bus); + clk_rate_exclusive_put(csi_dev->clk_mod); + clk_disable_unprepare(csi_dev->clk_mod); + reset_control_assert(csi_dev->reset); return 0; } - ret = clk_prepare_enable(sdev->clk_mod); + ret = clk_prepare_enable(csi_dev->clk_mod); if (ret) { - dev_err(sdev->dev, "Enable csi clk err %d\n", ret); + dev_err(csi_dev->dev, "Enable csi clk err %d\n", ret); return ret; } if (of_device_is_compatible(dev->of_node, "allwinner,sun50i-a64-csi")) - clk_set_rate_exclusive(sdev->clk_mod, 300000000); + clk_set_rate_exclusive(csi_dev->clk_mod, 300000000); - ret = clk_prepare_enable(sdev->clk_ram); + ret = clk_prepare_enable(csi_dev->clk_ram); if (ret) { - dev_err(sdev->dev, "Enable clk_dram_csi clk err %d\n", ret); + dev_err(csi_dev->dev, "Enable clk_dram_csi clk err %d\n", ret); goto clk_mod_disable; } - ret = reset_control_deassert(sdev->rstc_bus); + ret = reset_control_deassert(csi_dev->reset); if (ret) { - dev_err(sdev->dev, "reset err %d\n", ret); + dev_err(csi_dev->dev, "reset err %d\n", ret); goto clk_ram_disable; } @@ -204,15 +188,15 @@ int sun6i_csi_set_power(struct sun6i_csi *csi, bool enable) return 0; clk_ram_disable: - clk_disable_unprepare(sdev->clk_ram); + clk_disable_unprepare(csi_dev->clk_ram); clk_mod_disable: if (of_device_is_compatible(dev->of_node, "allwinner,sun50i-a64-csi")) - clk_rate_exclusive_put(sdev->clk_mod); - clk_disable_unprepare(sdev->clk_mod); + clk_rate_exclusive_put(csi_dev->clk_mod); + clk_disable_unprepare(csi_dev->clk_mod); return ret; } -static enum csi_input_fmt get_csi_input_format(struct sun6i_csi_dev *sdev, +static enum csi_input_fmt get_csi_input_format(struct sun6i_csi_device *csi_dev, u32 mbus_code, u32 pixformat) { /* non-YUV */ @@ -230,12 +214,13 @@ static enum csi_input_fmt get_csi_input_format(struct sun6i_csi_dev *sdev, } /* not support YUV420 input format yet */ - dev_dbg(sdev->dev, "Select YUV422 as default input format of CSI.\n"); + dev_dbg(csi_dev->dev, "Select YUV422 as default input format of CSI.\n"); return CSI_INPUT_FORMAT_YUV422; } -static enum csi_output_fmt get_csi_output_format(struct sun6i_csi_dev *sdev, - u32 pixformat, u32 field) +static enum csi_output_fmt +get_csi_output_format(struct sun6i_csi_device *csi_dev, u32 pixformat, + u32 field) { bool buf_interlaced = false; @@ -294,14 +279,14 @@ static enum csi_output_fmt get_csi_output_format(struct sun6i_csi_dev *sdev, return buf_interlaced ? CSI_FRAME_RAW_8 : CSI_FIELD_RAW_8; default: - dev_warn(sdev->dev, "Unsupported pixformat: 0x%x\n", pixformat); + dev_warn(csi_dev->dev, "Unsupported pixformat: 0x%x\n", pixformat); break; } return CSI_FIELD_RAW_8; } -static enum csi_input_seq get_csi_input_seq(struct sun6i_csi_dev *sdev, +static enum csi_input_seq get_csi_input_seq(struct sun6i_csi_device *csi_dev, u32 mbus_code, u32 pixformat) { /* Input sequence does not apply to non-YUV formats */ @@ -328,7 +313,7 @@ static enum csi_input_seq get_csi_input_seq(struct sun6i_csi_dev *sdev, case MEDIA_BUS_FMT_YVYU8_2X8: return CSI_INPUT_SEQ_YVYU; default: - dev_warn(sdev->dev, "Unsupported mbus code: 0x%x\n", + dev_warn(csi_dev->dev, "Unsupported mbus code: 0x%x\n", mbus_code); break; } @@ -350,7 +335,7 @@ static enum csi_input_seq get_csi_input_seq(struct sun6i_csi_dev *sdev, case MEDIA_BUS_FMT_YVYU8_2X8: return CSI_INPUT_SEQ_YUYV; default: - dev_warn(sdev->dev, "Unsupported mbus code: 0x%x\n", + dev_warn(csi_dev->dev, "Unsupported mbus code: 0x%x\n", mbus_code); break; } @@ -360,7 +345,7 @@ static enum csi_input_seq get_csi_input_seq(struct sun6i_csi_dev *sdev, return CSI_INPUT_SEQ_YUYV; default: - dev_warn(sdev->dev, "Unsupported pixformat: 0x%x, defaulting to YUYV\n", + dev_warn(csi_dev->dev, "Unsupported pixformat: 0x%x, defaulting to YUYV\n", pixformat); break; } @@ -368,23 +353,23 @@ static enum csi_input_seq get_csi_input_seq(struct sun6i_csi_dev *sdev, return CSI_INPUT_SEQ_YUYV; } -static void sun6i_csi_setup_bus(struct sun6i_csi_dev *sdev) +static void sun6i_csi_setup_bus(struct sun6i_csi_device *csi_dev) { - struct v4l2_fwnode_endpoint *endpoint = &sdev->csi.v4l2_ep; - struct sun6i_csi *csi = &sdev->csi; + struct v4l2_fwnode_endpoint *endpoint = &csi_dev->v4l2.v4l2_ep; + struct sun6i_csi_config *config = &csi_dev->config; unsigned char bus_width; u32 flags; u32 cfg; bool input_interlaced = false; - if (csi->config.field == V4L2_FIELD_INTERLACED - || csi->config.field == V4L2_FIELD_INTERLACED_TB - || csi->config.field == V4L2_FIELD_INTERLACED_BT) + if (config->field == V4L2_FIELD_INTERLACED + || config->field == V4L2_FIELD_INTERLACED_TB + || config->field == V4L2_FIELD_INTERLACED_BT) input_interlaced = true; bus_width = endpoint->bus.parallel.bus_width; - regmap_read(sdev->regmap, CSI_IF_CFG_REG, &cfg); + regmap_read(csi_dev->regmap, CSI_IF_CFG_REG, &cfg); cfg &= ~(CSI_IF_CFG_CSI_IF_MASK | CSI_IF_CFG_MIPI_IF_MASK | CSI_IF_CFG_IF_DATA_WIDTH_MASK | @@ -432,7 +417,7 @@ static void sun6i_csi_setup_bus(struct sun6i_csi_dev *sdev) cfg |= CSI_IF_CFG_CLK_POL_FALLING_EDGE; break; default: - dev_warn(sdev->dev, "Unsupported bus type: %d\n", + dev_warn(csi_dev->dev, "Unsupported bus type: %d\n", endpoint->bus_type); break; } @@ -450,54 +435,54 @@ static void sun6i_csi_setup_bus(struct sun6i_csi_dev *sdev) case 16: /* No need to configure DATA_WIDTH for 16bit */ break; default: - dev_warn(sdev->dev, "Unsupported bus width: %u\n", bus_width); + dev_warn(csi_dev->dev, "Unsupported bus width: %u\n", bus_width); break; } - regmap_write(sdev->regmap, CSI_IF_CFG_REG, cfg); + regmap_write(csi_dev->regmap, CSI_IF_CFG_REG, cfg); } -static void sun6i_csi_set_format(struct sun6i_csi_dev *sdev) +static void sun6i_csi_set_format(struct sun6i_csi_device *csi_dev) { - struct sun6i_csi *csi = &sdev->csi; + struct sun6i_csi_config *config = &csi_dev->config; u32 cfg; u32 val; - regmap_read(sdev->regmap, CSI_CH_CFG_REG, &cfg); + regmap_read(csi_dev->regmap, CSI_CH_CFG_REG, &cfg); cfg &= ~(CSI_CH_CFG_INPUT_FMT_MASK | CSI_CH_CFG_OUTPUT_FMT_MASK | CSI_CH_CFG_VFLIP_EN | CSI_CH_CFG_HFLIP_EN | CSI_CH_CFG_FIELD_SEL_MASK | CSI_CH_CFG_INPUT_SEQ_MASK); - val = get_csi_input_format(sdev, csi->config.code, - csi->config.pixelformat); + val = get_csi_input_format(csi_dev, config->code, + config->pixelformat); cfg |= CSI_CH_CFG_INPUT_FMT(val); - val = get_csi_output_format(sdev, csi->config.pixelformat, - csi->config.field); + val = get_csi_output_format(csi_dev, config->pixelformat, + config->field); cfg |= CSI_CH_CFG_OUTPUT_FMT(val); - val = get_csi_input_seq(sdev, csi->config.code, - csi->config.pixelformat); + val = get_csi_input_seq(csi_dev, config->code, + config->pixelformat); cfg |= CSI_CH_CFG_INPUT_SEQ(val); - if (csi->config.field == V4L2_FIELD_TOP) + if (config->field == V4L2_FIELD_TOP) cfg |= CSI_CH_CFG_FIELD_SEL_FIELD0; - else if (csi->config.field == V4L2_FIELD_BOTTOM) + else if (config->field == V4L2_FIELD_BOTTOM) cfg |= CSI_CH_CFG_FIELD_SEL_FIELD1; else cfg |= CSI_CH_CFG_FIELD_SEL_BOTH; - regmap_write(sdev->regmap, CSI_CH_CFG_REG, cfg); + regmap_write(csi_dev->regmap, CSI_CH_CFG_REG, cfg); } -static void sun6i_csi_set_window(struct sun6i_csi_dev *sdev) +static void sun6i_csi_set_window(struct sun6i_csi_device *csi_dev) { - struct sun6i_csi_config *config = &sdev->csi.config; + struct sun6i_csi_config *config = &csi_dev->config; u32 bytesperline_y; u32 bytesperline_c; - int *planar_offset = sdev->planar_offset; + int *planar_offset = csi_dev->planar_offset; u32 width = config->width; u32 height = config->height; u32 hor_len = width; @@ -507,7 +492,7 @@ static void sun6i_csi_set_window(struct sun6i_csi_dev *sdev) case V4L2_PIX_FMT_YVYU: case V4L2_PIX_FMT_UYVY: case V4L2_PIX_FMT_VYUY: - dev_dbg(sdev->dev, + dev_dbg(csi_dev->dev, "Horizontal length should be 2 times of width for packed YUV formats!\n"); hor_len = width * 2; break; @@ -515,10 +500,10 @@ static void sun6i_csi_set_window(struct sun6i_csi_dev *sdev) break; } - regmap_write(sdev->regmap, CSI_CH_HSIZE_REG, + regmap_write(csi_dev->regmap, CSI_CH_HSIZE_REG, CSI_CH_HSIZE_HOR_LEN(hor_len) | CSI_CH_HSIZE_HOR_START(0)); - regmap_write(sdev->regmap, CSI_CH_VSIZE_REG, + regmap_write(csi_dev->regmap, CSI_CH_VSIZE_REG, CSI_CH_VSIZE_VER_LEN(height) | CSI_CH_VSIZE_VER_START(0)); @@ -550,7 +535,7 @@ static void sun6i_csi_set_window(struct sun6i_csi_dev *sdev) bytesperline_c * height; break; default: /* raw */ - dev_dbg(sdev->dev, + dev_dbg(csi_dev->dev, "Calculating pixelformat(0x%x)'s bytesperline as a packed format\n", config->pixelformat); bytesperline_y = (sun6i_csi_get_bpp(config->pixelformat) * @@ -561,46 +546,42 @@ static void sun6i_csi_set_window(struct sun6i_csi_dev *sdev) break; } - regmap_write(sdev->regmap, CSI_CH_BUF_LEN_REG, + regmap_write(csi_dev->regmap, CSI_CH_BUF_LEN_REG, CSI_CH_BUF_LEN_BUF_LEN_C(bytesperline_c) | CSI_CH_BUF_LEN_BUF_LEN_Y(bytesperline_y)); } -int sun6i_csi_update_config(struct sun6i_csi *csi, +int sun6i_csi_update_config(struct sun6i_csi_device *csi_dev, struct sun6i_csi_config *config) { - struct sun6i_csi_dev *sdev = sun6i_csi_to_dev(csi); - if (!config) return -EINVAL; - memcpy(&csi->config, config, sizeof(csi->config)); + memcpy(&csi_dev->config, config, sizeof(csi_dev->config)); - sun6i_csi_setup_bus(sdev); - sun6i_csi_set_format(sdev); - sun6i_csi_set_window(sdev); + sun6i_csi_setup_bus(csi_dev); + sun6i_csi_set_format(csi_dev); + sun6i_csi_set_window(csi_dev); return 0; } -void sun6i_csi_update_buf_addr(struct sun6i_csi *csi, dma_addr_t addr) +void sun6i_csi_update_buf_addr(struct sun6i_csi_device *csi_dev, + dma_addr_t addr) { - struct sun6i_csi_dev *sdev = sun6i_csi_to_dev(csi); - - regmap_write(sdev->regmap, CSI_CH_F0_BUFA_REG, - (addr + sdev->planar_offset[0]) >> 2); - if (sdev->planar_offset[1] != -1) - regmap_write(sdev->regmap, CSI_CH_F1_BUFA_REG, - (addr + sdev->planar_offset[1]) >> 2); - if (sdev->planar_offset[2] != -1) - regmap_write(sdev->regmap, CSI_CH_F2_BUFA_REG, - (addr + sdev->planar_offset[2]) >> 2); + regmap_write(csi_dev->regmap, CSI_CH_F0_BUFA_REG, + (addr + csi_dev->planar_offset[0]) >> 2); + if (csi_dev->planar_offset[1] != -1) + regmap_write(csi_dev->regmap, CSI_CH_F1_BUFA_REG, + (addr + csi_dev->planar_offset[1]) >> 2); + if (csi_dev->planar_offset[2] != -1) + regmap_write(csi_dev->regmap, CSI_CH_F2_BUFA_REG, + (addr + csi_dev->planar_offset[2]) >> 2); } -void sun6i_csi_set_stream(struct sun6i_csi *csi, bool enable) +void sun6i_csi_set_stream(struct sun6i_csi_device *csi_dev, bool enable) { - struct sun6i_csi_dev *sdev = sun6i_csi_to_dev(csi); - struct regmap *regmap = sdev->regmap; + struct regmap *regmap = csi_dev->regmap; if (!enable) { regmap_update_bits(regmap, CSI_CAP_REG, CSI_CAP_CH0_VCAP_ON, 0); @@ -624,7 +605,7 @@ void sun6i_csi_set_stream(struct sun6i_csi *csi, bool enable) /* ----------------------------------------------------------------------------- * Media Controller and V4L2 */ -static int sun6i_csi_link_entity(struct sun6i_csi *csi, +static int sun6i_csi_link_entity(struct sun6i_csi_device *csi_dev, struct media_entity *entity, struct fwnode_handle *fwnode) { @@ -635,24 +616,25 @@ static int sun6i_csi_link_entity(struct sun6i_csi *csi, ret = media_entity_get_fwnode_pad(entity, fwnode, MEDIA_PAD_FL_SOURCE); if (ret < 0) { - dev_err(csi->dev, "%s: no source pad in external entity %s\n", - __func__, entity->name); + dev_err(csi_dev->dev, + "%s: no source pad in external entity %s\n", __func__, + entity->name); return -EINVAL; } src_pad_index = ret; - sink = &csi->video.vdev.entity; - sink_pad = &csi->video.pad; + sink = &csi_dev->video.vdev.entity; + sink_pad = &csi_dev->video.pad; - dev_dbg(csi->dev, "creating %s:%u -> %s:%u link\n", + dev_dbg(csi_dev->dev, "creating %s:%u -> %s:%u link\n", entity->name, src_pad_index, sink->name, sink_pad->index); ret = media_create_pad_link(entity, src_pad_index, sink, sink_pad->index, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE); if (ret < 0) { - dev_err(csi->dev, "failed to create %s:%u -> %s:%u link\n", + dev_err(csi_dev->dev, "failed to create %s:%u -> %s:%u link\n", entity->name, src_pad_index, sink->name, sink_pad->index); return ret; @@ -663,27 +645,29 @@ static int sun6i_csi_link_entity(struct sun6i_csi *csi, static int sun6i_subdev_notify_complete(struct v4l2_async_notifier *notifier) { - struct sun6i_csi *csi = container_of(notifier, struct sun6i_csi, - notifier); - struct v4l2_device *v4l2_dev = &csi->v4l2_dev; + struct sun6i_csi_device *csi_dev = + container_of(notifier, struct sun6i_csi_device, + v4l2.notifier); + struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2; + struct v4l2_device *v4l2_dev = &v4l2->v4l2_dev; struct v4l2_subdev *sd; int ret; - dev_dbg(csi->dev, "notify complete, all subdevs registered\n"); + dev_dbg(csi_dev->dev, "notify complete, all subdevs registered\n"); sd = list_first_entry(&v4l2_dev->subdevs, struct v4l2_subdev, list); if (!sd) return -EINVAL; - ret = sun6i_csi_link_entity(csi, &sd->entity, sd->fwnode); + ret = sun6i_csi_link_entity(csi_dev, &sd->entity, sd->fwnode); if (ret < 0) return ret; - ret = v4l2_device_register_subdev_nodes(&csi->v4l2_dev); + ret = v4l2_device_register_subdev_nodes(v4l2_dev); if (ret < 0) return ret; - return media_device_register(&csi->media_dev); + return media_device_register(&v4l2->media_dev); } static const struct v4l2_async_notifier_operations sun6i_csi_async_ops = { @@ -694,7 +678,7 @@ static int sun6i_csi_fwnode_parse(struct device *dev, struct v4l2_fwnode_endpoint *vep, struct v4l2_async_subdev *asd) { - struct sun6i_csi *csi = dev_get_drvdata(dev); + struct sun6i_csi_device *csi_dev = dev_get_drvdata(dev); if (vep->base.port || vep->base.id) { dev_warn(dev, "Only support a single port with one endpoint\n"); @@ -704,7 +688,7 @@ static int sun6i_csi_fwnode_parse(struct device *dev, switch (vep->bus_type) { case V4L2_MBUS_PARALLEL: case V4L2_MBUS_BT656: - csi->v4l2_ep = *vep; + csi_dev->v4l2.v4l2_ep = *vep; return 0; default: dev_err(dev, "Unsupported media bus type\n"); @@ -712,76 +696,79 @@ static int sun6i_csi_fwnode_parse(struct device *dev, } } -static void sun6i_csi_v4l2_cleanup(struct sun6i_csi *csi) +static void sun6i_csi_v4l2_cleanup(struct sun6i_csi_device *csi_dev) { - media_device_unregister(&csi->media_dev); - v4l2_async_nf_unregister(&csi->notifier); - v4l2_async_nf_cleanup(&csi->notifier); - sun6i_video_cleanup(&csi->video); - v4l2_device_unregister(&csi->v4l2_dev); - v4l2_ctrl_handler_free(&csi->ctrl_handler); - media_device_cleanup(&csi->media_dev); + struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2; + + media_device_unregister(&v4l2->media_dev); + v4l2_async_nf_unregister(&v4l2->notifier); + v4l2_async_nf_cleanup(&v4l2->notifier); + sun6i_video_cleanup(&csi_dev->video); + v4l2_device_unregister(&v4l2->v4l2_dev); + v4l2_ctrl_handler_free(&v4l2->ctrl_handler); + media_device_cleanup(&v4l2->media_dev); } -static int sun6i_csi_v4l2_init(struct sun6i_csi *csi) +static int sun6i_csi_v4l2_init(struct sun6i_csi_device *csi_dev) { + struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2; int ret; - csi->media_dev.dev = csi->dev; - strscpy(csi->media_dev.model, SUN6I_CSI_DESCRIPTION, - sizeof(csi->media_dev.model)); - csi->media_dev.hw_revision = 0; + v4l2->media_dev.dev = csi_dev->dev; + strscpy(v4l2->media_dev.model, SUN6I_CSI_DESCRIPTION, + sizeof(v4l2->media_dev.model)); + v4l2->media_dev.hw_revision = 0; - media_device_init(&csi->media_dev); - v4l2_async_nf_init(&csi->notifier); + media_device_init(&v4l2->media_dev); + v4l2_async_nf_init(&v4l2->notifier); - ret = v4l2_ctrl_handler_init(&csi->ctrl_handler, 0); + ret = v4l2_ctrl_handler_init(&v4l2->ctrl_handler, 0); if (ret) { - dev_err(csi->dev, "V4L2 controls handler init failed (%d)\n", + dev_err(csi_dev->dev, "V4L2 controls handler init failed (%d)\n", ret); goto clean_media; } - csi->v4l2_dev.mdev = &csi->media_dev; - csi->v4l2_dev.ctrl_handler = &csi->ctrl_handler; - ret = v4l2_device_register(csi->dev, &csi->v4l2_dev); + v4l2->v4l2_dev.mdev = &v4l2->media_dev; + v4l2->v4l2_dev.ctrl_handler = &v4l2->ctrl_handler; + ret = v4l2_device_register(csi_dev->dev, &v4l2->v4l2_dev); if (ret) { - dev_err(csi->dev, "V4L2 device registration failed (%d)\n", + dev_err(csi_dev->dev, "V4L2 device registration failed (%d)\n", ret); goto free_ctrl; } - ret = sun6i_video_init(&csi->video, csi, SUN6I_CSI_NAME); + ret = sun6i_video_init(&csi_dev->video, csi_dev, SUN6I_CSI_NAME); if (ret) goto unreg_v4l2; - ret = v4l2_async_nf_parse_fwnode_endpoints(csi->dev, - &csi->notifier, + ret = v4l2_async_nf_parse_fwnode_endpoints(csi_dev->dev, + &v4l2->notifier, sizeof(struct v4l2_async_subdev), sun6i_csi_fwnode_parse); if (ret) goto clean_video; - csi->notifier.ops = &sun6i_csi_async_ops; + v4l2->notifier.ops = &sun6i_csi_async_ops; - ret = v4l2_async_nf_register(&csi->v4l2_dev, &csi->notifier); + ret = v4l2_async_nf_register(&v4l2->v4l2_dev, &v4l2->notifier); if (ret) { - dev_err(csi->dev, "notifier registration failed\n"); + dev_err(csi_dev->dev, "notifier registration failed\n"); goto clean_video; } return 0; clean_video: - sun6i_video_cleanup(&csi->video); + sun6i_video_cleanup(&csi_dev->video); unreg_v4l2: - v4l2_device_unregister(&csi->v4l2_dev); + v4l2_device_unregister(&v4l2->v4l2_dev); free_ctrl: - v4l2_ctrl_handler_free(&csi->ctrl_handler); + v4l2_ctrl_handler_free(&v4l2->ctrl_handler); clean_media: - v4l2_async_nf_cleanup(&csi->notifier); - media_device_cleanup(&csi->media_dev); + v4l2_async_nf_cleanup(&v4l2->notifier); + media_device_cleanup(&v4l2->media_dev); return ret; } @@ -791,8 +778,8 @@ clean_media: */ static irqreturn_t sun6i_csi_isr(int irq, void *dev_id) { - struct sun6i_csi_dev *sdev = (struct sun6i_csi_dev *)dev_id; - struct regmap *regmap = sdev->regmap; + struct sun6i_csi_device *csi_dev = (struct sun6i_csi_device *)dev_id; + struct regmap *regmap = csi_dev->regmap; u32 status; regmap_read(regmap, CSI_CH_INT_STA_REG, &status); @@ -812,7 +799,7 @@ static irqreturn_t sun6i_csi_isr(int irq, void *dev_id) } if (status & CSI_CH_INT_STA_FD_PD) - sun6i_video_frame_done(&sdev->csi.video); + sun6i_video_frame_done(&csi_dev->video); regmap_write(regmap, CSI_CH_INT_STA_REG, status); @@ -826,7 +813,7 @@ static const struct regmap_config sun6i_csi_regmap_config = { .max_register = 0x9c, }; -static int sun6i_csi_resource_request(struct sun6i_csi_dev *sdev, +static int sun6i_csi_resource_request(struct sun6i_csi_device *csi_dev, struct platform_device *pdev) { void __iomem *io_base; @@ -837,29 +824,29 @@ static int sun6i_csi_resource_request(struct sun6i_csi_dev *sdev, if (IS_ERR(io_base)) return PTR_ERR(io_base); - sdev->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "bus", io_base, - &sun6i_csi_regmap_config); - if (IS_ERR(sdev->regmap)) { + csi_dev->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "bus", io_base, + &sun6i_csi_regmap_config); + if (IS_ERR(csi_dev->regmap)) { dev_err(&pdev->dev, "Failed to init register map\n"); - return PTR_ERR(sdev->regmap); + return PTR_ERR(csi_dev->regmap); } - sdev->clk_mod = devm_clk_get(&pdev->dev, "mod"); - if (IS_ERR(sdev->clk_mod)) { + csi_dev->clk_mod = devm_clk_get(&pdev->dev, "mod"); + if (IS_ERR(csi_dev->clk_mod)) { dev_err(&pdev->dev, "Unable to acquire csi clock\n"); - return PTR_ERR(sdev->clk_mod); + return PTR_ERR(csi_dev->clk_mod); } - sdev->clk_ram = devm_clk_get(&pdev->dev, "ram"); - if (IS_ERR(sdev->clk_ram)) { + csi_dev->clk_ram = devm_clk_get(&pdev->dev, "ram"); + if (IS_ERR(csi_dev->clk_ram)) { dev_err(&pdev->dev, "Unable to acquire dram-csi clock\n"); - return PTR_ERR(sdev->clk_ram); + return PTR_ERR(csi_dev->clk_ram); } - sdev->rstc_bus = devm_reset_control_get_shared(&pdev->dev, NULL); - if (IS_ERR(sdev->rstc_bus)) { + csi_dev->reset = devm_reset_control_get_shared(&pdev->dev, NULL); + if (IS_ERR(csi_dev->reset)) { dev_err(&pdev->dev, "Cannot get reset controller\n"); - return PTR_ERR(sdev->rstc_bus); + return PTR_ERR(csi_dev->reset); } irq = platform_get_irq(pdev, 0); @@ -867,7 +854,7 @@ static int sun6i_csi_resource_request(struct sun6i_csi_dev *sdev, return -ENXIO; ret = devm_request_irq(&pdev->dev, irq, sun6i_csi_isr, 0, - SUN6I_CSI_NAME, sdev); + SUN6I_CSI_NAME, csi_dev); if (ret) { dev_err(&pdev->dev, "Cannot request csi IRQ\n"); return ret; @@ -878,30 +865,29 @@ static int sun6i_csi_resource_request(struct sun6i_csi_dev *sdev, static int sun6i_csi_probe(struct platform_device *pdev) { - struct sun6i_csi_dev *sdev; + struct sun6i_csi_device *csi_dev; int ret; - sdev = devm_kzalloc(&pdev->dev, sizeof(*sdev), GFP_KERNEL); - if (!sdev) + csi_dev = devm_kzalloc(&pdev->dev, sizeof(*csi_dev), GFP_KERNEL); + if (!csi_dev) return -ENOMEM; - sdev->dev = &pdev->dev; + csi_dev->dev = &pdev->dev; - ret = sun6i_csi_resource_request(sdev, pdev); + ret = sun6i_csi_resource_request(csi_dev, pdev); if (ret) return ret; - platform_set_drvdata(pdev, sdev); + platform_set_drvdata(pdev, csi_dev); - sdev->csi.dev = &pdev->dev; - return sun6i_csi_v4l2_init(&sdev->csi); + return sun6i_csi_v4l2_init(csi_dev); } static int sun6i_csi_remove(struct platform_device *pdev) { - struct sun6i_csi_dev *sdev = platform_get_drvdata(pdev); + struct sun6i_csi_device *csi_dev = platform_get_drvdata(pdev); - sun6i_csi_v4l2_cleanup(&sdev->csi); + sun6i_csi_v4l2_cleanup(csi_dev); return 0; } diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h index e04f3c3fa27b..e151f983dbc6 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h @@ -17,8 +17,6 @@ #define SUN6I_CSI_NAME "sun6i-csi" #define SUN6I_CSI_DESCRIPTION "Allwinner A31 CSI Device" -struct sun6i_csi; - /** * struct sun6i_csi_config - configs for sun6i csi * @pixelformat: v4l2 pixel format (V4L2_PIX_FMT_*) @@ -35,59 +33,75 @@ struct sun6i_csi_config { u32 height; }; -struct sun6i_csi { - struct device *dev; - struct v4l2_ctrl_handler ctrl_handler; +struct sun6i_csi_v4l2 { struct v4l2_device v4l2_dev; + struct v4l2_ctrl_handler ctrl_handler; struct media_device media_dev; struct v4l2_async_notifier notifier; - /* video port settings */ struct v4l2_fwnode_endpoint v4l2_ep; +}; - struct sun6i_csi_config config; +struct sun6i_csi_device { + struct device *dev; + struct sun6i_csi_config config; + struct sun6i_csi_v4l2 v4l2; struct sun6i_video video; + + struct regmap *regmap; + struct clk *clk_mod; + struct clk *clk_ram; + struct reset_control *reset; + + int planar_offset[3]; }; /** * sun6i_csi_is_format_supported() - check if the format supported by csi - * @csi: pointer to the csi + * @csi_dev: pointer to the csi device * @pixformat: v4l2 pixel format (V4L2_PIX_FMT_*) * @mbus_code: media bus format code (MEDIA_BUS_FMT_*) + * + * Return: true if format is supported, false otherwise. */ -bool sun6i_csi_is_format_supported(struct sun6i_csi *csi, u32 pixformat, - u32 mbus_code); +bool sun6i_csi_is_format_supported(struct sun6i_csi_device *csi_dev, + u32 pixformat, u32 mbus_code); /** * sun6i_csi_set_power() - power on/off the csi - * @csi: pointer to the csi + * @csi_dev: pointer to the csi device * @enable: on/off + * + * Return: 0 if successful, error code otherwise. */ -int sun6i_csi_set_power(struct sun6i_csi *csi, bool enable); +int sun6i_csi_set_power(struct sun6i_csi_device *csi_dev, bool enable); /** * sun6i_csi_update_config() - update the csi register settings - * @csi: pointer to the csi + * @csi_dev: pointer to the csi device * @config: see struct sun6i_csi_config + * + * Return: 0 if successful, error code otherwise. */ -int sun6i_csi_update_config(struct sun6i_csi *csi, +int sun6i_csi_update_config(struct sun6i_csi_device *csi_dev, struct sun6i_csi_config *config); /** * sun6i_csi_update_buf_addr() - update the csi frame buffer address - * @csi: pointer to the csi + * @csi_dev: pointer to the csi device * @addr: frame buffer's physical address */ -void sun6i_csi_update_buf_addr(struct sun6i_csi *csi, dma_addr_t addr); +void sun6i_csi_update_buf_addr(struct sun6i_csi_device *csi_dev, + dma_addr_t addr); /** * sun6i_csi_set_stream() - start/stop csi streaming - * @csi: pointer to the csi + * @csi_dev: pointer to the csi device * @enable: start/stop */ -void sun6i_csi_set_stream(struct sun6i_csi *csi, bool enable); +void sun6i_csi_set_stream(struct sun6i_csi_device *csi_dev, bool enable); /* get bpp form v4l2 pixformat */ static inline int sun6i_csi_get_bpp(unsigned int pixformat) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c index da4b7f9557a1..1bfe7b3abc91 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c @@ -162,7 +162,7 @@ static int sun6i_video_start_streaming(struct vb2_queue *vq, unsigned int count) config.width = video->fmt.fmt.pix.width; config.height = video->fmt.fmt.pix.height; - ret = sun6i_csi_update_config(video->csi, &config); + ret = sun6i_csi_update_config(video->csi_dev, &config); if (ret < 0) goto stop_media_pipeline; @@ -171,9 +171,9 @@ static int sun6i_video_start_streaming(struct vb2_queue *vq, unsigned int count) buf = list_first_entry(&video->dma_queue, struct sun6i_csi_buffer, list); buf->queued_to_csi = true; - sun6i_csi_update_buf_addr(video->csi, buf->dma_addr); + sun6i_csi_update_buf_addr(video->csi_dev, buf->dma_addr); - sun6i_csi_set_stream(video->csi, true); + sun6i_csi_set_stream(video->csi_dev, true); /* * CSI will lookup the next dma buffer for next frame before the @@ -194,7 +194,7 @@ static int sun6i_video_start_streaming(struct vb2_queue *vq, unsigned int count) */ next_buf = list_next_entry(buf, list); next_buf->queued_to_csi = true; - sun6i_csi_update_buf_addr(video->csi, next_buf->dma_addr); + sun6i_csi_update_buf_addr(video->csi_dev, next_buf->dma_addr); spin_unlock_irqrestore(&video->dma_queue_lock, flags); @@ -205,7 +205,7 @@ static int sun6i_video_start_streaming(struct vb2_queue *vq, unsigned int count) return 0; stop_csi_stream: - sun6i_csi_set_stream(video->csi, false); + sun6i_csi_set_stream(video->csi_dev, false); stop_media_pipeline: video_device_pipeline_stop(&video->vdev); clear_dma_queue: @@ -229,7 +229,7 @@ static void sun6i_video_stop_streaming(struct vb2_queue *vq) if (subdev) v4l2_subdev_call(subdev, video, s_stream, 0); - sun6i_csi_set_stream(video->csi, false); + sun6i_csi_set_stream(video->csi_dev, false); video_device_pipeline_stop(&video->vdev); @@ -266,7 +266,7 @@ void sun6i_video_frame_done(struct sun6i_video *video) buf = list_first_entry(&video->dma_queue, struct sun6i_csi_buffer, list); if (list_is_last(&buf->list, &video->dma_queue)) { - dev_dbg(video->csi->dev, "Frame dropped!\n"); + dev_dbg(video->csi_dev->dev, "Frame dropped!\n"); goto unlock; } @@ -278,8 +278,8 @@ void sun6i_video_frame_done(struct sun6i_video *video) */ if (!next_buf->queued_to_csi) { next_buf->queued_to_csi = true; - sun6i_csi_update_buf_addr(video->csi, next_buf->dma_addr); - dev_dbg(video->csi->dev, "Frame dropped!\n"); + sun6i_csi_update_buf_addr(video->csi_dev, next_buf->dma_addr); + dev_dbg(video->csi_dev->dev, "Frame dropped!\n"); goto unlock; } @@ -293,9 +293,9 @@ void sun6i_video_frame_done(struct sun6i_video *video) if (!list_is_last(&next_buf->list, &video->dma_queue)) { next_buf = list_next_entry(next_buf, list); next_buf->queued_to_csi = true; - sun6i_csi_update_buf_addr(video->csi, next_buf->dma_addr); + sun6i_csi_update_buf_addr(video->csi_dev, next_buf->dma_addr); } else { - dev_dbg(video->csi->dev, "Next frame will be dropped!\n"); + dev_dbg(video->csi_dev->dev, "Next frame will be dropped!\n"); } unlock: @@ -321,7 +321,7 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(cap->driver, "sun6i-video", sizeof(cap->driver)); strscpy(cap->card, video->vdev.name, sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - video->csi->dev->of_node->name); + video->csi_dev->dev->of_node->name); return 0; } @@ -488,7 +488,7 @@ static int sun6i_video_open(struct file *file) if (!v4l2_fh_is_singular_file(file)) goto unlock; - ret = sun6i_csi_set_power(video->csi, true); + ret = sun6i_csi_set_power(video->csi_dev, true); if (ret < 0) goto fh_release; @@ -516,7 +516,7 @@ static int sun6i_video_close(struct file *file) v4l2_pipeline_pm_put(&video->vdev.entity); if (last_fh) - sun6i_csi_set_power(video->csi, false); + sun6i_csi_set_power(video->csi_dev, false); mutex_unlock(&video->lock); @@ -561,7 +561,7 @@ static int sun6i_video_link_validate(struct media_link *link) video->mbus_code = 0; if (!media_pad_remote_pad_first(link->sink->entity->pads)) { - dev_info(video->csi->dev, + dev_info(video->csi_dev->dev, "video node %s pad not connected\n", vdev->name); return -ENOLINK; } @@ -570,10 +570,10 @@ static int sun6i_video_link_validate(struct media_link *link) if (ret < 0) return ret; - if (!sun6i_csi_is_format_supported(video->csi, + if (!sun6i_csi_is_format_supported(video->csi_dev, video->fmt.fmt.pix.pixelformat, source_fmt.format.code)) { - dev_err(video->csi->dev, + dev_err(video->csi_dev->dev, "Unsupported pixformat: 0x%x with mbus code: 0x%x!\n", video->fmt.fmt.pix.pixelformat, source_fmt.format.code); @@ -582,7 +582,7 @@ static int sun6i_video_link_validate(struct media_link *link) if (source_fmt.format.width != video->fmt.fmt.pix.width || source_fmt.format.height != video->fmt.fmt.pix.height) { - dev_err(video->csi->dev, + dev_err(video->csi_dev->dev, "Wrong width or height %ux%u (%ux%u expected)\n", video->fmt.fmt.pix.width, video->fmt.fmt.pix.height, source_fmt.format.width, source_fmt.format.height); @@ -598,15 +598,16 @@ static const struct media_entity_operations sun6i_video_media_ops = { .link_validate = sun6i_video_link_validate }; -int sun6i_video_init(struct sun6i_video *video, struct sun6i_csi *csi, - const char *name) +int sun6i_video_init(struct sun6i_video *video, + struct sun6i_csi_device *csi_dev, const char *name) { + struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2; struct video_device *vdev = &video->vdev; struct vb2_queue *vidq = &video->vb2_vidq; struct v4l2_format fmt = { 0 }; int ret; - video->csi = csi; + video->csi_dev = csi_dev; /* Initialize the media entity... */ video->pad.flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT; @@ -641,11 +642,12 @@ int sun6i_video_init(struct sun6i_video *video, struct sun6i_csi *csi, vidq->lock = &video->lock; /* Make sure non-dropped frame */ vidq->min_buffers_needed = 3; - vidq->dev = csi->dev; + vidq->dev = csi_dev->dev; ret = vb2_queue_init(vidq); if (ret) { - v4l2_err(&csi->v4l2_dev, "vb2_queue_init failed: %d\n", ret); + v4l2_err(&v4l2->v4l2_dev, "vb2_queue_init failed: %d\n", + ret); goto clean_entity; } @@ -656,7 +658,7 @@ int sun6i_video_init(struct sun6i_video *video, struct sun6i_csi *csi, vdev->ioctl_ops = &sun6i_video_ioctl_ops; vdev->vfl_type = VFL_TYPE_VIDEO; vdev->vfl_dir = VFL_DIR_RX; - vdev->v4l2_dev = &csi->v4l2_dev; + vdev->v4l2_dev = &v4l2->v4l2_dev; vdev->queue = vidq; vdev->lock = &video->lock; vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE; @@ -664,7 +666,7 @@ int sun6i_video_init(struct sun6i_video *video, struct sun6i_csi *csi, ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); if (ret < 0) { - v4l2_err(&csi->v4l2_dev, + v4l2_err(&v4l2->v4l2_dev, "video_register_device failed: %d\n", ret); goto clean_entity; } diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h index b9cd919c24ac..30e37ee0d07f 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h @@ -11,12 +11,12 @@ #include #include -struct sun6i_csi; +struct sun6i_csi_device; struct sun6i_video { + struct sun6i_csi_device *csi_dev; struct video_device vdev; struct media_pad pad; - struct sun6i_csi *csi; struct mutex lock; @@ -29,8 +29,8 @@ struct sun6i_video { u32 mbus_code; }; -int sun6i_video_init(struct sun6i_video *video, struct sun6i_csi *csi, - const char *name); +int sun6i_video_init(struct sun6i_video *video, + struct sun6i_csi_device *csi_dev, const char *name); void sun6i_video_cleanup(struct sun6i_video *video); void sun6i_video_frame_done(struct sun6i_video *video); -- cgit From 43e80196625cdb3133ec6fef4ac06e6a967094fd Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Fri, 26 Aug 2022 20:32:00 +0200 Subject: media: sun6i-csi: Tidy up platform code Various renames, variables lowering and other cosmetic changes in the platform-support code. No functional change intended. Signed-off-by: Paul Kocialkowski Reviewed-by: Maxime Ripard Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c | 98 ++++++++++++---------- drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h | 4 +- 2 files changed, 56 insertions(+), 46 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index 0e2b4d38e81c..514f97d67c1c 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -153,25 +153,25 @@ int sun6i_csi_set_power(struct sun6i_csi_device *csi_dev, bool enable) if (!enable) { regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN, 0); - clk_disable_unprepare(csi_dev->clk_ram); + clk_disable_unprepare(csi_dev->clock_ram); if (of_device_is_compatible(dev->of_node, "allwinner,sun50i-a64-csi")) - clk_rate_exclusive_put(csi_dev->clk_mod); - clk_disable_unprepare(csi_dev->clk_mod); + clk_rate_exclusive_put(csi_dev->clock_mod); + clk_disable_unprepare(csi_dev->clock_mod); reset_control_assert(csi_dev->reset); return 0; } - ret = clk_prepare_enable(csi_dev->clk_mod); + ret = clk_prepare_enable(csi_dev->clock_mod); if (ret) { dev_err(csi_dev->dev, "Enable csi clk err %d\n", ret); return ret; } if (of_device_is_compatible(dev->of_node, "allwinner,sun50i-a64-csi")) - clk_set_rate_exclusive(csi_dev->clk_mod, 300000000); + clk_set_rate_exclusive(csi_dev->clock_mod, 300000000); - ret = clk_prepare_enable(csi_dev->clk_ram); + ret = clk_prepare_enable(csi_dev->clock_ram); if (ret) { dev_err(csi_dev->dev, "Enable clk_dram_csi clk err %d\n", ret); goto clk_mod_disable; @@ -188,11 +188,11 @@ int sun6i_csi_set_power(struct sun6i_csi_device *csi_dev, bool enable) return 0; clk_ram_disable: - clk_disable_unprepare(csi_dev->clk_ram); + clk_disable_unprepare(csi_dev->clock_ram); clk_mod_disable: if (of_device_is_compatible(dev->of_node, "allwinner,sun50i-a64-csi")) - clk_rate_exclusive_put(csi_dev->clk_mod); - clk_disable_unprepare(csi_dev->clk_mod); + clk_rate_exclusive_put(csi_dev->clock_mod); + clk_disable_unprepare(csi_dev->clock_mod); return ret; } @@ -773,12 +773,11 @@ clean_media: return ret; } -/* ----------------------------------------------------------------------------- - * Resources and IRQ - */ -static irqreturn_t sun6i_csi_isr(int irq, void *dev_id) +/* Platform */ + +static irqreturn_t sun6i_csi_interrupt(int irq, void *private) { - struct sun6i_csi_device *csi_dev = (struct sun6i_csi_device *)dev_id; + struct sun6i_csi_device *csi_dev = private; struct regmap *regmap = csi_dev->regmap; u32 status; @@ -813,73 +812,82 @@ static const struct regmap_config sun6i_csi_regmap_config = { .max_register = 0x9c, }; -static int sun6i_csi_resource_request(struct sun6i_csi_device *csi_dev, - struct platform_device *pdev) +static int sun6i_csi_resources_setup(struct sun6i_csi_device *csi_dev, + struct platform_device *platform_dev) { + struct device *dev = csi_dev->dev; void __iomem *io_base; int ret; int irq; - io_base = devm_platform_ioremap_resource(pdev, 0); + /* Registers */ + + io_base = devm_platform_ioremap_resource(platform_dev, 0); if (IS_ERR(io_base)) return PTR_ERR(io_base); - csi_dev->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "bus", io_base, + csi_dev->regmap = devm_regmap_init_mmio_clk(dev, "bus", io_base, &sun6i_csi_regmap_config); if (IS_ERR(csi_dev->regmap)) { - dev_err(&pdev->dev, "Failed to init register map\n"); + dev_err(dev, "failed to init register map\n"); return PTR_ERR(csi_dev->regmap); } - csi_dev->clk_mod = devm_clk_get(&pdev->dev, "mod"); - if (IS_ERR(csi_dev->clk_mod)) { - dev_err(&pdev->dev, "Unable to acquire csi clock\n"); - return PTR_ERR(csi_dev->clk_mod); + /* Clocks */ + + csi_dev->clock_mod = devm_clk_get(dev, "mod"); + if (IS_ERR(csi_dev->clock_mod)) { + dev_err(dev, "failed to acquire module clock\n"); + return PTR_ERR(csi_dev->clock_mod); } - csi_dev->clk_ram = devm_clk_get(&pdev->dev, "ram"); - if (IS_ERR(csi_dev->clk_ram)) { - dev_err(&pdev->dev, "Unable to acquire dram-csi clock\n"); - return PTR_ERR(csi_dev->clk_ram); + csi_dev->clock_ram = devm_clk_get(dev, "ram"); + if (IS_ERR(csi_dev->clock_ram)) { + dev_err(dev, "failed to acquire ram clock\n"); + return PTR_ERR(csi_dev->clock_ram); } - csi_dev->reset = devm_reset_control_get_shared(&pdev->dev, NULL); + /* Reset */ + + csi_dev->reset = devm_reset_control_get_shared(dev, NULL); if (IS_ERR(csi_dev->reset)) { - dev_err(&pdev->dev, "Cannot get reset controller\n"); + dev_err(dev, "failed to acquire reset\n"); return PTR_ERR(csi_dev->reset); } - irq = platform_get_irq(pdev, 0); + /* Interrupt */ + + irq = platform_get_irq(platform_dev, 0); if (irq < 0) return -ENXIO; - ret = devm_request_irq(&pdev->dev, irq, sun6i_csi_isr, 0, - SUN6I_CSI_NAME, csi_dev); + ret = devm_request_irq(dev, irq, sun6i_csi_interrupt, 0, SUN6I_CSI_NAME, + csi_dev); if (ret) { - dev_err(&pdev->dev, "Cannot request csi IRQ\n"); + dev_err(dev, "failed to request interrupt\n"); return ret; } return 0; } -static int sun6i_csi_probe(struct platform_device *pdev) +static int sun6i_csi_probe(struct platform_device *platform_dev) { struct sun6i_csi_device *csi_dev; + struct device *dev = &platform_dev->dev; int ret; - csi_dev = devm_kzalloc(&pdev->dev, sizeof(*csi_dev), GFP_KERNEL); + csi_dev = devm_kzalloc(dev, sizeof(*csi_dev), GFP_KERNEL); if (!csi_dev) return -ENOMEM; - csi_dev->dev = &pdev->dev; + csi_dev->dev = &platform_dev->dev; + platform_set_drvdata(platform_dev, csi_dev); - ret = sun6i_csi_resource_request(csi_dev, pdev); + ret = sun6i_csi_resources_setup(csi_dev, platform_dev); if (ret) return ret; - platform_set_drvdata(pdev, csi_dev); - return sun6i_csi_v4l2_init(csi_dev); } @@ -900,16 +908,18 @@ static const struct of_device_id sun6i_csi_of_match[] = { { .compatible = "allwinner,sun50i-a64-csi", }, {}, }; + MODULE_DEVICE_TABLE(of, sun6i_csi_of_match); static struct platform_driver sun6i_csi_platform_driver = { - .probe = sun6i_csi_probe, - .remove = sun6i_csi_remove, - .driver = { - .name = SUN6I_CSI_NAME, - .of_match_table = of_match_ptr(sun6i_csi_of_match), + .probe = sun6i_csi_probe, + .remove = sun6i_csi_remove, + .driver = { + .name = SUN6I_CSI_NAME, + .of_match_table = of_match_ptr(sun6i_csi_of_match), }, }; + module_platform_driver(sun6i_csi_platform_driver); MODULE_DESCRIPTION("Allwinner A31 Camera Sensor Interface driver"); diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h index e151f983dbc6..937ca0fe4ee6 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h @@ -51,8 +51,8 @@ struct sun6i_csi_device { struct sun6i_video video; struct regmap *regmap; - struct clk *clk_mod; - struct clk *clk_ram; + struct clk *clock_mod; + struct clk *clock_ram; struct reset_control *reset; int planar_offset[3]; -- cgit From 740b5b3d156b6a9cb3b3d3ee2427acca0a890607 Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Fri, 26 Aug 2022 20:32:01 +0200 Subject: media: sun6i-csi: Always set exclusive module clock rate In some situations the default rate of the module clock is not the required one for operation (for example when reconfiguring the clock tree to use a different parent). As a result, always set the correct rate for the clock (and take care of cleanup). Signed-off-by: Paul Kocialkowski Reviewed-by: Jernej Skrabec Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c | 54 ++++++++++++++++------ 1 file changed, 41 insertions(+), 13 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index 514f97d67c1c..89a15cd779ac 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -154,9 +154,6 @@ int sun6i_csi_set_power(struct sun6i_csi_device *csi_dev, bool enable) regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN, 0); clk_disable_unprepare(csi_dev->clock_ram); - if (of_device_is_compatible(dev->of_node, - "allwinner,sun50i-a64-csi")) - clk_rate_exclusive_put(csi_dev->clock_mod); clk_disable_unprepare(csi_dev->clock_mod); reset_control_assert(csi_dev->reset); return 0; @@ -168,9 +165,6 @@ int sun6i_csi_set_power(struct sun6i_csi_device *csi_dev, bool enable) return ret; } - if (of_device_is_compatible(dev->of_node, "allwinner,sun50i-a64-csi")) - clk_set_rate_exclusive(csi_dev->clock_mod, 300000000); - ret = clk_prepare_enable(csi_dev->clock_ram); if (ret) { dev_err(csi_dev->dev, "Enable clk_dram_csi clk err %d\n", ret); @@ -190,8 +184,6 @@ int sun6i_csi_set_power(struct sun6i_csi_device *csi_dev, bool enable) clk_ram_disable: clk_disable_unprepare(csi_dev->clock_ram); clk_mod_disable: - if (of_device_is_compatible(dev->of_node, "allwinner,sun50i-a64-csi")) - clk_rate_exclusive_put(csi_dev->clock_mod); clk_disable_unprepare(csi_dev->clock_mod); return ret; } @@ -816,6 +808,7 @@ static int sun6i_csi_resources_setup(struct sun6i_csi_device *csi_dev, struct platform_device *platform_dev) { struct device *dev = csi_dev->dev; + unsigned long clock_mod_rate; void __iomem *io_base; int ret; int irq; @@ -847,28 +840,53 @@ static int sun6i_csi_resources_setup(struct sun6i_csi_device *csi_dev, return PTR_ERR(csi_dev->clock_ram); } + if (of_device_is_compatible(dev->of_node, "allwinner,sun50i-a64-csi")) + clock_mod_rate = 300000000; + else + clock_mod_rate = 297000000; + + ret = clk_set_rate_exclusive(csi_dev->clock_mod, clock_mod_rate); + if (ret) { + dev_err(dev, "failed to set mod clock rate\n"); + return ret; + } + /* Reset */ csi_dev->reset = devm_reset_control_get_shared(dev, NULL); if (IS_ERR(csi_dev->reset)) { dev_err(dev, "failed to acquire reset\n"); - return PTR_ERR(csi_dev->reset); + ret = PTR_ERR(csi_dev->reset); + goto error_clock_rate_exclusive; } /* Interrupt */ irq = platform_get_irq(platform_dev, 0); - if (irq < 0) - return -ENXIO; + if (irq < 0) { + dev_err(dev, "failed to get interrupt\n"); + ret = -ENXIO; + goto error_clock_rate_exclusive; + } ret = devm_request_irq(dev, irq, sun6i_csi_interrupt, 0, SUN6I_CSI_NAME, csi_dev); if (ret) { dev_err(dev, "failed to request interrupt\n"); - return ret; + goto error_clock_rate_exclusive; } return 0; + +error_clock_rate_exclusive: + clk_rate_exclusive_put(csi_dev->clock_mod); + + return ret; +} + +static void sun6i_csi_resources_cleanup(struct sun6i_csi_device *csi_dev) +{ + clk_rate_exclusive_put(csi_dev->clock_mod); } static int sun6i_csi_probe(struct platform_device *platform_dev) @@ -888,7 +906,16 @@ static int sun6i_csi_probe(struct platform_device *platform_dev) if (ret) return ret; - return sun6i_csi_v4l2_init(csi_dev); + ret = sun6i_csi_v4l2_init(csi_dev); + if (ret) + goto error_resources; + + return 0; + +error_resources: + sun6i_csi_resources_cleanup(csi_dev); + + return ret; } static int sun6i_csi_remove(struct platform_device *pdev) @@ -896,6 +923,7 @@ static int sun6i_csi_remove(struct platform_device *pdev) struct sun6i_csi_device *csi_dev = platform_get_drvdata(pdev); sun6i_csi_v4l2_cleanup(csi_dev); + sun6i_csi_resources_cleanup(csi_dev); return 0; } -- cgit From bc67ec9e1348d94ead4e4704ca79e7a4bc97fac3 Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Fri, 26 Aug 2022 20:32:02 +0200 Subject: media: sun6i-csi: Define and use variant to get module clock rate Introduce a proper variant structure with the module clock rate instead of hardcoding it with a manual check on the compatible. Signed-off-by: Paul Kocialkowski Reviewed-by: Jernej Skrabec Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c | 47 ++++++++++++++++------ drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h | 4 ++ 2 files changed, 39 insertions(+), 12 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index 89a15cd779ac..800851f4e18c 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -808,11 +808,15 @@ static int sun6i_csi_resources_setup(struct sun6i_csi_device *csi_dev, struct platform_device *platform_dev) { struct device *dev = csi_dev->dev; - unsigned long clock_mod_rate; + const struct sun6i_csi_variant *variant; void __iomem *io_base; int ret; int irq; + variant = of_device_get_match_data(dev); + if (!variant) + return -EINVAL; + /* Registers */ io_base = devm_platform_ioremap_resource(platform_dev, 0); @@ -840,12 +844,8 @@ static int sun6i_csi_resources_setup(struct sun6i_csi_device *csi_dev, return PTR_ERR(csi_dev->clock_ram); } - if (of_device_is_compatible(dev->of_node, "allwinner,sun50i-a64-csi")) - clock_mod_rate = 300000000; - else - clock_mod_rate = 297000000; - - ret = clk_set_rate_exclusive(csi_dev->clock_mod, clock_mod_rate); + ret = clk_set_rate_exclusive(csi_dev->clock_mod, + variant->clock_mod_rate); if (ret) { dev_err(dev, "failed to set mod clock rate\n"); return ret; @@ -928,12 +928,35 @@ static int sun6i_csi_remove(struct platform_device *pdev) return 0; } +static const struct sun6i_csi_variant sun6i_a31_csi_variant = { + .clock_mod_rate = 297000000, +}; + +static const struct sun6i_csi_variant sun50i_a64_csi_variant = { + .clock_mod_rate = 300000000, +}; + static const struct of_device_id sun6i_csi_of_match[] = { - { .compatible = "allwinner,sun6i-a31-csi", }, - { .compatible = "allwinner,sun8i-a83t-csi", }, - { .compatible = "allwinner,sun8i-h3-csi", }, - { .compatible = "allwinner,sun8i-v3s-csi", }, - { .compatible = "allwinner,sun50i-a64-csi", }, + { + .compatible = "allwinner,sun6i-a31-csi", + .data = &sun6i_a31_csi_variant, + }, + { + .compatible = "allwinner,sun8i-a83t-csi", + .data = &sun6i_a31_csi_variant, + }, + { + .compatible = "allwinner,sun8i-h3-csi", + .data = &sun6i_a31_csi_variant, + }, + { + .compatible = "allwinner,sun8i-v3s-csi", + .data = &sun6i_a31_csi_variant, + }, + { + .compatible = "allwinner,sun50i-a64-csi", + .data = &sun50i_a64_csi_variant, + }, {}, }; diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h index 937ca0fe4ee6..e301d80362cf 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h @@ -58,6 +58,10 @@ struct sun6i_csi_device { int planar_offset[3]; }; +struct sun6i_csi_variant { + unsigned long clock_mod_rate; +}; + /** * sun6i_csi_is_format_supported() - check if the format supported by csi * @csi_dev: pointer to the csi device -- cgit From 69b80659a728b99b868518b975d00f25ea70ec21 Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Fri, 26 Aug 2022 20:32:03 +0200 Subject: media: sun6i-csi: Use runtime pm for clocks and reset Wrap the clock and reset preparation into runtime pm functions for better organization of the code. Also fix the clock and reset enable order to first deassert reset, as recommended in Allwinner literature. Make the driver depend on PM while at it since runtime pm is mandatory for the driver to work. Signed-off-by: Paul Kocialkowski Reviewed-by: Jernej Skrabec Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sunxi/sun6i-csi/Kconfig | 2 +- drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c | 84 +++++++++++++++------- 2 files changed, 60 insertions(+), 26 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/sunxi/sun6i-csi/Kconfig b/drivers/media/platform/sunxi/sun6i-csi/Kconfig index e5b6991ce7f0..a472f46648af 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/Kconfig +++ b/drivers/media/platform/sunxi/sun6i-csi/Kconfig @@ -2,7 +2,7 @@ config VIDEO_SUN6I_CSI tristate "Allwinner V3s Camera Sensor Interface driver" depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_DEV && COMMON_CLK && RESET_CONTROLLER && HAS_DMA + depends on VIDEO_DEV && COMMON_CLK && RESET_CONTROLLER && HAS_DMA && PM depends on ARCH_SUNXI || COMPILE_TEST select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index 800851f4e18c..31374d45eb9f 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -152,40 +152,18 @@ int sun6i_csi_set_power(struct sun6i_csi_device *csi_dev, bool enable) if (!enable) { regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN, 0); + pm_runtime_put(dev); - clk_disable_unprepare(csi_dev->clock_ram); - clk_disable_unprepare(csi_dev->clock_mod); - reset_control_assert(csi_dev->reset); return 0; } - ret = clk_prepare_enable(csi_dev->clock_mod); - if (ret) { - dev_err(csi_dev->dev, "Enable csi clk err %d\n", ret); + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) return ret; - } - - ret = clk_prepare_enable(csi_dev->clock_ram); - if (ret) { - dev_err(csi_dev->dev, "Enable clk_dram_csi clk err %d\n", ret); - goto clk_mod_disable; - } - - ret = reset_control_deassert(csi_dev->reset); - if (ret) { - dev_err(csi_dev->dev, "reset err %d\n", ret); - goto clk_ram_disable; - } regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN, CSI_EN_CSI_EN); return 0; - -clk_ram_disable: - clk_disable_unprepare(csi_dev->clock_ram); -clk_mod_disable: - clk_disable_unprepare(csi_dev->clock_mod); - return ret; } static enum csi_input_fmt get_csi_input_format(struct sun6i_csi_device *csi_dev, @@ -797,6 +775,56 @@ static irqreturn_t sun6i_csi_interrupt(int irq, void *private) return IRQ_HANDLED; } +static int sun6i_csi_suspend(struct device *dev) +{ + struct sun6i_csi_device *csi_dev = dev_get_drvdata(dev); + + reset_control_assert(csi_dev->reset); + clk_disable_unprepare(csi_dev->clock_ram); + clk_disable_unprepare(csi_dev->clock_mod); + + return 0; +} + +static int sun6i_csi_resume(struct device *dev) +{ + struct sun6i_csi_device *csi_dev = dev_get_drvdata(dev); + int ret; + + ret = reset_control_deassert(csi_dev->reset); + if (ret) { + dev_err(dev, "failed to deassert reset\n"); + return ret; + } + + ret = clk_prepare_enable(csi_dev->clock_mod); + if (ret) { + dev_err(dev, "failed to enable module clock\n"); + goto error_reset; + } + + ret = clk_prepare_enable(csi_dev->clock_ram); + if (ret) { + dev_err(dev, "failed to enable ram clock\n"); + goto error_clock_mod; + } + + return 0; + +error_clock_mod: + clk_disable_unprepare(csi_dev->clock_mod); + +error_reset: + reset_control_assert(csi_dev->reset); + + return ret; +} + +static const struct dev_pm_ops sun6i_csi_pm_ops = { + .runtime_suspend = sun6i_csi_suspend, + .runtime_resume = sun6i_csi_resume, +}; + static const struct regmap_config sun6i_csi_regmap_config = { .reg_bits = 32, .reg_stride = 4, @@ -876,6 +904,10 @@ static int sun6i_csi_resources_setup(struct sun6i_csi_device *csi_dev, goto error_clock_rate_exclusive; } + /* Runtime PM */ + + pm_runtime_enable(dev); + return 0; error_clock_rate_exclusive: @@ -886,6 +918,7 @@ error_clock_rate_exclusive: static void sun6i_csi_resources_cleanup(struct sun6i_csi_device *csi_dev) { + pm_runtime_disable(csi_dev->dev); clk_rate_exclusive_put(csi_dev->clock_mod); } @@ -968,6 +1001,7 @@ static struct platform_driver sun6i_csi_platform_driver = { .driver = { .name = SUN6I_CSI_NAME, .of_match_table = of_match_ptr(sun6i_csi_of_match), + .pm = &sun6i_csi_pm_ops, }, }; -- cgit From bffb52248930d76e98fcc5deecda5bc9b3043ef5 Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Fri, 26 Aug 2022 20:32:04 +0200 Subject: media: sun6i-csi: Tidy up Kconfig Update the option title and help, group related options together, add dependency on VIDEO_DEV since the driver uses it and update the description. Signed-off-by: Paul Kocialkowski Acked-by: Jernej Skrabec Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sunxi/sun6i-csi/Kconfig | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/sunxi/sun6i-csi/Kconfig b/drivers/media/platform/sunxi/sun6i-csi/Kconfig index a472f46648af..886006f6a48a 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/Kconfig +++ b/drivers/media/platform/sunxi/sun6i-csi/Kconfig @@ -1,13 +1,15 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_SUN6I_CSI - tristate "Allwinner V3s Camera Sensor Interface driver" - depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_DEV && COMMON_CLK && RESET_CONTROLLER && HAS_DMA && PM + tristate "Allwinner A31 Camera Sensor Interface (CSI) Driver" + depends on V4L_PLATFORM_DRIVERS && VIDEO_DEV depends on ARCH_SUNXI || COMPILE_TEST + depends on PM && COMMON_CLK && RESET_CONTROLLER && HAS_DMA select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select VIDEOBUF2_DMA_CONTIG - select REGMAP_MMIO select V4L2_FWNODE + select REGMAP_MMIO help - Support for the Allwinner Camera Sensor Interface Controller on V3s. + Support for the Allwinner A31 Camera Sensor Interface (CSI) + controller, also found on other platforms such as the A83T, H3, + V3/V3s or A64. -- cgit From cad7f35c1ab50bad92479e64ae57628b61da8b1b Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Fri, 26 Aug 2022 20:32:05 +0200 Subject: media: sun6i-csi: Tidy up v4l2 code Various cosmetic improvements to the v4l2 registration code, with renames, lowerings, etc. The cleanup function is moved down after setup. No functional change intended. Signed-off-by: Paul Kocialkowski Reviewed-by: Maxime Ripard Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c | 113 ++++++++++++--------- 1 file changed, 66 insertions(+), 47 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index 31374d45eb9f..98c9c887c543 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -27,6 +27,8 @@ #include "sun6i_csi.h" #include "sun6i_csi_reg.h" +/* Helpers */ + /* TODO add 10&12 bit YUV, RGB support */ bool sun6i_csi_is_format_supported(struct sun6i_csi_device *csi_dev, u32 pixformat, u32 mbus_code) @@ -572,9 +574,8 @@ void sun6i_csi_set_stream(struct sun6i_csi_device *csi_dev, bool enable) CSI_CAP_CH0_VCAP_ON); } -/* ----------------------------------------------------------------------------- - * Media Controller and V4L2 - */ +/* V4L2 */ + static int sun6i_csi_link_entity(struct sun6i_csi_device *csi_dev, struct media_entity *entity, struct fwnode_handle *fwnode) @@ -666,83 +667,101 @@ static int sun6i_csi_fwnode_parse(struct device *dev, } } -static void sun6i_csi_v4l2_cleanup(struct sun6i_csi_device *csi_dev) +static int sun6i_csi_v4l2_setup(struct sun6i_csi_device *csi_dev) { struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2; + struct media_device *media_dev = &v4l2->media_dev; + struct v4l2_device *v4l2_dev = &v4l2->v4l2_dev; + struct v4l2_async_notifier *notifier = &v4l2->notifier; + struct device *dev = csi_dev->dev; + int ret; - media_device_unregister(&v4l2->media_dev); - v4l2_async_nf_unregister(&v4l2->notifier); - v4l2_async_nf_cleanup(&v4l2->notifier); - sun6i_video_cleanup(&csi_dev->video); - v4l2_device_unregister(&v4l2->v4l2_dev); - v4l2_ctrl_handler_free(&v4l2->ctrl_handler); - media_device_cleanup(&v4l2->media_dev); -} + /* Media Device */ -static int sun6i_csi_v4l2_init(struct sun6i_csi_device *csi_dev) -{ - struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2; - int ret; + strscpy(media_dev->model, SUN6I_CSI_DESCRIPTION, + sizeof(media_dev->model)); + media_dev->hw_revision = 0; + media_dev->dev = dev; - v4l2->media_dev.dev = csi_dev->dev; - strscpy(v4l2->media_dev.model, SUN6I_CSI_DESCRIPTION, - sizeof(v4l2->media_dev.model)); - v4l2->media_dev.hw_revision = 0; + media_device_init(media_dev); - media_device_init(&v4l2->media_dev); - v4l2_async_nf_init(&v4l2->notifier); + /* V4L2 Control Handler */ ret = v4l2_ctrl_handler_init(&v4l2->ctrl_handler, 0); if (ret) { - dev_err(csi_dev->dev, "V4L2 controls handler init failed (%d)\n", - ret); - goto clean_media; + dev_err(dev, "failed to init v4l2 control handler: %d\n", ret); + goto error_media; } - v4l2->v4l2_dev.mdev = &v4l2->media_dev; - v4l2->v4l2_dev.ctrl_handler = &v4l2->ctrl_handler; - ret = v4l2_device_register(csi_dev->dev, &v4l2->v4l2_dev); + /* V4L2 Device */ + + v4l2_dev->mdev = media_dev; + v4l2_dev->ctrl_handler = &v4l2->ctrl_handler; + + ret = v4l2_device_register(dev, v4l2_dev); if (ret) { - dev_err(csi_dev->dev, "V4L2 device registration failed (%d)\n", - ret); - goto free_ctrl; + dev_err(dev, "failed to register v4l2 device: %d\n", ret); + goto error_v4l2_ctrl; } + /* Video */ + ret = sun6i_video_init(&csi_dev->video, csi_dev, SUN6I_CSI_NAME); if (ret) - goto unreg_v4l2; + goto error_v4l2_device; - ret = v4l2_async_nf_parse_fwnode_endpoints(csi_dev->dev, - &v4l2->notifier, + /* V4L2 Async */ + + v4l2_async_nf_init(notifier); + notifier->ops = &sun6i_csi_async_ops; + + ret = v4l2_async_nf_parse_fwnode_endpoints(dev, notifier, sizeof(struct v4l2_async_subdev), sun6i_csi_fwnode_parse); if (ret) - goto clean_video; - - v4l2->notifier.ops = &sun6i_csi_async_ops; + goto error_video; - ret = v4l2_async_nf_register(&v4l2->v4l2_dev, &v4l2->notifier); + ret = v4l2_async_nf_register(v4l2_dev, notifier); if (ret) { - dev_err(csi_dev->dev, "notifier registration failed\n"); - goto clean_video; + dev_err(dev, "failed to register v4l2 async notifier: %d\n", + ret); + goto error_v4l2_async_notifier; } return 0; -clean_video: +error_v4l2_async_notifier: + v4l2_async_nf_cleanup(notifier); + +error_video: sun6i_video_cleanup(&csi_dev->video); -unreg_v4l2: + +error_v4l2_device: v4l2_device_unregister(&v4l2->v4l2_dev); -free_ctrl: + +error_v4l2_ctrl: v4l2_ctrl_handler_free(&v4l2->ctrl_handler); -clean_media: - v4l2_async_nf_cleanup(&v4l2->notifier); - media_device_cleanup(&v4l2->media_dev); + +error_media: + media_device_cleanup(media_dev); return ret; } +static void sun6i_csi_v4l2_cleanup(struct sun6i_csi_device *csi_dev) +{ + struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2; + + media_device_unregister(&v4l2->media_dev); + v4l2_async_nf_unregister(&v4l2->notifier); + v4l2_async_nf_cleanup(&v4l2->notifier); + sun6i_video_cleanup(&csi_dev->video); + v4l2_device_unregister(&v4l2->v4l2_dev); + v4l2_ctrl_handler_free(&v4l2->ctrl_handler); + media_device_cleanup(&v4l2->media_dev); +} + /* Platform */ static irqreturn_t sun6i_csi_interrupt(int irq, void *private) @@ -939,7 +958,7 @@ static int sun6i_csi_probe(struct platform_device *platform_dev) if (ret) return ret; - ret = sun6i_csi_v4l2_init(csi_dev); + ret = sun6i_csi_v4l2_setup(csi_dev); if (ret) goto error_resources; -- cgit From ab2e8d5d67fb86ff74ccb3cad9b57988fb1adfcd Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Fri, 26 Aug 2022 20:32:06 +0200 Subject: media: sun6i-csi: Tidy up video code Some code cleanups, renames, variable lowerings and moving things around for better organization. No functional change intended. Signed-off-by: Paul Kocialkowski Reviewed-by: Maxime Ripard Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c | 4 +- .../media/platform/sunxi/sun6i-csi/sun6i_video.c | 509 +++++++++++---------- .../media/platform/sunxi/sun6i-csi/sun6i_video.h | 18 +- 3 files changed, 285 insertions(+), 246 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index 98c9c887c543..b4f90b065a0c 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -595,7 +595,7 @@ static int sun6i_csi_link_entity(struct sun6i_csi_device *csi_dev, src_pad_index = ret; - sink = &csi_dev->video.vdev.entity; + sink = &csi_dev->video.video_dev.entity; sink_pad = &csi_dev->video.pad; dev_dbg(csi_dev->dev, "creating %s:%u -> %s:%u link\n", @@ -706,7 +706,7 @@ static int sun6i_csi_v4l2_setup(struct sun6i_csi_device *csi_dev) /* Video */ - ret = sun6i_video_init(&csi_dev->video, csi_dev, SUN6I_CSI_NAME); + ret = sun6i_video_setup(&csi_dev->video, csi_dev); if (ret) goto error_v4l2_device; diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c index 1bfe7b3abc91..4710902447ac 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c @@ -24,14 +24,34 @@ #define MAX_HEIGHT (4800) struct sun6i_csi_buffer { - struct vb2_v4l2_buffer vb; + struct vb2_v4l2_buffer v4l2_buffer; struct list_head list; dma_addr_t dma_addr; bool queued_to_csi; }; -static const u32 supported_pixformats[] = { +/* Helpers */ + +static struct v4l2_subdev * +sun6i_video_remote_subdev(struct sun6i_video *video, u32 *pad) +{ + struct media_pad *remote; + + remote = media_pad_remote_pad_first(&video->pad); + + if (!remote || !is_media_entity_v4l2_subdev(remote->entity)) + return NULL; + + if (pad) + *pad = remote->index; + + return media_entity_to_v4l2_subdev(remote->entity); +} + +/* Format */ + +static const u32 sun6i_video_formats[] = { V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SGBRG8, V4L2_PIX_FMT_SGRBG8, @@ -61,77 +81,80 @@ static const u32 supported_pixformats[] = { V4L2_PIX_FMT_JPEG, }; -static bool is_pixformat_valid(unsigned int pixformat) +static bool sun6i_video_format_check(u32 format) { unsigned int i; - for (i = 0; i < ARRAY_SIZE(supported_pixformats); i++) - if (supported_pixformats[i] == pixformat) + for (i = 0; i < ARRAY_SIZE(sun6i_video_formats); i++) + if (sun6i_video_formats[i] == format) return true; return false; } -static struct v4l2_subdev * -sun6i_video_remote_subdev(struct sun6i_video *video, u32 *pad) -{ - struct media_pad *remote; - - remote = media_pad_remote_pad_first(&video->pad); +/* Queue */ - if (!remote || !is_media_entity_v4l2_subdev(remote->entity)) - return NULL; - - if (pad) - *pad = remote->index; - - return media_entity_to_v4l2_subdev(remote->entity); -} - -static int sun6i_video_queue_setup(struct vb2_queue *vq, - unsigned int *nbuffers, - unsigned int *nplanes, +static int sun6i_video_queue_setup(struct vb2_queue *queue, + unsigned int *buffers_count, + unsigned int *planes_count, unsigned int sizes[], struct device *alloc_devs[]) { - struct sun6i_video *video = vb2_get_drv_priv(vq); - unsigned int size = video->fmt.fmt.pix.sizeimage; + struct sun6i_video *video = vb2_get_drv_priv(queue); + unsigned int size = video->format.fmt.pix.sizeimage; - if (*nplanes) + if (*planes_count) return sizes[0] < size ? -EINVAL : 0; - *nplanes = 1; + *planes_count = 1; sizes[0] = size; return 0; } -static int sun6i_video_buffer_prepare(struct vb2_buffer *vb) +static int sun6i_video_buffer_prepare(struct vb2_buffer *buffer) { - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct sun6i_csi_buffer *buf = - container_of(vbuf, struct sun6i_csi_buffer, vb); - struct sun6i_video *video = vb2_get_drv_priv(vb->vb2_queue); - unsigned long size = video->fmt.fmt.pix.sizeimage; - - if (vb2_plane_size(vb, 0) < size) { - v4l2_err(video->vdev.v4l2_dev, "buffer too small (%lu < %lu)\n", - vb2_plane_size(vb, 0), size); + struct sun6i_video *video = vb2_get_drv_priv(buffer->vb2_queue); + struct sun6i_csi_device *csi_dev = video->csi_dev; + struct v4l2_device *v4l2_dev = &csi_dev->v4l2.v4l2_dev; + struct vb2_v4l2_buffer *v4l2_buffer = to_vb2_v4l2_buffer(buffer); + struct sun6i_csi_buffer *csi_buffer = + container_of(v4l2_buffer, struct sun6i_csi_buffer, v4l2_buffer); + unsigned long size = video->format.fmt.pix.sizeimage; + + if (vb2_plane_size(buffer, 0) < size) { + v4l2_err(v4l2_dev, "buffer too small (%lu < %lu)\n", + vb2_plane_size(buffer, 0), size); return -EINVAL; } - vb2_set_plane_payload(vb, 0, size); - - buf->dma_addr = vb2_dma_contig_plane_dma_addr(vb, 0); + vb2_set_plane_payload(buffer, 0, size); - vbuf->field = video->fmt.fmt.pix.field; + csi_buffer->dma_addr = vb2_dma_contig_plane_dma_addr(buffer, 0); + v4l2_buffer->field = video->format.fmt.pix.field; return 0; } -static int sun6i_video_start_streaming(struct vb2_queue *vq, unsigned int count) +static void sun6i_video_buffer_queue(struct vb2_buffer *buffer) +{ + struct sun6i_video *video = vb2_get_drv_priv(buffer->vb2_queue); + struct vb2_v4l2_buffer *v4l2_buffer = to_vb2_v4l2_buffer(buffer); + struct sun6i_csi_buffer *csi_buffer = + container_of(v4l2_buffer, struct sun6i_csi_buffer, v4l2_buffer); + unsigned long flags; + + spin_lock_irqsave(&video->dma_queue_lock, flags); + csi_buffer->queued_to_csi = false; + list_add_tail(&csi_buffer->list, &video->dma_queue); + spin_unlock_irqrestore(&video->dma_queue_lock, flags); +} + +static int sun6i_video_start_streaming(struct vb2_queue *queue, + unsigned int count) { - struct sun6i_video *video = vb2_get_drv_priv(vq); + struct sun6i_video *video = vb2_get_drv_priv(queue); + struct video_device *video_dev = &video->video_dev; struct sun6i_csi_buffer *buf; struct sun6i_csi_buffer *next_buf; struct sun6i_csi_config config; @@ -141,30 +164,30 @@ static int sun6i_video_start_streaming(struct vb2_queue *vq, unsigned int count) video->sequence = 0; - ret = video_device_pipeline_alloc_start(&video->vdev); + ret = video_device_pipeline_alloc_start(video_dev); if (ret < 0) - goto clear_dma_queue; + goto error_dma_queue_flush; if (video->mbus_code == 0) { ret = -EINVAL; - goto stop_media_pipeline; + goto error_media_pipeline; } subdev = sun6i_video_remote_subdev(video, NULL); if (!subdev) { ret = -EINVAL; - goto stop_media_pipeline; + goto error_media_pipeline; } - config.pixelformat = video->fmt.fmt.pix.pixelformat; + config.pixelformat = video->format.fmt.pix.pixelformat; config.code = video->mbus_code; - config.field = video->fmt.fmt.pix.field; - config.width = video->fmt.fmt.pix.width; - config.height = video->fmt.fmt.pix.height; + config.field = video->format.fmt.pix.field; + config.width = video->format.fmt.pix.width; + config.height = video->format.fmt.pix.height; ret = sun6i_csi_update_config(video->csi_dev, &config); if (ret < 0) - goto stop_media_pipeline; + goto error_media_pipeline; spin_lock_irqsave(&video->dma_queue_lock, flags); @@ -200,27 +223,30 @@ static int sun6i_video_start_streaming(struct vb2_queue *vq, unsigned int count) ret = v4l2_subdev_call(subdev, video, s_stream, 1); if (ret && ret != -ENOIOCTLCMD) - goto stop_csi_stream; + goto error_stream; return 0; -stop_csi_stream: +error_stream: sun6i_csi_set_stream(video->csi_dev, false); -stop_media_pipeline: - video_device_pipeline_stop(&video->vdev); -clear_dma_queue: + +error_media_pipeline: + video_device_pipeline_stop(video_dev); + +error_dma_queue_flush: spin_lock_irqsave(&video->dma_queue_lock, flags); list_for_each_entry(buf, &video->dma_queue, list) - vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED); + vb2_buffer_done(&buf->v4l2_buffer.vb2_buf, + VB2_BUF_STATE_QUEUED); INIT_LIST_HEAD(&video->dma_queue); spin_unlock_irqrestore(&video->dma_queue_lock, flags); return ret; } -static void sun6i_video_stop_streaming(struct vb2_queue *vq) +static void sun6i_video_stop_streaming(struct vb2_queue *queue) { - struct sun6i_video *video = vb2_get_drv_priv(vq); + struct sun6i_video *video = vb2_get_drv_priv(queue); struct v4l2_subdev *subdev; unsigned long flags; struct sun6i_csi_buffer *buf; @@ -231,35 +257,21 @@ static void sun6i_video_stop_streaming(struct vb2_queue *vq) sun6i_csi_set_stream(video->csi_dev, false); - video_device_pipeline_stop(&video->vdev); + video_device_pipeline_stop(&video->video_dev); /* Release all active buffers */ spin_lock_irqsave(&video->dma_queue_lock, flags); list_for_each_entry(buf, &video->dma_queue, list) - vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + vb2_buffer_done(&buf->v4l2_buffer.vb2_buf, VB2_BUF_STATE_ERROR); INIT_LIST_HEAD(&video->dma_queue); spin_unlock_irqrestore(&video->dma_queue_lock, flags); } -static void sun6i_video_buffer_queue(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct sun6i_csi_buffer *buf = - container_of(vbuf, struct sun6i_csi_buffer, vb); - struct sun6i_video *video = vb2_get_drv_priv(vb->vb2_queue); - unsigned long flags; - - spin_lock_irqsave(&video->dma_queue_lock, flags); - buf->queued_to_csi = false; - list_add_tail(&buf->list, &video->dma_queue); - spin_unlock_irqrestore(&video->dma_queue_lock, flags); -} - void sun6i_video_frame_done(struct sun6i_video *video) { struct sun6i_csi_buffer *buf; struct sun6i_csi_buffer *next_buf; - struct vb2_v4l2_buffer *vbuf; + struct vb2_v4l2_buffer *v4l2_buffer; spin_lock(&video->dma_queue_lock); @@ -267,7 +279,7 @@ void sun6i_video_frame_done(struct sun6i_video *video) struct sun6i_csi_buffer, list); if (list_is_last(&buf->list, &video->dma_queue)) { dev_dbg(video->csi_dev->dev, "Frame dropped!\n"); - goto unlock; + goto complete; } next_buf = list_next_entry(buf, list); @@ -280,14 +292,14 @@ void sun6i_video_frame_done(struct sun6i_video *video) next_buf->queued_to_csi = true; sun6i_csi_update_buf_addr(video->csi_dev, next_buf->dma_addr); dev_dbg(video->csi_dev->dev, "Frame dropped!\n"); - goto unlock; + goto complete; } list_del(&buf->list); - vbuf = &buf->vb; - vbuf->vb2_buf.timestamp = ktime_get_ns(); - vbuf->sequence = video->sequence; - vb2_buffer_done(&vbuf->vb2_buf, VB2_BUF_STATE_DONE); + v4l2_buffer = &buf->v4l2_buffer; + v4l2_buffer->vb2_buf.timestamp = ktime_get_ns(); + v4l2_buffer->sequence = video->sequence; + vb2_buffer_done(&v4l2_buffer->vb2_buf, VB2_BUF_STATE_DONE); /* Prepare buffer for next frame but one. */ if (!list_is_last(&next_buf->list, &video->dma_queue)) { @@ -298,165 +310,173 @@ void sun6i_video_frame_done(struct sun6i_video *video) dev_dbg(video->csi_dev->dev, "Next frame will be dropped!\n"); } -unlock: +complete: video->sequence++; spin_unlock(&video->dma_queue_lock); } -static const struct vb2_ops sun6i_csi_vb2_ops = { +static const struct vb2_ops sun6i_video_queue_ops = { .queue_setup = sun6i_video_queue_setup, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .buf_prepare = sun6i_video_buffer_prepare, + .buf_queue = sun6i_video_buffer_queue, .start_streaming = sun6i_video_start_streaming, .stop_streaming = sun6i_video_stop_streaming, - .buf_queue = sun6i_video_buffer_queue, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, }; -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) +/* V4L2 Device */ + +static int sun6i_video_querycap(struct file *file, void *private, + struct v4l2_capability *capability) { struct sun6i_video *video = video_drvdata(file); + struct sun6i_csi_device *csi_dev = video->csi_dev; + struct video_device *video_dev = &video->video_dev; - strscpy(cap->driver, "sun6i-video", sizeof(cap->driver)); - strscpy(cap->card, video->vdev.name, sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - video->csi_dev->dev->of_node->name); + strscpy(capability->driver, SUN6I_CSI_NAME, sizeof(capability->driver)); + strscpy(capability->card, video_dev->name, sizeof(capability->card)); + snprintf(capability->bus_info, sizeof(capability->bus_info), + "platform:%s", dev_name(csi_dev->dev)); return 0; } -static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) +static int sun6i_video_enum_fmt(struct file *file, void *private, + struct v4l2_fmtdesc *fmtdesc) { - u32 index = f->index; + u32 index = fmtdesc->index; - if (index >= ARRAY_SIZE(supported_pixformats)) + if (index >= ARRAY_SIZE(sun6i_video_formats)) return -EINVAL; - f->pixelformat = supported_pixformats[index]; + fmtdesc->pixelformat = sun6i_video_formats[index]; return 0; } -static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *fmt) +static int sun6i_video_g_fmt(struct file *file, void *private, + struct v4l2_format *format) { struct sun6i_video *video = video_drvdata(file); - *fmt = video->fmt; + *format = video->format; return 0; } -static int sun6i_video_try_fmt(struct sun6i_video *video, - struct v4l2_format *f) +static int sun6i_video_format_try(struct sun6i_video *video, + struct v4l2_format *format) { - struct v4l2_pix_format *pixfmt = &f->fmt.pix; + struct v4l2_pix_format *pix_format = &format->fmt.pix; int bpp; - if (!is_pixformat_valid(pixfmt->pixelformat)) - pixfmt->pixelformat = supported_pixformats[0]; + if (!sun6i_video_format_check(pix_format->pixelformat)) + pix_format->pixelformat = sun6i_video_formats[0]; - v4l_bound_align_image(&pixfmt->width, MIN_WIDTH, MAX_WIDTH, 1, - &pixfmt->height, MIN_HEIGHT, MAX_WIDTH, 1, 1); + v4l_bound_align_image(&pix_format->width, MIN_WIDTH, MAX_WIDTH, 1, + &pix_format->height, MIN_HEIGHT, MAX_WIDTH, 1, 1); - bpp = sun6i_csi_get_bpp(pixfmt->pixelformat); - pixfmt->bytesperline = (pixfmt->width * bpp) >> 3; - pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height; + bpp = sun6i_csi_get_bpp(pix_format->pixelformat); + pix_format->bytesperline = (pix_format->width * bpp) >> 3; + pix_format->sizeimage = pix_format->bytesperline * pix_format->height; - if (pixfmt->field == V4L2_FIELD_ANY) - pixfmt->field = V4L2_FIELD_NONE; + if (pix_format->field == V4L2_FIELD_ANY) + pix_format->field = V4L2_FIELD_NONE; - if (pixfmt->pixelformat == V4L2_PIX_FMT_JPEG) - pixfmt->colorspace = V4L2_COLORSPACE_JPEG; + if (pix_format->pixelformat == V4L2_PIX_FMT_JPEG) + pix_format->colorspace = V4L2_COLORSPACE_JPEG; else - pixfmt->colorspace = V4L2_COLORSPACE_SRGB; + pix_format->colorspace = V4L2_COLORSPACE_SRGB; - pixfmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; - pixfmt->quantization = V4L2_QUANTIZATION_DEFAULT; - pixfmt->xfer_func = V4L2_XFER_FUNC_DEFAULT; + pix_format->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + pix_format->quantization = V4L2_QUANTIZATION_DEFAULT; + pix_format->xfer_func = V4L2_XFER_FUNC_DEFAULT; return 0; } -static int sun6i_video_set_fmt(struct sun6i_video *video, struct v4l2_format *f) +static int sun6i_video_format_set(struct sun6i_video *video, + struct v4l2_format *format) { int ret; - ret = sun6i_video_try_fmt(video, f); + ret = sun6i_video_format_try(video, format); if (ret) return ret; - video->fmt = *f; + video->format = *format; return 0; } -static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) +static int sun6i_video_s_fmt(struct file *file, void *private, + struct v4l2_format *format) { struct sun6i_video *video = video_drvdata(file); - if (vb2_is_busy(&video->vb2_vidq)) + if (vb2_is_busy(&video->queue)) return -EBUSY; - return sun6i_video_set_fmt(video, f); + return sun6i_video_format_set(video, format); } -static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) +static int sun6i_video_try_fmt(struct file *file, void *private, + struct v4l2_format *format) { struct sun6i_video *video = video_drvdata(file); - return sun6i_video_try_fmt(video, f); + return sun6i_video_format_try(video, format); } -static int vidioc_enum_input(struct file *file, void *fh, - struct v4l2_input *inp) +static int sun6i_video_enum_input(struct file *file, void *private, + struct v4l2_input *input) { - if (inp->index != 0) + if (input->index != 0) return -EINVAL; - strscpy(inp->name, "camera", sizeof(inp->name)); - inp->type = V4L2_INPUT_TYPE_CAMERA; + input->type = V4L2_INPUT_TYPE_CAMERA; + strscpy(input->name, "Camera", sizeof(input->name)); return 0; } -static int vidioc_g_input(struct file *file, void *fh, unsigned int *i) +static int sun6i_video_g_input(struct file *file, void *private, + unsigned int *index) { - *i = 0; + *index = 0; return 0; } -static int vidioc_s_input(struct file *file, void *fh, unsigned int i) +static int sun6i_video_s_input(struct file *file, void *private, + unsigned int index) { - if (i != 0) + if (index != 0) return -EINVAL; return 0; } static const struct v4l2_ioctl_ops sun6i_video_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, + .vidioc_querycap = sun6i_video_querycap, + + .vidioc_enum_fmt_vid_cap = sun6i_video_enum_fmt, + .vidioc_g_fmt_vid_cap = sun6i_video_g_fmt, + .vidioc_s_fmt_vid_cap = sun6i_video_s_fmt, + .vidioc_try_fmt_vid_cap = sun6i_video_try_fmt, - .vidioc_enum_input = vidioc_enum_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_g_input = vidioc_g_input, + .vidioc_enum_input = sun6i_video_enum_input, + .vidioc_g_input = sun6i_video_g_input, + .vidioc_s_input = sun6i_video_s_input, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, .vidioc_reqbufs = vb2_ioctl_reqbufs, .vidioc_querybuf = vb2_ioctl_querybuf, - .vidioc_qbuf = vb2_ioctl_qbuf, .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_qbuf = vb2_ioctl_qbuf, .vidioc_dqbuf = vb2_ioctl_dqbuf, - .vidioc_create_bufs = vb2_ioctl_create_bufs, - .vidioc_prepare_buf = vb2_ioctl_prepare_buf, .vidioc_streamon = vb2_ioctl_streamon, .vidioc_streamoff = vb2_ioctl_streamoff, @@ -465,9 +485,8 @@ static const struct v4l2_ioctl_ops sun6i_video_ioctl_ops = { .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; -/* ----------------------------------------------------------------------------- - * V4L2 file operations - */ +/* V4L2 File */ + static int sun6i_video_open(struct file *file) { struct sun6i_video *video = video_drvdata(file); @@ -478,44 +497,46 @@ static int sun6i_video_open(struct file *file) ret = v4l2_fh_open(file); if (ret < 0) - goto unlock; + goto error_lock; - ret = v4l2_pipeline_pm_get(&video->vdev.entity); + ret = v4l2_pipeline_pm_get(&video->video_dev.entity); if (ret < 0) - goto fh_release; - - /* check if already powered */ - if (!v4l2_fh_is_singular_file(file)) - goto unlock; + goto error_v4l2_fh; - ret = sun6i_csi_set_power(video->csi_dev, true); - if (ret < 0) - goto fh_release; + /* Power on at first open. */ + if (v4l2_fh_is_singular_file(file)) { + ret = sun6i_csi_set_power(video->csi_dev, true); + if (ret < 0) + goto error_v4l2_fh; + } mutex_unlock(&video->lock); + return 0; -fh_release: +error_v4l2_fh: v4l2_fh_release(file); -unlock: + +error_lock: mutex_unlock(&video->lock); + return ret; } static int sun6i_video_close(struct file *file) { struct sun6i_video *video = video_drvdata(file); - bool last_fh; + bool last_close; mutex_lock(&video->lock); - last_fh = v4l2_fh_is_singular_file(file); + last_close = v4l2_fh_is_singular_file(file); _vb2_fop_release(file, NULL); + v4l2_pipeline_pm_put(&video->video_dev.entity); - v4l2_pipeline_pm_put(&video->vdev.entity); - - if (last_fh) + /* Power off at last close. */ + if (last_close) sun6i_csi_set_power(video->csi_dev, false); mutex_unlock(&video->lock); @@ -532,9 +553,8 @@ static const struct v4l2_file_operations sun6i_video_fops = { .poll = vb2_fop_poll }; -/* ----------------------------------------------------------------------------- - * Media Operations - */ +/* Media Entity */ + static int sun6i_video_link_validate_get_format(struct media_pad *pad, struct v4l2_subdev_format *fmt) { @@ -571,20 +591,20 @@ static int sun6i_video_link_validate(struct media_link *link) return ret; if (!sun6i_csi_is_format_supported(video->csi_dev, - video->fmt.fmt.pix.pixelformat, + video->format.fmt.pix.pixelformat, source_fmt.format.code)) { dev_err(video->csi_dev->dev, "Unsupported pixformat: 0x%x with mbus code: 0x%x!\n", - video->fmt.fmt.pix.pixelformat, + video->format.fmt.pix.pixelformat, source_fmt.format.code); return -EPIPE; } - if (source_fmt.format.width != video->fmt.fmt.pix.width || - source_fmt.format.height != video->fmt.fmt.pix.height) { + if (source_fmt.format.width != video->format.fmt.pix.width || + source_fmt.format.height != video->format.fmt.pix.height) { dev_err(video->csi_dev->dev, "Wrong width or height %ux%u (%ux%u expected)\n", - video->fmt.fmt.pix.width, video->fmt.fmt.pix.height, + video->format.fmt.pix.width, video->format.fmt.pix.height, source_fmt.format.width, source_fmt.format.height); return -EPIPE; } @@ -598,90 +618,109 @@ static const struct media_entity_operations sun6i_video_media_ops = { .link_validate = sun6i_video_link_validate }; -int sun6i_video_init(struct sun6i_video *video, - struct sun6i_csi_device *csi_dev, const char *name) +/* Video */ + +int sun6i_video_setup(struct sun6i_video *video, + struct sun6i_csi_device *csi_dev) { - struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2; - struct video_device *vdev = &video->vdev; - struct vb2_queue *vidq = &video->vb2_vidq; - struct v4l2_format fmt = { 0 }; + struct v4l2_device *v4l2_dev = &csi_dev->v4l2.v4l2_dev; + struct video_device *video_dev = &video->video_dev; + struct vb2_queue *queue = &video->queue; + struct media_pad *pad = &video->pad; + struct v4l2_format format = { 0 }; + struct v4l2_pix_format *pix_format = &format.fmt.pix; int ret; video->csi_dev = csi_dev; - /* Initialize the media entity... */ - video->pad.flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT; - vdev->entity.ops = &sun6i_video_media_ops; - ret = media_entity_pads_init(&vdev->entity, 1, &video->pad); + /* Media Entity */ + + video_dev->entity.ops = &sun6i_video_media_ops; + + /* Media Pad */ + + pad->flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT; + + ret = media_entity_pads_init(&video_dev->entity, 1, pad); if (ret < 0) return ret; - mutex_init(&video->lock); + /* DMA queue */ INIT_LIST_HEAD(&video->dma_queue); spin_lock_init(&video->dma_queue_lock); video->sequence = 0; - /* Setup default format */ - fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - fmt.fmt.pix.pixelformat = supported_pixformats[0]; - fmt.fmt.pix.width = 1280; - fmt.fmt.pix.height = 720; - fmt.fmt.pix.field = V4L2_FIELD_NONE; - sun6i_video_set_fmt(video, &fmt); - - /* Initialize videobuf2 queue */ - vidq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - vidq->io_modes = VB2_MMAP | VB2_DMABUF; - vidq->drv_priv = video; - vidq->buf_struct_size = sizeof(struct sun6i_csi_buffer); - vidq->ops = &sun6i_csi_vb2_ops; - vidq->mem_ops = &vb2_dma_contig_memops; - vidq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - vidq->lock = &video->lock; - /* Make sure non-dropped frame */ - vidq->min_buffers_needed = 3; - vidq->dev = csi_dev->dev; - - ret = vb2_queue_init(vidq); + /* Queue */ + + mutex_init(&video->lock); + + queue->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + queue->io_modes = VB2_MMAP | VB2_DMABUF; + queue->buf_struct_size = sizeof(struct sun6i_csi_buffer); + queue->ops = &sun6i_video_queue_ops; + queue->mem_ops = &vb2_dma_contig_memops; + queue->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + queue->lock = &video->lock; + queue->dev = csi_dev->dev; + queue->drv_priv = video; + + /* Make sure non-dropped frame. */ + queue->min_buffers_needed = 3; + + ret = vb2_queue_init(queue); if (ret) { - v4l2_err(&v4l2->v4l2_dev, "vb2_queue_init failed: %d\n", - ret); - goto clean_entity; + v4l2_err(v4l2_dev, "failed to initialize vb2 queue: %d\n", ret); + goto error_media_entity; } - /* Register video device */ - strscpy(vdev->name, name, sizeof(vdev->name)); - vdev->release = video_device_release_empty; - vdev->fops = &sun6i_video_fops; - vdev->ioctl_ops = &sun6i_video_ioctl_ops; - vdev->vfl_type = VFL_TYPE_VIDEO; - vdev->vfl_dir = VFL_DIR_RX; - vdev->v4l2_dev = &v4l2->v4l2_dev; - vdev->queue = vidq; - vdev->lock = &video->lock; - vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE; - video_set_drvdata(vdev, video); - - ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); + /* V4L2 Format */ + + format.type = queue->type; + pix_format->pixelformat = sun6i_video_formats[0]; + pix_format->width = 1280; + pix_format->height = 720; + pix_format->field = V4L2_FIELD_NONE; + + sun6i_video_format_set(video, &format); + + /* Video Device */ + + strscpy(video_dev->name, SUN6I_CSI_NAME, sizeof(video_dev->name)); + video_dev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + video_dev->vfl_dir = VFL_DIR_RX; + video_dev->release = video_device_release_empty; + video_dev->fops = &sun6i_video_fops; + video_dev->ioctl_ops = &sun6i_video_ioctl_ops; + video_dev->v4l2_dev = v4l2_dev; + video_dev->queue = queue; + video_dev->lock = &video->lock; + + video_set_drvdata(video_dev, video); + + ret = video_register_device(video_dev, VFL_TYPE_VIDEO, -1); if (ret < 0) { - v4l2_err(&v4l2->v4l2_dev, - "video_register_device failed: %d\n", ret); - goto clean_entity; + v4l2_err(v4l2_dev, "failed to register video device: %d\n", + ret); + goto error_media_entity; } return 0; -clean_entity: - media_entity_cleanup(&video->vdev.entity); +error_media_entity: + media_entity_cleanup(&video_dev->entity); + mutex_destroy(&video->lock); + return ret; } void sun6i_video_cleanup(struct sun6i_video *video) { - vb2_video_unregister_device(&video->vdev); - media_entity_cleanup(&video->vdev.entity); + struct video_device *video_dev = &video->video_dev; + + vb2_video_unregister_device(video_dev); + media_entity_cleanup(&video_dev->entity); mutex_destroy(&video->lock); } diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h index 30e37ee0d07f..7864f062d05b 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h @@ -15,22 +15,22 @@ struct sun6i_csi_device; struct sun6i_video { struct sun6i_csi_device *csi_dev; - struct video_device vdev; - struct media_pad pad; - struct mutex lock; + struct video_device video_dev; + struct vb2_queue queue; + struct mutex lock; /* Queue lock. */ + struct media_pad pad; - struct vb2_queue vb2_vidq; - spinlock_t dma_queue_lock; struct list_head dma_queue; + spinlock_t dma_queue_lock; /* DMA queue lock. */ - unsigned int sequence; - struct v4l2_format fmt; + struct v4l2_format format; u32 mbus_code; + unsigned int sequence; }; -int sun6i_video_init(struct sun6i_video *video, - struct sun6i_csi_device *csi_dev, const char *name); +int sun6i_video_setup(struct sun6i_video *video, + struct sun6i_csi_device *csi_dev); void sun6i_video_cleanup(struct sun6i_video *video); void sun6i_video_frame_done(struct sun6i_video *video); -- cgit From 92cc51588225d82a4e3d2358e47367ac52b1661a Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Fri, 26 Aug 2022 20:32:07 +0200 Subject: media: sun6i-csi: Pass and store csi device directly in video code The video structure is part of the main csi device structure, so pass pointers to that top-level structure directly. This makes it easier to navigate and access other elements. No functional change intended. Signed-off-by: Paul Kocialkowski Reviewed-by: Maxime Ripard Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c | 8 +- .../media/platform/sunxi/sun6i-csi/sun6i_video.c | 91 ++++++++++++---------- .../media/platform/sunxi/sun6i-csi/sun6i_video.h | 9 +-- 3 files changed, 57 insertions(+), 51 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index b4f90b065a0c..a55347b7a6d6 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -706,7 +706,7 @@ static int sun6i_csi_v4l2_setup(struct sun6i_csi_device *csi_dev) /* Video */ - ret = sun6i_video_setup(&csi_dev->video, csi_dev); + ret = sun6i_video_setup(csi_dev); if (ret) goto error_v4l2_device; @@ -735,7 +735,7 @@ error_v4l2_async_notifier: v4l2_async_nf_cleanup(notifier); error_video: - sun6i_video_cleanup(&csi_dev->video); + sun6i_video_cleanup(csi_dev); error_v4l2_device: v4l2_device_unregister(&v4l2->v4l2_dev); @@ -756,7 +756,7 @@ static void sun6i_csi_v4l2_cleanup(struct sun6i_csi_device *csi_dev) media_device_unregister(&v4l2->media_dev); v4l2_async_nf_unregister(&v4l2->notifier); v4l2_async_nf_cleanup(&v4l2->notifier); - sun6i_video_cleanup(&csi_dev->video); + sun6i_video_cleanup(csi_dev); v4l2_device_unregister(&v4l2->v4l2_dev); v4l2_ctrl_handler_free(&v4l2->ctrl_handler); media_device_cleanup(&v4l2->media_dev); @@ -787,7 +787,7 @@ static irqreturn_t sun6i_csi_interrupt(int irq, void *private) } if (status & CSI_CH_INT_STA_FD_PD) - sun6i_video_frame_done(&csi_dev->video); + sun6i_video_frame_done(csi_dev); regmap_write(regmap, CSI_CH_INT_STA_REG, status); diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c index 4710902447ac..50e5136e2281 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c @@ -100,7 +100,8 @@ static int sun6i_video_queue_setup(struct vb2_queue *queue, unsigned int sizes[], struct device *alloc_devs[]) { - struct sun6i_video *video = vb2_get_drv_priv(queue); + struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(queue); + struct sun6i_video *video = &csi_dev->video; unsigned int size = video->format.fmt.pix.sizeimage; if (*planes_count) @@ -114,8 +115,8 @@ static int sun6i_video_queue_setup(struct vb2_queue *queue, static int sun6i_video_buffer_prepare(struct vb2_buffer *buffer) { - struct sun6i_video *video = vb2_get_drv_priv(buffer->vb2_queue); - struct sun6i_csi_device *csi_dev = video->csi_dev; + struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(buffer->vb2_queue); + struct sun6i_video *video = &csi_dev->video; struct v4l2_device *v4l2_dev = &csi_dev->v4l2.v4l2_dev; struct vb2_v4l2_buffer *v4l2_buffer = to_vb2_v4l2_buffer(buffer); struct sun6i_csi_buffer *csi_buffer = @@ -138,7 +139,8 @@ static int sun6i_video_buffer_prepare(struct vb2_buffer *buffer) static void sun6i_video_buffer_queue(struct vb2_buffer *buffer) { - struct sun6i_video *video = vb2_get_drv_priv(buffer->vb2_queue); + struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(buffer->vb2_queue); + struct sun6i_video *video = &csi_dev->video; struct vb2_v4l2_buffer *v4l2_buffer = to_vb2_v4l2_buffer(buffer); struct sun6i_csi_buffer *csi_buffer = container_of(v4l2_buffer, struct sun6i_csi_buffer, v4l2_buffer); @@ -153,7 +155,8 @@ static void sun6i_video_buffer_queue(struct vb2_buffer *buffer) static int sun6i_video_start_streaming(struct vb2_queue *queue, unsigned int count) { - struct sun6i_video *video = vb2_get_drv_priv(queue); + struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(queue); + struct sun6i_video *video = &csi_dev->video; struct video_device *video_dev = &video->video_dev; struct sun6i_csi_buffer *buf; struct sun6i_csi_buffer *next_buf; @@ -185,7 +188,7 @@ static int sun6i_video_start_streaming(struct vb2_queue *queue, config.width = video->format.fmt.pix.width; config.height = video->format.fmt.pix.height; - ret = sun6i_csi_update_config(video->csi_dev, &config); + ret = sun6i_csi_update_config(csi_dev, &config); if (ret < 0) goto error_media_pipeline; @@ -194,9 +197,9 @@ static int sun6i_video_start_streaming(struct vb2_queue *queue, buf = list_first_entry(&video->dma_queue, struct sun6i_csi_buffer, list); buf->queued_to_csi = true; - sun6i_csi_update_buf_addr(video->csi_dev, buf->dma_addr); + sun6i_csi_update_buf_addr(csi_dev, buf->dma_addr); - sun6i_csi_set_stream(video->csi_dev, true); + sun6i_csi_set_stream(csi_dev, true); /* * CSI will lookup the next dma buffer for next frame before the @@ -217,7 +220,7 @@ static int sun6i_video_start_streaming(struct vb2_queue *queue, */ next_buf = list_next_entry(buf, list); next_buf->queued_to_csi = true; - sun6i_csi_update_buf_addr(video->csi_dev, next_buf->dma_addr); + sun6i_csi_update_buf_addr(csi_dev, next_buf->dma_addr); spin_unlock_irqrestore(&video->dma_queue_lock, flags); @@ -228,7 +231,7 @@ static int sun6i_video_start_streaming(struct vb2_queue *queue, return 0; error_stream: - sun6i_csi_set_stream(video->csi_dev, false); + sun6i_csi_set_stream(csi_dev, false); error_media_pipeline: video_device_pipeline_stop(video_dev); @@ -246,7 +249,8 @@ error_dma_queue_flush: static void sun6i_video_stop_streaming(struct vb2_queue *queue) { - struct sun6i_video *video = vb2_get_drv_priv(queue); + struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(queue); + struct sun6i_video *video = &csi_dev->video; struct v4l2_subdev *subdev; unsigned long flags; struct sun6i_csi_buffer *buf; @@ -255,7 +259,7 @@ static void sun6i_video_stop_streaming(struct vb2_queue *queue) if (subdev) v4l2_subdev_call(subdev, video, s_stream, 0); - sun6i_csi_set_stream(video->csi_dev, false); + sun6i_csi_set_stream(csi_dev, false); video_device_pipeline_stop(&video->video_dev); @@ -267,8 +271,9 @@ static void sun6i_video_stop_streaming(struct vb2_queue *queue) spin_unlock_irqrestore(&video->dma_queue_lock, flags); } -void sun6i_video_frame_done(struct sun6i_video *video) +void sun6i_video_frame_done(struct sun6i_csi_device *csi_dev) { + struct sun6i_video *video = &csi_dev->video; struct sun6i_csi_buffer *buf; struct sun6i_csi_buffer *next_buf; struct vb2_v4l2_buffer *v4l2_buffer; @@ -278,7 +283,7 @@ void sun6i_video_frame_done(struct sun6i_video *video) buf = list_first_entry(&video->dma_queue, struct sun6i_csi_buffer, list); if (list_is_last(&buf->list, &video->dma_queue)) { - dev_dbg(video->csi_dev->dev, "Frame dropped!\n"); + dev_dbg(csi_dev->dev, "Frame dropped!\n"); goto complete; } @@ -290,8 +295,8 @@ void sun6i_video_frame_done(struct sun6i_video *video) */ if (!next_buf->queued_to_csi) { next_buf->queued_to_csi = true; - sun6i_csi_update_buf_addr(video->csi_dev, next_buf->dma_addr); - dev_dbg(video->csi_dev->dev, "Frame dropped!\n"); + sun6i_csi_update_buf_addr(csi_dev, next_buf->dma_addr); + dev_dbg(csi_dev->dev, "Frame dropped!\n"); goto complete; } @@ -305,9 +310,9 @@ void sun6i_video_frame_done(struct sun6i_video *video) if (!list_is_last(&next_buf->list, &video->dma_queue)) { next_buf = list_next_entry(next_buf, list); next_buf->queued_to_csi = true; - sun6i_csi_update_buf_addr(video->csi_dev, next_buf->dma_addr); + sun6i_csi_update_buf_addr(csi_dev, next_buf->dma_addr); } else { - dev_dbg(video->csi_dev->dev, "Next frame will be dropped!\n"); + dev_dbg(csi_dev->dev, "Next frame will be dropped!\n"); } complete: @@ -330,9 +335,8 @@ static const struct vb2_ops sun6i_video_queue_ops = { static int sun6i_video_querycap(struct file *file, void *private, struct v4l2_capability *capability) { - struct sun6i_video *video = video_drvdata(file); - struct sun6i_csi_device *csi_dev = video->csi_dev; - struct video_device *video_dev = &video->video_dev; + struct sun6i_csi_device *csi_dev = video_drvdata(file); + struct video_device *video_dev = &csi_dev->video.video_dev; strscpy(capability->driver, SUN6I_CSI_NAME, sizeof(capability->driver)); strscpy(capability->card, video_dev->name, sizeof(capability->card)); @@ -358,7 +362,8 @@ static int sun6i_video_enum_fmt(struct file *file, void *private, static int sun6i_video_g_fmt(struct file *file, void *private, struct v4l2_format *format) { - struct sun6i_video *video = video_drvdata(file); + struct sun6i_csi_device *csi_dev = video_drvdata(file); + struct sun6i_video *video = &csi_dev->video; *format = video->format; @@ -413,7 +418,8 @@ static int sun6i_video_format_set(struct sun6i_video *video, static int sun6i_video_s_fmt(struct file *file, void *private, struct v4l2_format *format) { - struct sun6i_video *video = video_drvdata(file); + struct sun6i_csi_device *csi_dev = video_drvdata(file); + struct sun6i_video *video = &csi_dev->video; if (vb2_is_busy(&video->queue)) return -EBUSY; @@ -424,7 +430,8 @@ static int sun6i_video_s_fmt(struct file *file, void *private, static int sun6i_video_try_fmt(struct file *file, void *private, struct v4l2_format *format) { - struct sun6i_video *video = video_drvdata(file); + struct sun6i_csi_device *csi_dev = video_drvdata(file); + struct sun6i_video *video = &csi_dev->video; return sun6i_video_format_try(video, format); } @@ -489,7 +496,8 @@ static const struct v4l2_ioctl_ops sun6i_video_ioctl_ops = { static int sun6i_video_open(struct file *file) { - struct sun6i_video *video = video_drvdata(file); + struct sun6i_csi_device *csi_dev = video_drvdata(file); + struct sun6i_video *video = &csi_dev->video; int ret = 0; if (mutex_lock_interruptible(&video->lock)) @@ -505,7 +513,7 @@ static int sun6i_video_open(struct file *file) /* Power on at first open. */ if (v4l2_fh_is_singular_file(file)) { - ret = sun6i_csi_set_power(video->csi_dev, true); + ret = sun6i_csi_set_power(csi_dev, true); if (ret < 0) goto error_v4l2_fh; } @@ -525,7 +533,8 @@ error_lock: static int sun6i_video_close(struct file *file) { - struct sun6i_video *video = video_drvdata(file); + struct sun6i_csi_device *csi_dev = video_drvdata(file); + struct sun6i_video *video = &csi_dev->video; bool last_close; mutex_lock(&video->lock); @@ -537,7 +546,7 @@ static int sun6i_video_close(struct file *file) /* Power off at last close. */ if (last_close) - sun6i_csi_set_power(video->csi_dev, false); + sun6i_csi_set_power(csi_dev, false); mutex_unlock(&video->lock); @@ -574,15 +583,16 @@ static int sun6i_video_link_validate(struct media_link *link) { struct video_device *vdev = container_of(link->sink->entity, struct video_device, entity); - struct sun6i_video *video = video_get_drvdata(vdev); + struct sun6i_csi_device *csi_dev = video_get_drvdata(vdev); + struct sun6i_video *video = &csi_dev->video; struct v4l2_subdev_format source_fmt; int ret; video->mbus_code = 0; if (!media_pad_remote_pad_first(link->sink->entity->pads)) { - dev_info(video->csi_dev->dev, - "video node %s pad not connected\n", vdev->name); + dev_info(csi_dev->dev, "video node %s pad not connected\n", + vdev->name); return -ENOLINK; } @@ -590,10 +600,10 @@ static int sun6i_video_link_validate(struct media_link *link) if (ret < 0) return ret; - if (!sun6i_csi_is_format_supported(video->csi_dev, + if (!sun6i_csi_is_format_supported(csi_dev, video->format.fmt.pix.pixelformat, source_fmt.format.code)) { - dev_err(video->csi_dev->dev, + dev_err(csi_dev->dev, "Unsupported pixformat: 0x%x with mbus code: 0x%x!\n", video->format.fmt.pix.pixelformat, source_fmt.format.code); @@ -602,7 +612,7 @@ static int sun6i_video_link_validate(struct media_link *link) if (source_fmt.format.width != video->format.fmt.pix.width || source_fmt.format.height != video->format.fmt.pix.height) { - dev_err(video->csi_dev->dev, + dev_err(csi_dev->dev, "Wrong width or height %ux%u (%ux%u expected)\n", video->format.fmt.pix.width, video->format.fmt.pix.height, source_fmt.format.width, source_fmt.format.height); @@ -620,9 +630,9 @@ static const struct media_entity_operations sun6i_video_media_ops = { /* Video */ -int sun6i_video_setup(struct sun6i_video *video, - struct sun6i_csi_device *csi_dev) +int sun6i_video_setup(struct sun6i_csi_device *csi_dev) { + struct sun6i_video *video = &csi_dev->video; struct v4l2_device *v4l2_dev = &csi_dev->v4l2.v4l2_dev; struct video_device *video_dev = &video->video_dev; struct vb2_queue *queue = &video->queue; @@ -631,8 +641,6 @@ int sun6i_video_setup(struct sun6i_video *video, struct v4l2_pix_format *pix_format = &format.fmt.pix; int ret; - video->csi_dev = csi_dev; - /* Media Entity */ video_dev->entity.ops = &sun6i_video_media_ops; @@ -664,7 +672,7 @@ int sun6i_video_setup(struct sun6i_video *video, queue->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; queue->lock = &video->lock; queue->dev = csi_dev->dev; - queue->drv_priv = video; + queue->drv_priv = csi_dev; /* Make sure non-dropped frame. */ queue->min_buffers_needed = 3; @@ -697,7 +705,7 @@ int sun6i_video_setup(struct sun6i_video *video, video_dev->queue = queue; video_dev->lock = &video->lock; - video_set_drvdata(video_dev, video); + video_set_drvdata(video_dev, csi_dev); ret = video_register_device(video_dev, VFL_TYPE_VIDEO, -1); if (ret < 0) { @@ -716,8 +724,9 @@ error_media_entity: return ret; } -void sun6i_video_cleanup(struct sun6i_video *video) +void sun6i_video_cleanup(struct sun6i_csi_device *csi_dev) { + struct sun6i_video *video = &csi_dev->video; struct video_device *video_dev = &video->video_dev; vb2_video_unregister_device(video_dev); diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h index 7864f062d05b..a917d2da6deb 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h @@ -14,8 +14,6 @@ struct sun6i_csi_device; struct sun6i_video { - struct sun6i_csi_device *csi_dev; - struct video_device video_dev; struct vb2_queue queue; struct mutex lock; /* Queue lock. */ @@ -29,10 +27,9 @@ struct sun6i_video { unsigned int sequence; }; -int sun6i_video_setup(struct sun6i_video *video, - struct sun6i_csi_device *csi_dev); -void sun6i_video_cleanup(struct sun6i_video *video); +int sun6i_video_setup(struct sun6i_csi_device *csi_dev); +void sun6i_video_cleanup(struct sun6i_csi_device *csi_dev); -void sun6i_video_frame_done(struct sun6i_video *video); +void sun6i_video_frame_done(struct sun6i_csi_device *csi_dev); #endif /* __SUN6I_VIDEO_H__ */ -- cgit From f9a6e5651efff2b3461ef8256067437a39b54e9e Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Fri, 26 Aug 2022 20:32:08 +0200 Subject: media: sun6i-csi: Register the media device after creation There is no particular need to register the media device in the subdev notify complete callback. Register it in the v4l2 code instead where it's more in-context. Signed-off-by: Paul Kocialkowski Acked-by: Jernej Skrabec Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index a55347b7a6d6..e3d60b647cb2 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -638,7 +638,7 @@ static int sun6i_subdev_notify_complete(struct v4l2_async_notifier *notifier) if (ret < 0) return ret; - return media_device_register(&v4l2->media_dev); + return 0; } static const struct v4l2_async_notifier_operations sun6i_csi_async_ops = { @@ -685,6 +685,12 @@ static int sun6i_csi_v4l2_setup(struct sun6i_csi_device *csi_dev) media_device_init(media_dev); + ret = media_device_register(media_dev); + if (ret) { + dev_err(dev, "failed to register media device: %d\n", ret); + goto error_media; + } + /* V4L2 Control Handler */ ret = v4l2_ctrl_handler_init(&v4l2->ctrl_handler, 0); @@ -744,6 +750,7 @@ error_v4l2_ctrl: v4l2_ctrl_handler_free(&v4l2->ctrl_handler); error_media: + media_device_unregister(media_dev); media_device_cleanup(media_dev); return ret; -- cgit From daafbb94adc543641cd37b04dbe911244b8bf0f6 Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Fri, 26 Aug 2022 20:32:09 +0200 Subject: media: sun6i-csi: Remove controls handler from the driver The driver does not expose controls directly and thus does not need a controls handler for its own use. Controls attached to subdevs used to be exposed that way, however this can easily lead to issue when multiple subdevs attached to the same v4l2 device expose the same controls. Subdev controls should be set through each individual subdev node instead. Signed-off-by: Paul Kocialkowski Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c | 15 +-------------- drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h | 2 -- drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c | 4 ---- 3 files changed, 1 insertion(+), 20 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index e3d60b647cb2..d74eaa3132d6 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -691,23 +691,14 @@ static int sun6i_csi_v4l2_setup(struct sun6i_csi_device *csi_dev) goto error_media; } - /* V4L2 Control Handler */ - - ret = v4l2_ctrl_handler_init(&v4l2->ctrl_handler, 0); - if (ret) { - dev_err(dev, "failed to init v4l2 control handler: %d\n", ret); - goto error_media; - } - /* V4L2 Device */ v4l2_dev->mdev = media_dev; - v4l2_dev->ctrl_handler = &v4l2->ctrl_handler; ret = v4l2_device_register(dev, v4l2_dev); if (ret) { dev_err(dev, "failed to register v4l2 device: %d\n", ret); - goto error_v4l2_ctrl; + goto error_media; } /* Video */ @@ -746,9 +737,6 @@ error_video: error_v4l2_device: v4l2_device_unregister(&v4l2->v4l2_dev); -error_v4l2_ctrl: - v4l2_ctrl_handler_free(&v4l2->ctrl_handler); - error_media: media_device_unregister(media_dev); media_device_cleanup(media_dev); @@ -765,7 +753,6 @@ static void sun6i_csi_v4l2_cleanup(struct sun6i_csi_device *csi_dev) v4l2_async_nf_cleanup(&v4l2->notifier); sun6i_video_cleanup(csi_dev); v4l2_device_unregister(&v4l2->v4l2_dev); - v4l2_ctrl_handler_free(&v4l2->ctrl_handler); media_device_cleanup(&v4l2->media_dev); } diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h index e301d80362cf..4bb4c3d1be07 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h @@ -8,7 +8,6 @@ #ifndef __SUN6I_CSI_H__ #define __SUN6I_CSI_H__ -#include #include #include @@ -35,7 +34,6 @@ struct sun6i_csi_config { struct sun6i_csi_v4l2 { struct v4l2_device v4l2_dev; - struct v4l2_ctrl_handler ctrl_handler; struct media_device media_dev; struct v4l2_async_notifier notifier; diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c index 50e5136e2281..d75f762abb78 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c @@ -486,10 +486,6 @@ static const struct v4l2_ioctl_ops sun6i_video_ioctl_ops = { .vidioc_dqbuf = vb2_ioctl_dqbuf, .vidioc_streamon = vb2_ioctl_streamon, .vidioc_streamoff = vb2_ioctl_streamoff, - - .vidioc_log_status = v4l2_ctrl_log_status, - .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; /* V4L2 File */ -- cgit From b11d91321cacf638cbfbbb424f9267d4146872a9 Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Fri, 26 Aug 2022 20:32:10 +0200 Subject: media: sun6i-csi: Add media ops with link notify callback In order to keep the power use count fields balanced when link changes happen between v4l2_pipeline_pm_get/set calls (in open/close), the link_notify media operation callback needs to be registered. Signed-off-by: Paul Kocialkowski Acked-by: Jernej Skrabec Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index d74eaa3132d6..8b99c17e8403 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "sun6i_csi.h" #include "sun6i_csi_reg.h" @@ -574,6 +575,12 @@ void sun6i_csi_set_stream(struct sun6i_csi_device *csi_dev, bool enable) CSI_CAP_CH0_VCAP_ON); } +/* Media */ + +static const struct media_device_ops sun6i_csi_media_ops = { + .link_notify = v4l2_pipeline_link_notify, +}; + /* V4L2 */ static int sun6i_csi_link_entity(struct sun6i_csi_device *csi_dev, @@ -681,6 +688,7 @@ static int sun6i_csi_v4l2_setup(struct sun6i_csi_device *csi_dev) strscpy(media_dev->model, SUN6I_CSI_DESCRIPTION, sizeof(media_dev->model)); media_dev->hw_revision = 0; + media_dev->ops = &sun6i_csi_media_ops; media_dev->dev = dev; media_device_init(media_dev); -- cgit From 7d13cf0e0023000768876c4e65c89e7714e9071f Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Fri, 26 Aug 2022 20:32:11 +0200 Subject: media: sun6i-csi: Introduce and use video helper functions Introduce some helpers for buffer and general video configuration. Signed-off-by: Paul Kocialkowski Reviewed-by: Jernej Skrabec Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../media/platform/sunxi/sun6i-csi/sun6i_video.c | 46 +++++++++++++--------- 1 file changed, 28 insertions(+), 18 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c index d75f762abb78..dd3748d337be 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c @@ -92,6 +92,29 @@ static bool sun6i_video_format_check(u32 format) return false; } +/* Video */ + +static void sun6i_video_buffer_configure(struct sun6i_csi_device *csi_dev, + struct sun6i_csi_buffer *csi_buffer) +{ + csi_buffer->queued_to_csi = true; + sun6i_csi_update_buf_addr(csi_dev, csi_buffer->dma_addr); +} + +static void sun6i_video_configure(struct sun6i_csi_device *csi_dev) +{ + struct sun6i_video *video = &csi_dev->video; + struct sun6i_csi_config config = { 0 }; + + config.pixelformat = video->format.fmt.pix.pixelformat; + config.code = video->mbus_code; + config.field = video->format.fmt.pix.field; + config.width = video->format.fmt.pix.width; + config.height = video->format.fmt.pix.height; + + sun6i_csi_update_config(csi_dev, &config); +} + /* Queue */ static int sun6i_video_queue_setup(struct vb2_queue *queue, @@ -160,7 +183,6 @@ static int sun6i_video_start_streaming(struct vb2_queue *queue, struct video_device *video_dev = &video->video_dev; struct sun6i_csi_buffer *buf; struct sun6i_csi_buffer *next_buf; - struct sun6i_csi_config config; struct v4l2_subdev *subdev; unsigned long flags; int ret; @@ -182,22 +204,13 @@ static int sun6i_video_start_streaming(struct vb2_queue *queue, goto error_media_pipeline; } - config.pixelformat = video->format.fmt.pix.pixelformat; - config.code = video->mbus_code; - config.field = video->format.fmt.pix.field; - config.width = video->format.fmt.pix.width; - config.height = video->format.fmt.pix.height; - - ret = sun6i_csi_update_config(csi_dev, &config); - if (ret < 0) - goto error_media_pipeline; + sun6i_video_configure(csi_dev); spin_lock_irqsave(&video->dma_queue_lock, flags); buf = list_first_entry(&video->dma_queue, struct sun6i_csi_buffer, list); - buf->queued_to_csi = true; - sun6i_csi_update_buf_addr(csi_dev, buf->dma_addr); + sun6i_video_buffer_configure(csi_dev, buf); sun6i_csi_set_stream(csi_dev, true); @@ -219,8 +232,7 @@ static int sun6i_video_start_streaming(struct vb2_queue *queue, * would also drop frame when lacking of queued buffer. */ next_buf = list_next_entry(buf, list); - next_buf->queued_to_csi = true; - sun6i_csi_update_buf_addr(csi_dev, next_buf->dma_addr); + sun6i_video_buffer_configure(csi_dev, next_buf); spin_unlock_irqrestore(&video->dma_queue_lock, flags); @@ -294,8 +306,7 @@ void sun6i_video_frame_done(struct sun6i_csi_device *csi_dev) * for next ISR call. */ if (!next_buf->queued_to_csi) { - next_buf->queued_to_csi = true; - sun6i_csi_update_buf_addr(csi_dev, next_buf->dma_addr); + sun6i_video_buffer_configure(csi_dev, next_buf); dev_dbg(csi_dev->dev, "Frame dropped!\n"); goto complete; } @@ -309,8 +320,7 @@ void sun6i_video_frame_done(struct sun6i_csi_device *csi_dev) /* Prepare buffer for next frame but one. */ if (!list_is_last(&next_buf->list, &video->dma_queue)) { next_buf = list_next_entry(next_buf, list); - next_buf->queued_to_csi = true; - sun6i_csi_update_buf_addr(csi_dev, next_buf->dma_addr); + sun6i_video_buffer_configure(csi_dev, next_buf); } else { dev_dbg(csi_dev->dev, "Next frame will be dropped!\n"); } -- cgit From 70a7ce22e9229f216c638426a854efd5bd127b24 Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Fri, 26 Aug 2022 20:32:12 +0200 Subject: media: sun6i-csi: Move csi buffer definition to main header file The buffer structure is a top-level definition, put it in the main header to keep things tidy. No functional change intended. Signed-off-by: Paul Kocialkowski Reviewed-by: Maxime Ripard Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h | 9 +++++++++ drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c | 8 -------- 2 files changed, 9 insertions(+), 8 deletions(-) (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h index 4bb4c3d1be07..bab705678280 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h @@ -10,12 +10,21 @@ #include #include +#include #include "sun6i_video.h" #define SUN6I_CSI_NAME "sun6i-csi" #define SUN6I_CSI_DESCRIPTION "Allwinner A31 CSI Device" +struct sun6i_csi_buffer { + struct vb2_v4l2_buffer v4l2_buffer; + struct list_head list; + + dma_addr_t dma_addr; + bool queued_to_csi; +}; + /** * struct sun6i_csi_config - configs for sun6i csi * @pixelformat: v4l2 pixel format (V4L2_PIX_FMT_*) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c index dd3748d337be..791583d23a65 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c @@ -23,14 +23,6 @@ #define MAX_WIDTH (4800) #define MAX_HEIGHT (4800) -struct sun6i_csi_buffer { - struct vb2_v4l2_buffer v4l2_buffer; - struct list_head list; - - dma_addr_t dma_addr; - bool queued_to_csi; -}; - /* Helpers */ static struct v4l2_subdev * -- cgit