From 642ac63d166d07e43396a4d8c48ab24cb072cb18 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 11 Jun 2019 10:02:43 -0400 Subject: media: drivers/staging/media: don't set description for ENUM_FMT The V4L2 core sets the format description and flags for the driver in order to ensure consistent naming. So drop the strscpy of the description in drivers. Also remove any description strings in driver-internal structures since those are no longer needed. Note that bcm2835-camera.c: the formats array still stores the flags field for compressed formats since that information is used elsewhere in the driver. But enum_fmt doesn't use it anymore, since the core will set the COMPRESSED flag correctly. Signed-off-by: Hans Verkuil Reviewed-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/omap4iss/iss_video.c | 40 ++++++++++------------ drivers/staging/media/omap4iss/iss_video.h | 2 -- drivers/staging/media/soc_camera/soc_camera.c | 2 -- .../vc04_services/bcm2835-camera/bcm2835-camera.c | 29 ---------------- .../vc04_services/bcm2835-camera/mmal-common.h | 1 - 5 files changed, 19 insertions(+), 55 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/omap4iss/iss_video.c b/drivers/staging/media/omap4iss/iss_video.c index c307707480f7..54144dc9f509 100644 --- a/drivers/staging/media/omap4iss/iss_video.c +++ b/drivers/staging/media/omap4iss/iss_video.c @@ -31,61 +31,61 @@ static struct iss_format_info formats[] = { { MEDIA_BUS_FMT_Y8_1X8, MEDIA_BUS_FMT_Y8_1X8, MEDIA_BUS_FMT_Y8_1X8, MEDIA_BUS_FMT_Y8_1X8, - V4L2_PIX_FMT_GREY, 8, "Greyscale 8 bpp", }, + V4L2_PIX_FMT_GREY, 8, }, { MEDIA_BUS_FMT_Y10_1X10, MEDIA_BUS_FMT_Y10_1X10, MEDIA_BUS_FMT_Y10_1X10, MEDIA_BUS_FMT_Y8_1X8, - V4L2_PIX_FMT_Y10, 10, "Greyscale 10 bpp", }, + V4L2_PIX_FMT_Y10, 10, }, { MEDIA_BUS_FMT_Y12_1X12, MEDIA_BUS_FMT_Y10_1X10, MEDIA_BUS_FMT_Y12_1X12, MEDIA_BUS_FMT_Y8_1X8, - V4L2_PIX_FMT_Y12, 12, "Greyscale 12 bpp", }, + V4L2_PIX_FMT_Y12, 12, }, { MEDIA_BUS_FMT_SBGGR8_1X8, MEDIA_BUS_FMT_SBGGR8_1X8, MEDIA_BUS_FMT_SBGGR8_1X8, MEDIA_BUS_FMT_SBGGR8_1X8, - V4L2_PIX_FMT_SBGGR8, 8, "BGGR Bayer 8 bpp", }, + V4L2_PIX_FMT_SBGGR8, 8, }, { MEDIA_BUS_FMT_SGBRG8_1X8, MEDIA_BUS_FMT_SGBRG8_1X8, MEDIA_BUS_FMT_SGBRG8_1X8, MEDIA_BUS_FMT_SGBRG8_1X8, - V4L2_PIX_FMT_SGBRG8, 8, "GBRG Bayer 8 bpp", }, + V4L2_PIX_FMT_SGBRG8, 8, }, { MEDIA_BUS_FMT_SGRBG8_1X8, MEDIA_BUS_FMT_SGRBG8_1X8, MEDIA_BUS_FMT_SGRBG8_1X8, MEDIA_BUS_FMT_SGRBG8_1X8, - V4L2_PIX_FMT_SGRBG8, 8, "GRBG Bayer 8 bpp", }, + V4L2_PIX_FMT_SGRBG8, 8, }, { MEDIA_BUS_FMT_SRGGB8_1X8, MEDIA_BUS_FMT_SRGGB8_1X8, MEDIA_BUS_FMT_SRGGB8_1X8, MEDIA_BUS_FMT_SRGGB8_1X8, - V4L2_PIX_FMT_SRGGB8, 8, "RGGB Bayer 8 bpp", }, + V4L2_PIX_FMT_SRGGB8, 8, }, { MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, MEDIA_BUS_FMT_SGRBG10_1X10, 0, - V4L2_PIX_FMT_SGRBG10DPCM8, 8, "GRBG Bayer 10 bpp DPCM8", }, + V4L2_PIX_FMT_SGRBG10DPCM8, 8, }, { MEDIA_BUS_FMT_SBGGR10_1X10, MEDIA_BUS_FMT_SBGGR10_1X10, MEDIA_BUS_FMT_SBGGR10_1X10, MEDIA_BUS_FMT_SBGGR8_1X8, - V4L2_PIX_FMT_SBGGR10, 10, "BGGR Bayer 10 bpp", }, + V4L2_PIX_FMT_SBGGR10, 10, }, { MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SGBRG8_1X8, - V4L2_PIX_FMT_SGBRG10, 10, "GBRG Bayer 10 bpp", }, + V4L2_PIX_FMT_SGBRG10, 10, }, { MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SGRBG8_1X8, - V4L2_PIX_FMT_SGRBG10, 10, "GRBG Bayer 10 bpp", }, + V4L2_PIX_FMT_SGRBG10, 10, }, { MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SRGGB8_1X8, - V4L2_PIX_FMT_SRGGB10, 10, "RGGB Bayer 10 bpp", }, + V4L2_PIX_FMT_SRGGB10, 10, }, { MEDIA_BUS_FMT_SBGGR12_1X12, MEDIA_BUS_FMT_SBGGR10_1X10, MEDIA_BUS_FMT_SBGGR12_1X12, MEDIA_BUS_FMT_SBGGR8_1X8, - V4L2_PIX_FMT_SBGGR12, 12, "BGGR Bayer 12 bpp", }, + V4L2_PIX_FMT_SBGGR12, 12, }, { MEDIA_BUS_FMT_SGBRG12_1X12, MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SGBRG12_1X12, MEDIA_BUS_FMT_SGBRG8_1X8, - V4L2_PIX_FMT_SGBRG12, 12, "GBRG Bayer 12 bpp", }, + V4L2_PIX_FMT_SGBRG12, 12, }, { MEDIA_BUS_FMT_SGRBG12_1X12, MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SGRBG12_1X12, MEDIA_BUS_FMT_SGRBG8_1X8, - V4L2_PIX_FMT_SGRBG12, 12, "GRBG Bayer 12 bpp", }, + V4L2_PIX_FMT_SGRBG12, 12, }, { MEDIA_BUS_FMT_SRGGB12_1X12, MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SRGGB12_1X12, MEDIA_BUS_FMT_SRGGB8_1X8, - V4L2_PIX_FMT_SRGGB12, 12, "RGGB Bayer 12 bpp", }, + V4L2_PIX_FMT_SRGGB12, 12, }, { MEDIA_BUS_FMT_UYVY8_1X16, MEDIA_BUS_FMT_UYVY8_1X16, MEDIA_BUS_FMT_UYVY8_1X16, 0, - V4L2_PIX_FMT_UYVY, 16, "YUV 4:2:2 (UYVY)", }, + V4L2_PIX_FMT_UYVY, 16, }, { MEDIA_BUS_FMT_YUYV8_1X16, MEDIA_BUS_FMT_YUYV8_1X16, MEDIA_BUS_FMT_YUYV8_1X16, 0, - V4L2_PIX_FMT_YUYV, 16, "YUV 4:2:2 (YUYV)", }, + V4L2_PIX_FMT_YUYV, 16, }, { MEDIA_BUS_FMT_YUYV8_1_5X8, MEDIA_BUS_FMT_YUYV8_1_5X8, MEDIA_BUS_FMT_YUYV8_1_5X8, 0, - V4L2_PIX_FMT_NV12, 8, "YUV 4:2:0 (NV12)", }, + V4L2_PIX_FMT_NV12, 8, }, }; const struct iss_format_info * @@ -563,8 +563,6 @@ iss_video_enum_format(struct file *file, void *fh, struct v4l2_fmtdesc *f) if (index == 0) { f->pixelformat = info->pixelformat; - strscpy(f->description, info->description, - sizeof(f->description)); return 0; } diff --git a/drivers/staging/media/omap4iss/iss_video.h b/drivers/staging/media/omap4iss/iss_video.h index f22489edb562..8b3dd92021e1 100644 --- a/drivers/staging/media/omap4iss/iss_video.h +++ b/drivers/staging/media/omap4iss/iss_video.h @@ -36,7 +36,6 @@ struct v4l2_pix_format; * shifted to be 8 bits per pixel. =0 if format is not shiftable. * @pixelformat: V4L2 pixel format FCC identifier * @bpp: Bits per pixel - * @description: Human-readable format description */ struct iss_format_info { u32 code; @@ -45,7 +44,6 @@ struct iss_format_info { u32 flavor; u32 pixelformat; unsigned int bpp; - const char *description; }; enum iss_pipeline_stream_state { diff --git a/drivers/staging/media/soc_camera/soc_camera.c b/drivers/staging/media/soc_camera/soc_camera.c index a6232dcd59bc..7b9448e3c9ba 100644 --- a/drivers/staging/media/soc_camera/soc_camera.c +++ b/drivers/staging/media/soc_camera/soc_camera.c @@ -869,8 +869,6 @@ static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv, format = icd->user_formats[f->index].host_fmt; - if (format->name) - strscpy(f->description, format->name, sizeof(f->description)); f->pixelformat = format->fourcc; return 0; } diff --git a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c index ea54cc27e645..d4d1e44b16b2 100644 --- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c +++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c @@ -75,34 +75,27 @@ static const struct v4l2_fract /* video formats */ static struct mmal_fmt formats[] = { { - .name = "4:2:0, planar, YUV", .fourcc = V4L2_PIX_FMT_YUV420, - .flags = 0, .mmal = MMAL_ENCODING_I420, .depth = 12, .mmal_component = COMP_CAMERA, .ybbp = 1, .remove_padding = 1, }, { - .name = "4:2:2, packed, YUYV", .fourcc = V4L2_PIX_FMT_YUYV, - .flags = 0, .mmal = MMAL_ENCODING_YUYV, .depth = 16, .mmal_component = COMP_CAMERA, .ybbp = 2, .remove_padding = 0, }, { - .name = "RGB24 (LE)", .fourcc = V4L2_PIX_FMT_RGB24, - .flags = 0, .mmal = MMAL_ENCODING_RGB24, .depth = 24, .mmal_component = COMP_CAMERA, .ybbp = 3, .remove_padding = 0, }, { - .name = "JPEG", .fourcc = V4L2_PIX_FMT_JPEG, .flags = V4L2_FMT_FLAG_COMPRESSED, .mmal = MMAL_ENCODING_JPEG, @@ -111,7 +104,6 @@ static struct mmal_fmt formats[] = { .ybbp = 0, .remove_padding = 0, }, { - .name = "H264", .fourcc = V4L2_PIX_FMT_H264, .flags = V4L2_FMT_FLAG_COMPRESSED, .mmal = MMAL_ENCODING_H264, @@ -120,7 +112,6 @@ static struct mmal_fmt formats[] = { .ybbp = 0, .remove_padding = 0, }, { - .name = "MJPEG", .fourcc = V4L2_PIX_FMT_MJPEG, .flags = V4L2_FMT_FLAG_COMPRESSED, .mmal = MMAL_ENCODING_MJPEG, @@ -129,72 +120,56 @@ static struct mmal_fmt formats[] = { .ybbp = 0, .remove_padding = 0, }, { - .name = "4:2:2, packed, YVYU", .fourcc = V4L2_PIX_FMT_YVYU, - .flags = 0, .mmal = MMAL_ENCODING_YVYU, .depth = 16, .mmal_component = COMP_CAMERA, .ybbp = 2, .remove_padding = 0, }, { - .name = "4:2:2, packed, VYUY", .fourcc = V4L2_PIX_FMT_VYUY, - .flags = 0, .mmal = MMAL_ENCODING_VYUY, .depth = 16, .mmal_component = COMP_CAMERA, .ybbp = 2, .remove_padding = 0, }, { - .name = "4:2:2, packed, UYVY", .fourcc = V4L2_PIX_FMT_UYVY, - .flags = 0, .mmal = MMAL_ENCODING_UYVY, .depth = 16, .mmal_component = COMP_CAMERA, .ybbp = 2, .remove_padding = 0, }, { - .name = "4:2:0, planar, NV12", .fourcc = V4L2_PIX_FMT_NV12, - .flags = 0, .mmal = MMAL_ENCODING_NV12, .depth = 12, .mmal_component = COMP_CAMERA, .ybbp = 1, .remove_padding = 1, }, { - .name = "RGB24 (BE)", .fourcc = V4L2_PIX_FMT_BGR24, - .flags = 0, .mmal = MMAL_ENCODING_BGR24, .depth = 24, .mmal_component = COMP_CAMERA, .ybbp = 3, .remove_padding = 0, }, { - .name = "4:2:0, planar, YVU", .fourcc = V4L2_PIX_FMT_YVU420, - .flags = 0, .mmal = MMAL_ENCODING_YV12, .depth = 12, .mmal_component = COMP_CAMERA, .ybbp = 1, .remove_padding = 1, }, { - .name = "4:2:0, planar, NV21", .fourcc = V4L2_PIX_FMT_NV21, - .flags = 0, .mmal = MMAL_ENCODING_NV21, .depth = 12, .mmal_component = COMP_CAMERA, .ybbp = 1, .remove_padding = 1, }, { - .name = "RGB32 (BE)", .fourcc = V4L2_PIX_FMT_BGR32, - .flags = 0, .mmal = MMAL_ENCODING_BGRA, .depth = 32, .mmal_component = COMP_CAMERA, @@ -716,9 +691,7 @@ static int vidioc_enum_fmt_vid_overlay(struct file *file, void *priv, fmt = &formats[f->index]; - strlcpy((char *)f->description, fmt->name, sizeof(f->description)); f->pixelformat = fmt->fourcc; - f->flags = fmt->flags; return 0; } @@ -919,9 +892,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, fmt = &formats[f->index]; - strlcpy((char *)f->description, fmt->name, sizeof(f->description)); f->pixelformat = fmt->fourcc; - f->flags = fmt->flags; return 0; } diff --git a/drivers/staging/vc04_services/bcm2835-camera/mmal-common.h b/drivers/staging/vc04_services/bcm2835-camera/mmal-common.h index 6f56c517d850..ff5398737b4a 100644 --- a/drivers/staging/vc04_services/bcm2835-camera/mmal-common.h +++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-common.h @@ -26,7 +26,6 @@ struct mmal_msg_context; /* mapping between v4l and mmal video modes */ struct mmal_fmt { - char *name; u32 fourcc; /* v4l2 format id */ int flags; /* v4l2 flags field */ u32 mmal; -- cgit v1.2.3-59-g8ed1b From bdd034050a46be32a9a68cc2cd1db8046efe5324 Mon Sep 17 00:00:00 2001 From: ZhiChao Yu Date: Thu, 11 Jul 2019 16:26:44 -0400 Subject: media: hantro: Add support for VP8 decoding on rk3288 Introduce VP8 decoding support in RK3288. Signed-off-by: ZhiChao Yu Signed-off-by: Tomasz Figa Signed-off-by: Boris Brezillon Signed-off-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/hantro/Makefile | 4 +- drivers/staging/media/hantro/hantro.h | 27 ++ drivers/staging/media/hantro/hantro_drv.c | 6 + drivers/staging/media/hantro/hantro_g1_vp8_dec.c | 526 +++++++++++++++++++++++ drivers/staging/media/hantro/hantro_hw.h | 17 + drivers/staging/media/hantro/hantro_v4l2.c | 1 + drivers/staging/media/hantro/hantro_vp8.c | 188 ++++++++ drivers/staging/media/hantro/rk3288_vpu_hw.c | 22 +- 8 files changed, 789 insertions(+), 2 deletions(-) create mode 100644 drivers/staging/media/hantro/hantro_g1_vp8_dec.c create mode 100644 drivers/staging/media/hantro/hantro_vp8.c (limited to 'drivers/staging') diff --git a/drivers/staging/media/hantro/Makefile b/drivers/staging/media/hantro/Makefile index 1584acdbf4a3..a627aee77f75 100644 --- a/drivers/staging/media/hantro/Makefile +++ b/drivers/staging/media/hantro/Makefile @@ -5,10 +5,12 @@ hantro-vpu-y += \ hantro_v4l2.o \ hantro_h1_jpeg_enc.o \ hantro_g1_mpeg2_dec.o \ + hantro_g1_vp8_dec.o \ rk3399_vpu_hw_jpeg_enc.o \ rk3399_vpu_hw_mpeg2_dec.o \ hantro_jpeg.o \ - hantro_mpeg2.o + hantro_mpeg2.o \ + hantro_vp8.o hantro-vpu-$(CONFIG_VIDEO_HANTRO_ROCKCHIP) += \ rk3288_vpu_hw.o \ diff --git a/drivers/staging/media/hantro/hantro.h b/drivers/staging/media/hantro/hantro.h index 62dcca9ff19c..4d7cb7780bde 100644 --- a/drivers/staging/media/hantro/hantro.h +++ b/drivers/staging/media/hantro/hantro.h @@ -25,6 +25,10 @@ #include "hantro_hw.h" +#define VP8_MB_DIM 16 +#define VP8_MB_WIDTH(w) DIV_ROUND_UP(w, VP8_MB_DIM) +#define VP8_MB_HEIGHT(h) DIV_ROUND_UP(h, VP8_MB_DIM) + #define MPEG2_MB_DIM 16 #define MPEG2_MB_WIDTH(w) DIV_ROUND_UP(w, MPEG2_MB_DIM) #define MPEG2_MB_HEIGHT(h) DIV_ROUND_UP(h, MPEG2_MB_DIM) @@ -40,6 +44,7 @@ struct hantro_codec_ops; #define HANTRO_ENCODERS 0x0000ffff #define HANTRO_MPEG2_DECODER BIT(16) +#define HANTRO_VP8_DECODER BIT(17) #define HANTRO_DECODERS 0xffff0000 /** @@ -97,11 +102,13 @@ struct hantro_variant { * @HANTRO_MODE_NONE: No operating mode. Used for RAW video formats. * @HANTRO_MODE_JPEG_ENC: JPEG encoder. * @HANTRO_MODE_MPEG2_DEC: MPEG-2 decoder. + * @HANTRO_MODE_VP8_DEC: VP8 decoder. */ enum hantro_codec_mode { HANTRO_MODE_NONE = -1, HANTRO_MODE_JPEG_ENC, HANTRO_MODE_MPEG2_DEC, + HANTRO_MODE_VP8_DEC, }; /* @@ -215,6 +222,7 @@ struct hantro_dev { * @codec_ops: Set of operations related to codec mode. * @jpeg_enc: JPEG-encoding context. * @mpeg2_dec: MPEG-2-decoding context. + * @vp8_dec: VP8-decoding context. */ struct hantro_ctx { struct hantro_dev *dev; @@ -241,6 +249,7 @@ struct hantro_ctx { union { struct hantro_jpeg_enc_hw_ctx jpeg_enc; struct hantro_mpeg2_dec_hw_ctx mpeg2_dec; + struct hantro_vp8_dec_hw_ctx vp8_dec; }; }; @@ -265,6 +274,12 @@ struct hantro_fmt { struct v4l2_frmsize_stepwise frmsize; }; +struct hantro_reg { + u32 base; + u32 shift; + u32 mask; +}; + /* Logging helpers */ /** @@ -343,6 +358,18 @@ static inline u32 vdpu_read(struct hantro_dev *vpu, u32 reg) return val; } +static inline void hantro_reg_write(struct hantro_dev *vpu, + const struct hantro_reg *reg, + u32 val) +{ + u32 v; + + v = vdpu_read(vpu, reg->base); + v &= ~(reg->mask << reg->shift); + v |= ((val & reg->mask) << reg->shift); + vdpu_write_relaxed(vpu, v, reg->base); +} + bool hantro_is_encoder_ctx(const struct hantro_ctx *ctx); void *hantro_get_ctrl(struct hantro_ctx *ctx, u32 id); diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c index c3665f0e87a2..839f3f470811 100644 --- a/drivers/staging/media/hantro/hantro_drv.c +++ b/drivers/staging/media/hantro/hantro_drv.c @@ -284,6 +284,12 @@ static struct hantro_ctrl controls[] = { .cfg = { .elem_size = sizeof(struct v4l2_ctrl_mpeg2_quantization), }, + }, { + .id = V4L2_CID_MPEG_VIDEO_VP8_FRAME_HEADER, + .codec = HANTRO_VP8_DECODER, + .cfg = { + .elem_size = sizeof(struct v4l2_ctrl_vp8_frame_header), + }, }, }; diff --git a/drivers/staging/media/hantro/hantro_g1_vp8_dec.c b/drivers/staging/media/hantro/hantro_g1_vp8_dec.c new file mode 100644 index 000000000000..72d983a11ca1 --- /dev/null +++ b/drivers/staging/media/hantro/hantro_g1_vp8_dec.c @@ -0,0 +1,526 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Hantro VP8 codec driver + * + * Copyright (C) 2019 Rockchip Electronics Co., Ltd. + * ZhiChao Yu + * + * Copyright (C) 2019 Google, Inc. + * Tomasz Figa + */ + +#include +#include + +#include "hantro_hw.h" +#include "hantro.h" +#include "hantro_g1_regs.h" + +#define DEC_8190_ALIGN_MASK 0x07U + +/* DCT partition base address regs */ +static const struct hantro_reg vp8_dec_dct_base[8] = { + { G1_REG_ADDR_STR, 0, 0xffffffff }, + { G1_REG_ADDR_REF(8), 0, 0xffffffff }, + { G1_REG_ADDR_REF(9), 0, 0xffffffff }, + { G1_REG_ADDR_REF(10), 0, 0xffffffff }, + { G1_REG_ADDR_REF(11), 0, 0xffffffff }, + { G1_REG_ADDR_REF(12), 0, 0xffffffff }, + { G1_REG_ADDR_REF(14), 0, 0xffffffff }, + { G1_REG_ADDR_REF(15), 0, 0xffffffff }, +}; + +/* Loop filter level regs */ +static const struct hantro_reg vp8_dec_lf_level[4] = { + { G1_REG_REF_PIC(2), 18, 0x3f }, + { G1_REG_REF_PIC(2), 12, 0x3f }, + { G1_REG_REF_PIC(2), 6, 0x3f }, + { G1_REG_REF_PIC(2), 0, 0x3f }, +}; + +/* Macroblock loop filter level adjustment regs */ +static const struct hantro_reg vp8_dec_mb_adj[4] = { + { G1_REG_REF_PIC(0), 21, 0x7f }, + { G1_REG_REF_PIC(0), 14, 0x7f }, + { G1_REG_REF_PIC(0), 7, 0x7f }, + { G1_REG_REF_PIC(0), 0, 0x7f }, +}; + +/* Reference frame adjustment regs */ +static const struct hantro_reg vp8_dec_ref_adj[4] = { + { G1_REG_REF_PIC(1), 21, 0x7f }, + { G1_REG_REF_PIC(1), 14, 0x7f }, + { G1_REG_REF_PIC(1), 7, 0x7f }, + { G1_REG_REF_PIC(1), 0, 0x7f }, +}; + +/* Quantizer */ +static const struct hantro_reg vp8_dec_quant[4] = { + { G1_REG_REF_PIC(3), 11, 0x7ff }, + { G1_REG_REF_PIC(3), 0, 0x7ff }, + { G1_REG_BD_REF_PIC(4), 11, 0x7ff }, + { G1_REG_BD_REF_PIC(4), 0, 0x7ff }, +}; + +/* Quantizer delta regs */ +static const struct hantro_reg vp8_dec_quant_delta[5] = { + { G1_REG_REF_PIC(3), 27, 0x1f }, + { G1_REG_REF_PIC(3), 22, 0x1f }, + { G1_REG_BD_REF_PIC(4), 27, 0x1f }, + { G1_REG_BD_REF_PIC(4), 22, 0x1f }, + { G1_REG_BD_P_REF_PIC, 27, 0x1f }, +}; + +/* DCT partition start bits regs */ +static const struct hantro_reg vp8_dec_dct_start_bits[8] = { + { G1_REG_DEC_CTRL2, 26, 0x3f }, { G1_REG_DEC_CTRL4, 26, 0x3f }, + { G1_REG_DEC_CTRL4, 20, 0x3f }, { G1_REG_DEC_CTRL7, 24, 0x3f }, + { G1_REG_DEC_CTRL7, 18, 0x3f }, { G1_REG_DEC_CTRL7, 12, 0x3f }, + { G1_REG_DEC_CTRL7, 6, 0x3f }, { G1_REG_DEC_CTRL7, 0, 0x3f }, +}; + +/* Precision filter tap regs */ +static const struct hantro_reg vp8_dec_pred_bc_tap[8][4] = { + { + { G1_REG_PRED_FLT, 22, 0x3ff }, + { G1_REG_PRED_FLT, 12, 0x3ff }, + { G1_REG_PRED_FLT, 2, 0x3ff }, + { G1_REG_REF_PIC(4), 22, 0x3ff }, + }, + { + { G1_REG_REF_PIC(4), 12, 0x3ff }, + { G1_REG_REF_PIC(4), 2, 0x3ff }, + { G1_REG_REF_PIC(5), 22, 0x3ff }, + { G1_REG_REF_PIC(5), 12, 0x3ff }, + }, + { + { G1_REG_REF_PIC(5), 2, 0x3ff }, + { G1_REG_REF_PIC(6), 22, 0x3ff }, + { G1_REG_REF_PIC(6), 12, 0x3ff }, + { G1_REG_REF_PIC(6), 2, 0x3ff }, + }, + { + { G1_REG_REF_PIC(7), 22, 0x3ff }, + { G1_REG_REF_PIC(7), 12, 0x3ff }, + { G1_REG_REF_PIC(7), 2, 0x3ff }, + { G1_REG_LT_REF, 22, 0x3ff }, + }, + { + { G1_REG_LT_REF, 12, 0x3ff }, + { G1_REG_LT_REF, 2, 0x3ff }, + { G1_REG_VALID_REF, 22, 0x3ff }, + { G1_REG_VALID_REF, 12, 0x3ff }, + }, + { + { G1_REG_VALID_REF, 2, 0x3ff }, + { G1_REG_BD_REF_PIC(0), 22, 0x3ff }, + { G1_REG_BD_REF_PIC(0), 12, 0x3ff }, + { G1_REG_BD_REF_PIC(0), 2, 0x3ff }, + }, + { + { G1_REG_BD_REF_PIC(1), 22, 0x3ff }, + { G1_REG_BD_REF_PIC(1), 12, 0x3ff }, + { G1_REG_BD_REF_PIC(1), 2, 0x3ff }, + { G1_REG_BD_REF_PIC(2), 22, 0x3ff }, + }, + { + { G1_REG_BD_REF_PIC(2), 12, 0x3ff }, + { G1_REG_BD_REF_PIC(2), 2, 0x3ff }, + { G1_REG_BD_REF_PIC(3), 22, 0x3ff }, + { G1_REG_BD_REF_PIC(3), 12, 0x3ff }, + }, +}; + +/* + * filter taps taken to 7-bit precision, + * reference RFC6386#Page-16, filters[8][6] + */ +static const u32 vp8_dec_mc_filter[8][6] = { + { 0, 0, 128, 0, 0, 0 }, + { 0, -6, 123, 12, -1, 0 }, + { 2, -11, 108, 36, -8, 1 }, + { 0, -9, 93, 50, -6, 0 }, + { 3, -16, 77, 77, -16, 3 }, + { 0, -6, 50, 93, -9, 0 }, + { 1, -8, 36, 108, -11, 2 }, + { 0, -1, 12, 123, -6, 0 } +}; + +/* + * Set loop filters + */ +static void cfg_lf(struct hantro_ctx *ctx, + const struct v4l2_ctrl_vp8_frame_header *hdr) +{ + const struct v4l2_vp8_segment_header *seg = &hdr->segment_header; + const struct v4l2_vp8_loopfilter_header *lf = &hdr->lf_header; + struct hantro_dev *vpu = ctx->dev; + unsigned int i; + u32 reg; + + if (!(seg->flags & V4L2_VP8_SEGMENT_HEADER_FLAG_ENABLED)) { + hantro_reg_write(vpu, &vp8_dec_lf_level[0], lf->level); + } else if (seg->flags & V4L2_VP8_SEGMENT_HEADER_FLAG_DELTA_VALUE_MODE) { + for (i = 0; i < 4; i++) { + u32 lf_level = clamp(lf->level + seg->lf_update[i], + 0, 63); + + hantro_reg_write(vpu, &vp8_dec_lf_level[i], lf_level); + } + } else { + for (i = 0; i < 4; i++) + hantro_reg_write(vpu, &vp8_dec_lf_level[i], + seg->lf_update[i]); + } + + reg = G1_REG_REF_PIC_FILT_SHARPNESS(lf->sharpness_level); + if (lf->flags & V4L2_VP8_LF_FILTER_TYPE_SIMPLE) + reg |= G1_REG_REF_PIC_FILT_TYPE_E; + vdpu_write_relaxed(vpu, reg, G1_REG_REF_PIC(0)); + + if (lf->flags & V4L2_VP8_LF_HEADER_ADJ_ENABLE) { + for (i = 0; i < 4; i++) { + hantro_reg_write(vpu, &vp8_dec_mb_adj[i], + lf->mb_mode_delta[i]); + hantro_reg_write(vpu, &vp8_dec_ref_adj[i], + lf->ref_frm_delta[i]); + } + } +} + +/* + * Set quantization parameters + */ +static void cfg_qp(struct hantro_ctx *ctx, + const struct v4l2_ctrl_vp8_frame_header *hdr) +{ + const struct v4l2_vp8_quantization_header *q = &hdr->quant_header; + const struct v4l2_vp8_segment_header *seg = &hdr->segment_header; + struct hantro_dev *vpu = ctx->dev; + unsigned int i; + + if (!(seg->flags & V4L2_VP8_SEGMENT_HEADER_FLAG_ENABLED)) { + hantro_reg_write(vpu, &vp8_dec_quant[0], q->y_ac_qi); + } else if (seg->flags & V4L2_VP8_SEGMENT_HEADER_FLAG_DELTA_VALUE_MODE) { + for (i = 0; i < 4; i++) { + u32 quant = clamp(q->y_ac_qi + seg->quant_update[i], + 0, 127); + + hantro_reg_write(vpu, &vp8_dec_quant[i], quant); + } + } else { + for (i = 0; i < 4; i++) + hantro_reg_write(vpu, &vp8_dec_quant[i], + seg->quant_update[i]); + } + + hantro_reg_write(vpu, &vp8_dec_quant_delta[0], q->y_dc_delta); + hantro_reg_write(vpu, &vp8_dec_quant_delta[1], q->y2_dc_delta); + hantro_reg_write(vpu, &vp8_dec_quant_delta[2], q->y2_ac_delta); + hantro_reg_write(vpu, &vp8_dec_quant_delta[3], q->uv_dc_delta); + hantro_reg_write(vpu, &vp8_dec_quant_delta[4], q->uv_ac_delta); +} + +/* + * set control partition and DCT partition regs + * + * VP8 frame stream data layout: + * + * first_part_size parttion_sizes[0] + * ^ ^ + * src_dma | | + * ^ +--------+------+ +-----+-----+ + * | | control part | | | + * +--------+----------------+------------------+-----------+-----+-----------+ + * | tag 3B | extra 7B | hdr | mb_data | DCT sz | DCT part0 | ... | DCT partn | + * +--------+-----------------------------------+-----------+-----+-----------+ + * | | | | + * v +----+---+ v + * mb_start | src_dma_end + * v + * DCT size part + * (num_dct-1)*3B + * Note: + * 1. only key-frames have extra 7-bytes + * 2. all offsets are base on src_dma + * 3. number of DCT parts is 1, 2, 4 or 8 + * 4. the addresses set to the VPU must be 64-bits aligned + */ +static void cfg_parts(struct hantro_ctx *ctx, + const struct v4l2_ctrl_vp8_frame_header *hdr) +{ + struct hantro_dev *vpu = ctx->dev; + struct vb2_v4l2_buffer *vb2_src; + u32 first_part_offset = VP8_FRAME_IS_KEY_FRAME(hdr) ? 10 : 3; + u32 mb_size, mb_offset_bytes, mb_offset_bits, mb_start_bits; + u32 dct_size_part_size, dct_part_offset; + struct hantro_reg reg; + dma_addr_t src_dma; + u32 dct_part_total_len = 0; + u32 count = 0; + unsigned int i; + + vb2_src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + src_dma = vb2_dma_contig_plane_dma_addr(&vb2_src->vb2_buf, 0); + + /* + * Calculate control partition mb data info + * @first_part_header_bits: bits offset of mb data from first + * part start pos + * @mb_offset_bits: bits offset of mb data from src_dma + * base addr + * @mb_offset_byte: bytes offset of mb data from src_dma + * base addr + * @mb_start_bits: bits offset of mb data from mb data + * 64bits alignment addr + */ + mb_offset_bits = first_part_offset * 8 + + hdr->first_part_header_bits + 8; + mb_offset_bytes = mb_offset_bits / 8; + mb_start_bits = mb_offset_bits - + (mb_offset_bytes & (~DEC_8190_ALIGN_MASK)) * 8; + mb_size = hdr->first_part_size - + (mb_offset_bytes - first_part_offset) + + (mb_offset_bytes & DEC_8190_ALIGN_MASK); + + /* Macroblock data aligned base addr */ + vdpu_write_relaxed(vpu, (mb_offset_bytes & (~DEC_8190_ALIGN_MASK)) + + src_dma, G1_REG_ADDR_REF(13)); + + /* Macroblock data start bits */ + reg.base = G1_REG_DEC_CTRL2; + reg.mask = 0x3f; + reg.shift = 18; + hantro_reg_write(vpu, ®, mb_start_bits); + + /* Macroblock aligned data length */ + reg.base = G1_REG_DEC_CTRL6; + reg.mask = 0x3fffff; + reg.shift = 0; + hantro_reg_write(vpu, ®, mb_size + 1); + + /* + * Calculate DCT partition info + * @dct_size_part_size: Containing sizes of DCT part, every DCT part + * has 3 bytes to store its size, except the last + * DCT part + * @dct_part_offset: bytes offset of DCT parts from src_dma base addr + * @dct_part_total_len: total size of all DCT parts + */ + dct_size_part_size = (hdr->num_dct_parts - 1) * 3; + dct_part_offset = first_part_offset + hdr->first_part_size; + for (i = 0; i < hdr->num_dct_parts; i++) + dct_part_total_len += hdr->dct_part_sizes[i]; + dct_part_total_len += dct_size_part_size; + dct_part_total_len += (dct_part_offset & DEC_8190_ALIGN_MASK); + + /* Number of DCT partitions */ + reg.base = G1_REG_DEC_CTRL6; + reg.mask = 0xf; + reg.shift = 24; + hantro_reg_write(vpu, ®, hdr->num_dct_parts - 1); + + /* DCT partition length */ + vdpu_write_relaxed(vpu, + G1_REG_DEC_CTRL3_STREAM_LEN(dct_part_total_len), + G1_REG_DEC_CTRL3); + + /* DCT partitions base address */ + for (i = 0; i < hdr->num_dct_parts; i++) { + u32 byte_offset = dct_part_offset + dct_size_part_size + count; + u32 base_addr = byte_offset + src_dma; + + hantro_reg_write(vpu, &vp8_dec_dct_base[i], + base_addr & (~DEC_8190_ALIGN_MASK)); + + hantro_reg_write(vpu, &vp8_dec_dct_start_bits[i], + (byte_offset & DEC_8190_ALIGN_MASK) * 8); + + count += hdr->dct_part_sizes[i]; + } +} + +/* + * prediction filter taps + * normal 6-tap filters + */ +static void cfg_tap(struct hantro_ctx *ctx, + const struct v4l2_ctrl_vp8_frame_header *hdr) +{ + struct hantro_dev *vpu = ctx->dev; + struct hantro_reg reg; + u32 val = 0; + int i, j; + + reg.base = G1_REG_BD_REF_PIC(3); + reg.mask = 0xf; + + if ((hdr->version & 0x03) != 0) + return; /* Tap filter not used. */ + + for (i = 0; i < 8; i++) { + val = (vp8_dec_mc_filter[i][0] << 2) | vp8_dec_mc_filter[i][5]; + + for (j = 0; j < 4; j++) + hantro_reg_write(vpu, &vp8_dec_pred_bc_tap[i][j], + vp8_dec_mc_filter[i][j + 1]); + + switch (i) { + case 2: + reg.shift = 8; + break; + case 4: + reg.shift = 4; + break; + case 6: + reg.shift = 0; + break; + default: + continue; + } + + hantro_reg_write(vpu, ®, val); + } +} + +static void cfg_ref(struct hantro_ctx *ctx, + const struct v4l2_ctrl_vp8_frame_header *hdr) +{ + struct vb2_queue *cap_q = &ctx->fh.m2m_ctx->cap_q_ctx.q; + struct hantro_dev *vpu = ctx->dev; + struct vb2_v4l2_buffer *vb2_dst; + dma_addr_t ref; + + vb2_dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + + ref = hantro_get_ref(cap_q, hdr->last_frame_ts); + if (!ref) + ref = vb2_dma_contig_plane_dma_addr(&vb2_dst->vb2_buf, 0); + vdpu_write_relaxed(vpu, ref, G1_REG_ADDR_REF(0)); + + ref = hantro_get_ref(cap_q, hdr->golden_frame_ts); + WARN_ON(!ref && hdr->golden_frame_ts); + if (!ref) + ref = vb2_dma_contig_plane_dma_addr(&vb2_dst->vb2_buf, 0); + if (hdr->flags & V4L2_VP8_FRAME_HEADER_FLAG_SIGN_BIAS_GOLDEN) + ref |= G1_REG_ADDR_REF_TOPC_E; + vdpu_write_relaxed(vpu, ref, G1_REG_ADDR_REF(4)); + + ref = hantro_get_ref(cap_q, hdr->alt_frame_ts); + WARN_ON(!ref && hdr->alt_frame_ts); + if (!ref) + ref = vb2_dma_contig_plane_dma_addr(&vb2_dst->vb2_buf, 0); + if (hdr->flags & V4L2_VP8_FRAME_HEADER_FLAG_SIGN_BIAS_ALT) + ref |= G1_REG_ADDR_REF_TOPC_E; + vdpu_write_relaxed(vpu, ref, G1_REG_ADDR_REF(5)); +} + +static void cfg_buffers(struct hantro_ctx *ctx, + const struct v4l2_ctrl_vp8_frame_header *hdr) +{ + const struct v4l2_vp8_segment_header *seg = &hdr->segment_header; + struct hantro_dev *vpu = ctx->dev; + struct vb2_v4l2_buffer *vb2_dst; + dma_addr_t dst_dma; + u32 reg; + + vb2_dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + + /* Set probability table buffer address */ + vdpu_write_relaxed(vpu, ctx->vp8_dec.prob_tbl.dma, + G1_REG_ADDR_QTABLE); + + /* Set segment map address */ + reg = G1_REG_FWD_PIC1_SEGMENT_BASE(ctx->vp8_dec.segment_map.dma); + if (seg->flags & V4L2_VP8_SEGMENT_HEADER_FLAG_ENABLED) { + reg |= G1_REG_FWD_PIC1_SEGMENT_E; + if (seg->flags & V4L2_VP8_SEGMENT_HEADER_FLAG_UPDATE_MAP) + reg |= G1_REG_FWD_PIC1_SEGMENT_UPD_E; + } + vdpu_write_relaxed(vpu, reg, G1_REG_FWD_PIC(0)); + + dst_dma = vb2_dma_contig_plane_dma_addr(&vb2_dst->vb2_buf, 0); + vdpu_write_relaxed(vpu, dst_dma, G1_REG_ADDR_DST); +} + +void hantro_g1_vp8_dec_run(struct hantro_ctx *ctx) +{ + const struct v4l2_ctrl_vp8_frame_header *hdr; + struct hantro_dev *vpu = ctx->dev; + size_t height = ctx->dst_fmt.height; + size_t width = ctx->dst_fmt.width; + struct vb2_v4l2_buffer *vb2_src; + u32 mb_width, mb_height; + u32 reg; + + vb2_src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + v4l2_ctrl_request_setup(vb2_src->vb2_buf.req_obj.req, + &ctx->ctrl_handler); + + hdr = hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_VP8_FRAME_HEADER); + if (WARN_ON(!hdr)) + return; + + /* Reset segment_map buffer in keyframe */ + if (VP8_FRAME_IS_KEY_FRAME(hdr) && ctx->vp8_dec.segment_map.cpu) + memset(ctx->vp8_dec.segment_map.cpu, 0, + ctx->vp8_dec.segment_map.size); + + hantro_vp8_prob_update(ctx, hdr); + + reg = G1_REG_CONFIG_DEC_TIMEOUT_E | + G1_REG_CONFIG_DEC_STRENDIAN_E | + G1_REG_CONFIG_DEC_INSWAP32_E | + G1_REG_CONFIG_DEC_STRSWAP32_E | + G1_REG_CONFIG_DEC_OUTSWAP32_E | + G1_REG_CONFIG_DEC_CLK_GATE_E | + G1_REG_CONFIG_DEC_IN_ENDIAN | + G1_REG_CONFIG_DEC_OUT_ENDIAN | + G1_REG_CONFIG_DEC_MAX_BURST(16); + vdpu_write_relaxed(vpu, reg, G1_REG_CONFIG); + + reg = G1_REG_DEC_CTRL0_DEC_MODE(10); + if (!VP8_FRAME_IS_KEY_FRAME(hdr)) + reg |= G1_REG_DEC_CTRL0_PIC_INTER_E; + if (!(hdr->flags & V4L2_VP8_FRAME_HEADER_FLAG_MB_NO_SKIP_COEFF)) + reg |= G1_REG_DEC_CTRL0_SKIP_MODE; + if (hdr->lf_header.level == 0) + reg |= G1_REG_DEC_CTRL0_FILTERING_DIS; + vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL0); + + /* Frame dimensions */ + mb_width = VP8_MB_WIDTH(width); + mb_height = VP8_MB_HEIGHT(height); + reg = G1_REG_DEC_CTRL1_PIC_MB_WIDTH(mb_width) | + G1_REG_DEC_CTRL1_PIC_MB_HEIGHT_P(mb_height) | + G1_REG_DEC_CTRL1_PIC_MB_W_EXT(mb_width >> 9) | + G1_REG_DEC_CTRL1_PIC_MB_H_EXT(mb_height >> 8); + vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL1); + + /* Boolean decoder */ + reg = G1_REG_DEC_CTRL2_BOOLEAN_RANGE(hdr->coder_state.range) + | G1_REG_DEC_CTRL2_BOOLEAN_VALUE(hdr->coder_state.value); + vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL2); + + reg = 0; + if (hdr->version != 3) + reg |= G1_REG_DEC_CTRL4_VC1_HEIGHT_EXT; + if (hdr->version & 0x3) + reg |= G1_REG_DEC_CTRL4_BILIN_MC_E; + vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL4); + + cfg_lf(ctx, hdr); + cfg_qp(ctx, hdr); + cfg_parts(ctx, hdr); + cfg_tap(ctx, hdr); + cfg_ref(ctx, hdr); + cfg_buffers(ctx, hdr); + + /* Controls no longer in-use, we can complete them */ + v4l2_ctrl_request_complete(vb2_src->vb2_buf.req_obj.req, + &ctx->ctrl_handler); + + schedule_delayed_work(&vpu->watchdog_work, msecs_to_jiffies(2000)); + + vdpu_write(vpu, G1_REG_INTERRUPT_DEC_E, G1_REG_INTERRUPT); +} diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/staging/media/hantro/hantro_hw.h index 3c361c2e9b88..7849852affde 100644 --- a/drivers/staging/media/hantro/hantro_hw.h +++ b/drivers/staging/media/hantro/hantro_hw.h @@ -12,6 +12,7 @@ #include #include #include +#include #include struct hantro_dev; @@ -47,6 +48,16 @@ struct hantro_mpeg2_dec_hw_ctx { struct hantro_aux_buf qtable; }; +/** + * struct hantro_vp8d_hw_ctx + * @segment_map: Segment map buffer. + * @prob_tbl: Probability table buffer. + */ +struct hantro_vp8_dec_hw_ctx { + struct hantro_aux_buf segment_map; + struct hantro_aux_buf prob_tbl; +}; + /** * struct hantro_codec_ops - codec mode specific operations * @@ -99,4 +110,10 @@ void hantro_mpeg2_dec_copy_qtable(u8 *qtable, int hantro_mpeg2_dec_init(struct hantro_ctx *ctx); void hantro_mpeg2_dec_exit(struct hantro_ctx *ctx); +void hantro_g1_vp8_dec_run(struct hantro_ctx *ctx); +int hantro_vp8_dec_init(struct hantro_ctx *ctx); +void hantro_vp8_dec_exit(struct hantro_ctx *ctx); +void hantro_vp8_prob_update(struct hantro_ctx *ctx, + const struct v4l2_ctrl_vp8_frame_header *hdr); + #endif /* HANTRO_HW_H_ */ diff --git a/drivers/staging/media/hantro/hantro_v4l2.c b/drivers/staging/media/hantro/hantro_v4l2.c index 68f45ee66821..cd4eaa256e8b 100644 --- a/drivers/staging/media/hantro/hantro_v4l2.c +++ b/drivers/staging/media/hantro/hantro_v4l2.c @@ -344,6 +344,7 @@ hantro_update_requires_request(struct hantro_ctx *ctx, u32 fourcc) ctx->fh.m2m_ctx->out_q_ctx.q.requires_requests = false; break; case V4L2_PIX_FMT_MPEG2_SLICE: + case V4L2_PIX_FMT_VP8_FRAME: ctx->fh.m2m_ctx->out_q_ctx.q.requires_requests = true; break; default: diff --git a/drivers/staging/media/hantro/hantro_vp8.c b/drivers/staging/media/hantro/hantro_vp8.c new file mode 100644 index 000000000000..66c45335d871 --- /dev/null +++ b/drivers/staging/media/hantro/hantro_vp8.c @@ -0,0 +1,188 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Hantro VPU codec driver + * + * Copyright (C) 2018 Rockchip Electronics Co., Ltd. + */ + +#include "hantro.h" + +/* + * probs table with packed + */ +struct vp8_prob_tbl_packed { + u8 prob_mb_skip_false; + u8 prob_intra; + u8 prob_ref_last; + u8 prob_ref_golden; + u8 prob_segment[3]; + u8 padding0; + + u8 prob_luma_16x16_pred_mode[4]; + u8 prob_chroma_pred_mode[3]; + u8 padding1; + + /* mv prob */ + u8 prob_mv_context[2][19]; + u8 padding2[2]; + + /* coeff probs */ + u8 prob_coeffs[4][8][3][11]; + u8 padding3[96]; +}; + +void hantro_vp8_prob_update(struct hantro_ctx *ctx, + const struct v4l2_ctrl_vp8_frame_header *hdr) +{ + const struct v4l2_vp8_entropy_header *entropy = &hdr->entropy_header; + u32 i, j, k; + u8 *dst; + + /* first probs */ + dst = ctx->vp8_dec.prob_tbl.cpu; + + dst[0] = hdr->prob_skip_false; + dst[1] = hdr->prob_intra; + dst[2] = hdr->prob_last; + dst[3] = hdr->prob_gf; + dst[4] = hdr->segment_header.segment_probs[0]; + dst[5] = hdr->segment_header.segment_probs[1]; + dst[6] = hdr->segment_header.segment_probs[2]; + dst[7] = 0; + + dst += 8; + dst[0] = entropy->y_mode_probs[0]; + dst[1] = entropy->y_mode_probs[1]; + dst[2] = entropy->y_mode_probs[2]; + dst[3] = entropy->y_mode_probs[3]; + dst[4] = entropy->uv_mode_probs[0]; + dst[5] = entropy->uv_mode_probs[1]; + dst[6] = entropy->uv_mode_probs[2]; + dst[7] = 0; /*unused */ + + /* mv probs */ + dst += 8; + dst[0] = entropy->mv_probs[0][0]; /* is short */ + dst[1] = entropy->mv_probs[1][0]; + dst[2] = entropy->mv_probs[0][1]; /* sign */ + dst[3] = entropy->mv_probs[1][1]; + dst[4] = entropy->mv_probs[0][8 + 9]; + dst[5] = entropy->mv_probs[0][9 + 9]; + dst[6] = entropy->mv_probs[1][8 + 9]; + dst[7] = entropy->mv_probs[1][9 + 9]; + dst += 8; + for (i = 0; i < 2; ++i) { + for (j = 0; j < 8; j += 4) { + dst[0] = entropy->mv_probs[i][j + 9 + 0]; + dst[1] = entropy->mv_probs[i][j + 9 + 1]; + dst[2] = entropy->mv_probs[i][j + 9 + 2]; + dst[3] = entropy->mv_probs[i][j + 9 + 3]; + dst += 4; + } + } + for (i = 0; i < 2; ++i) { + dst[0] = entropy->mv_probs[i][0 + 2]; + dst[1] = entropy->mv_probs[i][1 + 2]; + dst[2] = entropy->mv_probs[i][2 + 2]; + dst[3] = entropy->mv_probs[i][3 + 2]; + dst[4] = entropy->mv_probs[i][4 + 2]; + dst[5] = entropy->mv_probs[i][5 + 2]; + dst[6] = entropy->mv_probs[i][6 + 2]; + dst[7] = 0; /*unused */ + dst += 8; + } + + /* coeff probs (header part) */ + dst = ctx->vp8_dec.prob_tbl.cpu; + dst += (8 * 7); + for (i = 0; i < 4; ++i) { + for (j = 0; j < 8; ++j) { + for (k = 0; k < 3; ++k) { + dst[0] = entropy->coeff_probs[i][j][k][0]; + dst[1] = entropy->coeff_probs[i][j][k][1]; + dst[2] = entropy->coeff_probs[i][j][k][2]; + dst[3] = entropy->coeff_probs[i][j][k][3]; + dst += 4; + } + } + } + + /* coeff probs (footer part) */ + dst = ctx->vp8_dec.prob_tbl.cpu; + dst += (8 * 55); + for (i = 0; i < 4; ++i) { + for (j = 0; j < 8; ++j) { + for (k = 0; k < 3; ++k) { + dst[0] = entropy->coeff_probs[i][j][k][4]; + dst[1] = entropy->coeff_probs[i][j][k][5]; + dst[2] = entropy->coeff_probs[i][j][k][6]; + dst[3] = entropy->coeff_probs[i][j][k][7]; + dst[4] = entropy->coeff_probs[i][j][k][8]; + dst[5] = entropy->coeff_probs[i][j][k][9]; + dst[6] = entropy->coeff_probs[i][j][k][10]; + dst[7] = 0; /*unused */ + dst += 8; + } + } + } +} + +int hantro_vp8_dec_init(struct hantro_ctx *ctx) +{ + struct hantro_dev *vpu = ctx->dev; + struct hantro_aux_buf *aux_buf; + unsigned int mb_width, mb_height; + size_t segment_map_size; + int ret; + + /* segment map table size calculation */ + mb_width = DIV_ROUND_UP(ctx->dst_fmt.width, 16); + mb_height = DIV_ROUND_UP(ctx->dst_fmt.height, 16); + segment_map_size = round_up(DIV_ROUND_UP(mb_width * mb_height, 4), 64); + + /* + * In context init the dma buffer for segment map must be allocated. + * And the data in segment map buffer must be set to all zero. + */ + aux_buf = &ctx->vp8_dec.segment_map; + aux_buf->size = segment_map_size; + aux_buf->cpu = dma_alloc_coherent(vpu->dev, aux_buf->size, + &aux_buf->dma, GFP_KERNEL); + if (!aux_buf->cpu) + return -ENOMEM; + + memset(aux_buf->cpu, 0, aux_buf->size); + + /* + * Allocate probability table buffer, + * total 1208 bytes, 4K page is far enough. + */ + aux_buf = &ctx->vp8_dec.prob_tbl; + aux_buf->size = sizeof(struct vp8_prob_tbl_packed); + aux_buf->cpu = dma_alloc_coherent(vpu->dev, aux_buf->size, + &aux_buf->dma, GFP_KERNEL); + if (!aux_buf->cpu) { + ret = -ENOMEM; + goto err_free_seg_map; + } + + return 0; + +err_free_seg_map: + dma_free_coherent(vpu->dev, ctx->vp8_dec.segment_map.size, + ctx->vp8_dec.segment_map.cpu, + ctx->vp8_dec.segment_map.dma); + + return ret; +} + +void hantro_vp8_dec_exit(struct hantro_ctx *ctx) +{ + struct hantro_vp8_dec_hw_ctx *vp8_dec = &ctx->vp8_dec; + struct hantro_dev *vpu = ctx->dev; + + dma_free_coherent(vpu->dev, vp8_dec->segment_map.size, + vp8_dec->segment_map.cpu, vp8_dec->segment_map.dma); + dma_free_coherent(vpu->dev, vp8_dec->prob_tbl.size, + vp8_dec->prob_tbl.cpu, vp8_dec->prob_tbl.dma); +} diff --git a/drivers/staging/media/hantro/rk3288_vpu_hw.c b/drivers/staging/media/hantro/rk3288_vpu_hw.c index bcacc4f51093..f1b573a006ae 100644 --- a/drivers/staging/media/hantro/rk3288_vpu_hw.c +++ b/drivers/staging/media/hantro/rk3288_vpu_hw.c @@ -74,6 +74,19 @@ static const struct hantro_fmt rk3288_vpu_dec_fmts[] = { .step_height = MPEG2_MB_DIM, }, }, + { + .fourcc = V4L2_PIX_FMT_VP8_FRAME, + .codec_mode = HANTRO_MODE_VP8_DEC, + .max_depth = 2, + .frmsize = { + .min_width = 48, + .max_width = 3840, + .step_width = VP8_MB_DIM, + .min_height = 48, + .max_height = 2160, + .step_height = VP8_MB_DIM, + }, + }, }; static irqreturn_t rk3288_vepu_irq(int irq, void *dev_id) @@ -155,6 +168,12 @@ static const struct hantro_codec_ops rk3288_vpu_codec_ops[] = { .init = hantro_mpeg2_dec_init, .exit = hantro_mpeg2_dec_exit, }, + [HANTRO_MODE_VP8_DEC] = { + .run = hantro_g1_vp8_dec_run, + .reset = rk3288_vpu_dec_reset, + .init = hantro_vp8_dec_init, + .exit = hantro_vp8_dec_exit, + }, }; /* @@ -177,7 +196,8 @@ const struct hantro_variant rk3288_vpu_variant = { .dec_offset = 0x400, .dec_fmts = rk3288_vpu_dec_fmts, .num_dec_fmts = ARRAY_SIZE(rk3288_vpu_dec_fmts), - .codec = HANTRO_JPEG_ENCODER | HANTRO_MPEG2_DECODER, + .codec = HANTRO_JPEG_ENCODER | HANTRO_MPEG2_DECODER | + HANTRO_VP8_DECODER, .codec_ops = rk3288_vpu_codec_ops, .irqs = rk3288_irqs, .num_irqs = ARRAY_SIZE(rk3288_irqs), -- cgit v1.2.3-59-g8ed1b From d3bfed33e2d80ce5a25549c2f935c91775b2b3f3 Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Wed, 12 Jun 2019 05:42:08 -0400 Subject: media: hantro: Add support for MPEG-2 decoding on RK3328 Add necessary bits to support MPEG2 decoding on RK3328. Signed-off-by: Jonas Karlman Signed-off-by: Ezequiel Garcia Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/hantro/Kconfig | 2 +- drivers/staging/media/hantro/hantro_drv.c | 1 + drivers/staging/media/hantro/rk3399_vpu_hw.c | 17 +++++++++++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/hantro/Kconfig b/drivers/staging/media/hantro/Kconfig index be133bbaa68a..de77fe6554e7 100644 --- a/drivers/staging/media/hantro/Kconfig +++ b/drivers/staging/media/hantro/Kconfig @@ -20,4 +20,4 @@ config VIDEO_HANTRO_ROCKCHIP depends on ARCH_ROCKCHIP || COMPILE_TEST default y help - Enable support for RK3288 and RK3399 SoCs. + Enable support for RK3288, RK3328, and RK3399 SoCs. diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c index 839f3f470811..b71a06e9159e 100644 --- a/drivers/staging/media/hantro/hantro_drv.c +++ b/drivers/staging/media/hantro/hantro_drv.c @@ -425,6 +425,7 @@ static const struct v4l2_file_operations hantro_fops = { static const struct of_device_id of_hantro_match[] = { #ifdef CONFIG_VIDEO_HANTRO_ROCKCHIP { .compatible = "rockchip,rk3399-vpu", .data = &rk3399_vpu_variant, }, + { .compatible = "rockchip,rk3328-vpu", .data = &rk3328_vpu_variant, }, { .compatible = "rockchip,rk3288-vpu", .data = &rk3288_vpu_variant, }, #endif { /* sentinel */ } diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw.c b/drivers/staging/media/hantro/rk3399_vpu_hw.c index 5718f8063542..f8400e49bc50 100644 --- a/drivers/staging/media/hantro/rk3399_vpu_hw.c +++ b/drivers/staging/media/hantro/rk3399_vpu_hw.c @@ -184,3 +184,20 @@ const struct hantro_variant rk3399_vpu_variant = { .clk_names = rk3399_clk_names, .num_clocks = ARRAY_SIZE(rk3399_clk_names) }; + +static const struct hantro_irq rk3328_irqs[] = { + { "vdpu", rk3399_vdpu_irq }, +}; + +const struct hantro_variant rk3328_vpu_variant = { + .dec_offset = 0x400, + .dec_fmts = rk3399_vpu_dec_fmts, + .num_dec_fmts = ARRAY_SIZE(rk3399_vpu_dec_fmts), + .codec = HANTRO_MPEG2_DECODER, + .codec_ops = rk3399_vpu_codec_ops, + .irqs = rk3328_irqs, + .num_irqs = ARRAY_SIZE(rk3328_irqs), + .init = rk3399_vpu_hw_init, + .clk_names = rk3399_clk_names, + .num_clocks = ARRAY_SIZE(rk3399_clk_names), +}; -- cgit v1.2.3-59-g8ed1b From 02c25c003405776084d440c30041a33836b74710 Mon Sep 17 00:00:00 2001 From: Steve Longerbeam Date: Wed, 26 Jun 2019 14:52:25 -0400 Subject: media: staging/imx: Fix NULL deref in find_pipeline_entity() Fix a cut&paste error in find_pipeline_entity(). The start entity must be passed to media_entity_to_video_device() in find_pipeline_entity(), not pad->entity. The pad is only put to use later, after determining the start entity is not the entity being searched for. Fixes: 3ef46bc97ca2 ("media: staging/imx: Improve pipeline searching") Reported-by: Colin Ian King Signed-off-by: Steve Longerbeam Reviewed-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/imx/imx-media-utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/imx/imx-media-utils.c b/drivers/staging/media/imx/imx-media-utils.c index 9088c4b720a3..4cc6a7462ae2 100644 --- a/drivers/staging/media/imx/imx-media-utils.c +++ b/drivers/staging/media/imx/imx-media-utils.c @@ -841,7 +841,7 @@ find_pipeline_entity(struct media_entity *start, u32 grp_id, if (sd->grp_id & grp_id) return &sd->entity; } else if (buftype && is_media_entity_v4l2_video_device(start)) { - vfd = media_entity_to_video_device(pad->entity); + vfd = media_entity_to_video_device(start); if (buftype == vfd->queue->type) return &vfd->entity; } -- cgit v1.2.3-59-g8ed1b From 322b169476aaeeb96515d69baaee330e47ac10a0 Mon Sep 17 00:00:00 2001 From: Hariprasad Kelam Date: Sat, 29 Jun 2019 15:31:27 -0400 Subject: media: staging/media/davinci_vpfe: Add null check post kmalloc Add NULL check post memory operations Signed-off-by: Hariprasad Kelam Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/davinci_vpfe/dm365_ipipe.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/staging') diff --git a/drivers/staging/media/davinci_vpfe/dm365_ipipe.c b/drivers/staging/media/davinci_vpfe/dm365_ipipe.c index 52397ad0e3e2..5d8ba357906b 100644 --- a/drivers/staging/media/davinci_vpfe/dm365_ipipe.c +++ b/drivers/staging/media/davinci_vpfe/dm365_ipipe.c @@ -1311,6 +1311,11 @@ static int ipipe_g_config(struct v4l2_subdev *sd, struct vpfe_ipipe_config *cfg) to = *(void **)((void *)cfg + module_if->config_offset); params = kmalloc(sizeof(*params), GFP_KERNEL); + if (!params) { + rval = -ENOMEM; + goto error; + } + from = (void *)params + module_if->param_offset; size = module_if->param_size; -- cgit v1.2.3-59-g8ed1b From 9e037bdf743cc081858423ad4123824e846b2358 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 10 Jul 2019 01:04:24 -0400 Subject: media: staging: media: cedrus: Fix misuse of GENMASK macro Arguments are supposed to be ordered high then low. Signed-off-by: Joe Perches Acked-by: Paul Kocialkowski Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/sunxi/cedrus/cedrus_regs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_regs.h b/drivers/staging/media/sunxi/cedrus/cedrus_regs.h index 3e9931416e45..ddd29788d685 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_regs.h +++ b/drivers/staging/media/sunxi/cedrus/cedrus_regs.h @@ -110,7 +110,7 @@ #define VE_DEC_MPEG_MBADDR (VE_ENGINE_DEC_MPEG + 0x10) #define VE_DEC_MPEG_MBADDR_X(w) (((w) << 8) & GENMASK(15, 8)) -#define VE_DEC_MPEG_MBADDR_Y(h) (((h) << 0) & GENMASK(0, 7)) +#define VE_DEC_MPEG_MBADDR_Y(h) (((h) << 0) & GENMASK(7, 0)) #define VE_DEC_MPEG_CTRL (VE_ENGINE_DEC_MPEG + 0x14) -- cgit v1.2.3-59-g8ed1b From 757c2bf597a8e9f859f8efceda9c5108607fd98d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 25 Jul 2019 02:31:53 -0400 Subject: media: staging/media/bcm2048: remove driver This driver has seen no substantial effort to move it out of staging for 6 years. And after asking around nobody stepped up to do the remaining work. So remove it. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/Kconfig | 2 - drivers/staging/media/Makefile | 1 - drivers/staging/media/bcm2048/Kconfig | 14 - drivers/staging/media/bcm2048/Makefile | 2 - drivers/staging/media/bcm2048/TODO | 24 - drivers/staging/media/bcm2048/radio-bcm2048.c | 2689 ------------------------- drivers/staging/media/bcm2048/radio-bcm2048.h | 26 - 7 files changed, 2758 deletions(-) delete mode 100644 drivers/staging/media/bcm2048/Kconfig delete mode 100644 drivers/staging/media/bcm2048/Makefile delete mode 100644 drivers/staging/media/bcm2048/TODO delete mode 100644 drivers/staging/media/bcm2048/radio-bcm2048.c delete mode 100644 drivers/staging/media/bcm2048/radio-bcm2048.h (limited to 'drivers/staging') diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig index 534d85d6c5e3..45075f977f1b 100644 --- a/drivers/staging/media/Kconfig +++ b/drivers/staging/media/Kconfig @@ -22,8 +22,6 @@ if STAGING_MEDIA && MEDIA_SUPPORT # Please keep them in alphabetic order source "drivers/staging/media/allegro-dvt/Kconfig" -source "drivers/staging/media/bcm2048/Kconfig" - source "drivers/staging/media/davinci_vpfe/Kconfig" source "drivers/staging/media/hantro/Kconfig" diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile index c486298194da..c19cfed0b059 100644 --- a/drivers/staging/media/Makefile +++ b/drivers/staging/media/Makefile @@ -1,6 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_VIDEO_ALLEGRO_DVT) += allegro-dvt/ -obj-$(CONFIG_I2C_BCM2048) += bcm2048/ obj-$(CONFIG_VIDEO_IMX_MEDIA) += imx/ obj-$(CONFIG_VIDEO_DM365_VPFE) += davinci_vpfe/ obj-$(CONFIG_VIDEO_MESON_VDEC) += meson/vdec/ diff --git a/drivers/staging/media/bcm2048/Kconfig b/drivers/staging/media/bcm2048/Kconfig deleted file mode 100644 index ab2d50cac140..000000000000 --- a/drivers/staging/media/bcm2048/Kconfig +++ /dev/null @@ -1,14 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Multimedia Video device configuration -# - -config I2C_BCM2048 - tristate "Broadcom BCM2048 FM Radio Receiver support" - depends on I2C && VIDEO_V4L2 && RADIO_ADAPTERS - help - Say Y here if you want support to BCM2048 FM Radio Receiver. - This device driver supports only i2c bus. - - To compile this driver as a module, choose M here: the - module will be called radio-bcm2048. diff --git a/drivers/staging/media/bcm2048/Makefile b/drivers/staging/media/bcm2048/Makefile deleted file mode 100644 index f42056848dc6..000000000000 --- a/drivers/staging/media/bcm2048/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_I2C_BCM2048) += radio-bcm2048.o diff --git a/drivers/staging/media/bcm2048/TODO b/drivers/staging/media/bcm2048/TODO deleted file mode 100644 index 6bee2a2dad68..000000000000 --- a/drivers/staging/media/bcm2048/TODO +++ /dev/null @@ -1,24 +0,0 @@ -TODO: - -From the initial code review: - -The main thing you need to do is to implement all the controls using the -control framework (see Documentation/media/kapi/v4l2-controls.rst). -Most drivers are by now converted to the control framework, so you will -find many examples of how to do this in drivers/media/radio. - -The sysfs stuff should be replaced by controls as well. A lot of the RDS -support is now available as controls (although there may well be some -missing features, but that is easy enough to add). Since the RDS data is -actually read() from the device I am not sure whether the RDS -properties/controls should be there at all. - -Correct Coding Style, as this driver also violates several Style -rules, and do evil tricks, like returning from a function inside a -macro. - -Finally this driver should probably be split up into two parts: one -v4l2_subdev-based core driver and one platform driver. See e.g. -radio-si4713/si4713-i2c.c as a good example. But I would wait with that -until the rest of the driver is cleaned up. Then I have a better idea of -whether this is necessary or not. diff --git a/drivers/staging/media/bcm2048/radio-bcm2048.c b/drivers/staging/media/bcm2048/radio-bcm2048.c deleted file mode 100644 index 2c60a1fb6350..000000000000 --- a/drivers/staging/media/bcm2048/radio-bcm2048.c +++ /dev/null @@ -1,2689 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * drivers/staging/media/radio-bcm2048.c - * - * Driver for I2C Broadcom BCM2048 FM Radio Receiver: - * - * Copyright (C) Nokia Corporation - * Contact: Eero Nurkkala - * - * Copyright (C) Nils Faerber - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - */ - -/* - * History: - * Eero Nurkkala - * Version 0.0.1 - * - Initial implementation - * 2010-02-21 Nils Faerber - * Version 0.0.2 - * - Add support for interrupt driven rds data reading - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "radio-bcm2048.h" - -/* driver definitions */ -#define BCM2048_DRIVER_AUTHOR "Eero Nurkkala " -#define BCM2048_DRIVER_NAME BCM2048_NAME -#define BCM2048_DRIVER_CARD "Broadcom bcm2048 FM Radio Receiver" -#define BCM2048_DRIVER_DESC "I2C driver for BCM2048 FM Radio Receiver" - -/* I2C Control Registers */ -#define BCM2048_I2C_FM_RDS_SYSTEM 0x00 -#define BCM2048_I2C_FM_CTRL 0x01 -#define BCM2048_I2C_RDS_CTRL0 0x02 -#define BCM2048_I2C_RDS_CTRL1 0x03 -#define BCM2048_I2C_FM_AUDIO_PAUSE 0x04 -#define BCM2048_I2C_FM_AUDIO_CTRL0 0x05 -#define BCM2048_I2C_FM_AUDIO_CTRL1 0x06 -#define BCM2048_I2C_FM_SEARCH_CTRL0 0x07 -#define BCM2048_I2C_FM_SEARCH_CTRL1 0x08 -#define BCM2048_I2C_FM_SEARCH_TUNE_MODE 0x09 -#define BCM2048_I2C_FM_FREQ0 0x0a -#define BCM2048_I2C_FM_FREQ1 0x0b -#define BCM2048_I2C_FM_AF_FREQ0 0x0c -#define BCM2048_I2C_FM_AF_FREQ1 0x0d -#define BCM2048_I2C_FM_CARRIER 0x0e -#define BCM2048_I2C_FM_RSSI 0x0f -#define BCM2048_I2C_FM_RDS_MASK0 0x10 -#define BCM2048_I2C_FM_RDS_MASK1 0x11 -#define BCM2048_I2C_FM_RDS_FLAG0 0x12 -#define BCM2048_I2C_FM_RDS_FLAG1 0x13 -#define BCM2048_I2C_RDS_WLINE 0x14 -#define BCM2048_I2C_RDS_BLKB_MATCH0 0x16 -#define BCM2048_I2C_RDS_BLKB_MATCH1 0x17 -#define BCM2048_I2C_RDS_BLKB_MASK0 0x18 -#define BCM2048_I2C_RDS_BLKB_MASK1 0x19 -#define BCM2048_I2C_RDS_PI_MATCH0 0x1a -#define BCM2048_I2C_RDS_PI_MATCH1 0x1b -#define BCM2048_I2C_RDS_PI_MASK0 0x1c -#define BCM2048_I2C_RDS_PI_MASK1 0x1d -#define BCM2048_I2C_SPARE1 0x20 -#define BCM2048_I2C_SPARE2 0x21 -#define BCM2048_I2C_FM_RDS_REV 0x28 -#define BCM2048_I2C_SLAVE_CONFIGURATION 0x29 -#define BCM2048_I2C_RDS_DATA 0x80 -#define BCM2048_I2C_FM_BEST_TUNE_MODE 0x90 - -/* BCM2048_I2C_FM_RDS_SYSTEM */ -#define BCM2048_FM_ON 0x01 -#define BCM2048_RDS_ON 0x02 - -/* BCM2048_I2C_FM_CTRL */ -#define BCM2048_BAND_SELECT 0x01 -#define BCM2048_STEREO_MONO_AUTO_SELECT 0x02 -#define BCM2048_STEREO_MONO_MANUAL_SELECT 0x04 -#define BCM2048_STEREO_MONO_BLEND_SWITCH 0x08 -#define BCM2048_HI_LO_INJECTION 0x10 - -/* BCM2048_I2C_RDS_CTRL0 */ -#define BCM2048_RBDS_RDS_SELECT 0x01 -#define BCM2048_FLUSH_FIFO 0x02 - -/* BCM2048_I2C_FM_AUDIO_PAUSE */ -#define BCM2048_AUDIO_PAUSE_RSSI_TRESH 0x0f -#define BCM2048_AUDIO_PAUSE_DURATION 0xf0 - -/* BCM2048_I2C_FM_AUDIO_CTRL0 */ -#define BCM2048_RF_MUTE 0x01 -#define BCM2048_MANUAL_MUTE 0x02 -#define BCM2048_DAC_OUTPUT_LEFT 0x04 -#define BCM2048_DAC_OUTPUT_RIGHT 0x08 -#define BCM2048_AUDIO_ROUTE_DAC 0x10 -#define BCM2048_AUDIO_ROUTE_I2S 0x20 -#define BCM2048_DE_EMPHASIS_SELECT 0x40 -#define BCM2048_AUDIO_BANDWIDTH_SELECT 0x80 - -/* BCM2048_I2C_FM_SEARCH_CTRL0 */ -#define BCM2048_SEARCH_RSSI_THRESHOLD 0x7f -#define BCM2048_SEARCH_DIRECTION 0x80 - -/* BCM2048_I2C_FM_SEARCH_TUNE_MODE */ -#define BCM2048_FM_AUTO_SEARCH 0x03 - -/* BCM2048_I2C_FM_RSSI */ -#define BCM2048_RSSI_VALUE 0xff - -/* BCM2048_I2C_FM_RDS_MASK0 */ -/* BCM2048_I2C_FM_RDS_MASK1 */ -#define BCM2048_FM_FLAG_SEARCH_TUNE_FINISHED 0x01 -#define BCM2048_FM_FLAG_SEARCH_TUNE_FAIL 0x02 -#define BCM2048_FM_FLAG_RSSI_LOW 0x04 -#define BCM2048_FM_FLAG_CARRIER_ERROR_HIGH 0x08 -#define BCM2048_FM_FLAG_AUDIO_PAUSE_INDICATION 0x10 -#define BCM2048_FLAG_STEREO_DETECTED 0x20 -#define BCM2048_FLAG_STEREO_ACTIVE 0x40 - -/* BCM2048_I2C_RDS_DATA */ -#define BCM2048_SLAVE_ADDRESS 0x3f -#define BCM2048_SLAVE_ENABLE 0x80 - -/* BCM2048_I2C_FM_BEST_TUNE_MODE */ -#define BCM2048_BEST_TUNE_MODE 0x80 - -#define BCM2048_FM_FLAG_SEARCH_TUNE_FINISHED 0x01 -#define BCM2048_FM_FLAG_SEARCH_TUNE_FAIL 0x02 -#define BCM2048_FM_FLAG_RSSI_LOW 0x04 -#define BCM2048_FM_FLAG_CARRIER_ERROR_HIGH 0x08 -#define BCM2048_FM_FLAG_AUDIO_PAUSE_INDICATION 0x10 -#define BCM2048_FLAG_STEREO_DETECTED 0x20 -#define BCM2048_FLAG_STEREO_ACTIVE 0x40 - -#define BCM2048_RDS_FLAG_FIFO_WLINE 0x02 -#define BCM2048_RDS_FLAG_B_BLOCK_MATCH 0x08 -#define BCM2048_RDS_FLAG_SYNC_LOST 0x10 -#define BCM2048_RDS_FLAG_PI_MATCH 0x20 - -#define BCM2048_RDS_MARK_END_BYTE0 0x7C -#define BCM2048_RDS_MARK_END_BYTEN 0xFF - -#define BCM2048_FM_FLAGS_ALL (FM_FLAG_SEARCH_TUNE_FINISHED | \ - FM_FLAG_SEARCH_TUNE_FAIL | \ - FM_FLAG_RSSI_LOW | \ - FM_FLAG_CARRIER_ERROR_HIGH | \ - FM_FLAG_AUDIO_PAUSE_INDICATION | \ - FLAG_STEREO_DETECTED | FLAG_STEREO_ACTIVE) - -#define BCM2048_RDS_FLAGS_ALL (RDS_FLAG_FIFO_WLINE | \ - RDS_FLAG_B_BLOCK_MATCH | \ - RDS_FLAG_SYNC_LOST | RDS_FLAG_PI_MATCH) - -#define BCM2048_DEFAULT_TIMEOUT 1500 -#define BCM2048_AUTO_SEARCH_TIMEOUT 3000 - -#define BCM2048_FREQDEV_UNIT 10000 -#define BCM2048_FREQV4L2_MULTI 625 -#define dev_to_v4l2(f) (((f) * BCM2048_FREQDEV_UNIT) / BCM2048_FREQV4L2_MULTI) -#define v4l2_to_dev(f) (((f) * BCM2048_FREQV4L2_MULTI) / BCM2048_FREQDEV_UNIT) - -#define msb(x) ((u8)((u16)(x) >> 8)) -#define lsb(x) ((u8)((u16)(x) & 0x00FF)) -#define compose_u16(msb, lsb) (((u16)(msb) << 8) | (lsb)) - -#define BCM2048_DEFAULT_POWERING_DELAY 20 -#define BCM2048_DEFAULT_REGION 0x02 -#define BCM2048_DEFAULT_MUTE 0x01 -#define BCM2048_DEFAULT_RSSI_THRESHOLD 0x64 -#define BCM2048_DEFAULT_RDS_WLINE 0x7E - -#define BCM2048_FM_SEARCH_INACTIVE 0x00 -#define BCM2048_FM_PRE_SET_MODE 0x01 -#define BCM2048_FM_AUTO_SEARCH_MODE 0x02 -#define BCM2048_FM_AF_JUMP_MODE 0x03 - -#define BCM2048_FREQUENCY_BASE 64000 - -#define BCM2048_POWER_ON 0x01 -#define BCM2048_POWER_OFF 0x00 - -#define BCM2048_ITEM_ENABLED 0x01 -#define BCM2048_SEARCH_DIRECTION_UP 0x01 - -#define BCM2048_DE_EMPHASIS_75us 75 -#define BCM2048_DE_EMPHASIS_50us 50 - -#define BCM2048_SCAN_FAIL 0x00 -#define BCM2048_SCAN_OK 0x01 - -#define BCM2048_FREQ_ERROR_FLOOR -20 -#define BCM2048_FREQ_ERROR_ROOF 20 - -/* -60 dB is reported as full signal strength */ -#define BCM2048_RSSI_LEVEL_BASE -60 -#define BCM2048_RSSI_LEVEL_ROOF -100 -#define BCM2048_RSSI_LEVEL_ROOF_NEG 100 -#define BCM2048_SIGNAL_MULTIPLIER (0xFFFF / \ - (BCM2048_RSSI_LEVEL_ROOF_NEG + \ - BCM2048_RSSI_LEVEL_BASE)) - -#define BCM2048_RDS_FIFO_DUPLE_SIZE 0x03 -#define BCM2048_RDS_CRC_MASK 0x0F -#define BCM2048_RDS_CRC_NONE 0x00 -#define BCM2048_RDS_CRC_MAX_2BITS 0x04 -#define BCM2048_RDS_CRC_LEAST_2BITS 0x08 -#define BCM2048_RDS_CRC_UNRECOVARABLE 0x0C - -#define BCM2048_RDS_BLOCK_MASK 0xF0 -#define BCM2048_RDS_BLOCK_A 0x00 -#define BCM2048_RDS_BLOCK_B 0x10 -#define BCM2048_RDS_BLOCK_C 0x20 -#define BCM2048_RDS_BLOCK_D 0x30 -#define BCM2048_RDS_BLOCK_C_SCORED 0x40 -#define BCM2048_RDS_BLOCK_E 0x60 - -#define BCM2048_RDS_RT 0x20 -#define BCM2048_RDS_PS 0x00 - -#define BCM2048_RDS_GROUP_AB_MASK 0x08 -#define BCM2048_RDS_GROUP_A 0x00 -#define BCM2048_RDS_GROUP_B 0x08 - -#define BCM2048_RDS_RT_AB_MASK 0x10 -#define BCM2048_RDS_RT_A 0x00 -#define BCM2048_RDS_RT_B 0x10 -#define BCM2048_RDS_RT_INDEX 0x0F - -#define BCM2048_RDS_PS_INDEX 0x03 - -struct rds_info { - u16 rds_pi; -#define BCM2048_MAX_RDS_RT (64 + 1) - u8 rds_rt[BCM2048_MAX_RDS_RT]; - u8 rds_rt_group_b; - u8 rds_rt_ab; -#define BCM2048_MAX_RDS_PS (8 + 1) - u8 rds_ps[BCM2048_MAX_RDS_PS]; - u8 rds_ps_group; - u8 rds_ps_group_cnt; -#define BCM2048_MAX_RDS_RADIO_TEXT 255 - u8 radio_text[BCM2048_MAX_RDS_RADIO_TEXT + 3]; - u8 text_len; -}; - -struct region_info { - u32 bottom_frequency; - u32 top_frequency; - u8 deemphasis; - u8 channel_spacing; - u8 region; -}; - -struct bcm2048_device { - struct i2c_client *client; - struct video_device videodev; - struct work_struct work; - struct completion compl; - struct mutex mutex; - struct bcm2048_platform_data *platform_data; - struct rds_info rds_info; - struct region_info region_info; - u16 frequency; - u8 cache_fm_rds_system; - u8 cache_fm_ctrl; - u8 cache_fm_audio_ctrl0; - u8 cache_fm_search_ctrl0; - u8 power_state; - u8 rds_state; - u8 fifo_size; - u8 scan_state; - u8 mute_state; - - /* for rds data device read */ - wait_queue_head_t read_queue; - unsigned int users; - unsigned char rds_data_available; - unsigned int rd_index; -}; - -static int radio_nr = -1; /* radio device minor (-1 ==> auto assign) */ -module_param(radio_nr, int, 0000); -MODULE_PARM_DESC(radio_nr, - "Minor number for radio device (-1 ==> auto assign)"); - -static const struct region_info region_configs[] = { - /* USA */ - { - .channel_spacing = 20, - .bottom_frequency = 87500, - .top_frequency = 108000, - .deemphasis = 75, - .region = 0, - }, - /* Australia */ - { - .channel_spacing = 20, - .bottom_frequency = 87500, - .top_frequency = 108000, - .deemphasis = 50, - .region = 1, - }, - /* Europe */ - { - .channel_spacing = 10, - .bottom_frequency = 87500, - .top_frequency = 108000, - .deemphasis = 50, - .region = 2, - }, - /* Japan */ - { - .channel_spacing = 10, - .bottom_frequency = 76000, - .top_frequency = 90000, - .deemphasis = 50, - .region = 3, - }, -}; - -/* - * I2C Interface read / write - */ -static int bcm2048_send_command(struct bcm2048_device *bdev, unsigned int reg, - unsigned int value) -{ - struct i2c_client *client = bdev->client; - u8 data[2]; - - if (!bdev->power_state) { - dev_err(&bdev->client->dev, "bcm2048: chip not powered!\n"); - return -EIO; - } - - data[0] = reg & 0xff; - data[1] = value & 0xff; - - if (i2c_master_send(client, data, 2) == 2) - return 0; - - dev_err(&bdev->client->dev, "BCM I2C error!\n"); - dev_err(&bdev->client->dev, "Is Bluetooth up and running?\n"); - return -EIO; -} - -static int bcm2048_recv_command(struct bcm2048_device *bdev, unsigned int reg, - u8 *value) -{ - struct i2c_client *client = bdev->client; - - if (!bdev->power_state) { - dev_err(&bdev->client->dev, "bcm2048: chip not powered!\n"); - return -EIO; - } - - value[0] = i2c_smbus_read_byte_data(client, reg & 0xff); - - return 0; -} - -static int bcm2048_recv_duples(struct bcm2048_device *bdev, unsigned int reg, - u8 *value, u8 duples) -{ - struct i2c_client *client = bdev->client; - struct i2c_adapter *adap = client->adapter; - struct i2c_msg msg[2]; - u8 buf; - - if (!bdev->power_state) { - dev_err(&bdev->client->dev, "bcm2048: chip not powered!\n"); - return -EIO; - } - - buf = reg & 0xff; - - msg[0].addr = client->addr; - msg[0].flags = client->flags & I2C_M_TEN; - msg[0].len = 1; - msg[0].buf = &buf; - - msg[1].addr = client->addr; - msg[1].flags = client->flags & I2C_M_TEN; - msg[1].flags |= I2C_M_RD; - msg[1].len = duples; - msg[1].buf = value; - - return i2c_transfer(adap, msg, 2); -} - -/* - * BCM2048 - I2C register programming helpers - */ -static int bcm2048_set_power_state(struct bcm2048_device *bdev, u8 power) -{ - int err = 0; - - mutex_lock(&bdev->mutex); - - if (power) { - bdev->power_state = BCM2048_POWER_ON; - bdev->cache_fm_rds_system |= BCM2048_FM_ON; - } else { - bdev->cache_fm_rds_system &= ~BCM2048_FM_ON; - } - - /* - * Warning! FM cannot be turned off because then - * the I2C communications get ruined! - * Comment off the "if (power)" when the chip works! - */ - if (power) - err = bcm2048_send_command(bdev, BCM2048_I2C_FM_RDS_SYSTEM, - bdev->cache_fm_rds_system); - msleep(BCM2048_DEFAULT_POWERING_DELAY); - - if (!power) - bdev->power_state = BCM2048_POWER_OFF; - - mutex_unlock(&bdev->mutex); - return err; -} - -static int bcm2048_get_power_state(struct bcm2048_device *bdev) -{ - int err; - u8 value; - - mutex_lock(&bdev->mutex); - - err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_RDS_SYSTEM, &value); - - mutex_unlock(&bdev->mutex); - - if (!err && (value & BCM2048_FM_ON)) - return BCM2048_POWER_ON; - - return err; -} - -static int bcm2048_set_rds_no_lock(struct bcm2048_device *bdev, u8 rds_on) -{ - int err; - u8 flags; - - bdev->cache_fm_rds_system &= ~BCM2048_RDS_ON; - - if (rds_on) { - bdev->cache_fm_rds_system |= BCM2048_RDS_ON; - bdev->rds_state = BCM2048_RDS_ON; - flags = BCM2048_RDS_FLAG_FIFO_WLINE; - err = bcm2048_send_command(bdev, BCM2048_I2C_FM_RDS_MASK1, - flags); - } else { - flags = 0; - bdev->rds_state = 0; - err = bcm2048_send_command(bdev, BCM2048_I2C_FM_RDS_MASK1, - flags); - memset(&bdev->rds_info, 0, sizeof(bdev->rds_info)); - } - if (err) - return err; - - return bcm2048_send_command(bdev, BCM2048_I2C_FM_RDS_SYSTEM, - bdev->cache_fm_rds_system); -} - -static int bcm2048_get_rds_no_lock(struct bcm2048_device *bdev) -{ - int err; - u8 value; - - err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_RDS_SYSTEM, &value); - - if (!err && (value & BCM2048_RDS_ON)) - return BCM2048_ITEM_ENABLED; - - return err; -} - -static int bcm2048_set_rds(struct bcm2048_device *bdev, u8 rds_on) -{ - int err; - - mutex_lock(&bdev->mutex); - - err = bcm2048_set_rds_no_lock(bdev, rds_on); - - mutex_unlock(&bdev->mutex); - return err; -} - -static int bcm2048_get_rds(struct bcm2048_device *bdev) -{ - int err; - - mutex_lock(&bdev->mutex); - - err = bcm2048_get_rds_no_lock(bdev); - - mutex_unlock(&bdev->mutex); - return err; -} - -static int bcm2048_get_rds_pi(struct bcm2048_device *bdev) -{ - return bdev->rds_info.rds_pi; -} - -static int bcm2048_set_fm_automatic_stereo_mono(struct bcm2048_device *bdev, - u8 enabled) -{ - int err; - - mutex_lock(&bdev->mutex); - - bdev->cache_fm_ctrl &= ~BCM2048_STEREO_MONO_AUTO_SELECT; - - if (enabled) - bdev->cache_fm_ctrl |= BCM2048_STEREO_MONO_AUTO_SELECT; - - err = bcm2048_send_command(bdev, BCM2048_I2C_FM_CTRL, - bdev->cache_fm_ctrl); - - mutex_unlock(&bdev->mutex); - return err; -} - -static int bcm2048_set_fm_hi_lo_injection(struct bcm2048_device *bdev, - u8 hi_lo) -{ - int err; - - mutex_lock(&bdev->mutex); - - bdev->cache_fm_ctrl &= ~BCM2048_HI_LO_INJECTION; - - if (hi_lo) - bdev->cache_fm_ctrl |= BCM2048_HI_LO_INJECTION; - - err = bcm2048_send_command(bdev, BCM2048_I2C_FM_CTRL, - bdev->cache_fm_ctrl); - - mutex_unlock(&bdev->mutex); - return err; -} - -static int bcm2048_get_fm_hi_lo_injection(struct bcm2048_device *bdev) -{ - int err; - u8 value; - - mutex_lock(&bdev->mutex); - - err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_CTRL, &value); - - mutex_unlock(&bdev->mutex); - - if (!err && (value & BCM2048_HI_LO_INJECTION)) - return BCM2048_ITEM_ENABLED; - - return err; -} - -static int bcm2048_set_fm_frequency(struct bcm2048_device *bdev, u32 frequency) -{ - int err; - - if (frequency < bdev->region_info.bottom_frequency || - frequency > bdev->region_info.top_frequency) - return -EDOM; - - frequency -= BCM2048_FREQUENCY_BASE; - - mutex_lock(&bdev->mutex); - - err = bcm2048_send_command(bdev, BCM2048_I2C_FM_FREQ0, lsb(frequency)); - err |= bcm2048_send_command(bdev, BCM2048_I2C_FM_FREQ1, - msb(frequency)); - - if (!err) - bdev->frequency = frequency; - - mutex_unlock(&bdev->mutex); - return err; -} - -static int bcm2048_get_fm_frequency(struct bcm2048_device *bdev) -{ - int err; - u8 lsb = 0, msb = 0; - - mutex_lock(&bdev->mutex); - - err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_FREQ0, &lsb); - err |= bcm2048_recv_command(bdev, BCM2048_I2C_FM_FREQ1, &msb); - - mutex_unlock(&bdev->mutex); - - if (err) - return err; - - err = compose_u16(msb, lsb); - err += BCM2048_FREQUENCY_BASE; - - return err; -} - -static int bcm2048_set_fm_af_frequency(struct bcm2048_device *bdev, - u32 frequency) -{ - int err; - - if (frequency < bdev->region_info.bottom_frequency || - frequency > bdev->region_info.top_frequency) - return -EDOM; - - frequency -= BCM2048_FREQUENCY_BASE; - - mutex_lock(&bdev->mutex); - - err = bcm2048_send_command(bdev, BCM2048_I2C_FM_AF_FREQ0, - lsb(frequency)); - err |= bcm2048_send_command(bdev, BCM2048_I2C_FM_AF_FREQ1, - msb(frequency)); - if (!err) - bdev->frequency = frequency; - - mutex_unlock(&bdev->mutex); - return err; -} - -static int bcm2048_get_fm_af_frequency(struct bcm2048_device *bdev) -{ - int err; - u8 lsb = 0, msb = 0; - - mutex_lock(&bdev->mutex); - - err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_AF_FREQ0, &lsb); - err |= bcm2048_recv_command(bdev, BCM2048_I2C_FM_AF_FREQ1, &msb); - - mutex_unlock(&bdev->mutex); - - if (err) - return err; - - err = compose_u16(msb, lsb); - err += BCM2048_FREQUENCY_BASE; - - return err; -} - -static int bcm2048_set_fm_deemphasis(struct bcm2048_device *bdev, int d) -{ - int err; - u8 deemphasis; - - if (d == BCM2048_DE_EMPHASIS_75us) - deemphasis = BCM2048_DE_EMPHASIS_SELECT; - else - deemphasis = 0; - - mutex_lock(&bdev->mutex); - - bdev->cache_fm_audio_ctrl0 &= ~BCM2048_DE_EMPHASIS_SELECT; - bdev->cache_fm_audio_ctrl0 |= deemphasis; - - err = bcm2048_send_command(bdev, BCM2048_I2C_FM_AUDIO_CTRL0, - bdev->cache_fm_audio_ctrl0); - - if (!err) - bdev->region_info.deemphasis = d; - - mutex_unlock(&bdev->mutex); - - return err; -} - -static int bcm2048_get_fm_deemphasis(struct bcm2048_device *bdev) -{ - int err; - u8 value; - - mutex_lock(&bdev->mutex); - - err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_AUDIO_CTRL0, &value); - - mutex_unlock(&bdev->mutex); - - if (!err) { - if (value & BCM2048_DE_EMPHASIS_SELECT) - return BCM2048_DE_EMPHASIS_75us; - - return BCM2048_DE_EMPHASIS_50us; - } - - return err; -} - -static int bcm2048_set_region(struct bcm2048_device *bdev, u8 region) -{ - int err; - u32 new_frequency = 0; - - if (region >= ARRAY_SIZE(region_configs)) - return -EINVAL; - - mutex_lock(&bdev->mutex); - bdev->region_info = region_configs[region]; - - if (region_configs[region].bottom_frequency < 87500) - bdev->cache_fm_ctrl |= BCM2048_BAND_SELECT; - else - bdev->cache_fm_ctrl &= ~BCM2048_BAND_SELECT; - - err = bcm2048_send_command(bdev, BCM2048_I2C_FM_CTRL, - bdev->cache_fm_ctrl); - if (err) { - mutex_unlock(&bdev->mutex); - goto done; - } - mutex_unlock(&bdev->mutex); - - if (bdev->frequency < region_configs[region].bottom_frequency || - bdev->frequency > region_configs[region].top_frequency) - new_frequency = region_configs[region].bottom_frequency; - - if (new_frequency > 0) { - err = bcm2048_set_fm_frequency(bdev, new_frequency); - - if (err) - goto done; - } - - err = bcm2048_set_fm_deemphasis(bdev, - region_configs[region].deemphasis); - -done: - return err; -} - -static int bcm2048_get_region(struct bcm2048_device *bdev) -{ - int err; - - mutex_lock(&bdev->mutex); - err = bdev->region_info.region; - mutex_unlock(&bdev->mutex); - - return err; -} - -static int bcm2048_set_mute(struct bcm2048_device *bdev, u16 mute) -{ - int err; - - mutex_lock(&bdev->mutex); - - bdev->cache_fm_audio_ctrl0 &= ~(BCM2048_RF_MUTE | BCM2048_MANUAL_MUTE); - - if (mute) - bdev->cache_fm_audio_ctrl0 |= (BCM2048_RF_MUTE | - BCM2048_MANUAL_MUTE); - - err = bcm2048_send_command(bdev, BCM2048_I2C_FM_AUDIO_CTRL0, - bdev->cache_fm_audio_ctrl0); - - if (!err) - bdev->mute_state = mute; - - mutex_unlock(&bdev->mutex); - return err; -} - -static int bcm2048_get_mute(struct bcm2048_device *bdev) -{ - int err; - u8 value; - - mutex_lock(&bdev->mutex); - - if (bdev->power_state) { - err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_AUDIO_CTRL0, - &value); - if (!err) - err = value & (BCM2048_RF_MUTE | BCM2048_MANUAL_MUTE); - } else { - err = bdev->mute_state; - } - - mutex_unlock(&bdev->mutex); - return err; -} - -static int bcm2048_set_audio_route(struct bcm2048_device *bdev, u8 route) -{ - int err; - - mutex_lock(&bdev->mutex); - - route &= (BCM2048_AUDIO_ROUTE_DAC | BCM2048_AUDIO_ROUTE_I2S); - bdev->cache_fm_audio_ctrl0 &= ~(BCM2048_AUDIO_ROUTE_DAC | - BCM2048_AUDIO_ROUTE_I2S); - bdev->cache_fm_audio_ctrl0 |= route; - - err = bcm2048_send_command(bdev, BCM2048_I2C_FM_AUDIO_CTRL0, - bdev->cache_fm_audio_ctrl0); - - mutex_unlock(&bdev->mutex); - return err; -} - -static int bcm2048_get_audio_route(struct bcm2048_device *bdev) -{ - int err; - u8 value; - - mutex_lock(&bdev->mutex); - - err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_AUDIO_CTRL0, &value); - - mutex_unlock(&bdev->mutex); - - if (!err) - return value & (BCM2048_AUDIO_ROUTE_DAC | - BCM2048_AUDIO_ROUTE_I2S); - - return err; -} - -static int bcm2048_set_dac_output(struct bcm2048_device *bdev, u8 channels) -{ - int err; - - mutex_lock(&bdev->mutex); - - bdev->cache_fm_audio_ctrl0 &= ~(BCM2048_DAC_OUTPUT_LEFT | - BCM2048_DAC_OUTPUT_RIGHT); - bdev->cache_fm_audio_ctrl0 |= channels; - - err = bcm2048_send_command(bdev, BCM2048_I2C_FM_AUDIO_CTRL0, - bdev->cache_fm_audio_ctrl0); - - mutex_unlock(&bdev->mutex); - return err; -} - -static int bcm2048_get_dac_output(struct bcm2048_device *bdev) -{ - int err; - u8 value; - - mutex_lock(&bdev->mutex); - - err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_AUDIO_CTRL0, &value); - - mutex_unlock(&bdev->mutex); - - if (!err) - return value & (BCM2048_DAC_OUTPUT_LEFT | - BCM2048_DAC_OUTPUT_RIGHT); - - return err; -} - -static int bcm2048_set_fm_search_rssi_threshold(struct bcm2048_device *bdev, - u8 threshold) -{ - int err; - - mutex_lock(&bdev->mutex); - - threshold &= BCM2048_SEARCH_RSSI_THRESHOLD; - bdev->cache_fm_search_ctrl0 &= ~BCM2048_SEARCH_RSSI_THRESHOLD; - bdev->cache_fm_search_ctrl0 |= threshold; - - err = bcm2048_send_command(bdev, BCM2048_I2C_FM_SEARCH_CTRL0, - bdev->cache_fm_search_ctrl0); - - mutex_unlock(&bdev->mutex); - return err; -} - -static int bcm2048_get_fm_search_rssi_threshold(struct bcm2048_device *bdev) -{ - int err; - u8 value; - - mutex_lock(&bdev->mutex); - - err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_SEARCH_CTRL0, &value); - - mutex_unlock(&bdev->mutex); - - if (!err) - return value & BCM2048_SEARCH_RSSI_THRESHOLD; - - return err; -} - -static int bcm2048_set_fm_search_mode_direction(struct bcm2048_device *bdev, - u8 direction) -{ - int err; - - mutex_lock(&bdev->mutex); - - bdev->cache_fm_search_ctrl0 &= ~BCM2048_SEARCH_DIRECTION; - - if (direction) - bdev->cache_fm_search_ctrl0 |= BCM2048_SEARCH_DIRECTION; - - err = bcm2048_send_command(bdev, BCM2048_I2C_FM_SEARCH_CTRL0, - bdev->cache_fm_search_ctrl0); - - mutex_unlock(&bdev->mutex); - return err; -} - -static int bcm2048_get_fm_search_mode_direction(struct bcm2048_device *bdev) -{ - int err; - u8 value; - - mutex_lock(&bdev->mutex); - - err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_SEARCH_CTRL0, &value); - - mutex_unlock(&bdev->mutex); - - if (!err && (value & BCM2048_SEARCH_DIRECTION)) - return BCM2048_SEARCH_DIRECTION_UP; - - return err; -} - -static int bcm2048_set_fm_search_tune_mode(struct bcm2048_device *bdev, - u8 mode) -{ - int err, timeout, restart_rds = 0; - u8 value, flags; - - value = mode & BCM2048_FM_AUTO_SEARCH; - - flags = BCM2048_FM_FLAG_SEARCH_TUNE_FINISHED | - BCM2048_FM_FLAG_SEARCH_TUNE_FAIL; - - mutex_lock(&bdev->mutex); - - /* - * If RDS is enabled, and frequency is changed, RDS quits working. - * Thus, always restart RDS if it's enabled. Moreover, RDS must - * not be enabled while changing the frequency because it can - * provide a race to the mutex from the workqueue handler if RDS - * IRQ occurs while waiting for frequency changed IRQ. - */ - if (bcm2048_get_rds_no_lock(bdev)) { - err = bcm2048_set_rds_no_lock(bdev, 0); - if (err) - goto unlock; - restart_rds = 1; - } - - err = bcm2048_send_command(bdev, BCM2048_I2C_FM_RDS_MASK0, flags); - - if (err) - goto unlock; - - bcm2048_send_command(bdev, BCM2048_I2C_FM_SEARCH_TUNE_MODE, value); - - if (mode != BCM2048_FM_AUTO_SEARCH_MODE) - timeout = BCM2048_DEFAULT_TIMEOUT; - else - timeout = BCM2048_AUTO_SEARCH_TIMEOUT; - - if (!wait_for_completion_timeout(&bdev->compl, - msecs_to_jiffies(timeout))) - dev_err(&bdev->client->dev, "IRQ timeout.\n"); - - if (value) - if (!bdev->scan_state) - err = -EIO; - -unlock: - if (restart_rds) - err |= bcm2048_set_rds_no_lock(bdev, 1); - - mutex_unlock(&bdev->mutex); - - return err; -} - -static int bcm2048_get_fm_search_tune_mode(struct bcm2048_device *bdev) -{ - int err; - u8 value; - - mutex_lock(&bdev->mutex); - - err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_SEARCH_TUNE_MODE, - &value); - - mutex_unlock(&bdev->mutex); - - if (!err) - return value & BCM2048_FM_AUTO_SEARCH; - - return err; -} - -static int bcm2048_set_rds_b_block_mask(struct bcm2048_device *bdev, u16 mask) -{ - int err; - - mutex_lock(&bdev->mutex); - - err = bcm2048_send_command(bdev, BCM2048_I2C_RDS_BLKB_MASK0, - lsb(mask)); - err |= bcm2048_send_command(bdev, BCM2048_I2C_RDS_BLKB_MASK1, - msb(mask)); - - mutex_unlock(&bdev->mutex); - return err; -} - -static int bcm2048_get_rds_b_block_mask(struct bcm2048_device *bdev) -{ - int err; - u8 lsb = 0, msb = 0; - - mutex_lock(&bdev->mutex); - - err = bcm2048_recv_command(bdev, BCM2048_I2C_RDS_BLKB_MASK0, &lsb); - err |= bcm2048_recv_command(bdev, BCM2048_I2C_RDS_BLKB_MASK1, &msb); - - mutex_unlock(&bdev->mutex); - - if (!err) - return compose_u16(msb, lsb); - - return err; -} - -static int bcm2048_set_rds_b_block_match(struct bcm2048_device *bdev, - u16 match) -{ - int err; - - mutex_lock(&bdev->mutex); - - err = bcm2048_send_command(bdev, BCM2048_I2C_RDS_BLKB_MATCH0, - lsb(match)); - err |= bcm2048_send_command(bdev, BCM2048_I2C_RDS_BLKB_MATCH1, - msb(match)); - - mutex_unlock(&bdev->mutex); - return err; -} - -static int bcm2048_get_rds_b_block_match(struct bcm2048_device *bdev) -{ - int err; - u8 lsb = 0, msb = 0; - - mutex_lock(&bdev->mutex); - - err = bcm2048_recv_command(bdev, BCM2048_I2C_RDS_BLKB_MATCH0, &lsb); - err |= bcm2048_recv_command(bdev, BCM2048_I2C_RDS_BLKB_MATCH1, &msb); - - mutex_unlock(&bdev->mutex); - - if (!err) - return compose_u16(msb, lsb); - - return err; -} - -static int bcm2048_set_rds_pi_mask(struct bcm2048_device *bdev, u16 mask) -{ - int err; - - mutex_lock(&bdev->mutex); - - err = bcm2048_send_command(bdev, BCM2048_I2C_RDS_PI_MASK0, lsb(mask)); - err |= bcm2048_send_command(bdev, BCM2048_I2C_RDS_PI_MASK1, msb(mask)); - - mutex_unlock(&bdev->mutex); - return err; -} - -static int bcm2048_get_rds_pi_mask(struct bcm2048_device *bdev) -{ - int err; - u8 lsb = 0, msb = 0; - - mutex_lock(&bdev->mutex); - - err = bcm2048_recv_command(bdev, BCM2048_I2C_RDS_PI_MASK0, &lsb); - err |= bcm2048_recv_command(bdev, BCM2048_I2C_RDS_PI_MASK1, &msb); - - mutex_unlock(&bdev->mutex); - - if (!err) - return compose_u16(msb, lsb); - - return err; -} - -static int bcm2048_set_rds_pi_match(struct bcm2048_device *bdev, u16 match) -{ - int err; - - mutex_lock(&bdev->mutex); - - err = bcm2048_send_command(bdev, BCM2048_I2C_RDS_PI_MATCH0, - lsb(match)); - err |= bcm2048_send_command(bdev, BCM2048_I2C_RDS_PI_MATCH1, - msb(match)); - - mutex_unlock(&bdev->mutex); - return err; -} - -static int bcm2048_get_rds_pi_match(struct bcm2048_device *bdev) -{ - int err; - u8 lsb = 0, msb = 0; - - mutex_lock(&bdev->mutex); - - err = bcm2048_recv_command(bdev, BCM2048_I2C_RDS_PI_MATCH0, &lsb); - err |= bcm2048_recv_command(bdev, BCM2048_I2C_RDS_PI_MATCH1, &msb); - - mutex_unlock(&bdev->mutex); - - if (!err) - return compose_u16(msb, lsb); - - return err; -} - -static int bcm2048_set_fm_rds_mask(struct bcm2048_device *bdev, u16 mask) -{ - int err; - - mutex_lock(&bdev->mutex); - - err = bcm2048_send_command(bdev, BCM2048_I2C_FM_RDS_MASK0, lsb(mask)); - err |= bcm2048_send_command(bdev, BCM2048_I2C_FM_RDS_MASK1, msb(mask)); - - mutex_unlock(&bdev->mutex); - return err; -} - -static int bcm2048_get_fm_rds_mask(struct bcm2048_device *bdev) -{ - int err; - u8 value0 = 0, value1 = 0; - - mutex_lock(&bdev->mutex); - - err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_RDS_MASK0, &value0); - err |= bcm2048_recv_command(bdev, BCM2048_I2C_FM_RDS_MASK1, &value1); - - mutex_unlock(&bdev->mutex); - - if (!err) - return compose_u16(value1, value0); - - return err; -} - -static int bcm2048_get_fm_rds_flags(struct bcm2048_device *bdev) -{ - int err; - u8 value0 = 0, value1 = 0; - - mutex_lock(&bdev->mutex); - - err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_RDS_FLAG0, &value0); - err |= bcm2048_recv_command(bdev, BCM2048_I2C_FM_RDS_FLAG1, &value1); - - mutex_unlock(&bdev->mutex); - - if (!err) - return compose_u16(value1, value0); - - return err; -} - -static int bcm2048_get_region_bottom_frequency(struct bcm2048_device *bdev) -{ - return bdev->region_info.bottom_frequency; -} - -static int bcm2048_get_region_top_frequency(struct bcm2048_device *bdev) -{ - return bdev->region_info.top_frequency; -} - -static int bcm2048_set_fm_best_tune_mode(struct bcm2048_device *bdev, u8 mode) -{ - int err; - u8 value = 0; - - mutex_lock(&bdev->mutex); - - /* Perform read as the manual indicates */ - err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_BEST_TUNE_MODE, - &value); - value &= ~BCM2048_BEST_TUNE_MODE; - - if (mode) - value |= BCM2048_BEST_TUNE_MODE; - err |= bcm2048_send_command(bdev, BCM2048_I2C_FM_BEST_TUNE_MODE, - value); - - mutex_unlock(&bdev->mutex); - return err; -} - -static int bcm2048_get_fm_best_tune_mode(struct bcm2048_device *bdev) -{ - int err; - u8 value; - - mutex_lock(&bdev->mutex); - - err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_BEST_TUNE_MODE, - &value); - - mutex_unlock(&bdev->mutex); - - if (!err && (value & BCM2048_BEST_TUNE_MODE)) - return BCM2048_ITEM_ENABLED; - - return err; -} - -static int bcm2048_get_fm_carrier_error(struct bcm2048_device *bdev) -{ - int err = 0; - s8 value; - - mutex_lock(&bdev->mutex); - err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_CARRIER, &value); - mutex_unlock(&bdev->mutex); - - if (!err) - return value; - - return err; -} - -static int bcm2048_get_fm_rssi(struct bcm2048_device *bdev) -{ - int err; - s8 value; - - mutex_lock(&bdev->mutex); - err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_RSSI, &value); - mutex_unlock(&bdev->mutex); - - if (!err) - return value; - - return err; -} - -static int bcm2048_set_rds_wline(struct bcm2048_device *bdev, u8 wline) -{ - int err; - - mutex_lock(&bdev->mutex); - - err = bcm2048_send_command(bdev, BCM2048_I2C_RDS_WLINE, wline); - - if (!err) - bdev->fifo_size = wline; - - mutex_unlock(&bdev->mutex); - return err; -} - -static int bcm2048_get_rds_wline(struct bcm2048_device *bdev) -{ - int err; - u8 value; - - mutex_lock(&bdev->mutex); - - err = bcm2048_recv_command(bdev, BCM2048_I2C_RDS_WLINE, &value); - - mutex_unlock(&bdev->mutex); - - if (!err) { - bdev->fifo_size = value; - return value; - } - - return err; -} - -static int bcm2048_checkrev(struct bcm2048_device *bdev) -{ - int err; - u8 version; - - mutex_lock(&bdev->mutex); - - err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_RDS_REV, &version); - - mutex_unlock(&bdev->mutex); - - if (!err) { - dev_info(&bdev->client->dev, "BCM2048 Version 0x%x\n", - version); - return version; - } - - return err; -} - -static int bcm2048_get_rds_rt(struct bcm2048_device *bdev, char *data) -{ - int err = 0, i, j = 0, ce = 0, cr = 0; - char data_buffer[BCM2048_MAX_RDS_RT + 1]; - - mutex_lock(&bdev->mutex); - - if (!bdev->rds_info.text_len) { - err = -EINVAL; - goto unlock; - } - - for (i = 0; i < BCM2048_MAX_RDS_RT; i++) { - if (bdev->rds_info.rds_rt[i]) { - ce = i; - /* Skip the carriage return */ - if (bdev->rds_info.rds_rt[i] != 0x0d) { - data_buffer[j++] = bdev->rds_info.rds_rt[i]; - } else { - cr = i; - break; - } - } - } - - if (j <= BCM2048_MAX_RDS_RT) - data_buffer[j] = 0; - - for (i = 0; i < BCM2048_MAX_RDS_RT; i++) { - if (!bdev->rds_info.rds_rt[i]) { - if (cr && (i < cr)) { - err = -EBUSY; - goto unlock; - } - if (i < ce) { - if (cr && (i >= cr)) - break; - err = -EBUSY; - goto unlock; - } - } - } - - memcpy(data, data_buffer, sizeof(data_buffer)); - -unlock: - mutex_unlock(&bdev->mutex); - return err; -} - -static int bcm2048_get_rds_ps(struct bcm2048_device *bdev, char *data) -{ - int err = 0, i, j = 0; - char data_buffer[BCM2048_MAX_RDS_PS + 1]; - - mutex_lock(&bdev->mutex); - - if (!bdev->rds_info.text_len) { - err = -EINVAL; - goto unlock; - } - - for (i = 0; i < BCM2048_MAX_RDS_PS; i++) { - if (bdev->rds_info.rds_ps[i]) { - data_buffer[j++] = bdev->rds_info.rds_ps[i]; - } else { - if (i < (BCM2048_MAX_RDS_PS - 1)) { - err = -EBUSY; - goto unlock; - } - } - } - - if (j <= BCM2048_MAX_RDS_PS) - data_buffer[j] = 0; - - memcpy(data, data_buffer, sizeof(data_buffer)); - -unlock: - mutex_unlock(&bdev->mutex); - return err; -} - -static void bcm2048_parse_rds_pi(struct bcm2048_device *bdev) -{ - int i, cnt = 0; - u16 pi; - - for (i = 0; i < bdev->fifo_size; i += BCM2048_RDS_FIFO_DUPLE_SIZE) { - /* Block A match, only data without crc errors taken */ - if (bdev->rds_info.radio_text[i] == BCM2048_RDS_BLOCK_A) { - pi = (bdev->rds_info.radio_text[i + 1] << 8) + - bdev->rds_info.radio_text[i + 2]; - - if (!bdev->rds_info.rds_pi) { - bdev->rds_info.rds_pi = pi; - return; - } - if (pi != bdev->rds_info.rds_pi) { - cnt++; - if (cnt > 3) { - bdev->rds_info.rds_pi = pi; - cnt = 0; - } - } else { - cnt = 0; - } - } - } -} - -static int bcm2048_rds_block_crc(struct bcm2048_device *bdev, int i) -{ - return bdev->rds_info.radio_text[i] & BCM2048_RDS_CRC_MASK; -} - -static void bcm2048_parse_rds_rt_block(struct bcm2048_device *bdev, int i, - int index, int crc) -{ - /* Good data will overwrite poor data */ - if (crc) { - if (!bdev->rds_info.rds_rt[index]) - bdev->rds_info.rds_rt[index] = - bdev->rds_info.radio_text[i + 1]; - if (!bdev->rds_info.rds_rt[index + 1]) - bdev->rds_info.rds_rt[index + 1] = - bdev->rds_info.radio_text[i + 2]; - } else { - bdev->rds_info.rds_rt[index] = - bdev->rds_info.radio_text[i + 1]; - bdev->rds_info.rds_rt[index + 1] = - bdev->rds_info.radio_text[i + 2]; - } -} - -static int bcm2048_parse_rt_match_b(struct bcm2048_device *bdev, int i) -{ - int crc, rt_id, rt_group_b, rt_ab, index = 0; - - crc = bcm2048_rds_block_crc(bdev, i); - - if (crc == BCM2048_RDS_CRC_UNRECOVARABLE) - return -EIO; - - if ((bdev->rds_info.radio_text[i] & BCM2048_RDS_BLOCK_MASK) == - BCM2048_RDS_BLOCK_B) { - rt_id = bdev->rds_info.radio_text[i + 1] & - BCM2048_RDS_BLOCK_MASK; - rt_group_b = bdev->rds_info.radio_text[i + 1] & - BCM2048_RDS_GROUP_AB_MASK; - rt_ab = bdev->rds_info.radio_text[i + 2] & - BCM2048_RDS_RT_AB_MASK; - - if (rt_group_b != bdev->rds_info.rds_rt_group_b) { - memset(bdev->rds_info.rds_rt, 0, - sizeof(bdev->rds_info.rds_rt)); - bdev->rds_info.rds_rt_group_b = rt_group_b; - } - - if (rt_id == BCM2048_RDS_RT) { - /* A to B or (vice versa), means: clear screen */ - if (rt_ab != bdev->rds_info.rds_rt_ab) { - memset(bdev->rds_info.rds_rt, 0, - sizeof(bdev->rds_info.rds_rt)); - bdev->rds_info.rds_rt_ab = rt_ab; - } - - index = bdev->rds_info.radio_text[i + 2] & - BCM2048_RDS_RT_INDEX; - - if (bdev->rds_info.rds_rt_group_b) - index <<= 1; - else - index <<= 2; - - return index; - } - } - - return -EIO; -} - -static int bcm2048_parse_rt_match_c(struct bcm2048_device *bdev, int i, - int index) -{ - int crc; - - crc = bcm2048_rds_block_crc(bdev, i); - - if (crc == BCM2048_RDS_CRC_UNRECOVARABLE) - return 0; - - if ((index + 2) >= BCM2048_MAX_RDS_RT) { - dev_err(&bdev->client->dev, - "Incorrect index = %d\n", index); - return 0; - } - - if ((bdev->rds_info.radio_text[i] & BCM2048_RDS_BLOCK_MASK) == - BCM2048_RDS_BLOCK_C) { - if (bdev->rds_info.rds_rt_group_b) - return 1; - bcm2048_parse_rds_rt_block(bdev, i, index, crc); - return 1; - } - - return 0; -} - -static void bcm2048_parse_rt_match_d(struct bcm2048_device *bdev, int i, - int index) -{ - int crc; - - crc = bcm2048_rds_block_crc(bdev, i); - - if (crc == BCM2048_RDS_CRC_UNRECOVARABLE) - return; - - if ((index + 4) >= BCM2048_MAX_RDS_RT) { - dev_err(&bdev->client->dev, - "Incorrect index = %d\n", index); - return; - } - - if ((bdev->rds_info.radio_text[i] & BCM2048_RDS_BLOCK_MASK) == - BCM2048_RDS_BLOCK_D) - bcm2048_parse_rds_rt_block(bdev, i, index + 2, crc); -} - -static void bcm2048_parse_rds_rt(struct bcm2048_device *bdev) -{ - int i, index = 0, crc, match_b = 0, match_c = 0, match_d = 0; - - for (i = 0; i < bdev->fifo_size; i += BCM2048_RDS_FIFO_DUPLE_SIZE) { - if (match_b) { - match_b = 0; - index = bcm2048_parse_rt_match_b(bdev, i); - if (index >= 0 && index <= (BCM2048_MAX_RDS_RT - 5)) - match_c = 1; - continue; - } else if (match_c) { - match_c = 0; - if (bcm2048_parse_rt_match_c(bdev, i, index)) - match_d = 1; - continue; - } else if (match_d) { - match_d = 0; - bcm2048_parse_rt_match_d(bdev, i, index); - continue; - } - - /* Skip erroneous blocks due to messed up A block altogether */ - if ((bdev->rds_info.radio_text[i] & BCM2048_RDS_BLOCK_MASK) == - BCM2048_RDS_BLOCK_A) { - crc = bcm2048_rds_block_crc(bdev, i); - if (crc == BCM2048_RDS_CRC_UNRECOVARABLE) - continue; - /* Synchronize to a good RDS PI */ - if (((bdev->rds_info.radio_text[i + 1] << 8) + - bdev->rds_info.radio_text[i + 2]) == - bdev->rds_info.rds_pi) - match_b = 1; - } - } -} - -static void bcm2048_parse_rds_ps_block(struct bcm2048_device *bdev, int i, - int index, int crc) -{ - /* Good data will overwrite poor data */ - if (crc) { - if (!bdev->rds_info.rds_ps[index]) - bdev->rds_info.rds_ps[index] = - bdev->rds_info.radio_text[i + 1]; - if (!bdev->rds_info.rds_ps[index + 1]) - bdev->rds_info.rds_ps[index + 1] = - bdev->rds_info.radio_text[i + 2]; - } else { - bdev->rds_info.rds_ps[index] = - bdev->rds_info.radio_text[i + 1]; - bdev->rds_info.rds_ps[index + 1] = - bdev->rds_info.radio_text[i + 2]; - } -} - -static int bcm2048_parse_ps_match_c(struct bcm2048_device *bdev, int i, - int index) -{ - int crc; - - crc = bcm2048_rds_block_crc(bdev, i); - - if (crc == BCM2048_RDS_CRC_UNRECOVARABLE) - return 0; - - if ((bdev->rds_info.radio_text[i] & BCM2048_RDS_BLOCK_MASK) == - BCM2048_RDS_BLOCK_C) - return 1; - - return 0; -} - -static void bcm2048_parse_ps_match_d(struct bcm2048_device *bdev, int i, - int index) -{ - int crc; - - crc = bcm2048_rds_block_crc(bdev, i); - - if (crc == BCM2048_RDS_CRC_UNRECOVARABLE) - return; - - if ((bdev->rds_info.radio_text[i] & BCM2048_RDS_BLOCK_MASK) == - BCM2048_RDS_BLOCK_D) - bcm2048_parse_rds_ps_block(bdev, i, index, crc); -} - -static int bcm2048_parse_ps_match_b(struct bcm2048_device *bdev, int i) -{ - int crc, index, ps_id, ps_group; - - crc = bcm2048_rds_block_crc(bdev, i); - - if (crc == BCM2048_RDS_CRC_UNRECOVARABLE) - return -EIO; - - /* Block B Radio PS match */ - if ((bdev->rds_info.radio_text[i] & BCM2048_RDS_BLOCK_MASK) == - BCM2048_RDS_BLOCK_B) { - ps_id = bdev->rds_info.radio_text[i + 1] & - BCM2048_RDS_BLOCK_MASK; - ps_group = bdev->rds_info.radio_text[i + 1] & - BCM2048_RDS_GROUP_AB_MASK; - - /* - * Poor RSSI will lead to RDS data corruption - * So using 3 (same) sequential values to justify major changes - */ - if (ps_group != bdev->rds_info.rds_ps_group) { - if (crc == BCM2048_RDS_CRC_NONE) { - bdev->rds_info.rds_ps_group_cnt++; - if (bdev->rds_info.rds_ps_group_cnt > 2) { - bdev->rds_info.rds_ps_group = ps_group; - bdev->rds_info.rds_ps_group_cnt = 0; - dev_err(&bdev->client->dev, - "RDS PS Group change!\n"); - } else { - return -EIO; - } - } else { - bdev->rds_info.rds_ps_group_cnt = 0; - } - } - - if (ps_id == BCM2048_RDS_PS) { - index = bdev->rds_info.radio_text[i + 2] & - BCM2048_RDS_PS_INDEX; - index <<= 1; - return index; - } - } - - return -EIO; -} - -static void bcm2048_parse_rds_ps(struct bcm2048_device *bdev) -{ - int i, index = 0, crc, match_b = 0, match_c = 0, match_d = 0; - - for (i = 0; i < bdev->fifo_size; i += BCM2048_RDS_FIFO_DUPLE_SIZE) { - if (match_b) { - match_b = 0; - index = bcm2048_parse_ps_match_b(bdev, i); - if (index >= 0 && index < (BCM2048_MAX_RDS_PS - 1)) - match_c = 1; - continue; - } else if (match_c) { - match_c = 0; - if (bcm2048_parse_ps_match_c(bdev, i, index)) - match_d = 1; - continue; - } else if (match_d) { - match_d = 0; - bcm2048_parse_ps_match_d(bdev, i, index); - continue; - } - - /* Skip erroneous blocks due to messed up A block altogether */ - if ((bdev->rds_info.radio_text[i] & BCM2048_RDS_BLOCK_MASK) == - BCM2048_RDS_BLOCK_A) { - crc = bcm2048_rds_block_crc(bdev, i); - if (crc == BCM2048_RDS_CRC_UNRECOVARABLE) - continue; - /* Synchronize to a good RDS PI */ - if (((bdev->rds_info.radio_text[i + 1] << 8) + - bdev->rds_info.radio_text[i + 2]) == - bdev->rds_info.rds_pi) - match_b = 1; - } - } -} - -static void bcm2048_rds_fifo_receive(struct bcm2048_device *bdev) -{ - int err; - - mutex_lock(&bdev->mutex); - - err = bcm2048_recv_duples(bdev, BCM2048_I2C_RDS_DATA, - bdev->rds_info.radio_text, bdev->fifo_size); - if (err != 2) { - dev_err(&bdev->client->dev, "RDS Read problem\n"); - mutex_unlock(&bdev->mutex); - return; - } - - bdev->rds_info.text_len = bdev->fifo_size; - - bcm2048_parse_rds_pi(bdev); - bcm2048_parse_rds_rt(bdev); - bcm2048_parse_rds_ps(bdev); - - mutex_unlock(&bdev->mutex); - - wake_up_interruptible(&bdev->read_queue); -} - -static int bcm2048_get_rds_data(struct bcm2048_device *bdev, char *data) -{ - int err = 0, i, p = 0; - char *data_buffer; - - mutex_lock(&bdev->mutex); - - if (!bdev->rds_info.text_len) { - err = -EINVAL; - goto unlock; - } - - data_buffer = kcalloc(BCM2048_MAX_RDS_RADIO_TEXT, 5, GFP_KERNEL); - if (!data_buffer) { - err = -ENOMEM; - goto unlock; - } - - for (i = 0; i < bdev->rds_info.text_len; i++) { - p += sprintf(data_buffer + p, "%x ", - bdev->rds_info.radio_text[i]); - } - - memcpy(data, data_buffer, p); - kfree(data_buffer); - -unlock: - mutex_unlock(&bdev->mutex); - return err; -} - -/* - * BCM2048 default initialization sequence - */ -static int bcm2048_init(struct bcm2048_device *bdev) -{ - int err; - - err = bcm2048_set_power_state(bdev, BCM2048_POWER_ON); - if (err < 0) - goto exit; - - err = bcm2048_set_audio_route(bdev, BCM2048_AUDIO_ROUTE_DAC); - if (err < 0) - goto exit; - - err = bcm2048_set_dac_output(bdev, BCM2048_DAC_OUTPUT_LEFT | - BCM2048_DAC_OUTPUT_RIGHT); - -exit: - return err; -} - -/* - * BCM2048 default deinitialization sequence - */ -static int bcm2048_deinit(struct bcm2048_device *bdev) -{ - int err; - - err = bcm2048_set_audio_route(bdev, 0); - if (err < 0) - return err; - - err = bcm2048_set_dac_output(bdev, 0); - if (err < 0) - return err; - - return bcm2048_set_power_state(bdev, BCM2048_POWER_OFF); -} - -/* - * BCM2048 probe sequence - */ -static int bcm2048_probe(struct bcm2048_device *bdev) -{ - int err; - - err = bcm2048_set_power_state(bdev, BCM2048_POWER_ON); - if (err < 0) - goto unlock; - - err = bcm2048_checkrev(bdev); - if (err < 0) - goto unlock; - - err = bcm2048_set_mute(bdev, BCM2048_DEFAULT_MUTE); - if (err < 0) - goto unlock; - - err = bcm2048_set_region(bdev, BCM2048_DEFAULT_REGION); - if (err < 0) - goto unlock; - - err = bcm2048_set_fm_search_rssi_threshold(bdev, - BCM2048_DEFAULT_RSSI_THRESHOLD); - if (err < 0) - goto unlock; - - err = bcm2048_set_fm_automatic_stereo_mono(bdev, BCM2048_ITEM_ENABLED); - if (err < 0) - goto unlock; - - err = bcm2048_get_rds_wline(bdev); - if (err < BCM2048_DEFAULT_RDS_WLINE) - err = bcm2048_set_rds_wline(bdev, BCM2048_DEFAULT_RDS_WLINE); - if (err < 0) - goto unlock; - - err = bcm2048_set_power_state(bdev, BCM2048_POWER_OFF); - - init_waitqueue_head(&bdev->read_queue); - bdev->rds_data_available = 0; - bdev->rd_index = 0; - bdev->users = 0; - -unlock: - return err; -} - -/* - * BCM2048 workqueue handler - */ -static void bcm2048_work(struct work_struct *work) -{ - struct bcm2048_device *bdev; - u8 flag_lsb = 0, flag_msb = 0, flags; - - bdev = container_of(work, struct bcm2048_device, work); - bcm2048_recv_command(bdev, BCM2048_I2C_FM_RDS_FLAG0, &flag_lsb); - bcm2048_recv_command(bdev, BCM2048_I2C_FM_RDS_FLAG1, &flag_msb); - - if (flag_lsb & (BCM2048_FM_FLAG_SEARCH_TUNE_FINISHED | - BCM2048_FM_FLAG_SEARCH_TUNE_FAIL)) { - if (flag_lsb & BCM2048_FM_FLAG_SEARCH_TUNE_FAIL) - bdev->scan_state = BCM2048_SCAN_FAIL; - else - bdev->scan_state = BCM2048_SCAN_OK; - - complete(&bdev->compl); - } - - if (flag_msb & BCM2048_RDS_FLAG_FIFO_WLINE) { - bcm2048_rds_fifo_receive(bdev); - if (bdev->rds_state) { - flags = BCM2048_RDS_FLAG_FIFO_WLINE; - bcm2048_send_command(bdev, BCM2048_I2C_FM_RDS_MASK1, - flags); - } - bdev->rds_data_available = 1; - bdev->rd_index = 0; /* new data, new start */ - } -} - -/* - * BCM2048 interrupt handler - */ -static irqreturn_t bcm2048_handler(int irq, void *dev) -{ - struct bcm2048_device *bdev = dev; - - dev_dbg(&bdev->client->dev, "IRQ called, queuing work\n"); - if (bdev->power_state) - schedule_work(&bdev->work); - - return IRQ_HANDLED; -} - -/* - * BCM2048 sysfs interface definitions - */ -#define property_write(prop, type, mask, check) \ -static ssize_t bcm2048_##prop##_write(struct device *dev, \ - struct device_attribute *attr, \ - const char *buf, \ - size_t count) \ -{ \ - struct bcm2048_device *bdev = dev_get_drvdata(dev); \ - type value; \ - int err; \ - \ - if (!bdev) \ - return -ENODEV; \ - \ - if (sscanf(buf, mask, &value) != 1) \ - return -EINVAL; \ - \ - if (check) \ - return -EDOM; \ - \ - err = bcm2048_set_##prop(bdev, value); \ - \ - return err < 0 ? err : count; \ -} - -#define property_read(prop, mask) \ -static ssize_t bcm2048_##prop##_read(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - struct bcm2048_device *bdev = dev_get_drvdata(dev); \ - int value; \ - \ - if (!bdev) \ - return -ENODEV; \ - \ - value = bcm2048_get_##prop(bdev); \ - \ - if (value >= 0) \ - value = sprintf(buf, mask "\n", value); \ - \ - return value; \ -} - -#define property_signed_read(prop, size, mask) \ -static ssize_t bcm2048_##prop##_read(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - struct bcm2048_device *bdev = dev_get_drvdata(dev); \ - size value; \ - \ - if (!bdev) \ - return -ENODEV; \ - \ - value = bcm2048_get_##prop(bdev); \ - \ - return sprintf(buf, mask "\n", value); \ -} - -#define DEFINE_SYSFS_PROPERTY(prop, prop_type, mask, check) \ -property_write(prop, prop_type, mask, check) \ -property_read(prop, mask) \ - -#define property_str_read(prop, size) \ -static ssize_t bcm2048_##prop##_read(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - struct bcm2048_device *bdev = dev_get_drvdata(dev); \ - int count; \ - u8 *out; \ - \ - if (!bdev) \ - return -ENODEV; \ - \ - out = kzalloc((size) + 1, GFP_KERNEL); \ - if (!out) \ - return -ENOMEM; \ - \ - bcm2048_get_##prop(bdev, out); \ - count = sprintf(buf, "%s\n", out); \ - \ - kfree(out); \ - \ - return count; \ -} - -DEFINE_SYSFS_PROPERTY(power_state, unsigned int, "%u", 0) -DEFINE_SYSFS_PROPERTY(mute, unsigned int, "%u", 0) -DEFINE_SYSFS_PROPERTY(audio_route, unsigned int, "%u", 0) -DEFINE_SYSFS_PROPERTY(dac_output, unsigned int, "%u", 0) - -DEFINE_SYSFS_PROPERTY(fm_hi_lo_injection, unsigned int, "%u", 0) -DEFINE_SYSFS_PROPERTY(fm_frequency, unsigned int, "%u", 0) -DEFINE_SYSFS_PROPERTY(fm_af_frequency, unsigned int, "%u", 0) -DEFINE_SYSFS_PROPERTY(fm_deemphasis, unsigned int, "%u", 0) -DEFINE_SYSFS_PROPERTY(fm_rds_mask, unsigned int, "%u", 0) -DEFINE_SYSFS_PROPERTY(fm_best_tune_mode, unsigned int, "%u", 0) -DEFINE_SYSFS_PROPERTY(fm_search_rssi_threshold, unsigned int, "%u", 0) -DEFINE_SYSFS_PROPERTY(fm_search_mode_direction, unsigned int, "%u", 0) -DEFINE_SYSFS_PROPERTY(fm_search_tune_mode, unsigned int, "%u", value > 3) - -DEFINE_SYSFS_PROPERTY(rds, unsigned int, "%u", 0) -DEFINE_SYSFS_PROPERTY(rds_b_block_mask, unsigned int, "%u", 0) -DEFINE_SYSFS_PROPERTY(rds_b_block_match, unsigned int, "%u", 0) -DEFINE_SYSFS_PROPERTY(rds_pi_mask, unsigned int, "%u", 0) -DEFINE_SYSFS_PROPERTY(rds_pi_match, unsigned int, "%u", 0) -DEFINE_SYSFS_PROPERTY(rds_wline, unsigned int, "%u", 0) -property_read(rds_pi, "%x") -property_str_read(rds_rt, (BCM2048_MAX_RDS_RT + 1)) -property_str_read(rds_ps, (BCM2048_MAX_RDS_PS + 1)) - -property_read(fm_rds_flags, "%u") -property_str_read(rds_data, BCM2048_MAX_RDS_RADIO_TEXT * 5) - -property_read(region_bottom_frequency, "%u") -property_read(region_top_frequency, "%u") -property_signed_read(fm_carrier_error, int, "%d") -property_signed_read(fm_rssi, int, "%d") -DEFINE_SYSFS_PROPERTY(region, unsigned int, "%u", 0) - -static struct device_attribute attrs[] = { - __ATTR(power_state, 0644, bcm2048_power_state_read, - bcm2048_power_state_write), - __ATTR(mute, 0644, bcm2048_mute_read, - bcm2048_mute_write), - __ATTR(audio_route, 0644, bcm2048_audio_route_read, - bcm2048_audio_route_write), - __ATTR(dac_output, 0644, bcm2048_dac_output_read, - bcm2048_dac_output_write), - __ATTR(fm_hi_lo_injection, 0644, - bcm2048_fm_hi_lo_injection_read, - bcm2048_fm_hi_lo_injection_write), - __ATTR(fm_frequency, 0644, bcm2048_fm_frequency_read, - bcm2048_fm_frequency_write), - __ATTR(fm_af_frequency, 0644, - bcm2048_fm_af_frequency_read, - bcm2048_fm_af_frequency_write), - __ATTR(fm_deemphasis, 0644, bcm2048_fm_deemphasis_read, - bcm2048_fm_deemphasis_write), - __ATTR(fm_rds_mask, 0644, bcm2048_fm_rds_mask_read, - bcm2048_fm_rds_mask_write), - __ATTR(fm_best_tune_mode, 0644, - bcm2048_fm_best_tune_mode_read, - bcm2048_fm_best_tune_mode_write), - __ATTR(fm_search_rssi_threshold, 0644, - bcm2048_fm_search_rssi_threshold_read, - bcm2048_fm_search_rssi_threshold_write), - __ATTR(fm_search_mode_direction, 0644, - bcm2048_fm_search_mode_direction_read, - bcm2048_fm_search_mode_direction_write), - __ATTR(fm_search_tune_mode, 0644, - bcm2048_fm_search_tune_mode_read, - bcm2048_fm_search_tune_mode_write), - __ATTR(rds, 0644, bcm2048_rds_read, - bcm2048_rds_write), - __ATTR(rds_b_block_mask, 0644, - bcm2048_rds_b_block_mask_read, - bcm2048_rds_b_block_mask_write), - __ATTR(rds_b_block_match, 0644, - bcm2048_rds_b_block_match_read, - bcm2048_rds_b_block_match_write), - __ATTR(rds_pi_mask, 0644, bcm2048_rds_pi_mask_read, - bcm2048_rds_pi_mask_write), - __ATTR(rds_pi_match, 0644, bcm2048_rds_pi_match_read, - bcm2048_rds_pi_match_write), - __ATTR(rds_wline, 0644, bcm2048_rds_wline_read, - bcm2048_rds_wline_write), - __ATTR(rds_pi, 0444, bcm2048_rds_pi_read, NULL), - __ATTR(rds_rt, 0444, bcm2048_rds_rt_read, NULL), - __ATTR(rds_ps, 0444, bcm2048_rds_ps_read, NULL), - __ATTR(fm_rds_flags, 0444, bcm2048_fm_rds_flags_read, NULL), - __ATTR(region_bottom_frequency, 0444, - bcm2048_region_bottom_frequency_read, NULL), - __ATTR(region_top_frequency, 0444, - bcm2048_region_top_frequency_read, NULL), - __ATTR(fm_carrier_error, 0444, - bcm2048_fm_carrier_error_read, NULL), - __ATTR(fm_rssi, 0444, - bcm2048_fm_rssi_read, NULL), - __ATTR(region, 0644, bcm2048_region_read, - bcm2048_region_write), - __ATTR(rds_data, 0444, bcm2048_rds_data_read, NULL), -}; - -static int bcm2048_sysfs_unregister_properties(struct bcm2048_device *bdev, - int size) -{ - int i; - - for (i = 0; i < size; i++) - device_remove_file(&bdev->client->dev, &attrs[i]); - - return 0; -} - -static int bcm2048_sysfs_register_properties(struct bcm2048_device *bdev) -{ - int err = 0; - int i; - - for (i = 0; i < ARRAY_SIZE(attrs); i++) { - if (device_create_file(&bdev->client->dev, &attrs[i]) != 0) { - dev_err(&bdev->client->dev, - "could not register sysfs entry\n"); - err = -EBUSY; - bcm2048_sysfs_unregister_properties(bdev, i); - break; - } - } - - return err; -} - -static int bcm2048_fops_open(struct file *file) -{ - struct bcm2048_device *bdev = video_drvdata(file); - - bdev->users++; - bdev->rd_index = 0; - bdev->rds_data_available = 0; - - return 0; -} - -static int bcm2048_fops_release(struct file *file) -{ - struct bcm2048_device *bdev = video_drvdata(file); - - bdev->users--; - - return 0; -} - -static __poll_t bcm2048_fops_poll(struct file *file, - struct poll_table_struct *pts) -{ - struct bcm2048_device *bdev = video_drvdata(file); - __poll_t retval = 0; - - poll_wait(file, &bdev->read_queue, pts); - - if (bdev->rds_data_available) - retval = EPOLLIN | EPOLLRDNORM; - - return retval; -} - -static ssize_t bcm2048_fops_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - struct bcm2048_device *bdev = video_drvdata(file); - int i; - int retval = 0; - - /* we return at least 3 bytes, one block */ - count = (count / 3) * 3; /* only multiples of 3 */ - if (count < 3) - return -ENOBUFS; - - while (!bdev->rds_data_available) { - if (file->f_flags & O_NONBLOCK) { - retval = -EWOULDBLOCK; - goto done; - } - /* interruptible_sleep_on(&bdev->read_queue); */ - if (wait_event_interruptible(bdev->read_queue, - bdev->rds_data_available) < 0) { - retval = -EINTR; - goto done; - } - } - - mutex_lock(&bdev->mutex); - /* copy data to userspace */ - i = bdev->fifo_size - bdev->rd_index; - if (count > i) - count = (i / 3) * 3; - - i = 0; - while (i < count) { - unsigned char tmpbuf[3]; - - tmpbuf[i] = bdev->rds_info.radio_text[bdev->rd_index + i + 2]; - tmpbuf[i + 1] = - bdev->rds_info.radio_text[bdev->rd_index + i + 1]; - tmpbuf[i + 2] = - (bdev->rds_info.radio_text[bdev->rd_index + i] & - 0xf0) >> 4; - if ((bdev->rds_info.radio_text[bdev->rd_index + i] & - BCM2048_RDS_CRC_MASK) == BCM2048_RDS_CRC_UNRECOVARABLE) - tmpbuf[i + 2] |= 0x80; - if (copy_to_user(buf + i, tmpbuf, 3)) { - retval = -EFAULT; - break; - } - i += 3; - } - - bdev->rd_index += i; - if (bdev->rd_index >= bdev->fifo_size) - bdev->rds_data_available = 0; - - mutex_unlock(&bdev->mutex); - if (retval == 0) - retval = i; - -done: - return retval; -} - -/* - * bcm2048_fops - file operations interface - */ -static const struct v4l2_file_operations bcm2048_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = video_ioctl2, - /* for RDS read support */ - .open = bcm2048_fops_open, - .release = bcm2048_fops_release, - .read = bcm2048_fops_read, - .poll = bcm2048_fops_poll -}; - -/* - * Video4Linux Interface - */ -static struct v4l2_queryctrl bcm2048_v4l2_queryctrl[] = { - { - .id = V4L2_CID_AUDIO_VOLUME, - .flags = V4L2_CTRL_FLAG_DISABLED, - }, - { - .id = V4L2_CID_AUDIO_BALANCE, - .flags = V4L2_CTRL_FLAG_DISABLED, - }, - { - .id = V4L2_CID_AUDIO_BASS, - .flags = V4L2_CTRL_FLAG_DISABLED, - }, - { - .id = V4L2_CID_AUDIO_TREBLE, - .flags = V4L2_CTRL_FLAG_DISABLED, - }, - { - .id = V4L2_CID_AUDIO_MUTE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Mute", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - }, - { - .id = V4L2_CID_AUDIO_LOUDNESS, - .flags = V4L2_CTRL_FLAG_DISABLED, - }, -}; - -static int bcm2048_vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *capability) -{ - struct bcm2048_device *bdev = video_get_drvdata(video_devdata(file)); - - strscpy(capability->driver, BCM2048_DRIVER_NAME, - sizeof(capability->driver)); - strscpy(capability->card, BCM2048_DRIVER_CARD, - sizeof(capability->card)); - snprintf(capability->bus_info, 32, "I2C: 0x%X", bdev->client->addr); - return 0; -} - -static int bcm2048_vidioc_g_input(struct file *filp, void *priv, - unsigned int *i) -{ - *i = 0; - - return 0; -} - -static int bcm2048_vidioc_s_input(struct file *filp, void *priv, - unsigned int i) -{ - if (i) - return -EINVAL; - - return 0; -} - -static int bcm2048_vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(bcm2048_v4l2_queryctrl); i++) { - if (qc->id && qc->id == bcm2048_v4l2_queryctrl[i].id) { - *qc = bcm2048_v4l2_queryctrl[i]; - return 0; - } - } - - return -EINVAL; -} - -static int bcm2048_vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct bcm2048_device *bdev = video_get_drvdata(video_devdata(file)); - int err = 0; - - if (!bdev) - return -ENODEV; - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - err = bcm2048_get_mute(bdev); - if (err >= 0) - ctrl->value = err; - break; - } - - return err; -} - -static int bcm2048_vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct bcm2048_device *bdev = video_get_drvdata(video_devdata(file)); - int err = 0; - - if (!bdev) - return -ENODEV; - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - if (ctrl->value) { - if (bdev->power_state) { - err = bcm2048_set_mute(bdev, ctrl->value); - err |= bcm2048_deinit(bdev); - } - } else { - if (!bdev->power_state) { - err = bcm2048_init(bdev); - err |= bcm2048_set_mute(bdev, ctrl->value); - } - } - break; - } - - return err; -} - -static int bcm2048_vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *audio) -{ - if (audio->index > 1) - return -EINVAL; - - strscpy(audio->name, "Radio", sizeof(audio->name)); - audio->capability = V4L2_AUDCAP_STEREO; - - return 0; -} - -static int bcm2048_vidioc_s_audio(struct file *file, void *priv, - const struct v4l2_audio *audio) -{ - if (audio->index != 0) - return -EINVAL; - - return 0; -} - -static int bcm2048_vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *tuner) -{ - struct bcm2048_device *bdev = video_get_drvdata(video_devdata(file)); - s8 f_error; - s8 rssi; - - if (!bdev) - return -ENODEV; - - if (tuner->index > 0) - return -EINVAL; - - strscpy(tuner->name, "FM Receiver", sizeof(tuner->name)); - tuner->type = V4L2_TUNER_RADIO; - tuner->rangelow = - dev_to_v4l2(bcm2048_get_region_bottom_frequency(bdev)); - tuner->rangehigh = - dev_to_v4l2(bcm2048_get_region_top_frequency(bdev)); - tuner->rxsubchans = V4L2_TUNER_SUB_STEREO; - tuner->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LOW; - tuner->audmode = V4L2_TUNER_MODE_STEREO; - tuner->afc = 0; - if (bdev->power_state) { - /* - * Report frequencies with high carrier errors to have zero - * signal level - */ - f_error = bcm2048_get_fm_carrier_error(bdev); - if (f_error < BCM2048_FREQ_ERROR_FLOOR || - f_error > BCM2048_FREQ_ERROR_ROOF) { - tuner->signal = 0; - } else { - /* - * RSSI level -60 dB is defined to report full - * signal strength - */ - rssi = bcm2048_get_fm_rssi(bdev); - if (rssi >= BCM2048_RSSI_LEVEL_BASE) { - tuner->signal = 0xFFFF; - } else if (rssi > BCM2048_RSSI_LEVEL_ROOF) { - tuner->signal = (rssi + - BCM2048_RSSI_LEVEL_ROOF_NEG) - * BCM2048_SIGNAL_MULTIPLIER; - } else { - tuner->signal = 0; - } - } - } else { - tuner->signal = 0; - } - - return 0; -} - -static int bcm2048_vidioc_s_tuner(struct file *file, void *priv, - const struct v4l2_tuner *tuner) -{ - struct bcm2048_device *bdev = video_get_drvdata(video_devdata(file)); - - if (!bdev) - return -ENODEV; - - if (tuner->index > 0) - return -EINVAL; - - return 0; -} - -static int bcm2048_vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *freq) -{ - struct bcm2048_device *bdev = video_get_drvdata(video_devdata(file)); - int err = 0; - int f; - - if (!bdev->power_state) - return -ENODEV; - - freq->type = V4L2_TUNER_RADIO; - f = bcm2048_get_fm_frequency(bdev); - - if (f < 0) - err = f; - else - freq->frequency = dev_to_v4l2(f); - - return err; -} - -static int bcm2048_vidioc_s_frequency(struct file *file, void *priv, - const struct v4l2_frequency *freq) -{ - struct bcm2048_device *bdev = video_get_drvdata(video_devdata(file)); - int err; - - if (freq->type != V4L2_TUNER_RADIO) - return -EINVAL; - - if (!bdev->power_state) - return -ENODEV; - - err = bcm2048_set_fm_frequency(bdev, v4l2_to_dev(freq->frequency)); - err |= bcm2048_set_fm_search_tune_mode(bdev, BCM2048_FM_PRE_SET_MODE); - - return err; -} - -static int bcm2048_vidioc_s_hw_freq_seek(struct file *file, void *priv, - const struct v4l2_hw_freq_seek *seek) -{ - struct bcm2048_device *bdev = video_get_drvdata(video_devdata(file)); - int err; - - if (!bdev->power_state) - return -ENODEV; - - if ((seek->tuner != 0) || (seek->type != V4L2_TUNER_RADIO)) - return -EINVAL; - - err = bcm2048_set_fm_search_mode_direction(bdev, seek->seek_upward); - err |= bcm2048_set_fm_search_tune_mode(bdev, - BCM2048_FM_AUTO_SEARCH_MODE); - - return err; -} - -static const struct v4l2_ioctl_ops bcm2048_ioctl_ops = { - .vidioc_querycap = bcm2048_vidioc_querycap, - .vidioc_g_input = bcm2048_vidioc_g_input, - .vidioc_s_input = bcm2048_vidioc_s_input, - .vidioc_queryctrl = bcm2048_vidioc_queryctrl, - .vidioc_g_ctrl = bcm2048_vidioc_g_ctrl, - .vidioc_s_ctrl = bcm2048_vidioc_s_ctrl, - .vidioc_g_audio = bcm2048_vidioc_g_audio, - .vidioc_s_audio = bcm2048_vidioc_s_audio, - .vidioc_g_tuner = bcm2048_vidioc_g_tuner, - .vidioc_s_tuner = bcm2048_vidioc_s_tuner, - .vidioc_g_frequency = bcm2048_vidioc_g_frequency, - .vidioc_s_frequency = bcm2048_vidioc_s_frequency, - .vidioc_s_hw_freq_seek = bcm2048_vidioc_s_hw_freq_seek, -}; - -/* - * bcm2048_viddev_template - video device interface - */ -static const struct video_device bcm2048_viddev_template = { - .fops = &bcm2048_fops, - .name = BCM2048_DRIVER_NAME, - .release = video_device_release_empty, - .ioctl_ops = &bcm2048_ioctl_ops, - .device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO | - V4L2_CAP_HW_FREQ_SEEK, -}; - -/* - * I2C driver interface - */ -static int bcm2048_i2c_driver_probe(struct i2c_client *client) -{ - struct bcm2048_device *bdev; - int err; - - bdev = kzalloc(sizeof(*bdev), GFP_KERNEL); - if (!bdev) { - err = -ENOMEM; - goto exit; - } - - bdev->client = client; - i2c_set_clientdata(client, bdev); - mutex_init(&bdev->mutex); - init_completion(&bdev->compl); - INIT_WORK(&bdev->work, bcm2048_work); - - if (client->irq) { - err = request_irq(client->irq, - bcm2048_handler, IRQF_TRIGGER_FALLING, - client->name, bdev); - if (err < 0) { - dev_err(&client->dev, "Could not request IRQ\n"); - goto free_bdev; - } - dev_dbg(&client->dev, "IRQ requested.\n"); - } else { - dev_dbg(&client->dev, "IRQ not configured. Using timeouts.\n"); - } - - bdev->videodev = bcm2048_viddev_template; - video_set_drvdata(&bdev->videodev, bdev); - if (video_register_device(&bdev->videodev, VFL_TYPE_RADIO, radio_nr)) { - dev_dbg(&client->dev, "Could not register video device.\n"); - err = -EIO; - goto free_irq; - } - - err = bcm2048_sysfs_register_properties(bdev); - if (err < 0) { - dev_dbg(&client->dev, "Could not register sysfs interface.\n"); - goto free_registration; - } - - err = bcm2048_probe(bdev); - if (err < 0) { - dev_dbg(&client->dev, "Failed to probe device information.\n"); - goto free_sysfs; - } - - return 0; - -free_sysfs: - bcm2048_sysfs_unregister_properties(bdev, ARRAY_SIZE(attrs)); -free_registration: - video_unregister_device(&bdev->videodev); -free_irq: - if (client->irq) - free_irq(client->irq, bdev); -free_bdev: - i2c_set_clientdata(client, NULL); - kfree(bdev); -exit: - return err; -} - -static int bcm2048_i2c_driver_remove(struct i2c_client *client) -{ - struct bcm2048_device *bdev = i2c_get_clientdata(client); - - if (!client->adapter) - return -ENODEV; - - if (bdev) { - bcm2048_sysfs_unregister_properties(bdev, ARRAY_SIZE(attrs)); - video_unregister_device(&bdev->videodev); - - if (bdev->power_state) - bcm2048_set_power_state(bdev, BCM2048_POWER_OFF); - - if (client->irq > 0) - free_irq(client->irq, bdev); - - cancel_work_sync(&bdev->work); - - kfree(bdev); - } - - return 0; -} - -/* - * bcm2048_i2c_driver - i2c driver interface - */ -static const struct i2c_device_id bcm2048_id[] = { - { "bcm2048", 0 }, - { }, -}; -MODULE_DEVICE_TABLE(i2c, bcm2048_id); - -static struct i2c_driver bcm2048_i2c_driver = { - .driver = { - .name = BCM2048_DRIVER_NAME, - }, - .probe_new = bcm2048_i2c_driver_probe, - .remove = bcm2048_i2c_driver_remove, - .id_table = bcm2048_id, -}; - -module_i2c_driver(bcm2048_i2c_driver); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR(BCM2048_DRIVER_AUTHOR); -MODULE_DESCRIPTION(BCM2048_DRIVER_DESC); -MODULE_VERSION("0.0.2"); diff --git a/drivers/staging/media/bcm2048/radio-bcm2048.h b/drivers/staging/media/bcm2048/radio-bcm2048.h deleted file mode 100644 index 22887a075257..000000000000 --- a/drivers/staging/media/bcm2048/radio-bcm2048.h +++ /dev/null @@ -1,26 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * drivers/staging/media/radio-bcm2048.h - * - * Property and command definitions for bcm2048 radio receiver chip. - * - * Copyright (C) Nokia Corporation - * Contact: Eero Nurkkala - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef BCM2048_H -#define BCM2048_H - -#define BCM2048_NAME "bcm2048" -#define BCM2048_I2C_ADDR 0x22 - -#endif /* ifndef BCM2048_H */ -- cgit v1.2.3-59-g8ed1b From 4ee222406740f0c39e00b12f51eda8133e35ee83 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 25 Jul 2019 03:30:23 -0400 Subject: media: staging: davinci: remove vpfe driver The davinci_vpfe driver was merged into staging back in 2012 by Manjunath Hadli from TI, with a long TODO list. For all I can tell, since then it has only seen fixes for compile-time issues and global cleanups, but nobody has actually worked on the items on the TODO list. To make things worse, the driver in its current form is incompatible with the platform code in arch/arm/mach-davinci, i.e. the driver expects to get its platform_data passed to the device as a 'struct vpfe_config', but uses a differnet definition for that structure compared to what the platform uses. Finally, there is another driver for the same device in drivers/media/platform/davinci/vpfe_capture.c. From all I can tell, the staging version was originally a copy of a more featureful driver in TI's downstream kernels. However, that kernel no longer supports dm365 after linux-2.6.37, and the mainline version moved in a different direction. Signed-off-by: Arnd Bergmann Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/Kconfig | 2 - drivers/staging/media/Makefile | 1 - drivers/staging/media/davinci_vpfe/Kconfig | 13 - drivers/staging/media/davinci_vpfe/Makefile | 11 - drivers/staging/media/davinci_vpfe/TODO | 38 - .../staging/media/davinci_vpfe/davinci-vpfe-mc.txt | 154 -- .../staging/media/davinci_vpfe/davinci_vpfe_user.h | 1287 ------------ drivers/staging/media/davinci_vpfe/dm365_ipipe.c | 1857 ----------------- drivers/staging/media/davinci_vpfe/dm365_ipipe.h | 174 -- .../staging/media/davinci_vpfe/dm365_ipipe_hw.c | 1038 ---------- .../staging/media/davinci_vpfe/dm365_ipipe_hw.h | 556 ------ drivers/staging/media/davinci_vpfe/dm365_ipipeif.c | 1070 ---------- drivers/staging/media/davinci_vpfe/dm365_ipipeif.h | 228 --- .../media/davinci_vpfe/dm365_ipipeif_user.h | 90 - drivers/staging/media/davinci_vpfe/dm365_isif.c | 2097 -------------------- drivers/staging/media/davinci_vpfe/dm365_isif.h | 200 -- .../staging/media/davinci_vpfe/dm365_isif_regs.h | 291 --- drivers/staging/media/davinci_vpfe/dm365_resizer.c | 1995 ------------------- drivers/staging/media/davinci_vpfe/dm365_resizer.h | 241 --- drivers/staging/media/davinci_vpfe/vpfe.h | 83 - .../staging/media/davinci_vpfe/vpfe_mc_capture.c | 716 ------- .../staging/media/davinci_vpfe/vpfe_mc_capture.h | 90 - drivers/staging/media/davinci_vpfe/vpfe_video.c | 1646 --------------- drivers/staging/media/davinci_vpfe/vpfe_video.h | 150 -- 24 files changed, 14028 deletions(-) delete mode 100644 drivers/staging/media/davinci_vpfe/Kconfig delete mode 100644 drivers/staging/media/davinci_vpfe/Makefile delete mode 100644 drivers/staging/media/davinci_vpfe/TODO delete mode 100644 drivers/staging/media/davinci_vpfe/davinci-vpfe-mc.txt delete mode 100644 drivers/staging/media/davinci_vpfe/davinci_vpfe_user.h delete mode 100644 drivers/staging/media/davinci_vpfe/dm365_ipipe.c delete mode 100644 drivers/staging/media/davinci_vpfe/dm365_ipipe.h delete mode 100644 drivers/staging/media/davinci_vpfe/dm365_ipipe_hw.c delete mode 100644 drivers/staging/media/davinci_vpfe/dm365_ipipe_hw.h delete mode 100644 drivers/staging/media/davinci_vpfe/dm365_ipipeif.c delete mode 100644 drivers/staging/media/davinci_vpfe/dm365_ipipeif.h delete mode 100644 drivers/staging/media/davinci_vpfe/dm365_ipipeif_user.h delete mode 100644 drivers/staging/media/davinci_vpfe/dm365_isif.c delete mode 100644 drivers/staging/media/davinci_vpfe/dm365_isif.h delete mode 100644 drivers/staging/media/davinci_vpfe/dm365_isif_regs.h delete mode 100644 drivers/staging/media/davinci_vpfe/dm365_resizer.c delete mode 100644 drivers/staging/media/davinci_vpfe/dm365_resizer.h delete mode 100644 drivers/staging/media/davinci_vpfe/vpfe.h delete mode 100644 drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c delete mode 100644 drivers/staging/media/davinci_vpfe/vpfe_mc_capture.h delete mode 100644 drivers/staging/media/davinci_vpfe/vpfe_video.c delete mode 100644 drivers/staging/media/davinci_vpfe/vpfe_video.h (limited to 'drivers/staging') diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig index 45075f977f1b..642adc4c24d2 100644 --- a/drivers/staging/media/Kconfig +++ b/drivers/staging/media/Kconfig @@ -22,8 +22,6 @@ if STAGING_MEDIA && MEDIA_SUPPORT # Please keep them in alphabetic order source "drivers/staging/media/allegro-dvt/Kconfig" -source "drivers/staging/media/davinci_vpfe/Kconfig" - source "drivers/staging/media/hantro/Kconfig" source "drivers/staging/media/imx/Kconfig" diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile index c19cfed0b059..2f1711a8aeed 100644 --- a/drivers/staging/media/Makefile +++ b/drivers/staging/media/Makefile @@ -1,7 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_VIDEO_ALLEGRO_DVT) += allegro-dvt/ obj-$(CONFIG_VIDEO_IMX_MEDIA) += imx/ -obj-$(CONFIG_VIDEO_DM365_VPFE) += davinci_vpfe/ obj-$(CONFIG_VIDEO_MESON_VDEC) += meson/vdec/ obj-$(CONFIG_VIDEO_OMAP4) += omap4iss/ obj-$(CONFIG_VIDEO_SUNXI) += sunxi/ diff --git a/drivers/staging/media/davinci_vpfe/Kconfig b/drivers/staging/media/davinci_vpfe/Kconfig deleted file mode 100644 index 94bf6746c03f..000000000000 --- a/drivers/staging/media/davinci_vpfe/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -config VIDEO_DM365_VPFE - tristate "DM365 VPFE Media Controller Capture Driver" - depends on VIDEO_V4L2 - depends on (ARCH_DAVINCI_DM365 && !VIDEO_DM365_ISIF) || (COMPILE_TEST && !ARCH_OMAP1) - depends on VIDEO_V4L2_SUBDEV_API - depends on VIDEO_DAVINCI_VPBE_DISPLAY - select VIDEOBUF2_DMA_CONTIG - help - Support for DM365 VPFE based Media Controller Capture driver. - - To compile this driver as a module, choose M here: the - module will be called vpfe-mc-capture. diff --git a/drivers/staging/media/davinci_vpfe/Makefile b/drivers/staging/media/davinci_vpfe/Makefile deleted file mode 100644 index 0ae8c5014f74..000000000000 --- a/drivers/staging/media/davinci_vpfe/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_VIDEO_DM365_VPFE) += davinci-vfpe.o - -davinci-vfpe-objs := \ - dm365_isif.o dm365_ipipe_hw.o dm365_ipipe.o \ - dm365_resizer.o dm365_ipipeif.o vpfe_mc_capture.o vpfe_video.o - -# Allow building it with COMPILE_TEST on other archs -ifndef CONFIG_ARCH_DAVINCI -ccflags-y += -I $(srctree)/arch/arm/mach-davinci/include/ -endif diff --git a/drivers/staging/media/davinci_vpfe/TODO b/drivers/staging/media/davinci_vpfe/TODO deleted file mode 100644 index cc8bd9306f2a..000000000000 --- a/drivers/staging/media/davinci_vpfe/TODO +++ /dev/null @@ -1,38 +0,0 @@ -TODO (general): -================================== - -- User space interface refinement - - Controls should be used when possible rather than private ioctl - - No enums should be used - - Use of MC and V4L2 subdev APIs when applicable - - Single interface header might suffice - - Current interface forces to configure everything at once -- Get rid of the dm365_ipipe_hw.[ch] layer -- Active external sub-devices defined by link configuration; no strcmp - needed -- More generic platform data (i2c adapters) -- The driver should have no knowledge of possible external subdevs; see - struct vpfe_subdev_id -- Some of the hardware control should be refactorede -- Check proper serialisation (through mutexes and spinlocks) -- Names that are visible in kernel global namespace should have a common - prefix (or a few) -- While replacing the older driver in media folder, provide a compatibility - layer and compatibility tests that warrants (using the libv4l's LD_PRELOAD - approach) there is no regression for the users using the older driver. -- make it independent of arch-specific APIs (mach/mux.h). - -Building of uImage and Applications: -================================== - -As of now since the interface will undergo few changes all the include -files are present in staging itself, to build for dm365 follow below steps, - -- copy vpfe.h from drivers/staging/media/davinci_vpfe/ to - include/media/davinci/ folder for building the uImage. -- copy davinci_vpfe_user.h from drivers/staging/media/davinci_vpfe/ to - include/uapi/linux/davinci_vpfe.h, and add a entry in Kbuild (required - for building application). -- copy dm365_ipipeif_user.h from drivers/staging/media/davinci_vpfe/ to - include/uapi/linux/dm365_ipipeif.h and a entry in Kbuild (required - for building application). diff --git a/drivers/staging/media/davinci_vpfe/davinci-vpfe-mc.txt b/drivers/staging/media/davinci_vpfe/davinci-vpfe-mc.txt deleted file mode 100644 index a1e91778aa9b..000000000000 --- a/drivers/staging/media/davinci_vpfe/davinci-vpfe-mc.txt +++ /dev/null @@ -1,154 +0,0 @@ -Davinci Video processing Front End (VPFE) driver - -Copyright (C) 2012 Texas Instruments Inc - -Contacts: Manjunath Hadli - Prabhakar Lad - - -Introduction -============ - -This file documents the Texas Instruments Davinci Video processing Front End -(VPFE) driver located under drivers/media/platform/davinci. The original driver -exists for Davinci VPFE, which is now being changed to Media Controller -Framework. - -Currently the driver has been successfully used on the following -version of Davinci: - - DM365/DM368 - -The driver implements V4L2, Media controller and v4l2_subdev interfaces. Sensor, -lens and flash drivers using the v4l2_subdev interface in the kernel are -supported. - - -Split to subdevs -================ - -The Davinci VPFE is split into V4L2 subdevs, each of the blocks inside the VPFE -having one subdev to represent it. Each of the subdevs provide a V4L2 subdev -interface to userspace. - - DAVINCI ISIF - DAVINCI IPIPEIF - DAVINCI IPIPE - DAVINCI CROP RESIZER - DAVINCI RESIZER A - DAVINCI RESIZER B - -Each possible link in the VPFE is modelled by a link in the Media controller -interface. For an example program see [1]. - - -ISIF, IPIPE, and RESIZER block IOCTLs -====================================== - -The Davinci Video processing Front End (VPFE) driver supports standard V4L2 -IOCTLs and controls where possible and practical. Much of the functions provided -by the VPFE, however, does not fall under the standard IOCTL's. - -In general, there is a private ioctl for configuring each of the blocks -containing hardware-dependent functions. - -The following private IOCTLs are supported: - - VIDIOC_VPFE_ISIF_[S/G]_RAW_PARAMS - VIDIOC_VPFE_IPIPE_[S/G]_CONFIG - VIDIOC_VPFE_RSZ_[S/G]_CONFIG - -The parameter structures used by these ioctl's are described in -include/uapi/linux/davinci_vpfe.h. - -The VIDIOC_VPFE_ISIF_S_RAW_PARAMS, VIDIOC_VPFE_IPIPE_S_CONFIG and -VIDIOC_VPFE_RSZ_S_CONFIG are used to configure, enable and disable functions in -the isif, ipipe and resizer blocks respectively. These IOCTL's control several -functions in the blocks they control. VIDIOC_VPFE_ISIF_S_RAW_PARAMS IOCTL -accepts a pointer to struct vpfe_isif_raw_config as its argument. Similarly -VIDIOC_VPFE_IPIPE_S_CONFIG accepts a pointer to struct vpfe_ipipe_config. And -VIDIOC_VPFE_RSZ_S_CONFIG accepts a pointer to struct vpfe_rsz_config as its -argument. Similarly VIDIOC_VPFE_ISIF_G_RAW_PARAMS, VIDIOC_VPFE_IPIPE_G_CONFIG -and VIDIOC_VPFE_RSZ_G_CONFIG are used to get the current configuration set in -the isif, ipipe and resizer blocks respectively. - -The detailed functions of the VPFE itself related to a given VPFE block is -described in the Technical Reference Manuals (TRMs) --- see the end of the -document for those. - - -IPIPEIF block IOCTLs -====================================== - -The following private IOCTLs are supported: - - VIDIOC_VPFE_IPIPEIF_[S/G]_CONFIG - -The parameter structures used by these ioctl's are described in -include/uapi/linux/dm365_ipipeif.h - -The VIDIOC_VPFE_IPIPEIF_S_CONFIG is used to configure the ipipeif -hardware block. The VIDIOC_VPFE_IPIPEIF_S_CONFIG and -VIDIOC_VPFE_IPIPEIF_G_CONFIG accepts a pointer to struct ipipeif_params -as its argument. - - -VPFE Operating Modes -========================================== - -a: Continuous Modes ------------------------- - -1: tvp514x/tvp7002/mt9p031---> DAVINCI ISIF---> SDRAM - -2: tvp514x/tvp7002/mt9p031---> DAVINCI ISIF---> DAVINCI IPIPEIF--->| - | - <--------------------<----------------<---------------------<---| - | - V - DAVINCI CROP RESIZER--->DAVINCI RESIZER [A/B]---> SDRAM - -3: tvp514x/tvp7002/mt9p031---> DAVINCI ISIF---> DAVINCI IPIPEIF--->| - | - <--------------------<----------------<---------------------<---| - | - V - DAVINCI IPIPE---> DAVINCI CROP RESIZER--->DAVINCI RESIZER [A/B]---> SDRAM - -a: Single Shot Modes ------------------------- - -1: SDRAM---> DAVINCI IPIPEIF---> DAVINCI IPIPE---> DAVINCI CROP RESIZER--->| - | - <----------------<----------------<------------------<---------------<--| - | - V -DAVINCI RESIZER [A/B]---> SDRAM - -2: SDRAM---> DAVINCI IPIPEIF---> DAVINCI CROP RESIZER--->| - | - <----------------<----------------<---------------<---| - | - V -DAVINCI RESIZER [A/B]---> SDRAM - - -Technical reference manuals (TRMs) and other documentation -========================================================== - -Davinci DM365 TRM: - -Referenced MARCH 2009-REVISED JUNE 2011 - -Davinci DM368 TRM: - -Referenced APRIL 2010-REVISED JUNE 2011 - -Davinci Video Processing Front End (VPFE) DM36x - - - -References -========== - -[1] http://git.ideasonboard.org/?p=media-ctl.git;a=summary diff --git a/drivers/staging/media/davinci_vpfe/davinci_vpfe_user.h b/drivers/staging/media/davinci_vpfe/davinci_vpfe_user.h deleted file mode 100644 index 8d772029c91d..000000000000 --- a/drivers/staging/media/davinci_vpfe/davinci_vpfe_user.h +++ /dev/null @@ -1,1287 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2012 Texas Instruments Inc - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Contributors: - * Manjunath Hadli - * Prabhakar Lad - */ - -#ifndef _DAVINCI_VPFE_USER_H -#define _DAVINCI_VPFE_USER_H - -#include -#include - -/* - * Private IOCTL - * - * VIDIOC_VPFE_ISIF_S_RAW_PARAMS: Set raw params in isif - * VIDIOC_VPFE_ISIF_G_RAW_PARAMS: Get raw params from isif - * VIDIOC_VPFE_PRV_S_CONFIG: Set ipipe engine configuration - * VIDIOC_VPFE_PRV_G_CONFIG: Get ipipe engine configuration - * VIDIOC_VPFE_RSZ_S_CONFIG: Set resizer engine configuration - * VIDIOC_VPFE_RSZ_G_CONFIG: Get resizer engine configuration - */ - -#define VIDIOC_VPFE_ISIF_S_RAW_PARAMS \ - _IOW('V', BASE_VIDIOC_PRIVATE + 1, struct vpfe_isif_raw_config) -#define VIDIOC_VPFE_ISIF_G_RAW_PARAMS \ - _IOR('V', BASE_VIDIOC_PRIVATE + 2, struct vpfe_isif_raw_config) -#define VIDIOC_VPFE_IPIPE_S_CONFIG \ - _IOWR('P', BASE_VIDIOC_PRIVATE + 3, struct vpfe_ipipe_config) -#define VIDIOC_VPFE_IPIPE_G_CONFIG \ - _IOWR('P', BASE_VIDIOC_PRIVATE + 4, struct vpfe_ipipe_config) -#define VIDIOC_VPFE_RSZ_S_CONFIG \ - _IOWR('R', BASE_VIDIOC_PRIVATE + 5, struct vpfe_rsz_config) -#define VIDIOC_VPFE_RSZ_G_CONFIG \ - _IOWR('R', BASE_VIDIOC_PRIVATE + 6, struct vpfe_rsz_config) - -/* - * Private Control's for ISIF - */ -#define VPFE_ISIF_CID_CRGAIN (V4L2_CID_USER_BASE | 0xa001) -#define VPFE_ISIF_CID_CGRGAIN (V4L2_CID_USER_BASE | 0xa002) -#define VPFE_ISIF_CID_CGBGAIN (V4L2_CID_USER_BASE | 0xa003) -#define VPFE_ISIF_CID_CBGAIN (V4L2_CID_USER_BASE | 0xa004) -#define VPFE_ISIF_CID_GAIN_OFFSET (V4L2_CID_USER_BASE | 0xa005) - -/* - * Private Control's for ISIF and IPIPEIF - */ -#define VPFE_CID_DPCM_PREDICTOR (V4L2_CID_USER_BASE | 0xa006) - -/************************************************************************ - * Vertical Defect Correction parameters - ***********************************************************************/ - -/** - * vertical defect correction methods - */ -enum vpfe_isif_vdfc_corr_mode { - /* Defect level subtraction. Just fed through if saturating */ - VPFE_ISIF_VDFC_NORMAL, - /** - * Defect level subtraction. Horizontal interpolation ((i-2)+(i+2))/2 - * if data saturating - */ - VPFE_ISIF_VDFC_HORZ_INTERPOL_IF_SAT, - /* Horizontal interpolation (((i-2)+(i+2))/2) */ - VPFE_ISIF_VDFC_HORZ_INTERPOL -}; - -/** - * Max Size of the Vertical Defect Correction table - */ -#define VPFE_ISIF_VDFC_TABLE_SIZE 8 - -/** - * Values used for shifting up the vdfc defect level - */ -enum vpfe_isif_vdfc_shift { - /* No Shift */ - VPFE_ISIF_VDFC_NO_SHIFT, - /* Shift by 1 bit */ - VPFE_ISIF_VDFC_SHIFT_1, - /* Shift by 2 bit */ - VPFE_ISIF_VDFC_SHIFT_2, - /* Shift by 3 bit */ - VPFE_ISIF_VDFC_SHIFT_3, - /* Shift by 4 bit */ - VPFE_ISIF_VDFC_SHIFT_4 -}; - -/** - * Defect Correction (DFC) table entry - */ -struct vpfe_isif_vdfc_entry { - /* vertical position of defect */ - unsigned short pos_vert; - /* horizontal position of defect */ - unsigned short pos_horz; - /** - * Defect level of Vertical line defect position. This is subtracted - * from the data at the defect position - */ - unsigned char level_at_pos; - /** - * Defect level of the pixels upper than the vertical line defect. - * This is subtracted from the data - */ - unsigned char level_up_pixels; - /** - * Defect level of the pixels lower than the vertical line defect. - * This is subtracted from the data - */ - unsigned char level_low_pixels; -}; - -/** - * Structure for Defect Correction (DFC) parameter - */ -struct vpfe_isif_dfc { - /* enable vertical defect correction */ - unsigned char en; - /* Correction methods */ - enum vpfe_isif_vdfc_corr_mode corr_mode; - /** - * 0 - whole line corrected, 1 - not - * pixels upper than the defect - */ - unsigned char corr_whole_line; - /** - * defect level shift value. level_at_pos, level_upper_pos, - * and level_lower_pos can be shifted up by this value - */ - enum vpfe_isif_vdfc_shift def_level_shift; - /* defect saturation level */ - unsigned short def_sat_level; - /* number of vertical defects. Max is VPFE_ISIF_VDFC_TABLE_SIZE */ - short num_vdefects; - /* VDFC table ptr */ - struct vpfe_isif_vdfc_entry table[VPFE_ISIF_VDFC_TABLE_SIZE]; -}; - -/************************************************************************ - * Digital/Black clamp or DC Subtract parameters - ************************************************************************/ -/** - * Horizontal Black Clamp modes - */ -enum vpfe_isif_horz_bc_mode { - /** - * Horizontal clamp disabled. Only vertical clamp - * value is subtracted - */ - VPFE_ISIF_HORZ_BC_DISABLE, - /** - * Horizontal clamp value is calculated and subtracted - * from image data along with vertical clamp value - */ - VPFE_ISIF_HORZ_BC_CLAMP_CALC_ENABLED, - /** - * Horizontal clamp value calculated from previous image - * is subtracted from image data along with vertical clamp - * value. How the horizontal clamp value for the first image - * is calculated in this case ??? - */ - VPFE_ISIF_HORZ_BC_CLAMP_NOT_UPDATED -}; - -/** - * Base window selection for Horizontal Black Clamp calculations - */ -enum vpfe_isif_horz_bc_base_win_sel { - /* Select Most left window for bc calculation */ - VPFE_ISIF_SEL_MOST_LEFT_WIN, - - /* Select Most right window for bc calculation */ - VPFE_ISIF_SEL_MOST_RIGHT_WIN, -}; - -/* Size of window in horizontal direction for horizontal bc */ -enum vpfe_isif_horz_bc_sz_h { - VPFE_ISIF_HORZ_BC_SZ_H_2PIXELS, - VPFE_ISIF_HORZ_BC_SZ_H_4PIXELS, - VPFE_ISIF_HORZ_BC_SZ_H_8PIXELS, - VPFE_ISIF_HORZ_BC_SZ_H_16PIXELS -}; - -/* Size of window in vertcal direction for vertical bc */ -enum vpfe_isif_horz_bc_sz_v { - VPFE_ISIF_HORZ_BC_SZ_H_32PIXELS, - VPFE_ISIF_HORZ_BC_SZ_H_64PIXELS, - VPFE_ISIF_HORZ_BC_SZ_H_128PIXELS, - VPFE_ISIF_HORZ_BC_SZ_H_256PIXELS -}; - -/** - * Structure for Horizontal Black Clamp config params - */ -struct vpfe_isif_horz_bclamp { - /* horizontal clamp mode */ - enum vpfe_isif_horz_bc_mode mode; - /** - * pixel value limit enable. - * 0 - limit disabled - * 1 - pixel value limited to 1023 - */ - unsigned char clamp_pix_limit; - /** - * Select most left or right window for clamp val - * calculation - */ - enum vpfe_isif_horz_bc_base_win_sel base_win_sel_calc; - /* Window count per color for calculation. range 1-32 */ - unsigned char win_count_calc; - /* Window start position - horizontal for calculation. 0 - 8191 */ - unsigned short win_start_h_calc; - /* Window start position - vertical for calculation 0 - 8191 */ - unsigned short win_start_v_calc; - /* Width of the sample window in pixels for calculation */ - enum vpfe_isif_horz_bc_sz_h win_h_sz_calc; - /* Height of the sample window in pixels for calculation */ - enum vpfe_isif_horz_bc_sz_v win_v_sz_calc; -}; - -/** - * Black Clamp vertical reset values - */ -enum vpfe_isif_vert_bc_reset_val_sel { - /* Reset value used is the clamp value calculated */ - VPFE_ISIF_VERT_BC_USE_HORZ_CLAMP_VAL, - /* Reset value used is reset_clamp_val configured */ - VPFE_ISIF_VERT_BC_USE_CONFIG_CLAMP_VAL, - /* No update, previous image value is used */ - VPFE_ISIF_VERT_BC_NO_UPDATE -}; - -enum vpfe_isif_vert_bc_sz_h { - VPFE_ISIF_VERT_BC_SZ_H_2PIXELS, - VPFE_ISIF_VERT_BC_SZ_H_4PIXELS, - VPFE_ISIF_VERT_BC_SZ_H_8PIXELS, - VPFE_ISIF_VERT_BC_SZ_H_16PIXELS, - VPFE_ISIF_VERT_BC_SZ_H_32PIXELS, - VPFE_ISIF_VERT_BC_SZ_H_64PIXELS -}; - -/** - * Structure for Vertical Black Clamp configuration params - */ -struct vpfe_isif_vert_bclamp { - /* Reset value selection for vertical clamp calculation */ - enum vpfe_isif_vert_bc_reset_val_sel reset_val_sel; - /* U12 value if reset_sel = ISIF_BC_VERT_USE_CONFIG_CLAMP_VAL */ - unsigned short reset_clamp_val; - /** - * U8Q8. Line average coefficient used in vertical clamp - * calculation - */ - unsigned char line_ave_coef; - /* Width in pixels of the optical black region used for calculation. */ - enum vpfe_isif_vert_bc_sz_h ob_h_sz_calc; - /* Height of the optical black region for calculation */ - unsigned short ob_v_sz_calc; - /* Optical black region start position - horizontal. 0 - 8191 */ - unsigned short ob_start_h; - /* Optical black region start position - vertical 0 - 8191 */ - unsigned short ob_start_v; -}; - -/** - * Structure for Black Clamp configuration params - */ -struct vpfe_isif_black_clamp { - /** - * this offset value is added irrespective of the clamp - * enable status. S13 - */ - unsigned short dc_offset; - /** - * Enable black/digital clamp value to be subtracted - * from the image data - */ - unsigned char en; - /** - * black clamp mode. same/separate clamp for 4 colors - * 0 - disable - same clamp value for all colors - * 1 - clamp value calculated separately for all colors - */ - unsigned char bc_mode_color; - /* Vertical start position for bc subtraction */ - unsigned short vert_start_sub; - /* Black clamp for horizontal direction */ - struct vpfe_isif_horz_bclamp horz; - /* Black clamp for vertical direction */ - struct vpfe_isif_vert_bclamp vert; -}; - -/************************************************************************* - ** Color Space Conversion (CSC) - *************************************************************************/ -/** - * Number of Coefficient values used for CSC - */ -#define VPFE_ISIF_CSC_NUM_COEFF 16 - -struct float_8_bit { - /* 8 bit integer part */ - __u8 integer; - /* 8 bit decimal part */ - __u8 decimal; -}; - -struct float_16_bit { - /* 16 bit integer part */ - __u16 integer; - /* 16 bit decimal part */ - __u16 decimal; -}; - -/************************************************************************* - ** Color Space Conversion parameters - *************************************************************************/ -/** - * Structure used for CSC config params - */ -struct vpfe_isif_color_space_conv { - /* Enable color space conversion */ - unsigned char en; - /** - * csc coefficient table. S8Q5, M00 at index 0, M01 at index 1, and - * so forth - */ - struct float_8_bit coeff[VPFE_ISIF_CSC_NUM_COEFF]; -}; - -enum vpfe_isif_datasft { - /* No Shift */ - VPFE_ISIF_NO_SHIFT, - /* 1 bit Shift */ - VPFE_ISIF_1BIT_SHIFT, - /* 2 bit Shift */ - VPFE_ISIF_2BIT_SHIFT, - /* 3 bit Shift */ - VPFE_ISIF_3BIT_SHIFT, - /* 4 bit Shift */ - VPFE_ISIF_4BIT_SHIFT, - /* 5 bit Shift */ - VPFE_ISIF_5BIT_SHIFT, - /* 6 bit Shift */ - VPFE_ISIF_6BIT_SHIFT -}; - -#define VPFE_ISIF_LINEAR_TAB_SIZE 192 -/************************************************************************* - ** Linearization parameters - *************************************************************************/ -/** - * Structure for Sensor data linearization - */ -struct vpfe_isif_linearize { - /* Enable or Disable linearization of data */ - unsigned char en; - /* Shift value applied */ - enum vpfe_isif_datasft corr_shft; - /* scale factor applied U11Q10 */ - struct float_16_bit scale_fact; - /* Size of the linear table */ - unsigned short table[VPFE_ISIF_LINEAR_TAB_SIZE]; -}; - -/************************************************************************* - ** ISIF Raw configuration parameters - *************************************************************************/ -enum vpfe_isif_fmt_mode { - VPFE_ISIF_SPLIT, - VPFE_ISIF_COMBINE -}; - -enum vpfe_isif_lnum { - VPFE_ISIF_1LINE, - VPFE_ISIF_2LINES, - VPFE_ISIF_3LINES, - VPFE_ISIF_4LINES -}; - -enum vpfe_isif_line { - VPFE_ISIF_1STLINE, - VPFE_ISIF_2NDLINE, - VPFE_ISIF_3RDLINE, - VPFE_ISIF_4THLINE -}; - -struct vpfe_isif_fmtplen { - /** - * number of program entries for SET0, range 1 - 16 - * when fmtmode is ISIF_SPLIT, 1 - 8 when fmtmode is - * ISIF_COMBINE - */ - unsigned short plen0; - /** - * number of program entries for SET1, range 1 - 16 - * when fmtmode is ISIF_SPLIT, 1 - 8 when fmtmode is - * ISIF_COMBINE - */ - unsigned short plen1; - /** - * number of program entries for SET2, range 1 - 16 - * when fmtmode is ISIF_SPLIT, 1 - 8 when fmtmode is - * ISIF_COMBINE - */ - unsigned short plen2; - /** - * number of program entries for SET3, range 1 - 16 - * when fmtmode is ISIF_SPLIT, 1 - 8 when fmtmode is - * ISIF_COMBINE - */ - unsigned short plen3; -}; - -struct vpfe_isif_fmt_cfg { - /* Split or combine or line alternate */ - enum vpfe_isif_fmt_mode fmtmode; - /* enable or disable line alternating mode */ - unsigned char ln_alter_en; - /* Split/combine line number */ - enum vpfe_isif_lnum lnum; - /* Address increment Range 1 - 16 */ - unsigned int addrinc; -}; - -struct vpfe_isif_fmt_addr_ptr { - /* Initial address */ - unsigned int init_addr; - /* output line number */ - enum vpfe_isif_line out_line; -}; - -struct vpfe_isif_fmtpgm_ap { - /* program address pointer */ - unsigned char pgm_aptr; - /* program address increment or decrement */ - unsigned char pgmupdt; -}; - -struct vpfe_isif_data_formatter { - /* Enable/Disable data formatter */ - unsigned char en; - /* data formatter configuration */ - struct vpfe_isif_fmt_cfg cfg; - /* Formatter program entries length */ - struct vpfe_isif_fmtplen plen; - /* first pixel in a line fed to formatter */ - unsigned short fmtrlen; - /* HD interval for output line. Only valid when split line */ - unsigned short fmthcnt; - /* formatter address pointers */ - struct vpfe_isif_fmt_addr_ptr fmtaddr_ptr[16]; - /* program enable/disable */ - unsigned char pgm_en[32]; - /* program address pointers */ - struct vpfe_isif_fmtpgm_ap fmtpgm_ap[32]; -}; - -struct vpfe_isif_df_csc { - /* Color Space Conversion configuration, 0 - csc, 1 - df */ - unsigned int df_or_csc; - /* csc configuration valid if df_or_csc is 0 */ - struct vpfe_isif_color_space_conv csc; - /* data formatter configuration valid if df_or_csc is 1 */ - struct vpfe_isif_data_formatter df; - /* start pixel in a line at the input */ - unsigned int start_pix; - /* number of pixels in input line */ - unsigned int num_pixels; - /* start line at the input */ - unsigned int start_line; - /* number of lines at the input */ - unsigned int num_lines; -}; - -struct vpfe_isif_gain_offsets_adj { - /* Enable or Disable Gain adjustment for SDRAM data */ - unsigned char gain_sdram_en; - /* Enable or Disable Gain adjustment for IPIPE data */ - unsigned char gain_ipipe_en; - /* Enable or Disable Gain adjustment for H3A data */ - unsigned char gain_h3a_en; - /* Enable or Disable Gain adjustment for SDRAM data */ - unsigned char offset_sdram_en; - /* Enable or Disable Gain adjustment for IPIPE data */ - unsigned char offset_ipipe_en; - /* Enable or Disable Gain adjustment for H3A data */ - unsigned char offset_h3a_en; -}; - -struct vpfe_isif_cul { - /* Horizontal Cull pattern for odd lines */ - unsigned char hcpat_odd; - /* Horizontal Cull pattern for even lines */ - unsigned char hcpat_even; - /* Vertical Cull pattern */ - unsigned char vcpat; - /* Enable or disable lpf. Apply when cull is enabled */ - unsigned char en_lpf; -}; - -/* all the stuff in this struct will be provided by userland */ -struct vpfe_isif_raw_config { - /* Linearization parameters for image sensor data input */ - struct vpfe_isif_linearize linearize; - /* Data formatter or CSC */ - struct vpfe_isif_df_csc df_csc; - /* Defect Pixel Correction (DFC) confguration */ - struct vpfe_isif_dfc dfc; - /* Black/Digital Clamp configuration */ - struct vpfe_isif_black_clamp bclamp; - /* Gain, offset adjustments */ - struct vpfe_isif_gain_offsets_adj gain_offset; - /* Culling */ - struct vpfe_isif_cul culling; - /* horizontal offset for Gain/LSC/DFC */ - unsigned short horz_offset; - /* vertical offset for Gain/LSC/DFC */ - unsigned short vert_offset; -}; - -/********************************************************************** - * IPIPE API Structures - **********************************************************************/ - -/* IPIPE module configurations */ - -/* IPIPE input configuration */ -#define VPFE_IPIPE_INPUT_CONFIG BIT(0) -/* LUT based Defect Pixel Correction */ -#define VPFE_IPIPE_LUTDPC BIT(1) -/* On the fly (OTF) Defect Pixel Correction */ -#define VPFE_IPIPE_OTFDPC BIT(2) -/* Noise Filter - 1 */ -#define VPFE_IPIPE_NF1 BIT(3) -/* Noise Filter - 2 */ -#define VPFE_IPIPE_NF2 BIT(4) -/* White Balance. Also a control ID */ -#define VPFE_IPIPE_WB BIT(5) -/* 1st RGB to RBG Blend module */ -#define VPFE_IPIPE_RGB2RGB_1 BIT(6) -/* 2nd RGB to RBG Blend module */ -#define VPFE_IPIPE_RGB2RGB_2 BIT(7) -/* Gamma Correction */ -#define VPFE_IPIPE_GAMMA BIT(8) -/* 3D LUT color conversion */ -#define VPFE_IPIPE_3D_LUT BIT(9) -/* RGB to YCbCr module */ -#define VPFE_IPIPE_RGB2YUV BIT(10) -/* YUV 422 conversion module */ -#define VPFE_IPIPE_YUV422_CONV BIT(11) -/* Edge Enhancement */ -#define VPFE_IPIPE_YEE BIT(12) -/* Green Imbalance Correction */ -#define VPFE_IPIPE_GIC BIT(13) -/* CFA Interpolation */ -#define VPFE_IPIPE_CFA BIT(14) -/* Chroma Artifact Reduction */ -#define VPFE_IPIPE_CAR BIT(15) -/* Chroma Gain Suppression */ -#define VPFE_IPIPE_CGS BIT(16) -/* Global brightness and contrast control */ -#define VPFE_IPIPE_GBCE BIT(17) - -#define VPFE_IPIPE_MAX_MODULES 18 - -struct ipipe_float_u16 { - unsigned short integer; - unsigned short decimal; -}; - -struct ipipe_float_s16 { - short integer; - unsigned short decimal; -}; - -struct ipipe_float_u8 { - unsigned char integer; - unsigned char decimal; -}; - -/* Copy method selection for vertical correction - * Used when ipipe_dfc_corr_meth is IPIPE_DPC_CTORB_AFTER_HINT - */ -enum vpfe_ipipe_dpc_corr_meth { - /* replace by black or white dot specified by repl_white */ - VPFE_IPIPE_DPC_REPL_BY_DOT = 0, - /* Copy from left */ - VPFE_IPIPE_DPC_CL = 1, - /* Copy from right */ - VPFE_IPIPE_DPC_CR = 2, - /* Horizontal interpolation */ - VPFE_IPIPE_DPC_H_INTP = 3, - /* Vertical interpolation */ - VPFE_IPIPE_DPC_V_INTP = 4, - /* Copy from top */ - VPFE_IPIPE_DPC_CT = 5, - /* Copy from bottom */ - VPFE_IPIPE_DPC_CB = 6, - /* 2D interpolation */ - VPFE_IPIPE_DPC_2D_INTP = 7, -}; - -struct vpfe_ipipe_lutdpc_entry { - /* Horizontal position */ - unsigned short horz_pos; - /* vertical position */ - unsigned short vert_pos; - enum vpfe_ipipe_dpc_corr_meth method; -}; - -#define VPFE_IPIPE_MAX_SIZE_DPC 256 - -/* Structure for configuring DPC module */ -struct vpfe_ipipe_lutdpc { - /* 0 - disable, 1 - enable */ - unsigned char en; - /* 0 - replace with black dot, 1 - white dot when correction - * method is IPIPE_DFC_REPL_BY_DOT=0, - */ - unsigned char repl_white; - /* number of entries in the correction table. Currently only - * support up-to 256 entries. infinite mode is not supported - */ - unsigned short dpc_size; - struct vpfe_ipipe_lutdpc_entry table[VPFE_IPIPE_MAX_SIZE_DPC]; -}; - -enum vpfe_ipipe_otfdpc_det_meth { - VPFE_IPIPE_DPC_OTF_MIN_MAX, - VPFE_IPIPE_DPC_OTF_MIN_MAX2 -}; - -struct vpfe_ipipe_otfdpc_thr { - unsigned short r; - unsigned short gr; - unsigned short gb; - unsigned short b; -}; - -enum vpfe_ipipe_otfdpc_alg { - VPFE_IPIPE_OTFDPC_2_0, - VPFE_IPIPE_OTFDPC_3_0 -}; - -struct vpfe_ipipe_otfdpc_2_0_cfg { - /* defect detection threshold for MIN_MAX2 method (DPC 2.0 alg) */ - struct vpfe_ipipe_otfdpc_thr det_thr; - /* defect correction threshold for MIN_MAX2 method (DPC 2.0 alg) or - * maximum value for MIN_MAX method - */ - struct vpfe_ipipe_otfdpc_thr corr_thr; -}; - -struct vpfe_ipipe_otfdpc_3_0_cfg { - /* DPC3.0 activity adj shf. activity = (max2-min2) >> (6 -shf) - */ - unsigned char act_adj_shf; - /* DPC3.0 detection threshold, THR */ - unsigned short det_thr; - /* DPC3.0 detection threshold slope, SLP */ - unsigned short det_slp; - /* DPC3.0 detection threshold min, MIN */ - unsigned short det_thr_min; - /* DPC3.0 detection threshold max, MAX */ - unsigned short det_thr_max; - /* DPC3.0 correction threshold, THR */ - unsigned short corr_thr; - /* DPC3.0 correction threshold slope, SLP */ - unsigned short corr_slp; - /* DPC3.0 correction threshold min, MIN */ - unsigned short corr_thr_min; - /* DPC3.0 correction threshold max, MAX */ - unsigned short corr_thr_max; -}; - -struct vpfe_ipipe_otfdpc { - /* 0 - disable, 1 - enable */ - unsigned char en; - /* defect detection method */ - enum vpfe_ipipe_otfdpc_det_meth det_method; - /* Algorithm used. Applicable only when IPIPE_DPC_OTF_MIN_MAX2 is - * used - */ - enum vpfe_ipipe_otfdpc_alg alg; - union { - /* if alg is IPIPE_OTFDPC_2_0 */ - struct vpfe_ipipe_otfdpc_2_0_cfg dpc_2_0; - /* if alg is IPIPE_OTFDPC_3_0 */ - struct vpfe_ipipe_otfdpc_3_0_cfg dpc_3_0; - } alg_cfg; -}; - -/* Threshold values table size */ -#define VPFE_IPIPE_NF_THR_TABLE_SIZE 8 -/* Intensity values table size */ -#define VPFE_IPIPE_NF_STR_TABLE_SIZE 8 - -/* NF, sampling method for green pixels */ -enum vpfe_ipipe_nf_sampl_meth { - /* Same as R or B */ - VPFE_IPIPE_NF_BOX, - /* Diamond mode */ - VPFE_IPIPE_NF_DIAMOND -}; - -/* Structure for configuring NF module */ -struct vpfe_ipipe_nf { - /* 0 - disable, 1 - enable */ - unsigned char en; - /* Sampling method for green pixels */ - enum vpfe_ipipe_nf_sampl_meth gr_sample_meth; - /* Down shift value in LUT reference address - */ - unsigned char shft_val; - /* Spread value in NF algorithm - */ - unsigned char spread_val; - /* Apply LSC gain to threshold. Enable this only if - * LSC is enabled in ISIF - */ - unsigned char apply_lsc_gain; - /* Threshold values table */ - unsigned short thr[VPFE_IPIPE_NF_THR_TABLE_SIZE]; - /* intensity values table */ - unsigned char str[VPFE_IPIPE_NF_STR_TABLE_SIZE]; - /* Edge detection minimum threshold */ - unsigned short edge_det_min_thr; - /* Edge detection maximum threshold */ - unsigned short edge_det_max_thr; -}; - -enum vpfe_ipipe_gic_alg { - VPFE_IPIPE_GIC_ALG_CONST_GAIN, - VPFE_IPIPE_GIC_ALG_ADAPT_GAIN -}; - -enum vpfe_ipipe_gic_thr_sel { - VPFE_IPIPE_GIC_THR_REG, - VPFE_IPIPE_GIC_THR_NF -}; - -enum vpfe_ipipe_gic_wt_fn_type { - /* Use difference as index */ - VPFE_IPIPE_GIC_WT_FN_TYP_DIF, - /* Use weight function as index */ - VPFE_IPIPE_GIC_WT_FN_TYP_HP_VAL -}; - -/* structure for Green Imbalance Correction */ -struct vpfe_ipipe_gic { - /* 0 - disable, 1 - enable */ - unsigned char en; - /* 0 - Constant gain , 1 - Adaptive gain algorithm */ - enum vpfe_ipipe_gic_alg gic_alg; - /* GIC gain or weight. Used for Constant gain and Adaptive algorithms - */ - unsigned short gain; - /* Threshold selection. GIC register values or NF2 thr table */ - enum vpfe_ipipe_gic_thr_sel thr_sel; - /* thr1. Used when thr_sel is IPIPE_GIC_THR_REG */ - unsigned short thr; - /* this value is used for thr2-thr1, thr3-thr2 or - * thr4-thr3 when wt_fn_type is index. Otherwise it - * is the - */ - unsigned short slope; - /* Apply LSC gain to threshold. Enable this only if - * LSC is enabled in ISIF & thr_sel is IPIPE_GIC_THR_REG - */ - unsigned char apply_lsc_gain; - /* Multiply Nf2 threshold by this gain. Use this when thr_sel - * is IPIPE_GIC_THR_NF - */ - struct ipipe_float_u8 nf2_thr_gain; - /* Weight function uses difference as index or high pass value. - * Used for adaptive gain algorithm - */ - enum vpfe_ipipe_gic_wt_fn_type wt_fn_type; -}; - -/* Structure for configuring WB module */ -struct vpfe_ipipe_wb { - /* Offset (S12) for R */ - short ofst_r; - /* Offset (S12) for Gr */ - short ofst_gr; - /* Offset (S12) for Gb */ - short ofst_gb; - /* Offset (S12) for B */ - short ofst_b; - /* Gain (U13Q9) for Red */ - struct ipipe_float_u16 gain_r; - /* Gain (U13Q9) for Gr */ - struct ipipe_float_u16 gain_gr; - /* Gain (U13Q9) for Gb */ - struct ipipe_float_u16 gain_gb; - /* Gain (U13Q9) for Blue */ - struct ipipe_float_u16 gain_b; -}; - -enum vpfe_ipipe_cfa_alg { - /* Algorithm is 2DirAC */ - VPFE_IPIPE_CFA_ALG_2DIRAC, - /* Algorithm is 2DirAC + Digital Antialiasing (DAA) */ - VPFE_IPIPE_CFA_ALG_2DIRAC_DAA, - /* Algorithm is DAA */ - VPFE_IPIPE_CFA_ALG_DAA -}; - -/* Structure for CFA Interpolation */ -struct vpfe_ipipe_cfa { - /* 2DirAC or 2DirAC + DAA */ - enum vpfe_ipipe_cfa_alg alg; - /* 2Dir CFA HP value Low Threshold */ - unsigned short hpf_thr_2dir; - /* 2Dir CFA HP value slope */ - unsigned short hpf_slp_2dir; - /* 2Dir CFA HP mix threshold */ - unsigned short hp_mix_thr_2dir; - /* 2Dir CFA HP mix slope */ - unsigned short hp_mix_slope_2dir; - /* 2Dir Direction threshold */ - unsigned short dir_thr_2dir; - /* 2Dir Direction slope */ - unsigned short dir_slope_2dir; - /* 2Dir Non Directional Weight */ - unsigned short nd_wt_2dir; - /* DAA Mono Hue Fraction */ - unsigned short hue_fract_daa; - /* DAA Mono Edge threshold */ - unsigned short edge_thr_daa; - /* DAA Mono threshold minimum */ - unsigned short thr_min_daa; - /* DAA Mono threshold slope */ - unsigned short thr_slope_daa; - /* DAA Mono slope minimum */ - unsigned short slope_min_daa; - /* DAA Mono slope slope */ - unsigned short slope_slope_daa; - /* DAA Mono LP wight */ - unsigned short lp_wt_daa; -}; - -/* Struct for configuring RGB2RGB blending module */ -struct vpfe_ipipe_rgb2rgb { - /* Matrix coefficient for RR S12Q8 for ID = 1 and S11Q8 for ID = 2 */ - struct ipipe_float_s16 coef_rr; - /* Matrix coefficient for GR S12Q8/S11Q8 */ - struct ipipe_float_s16 coef_gr; - /* Matrix coefficient for BR S12Q8/S11Q8 */ - struct ipipe_float_s16 coef_br; - /* Matrix coefficient for RG S12Q8/S11Q8 */ - struct ipipe_float_s16 coef_rg; - /* Matrix coefficient for GG S12Q8/S11Q8 */ - struct ipipe_float_s16 coef_gg; - /* Matrix coefficient for BG S12Q8/S11Q8 */ - struct ipipe_float_s16 coef_bg; - /* Matrix coefficient for RB S12Q8/S11Q8 */ - struct ipipe_float_s16 coef_rb; - /* Matrix coefficient for GB S12Q8/S11Q8 */ - struct ipipe_float_s16 coef_gb; - /* Matrix coefficient for BB S12Q8/S11Q8 */ - struct ipipe_float_s16 coef_bb; - /* Output offset for R S13/S11 */ - int out_ofst_r; - /* Output offset for G S13/S11 */ - int out_ofst_g; - /* Output offset for B S13/S11 */ - int out_ofst_b; -}; - -#define VPFE_IPIPE_MAX_SIZE_GAMMA 512 - -enum vpfe_ipipe_gamma_tbl_size { - VPFE_IPIPE_GAMMA_TBL_SZ_64 = 64, - VPFE_IPIPE_GAMMA_TBL_SZ_128 = 128, - VPFE_IPIPE_GAMMA_TBL_SZ_256 = 256, - VPFE_IPIPE_GAMMA_TBL_SZ_512 = 512, -}; - -enum vpfe_ipipe_gamma_tbl_sel { - VPFE_IPIPE_GAMMA_TBL_RAM = 0, - VPFE_IPIPE_GAMMA_TBL_ROM = 1, -}; - -struct vpfe_ipipe_gamma_entry { - /* 10 bit slope */ - short slope; - /* 10 bit offset */ - unsigned short offset; -}; - -/* Structure for configuring Gamma correction module */ -struct vpfe_ipipe_gamma { - /* 0 - Enable Gamma correction for Red - * 1 - bypass Gamma correction. Data is divided by 16 - */ - unsigned char bypass_r; - /* 0 - Enable Gamma correction for Blue - * 1 - bypass Gamma correction. Data is divided by 16 - */ - unsigned char bypass_b; - /* 0 - Enable Gamma correction for Green - * 1 - bypass Gamma correction. Data is divided by 16 - */ - unsigned char bypass_g; - /* IPIPE_GAMMA_TBL_RAM or IPIPE_GAMMA_TBL_ROM */ - enum vpfe_ipipe_gamma_tbl_sel tbl_sel; - /* Table size for RAM gamma table. - */ - enum vpfe_ipipe_gamma_tbl_size tbl_size; - /* R table */ - struct vpfe_ipipe_gamma_entry table_r[VPFE_IPIPE_MAX_SIZE_GAMMA]; - /* Blue table */ - struct vpfe_ipipe_gamma_entry table_b[VPFE_IPIPE_MAX_SIZE_GAMMA]; - /* Green table */ - struct vpfe_ipipe_gamma_entry table_g[VPFE_IPIPE_MAX_SIZE_GAMMA]; -}; - -#define VPFE_IPIPE_MAX_SIZE_3D_LUT 729 - -struct vpfe_ipipe_3d_lut_entry { - /* 10 bit entry for red */ - unsigned short r; - /* 10 bit entry for green */ - unsigned short g; - /* 10 bit entry for blue */ - unsigned short b; -}; - -/* structure for 3D-LUT */ -struct vpfe_ipipe_3d_lut { - /* enable/disable 3D lut */ - unsigned char en; - /* 3D - LUT table entry */ - struct vpfe_ipipe_3d_lut_entry table[VPFE_IPIPE_MAX_SIZE_3D_LUT]; -}; - -/* Struct for configuring rgb2ycbcr module */ -struct vpfe_ipipe_rgb2yuv { - /* Matrix coefficient for RY S12Q8 */ - struct ipipe_float_s16 coef_ry; - /* Matrix coefficient for GY S12Q8 */ - struct ipipe_float_s16 coef_gy; - /* Matrix coefficient for BY S12Q8 */ - struct ipipe_float_s16 coef_by; - /* Matrix coefficient for RCb S12Q8 */ - struct ipipe_float_s16 coef_rcb; - /* Matrix coefficient for GCb S12Q8 */ - struct ipipe_float_s16 coef_gcb; - /* Matrix coefficient for BCb S12Q8 */ - struct ipipe_float_s16 coef_bcb; - /* Matrix coefficient for RCr S12Q8 */ - struct ipipe_float_s16 coef_rcr; - /* Matrix coefficient for GCr S12Q8 */ - struct ipipe_float_s16 coef_gcr; - /* Matrix coefficient for BCr S12Q8 */ - struct ipipe_float_s16 coef_bcr; - /* Output offset for R S11 */ - int out_ofst_y; - /* Output offset for Cb S11 */ - int out_ofst_cb; - /* Output offset for Cr S11 */ - int out_ofst_cr; -}; - -enum vpfe_ipipe_gbce_type { - VPFE_IPIPE_GBCE_Y_VAL_TBL = 0, - VPFE_IPIPE_GBCE_GAIN_TBL = 1, -}; - -#define VPFE_IPIPE_MAX_SIZE_GBCE_LUT 1024 - -/* structure for Global brightness and Contrast */ -struct vpfe_ipipe_gbce { - /* enable/disable GBCE */ - unsigned char en; - /* Y - value table or Gain table */ - enum vpfe_ipipe_gbce_type type; - /* ptr to LUT for GBCE with 1024 entries */ - unsigned short table[VPFE_IPIPE_MAX_SIZE_GBCE_LUT]; -}; - -/* Chrominance position. Applicable only for YCbCr input - * Applied after edge enhancement - */ -enum vpfe_chr_pos { - /* Co-siting, same position with luminance */ - VPFE_IPIPE_YUV422_CHR_POS_COSITE = 0, - /* Centering, In the middle of luminance */ - VPFE_IPIPE_YUV422_CHR_POS_CENTRE = 1, -}; - -/* Structure for configuring yuv422 conversion module */ -struct vpfe_ipipe_yuv422_conv { - /* Max Chrominance value */ - unsigned char en_chrom_lpf; - /* 1 - enable LPF for chrminance, 0 - disable */ - enum vpfe_chr_pos chrom_pos; -}; - -#define VPFE_IPIPE_MAX_SIZE_YEE_LUT 1024 - -enum vpfe_ipipe_yee_merge_meth { - VPFE_IPIPE_YEE_ABS_MAX = 0, - VPFE_IPIPE_YEE_EE_ES = 1, -}; - -/* Structure for configuring YUV Edge Enhancement module */ -struct vpfe_ipipe_yee { - /* 1 - enable enhancement, 0 - disable */ - unsigned char en; - /* enable/disable halo reduction in edge sharpner */ - unsigned char en_halo_red; - /* Merge method between Edge Enhancer and Edge sharpner */ - enum vpfe_ipipe_yee_merge_meth merge_meth; - /* HPF Shift length */ - unsigned char hpf_shft; - /* HPF Coefficient 00, S10 */ - short hpf_coef_00; - /* HPF Coefficient 01, S10 */ - short hpf_coef_01; - /* HPF Coefficient 02, S10 */ - short hpf_coef_02; - /* HPF Coefficient 10, S10 */ - short hpf_coef_10; - /* HPF Coefficient 11, S10 */ - short hpf_coef_11; - /* HPF Coefficient 12, S10 */ - short hpf_coef_12; - /* HPF Coefficient 20, S10 */ - short hpf_coef_20; - /* HPF Coefficient 21, S10 */ - short hpf_coef_21; - /* HPF Coefficient 22, S10 */ - short hpf_coef_22; - /* Lower threshold before referring to LUT */ - unsigned short yee_thr; - /* Edge sharpener Gain */ - unsigned short es_gain; - /* Edge sharpener lower threshold */ - unsigned short es_thr1; - /* Edge sharpener upper threshold */ - unsigned short es_thr2; - /* Edge sharpener gain on gradient */ - unsigned short es_gain_grad; - /* Edge sharpener offset on gradient */ - unsigned short es_ofst_grad; - /* Ptr to EE table. Must have 1024 entries */ - short table[VPFE_IPIPE_MAX_SIZE_YEE_LUT]; -}; - -enum vpfe_ipipe_car_meth { - /* Chromatic Gain Control */ - VPFE_IPIPE_CAR_CHR_GAIN_CTRL = 0, - /* Dynamic switching between CHR_GAIN_CTRL - * and MED_FLTR - */ - VPFE_IPIPE_CAR_DYN_SWITCH = 1, - /* Median Filter */ - VPFE_IPIPE_CAR_MED_FLTR = 2, -}; - -enum vpfe_ipipe_car_hpf_type { - VPFE_IPIPE_CAR_HPF_Y = 0, - VPFE_IPIPE_CAR_HPF_H = 1, - VPFE_IPIPE_CAR_HPF_V = 2, - VPFE_IPIPE_CAR_HPF_2D = 3, - /* 2D HPF from YUV Edge Enhancement */ - VPFE_IPIPE_CAR_HPF_2D_YEE = 4, -}; - -struct vpfe_ipipe_car_gain { - /* csup_gain */ - unsigned char gain; - /* csup_shf. */ - unsigned char shft; - /* gain minimum */ - unsigned short gain_min; -}; - -/* Structure for Chromatic Artifact Reduction */ -struct vpfe_ipipe_car { - /* enable/disable */ - unsigned char en; - /* Gain control or Dynamic switching */ - enum vpfe_ipipe_car_meth meth; - /* Gain1 function configuration for Gain control */ - struct vpfe_ipipe_car_gain gain1; - /* Gain2 function configuration for Gain control */ - struct vpfe_ipipe_car_gain gain2; - /* HPF type used for CAR */ - enum vpfe_ipipe_car_hpf_type hpf; - /* csup_thr: HPF threshold for Gain control */ - unsigned char hpf_thr; - /* Down shift value for hpf. 2 bits */ - unsigned char hpf_shft; - /* switch limit for median filter */ - unsigned char sw0; - /* switch coefficient for Gain control */ - unsigned char sw1; -}; - -/* structure for Chromatic Gain Suppression */ -struct vpfe_ipipe_cgs { - /* enable/disable */ - unsigned char en; - /* gain1 bright side threshold */ - unsigned char h_thr; - /* gain1 bright side slope */ - unsigned char h_slope; - /* gain1 down shift value for bright side */ - unsigned char h_shft; - /* gain1 bright side minimum gain */ - unsigned char h_min; -}; - -/* Max pixels allowed in the input. If above this either decimation - * or frame division mode to be enabled - */ -#define VPFE_IPIPE_MAX_INPUT_WIDTH 2600 - -struct vpfe_ipipe_input_config { - unsigned int vst; - unsigned int hst; -}; - -/** - * struct vpfe_ipipe_config - IPIPE engine configuration (user) - * @input_config: Pointer to structure for ipipe configuration. - * @flag: Specifies which ISP IPIPE functions should be enabled. - * @lutdpc: Pointer to luma enhancement structure. - * @otfdpc: Pointer to structure for defect correction. - * @nf1: Pointer to structure for Noise Filter. - * @nf2: Pointer to structure for Noise Filter. - * @gic: Pointer to structure for Green Imbalance. - * @wbal: Pointer to structure for White Balance. - * @cfa: Pointer to structure containing the CFA interpolation. - * @rgb2rgb1: Pointer to structure for RGB to RGB Blending. - * @rgb2rgb2: Pointer to structure for RGB to RGB Blending. - * @gamma: Pointer to gamma structure. - * @lut: Pointer to structure for 3D LUT. - * @rgb2yuv: Pointer to structure for RGB-YCbCr conversion. - * @gbce: Pointer to structure for Global Brightness,Contrast Control. - * @yuv422_conv: Pointer to structure for YUV 422 conversion. - * @yee: Pointer to structure for Edge Enhancer. - * @car: Pointer to structure for Chromatic Artifact Reduction. - * @cgs: Pointer to structure for Chromatic Gain Suppression. - */ -struct vpfe_ipipe_config { - __u32 flag; - struct vpfe_ipipe_input_config __user *input_config; - struct vpfe_ipipe_lutdpc __user *lutdpc; - struct vpfe_ipipe_otfdpc __user *otfdpc; - struct vpfe_ipipe_nf __user *nf1; - struct vpfe_ipipe_nf __user *nf2; - struct vpfe_ipipe_gic __user *gic; - struct vpfe_ipipe_wb __user *wbal; - struct vpfe_ipipe_cfa __user *cfa; - struct vpfe_ipipe_rgb2rgb __user *rgb2rgb1; - struct vpfe_ipipe_rgb2rgb __user *rgb2rgb2; - struct vpfe_ipipe_gamma __user *gamma; - struct vpfe_ipipe_3d_lut __user *lut; - struct vpfe_ipipe_rgb2yuv __user *rgb2yuv; - struct vpfe_ipipe_gbce __user *gbce; - struct vpfe_ipipe_yuv422_conv __user *yuv422_conv; - struct vpfe_ipipe_yee __user *yee; - struct vpfe_ipipe_car __user *car; - struct vpfe_ipipe_cgs __user *cgs; -}; - -/******************************************************************* - ** Resizer API structures - *******************************************************************/ -/* Interpolation types used for horizontal rescale */ -enum vpfe_rsz_intp_t { - VPFE_RSZ_INTP_CUBIC, - VPFE_RSZ_INTP_LINEAR -}; - -/* Horizontal LPF intensity selection */ -enum vpfe_rsz_h_lpf_lse_t { - VPFE_RSZ_H_LPF_LSE_INTERN, - VPFE_RSZ_H_LPF_LSE_USER_VAL -}; - -enum vpfe_rsz_down_scale_ave_sz { - VPFE_IPIPE_DWN_SCALE_1_OVER_2, - VPFE_IPIPE_DWN_SCALE_1_OVER_4, - VPFE_IPIPE_DWN_SCALE_1_OVER_8, - VPFE_IPIPE_DWN_SCALE_1_OVER_16, - VPFE_IPIPE_DWN_SCALE_1_OVER_32, - VPFE_IPIPE_DWN_SCALE_1_OVER_64, - VPFE_IPIPE_DWN_SCALE_1_OVER_128, - VPFE_IPIPE_DWN_SCALE_1_OVER_256 -}; - -struct vpfe_rsz_output_spec { - /* enable horizontal flip */ - unsigned char h_flip; - /* enable vertical flip */ - unsigned char v_flip; - /* line start offset for y. */ - unsigned int vst_y; - /* line start offset for c. Only for 420 */ - unsigned int vst_c; - /* vertical rescale interpolation type, YCbCr or Luminance */ - enum vpfe_rsz_intp_t v_typ_y; - /* vertical rescale interpolation type for Chrominance */ - enum vpfe_rsz_intp_t v_typ_c; - /* vertical lpf intensity - Luminance */ - unsigned char v_lpf_int_y; - /* vertical lpf intensity - Chrominance */ - unsigned char v_lpf_int_c; - /* horizontal rescale interpolation types, YCbCr or Luminance */ - enum vpfe_rsz_intp_t h_typ_y; - /* horizontal rescale interpolation types, Chrominance */ - enum vpfe_rsz_intp_t h_typ_c; - /* horizontal lpf intensity - Luminance */ - unsigned char h_lpf_int_y; - /* horizontal lpf intensity - Chrominance */ - unsigned char h_lpf_int_c; - /* Use down scale mode for scale down */ - unsigned char en_down_scale; - /* if downscale, set the downscale more average size for horizontal - * direction. Used only if output width and height is less than - * input sizes - */ - enum vpfe_rsz_down_scale_ave_sz h_dscale_ave_sz; - /* if downscale, set the downscale more average size for vertical - * direction. Used only if output width and height is less than - * input sizes - */ - enum vpfe_rsz_down_scale_ave_sz v_dscale_ave_sz; - /* Y offset. If set, the offset would be added to the base address - */ - unsigned int user_y_ofst; - /* C offset. If set, the offset would be added to the base address - */ - unsigned int user_c_ofst; -}; - -struct vpfe_rsz_config_params { - unsigned int vst; - /* horizontal start position of the image - * data to IPIPE - */ - unsigned int hst; - /* output spec of the image data coming out of resizer - 0(UYVY). - */ - struct vpfe_rsz_output_spec output1; - /* output spec of the image data coming out of resizer - 1(UYVY). - */ - struct vpfe_rsz_output_spec output2; - /* 0 , chroma sample at odd pixel, 1 - even pixel */ - unsigned char chroma_sample_even; - unsigned char frame_div_mode_en; - unsigned char yuv_y_min; - unsigned char yuv_y_max; - unsigned char yuv_c_min; - unsigned char yuv_c_max; - enum vpfe_chr_pos out_chr_pos; - unsigned char bypass; -}; - -/* Structure for VIDIOC_VPFE_RSZ_[S/G]_CONFIG IOCTLs */ -struct vpfe_rsz_config { - struct vpfe_rsz_config_params *config; -}; - -#endif /* _DAVINCI_VPFE_USER_H */ diff --git a/drivers/staging/media/davinci_vpfe/dm365_ipipe.c b/drivers/staging/media/davinci_vpfe/dm365_ipipe.c deleted file mode 100644 index 5d8ba357906b..000000000000 --- a/drivers/staging/media/davinci_vpfe/dm365_ipipe.c +++ /dev/null @@ -1,1857 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2012 Texas Instruments Inc - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Contributors: - * Manjunath Hadli - * Prabhakar Lad - * - * - * IPIPE allows fine tuning of the input image using different - * tuning modules in IPIPE. Some examples :- Noise filter, Defect - * pixel correction etc. It essentially operate on Bayer Raw data - * or YUV raw data. To do image tuning, application call, - * - */ - -#include -#include - -#include "dm365_ipipe.h" -#include "dm365_ipipe_hw.h" -#include "vpfe_mc_capture.h" - -#define MIN_OUT_WIDTH 32 -#define MIN_OUT_HEIGHT 32 - -/* ipipe input format's */ -static const unsigned int ipipe_input_fmts[] = { - MEDIA_BUS_FMT_UYVY8_2X8, - MEDIA_BUS_FMT_SGRBG12_1X12, - MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, - MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8, -}; - -/* ipipe output format's */ -static const unsigned int ipipe_output_fmts[] = { - MEDIA_BUS_FMT_UYVY8_2X8, -}; - -static int ipipe_validate_lutdpc_params(struct vpfe_ipipe_lutdpc *lutdpc) -{ - int i; - - if (lutdpc->en > 1 || lutdpc->repl_white > 1 || - lutdpc->dpc_size > LUT_DPC_MAX_SIZE) - return -EINVAL; - - if (lutdpc->en) - return -EINVAL; - - for (i = 0; i < lutdpc->dpc_size; i++) - if (lutdpc->table[i].horz_pos > LUT_DPC_H_POS_MASK || - lutdpc->table[i].vert_pos > LUT_DPC_V_POS_MASK) - return -EINVAL; - - return 0; -} - -static int ipipe_set_lutdpc_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_lutdpc *lutdpc = &ipipe->config.lutdpc; - struct vpfe_ipipe_lutdpc *dpc_param; - - if (!param) { - memset((void *)lutdpc, 0, sizeof(struct vpfe_ipipe_lutdpc)); - goto success; - } - - dpc_param = param; - lutdpc->en = dpc_param->en; - lutdpc->repl_white = dpc_param->repl_white; - lutdpc->dpc_size = dpc_param->dpc_size; - memcpy(&lutdpc->table, &dpc_param->table, - (dpc_param->dpc_size * sizeof(struct vpfe_ipipe_lutdpc_entry))); - if (ipipe_validate_lutdpc_params(lutdpc) < 0) - return -EINVAL; - -success: - ipipe_set_lutdpc_regs(ipipe->base_addr, ipipe->isp5_base_addr, lutdpc); - - return 0; -} - -static int ipipe_get_lutdpc_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_lutdpc *lut_param = param; - struct vpfe_ipipe_lutdpc *lutdpc = &ipipe->config.lutdpc; - - lut_param->en = lutdpc->en; - lut_param->repl_white = lutdpc->repl_white; - lut_param->dpc_size = lutdpc->dpc_size; - memcpy(&lut_param->table, &lutdpc->table, - (lutdpc->dpc_size * sizeof(struct vpfe_ipipe_lutdpc_entry))); - - return 0; -} - -static int ipipe_set_input_config(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_input_config *config = &ipipe->config.input_config; - - if (!param) - memset(config, 0, sizeof(struct vpfe_ipipe_input_config)); - else - memcpy(config, param, sizeof(struct vpfe_ipipe_input_config)); - return 0; -} - -static int ipipe_get_input_config(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_input_config *config = &ipipe->config.input_config; - - if (!param) - return -EINVAL; - - memcpy(param, config, sizeof(struct vpfe_ipipe_input_config)); - - return 0; -} - -static int ipipe_validate_otfdpc_params(struct vpfe_ipipe_otfdpc *dpc_param) -{ - struct vpfe_ipipe_otfdpc_2_0_cfg *dpc_2_0; - struct vpfe_ipipe_otfdpc_3_0_cfg *dpc_3_0; - - if (dpc_param->en > 1) - return -EINVAL; - - if (dpc_param->alg == VPFE_IPIPE_OTFDPC_2_0) { - dpc_2_0 = &dpc_param->alg_cfg.dpc_2_0; - if (dpc_2_0->det_thr.r > OTFDPC_DPC2_THR_MASK || - dpc_2_0->det_thr.gr > OTFDPC_DPC2_THR_MASK || - dpc_2_0->det_thr.gb > OTFDPC_DPC2_THR_MASK || - dpc_2_0->det_thr.b > OTFDPC_DPC2_THR_MASK || - dpc_2_0->corr_thr.r > OTFDPC_DPC2_THR_MASK || - dpc_2_0->corr_thr.gr > OTFDPC_DPC2_THR_MASK || - dpc_2_0->corr_thr.gb > OTFDPC_DPC2_THR_MASK || - dpc_2_0->corr_thr.b > OTFDPC_DPC2_THR_MASK) - return -EINVAL; - return 0; - } - - dpc_3_0 = &dpc_param->alg_cfg.dpc_3_0; - - if (dpc_3_0->act_adj_shf > OTF_DPC3_0_SHF_MASK || - dpc_3_0->det_thr > OTF_DPC3_0_DET_MASK || - dpc_3_0->det_slp > OTF_DPC3_0_SLP_MASK || - dpc_3_0->det_thr_min > OTF_DPC3_0_DET_MASK || - dpc_3_0->det_thr_max > OTF_DPC3_0_DET_MASK || - dpc_3_0->corr_thr > OTF_DPC3_0_CORR_MASK || - dpc_3_0->corr_slp > OTF_DPC3_0_SLP_MASK || - dpc_3_0->corr_thr_min > OTF_DPC3_0_CORR_MASK || - dpc_3_0->corr_thr_max > OTF_DPC3_0_CORR_MASK) - return -EINVAL; - - return 0; -} - -static int ipipe_set_otfdpc_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_otfdpc *dpc_param = param; - struct vpfe_ipipe_otfdpc *otfdpc = &ipipe->config.otfdpc; - struct device *dev; - - if (!param) { - memset((void *)otfdpc, 0, sizeof(struct ipipe_otfdpc_2_0)); - goto success; - } - dev = ipipe->subdev.v4l2_dev->dev; - memcpy(otfdpc, dpc_param, sizeof(struct vpfe_ipipe_otfdpc)); - if (ipipe_validate_otfdpc_params(otfdpc) < 0) { - dev_err(dev, "Invalid otfdpc params\n"); - return -EINVAL; - } - -success: - ipipe_set_otfdpc_regs(ipipe->base_addr, otfdpc); - - return 0; -} - -static int ipipe_get_otfdpc_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_otfdpc *dpc_param = param; - struct vpfe_ipipe_otfdpc *otfdpc = &ipipe->config.otfdpc; - - memcpy(dpc_param, otfdpc, sizeof(struct vpfe_ipipe_otfdpc)); - return 0; -} - -static int ipipe_validate_nf_params(struct vpfe_ipipe_nf *nf_param) -{ - int i; - - if (nf_param->en > 1 || nf_param->shft_val > D2F_SHFT_VAL_MASK || - nf_param->spread_val > D2F_SPR_VAL_MASK || - nf_param->apply_lsc_gain > 1 || - nf_param->edge_det_min_thr > D2F_EDGE_DET_THR_MASK || - nf_param->edge_det_max_thr > D2F_EDGE_DET_THR_MASK) - return -EINVAL; - - for (i = 0; i < VPFE_IPIPE_NF_THR_TABLE_SIZE; i++) - if (nf_param->thr[i] > D2F_THR_VAL_MASK) - return -EINVAL; - - for (i = 0; i < VPFE_IPIPE_NF_STR_TABLE_SIZE; i++) - if (nf_param->str[i] > D2F_STR_VAL_MASK) - return -EINVAL; - - return 0; -} - -static int ipipe_set_nf_params(struct vpfe_ipipe_device *ipipe, - unsigned int id, void *param) -{ - struct vpfe_ipipe_nf *nf_param = param; - struct vpfe_ipipe_nf *nf = &ipipe->config.nf1; - struct device *dev; - - if (id == IPIPE_D2F_2ND) - nf = &ipipe->config.nf2; - - if (!nf_param) { - memset((void *)nf, 0, sizeof(struct vpfe_ipipe_nf)); - goto success; - } - - dev = ipipe->subdev.v4l2_dev->dev; - memcpy(nf, nf_param, sizeof(struct vpfe_ipipe_nf)); - if (ipipe_validate_nf_params(nf) < 0) { - dev_err(dev, "Invalid nf params\n"); - return -EINVAL; - } - -success: - ipipe_set_d2f_regs(ipipe->base_addr, id, nf); - - return 0; -} - -static int ipipe_set_nf1_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - return ipipe_set_nf_params(ipipe, IPIPE_D2F_1ST, param); -} - -static int ipipe_set_nf2_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - return ipipe_set_nf_params(ipipe, IPIPE_D2F_2ND, param); -} - -static int ipipe_get_nf_params(struct vpfe_ipipe_device *ipipe, - unsigned int id, void *param) -{ - struct vpfe_ipipe_nf *nf_param = param; - struct vpfe_ipipe_nf *nf = &ipipe->config.nf1; - - if (id == IPIPE_D2F_2ND) - nf = &ipipe->config.nf2; - - memcpy(nf_param, nf, sizeof(struct vpfe_ipipe_nf)); - - return 0; -} - -static int ipipe_get_nf1_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - return ipipe_get_nf_params(ipipe, IPIPE_D2F_1ST, param); -} - -static int ipipe_get_nf2_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - return ipipe_get_nf_params(ipipe, IPIPE_D2F_2ND, param); -} - -static int ipipe_validate_gic_params(struct vpfe_ipipe_gic *gic) -{ - if (gic->en > 1 || gic->gain > GIC_GAIN_MASK || - gic->thr > GIC_THR_MASK || gic->slope > GIC_SLOPE_MASK || - gic->apply_lsc_gain > 1 || - gic->nf2_thr_gain.integer > GIC_NFGAN_INT_MASK || - gic->nf2_thr_gain.decimal > GIC_NFGAN_DECI_MASK) - return -EINVAL; - - return 0; -} - -static int ipipe_set_gic_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_gic *gic_param = param; - struct device *dev = ipipe->subdev.v4l2_dev->dev; - struct vpfe_ipipe_gic *gic = &ipipe->config.gic; - - if (!gic_param) { - memset((void *)gic, 0, sizeof(struct vpfe_ipipe_gic)); - goto success; - } - - memcpy(gic, gic_param, sizeof(struct vpfe_ipipe_gic)); - if (ipipe_validate_gic_params(gic) < 0) { - dev_err(dev, "Invalid gic params\n"); - return -EINVAL; - } - -success: - ipipe_set_gic_regs(ipipe->base_addr, gic); - - return 0; -} - -static int ipipe_get_gic_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_gic *gic_param = param; - struct vpfe_ipipe_gic *gic = &ipipe->config.gic; - - memcpy(gic_param, gic, sizeof(struct vpfe_ipipe_gic)); - - return 0; -} - -static int ipipe_validate_wb_params(struct vpfe_ipipe_wb *wbal) -{ - if (wbal->ofst_r > WB_OFFSET_MASK || - wbal->ofst_gr > WB_OFFSET_MASK || - wbal->ofst_gb > WB_OFFSET_MASK || - wbal->ofst_b > WB_OFFSET_MASK || - wbal->gain_r.integer > WB_GAIN_INT_MASK || - wbal->gain_r.decimal > WB_GAIN_DECI_MASK || - wbal->gain_gr.integer > WB_GAIN_INT_MASK || - wbal->gain_gr.decimal > WB_GAIN_DECI_MASK || - wbal->gain_gb.integer > WB_GAIN_INT_MASK || - wbal->gain_gb.decimal > WB_GAIN_DECI_MASK || - wbal->gain_b.integer > WB_GAIN_INT_MASK || - wbal->gain_b.decimal > WB_GAIN_DECI_MASK) - return -EINVAL; - - return 0; -} - -static int ipipe_set_wb_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_wb *wb_param = param; - struct vpfe_ipipe_wb *wbal = &ipipe->config.wbal; - - if (!wb_param) { - const struct vpfe_ipipe_wb wb_defaults = { - .gain_r = {2, 0x0}, - .gain_gr = {2, 0x0}, - .gain_gb = {2, 0x0}, - .gain_b = {2, 0x0} - }; - memcpy(wbal, &wb_defaults, sizeof(struct vpfe_ipipe_wb)); - goto success; - } - - memcpy(wbal, wb_param, sizeof(struct vpfe_ipipe_wb)); - if (ipipe_validate_wb_params(wbal) < 0) - return -EINVAL; - -success: - ipipe_set_wb_regs(ipipe->base_addr, wbal); - - return 0; -} - -static int ipipe_get_wb_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_wb *wb_param = param; - struct vpfe_ipipe_wb *wbal = &ipipe->config.wbal; - - memcpy(wb_param, wbal, sizeof(struct vpfe_ipipe_wb)); - return 0; -} - -static int ipipe_validate_cfa_params(struct vpfe_ipipe_cfa *cfa) -{ - if (cfa->hpf_thr_2dir > CFA_HPF_THR_2DIR_MASK || - cfa->hpf_slp_2dir > CFA_HPF_SLOPE_2DIR_MASK || - cfa->hp_mix_thr_2dir > CFA_HPF_MIX_THR_2DIR_MASK || - cfa->hp_mix_slope_2dir > CFA_HPF_MIX_SLP_2DIR_MASK || - cfa->dir_thr_2dir > CFA_DIR_THR_2DIR_MASK || - cfa->dir_slope_2dir > CFA_DIR_SLP_2DIR_MASK || - cfa->nd_wt_2dir > CFA_ND_WT_2DIR_MASK || - cfa->hue_fract_daa > CFA_DAA_HUE_FRA_MASK || - cfa->edge_thr_daa > CFA_DAA_EDG_THR_MASK || - cfa->thr_min_daa > CFA_DAA_THR_MIN_MASK || - cfa->thr_slope_daa > CFA_DAA_THR_SLP_MASK || - cfa->slope_min_daa > CFA_DAA_SLP_MIN_MASK || - cfa->slope_slope_daa > CFA_DAA_SLP_SLP_MASK || - cfa->lp_wt_daa > CFA_DAA_LP_WT_MASK) - return -EINVAL; - - return 0; -} - -static int ipipe_set_cfa_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_cfa *cfa_param = param; - struct vpfe_ipipe_cfa *cfa = &ipipe->config.cfa; - - if (!cfa_param) { - memset(cfa, 0, sizeof(struct vpfe_ipipe_cfa)); - cfa->alg = VPFE_IPIPE_CFA_ALG_2DIRAC; - goto success; - } - - memcpy(cfa, cfa_param, sizeof(struct vpfe_ipipe_cfa)); - if (ipipe_validate_cfa_params(cfa) < 0) - return -EINVAL; - -success: - ipipe_set_cfa_regs(ipipe->base_addr, cfa); - - return 0; -} - -static int ipipe_get_cfa_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_cfa *cfa_param = param; - struct vpfe_ipipe_cfa *cfa = &ipipe->config.cfa; - - memcpy(cfa_param, cfa, sizeof(struct vpfe_ipipe_cfa)); - return 0; -} - -static int -ipipe_validate_rgb2rgb_params(struct vpfe_ipipe_rgb2rgb *rgb2rgb, - unsigned int id) -{ - u32 gain_int_upper = RGB2RGB_1_GAIN_INT_MASK; - u32 offset_upper = RGB2RGB_1_OFST_MASK; - - if (id == IPIPE_RGB2RGB_2) { - offset_upper = RGB2RGB_2_OFST_MASK; - gain_int_upper = RGB2RGB_2_GAIN_INT_MASK; - } - - if (rgb2rgb->coef_rr.decimal > RGB2RGB_GAIN_DECI_MASK || - rgb2rgb->coef_rr.integer > gain_int_upper) - return -EINVAL; - - if (rgb2rgb->coef_gr.decimal > RGB2RGB_GAIN_DECI_MASK || - rgb2rgb->coef_gr.integer > gain_int_upper) - return -EINVAL; - - if (rgb2rgb->coef_br.decimal > RGB2RGB_GAIN_DECI_MASK || - rgb2rgb->coef_br.integer > gain_int_upper) - return -EINVAL; - - if (rgb2rgb->coef_rg.decimal > RGB2RGB_GAIN_DECI_MASK || - rgb2rgb->coef_rg.integer > gain_int_upper) - return -EINVAL; - - if (rgb2rgb->coef_gg.decimal > RGB2RGB_GAIN_DECI_MASK || - rgb2rgb->coef_gg.integer > gain_int_upper) - return -EINVAL; - - if (rgb2rgb->coef_bg.decimal > RGB2RGB_GAIN_DECI_MASK || - rgb2rgb->coef_bg.integer > gain_int_upper) - return -EINVAL; - - if (rgb2rgb->coef_rb.decimal > RGB2RGB_GAIN_DECI_MASK || - rgb2rgb->coef_rb.integer > gain_int_upper) - return -EINVAL; - - if (rgb2rgb->coef_gb.decimal > RGB2RGB_GAIN_DECI_MASK || - rgb2rgb->coef_gb.integer > gain_int_upper) - return -EINVAL; - - if (rgb2rgb->coef_bb.decimal > RGB2RGB_GAIN_DECI_MASK || - rgb2rgb->coef_bb.integer > gain_int_upper) - return -EINVAL; - - if (rgb2rgb->out_ofst_r > offset_upper || - rgb2rgb->out_ofst_g > offset_upper || - rgb2rgb->out_ofst_b > offset_upper) - return -EINVAL; - - return 0; -} - -static int ipipe_set_rgb2rgb_params(struct vpfe_ipipe_device *ipipe, - unsigned int id, void *param) -{ - struct vpfe_ipipe_rgb2rgb *rgb2rgb = &ipipe->config.rgb2rgb1; - struct device *dev = ipipe->subdev.v4l2_dev->dev; - struct vpfe_ipipe_rgb2rgb *rgb2rgb_param; - - rgb2rgb_param = param; - - if (id == IPIPE_RGB2RGB_2) - rgb2rgb = &ipipe->config.rgb2rgb2; - - if (!rgb2rgb_param) { - const struct vpfe_ipipe_rgb2rgb rgb2rgb_defaults = { - .coef_rr = {1, 0}, /* 256 */ - .coef_gr = {0, 0}, - .coef_br = {0, 0}, - .coef_rg = {0, 0}, - .coef_gg = {1, 0}, /* 256 */ - .coef_bg = {0, 0}, - .coef_rb = {0, 0}, - .coef_gb = {0, 0}, - .coef_bb = {1, 0}, /* 256 */ - }; - /* Copy defaults for rgb2rgb conversion */ - memcpy(rgb2rgb, &rgb2rgb_defaults, - sizeof(struct vpfe_ipipe_rgb2rgb)); - goto success; - } - - memcpy(rgb2rgb, rgb2rgb_param, sizeof(struct vpfe_ipipe_rgb2rgb)); - if (ipipe_validate_rgb2rgb_params(rgb2rgb, id) < 0) { - dev_err(dev, "Invalid rgb2rgb params\n"); - return -EINVAL; - } - -success: - ipipe_set_rgb2rgb_regs(ipipe->base_addr, id, rgb2rgb); - - return 0; -} - -static int -ipipe_set_rgb2rgb_1_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - return ipipe_set_rgb2rgb_params(ipipe, IPIPE_RGB2RGB_1, param); -} - -static int -ipipe_set_rgb2rgb_2_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - return ipipe_set_rgb2rgb_params(ipipe, IPIPE_RGB2RGB_2, param); -} - -static int ipipe_get_rgb2rgb_params(struct vpfe_ipipe_device *ipipe, - unsigned int id, void *param) -{ - struct vpfe_ipipe_rgb2rgb *rgb2rgb = &ipipe->config.rgb2rgb1; - struct vpfe_ipipe_rgb2rgb *rgb2rgb_param; - - rgb2rgb_param = param; - - if (id == IPIPE_RGB2RGB_2) - rgb2rgb = &ipipe->config.rgb2rgb2; - - memcpy(rgb2rgb_param, rgb2rgb, sizeof(struct vpfe_ipipe_rgb2rgb)); - - return 0; -} - -static int -ipipe_get_rgb2rgb_1_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - return ipipe_get_rgb2rgb_params(ipipe, IPIPE_RGB2RGB_1, param); -} - -static int -ipipe_get_rgb2rgb_2_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - return ipipe_get_rgb2rgb_params(ipipe, IPIPE_RGB2RGB_2, param); -} - -static int -ipipe_validate_gamma_entry(struct vpfe_ipipe_gamma_entry *table, int size) -{ - int i; - - if (!table) - return -EINVAL; - - for (i = 0; i < size; i++) - if (table[i].slope > GAMMA_MASK || - table[i].offset > GAMMA_MASK) - return -EINVAL; - - return 0; -} - -static int -ipipe_validate_gamma_params(struct vpfe_ipipe_gamma *gamma, struct device *dev) -{ - int table_size; - int err; - - if (gamma->bypass_r > 1 || - gamma->bypass_b > 1 || - gamma->bypass_g > 1) - return -EINVAL; - - if (gamma->tbl_sel != VPFE_IPIPE_GAMMA_TBL_RAM) - return 0; - - table_size = gamma->tbl_size; - if (!gamma->bypass_r) { - err = ipipe_validate_gamma_entry(gamma->table_r, table_size); - if (err) { - dev_err(dev, "GAMMA R - table entry invalid\n"); - return err; - } - } - - if (!gamma->bypass_b) { - err = ipipe_validate_gamma_entry(gamma->table_b, table_size); - if (err) { - dev_err(dev, "GAMMA B - table entry invalid\n"); - return err; - } - } - - if (!gamma->bypass_g) { - err = ipipe_validate_gamma_entry(gamma->table_g, table_size); - if (err) { - dev_err(dev, "GAMMA G - table entry invalid\n"); - return err; - } - } - - return 0; -} - -static int -ipipe_set_gamma_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_gamma *gamma_param = param; - struct vpfe_ipipe_gamma *gamma = &ipipe->config.gamma; - struct device *dev = ipipe->subdev.v4l2_dev->dev; - int table_size; - - if (!gamma_param) { - memset(gamma, 0, sizeof(struct vpfe_ipipe_gamma)); - gamma->tbl_sel = VPFE_IPIPE_GAMMA_TBL_ROM; - goto success; - } - - gamma->bypass_r = gamma_param->bypass_r; - gamma->bypass_b = gamma_param->bypass_b; - gamma->bypass_g = gamma_param->bypass_g; - gamma->tbl_sel = gamma_param->tbl_sel; - gamma->tbl_size = gamma_param->tbl_size; - - if (ipipe_validate_gamma_params(gamma, dev) < 0) - return -EINVAL; - - if (gamma_param->tbl_sel != VPFE_IPIPE_GAMMA_TBL_RAM) - goto success; - - table_size = gamma->tbl_size; - if (!gamma_param->bypass_r) - memcpy(&gamma->table_r, &gamma_param->table_r, - (table_size * sizeof(struct vpfe_ipipe_gamma_entry))); - - if (!gamma_param->bypass_b) - memcpy(&gamma->table_b, &gamma_param->table_b, - (table_size * sizeof(struct vpfe_ipipe_gamma_entry))); - - if (!gamma_param->bypass_g) - memcpy(&gamma->table_g, &gamma_param->table_g, - (table_size * sizeof(struct vpfe_ipipe_gamma_entry))); - -success: - ipipe_set_gamma_regs(ipipe->base_addr, ipipe->isp5_base_addr, gamma); - - return 0; -} - -static int ipipe_get_gamma_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_gamma *gamma_param = param; - struct vpfe_ipipe_gamma *gamma = &ipipe->config.gamma; - struct device *dev = ipipe->subdev.v4l2_dev->dev; - int table_size; - - gamma_param->bypass_r = gamma->bypass_r; - gamma_param->bypass_g = gamma->bypass_g; - gamma_param->bypass_b = gamma->bypass_b; - gamma_param->tbl_sel = gamma->tbl_sel; - gamma_param->tbl_size = gamma->tbl_size; - - if (gamma->tbl_sel != VPFE_IPIPE_GAMMA_TBL_RAM) - return 0; - - table_size = gamma->tbl_size; - - if (!gamma->bypass_r) { - dev_err(dev, - "%s: table ptr empty for R\n", __func__); - return -EINVAL; - } - memcpy(gamma_param->table_r, gamma->table_r, - (table_size * sizeof(struct vpfe_ipipe_gamma_entry))); - - if (!gamma->bypass_g) { - dev_err(dev, "%s: table ptr empty for G\n", __func__); - return -EINVAL; - } - memcpy(gamma_param->table_g, gamma->table_g, - (table_size * sizeof(struct vpfe_ipipe_gamma_entry))); - - if (!gamma->bypass_b) { - dev_err(dev, "%s: table ptr empty for B\n", __func__); - return -EINVAL; - } - memcpy(gamma_param->table_b, gamma->table_b, - (table_size * sizeof(struct vpfe_ipipe_gamma_entry))); - - return 0; -} - -static int ipipe_validate_3d_lut_params(struct vpfe_ipipe_3d_lut *lut) -{ - int i; - - if (!lut->en) - return 0; - - for (i = 0; i < VPFE_IPIPE_MAX_SIZE_3D_LUT; i++) - if (lut->table[i].r > D3_LUT_ENTRY_MASK || - lut->table[i].g > D3_LUT_ENTRY_MASK || - lut->table[i].b > D3_LUT_ENTRY_MASK) - return -EINVAL; - - return 0; -} - -static int ipipe_get_3d_lut_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_3d_lut *lut_param = param; - struct vpfe_ipipe_3d_lut *lut = &ipipe->config.lut; - - lut_param->en = lut->en; - - memcpy(lut_param->table, &lut->table, - (VPFE_IPIPE_MAX_SIZE_3D_LUT * - sizeof(struct vpfe_ipipe_3d_lut_entry))); - - return 0; -} - -static int -ipipe_set_3d_lut_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_3d_lut *lut_param = param; - struct vpfe_ipipe_3d_lut *lut = &ipipe->config.lut; - struct device *dev = ipipe->subdev.v4l2_dev->dev; - - if (!lut_param) { - memset(lut, 0, sizeof(struct vpfe_ipipe_3d_lut)); - goto success; - } - - memcpy(lut, lut_param, sizeof(struct vpfe_ipipe_3d_lut)); - if (ipipe_validate_3d_lut_params(lut) < 0) { - dev_err(dev, "Invalid 3D-LUT Params\n"); - return -EINVAL; - } - -success: - ipipe_set_3d_lut_regs(ipipe->base_addr, ipipe->isp5_base_addr, lut); - - return 0; -} - -static int ipipe_validate_rgb2yuv_params(struct vpfe_ipipe_rgb2yuv *rgb2yuv) -{ - if (rgb2yuv->coef_ry.decimal > RGB2YCBCR_COEF_DECI_MASK || - rgb2yuv->coef_ry.integer > RGB2YCBCR_COEF_INT_MASK) - return -EINVAL; - - if (rgb2yuv->coef_gy.decimal > RGB2YCBCR_COEF_DECI_MASK || - rgb2yuv->coef_gy.integer > RGB2YCBCR_COEF_INT_MASK) - return -EINVAL; - - if (rgb2yuv->coef_by.decimal > RGB2YCBCR_COEF_DECI_MASK || - rgb2yuv->coef_by.integer > RGB2YCBCR_COEF_INT_MASK) - return -EINVAL; - - if (rgb2yuv->coef_rcb.decimal > RGB2YCBCR_COEF_DECI_MASK || - rgb2yuv->coef_rcb.integer > RGB2YCBCR_COEF_INT_MASK) - return -EINVAL; - - if (rgb2yuv->coef_gcb.decimal > RGB2YCBCR_COEF_DECI_MASK || - rgb2yuv->coef_gcb.integer > RGB2YCBCR_COEF_INT_MASK) - return -EINVAL; - - if (rgb2yuv->coef_bcb.decimal > RGB2YCBCR_COEF_DECI_MASK || - rgb2yuv->coef_bcb.integer > RGB2YCBCR_COEF_INT_MASK) - return -EINVAL; - - if (rgb2yuv->coef_rcr.decimal > RGB2YCBCR_COEF_DECI_MASK || - rgb2yuv->coef_rcr.integer > RGB2YCBCR_COEF_INT_MASK) - return -EINVAL; - - if (rgb2yuv->coef_gcr.decimal > RGB2YCBCR_COEF_DECI_MASK || - rgb2yuv->coef_gcr.integer > RGB2YCBCR_COEF_INT_MASK) - return -EINVAL; - - if (rgb2yuv->coef_bcr.decimal > RGB2YCBCR_COEF_DECI_MASK || - rgb2yuv->coef_bcr.integer > RGB2YCBCR_COEF_INT_MASK) - return -EINVAL; - - if (rgb2yuv->out_ofst_y > RGB2YCBCR_OFST_MASK || - rgb2yuv->out_ofst_cb > RGB2YCBCR_OFST_MASK || - rgb2yuv->out_ofst_cr > RGB2YCBCR_OFST_MASK) - return -EINVAL; - - return 0; -} - -static int -ipipe_set_rgb2yuv_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_rgb2yuv *rgb2yuv = &ipipe->config.rgb2yuv; - struct device *dev = ipipe->subdev.v4l2_dev->dev; - struct vpfe_ipipe_rgb2yuv *rgb2yuv_param; - - rgb2yuv_param = param; - if (!rgb2yuv_param) { - /* Defaults for rgb2yuv conversion */ - const struct vpfe_ipipe_rgb2yuv rgb2yuv_defaults = { - .coef_ry = {0, 0x4d}, - .coef_gy = {0, 0x96}, - .coef_by = {0, 0x1d}, - .coef_rcb = {0xf, 0xd5}, - .coef_gcb = {0xf, 0xab}, - .coef_bcb = {0, 0x80}, - .coef_rcr = {0, 0x80}, - .coef_gcr = {0xf, 0x95}, - .coef_bcr = {0xf, 0xeb}, - .out_ofst_cb = 0x80, - .out_ofst_cr = 0x80, - }; - /* Copy defaults for rgb2yuv conversion */ - memcpy(rgb2yuv, &rgb2yuv_defaults, - sizeof(struct vpfe_ipipe_rgb2yuv)); - goto success; - } - - memcpy(rgb2yuv, rgb2yuv_param, sizeof(struct vpfe_ipipe_rgb2yuv)); - if (ipipe_validate_rgb2yuv_params(rgb2yuv) < 0) { - dev_err(dev, "Invalid rgb2yuv params\n"); - return -EINVAL; - } - -success: - ipipe_set_rgb2ycbcr_regs(ipipe->base_addr, rgb2yuv); - - return 0; -} - -static int -ipipe_get_rgb2yuv_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_rgb2yuv *rgb2yuv = &ipipe->config.rgb2yuv; - struct vpfe_ipipe_rgb2yuv *rgb2yuv_param; - - rgb2yuv_param = param; - memcpy(rgb2yuv_param, rgb2yuv, sizeof(struct vpfe_ipipe_rgb2yuv)); - return 0; -} - -static int ipipe_validate_gbce_params(struct vpfe_ipipe_gbce *gbce) -{ - u32 max = GBCE_Y_VAL_MASK; - int i; - - if (!gbce->en) - return 0; - - if (gbce->type == VPFE_IPIPE_GBCE_GAIN_TBL) - max = GBCE_GAIN_VAL_MASK; - - for (i = 0; i < VPFE_IPIPE_MAX_SIZE_GBCE_LUT; i++) - if (gbce->table[i] > max) - return -EINVAL; - - return 0; -} - -static int ipipe_set_gbce_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_gbce *gbce_param = param; - struct vpfe_ipipe_gbce *gbce = &ipipe->config.gbce; - struct device *dev = ipipe->subdev.v4l2_dev->dev; - - if (!gbce_param) { - memset(gbce, 0, sizeof(struct vpfe_ipipe_gbce)); - } else { - memcpy(gbce, gbce_param, sizeof(struct vpfe_ipipe_gbce)); - if (ipipe_validate_gbce_params(gbce) < 0) { - dev_err(dev, "Invalid gbce params\n"); - return -EINVAL; - } - } - - ipipe_set_gbce_regs(ipipe->base_addr, ipipe->isp5_base_addr, gbce); - - return 0; -} - -static int ipipe_get_gbce_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_gbce *gbce_param = param; - struct vpfe_ipipe_gbce *gbce = &ipipe->config.gbce; - - gbce_param->en = gbce->en; - gbce_param->type = gbce->type; - - memcpy(gbce_param->table, gbce->table, - (VPFE_IPIPE_MAX_SIZE_GBCE_LUT * sizeof(unsigned short))); - - return 0; -} - -static int -ipipe_validate_yuv422_conv_params(struct vpfe_ipipe_yuv422_conv *yuv422_conv) -{ - if (yuv422_conv->en_chrom_lpf > 1) - return -EINVAL; - - return 0; -} - -static int -ipipe_set_yuv422_conv_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_yuv422_conv *yuv422_conv = &ipipe->config.yuv422_conv; - struct vpfe_ipipe_yuv422_conv *yuv422_conv_param; - struct device *dev = ipipe->subdev.v4l2_dev->dev; - - yuv422_conv_param = param; - if (!yuv422_conv_param) { - memset(yuv422_conv, 0, sizeof(struct vpfe_ipipe_yuv422_conv)); - yuv422_conv->chrom_pos = VPFE_IPIPE_YUV422_CHR_POS_COSITE; - } else { - memcpy(yuv422_conv, yuv422_conv_param, - sizeof(struct vpfe_ipipe_yuv422_conv)); - if (ipipe_validate_yuv422_conv_params(yuv422_conv) < 0) { - dev_err(dev, "Invalid yuv422 params\n"); - return -EINVAL; - } - } - - ipipe_set_yuv422_conv_regs(ipipe->base_addr, yuv422_conv); - - return 0; -} - -static int -ipipe_get_yuv422_conv_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_yuv422_conv *yuv422_conv = &ipipe->config.yuv422_conv; - struct vpfe_ipipe_yuv422_conv *yuv422_conv_param; - - yuv422_conv_param = param; - memcpy(yuv422_conv_param, yuv422_conv, - sizeof(struct vpfe_ipipe_yuv422_conv)); - - return 0; -} - -static int ipipe_validate_yee_params(struct vpfe_ipipe_yee *yee) -{ - int i; - - if (yee->en > 1 || - yee->en_halo_red > 1 || - yee->hpf_shft > YEE_HPF_SHIFT_MASK) - return -EINVAL; - - if (yee->hpf_coef_00 > YEE_COEF_MASK || - yee->hpf_coef_01 > YEE_COEF_MASK || - yee->hpf_coef_02 > YEE_COEF_MASK || - yee->hpf_coef_10 > YEE_COEF_MASK || - yee->hpf_coef_11 > YEE_COEF_MASK || - yee->hpf_coef_12 > YEE_COEF_MASK || - yee->hpf_coef_20 > YEE_COEF_MASK || - yee->hpf_coef_21 > YEE_COEF_MASK || - yee->hpf_coef_22 > YEE_COEF_MASK) - return -EINVAL; - - if (yee->yee_thr > YEE_THR_MASK || - yee->es_gain > YEE_ES_GAIN_MASK || - yee->es_thr1 > YEE_ES_THR1_MASK || - yee->es_thr2 > YEE_THR_MASK || - yee->es_gain_grad > YEE_THR_MASK || - yee->es_ofst_grad > YEE_THR_MASK) - return -EINVAL; - - for (i = 0; i < VPFE_IPIPE_MAX_SIZE_YEE_LUT; i++) - if (yee->table[i] > YEE_ENTRY_MASK) - return -EINVAL; - - return 0; -} - -static int ipipe_set_yee_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_yee *yee_param = param; - struct device *dev = ipipe->subdev.v4l2_dev->dev; - struct vpfe_ipipe_yee *yee = &ipipe->config.yee; - - if (!yee_param) { - memset(yee, 0, sizeof(struct vpfe_ipipe_yee)); - } else { - memcpy(yee, yee_param, sizeof(struct vpfe_ipipe_yee)); - if (ipipe_validate_yee_params(yee) < 0) { - dev_err(dev, "Invalid yee params\n"); - return -EINVAL; - } - } - - ipipe_set_ee_regs(ipipe->base_addr, ipipe->isp5_base_addr, yee); - - return 0; -} - -static int ipipe_get_yee_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_yee *yee_param = param; - struct vpfe_ipipe_yee *yee = &ipipe->config.yee; - - yee_param->en = yee->en; - yee_param->en_halo_red = yee->en_halo_red; - yee_param->merge_meth = yee->merge_meth; - yee_param->hpf_shft = yee->hpf_shft; - yee_param->hpf_coef_00 = yee->hpf_coef_00; - yee_param->hpf_coef_01 = yee->hpf_coef_01; - yee_param->hpf_coef_02 = yee->hpf_coef_02; - yee_param->hpf_coef_10 = yee->hpf_coef_10; - yee_param->hpf_coef_11 = yee->hpf_coef_11; - yee_param->hpf_coef_12 = yee->hpf_coef_12; - yee_param->hpf_coef_20 = yee->hpf_coef_20; - yee_param->hpf_coef_21 = yee->hpf_coef_21; - yee_param->hpf_coef_22 = yee->hpf_coef_22; - yee_param->yee_thr = yee->yee_thr; - yee_param->es_gain = yee->es_gain; - yee_param->es_thr1 = yee->es_thr1; - yee_param->es_thr2 = yee->es_thr2; - yee_param->es_gain_grad = yee->es_gain_grad; - yee_param->es_ofst_grad = yee->es_ofst_grad; - memcpy(yee_param->table, &yee->table, - (VPFE_IPIPE_MAX_SIZE_YEE_LUT * sizeof(short))); - - return 0; -} - -static int ipipe_validate_car_params(struct vpfe_ipipe_car *car) -{ - if (car->en > 1 || car->hpf_shft > CAR_HPF_SHIFT_MASK || - car->gain1.shft > CAR_GAIN1_SHFT_MASK || - car->gain1.gain_min > CAR_GAIN_MIN_MASK || - car->gain2.shft > CAR_GAIN2_SHFT_MASK || - car->gain2.gain_min > CAR_GAIN_MIN_MASK) - return -EINVAL; - - return 0; -} - -static int ipipe_set_car_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_car *car_param = param; - struct device *dev = ipipe->subdev.v4l2_dev->dev; - struct vpfe_ipipe_car *car = &ipipe->config.car; - - if (!car_param) { - memset(car, 0, sizeof(struct vpfe_ipipe_car)); - } else { - memcpy(car, car_param, sizeof(struct vpfe_ipipe_car)); - if (ipipe_validate_car_params(car) < 0) { - dev_err(dev, "Invalid car params\n"); - return -EINVAL; - } - } - - ipipe_set_car_regs(ipipe->base_addr, car); - - return 0; -} - -static int ipipe_get_car_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_car *car_param = param; - struct vpfe_ipipe_car *car = &ipipe->config.car; - - memcpy(car_param, car, sizeof(struct vpfe_ipipe_car)); - return 0; -} - -static int ipipe_validate_cgs_params(struct vpfe_ipipe_cgs *cgs) -{ - if (cgs->en > 1 || cgs->h_shft > CAR_SHIFT_MASK) - return -EINVAL; - - return 0; -} - -static int ipipe_set_cgs_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_cgs *cgs_param = param; - struct device *dev = ipipe->subdev.v4l2_dev->dev; - struct vpfe_ipipe_cgs *cgs = &ipipe->config.cgs; - - if (!cgs_param) { - memset(cgs, 0, sizeof(struct vpfe_ipipe_cgs)); - } else { - memcpy(cgs, cgs_param, sizeof(struct vpfe_ipipe_cgs)); - if (ipipe_validate_cgs_params(cgs) < 0) { - dev_err(dev, "Invalid cgs params\n"); - return -EINVAL; - } - } - - ipipe_set_cgs_regs(ipipe->base_addr, cgs); - - return 0; -} - -static int ipipe_get_cgs_params(struct vpfe_ipipe_device *ipipe, void *param) -{ - struct vpfe_ipipe_cgs *cgs_param = param; - struct vpfe_ipipe_cgs *cgs = &ipipe->config.cgs; - - memcpy(cgs_param, cgs, sizeof(struct vpfe_ipipe_cgs)); - - return 0; -} - -static const struct ipipe_module_if ipipe_modules[VPFE_IPIPE_MAX_MODULES] = { - /* VPFE_IPIPE_INPUT_CONFIG */ { - offsetof(struct ipipe_module_params, input_config), - FIELD_SIZEOF(struct ipipe_module_params, input_config), - offsetof(struct vpfe_ipipe_config, input_config), - ipipe_set_input_config, - ipipe_get_input_config, - }, /* VPFE_IPIPE_LUTDPC */ { - offsetof(struct ipipe_module_params, lutdpc), - FIELD_SIZEOF(struct ipipe_module_params, lutdpc), - offsetof(struct vpfe_ipipe_config, lutdpc), - ipipe_set_lutdpc_params, - ipipe_get_lutdpc_params, - }, /* VPFE_IPIPE_OTFDPC */ { - offsetof(struct ipipe_module_params, otfdpc), - FIELD_SIZEOF(struct ipipe_module_params, otfdpc), - offsetof(struct vpfe_ipipe_config, otfdpc), - ipipe_set_otfdpc_params, - ipipe_get_otfdpc_params, - }, /* VPFE_IPIPE_NF1 */ { - offsetof(struct ipipe_module_params, nf1), - FIELD_SIZEOF(struct ipipe_module_params, nf1), - offsetof(struct vpfe_ipipe_config, nf1), - ipipe_set_nf1_params, - ipipe_get_nf1_params, - }, /* VPFE_IPIPE_NF2 */ { - offsetof(struct ipipe_module_params, nf2), - FIELD_SIZEOF(struct ipipe_module_params, nf2), - offsetof(struct vpfe_ipipe_config, nf2), - ipipe_set_nf2_params, - ipipe_get_nf2_params, - }, /* VPFE_IPIPE_WB */ { - offsetof(struct ipipe_module_params, wbal), - FIELD_SIZEOF(struct ipipe_module_params, wbal), - offsetof(struct vpfe_ipipe_config, wbal), - ipipe_set_wb_params, - ipipe_get_wb_params, - }, /* VPFE_IPIPE_RGB2RGB_1 */ { - offsetof(struct ipipe_module_params, rgb2rgb1), - FIELD_SIZEOF(struct ipipe_module_params, rgb2rgb1), - offsetof(struct vpfe_ipipe_config, rgb2rgb1), - ipipe_set_rgb2rgb_1_params, - ipipe_get_rgb2rgb_1_params, - }, /* VPFE_IPIPE_RGB2RGB_2 */ { - offsetof(struct ipipe_module_params, rgb2rgb2), - FIELD_SIZEOF(struct ipipe_module_params, rgb2rgb2), - offsetof(struct vpfe_ipipe_config, rgb2rgb2), - ipipe_set_rgb2rgb_2_params, - ipipe_get_rgb2rgb_2_params, - }, /* VPFE_IPIPE_GAMMA */ { - offsetof(struct ipipe_module_params, gamma), - FIELD_SIZEOF(struct ipipe_module_params, gamma), - offsetof(struct vpfe_ipipe_config, gamma), - ipipe_set_gamma_params, - ipipe_get_gamma_params, - }, /* VPFE_IPIPE_3D_LUT */ { - offsetof(struct ipipe_module_params, lut), - FIELD_SIZEOF(struct ipipe_module_params, lut), - offsetof(struct vpfe_ipipe_config, lut), - ipipe_set_3d_lut_params, - ipipe_get_3d_lut_params, - }, /* VPFE_IPIPE_RGB2YUV */ { - offsetof(struct ipipe_module_params, rgb2yuv), - FIELD_SIZEOF(struct ipipe_module_params, rgb2yuv), - offsetof(struct vpfe_ipipe_config, rgb2yuv), - ipipe_set_rgb2yuv_params, - ipipe_get_rgb2yuv_params, - }, /* VPFE_IPIPE_YUV422_CONV */ { - offsetof(struct ipipe_module_params, yuv422_conv), - FIELD_SIZEOF(struct ipipe_module_params, yuv422_conv), - offsetof(struct vpfe_ipipe_config, yuv422_conv), - ipipe_set_yuv422_conv_params, - ipipe_get_yuv422_conv_params, - }, /* VPFE_IPIPE_YEE */ { - offsetof(struct ipipe_module_params, yee), - FIELD_SIZEOF(struct ipipe_module_params, yee), - offsetof(struct vpfe_ipipe_config, yee), - ipipe_set_yee_params, - ipipe_get_yee_params, - }, /* VPFE_IPIPE_GIC */ { - offsetof(struct ipipe_module_params, gic), - FIELD_SIZEOF(struct ipipe_module_params, gic), - offsetof(struct vpfe_ipipe_config, gic), - ipipe_set_gic_params, - ipipe_get_gic_params, - }, /* VPFE_IPIPE_CFA */ { - offsetof(struct ipipe_module_params, cfa), - FIELD_SIZEOF(struct ipipe_module_params, cfa), - offsetof(struct vpfe_ipipe_config, cfa), - ipipe_set_cfa_params, - ipipe_get_cfa_params, - }, /* VPFE_IPIPE_CAR */ { - offsetof(struct ipipe_module_params, car), - FIELD_SIZEOF(struct ipipe_module_params, car), - offsetof(struct vpfe_ipipe_config, car), - ipipe_set_car_params, - ipipe_get_car_params, - }, /* VPFE_IPIPE_CGS */ { - offsetof(struct ipipe_module_params, cgs), - FIELD_SIZEOF(struct ipipe_module_params, cgs), - offsetof(struct vpfe_ipipe_config, cgs), - ipipe_set_cgs_params, - ipipe_get_cgs_params, - }, /* VPFE_IPIPE_GBCE */ { - offsetof(struct ipipe_module_params, gbce), - FIELD_SIZEOF(struct ipipe_module_params, gbce), - offsetof(struct vpfe_ipipe_config, gbce), - ipipe_set_gbce_params, - ipipe_get_gbce_params, - }, -}; - -static int ipipe_s_config(struct v4l2_subdev *sd, struct vpfe_ipipe_config *cfg) -{ - struct vpfe_ipipe_device *ipipe = v4l2_get_subdevdata(sd); - unsigned int i; - int rval = 0; - struct ipipe_module_params *params; - - for (i = 0; i < ARRAY_SIZE(ipipe_modules); i++) { - const struct ipipe_module_if *module_if; - void *from, *to; - size_t size; - - if (!(cfg->flag & BIT(i))) - continue; - - module_if = &ipipe_modules[i]; - from = *(void **)((void *)cfg + module_if->config_offset); - - params = kmalloc(sizeof(*params), GFP_KERNEL); - if (!params) - return -ENOMEM; - to = (void *)params + module_if->param_offset; - size = module_if->param_size; - - if (to && from && size) { - if (copy_from_user(to, (void __user *)from, size)) { - rval = -EFAULT; - goto error_free; - } - rval = module_if->set(ipipe, to); - if (rval) - goto error_free; - } else if (to && !from && size) { - rval = module_if->set(ipipe, NULL); - if (rval) - goto error_free; - } - kfree(params); - } - return rval; - -error_free: - kfree(params); - return rval; -} - -static int ipipe_g_config(struct v4l2_subdev *sd, struct vpfe_ipipe_config *cfg) -{ - struct vpfe_ipipe_device *ipipe = v4l2_get_subdevdata(sd); - unsigned int i; - int rval = 0; - - for (i = 1; i < ARRAY_SIZE(ipipe_modules); i++) { - const struct ipipe_module_if *module_if; - struct ipipe_module_params *params; - void *from, *to; - size_t size; - - if (!(cfg->flag & BIT(i))) - continue; - - module_if = &ipipe_modules[i]; - to = *(void **)((void *)cfg + module_if->config_offset); - - params = kmalloc(sizeof(*params), GFP_KERNEL); - if (!params) { - rval = -ENOMEM; - goto error; - } - - from = (void *)params + module_if->param_offset; - size = module_if->param_size; - - if (to && from && size) { - rval = module_if->get(ipipe, from); - if (rval) - goto error; - if (copy_to_user((void __user *)to, from, size)) { - rval = -EFAULT; - break; - } - } - kfree(params); - } -error: - return rval; -} - -/* - * ipipe_ioctl() - Handle ipipe module private ioctl's - * @sd: pointer to v4l2 subdev structure - * @cmd: configuration command - * @arg: configuration argument - */ -static long ipipe_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) -{ - switch (cmd) { - case VIDIOC_VPFE_IPIPE_S_CONFIG: - return ipipe_s_config(sd, arg); - - case VIDIOC_VPFE_IPIPE_G_CONFIG: - return ipipe_g_config(sd, arg); - - default: - return -ENOIOCTLCMD; - } -} - -void vpfe_ipipe_enable(struct vpfe_device *vpfe_dev, int en) -{ - struct vpfe_ipipeif_device *ipipeif = &vpfe_dev->vpfe_ipipeif; - struct vpfe_ipipe_device *ipipe = &vpfe_dev->vpfe_ipipe; - unsigned char val; - - if (ipipe->input == IPIPE_INPUT_NONE) - return; - - /* ipipe is set to single shot */ - if (ipipeif->input == IPIPEIF_INPUT_MEMORY && en) { - /* for single-shot mode, need to wait for h/w to - * reset many register bits - */ - do { - val = regr_ip(vpfe_dev->vpfe_ipipe.base_addr, - IPIPE_SRC_EN); - } while (val); - } - regw_ip(vpfe_dev->vpfe_ipipe.base_addr, en, IPIPE_SRC_EN); -} - -/* - * ipipe_set_stream() - Enable/Disable streaming on the ipipe subdevice - * @sd: pointer to v4l2 subdev structure - * @enable: 1 == Enable, 0 == Disable - */ -static int ipipe_set_stream(struct v4l2_subdev *sd, int enable) -{ - struct vpfe_ipipe_device *ipipe = v4l2_get_subdevdata(sd); - struct vpfe_device *vpfe_dev = to_vpfe_device(ipipe); - - if (enable && ipipe->input != IPIPE_INPUT_NONE && - ipipe->output != IPIPE_OUTPUT_NONE) { - if (config_ipipe_hw(ipipe) < 0) - return -EINVAL; - } - - vpfe_ipipe_enable(vpfe_dev, enable); - - return 0; -} - -/* - * __ipipe_get_format() - helper function for getting ipipe format - * @ipipe: pointer to ipipe private structure. - * @pad: pad number. - * @cfg: V4L2 subdev pad config - * @which: wanted subdev format. - * - */ -static struct v4l2_mbus_framefmt * -__ipipe_get_format(struct vpfe_ipipe_device *ipipe, - struct v4l2_subdev_pad_config *cfg, unsigned int pad, - enum v4l2_subdev_format_whence which) -{ - if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(&ipipe->subdev, cfg, pad); - - return &ipipe->formats[pad]; -} - -/* - * ipipe_try_format() - Handle try format by pad subdev method - * @ipipe: VPFE ipipe device. - * @cfg: V4L2 subdev pad config - * @pad: pad num. - * @fmt: pointer to v4l2 format structure. - * @which : wanted subdev format - */ -static void -ipipe_try_format(struct vpfe_ipipe_device *ipipe, - struct v4l2_subdev_pad_config *cfg, unsigned int pad, - struct v4l2_mbus_framefmt *fmt, - enum v4l2_subdev_format_whence which) -{ - unsigned int max_out_height; - unsigned int max_out_width; - unsigned int i; - - max_out_width = IPIPE_MAX_OUTPUT_WIDTH_A; - max_out_height = IPIPE_MAX_OUTPUT_HEIGHT_A; - - if (pad == IPIPE_PAD_SINK) { - for (i = 0; i < ARRAY_SIZE(ipipe_input_fmts); i++) - if (fmt->code == ipipe_input_fmts[i]) - break; - - /* If not found, use SBGGR10 as default */ - if (i >= ARRAY_SIZE(ipipe_input_fmts)) - fmt->code = MEDIA_BUS_FMT_SGRBG12_1X12; - } else if (pad == IPIPE_PAD_SOURCE) { - for (i = 0; i < ARRAY_SIZE(ipipe_output_fmts); i++) - if (fmt->code == ipipe_output_fmts[i]) - break; - - /* If not found, use UYVY as default */ - if (i >= ARRAY_SIZE(ipipe_output_fmts)) - fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; - } - - fmt->width = clamp_t(u32, fmt->width, MIN_OUT_HEIGHT, max_out_width); - fmt->height = clamp_t(u32, fmt->height, MIN_OUT_WIDTH, max_out_height); -} - -/* - * ipipe_set_format() - Handle set format by pads subdev method - * @sd: pointer to v4l2 subdev structure - * @cfg: V4L2 subdev pad config - * @fmt: pointer to v4l2 subdev format structure - * return -EINVAL or zero on success - */ -static int -ipipe_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *fmt) -{ - struct vpfe_ipipe_device *ipipe = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *format; - - format = __ipipe_get_format(ipipe, cfg, fmt->pad, fmt->which); - if (!format) - return -EINVAL; - - ipipe_try_format(ipipe, cfg, fmt->pad, &fmt->format, fmt->which); - *format = fmt->format; - - if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) - return 0; - - if (fmt->pad == IPIPE_PAD_SINK && - (ipipe->input == IPIPE_INPUT_CCDC || - ipipe->input == IPIPE_INPUT_MEMORY)) - ipipe->formats[fmt->pad] = fmt->format; - else if (fmt->pad == IPIPE_PAD_SOURCE && - ipipe->output == IPIPE_OUTPUT_RESIZER) - ipipe->formats[fmt->pad] = fmt->format; - else - return -EINVAL; - - return 0; -} - -/* - * ipipe_get_format() - Handle get format by pads subdev method. - * @sd: pointer to v4l2 subdev structure. - * @cfg: V4L2 subdev pad config - * @fmt: pointer to v4l2 subdev format structure. - */ -static int -ipipe_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *fmt) -{ - struct vpfe_ipipe_device *ipipe = v4l2_get_subdevdata(sd); - - if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) - fmt->format = ipipe->formats[fmt->pad]; - else - fmt->format = *(v4l2_subdev_get_try_format(sd, cfg, fmt->pad)); - - return 0; -} - -/* - * ipipe_enum_frame_size() - enum frame sizes on pads - * @sd: pointer to v4l2 subdev structure. - * @cfg: V4L2 subdev pad config - * @fse: pointer to v4l2_subdev_frame_size_enum structure. - */ -static int -ipipe_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_frame_size_enum *fse) -{ - struct vpfe_ipipe_device *ipipe = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt format; - - if (fse->index != 0) - return -EINVAL; - - format.code = fse->code; - format.width = 1; - format.height = 1; - ipipe_try_format(ipipe, cfg, fse->pad, &format, fse->which); - fse->min_width = format.width; - fse->min_height = format.height; - - if (format.code != fse->code) - return -EINVAL; - - format.code = fse->code; - format.width = -1; - format.height = -1; - ipipe_try_format(ipipe, cfg, fse->pad, &format, fse->which); - fse->max_width = format.width; - fse->max_height = format.height; - - return 0; -} - -/* - * ipipe_enum_mbus_code() - enum mbus codes for pads - * @sd: pointer to v4l2 subdev structure. - * @cfg: V4L2 subdev pad config - * @code: pointer to v4l2_subdev_mbus_code_enum structure - */ -static int -ipipe_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) -{ - switch (code->pad) { - case IPIPE_PAD_SINK: - if (code->index >= ARRAY_SIZE(ipipe_input_fmts)) - return -EINVAL; - code->code = ipipe_input_fmts[code->index]; - break; - - case IPIPE_PAD_SOURCE: - if (code->index >= ARRAY_SIZE(ipipe_output_fmts)) - return -EINVAL; - code->code = ipipe_output_fmts[code->index]; - break; - - default: - return -EINVAL; - } - - return 0; -} - -/* - * ipipe_s_ctrl() - Handle set control subdev method - * @ctrl: pointer to v4l2 control structure - */ -static int ipipe_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct vpfe_ipipe_device *ipipe = - container_of(ctrl->handler, struct vpfe_ipipe_device, ctrls); - struct ipipe_lum_adj *lum_adj = &ipipe->config.lum_adj; - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - lum_adj->brightness = ctrl->val; - ipipe_set_lum_adj_regs(ipipe->base_addr, lum_adj); - break; - - case V4L2_CID_CONTRAST: - lum_adj->contrast = ctrl->val; - ipipe_set_lum_adj_regs(ipipe->base_addr, lum_adj); - break; - - default: - return -EINVAL; - } - - return 0; -} - -/* - * ipipe_init_formats() - Initialize formats on all pads - * @sd: pointer to v4l2 subdev structure. - * @fh: V4L2 subdev file handle - * - * Initialize all pad formats with default values. Try formats are initialized - * on the file handle. - */ -static int -ipipe_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) -{ - struct v4l2_subdev_format format; - - memset(&format, 0, sizeof(format)); - format.pad = IPIPE_PAD_SINK; - format.which = V4L2_SUBDEV_FORMAT_TRY; - format.format.code = MEDIA_BUS_FMT_SGRBG12_1X12; - format.format.width = IPIPE_MAX_OUTPUT_WIDTH_A; - format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_A; - ipipe_set_format(sd, fh->pad, &format); - - memset(&format, 0, sizeof(format)); - format.pad = IPIPE_PAD_SOURCE; - format.which = V4L2_SUBDEV_FORMAT_TRY; - format.format.code = MEDIA_BUS_FMT_UYVY8_2X8; - format.format.width = IPIPE_MAX_OUTPUT_WIDTH_A; - format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_A; - ipipe_set_format(sd, fh->pad, &format); - - return 0; -} - -/* subdev core operations */ -static const struct v4l2_subdev_core_ops ipipe_v4l2_core_ops = { - .ioctl = ipipe_ioctl, -}; - -static const struct v4l2_ctrl_ops ipipe_ctrl_ops = { - .s_ctrl = ipipe_s_ctrl, -}; - -/* subdev file operations */ -static const struct v4l2_subdev_internal_ops ipipe_v4l2_internal_ops = { - .open = ipipe_init_formats, -}; - -/* subdev video operations */ -static const struct v4l2_subdev_video_ops ipipe_v4l2_video_ops = { - .s_stream = ipipe_set_stream, -}; - -/* subdev pad operations */ -static const struct v4l2_subdev_pad_ops ipipe_v4l2_pad_ops = { - .enum_mbus_code = ipipe_enum_mbus_code, - .enum_frame_size = ipipe_enum_frame_size, - .get_fmt = ipipe_get_format, - .set_fmt = ipipe_set_format, -}; - -/* v4l2 subdev operation */ -static const struct v4l2_subdev_ops ipipe_v4l2_ops = { - .core = &ipipe_v4l2_core_ops, - .video = &ipipe_v4l2_video_ops, - .pad = &ipipe_v4l2_pad_ops, -}; - -/* - * Media entity operations - */ - -/* - * ipipe_link_setup() - Setup ipipe connections - * @entity: ipipe media entity - * @local: Pad at the local end of the link - * @remote: Pad at the remote end of the link - * @flags: Link flags - * - * return -EINVAL or zero on success - */ -static int -ipipe_link_setup(struct media_entity *entity, const struct media_pad *local, - const struct media_pad *remote, u32 flags) -{ - struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); - struct vpfe_ipipe_device *ipipe = v4l2_get_subdevdata(sd); - struct vpfe_device *vpfe_dev = to_vpfe_device(ipipe); - u16 ipipeif_sink = vpfe_dev->vpfe_ipipeif.input; - - if (!is_media_entity_v4l2_subdev(remote->entity)) - return -EINVAL; - - switch (local->index) { - case IPIPE_PAD_SINK: - if (!(flags & MEDIA_LNK_FL_ENABLED)) { - ipipe->input = IPIPE_INPUT_NONE; - break; - } - if (ipipe->input != IPIPE_INPUT_NONE) - return -EBUSY; - if (ipipeif_sink == IPIPEIF_INPUT_MEMORY) - ipipe->input = IPIPE_INPUT_MEMORY; - else - ipipe->input = IPIPE_INPUT_CCDC; - break; - - case IPIPE_PAD_SOURCE: - /* out to RESIZER */ - if (flags & MEDIA_LNK_FL_ENABLED) - ipipe->output = IPIPE_OUTPUT_RESIZER; - else - ipipe->output = IPIPE_OUTPUT_NONE; - break; - - default: - return -EINVAL; - } - - return 0; -} - -static const struct media_entity_operations ipipe_media_ops = { - .link_setup = ipipe_link_setup, -}; - -/* - * vpfe_ipipe_unregister_entities() - ipipe unregister entity - * @vpfe_ipipe: pointer to ipipe subdevice structure. - */ -void vpfe_ipipe_unregister_entities(struct vpfe_ipipe_device *vpfe_ipipe) -{ - /* unregister subdev */ - v4l2_device_unregister_subdev(&vpfe_ipipe->subdev); - /* cleanup entity */ - media_entity_cleanup(&vpfe_ipipe->subdev.entity); -} - -/* - * vpfe_ipipe_register_entities() - ipipe register entity - * @ipipe: pointer to ipipe subdevice structure. - * @vdev: pointer to v4l2 device structure. - */ -int -vpfe_ipipe_register_entities(struct vpfe_ipipe_device *ipipe, - struct v4l2_device *vdev) -{ - int ret; - - /* Register the subdev */ - ret = v4l2_device_register_subdev(vdev, &ipipe->subdev); - if (ret) { - pr_err("Failed to register ipipe as v4l2 subdevice\n"); - return ret; - } - - return ret; -} - -#define IPIPE_CONTRAST_HIGH 0xff -#define IPIPE_BRIGHT_HIGH 0xff - -/* - * vpfe_ipipe_init() - ipipe module initialization. - * @ipipe: pointer to ipipe subdevice structure. - * @pdev: platform device pointer. - */ -int -vpfe_ipipe_init(struct vpfe_ipipe_device *ipipe, struct platform_device *pdev) -{ - struct media_pad *pads = &ipipe->pads[0]; - struct v4l2_subdev *sd = &ipipe->subdev; - struct media_entity *me = &sd->entity; - struct resource *res, *res2, *memres; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 4); - if (!res) - return -ENOENT; - - memres = request_mem_region(res->start, resource_size(res), res->name); - if (!memres) - return -EBUSY; - ipipe->base_addr = ioremap_nocache(memres->start, - resource_size(memres)); - if (!ipipe->base_addr) - goto error_release; - - res2 = platform_get_resource(pdev, IORESOURCE_MEM, 6); - if (!res2) - goto error_unmap; - ipipe->isp5_base_addr = ioremap_nocache(res2->start, - resource_size(res2)); - if (!ipipe->isp5_base_addr) - goto error_unmap; - - v4l2_subdev_init(sd, &ipipe_v4l2_ops); - sd->internal_ops = &ipipe_v4l2_internal_ops; - strscpy(sd->name, "DAVINCI IPIPE", sizeof(sd->name)); - sd->grp_id = 1 << 16; /* group ID for davinci subdevs */ - v4l2_set_subdevdata(sd, ipipe); - sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - - pads[IPIPE_PAD_SINK].flags = MEDIA_PAD_FL_SINK; - pads[IPIPE_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; - - ipipe->input = IPIPE_INPUT_NONE; - ipipe->output = IPIPE_OUTPUT_NONE; - - me->ops = &ipipe_media_ops; - v4l2_ctrl_handler_init(&ipipe->ctrls, 2); - v4l2_ctrl_new_std(&ipipe->ctrls, &ipipe_ctrl_ops, - V4L2_CID_BRIGHTNESS, 0, - IPIPE_BRIGHT_HIGH, 1, 16); - v4l2_ctrl_new_std(&ipipe->ctrls, &ipipe_ctrl_ops, - V4L2_CID_CONTRAST, 0, - IPIPE_CONTRAST_HIGH, 1, 16); - v4l2_ctrl_handler_setup(&ipipe->ctrls); - sd->ctrl_handler = &ipipe->ctrls; - - return media_entity_pads_init(me, IPIPE_PADS_NUM, pads); - -error_unmap: - iounmap(ipipe->base_addr); -error_release: - release_mem_region(memres->start, resource_size(memres)); - return -ENOMEM; -} - -/* - * vpfe_ipipe_cleanup() - ipipe subdevice cleanup. - * @ipipe: pointer to ipipe subdevice - * @dev: pointer to platform device - */ -void vpfe_ipipe_cleanup(struct vpfe_ipipe_device *ipipe, - struct platform_device *pdev) -{ - struct resource *res; - - v4l2_ctrl_handler_free(&ipipe->ctrls); - - iounmap(ipipe->base_addr); - iounmap(ipipe->isp5_base_addr); - res = platform_get_resource(pdev, IORESOURCE_MEM, 4); - if (res) - release_mem_region(res->start, resource_size(res)); -} diff --git a/drivers/staging/media/davinci_vpfe/dm365_ipipe.h b/drivers/staging/media/davinci_vpfe/dm365_ipipe.h deleted file mode 100644 index 866ae12aeb07..000000000000 --- a/drivers/staging/media/davinci_vpfe/dm365_ipipe.h +++ /dev/null @@ -1,174 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2012 Texas Instruments Inc - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Contributors: - * Manjunath Hadli - * Prabhakar Lad - */ - -#ifndef _DAVINCI_VPFE_DM365_IPIPE_H -#define _DAVINCI_VPFE_DM365_IPIPE_H - -#include - -#include -#include - -#include "davinci_vpfe_user.h" -#include "vpfe_video.h" - -enum ipipe_noise_filter { - IPIPE_D2F_1ST = 0, - IPIPE_D2F_2ND = 1, -}; - -/* Used for driver storage */ -struct ipipe_otfdpc_2_0 { - /* 0 - disable, 1 - enable */ - unsigned char en; - /* defect detection method */ - enum vpfe_ipipe_otfdpc_det_meth det_method; - /* Algorithm used. Applicable only when IPIPE_DPC_OTF_MIN_MAX2 is - * used - */ - enum vpfe_ipipe_otfdpc_alg alg; - struct vpfe_ipipe_otfdpc_2_0_cfg otfdpc_2_0; -}; - -struct ipipe_otfdpc_3_0 { - /* 0 - disable, 1 - enable */ - unsigned char en; - /* defect detection method */ - enum vpfe_ipipe_otfdpc_det_meth det_method; - /* Algorithm used. Applicable only when IPIPE_DPC_OTF_MIN_MAX2 is - * used - */ - enum vpfe_ipipe_otfdpc_alg alg; - struct vpfe_ipipe_otfdpc_3_0_cfg otfdpc_3_0; -}; - -/* Structure for configuring Luminance Adjustment module */ -struct ipipe_lum_adj { - /* Brightness adjustments */ - unsigned char brightness; - /* contrast adjustments */ - unsigned char contrast; -}; - -enum ipipe_rgb2rgb { - IPIPE_RGB2RGB_1 = 0, - IPIPE_RGB2RGB_2 = 1, -}; - -struct ipipe_module_params { - __u32 flag; - struct vpfe_ipipe_input_config input_config; - struct vpfe_ipipe_lutdpc lutdpc; - struct vpfe_ipipe_otfdpc otfdpc; - struct vpfe_ipipe_nf nf1; - struct vpfe_ipipe_nf nf2; - struct vpfe_ipipe_gic gic; - struct vpfe_ipipe_wb wbal; - struct vpfe_ipipe_cfa cfa; - struct vpfe_ipipe_rgb2rgb rgb2rgb1; - struct vpfe_ipipe_rgb2rgb rgb2rgb2; - struct vpfe_ipipe_gamma gamma; - struct vpfe_ipipe_3d_lut lut; - struct vpfe_ipipe_rgb2yuv rgb2yuv; - struct vpfe_ipipe_gbce gbce; - struct vpfe_ipipe_yuv422_conv yuv422_conv; - struct vpfe_ipipe_yee yee; - struct vpfe_ipipe_car car; - struct vpfe_ipipe_cgs cgs; - struct ipipe_lum_adj lum_adj; -}; - -#define IPIPE_PAD_SINK 0 -#define IPIPE_PAD_SOURCE 1 - -#define IPIPE_PADS_NUM 2 - -#define IPIPE_OUTPUT_NONE 0 -#define IPIPE_OUTPUT_RESIZER (1 << 0) - -enum ipipe_input_entity { - IPIPE_INPUT_NONE = 0, - IPIPE_INPUT_MEMORY = 1, - IPIPE_INPUT_CCDC = 2, -}; - - -struct vpfe_ipipe_device { - struct v4l2_subdev subdev; - struct media_pad pads[IPIPE_PADS_NUM]; - struct v4l2_mbus_framefmt formats[IPIPE_PADS_NUM]; - enum ipipe_input_entity input; - unsigned int output; - struct v4l2_ctrl_handler ctrls; - void __iomem *base_addr; - void __iomem *isp5_base_addr; - struct ipipe_module_params config; -}; - -struct ipipe_module_if { - unsigned int param_offset; - unsigned int param_size; - unsigned int config_offset; - int (*set)(struct vpfe_ipipe_device *ipipe, void *param); - int (*get)(struct vpfe_ipipe_device *ipipe, void *param); -}; - -/* data paths */ -enum ipipe_data_paths { - IPIPE_RAW2YUV, - /* Bayer RAW input to YCbCr output */ - IPIPE_RAW2RAW, - /* Bayer Raw to Bayer output */ - IPIPE_RAW2BOX, - /* Bayer Raw to Boxcar output */ - IPIPE_YUV2YUV - /* YUV Raw to YUV Raw output */ -}; - -#define IPIPE_COLPTN_R_Ye 0x0 -#define IPIPE_COLPTN_Gr_Cy 0x1 -#define IPIPE_COLPTN_Gb_G 0x2 -#define IPIPE_COLPTN_B_Mg 0x3 - -#define COLPAT_EE_SHIFT 0 -#define COLPAT_EO_SHIFT 2 -#define COLPAT_OE_SHIFT 4 -#define COLPAT_OO_SHIFT 6 - -#define ipipe_sgrbg_pattern \ - (IPIPE_COLPTN_Gr_Cy << COLPAT_EE_SHIFT | \ - IPIPE_COLPTN_R_Ye << COLPAT_EO_SHIFT | \ - IPIPE_COLPTN_B_Mg << COLPAT_OE_SHIFT | \ - IPIPE_COLPTN_Gb_G << COLPAT_OO_SHIFT) - -#define ipipe_srggb_pattern \ - (IPIPE_COLPTN_R_Ye << COLPAT_EE_SHIFT | \ - IPIPE_COLPTN_Gr_Cy << COLPAT_EO_SHIFT | \ - IPIPE_COLPTN_Gb_G << COLPAT_OE_SHIFT | \ - IPIPE_COLPTN_B_Mg << COLPAT_OO_SHIFT) - -int vpfe_ipipe_register_entities(struct vpfe_ipipe_device *ipipe, - struct v4l2_device *v4l2_dev); -int vpfe_ipipe_init(struct vpfe_ipipe_device *ipipe, - struct platform_device *pdev); -void vpfe_ipipe_unregister_entities(struct vpfe_ipipe_device *ipipe); -void vpfe_ipipe_cleanup(struct vpfe_ipipe_device *ipipe, - struct platform_device *pdev); -void vpfe_ipipe_enable(struct vpfe_device *vpfe_dev, int en); - -#endif /* _DAVINCI_VPFE_DM365_IPIPE_H */ diff --git a/drivers/staging/media/davinci_vpfe/dm365_ipipe_hw.c b/drivers/staging/media/davinci_vpfe/dm365_ipipe_hw.c deleted file mode 100644 index 110473c30577..000000000000 --- a/drivers/staging/media/davinci_vpfe/dm365_ipipe_hw.c +++ /dev/null @@ -1,1038 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2012 Texas Instruments Inc - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Contributors: - * Manjunath Hadli - * Prabhakar Lad - */ - -#include "dm365_ipipe_hw.h" - -#define IPIPE_MODE_CONTINUOUS 0 -#define IPIPE_MODE_SINGLE_SHOT 1 - -static void ipipe_clock_enable(void __iomem *base_addr) -{ - /* enable IPIPE MMR for register write access */ - regw_ip(base_addr, IPIPE_GCK_MMR_DEFAULT, IPIPE_GCK_MMR); - - /* enable the clock wb,cfa,dfc,d2f,pre modules */ - regw_ip(base_addr, IPIPE_GCK_PIX_DEFAULT, IPIPE_GCK_PIX); -} - -static void -rsz_set_common_params(void __iomem *rsz_base, struct resizer_params *params) -{ - struct rsz_common_params *rsz_common = ¶ms->rsz_common; - u32 val; - - /* Set mode */ - regw_rsz(rsz_base, params->oper_mode, RSZ_SRC_MODE); - - /* data source selection and bypass */ - val = (rsz_common->passthrough << RSZ_BYPASS_SHIFT) | - rsz_common->source; - regw_rsz(rsz_base, val, RSZ_SRC_FMT0); - - /* src image selection */ - val = (rsz_common->raw_flip & 1) | - (rsz_common->src_img_fmt << RSZ_SRC_IMG_FMT_SHIFT) | - ((rsz_common->y_c & 1) << RSZ_SRC_Y_C_SEL_SHIFT); - regw_rsz(rsz_base, val, RSZ_SRC_FMT1); - - regw_rsz(rsz_base, rsz_common->vps & IPIPE_RSZ_VPS_MASK, RSZ_SRC_VPS); - regw_rsz(rsz_base, rsz_common->hps & IPIPE_RSZ_HPS_MASK, RSZ_SRC_HPS); - regw_rsz(rsz_base, rsz_common->vsz & IPIPE_RSZ_VSZ_MASK, RSZ_SRC_VSZ); - regw_rsz(rsz_base, rsz_common->hsz & IPIPE_RSZ_HSZ_MASK, RSZ_SRC_HSZ); - regw_rsz(rsz_base, rsz_common->yuv_y_min, RSZ_YUV_Y_MIN); - regw_rsz(rsz_base, rsz_common->yuv_y_max, RSZ_YUV_Y_MAX); - regw_rsz(rsz_base, rsz_common->yuv_c_min, RSZ_YUV_C_MIN); - regw_rsz(rsz_base, rsz_common->yuv_c_max, RSZ_YUV_C_MAX); - /* chromatic position */ - regw_rsz(rsz_base, rsz_common->out_chr_pos, RSZ_YUV_PHS); -} - -static void -rsz_set_rsz_regs(void __iomem *rsz_base, unsigned int rsz_id, - struct resizer_params *params) -{ - struct resizer_scale_param *rsc_params; - struct rsz_ext_mem_param *ext_mem; - struct resizer_rgb *rgb; - u32 reg_base; - u32 val; - - rsc_params = ¶ms->rsz_rsc_param[rsz_id]; - rgb = ¶ms->rsz2rgb[rsz_id]; - ext_mem = ¶ms->ext_mem_param[rsz_id]; - - if (rsz_id == RSZ_A) { - val = rsc_params->h_flip << RSZA_H_FLIP_SHIFT; - val |= rsc_params->v_flip << RSZA_V_FLIP_SHIFT; - reg_base = RSZ_EN_A; - } else { - val = rsc_params->h_flip << RSZB_H_FLIP_SHIFT; - val |= rsc_params->v_flip << RSZB_V_FLIP_SHIFT; - reg_base = RSZ_EN_B; - } - /* update flip settings */ - regw_rsz(rsz_base, val, RSZ_SEQ); - - regw_rsz(rsz_base, params->oper_mode, reg_base + RSZ_MODE); - - val = (rsc_params->cen << RSZ_CEN_SHIFT) | rsc_params->yen; - regw_rsz(rsz_base, val, reg_base + RSZ_420); - - regw_rsz(rsz_base, rsc_params->i_vps & RSZ_VPS_MASK, - reg_base + RSZ_I_VPS); - regw_rsz(rsz_base, rsc_params->i_hps & RSZ_HPS_MASK, - reg_base + RSZ_I_HPS); - regw_rsz(rsz_base, rsc_params->o_vsz & RSZ_O_VSZ_MASK, - reg_base + RSZ_O_VSZ); - regw_rsz(rsz_base, rsc_params->o_hsz & RSZ_O_HSZ_MASK, - reg_base + RSZ_O_HSZ); - regw_rsz(rsz_base, rsc_params->v_phs_y & RSZ_V_PHS_MASK, - reg_base + RSZ_V_PHS_Y); - regw_rsz(rsz_base, rsc_params->v_phs_c & RSZ_V_PHS_MASK, - reg_base + RSZ_V_PHS_C); - - /* keep this additional adjustment to zero for now */ - regw_rsz(rsz_base, rsc_params->v_dif & RSZ_V_DIF_MASK, - reg_base + RSZ_V_DIF); - - val = (rsc_params->v_typ_y & 1) | - ((rsc_params->v_typ_c & 1) << RSZ_TYP_C_SHIFT); - regw_rsz(rsz_base, val, reg_base + RSZ_V_TYP); - - val = (rsc_params->v_lpf_int_y & RSZ_LPF_INT_MASK) | - ((rsc_params->v_lpf_int_c & RSZ_LPF_INT_MASK) << - RSZ_LPF_INT_C_SHIFT); - regw_rsz(rsz_base, val, reg_base + RSZ_V_LPF); - - regw_rsz(rsz_base, rsc_params->h_phs & - RSZ_H_PHS_MASK, reg_base + RSZ_H_PHS); - - regw_rsz(rsz_base, 0, reg_base + RSZ_H_PHS_ADJ); - regw_rsz(rsz_base, rsc_params->h_dif & - RSZ_H_DIF_MASK, reg_base + RSZ_H_DIF); - - val = (rsc_params->h_typ_y & 1) | - ((rsc_params->h_typ_c & 1) << RSZ_TYP_C_SHIFT); - regw_rsz(rsz_base, val, reg_base + RSZ_H_TYP); - - val = (rsc_params->h_lpf_int_y & RSZ_LPF_INT_MASK) | - ((rsc_params->h_lpf_int_c & RSZ_LPF_INT_MASK) << - RSZ_LPF_INT_C_SHIFT); - regw_rsz(rsz_base, val, reg_base + RSZ_H_LPF); - - regw_rsz(rsz_base, rsc_params->dscale_en & 1, reg_base + RSZ_DWN_EN); - - val = (rsc_params->h_dscale_ave_sz & RSZ_DWN_SCALE_AV_SZ_MASK) | - ((rsc_params->v_dscale_ave_sz & RSZ_DWN_SCALE_AV_SZ_MASK) << - RSZ_DWN_SCALE_AV_SZ_V_SHIFT); - regw_rsz(rsz_base, val, reg_base + RSZ_DWN_AV); - - /* setting rgb conversion parameters */ - regw_rsz(rsz_base, rgb->rgb_en, reg_base + RSZ_RGB_EN); - - val = (rgb->rgb_typ << RSZ_RGB_TYP_SHIFT) | - (rgb->rgb_msk0 << RSZ_RGB_MSK0_SHIFT) | - (rgb->rgb_msk1 << RSZ_RGB_MSK1_SHIFT); - regw_rsz(rsz_base, val, reg_base + RSZ_RGB_TYP); - - regw_rsz(rsz_base, rgb->rgb_alpha_val & RSZ_RGB_ALPHA_MASK, - reg_base + RSZ_RGB_BLD); - - /* setting external memory parameters */ - regw_rsz(rsz_base, ext_mem->rsz_sdr_oft_y, reg_base + RSZ_SDR_Y_OFT); - regw_rsz(rsz_base, ext_mem->rsz_sdr_ptr_s_y, - reg_base + RSZ_SDR_Y_PTR_S); - regw_rsz(rsz_base, ext_mem->rsz_sdr_ptr_e_y, - reg_base + RSZ_SDR_Y_PTR_E); - regw_rsz(rsz_base, ext_mem->rsz_sdr_oft_c, reg_base + RSZ_SDR_C_OFT); - regw_rsz(rsz_base, ext_mem->rsz_sdr_ptr_s_c, - reg_base + RSZ_SDR_C_PTR_S); - regw_rsz(rsz_base, (ext_mem->rsz_sdr_ptr_e_c >> 1), - reg_base + RSZ_SDR_C_PTR_E); -} - -/*set the registers of either RSZ0 or RSZ1 */ -static void -ipipe_setup_resizer(void __iomem *rsz_base, struct resizer_params *params) -{ - /* enable MMR gate to write to Resizer */ - regw_rsz(rsz_base, 1, RSZ_GCK_MMR); - - /* Enable resizer if it is not in bypass mode */ - if (params->rsz_common.passthrough) - regw_rsz(rsz_base, 0, RSZ_GCK_SDR); - else - regw_rsz(rsz_base, 1, RSZ_GCK_SDR); - - rsz_set_common_params(rsz_base, params); - - regw_rsz(rsz_base, params->rsz_en[RSZ_A], RSZ_EN_A); - - if (params->rsz_en[RSZ_A]) - /*setting rescale parameters */ - rsz_set_rsz_regs(rsz_base, RSZ_A, params); - - regw_rsz(rsz_base, params->rsz_en[RSZ_B], RSZ_EN_B); - - if (params->rsz_en[RSZ_B]) - rsz_set_rsz_regs(rsz_base, RSZ_B, params); -} - -static u32 ipipe_get_color_pat(u32 pix) -{ - switch (pix) { - case MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8: - case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8: - case MEDIA_BUS_FMT_SGRBG12_1X12: - return ipipe_sgrbg_pattern; - - default: - return ipipe_srggb_pattern; - } -} - -static int ipipe_get_data_path(struct vpfe_ipipe_device *ipipe) -{ - u32 temp_pix_fmt; - - switch (ipipe->formats[IPIPE_PAD_SINK].code) { - case MEDIA_BUS_FMT_SBGGR8_1X8: - case MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8: - case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8: - case MEDIA_BUS_FMT_SGRBG12_1X12: - temp_pix_fmt = MEDIA_BUS_FMT_SGRBG12_1X12; - break; - - default: - temp_pix_fmt = MEDIA_BUS_FMT_UYVY8_2X8; - } - - if (temp_pix_fmt == MEDIA_BUS_FMT_SGRBG12_1X12) { - if (ipipe->formats[IPIPE_PAD_SOURCE].code == - MEDIA_BUS_FMT_SGRBG12_1X12) - return IPIPE_RAW2RAW; - return IPIPE_RAW2YUV; - } - - return IPIPE_YUV2YUV; -} - -static int get_ipipe_mode(struct vpfe_ipipe_device *ipipe) -{ - struct vpfe_device *vpfe_dev = to_vpfe_device(ipipe); - u16 ipipeif_sink = vpfe_dev->vpfe_ipipeif.input; - - if (ipipeif_sink == IPIPEIF_INPUT_MEMORY) - return IPIPE_MODE_SINGLE_SHOT; - if (ipipeif_sink == IPIPEIF_INPUT_ISIF) - return IPIPE_MODE_CONTINUOUS; - - return -EINVAL; -} - -int config_ipipe_hw(struct vpfe_ipipe_device *ipipe) -{ - struct vpfe_ipipe_input_config *config = &ipipe->config.input_config; - void __iomem *ipipe_base = ipipe->base_addr; - struct v4l2_mbus_framefmt *outformat; - u32 color_pat; - int ipipe_mode; - u32 data_path; - - /* enable clock to IPIPE */ - vpss_enable_clock(VPSS_IPIPE_CLOCK, 1); - ipipe_clock_enable(ipipe_base); - - if (ipipe->input == IPIPE_INPUT_NONE) { - regw_ip(ipipe_base, 0, IPIPE_SRC_EN); - return 0; - } - - ipipe_mode = get_ipipe_mode(ipipe); - if (ipipe_mode < 0) { - pr_err("Failed to get ipipe mode"); - return -EINVAL; - } - regw_ip(ipipe_base, ipipe_mode, IPIPE_SRC_MODE); - - data_path = ipipe_get_data_path(ipipe); - regw_ip(ipipe_base, data_path, IPIPE_SRC_FMT); - - regw_ip(ipipe_base, config->vst & IPIPE_RSZ_VPS_MASK, IPIPE_SRC_VPS); - regw_ip(ipipe_base, config->hst & IPIPE_RSZ_HPS_MASK, IPIPE_SRC_HPS); - - outformat = &ipipe->formats[IPIPE_PAD_SOURCE]; - regw_ip(ipipe_base, (outformat->height + 1) & IPIPE_RSZ_VSZ_MASK, - IPIPE_SRC_VSZ); - regw_ip(ipipe_base, (outformat->width + 1) & IPIPE_RSZ_HSZ_MASK, - IPIPE_SRC_HSZ); - - if (data_path == IPIPE_RAW2YUV || - data_path == IPIPE_RAW2RAW) { - color_pat = - ipipe_get_color_pat(ipipe->formats[IPIPE_PAD_SINK].code); - regw_ip(ipipe_base, color_pat, IPIPE_SRC_COL); - } - - return 0; -} - -/* - * config_rsz_hw() - Performs hardware setup of resizer. - */ -int config_rsz_hw(struct vpfe_resizer_device *resizer, - struct resizer_params *config) -{ - struct vpfe_device *vpfe_dev = to_vpfe_device(resizer); - void __iomem *ipipe_base = vpfe_dev->vpfe_ipipe.base_addr; - void __iomem *rsz_base = vpfe_dev->vpfe_resizer.base_addr; - - /* enable VPSS clock */ - vpss_enable_clock(VPSS_IPIPE_CLOCK, 1); - ipipe_clock_enable(ipipe_base); - - ipipe_setup_resizer(rsz_base, config); - - return 0; -} - -static void -rsz_set_y_address(void __iomem *rsz_base, unsigned int address, - unsigned int offset) -{ - u32 val; - - val = address & SET_LOW_ADDR; - regw_rsz(rsz_base, val, offset + RSZ_SDR_Y_BAD_L); - regw_rsz(rsz_base, val, offset + RSZ_SDR_Y_SAD_L); - - val = (address & SET_HIGH_ADDR) >> 16; - regw_rsz(rsz_base, val, offset + RSZ_SDR_Y_BAD_H); - regw_rsz(rsz_base, val, offset + RSZ_SDR_Y_SAD_H); -} - -static void -rsz_set_c_address(void __iomem *rsz_base, unsigned int address, - unsigned int offset) -{ - u32 val; - - val = address & SET_LOW_ADDR; - regw_rsz(rsz_base, val, offset + RSZ_SDR_C_BAD_L); - regw_rsz(rsz_base, val, offset + RSZ_SDR_C_SAD_L); - - val = (address & SET_HIGH_ADDR) >> 16; - regw_rsz(rsz_base, val, offset + RSZ_SDR_C_BAD_H); - regw_rsz(rsz_base, val, offset + RSZ_SDR_C_SAD_H); -} - -/* - * resizer_set_outaddr() - set the address for given resize_no - * @rsz_base: resizer base address - * @params: pointer to ipipe_params structure - * @resize_no: 0 - Resizer-A, 1 - Resizer B - * @address: the address to set - */ -int -resizer_set_outaddr(void __iomem *rsz_base, struct resizer_params *params, - int resize_no, unsigned int address) -{ - struct resizer_scale_param *rsc_param; - struct rsz_ext_mem_param *mem_param; - struct rsz_common_params *rsz_common; - unsigned int rsz_start_add; - unsigned int val; - - if (resize_no != RSZ_A && resize_no != RSZ_B) - return -EINVAL; - - mem_param = ¶ms->ext_mem_param[resize_no]; - rsc_param = ¶ms->rsz_rsc_param[resize_no]; - rsz_common = ¶ms->rsz_common; - - if (resize_no == RSZ_A) - rsz_start_add = RSZ_EN_A; - else - rsz_start_add = RSZ_EN_B; - - /* y_c = 0 for y, = 1 for c */ - if (rsz_common->src_img_fmt == RSZ_IMG_420) { - if (rsz_common->y_c) { - /* C channel */ - val = address + mem_param->flip_ofst_c; - rsz_set_c_address(rsz_base, val, rsz_start_add); - } else { - val = address + mem_param->flip_ofst_y; - rsz_set_y_address(rsz_base, val, rsz_start_add); - } - } else { - if (rsc_param->cen && rsc_param->yen) { - /* 420 */ - val = address + mem_param->c_offset + - mem_param->flip_ofst_c + - mem_param->user_y_ofst + - mem_param->user_c_ofst; - if (resize_no == RSZ_B) - val += - params->ext_mem_param[RSZ_A].user_y_ofst + - params->ext_mem_param[RSZ_A].user_c_ofst; - /* set C address */ - rsz_set_c_address(rsz_base, val, rsz_start_add); - } - val = address + mem_param->flip_ofst_y + mem_param->user_y_ofst; - if (resize_no == RSZ_B) - val += params->ext_mem_param[RSZ_A].user_y_ofst + - params->ext_mem_param[RSZ_A].user_c_ofst; - /* set Y address */ - rsz_set_y_address(rsz_base, val, rsz_start_add); - } - /* resizer must be enabled */ - regw_rsz(rsz_base, params->rsz_en[resize_no], rsz_start_add); - - return 0; -} - -void -ipipe_set_lutdpc_regs(void __iomem *base_addr, void __iomem *isp5_base_addr, - struct vpfe_ipipe_lutdpc *dpc) -{ - u32 max_tbl_size = LUT_DPC_MAX_SIZE >> 1; - u32 lut_start_addr = DPC_TB0_START_ADDR; - u32 val; - u32 count; - - ipipe_clock_enable(base_addr); - regw_ip(base_addr, dpc->en, DPC_LUT_EN); - - if (dpc->en != 1) - return; - - val = LUTDPC_TBL_256_EN | (dpc->repl_white & 1); - regw_ip(base_addr, val, DPC_LUT_SEL); - regw_ip(base_addr, LUT_DPC_START_ADDR, DPC_LUT_ADR); - regw_ip(base_addr, dpc->dpc_size, DPC_LUT_SIZ & LUT_DPC_SIZE_MASK); - - for (count = 0; count < dpc->dpc_size; count++) { - if (count >= max_tbl_size) - lut_start_addr = DPC_TB1_START_ADDR; - val = (dpc->table[count].horz_pos & LUT_DPC_H_POS_MASK) | - ((dpc->table[count].vert_pos & LUT_DPC_V_POS_MASK) << - LUT_DPC_V_POS_SHIFT) | (dpc->table[count].method << - LUT_DPC_CORR_METH_SHIFT); - w_ip_table(isp5_base_addr, val, (lut_start_addr + - ((count % max_tbl_size) << 2))); - } -} - -static void -set_dpc_thresholds(void __iomem *base_addr, - struct vpfe_ipipe_otfdpc_2_0_cfg *dpc_thr) -{ - regw_ip(base_addr, dpc_thr->corr_thr.r & OTFDPC_DPC2_THR_MASK, - DPC_OTF_2C_THR_R); - regw_ip(base_addr, dpc_thr->corr_thr.gr & OTFDPC_DPC2_THR_MASK, - DPC_OTF_2C_THR_GR); - regw_ip(base_addr, dpc_thr->corr_thr.gb & OTFDPC_DPC2_THR_MASK, - DPC_OTF_2C_THR_GB); - regw_ip(base_addr, dpc_thr->corr_thr.b & OTFDPC_DPC2_THR_MASK, - DPC_OTF_2C_THR_B); - regw_ip(base_addr, dpc_thr->det_thr.r & OTFDPC_DPC2_THR_MASK, - DPC_OTF_2D_THR_R); - regw_ip(base_addr, dpc_thr->det_thr.gr & OTFDPC_DPC2_THR_MASK, - DPC_OTF_2D_THR_GR); - regw_ip(base_addr, dpc_thr->det_thr.gb & OTFDPC_DPC2_THR_MASK, - DPC_OTF_2D_THR_GB); - regw_ip(base_addr, dpc_thr->det_thr.b & OTFDPC_DPC2_THR_MASK, - DPC_OTF_2D_THR_B); -} - -void ipipe_set_otfdpc_regs(void __iomem *base_addr, - struct vpfe_ipipe_otfdpc *otfdpc) -{ - struct vpfe_ipipe_otfdpc_2_0_cfg *dpc_2_0 = &otfdpc->alg_cfg.dpc_2_0; - struct vpfe_ipipe_otfdpc_3_0_cfg *dpc_3_0 = &otfdpc->alg_cfg.dpc_3_0; - u32 val; - - ipipe_clock_enable(base_addr); - - regw_ip(base_addr, (otfdpc->en & 1), DPC_OTF_EN); - if (!otfdpc->en) - return; - - /* dpc enabled */ - val = (otfdpc->det_method << OTF_DET_METHOD_SHIFT) | otfdpc->alg; - regw_ip(base_addr, val, DPC_OTF_TYP); - - if (otfdpc->det_method == VPFE_IPIPE_DPC_OTF_MIN_MAX) { - /* ALG= 0, TYP = 0, DPC_OTF_2D_THR_[x]=0 - * DPC_OTF_2C_THR_[x] = Maximum thresohld - * MinMax method - */ - dpc_2_0->det_thr.r = dpc_2_0->det_thr.gb = - dpc_2_0->det_thr.gr = dpc_2_0->det_thr.b = 0; - set_dpc_thresholds(base_addr, dpc_2_0); - return; - } - /* MinMax2 */ - if (otfdpc->alg == VPFE_IPIPE_OTFDPC_2_0) { - set_dpc_thresholds(base_addr, dpc_2_0); - return; - } - regw_ip(base_addr, dpc_3_0->act_adj_shf & - OTF_DPC3_0_SHF_MASK, DPC_OTF_3_SHF); - /* Detection thresholds */ - regw_ip(base_addr, ((dpc_3_0->det_thr & OTF_DPC3_0_THR_MASK) << - OTF_DPC3_0_THR_SHIFT), DPC_OTF_3D_THR); - regw_ip(base_addr, dpc_3_0->det_slp & - OTF_DPC3_0_SLP_MASK, DPC_OTF_3D_SLP); - regw_ip(base_addr, dpc_3_0->det_thr_min & - OTF_DPC3_0_DET_MASK, DPC_OTF_3D_MIN); - regw_ip(base_addr, dpc_3_0->det_thr_max & - OTF_DPC3_0_DET_MASK, DPC_OTF_3D_MAX); - /* Correction thresholds */ - regw_ip(base_addr, ((dpc_3_0->corr_thr & OTF_DPC3_0_THR_MASK) << - OTF_DPC3_0_THR_SHIFT), DPC_OTF_3C_THR); - regw_ip(base_addr, dpc_3_0->corr_slp & - OTF_DPC3_0_SLP_MASK, DPC_OTF_3C_SLP); - regw_ip(base_addr, dpc_3_0->corr_thr_min & - OTF_DPC3_0_CORR_MASK, DPC_OTF_3C_MIN); - regw_ip(base_addr, dpc_3_0->corr_thr_max & - OTF_DPC3_0_CORR_MASK, DPC_OTF_3C_MAX); -} - -/* 2D Noise filter */ -void -ipipe_set_d2f_regs(void __iomem *base_addr, unsigned int id, - struct vpfe_ipipe_nf *noise_filter) -{ - - u32 offset = D2F_1ST; - int count; - u32 val; - - if (id == IPIPE_D2F_2ND) - offset = D2F_2ND; - - ipipe_clock_enable(base_addr); - regw_ip(base_addr, noise_filter->en & 1, offset + D2F_EN); - if (!noise_filter->en) - return; - - /*noise filter enabled */ - /* Combine all the fields to make D2F_CFG register of IPIPE */ - val = ((noise_filter->spread_val & D2F_SPR_VAL_MASK) << - D2F_SPR_VAL_SHIFT) | ((noise_filter->shft_val & - D2F_SHFT_VAL_MASK) << D2F_SHFT_VAL_SHIFT) | - (noise_filter->gr_sample_meth << D2F_SAMPLE_METH_SHIFT) | - ((noise_filter->apply_lsc_gain & 1) << - D2F_APPLY_LSC_GAIN_SHIFT) | D2F_USE_SPR_REG_VAL; - regw_ip(base_addr, val, offset + D2F_TYP); - - /* edge detection minimum */ - regw_ip(base_addr, noise_filter->edge_det_min_thr & - D2F_EDGE_DET_THR_MASK, offset + D2F_EDG_MIN); - - /* edge detection maximum */ - regw_ip(base_addr, noise_filter->edge_det_max_thr & - D2F_EDGE_DET_THR_MASK, offset + D2F_EDG_MAX); - - for (count = 0; count < VPFE_IPIPE_NF_STR_TABLE_SIZE; count++) - regw_ip(base_addr, - (noise_filter->str[count] & D2F_STR_VAL_MASK), - offset + D2F_STR + count * 4); - - for (count = 0; count < VPFE_IPIPE_NF_THR_TABLE_SIZE; count++) - regw_ip(base_addr, noise_filter->thr[count] & D2F_THR_VAL_MASK, - offset + D2F_THR + count * 4); -} - -#define IPIPE_U8Q5(decimal, integer) \ - (((decimal & 0x1f) | ((integer & 0x7) << 5))) - -/* Green Imbalance Correction */ -void ipipe_set_gic_regs(void __iomem *base_addr, struct vpfe_ipipe_gic *gic) -{ - u32 val; - - ipipe_clock_enable(base_addr); - regw_ip(base_addr, gic->en & 1, GIC_EN); - - if (!gic->en) - return; - - /*gic enabled */ - val = (gic->wt_fn_type << GIC_TYP_SHIFT) | - (gic->thr_sel << GIC_THR_SEL_SHIFT) | - ((gic->apply_lsc_gain & 1) << GIC_APPLY_LSC_GAIN_SHIFT); - regw_ip(base_addr, val, GIC_TYP); - - regw_ip(base_addr, gic->gain & GIC_GAIN_MASK, GIC_GAN); - - if (gic->gic_alg != VPFE_IPIPE_GIC_ALG_ADAPT_GAIN) { - /* Constant Gain. Set threshold to maximum */ - regw_ip(base_addr, GIC_THR_MASK, GIC_THR); - return; - } - - if (gic->thr_sel == VPFE_IPIPE_GIC_THR_REG) { - regw_ip(base_addr, gic->thr & GIC_THR_MASK, GIC_THR); - regw_ip(base_addr, gic->slope & GIC_SLOPE_MASK, GIC_SLP); - } else { - /* Use NF thresholds */ - val = IPIPE_U8Q5(gic->nf2_thr_gain.decimal, - gic->nf2_thr_gain.integer); - regw_ip(base_addr, val, GIC_NFGAN); - } -} - -#define IPIPE_U13Q9(decimal, integer) \ - (((decimal & 0x1ff) | ((integer & 0xf) << 9))) -/* White balance */ -void ipipe_set_wb_regs(void __iomem *base_addr, struct vpfe_ipipe_wb *wb) -{ - u32 val; - - ipipe_clock_enable(base_addr); - /* Ofsets. S12 */ - regw_ip(base_addr, wb->ofst_r & WB_OFFSET_MASK, WB2_OFT_R); - regw_ip(base_addr, wb->ofst_gr & WB_OFFSET_MASK, WB2_OFT_GR); - regw_ip(base_addr, wb->ofst_gb & WB_OFFSET_MASK, WB2_OFT_GB); - regw_ip(base_addr, wb->ofst_b & WB_OFFSET_MASK, WB2_OFT_B); - - /* Gains. U13Q9 */ - val = IPIPE_U13Q9(wb->gain_r.decimal, wb->gain_r.integer); - regw_ip(base_addr, val, WB2_WGN_R); - - val = IPIPE_U13Q9(wb->gain_gr.decimal, wb->gain_gr.integer); - regw_ip(base_addr, val, WB2_WGN_GR); - - val = IPIPE_U13Q9(wb->gain_gb.decimal, wb->gain_gb.integer); - regw_ip(base_addr, val, WB2_WGN_GB); - - val = IPIPE_U13Q9(wb->gain_b.decimal, wb->gain_b.integer); - regw_ip(base_addr, val, WB2_WGN_B); -} - -/* CFA */ -void ipipe_set_cfa_regs(void __iomem *base_addr, struct vpfe_ipipe_cfa *cfa) -{ - ipipe_clock_enable(base_addr); - - regw_ip(base_addr, cfa->alg, CFA_MODE); - regw_ip(base_addr, cfa->hpf_thr_2dir & CFA_HPF_THR_2DIR_MASK, - CFA_2DIR_HPF_THR); - regw_ip(base_addr, cfa->hpf_slp_2dir & CFA_HPF_SLOPE_2DIR_MASK, - CFA_2DIR_HPF_SLP); - regw_ip(base_addr, cfa->hp_mix_thr_2dir & CFA_HPF_MIX_THR_2DIR_MASK, - CFA_2DIR_MIX_THR); - regw_ip(base_addr, cfa->hp_mix_slope_2dir & CFA_HPF_MIX_SLP_2DIR_MASK, - CFA_2DIR_MIX_SLP); - regw_ip(base_addr, cfa->dir_thr_2dir & CFA_DIR_THR_2DIR_MASK, - CFA_2DIR_DIR_THR); - regw_ip(base_addr, cfa->dir_slope_2dir & CFA_DIR_SLP_2DIR_MASK, - CFA_2DIR_DIR_SLP); - regw_ip(base_addr, cfa->nd_wt_2dir & CFA_ND_WT_2DIR_MASK, - CFA_2DIR_NDWT); - regw_ip(base_addr, cfa->hue_fract_daa & CFA_DAA_HUE_FRA_MASK, - CFA_MONO_HUE_FRA); - regw_ip(base_addr, cfa->edge_thr_daa & CFA_DAA_EDG_THR_MASK, - CFA_MONO_EDG_THR); - regw_ip(base_addr, cfa->thr_min_daa & CFA_DAA_THR_MIN_MASK, - CFA_MONO_THR_MIN); - regw_ip(base_addr, cfa->thr_slope_daa & CFA_DAA_THR_SLP_MASK, - CFA_MONO_THR_SLP); - regw_ip(base_addr, cfa->slope_min_daa & CFA_DAA_SLP_MIN_MASK, - CFA_MONO_SLP_MIN); - regw_ip(base_addr, cfa->slope_slope_daa & CFA_DAA_SLP_SLP_MASK, - CFA_MONO_SLP_SLP); - regw_ip(base_addr, cfa->lp_wt_daa & CFA_DAA_LP_WT_MASK, - CFA_MONO_LPWT); -} - -void -ipipe_set_rgb2rgb_regs(void __iomem *base_addr, unsigned int id, - struct vpfe_ipipe_rgb2rgb *rgb) -{ - u32 offset_mask = RGB2RGB_1_OFST_MASK; - u32 offset = RGB1_MUL_BASE; - u32 integ_mask = 0xf; - u32 val; - - ipipe_clock_enable(base_addr); - - if (id == IPIPE_RGB2RGB_2) { - /* - * For second RGB module, gain integer is 3 bits instead - * of 4, offset has 11 bits insread of 13 - */ - offset = RGB2_MUL_BASE; - integ_mask = 0x7; - offset_mask = RGB2RGB_2_OFST_MASK; - } - /* Gains */ - val = (rgb->coef_rr.decimal & 0xff) | - ((rgb->coef_rr.integer & integ_mask) << 8); - regw_ip(base_addr, val, offset + RGB_MUL_RR); - val = (rgb->coef_gr.decimal & 0xff) | - ((rgb->coef_gr.integer & integ_mask) << 8); - regw_ip(base_addr, val, offset + RGB_MUL_GR); - val = (rgb->coef_br.decimal & 0xff) | - ((rgb->coef_br.integer & integ_mask) << 8); - regw_ip(base_addr, val, offset + RGB_MUL_BR); - val = (rgb->coef_rg.decimal & 0xff) | - ((rgb->coef_rg.integer & integ_mask) << 8); - regw_ip(base_addr, val, offset + RGB_MUL_RG); - val = (rgb->coef_gg.decimal & 0xff) | - ((rgb->coef_gg.integer & integ_mask) << 8); - regw_ip(base_addr, val, offset + RGB_MUL_GG); - val = (rgb->coef_bg.decimal & 0xff) | - ((rgb->coef_bg.integer & integ_mask) << 8); - regw_ip(base_addr, val, offset + RGB_MUL_BG); - val = (rgb->coef_rb.decimal & 0xff) | - ((rgb->coef_rb.integer & integ_mask) << 8); - regw_ip(base_addr, val, offset + RGB_MUL_RB); - val = (rgb->coef_gb.decimal & 0xff) | - ((rgb->coef_gb.integer & integ_mask) << 8); - regw_ip(base_addr, val, offset + RGB_MUL_GB); - val = (rgb->coef_bb.decimal & 0xff) | - ((rgb->coef_bb.integer & integ_mask) << 8); - regw_ip(base_addr, val, offset + RGB_MUL_BB); - - /* Offsets */ - regw_ip(base_addr, rgb->out_ofst_r & offset_mask, offset + RGB_OFT_OR); - regw_ip(base_addr, rgb->out_ofst_g & offset_mask, offset + RGB_OFT_OG); - regw_ip(base_addr, rgb->out_ofst_b & offset_mask, offset + RGB_OFT_OB); -} - -static void -ipipe_update_gamma_tbl(void __iomem *isp5_base_addr, - struct vpfe_ipipe_gamma_entry *table, int size, u32 addr) -{ - int count; - u32 val; - - for (count = 0; count < size; count++) { - val = table[count].slope & GAMMA_MASK; - val |= (table[count].offset & GAMMA_MASK) << GAMMA_SHIFT; - w_ip_table(isp5_base_addr, val, (addr + (count * 4))); - } -} - -void -ipipe_set_gamma_regs(void __iomem *base_addr, void __iomem *isp5_base_addr, - struct vpfe_ipipe_gamma *gamma) -{ - int table_size; - u32 val; - - ipipe_clock_enable(base_addr); - val = (gamma->bypass_r << GAMMA_BYPR_SHIFT) | - (gamma->bypass_b << GAMMA_BYPG_SHIFT) | - (gamma->bypass_g << GAMMA_BYPB_SHIFT) | - (gamma->tbl_sel << GAMMA_TBL_SEL_SHIFT) | - (gamma->tbl_size << GAMMA_TBL_SIZE_SHIFT); - - regw_ip(base_addr, val, GMM_CFG); - - if (gamma->tbl_sel != VPFE_IPIPE_GAMMA_TBL_RAM) - return; - - table_size = gamma->tbl_size; - - if (!gamma->bypass_r) - ipipe_update_gamma_tbl(isp5_base_addr, gamma->table_r, - table_size, GAMMA_R_START_ADDR); - if (!gamma->bypass_b) - ipipe_update_gamma_tbl(isp5_base_addr, gamma->table_b, - table_size, GAMMA_B_START_ADDR); - if (!gamma->bypass_g) - ipipe_update_gamma_tbl(isp5_base_addr, gamma->table_g, - table_size, GAMMA_G_START_ADDR); -} - -void -ipipe_set_3d_lut_regs(void __iomem *base_addr, void __iomem *isp5_base_addr, - struct vpfe_ipipe_3d_lut *lut_3d) -{ - struct vpfe_ipipe_3d_lut_entry *tbl; - u32 bnk_index; - u32 tbl_index; - u32 val; - u32 i; - - ipipe_clock_enable(base_addr); - regw_ip(base_addr, lut_3d->en, D3LUT_EN); - - if (!lut_3d->en) - return; - - /* valid table */ - tbl = lut_3d->table; - for (i = 0; i < VPFE_IPIPE_MAX_SIZE_3D_LUT; i++) { - /* - * Each entry has 0-9 (B), 10-19 (G) and - * 20-29 R values - */ - val = tbl[i].b & D3_LUT_ENTRY_MASK; - val |= (tbl[i].g & D3_LUT_ENTRY_MASK) << - D3_LUT_ENTRY_G_SHIFT; - val |= (tbl[i].r & D3_LUT_ENTRY_MASK) << - D3_LUT_ENTRY_R_SHIFT; - bnk_index = i % 4; - tbl_index = i >> 2; - tbl_index <<= 2; - if (bnk_index == 0) - w_ip_table(isp5_base_addr, val, - tbl_index + D3L_TB0_START_ADDR); - else if (bnk_index == 1) - w_ip_table(isp5_base_addr, val, - tbl_index + D3L_TB1_START_ADDR); - else if (bnk_index == 2) - w_ip_table(isp5_base_addr, val, - tbl_index + D3L_TB2_START_ADDR); - else - w_ip_table(isp5_base_addr, val, - tbl_index + D3L_TB3_START_ADDR); - } -} - -/* Lumina adjustments */ -void -ipipe_set_lum_adj_regs(void __iomem *base_addr, struct ipipe_lum_adj *lum_adj) -{ - u32 val; - - ipipe_clock_enable(base_addr); - - /* combine fields of YUV_ADJ to set brightness and contrast */ - val = lum_adj->contrast << LUM_ADJ_CONTR_SHIFT | - lum_adj->brightness << LUM_ADJ_BRIGHT_SHIFT; - regw_ip(base_addr, val, YUV_ADJ); -} - -inline u32 ipipe_s12q8(unsigned short decimal, short integer) -{ - return (decimal & 0xff) | ((integer & 0xf) << 8); -} - -void ipipe_set_rgb2ycbcr_regs(void __iomem *base_addr, - struct vpfe_ipipe_rgb2yuv *yuv) -{ - u32 val; - - /* S10Q8 */ - ipipe_clock_enable(base_addr); - val = ipipe_s12q8(yuv->coef_ry.decimal, yuv->coef_ry.integer); - regw_ip(base_addr, val, YUV_MUL_RY); - val = ipipe_s12q8(yuv->coef_gy.decimal, yuv->coef_gy.integer); - regw_ip(base_addr, val, YUV_MUL_GY); - val = ipipe_s12q8(yuv->coef_by.decimal, yuv->coef_by.integer); - regw_ip(base_addr, val, YUV_MUL_BY); - val = ipipe_s12q8(yuv->coef_rcb.decimal, yuv->coef_rcb.integer); - regw_ip(base_addr, val, YUV_MUL_RCB); - val = ipipe_s12q8(yuv->coef_gcb.decimal, yuv->coef_gcb.integer); - regw_ip(base_addr, val, YUV_MUL_GCB); - val = ipipe_s12q8(yuv->coef_bcb.decimal, yuv->coef_bcb.integer); - regw_ip(base_addr, val, YUV_MUL_BCB); - val = ipipe_s12q8(yuv->coef_rcr.decimal, yuv->coef_rcr.integer); - regw_ip(base_addr, val, YUV_MUL_RCR); - val = ipipe_s12q8(yuv->coef_gcr.decimal, yuv->coef_gcr.integer); - regw_ip(base_addr, val, YUV_MUL_GCR); - val = ipipe_s12q8(yuv->coef_bcr.decimal, yuv->coef_bcr.integer); - regw_ip(base_addr, val, YUV_MUL_BCR); - regw_ip(base_addr, yuv->out_ofst_y & RGB2YCBCR_OFST_MASK, YUV_OFT_Y); - regw_ip(base_addr, yuv->out_ofst_cb & RGB2YCBCR_OFST_MASK, YUV_OFT_CB); - regw_ip(base_addr, yuv->out_ofst_cr & RGB2YCBCR_OFST_MASK, YUV_OFT_CR); -} - -/* YUV 422 conversion */ -void -ipipe_set_yuv422_conv_regs(void __iomem *base_addr, - struct vpfe_ipipe_yuv422_conv *conv) -{ - u32 val; - - ipipe_clock_enable(base_addr); - - /* Combine all the fields to make YUV_PHS register of IPIPE */ - val = (conv->chrom_pos << 0) | (conv->en_chrom_lpf << 1); - regw_ip(base_addr, val, YUV_PHS); -} - -void -ipipe_set_gbce_regs(void __iomem *base_addr, void __iomem *isp5_base_addr, - struct vpfe_ipipe_gbce *gbce) -{ - unsigned int count; - u32 mask = GBCE_Y_VAL_MASK; - - if (gbce->type == VPFE_IPIPE_GBCE_GAIN_TBL) - mask = GBCE_GAIN_VAL_MASK; - - ipipe_clock_enable(base_addr); - regw_ip(base_addr, gbce->en & 1, GBCE_EN); - - if (!gbce->en) - return; - - regw_ip(base_addr, gbce->type, GBCE_TYP); - - for (count = 0; count < VPFE_IPIPE_MAX_SIZE_GBCE_LUT; count += 2) - w_ip_table(isp5_base_addr, ((gbce->table[count + 1] & mask) << - GBCE_ENTRY_SHIFT) | (gbce->table[count] & mask), - ((count/2) << 2) + GBCE_TB_START_ADDR); -} - -void -ipipe_set_ee_regs(void __iomem *base_addr, void __iomem *isp5_base_addr, - struct vpfe_ipipe_yee *ee) -{ - unsigned int count; - u32 val; - - ipipe_clock_enable(base_addr); - regw_ip(base_addr, ee->en, YEE_EN); - - if (!ee->en) - return; - - val = ee->en_halo_red & 1; - val |= ee->merge_meth << YEE_HALO_RED_EN_SHIFT; - regw_ip(base_addr, val, YEE_TYP); - - regw_ip(base_addr, ee->hpf_shft, YEE_SHF); - regw_ip(base_addr, ee->hpf_coef_00 & YEE_COEF_MASK, YEE_MUL_00); - regw_ip(base_addr, ee->hpf_coef_01 & YEE_COEF_MASK, YEE_MUL_01); - regw_ip(base_addr, ee->hpf_coef_02 & YEE_COEF_MASK, YEE_MUL_02); - regw_ip(base_addr, ee->hpf_coef_10 & YEE_COEF_MASK, YEE_MUL_10); - regw_ip(base_addr, ee->hpf_coef_11 & YEE_COEF_MASK, YEE_MUL_11); - regw_ip(base_addr, ee->hpf_coef_12 & YEE_COEF_MASK, YEE_MUL_12); - regw_ip(base_addr, ee->hpf_coef_20 & YEE_COEF_MASK, YEE_MUL_20); - regw_ip(base_addr, ee->hpf_coef_21 & YEE_COEF_MASK, YEE_MUL_21); - regw_ip(base_addr, ee->hpf_coef_22 & YEE_COEF_MASK, YEE_MUL_22); - regw_ip(base_addr, ee->yee_thr & YEE_THR_MASK, YEE_THR); - regw_ip(base_addr, ee->es_gain & YEE_ES_GAIN_MASK, YEE_E_GAN); - regw_ip(base_addr, ee->es_thr1 & YEE_ES_THR1_MASK, YEE_E_THR1); - regw_ip(base_addr, ee->es_thr2 & YEE_THR_MASK, YEE_E_THR2); - regw_ip(base_addr, ee->es_gain_grad & YEE_THR_MASK, YEE_G_GAN); - regw_ip(base_addr, ee->es_ofst_grad & YEE_THR_MASK, YEE_G_OFT); - - for (count = 0; count < VPFE_IPIPE_MAX_SIZE_YEE_LUT; count += 2) - w_ip_table(isp5_base_addr, ((ee->table[count + 1] & - YEE_ENTRY_MASK) << YEE_ENTRY_SHIFT) | - (ee->table[count] & YEE_ENTRY_MASK), - ((count/2) << 2) + YEE_TB_START_ADDR); -} - -/* Chromatic Artifact Correction. CAR */ -static void ipipe_set_mf(void __iomem *base_addr) -{ - /* typ to dynamic switch */ - regw_ip(base_addr, VPFE_IPIPE_CAR_DYN_SWITCH, CAR_TYP); - /* Set SW0 to maximum */ - regw_ip(base_addr, CAR_MF_THR, CAR_SW); -} - -static void -ipipe_set_gain_ctrl(void __iomem *base_addr, struct vpfe_ipipe_car *car) -{ - regw_ip(base_addr, VPFE_IPIPE_CAR_CHR_GAIN_CTRL, CAR_TYP); - regw_ip(base_addr, car->hpf, CAR_HPF_TYP); - regw_ip(base_addr, car->hpf_shft & CAR_HPF_SHIFT_MASK, CAR_HPF_SHF); - regw_ip(base_addr, car->hpf_thr, CAR_HPF_THR); - regw_ip(base_addr, car->gain1.gain, CAR_GN1_GAN); - regw_ip(base_addr, car->gain1.shft & CAR_GAIN1_SHFT_MASK, CAR_GN1_SHF); - regw_ip(base_addr, car->gain1.gain_min & CAR_GAIN_MIN_MASK, - CAR_GN1_MIN); - regw_ip(base_addr, car->gain2.gain, CAR_GN2_GAN); - regw_ip(base_addr, car->gain2.shft & CAR_GAIN2_SHFT_MASK, CAR_GN2_SHF); - regw_ip(base_addr, car->gain2.gain_min & CAR_GAIN_MIN_MASK, - CAR_GN2_MIN); -} - -void ipipe_set_car_regs(void __iomem *base_addr, struct vpfe_ipipe_car *car) -{ - u32 val; - - ipipe_clock_enable(base_addr); - regw_ip(base_addr, car->en, CAR_EN); - - if (!car->en) - return; - - switch (car->meth) { - case VPFE_IPIPE_CAR_MED_FLTR: - ipipe_set_mf(base_addr); - break; - - case VPFE_IPIPE_CAR_CHR_GAIN_CTRL: - ipipe_set_gain_ctrl(base_addr, car); - break; - - default: - /* Dynamic switch between MF and Gain Ctrl. */ - ipipe_set_mf(base_addr); - ipipe_set_gain_ctrl(base_addr, car); - /* Set the threshold for switching between - * the two Here we overwrite the MF SW0 value - */ - regw_ip(base_addr, VPFE_IPIPE_CAR_DYN_SWITCH, CAR_TYP); - val = car->sw1; - val <<= CAR_SW1_SHIFT; - val |= car->sw0; - regw_ip(base_addr, val, CAR_SW); - } -} - -/* Chromatic Gain Suppression */ -void ipipe_set_cgs_regs(void __iomem *base_addr, struct vpfe_ipipe_cgs *cgs) -{ - ipipe_clock_enable(base_addr); - regw_ip(base_addr, cgs->en, CGS_EN); - - if (!cgs->en) - return; - - /* Set the bright side parameters */ - regw_ip(base_addr, cgs->h_thr, CGS_GN1_H_THR); - regw_ip(base_addr, cgs->h_slope, CGS_GN1_H_GAN); - regw_ip(base_addr, cgs->h_shft & CAR_SHIFT_MASK, CGS_GN1_H_SHF); - regw_ip(base_addr, cgs->h_min, CGS_GN1_H_MIN); -} - -void rsz_src_enable(void __iomem *rsz_base, int enable) -{ - regw_rsz(rsz_base, enable, RSZ_SRC_EN); -} - -int rsz_enable(void __iomem *rsz_base, int rsz_id, int enable) -{ - if (rsz_id == RSZ_A) { - regw_rsz(rsz_base, enable, RSZ_EN_A); - /* We always enable RSZ_A. RSZ_B is enable upon request from - * application. So enable RSZ_SRC_EN along with RSZ_A - */ - regw_rsz(rsz_base, enable, RSZ_SRC_EN); - } else if (rsz_id == RSZ_B) { - regw_rsz(rsz_base, enable, RSZ_EN_B); - } else { - BUG(); - } - - return 0; -} diff --git a/drivers/staging/media/davinci_vpfe/dm365_ipipe_hw.h b/drivers/staging/media/davinci_vpfe/dm365_ipipe_hw.h deleted file mode 100644 index 16b6a14b7058..000000000000 --- a/drivers/staging/media/davinci_vpfe/dm365_ipipe_hw.h +++ /dev/null @@ -1,556 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2012 Texas Instruments Inc - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Contributors: - * Manjunath Hadli - * Prabhakar Lad - */ - -#ifndef _DAVINCI_VPFE_DM365_IPIPE_HW_H -#define _DAVINCI_VPFE_DM365_IPIPE_HW_H - -#include "vpfe_mc_capture.h" - -#define SET_LOW_ADDR 0x0000ffff -#define SET_HIGH_ADDR 0xffff0000 - -/* Below are the internal tables */ -#define DPC_TB0_START_ADDR 0x8000 -#define DPC_TB1_START_ADDR 0x8400 - -#define GAMMA_R_START_ADDR 0xa800 -#define GAMMA_G_START_ADDR 0xb000 -#define GAMMA_B_START_ADDR 0xb800 - -/* RAM table addresses for edge enhancement correction*/ -#define YEE_TB_START_ADDR 0x8800 - -/* RAM table address for GBC LUT */ -#define GBCE_TB_START_ADDR 0x9000 - -/* RAM table for 3D NF LUT */ -#define D3L_TB0_START_ADDR 0x9800 -#define D3L_TB1_START_ADDR 0x9c00 -#define D3L_TB2_START_ADDR 0xa000 -#define D3L_TB3_START_ADDR 0xa400 - -/* IPIPE Register Offsets from the base address */ -#define IPIPE_SRC_EN 0x0000 -#define IPIPE_SRC_MODE 0x0004 -#define IPIPE_SRC_FMT 0x0008 -#define IPIPE_SRC_COL 0x000c -#define IPIPE_SRC_VPS 0x0010 -#define IPIPE_SRC_VSZ 0x0014 -#define IPIPE_SRC_HPS 0x0018 -#define IPIPE_SRC_HSZ 0x001c - -#define IPIPE_SEL_SBU 0x0020 - -#define IPIPE_DMA_STA 0x0024 -#define IPIPE_GCK_MMR 0x0028 -#define IPIPE_GCK_PIX 0x002c -#define IPIPE_RESERVED0 0x0030 - -/* Defect Correction */ -#define DPC_LUT_EN 0x0034 -#define DPC_LUT_SEL 0x0038 -#define DPC_LUT_ADR 0x003c -#define DPC_LUT_SIZ 0x0040 -#define DPC_OTF_EN 0x0044 -#define DPC_OTF_TYP 0x0048 -#define DPC_OTF_2D_THR_R 0x004c -#define DPC_OTF_2D_THR_GR 0x0050 -#define DPC_OTF_2D_THR_GB 0x0054 -#define DPC_OTF_2D_THR_B 0x0058 -#define DPC_OTF_2C_THR_R 0x005c -#define DPC_OTF_2C_THR_GR 0x0060 -#define DPC_OTF_2C_THR_GB 0x0064 -#define DPC_OTF_2C_THR_B 0x0068 -#define DPC_OTF_3_SHF 0x006c -#define DPC_OTF_3D_THR 0x0070 -#define DPC_OTF_3D_SLP 0x0074 -#define DPC_OTF_3D_MIN 0x0078 -#define DPC_OTF_3D_MAX 0x007c -#define DPC_OTF_3C_THR 0x0080 -#define DPC_OTF_3C_SLP 0x0084 -#define DPC_OTF_3C_MIN 0x0088 -#define DPC_OTF_3C_MAX 0x008c - -/* Lense Shading Correction */ -#define LSC_VOFT 0x90 -#define LSC_VA2 0x94 -#define LSC_VA1 0x98 -#define LSC_VS 0x9c -#define LSC_HOFT 0xa0 -#define LSC_HA2 0xa4 -#define LSC_HA1 0xa8 -#define LSC_HS 0xac -#define LSC_GAIN_R 0xb0 -#define LSC_GAIN_GR 0xb4 -#define LSC_GAIN_GB 0xb8 -#define LSC_GAIN_B 0xbc -#define LSC_OFT_R 0xc0 -#define LSC_OFT_GR 0xc4 -#define LSC_OFT_GB 0xc8 -#define LSC_OFT_B 0xcc -#define LSC_SHF 0xd0 -#define LSC_MAX 0xd4 - -/* Noise Filter 1. Ofsets from start address given */ -#define D2F_1ST 0xd8 -#define D2F_EN 0x0 -#define D2F_TYP 0x4 -#define D2F_THR 0x8 -#define D2F_STR 0x28 -#define D2F_SPR 0x48 -#define D2F_EDG_MIN 0x68 -#define D2F_EDG_MAX 0x6c - -/* Noise Filter 2 */ -#define D2F_2ND 0x148 - -/* GIC */ -#define GIC_EN 0x1b8 -#define GIC_TYP 0x1bc -#define GIC_GAN 0x1c0 -#define GIC_NFGAN 0x1c4 -#define GIC_THR 0x1c8 -#define GIC_SLP 0x1cc - -/* White Balance */ -#define WB2_OFT_R 0x1d0 -#define WB2_OFT_GR 0x1d4 -#define WB2_OFT_GB 0x1d8 -#define WB2_OFT_B 0x1dc -#define WB2_WGN_R 0x1e0 -#define WB2_WGN_GR 0x1e4 -#define WB2_WGN_GB 0x1e8 -#define WB2_WGN_B 0x1ec - -/* CFA interpolation */ -#define CFA_MODE 0x1f0 -#define CFA_2DIR_HPF_THR 0x1f4 -#define CFA_2DIR_HPF_SLP 0x1f8 -#define CFA_2DIR_MIX_THR 0x1fc -#define CFA_2DIR_MIX_SLP 0x200 -#define CFA_2DIR_DIR_THR 0x204 -#define CFA_2DIR_DIR_SLP 0x208 -#define CFA_2DIR_NDWT 0x20c -#define CFA_MONO_HUE_FRA 0x210 -#define CFA_MONO_EDG_THR 0x214 -#define CFA_MONO_THR_MIN 0x218 -#define CFA_MONO_THR_SLP 0x21c -#define CFA_MONO_SLP_MIN 0x220 -#define CFA_MONO_SLP_SLP 0x224 -#define CFA_MONO_LPWT 0x228 - -/* RGB to RGB conversiona - 1st */ -#define RGB1_MUL_BASE 0x22c -/* Offsets from base */ -#define RGB_MUL_RR 0x0 -#define RGB_MUL_GR 0x4 -#define RGB_MUL_BR 0x8 -#define RGB_MUL_RG 0xc -#define RGB_MUL_GG 0x10 -#define RGB_MUL_BG 0x14 -#define RGB_MUL_RB 0x18 -#define RGB_MUL_GB 0x1c -#define RGB_MUL_BB 0x20 -#define RGB_OFT_OR 0x24 -#define RGB_OFT_OG 0x28 -#define RGB_OFT_OB 0x2c - -/* Gamma */ -#define GMM_CFG 0x25c - -/* RGB to RGB conversiona - 2nd */ -#define RGB2_MUL_BASE 0x260 - -/* 3D LUT */ -#define D3LUT_EN 0x290 - -/* RGB to YUV(YCbCr) conversion */ -#define YUV_ADJ 0x294 -#define YUV_MUL_RY 0x298 -#define YUV_MUL_GY 0x29c -#define YUV_MUL_BY 0x2a0 -#define YUV_MUL_RCB 0x2a4 -#define YUV_MUL_GCB 0x2a8 -#define YUV_MUL_BCB 0x2ac -#define YUV_MUL_RCR 0x2b0 -#define YUV_MUL_GCR 0x2b4 -#define YUV_MUL_BCR 0x2b8 -#define YUV_OFT_Y 0x2bc -#define YUV_OFT_CB 0x2c0 -#define YUV_OFT_CR 0x2c4 -#define YUV_PHS 0x2c8 - -/* Global Brightness and Contrast */ -#define GBCE_EN 0x2cc -#define GBCE_TYP 0x2d0 - -/* Edge Enhancer */ -#define YEE_EN 0x2d4 -#define YEE_TYP 0x2d8 -#define YEE_SHF 0x2dc -#define YEE_MUL_00 0x2e0 -#define YEE_MUL_01 0x2e4 -#define YEE_MUL_02 0x2e8 -#define YEE_MUL_10 0x2ec -#define YEE_MUL_11 0x2f0 -#define YEE_MUL_12 0x2f4 -#define YEE_MUL_20 0x2f8 -#define YEE_MUL_21 0x2fc -#define YEE_MUL_22 0x300 -#define YEE_THR 0x304 -#define YEE_E_GAN 0x308 -#define YEE_E_THR1 0x30c -#define YEE_E_THR2 0x310 -#define YEE_G_GAN 0x314 -#define YEE_G_OFT 0x318 - -/* Chroma Artifact Reduction */ -#define CAR_EN 0x31c -#define CAR_TYP 0x320 -#define CAR_SW 0x324 -#define CAR_HPF_TYP 0x328 -#define CAR_HPF_SHF 0x32c -#define CAR_HPF_THR 0x330 -#define CAR_GN1_GAN 0x334 -#define CAR_GN1_SHF 0x338 -#define CAR_GN1_MIN 0x33c -#define CAR_GN2_GAN 0x340 -#define CAR_GN2_SHF 0x344 -#define CAR_GN2_MIN 0x348 - -/* Chroma Gain Suppression */ -#define CGS_EN 0x34c -#define CGS_GN1_L_THR 0x350 -#define CGS_GN1_L_GAN 0x354 -#define CGS_GN1_L_SHF 0x358 -#define CGS_GN1_L_MIN 0x35c -#define CGS_GN1_H_THR 0x360 -#define CGS_GN1_H_GAN 0x364 -#define CGS_GN1_H_SHF 0x368 -#define CGS_GN1_H_MIN 0x36c -#define CGS_GN2_L_THR 0x370 -#define CGS_GN2_L_GAN 0x374 -#define CGS_GN2_L_SHF 0x378 -#define CGS_GN2_L_MIN 0x37c - -/* Resizer */ -#define RSZ_SRC_EN 0x0 -#define RSZ_SRC_MODE 0x4 -#define RSZ_SRC_FMT0 0x8 -#define RSZ_SRC_FMT1 0xc -#define RSZ_SRC_VPS 0x10 -#define RSZ_SRC_VSZ 0x14 -#define RSZ_SRC_HPS 0x18 -#define RSZ_SRC_HSZ 0x1c -#define RSZ_DMA_RZA 0x20 -#define RSZ_DMA_RZB 0x24 -#define RSZ_DMA_STA 0x28 -#define RSZ_GCK_MMR 0x2c -#define RSZ_RESERVED0 0x30 -#define RSZ_GCK_SDR 0x34 -#define RSZ_IRQ_RZA 0x38 -#define RSZ_IRQ_RZB 0x3c -#define RSZ_YUV_Y_MIN 0x40 -#define RSZ_YUV_Y_MAX 0x44 -#define RSZ_YUV_C_MIN 0x48 -#define RSZ_YUV_C_MAX 0x4c -#define RSZ_YUV_PHS 0x50 -#define RSZ_SEQ 0x54 - -/* Resizer Rescale Parameters */ -#define RSZ_EN_A 0x58 -#define RSZ_EN_B 0xe8 -/* - * offset of the registers to be added with base register of - * either RSZ0 or RSZ1 - */ -#define RSZ_MODE 0x4 -#define RSZ_420 0x8 -#define RSZ_I_VPS 0xc -#define RSZ_I_HPS 0x10 -#define RSZ_O_VSZ 0x14 -#define RSZ_O_HSZ 0x18 -#define RSZ_V_PHS_Y 0x1c -#define RSZ_V_PHS_C 0x20 -#define RSZ_V_DIF 0x24 -#define RSZ_V_TYP 0x28 -#define RSZ_V_LPF 0x2c -#define RSZ_H_PHS 0x30 -#define RSZ_H_PHS_ADJ 0x34 -#define RSZ_H_DIF 0x38 -#define RSZ_H_TYP 0x3c -#define RSZ_H_LPF 0x40 -#define RSZ_DWN_EN 0x44 -#define RSZ_DWN_AV 0x48 - -/* Resizer RGB Conversion Parameters */ -#define RSZ_RGB_EN 0x4c -#define RSZ_RGB_TYP 0x50 -#define RSZ_RGB_BLD 0x54 - -/* Resizer External Memory Parameters */ -#define RSZ_SDR_Y_BAD_H 0x58 -#define RSZ_SDR_Y_BAD_L 0x5c -#define RSZ_SDR_Y_SAD_H 0x60 -#define RSZ_SDR_Y_SAD_L 0x64 -#define RSZ_SDR_Y_OFT 0x68 -#define RSZ_SDR_Y_PTR_S 0x6c -#define RSZ_SDR_Y_PTR_E 0x70 -#define RSZ_SDR_C_BAD_H 0x74 -#define RSZ_SDR_C_BAD_L 0x78 -#define RSZ_SDR_C_SAD_H 0x7c -#define RSZ_SDR_C_SAD_L 0x80 -#define RSZ_SDR_C_OFT 0x84 -#define RSZ_SDR_C_PTR_S 0x88 -#define RSZ_SDR_C_PTR_E 0x8c - -/* Macro for resizer */ -#define RSZ_YUV_Y_MIN 0x40 -#define RSZ_YUV_Y_MAX 0x44 -#define RSZ_YUV_C_MIN 0x48 -#define RSZ_YUV_C_MAX 0x4c - -#define IPIPE_GCK_MMR_DEFAULT 1 -#define IPIPE_GCK_PIX_DEFAULT 0xe -#define RSZ_GCK_MMR_DEFAULT 1 -#define RSZ_GCK_SDR_DEFAULT 1 - -/* LUTDPC */ -#define LUTDPC_TBL_256_EN 0 -#define LUTDPC_INF_TBL_EN 1 -#define LUT_DPC_START_ADDR 0 -#define LUT_DPC_H_POS_MASK 0x1fff -#define LUT_DPC_V_POS_MASK 0x1fff -#define LUT_DPC_V_POS_SHIFT 13 -#define LUT_DPC_CORR_METH_SHIFT 26 -#define LUT_DPC_MAX_SIZE 256 -#define LUT_DPC_SIZE_MASK 0x3ff - -/* OTFDPC */ -#define OTFDPC_DPC2_THR_MASK 0xfff -#define OTF_DET_METHOD_SHIFT 1 -#define OTF_DPC3_0_SHF_MASK 3 -#define OTF_DPC3_0_THR_SHIFT 6 -#define OTF_DPC3_0_THR_MASK 0x3f -#define OTF_DPC3_0_SLP_MASK 0x3f -#define OTF_DPC3_0_DET_MASK 0xfff -#define OTF_DPC3_0_CORR_MASK 0xfff - -/* NF (D2F) */ -#define D2F_SPR_VAL_MASK 0x1f -#define D2F_SPR_VAL_SHIFT 0 -#define D2F_SHFT_VAL_MASK 3 -#define D2F_SHFT_VAL_SHIFT 5 -#define D2F_SAMPLE_METH_SHIFT 7 -#define D2F_APPLY_LSC_GAIN_SHIFT 8 -#define D2F_USE_SPR_REG_VAL 0 -#define D2F_STR_VAL_MASK 0x1f -#define D2F_THR_VAL_MASK 0x3ff -#define D2F_EDGE_DET_THR_MASK 0x7ff - -/* Green Imbalance Correction */ -#define GIC_TYP_SHIFT 0 -#define GIC_THR_SEL_SHIFT 1 -#define GIC_APPLY_LSC_GAIN_SHIFT 2 -#define GIC_GAIN_MASK 0xff -#define GIC_THR_MASK 0xfff -#define GIC_SLOPE_MASK 0xfff -#define GIC_NFGAN_INT_MASK 7 -#define GIC_NFGAN_DECI_MASK 0x1f - -/* WB */ -#define WB_OFFSET_MASK 0xfff -#define WB_GAIN_INT_MASK 0xf -#define WB_GAIN_DECI_MASK 0x1ff - -/* CFA */ -#define CFA_HPF_THR_2DIR_MASK 0x1fff -#define CFA_HPF_SLOPE_2DIR_MASK 0x3ff -#define CFA_HPF_MIX_THR_2DIR_MASK 0x1fff -#define CFA_HPF_MIX_SLP_2DIR_MASK 0x3ff -#define CFA_DIR_THR_2DIR_MASK 0x3ff -#define CFA_DIR_SLP_2DIR_MASK 0x7f -#define CFA_ND_WT_2DIR_MASK 0x3f -#define CFA_DAA_HUE_FRA_MASK 0x3f -#define CFA_DAA_EDG_THR_MASK 0xff -#define CFA_DAA_THR_MIN_MASK 0x3ff -#define CFA_DAA_THR_SLP_MASK 0x3ff -#define CFA_DAA_SLP_MIN_MASK 0x3ff -#define CFA_DAA_SLP_SLP_MASK 0x3ff -#define CFA_DAA_LP_WT_MASK 0x3f - -/* RGB2RGB */ -#define RGB2RGB_1_OFST_MASK 0x1fff -#define RGB2RGB_1_GAIN_INT_MASK 0xf -#define RGB2RGB_GAIN_DECI_MASK 0xff -#define RGB2RGB_2_OFST_MASK 0x7ff -#define RGB2RGB_2_GAIN_INT_MASK 0x7 - -/* Gamma */ -#define GAMMA_BYPR_SHIFT 0 -#define GAMMA_BYPG_SHIFT 1 -#define GAMMA_BYPB_SHIFT 2 -#define GAMMA_TBL_SEL_SHIFT 4 -#define GAMMA_TBL_SIZE_SHIFT 5 -#define GAMMA_MASK 0x3ff -#define GAMMA_SHIFT 10 - -/* 3D LUT */ -#define D3_LUT_ENTRY_MASK 0x3ff -#define D3_LUT_ENTRY_R_SHIFT 20 -#define D3_LUT_ENTRY_G_SHIFT 10 -#define D3_LUT_ENTRY_B_SHIFT 0 - -/* Lumina adj */ -#define LUM_ADJ_CONTR_SHIFT 0 -#define LUM_ADJ_BRIGHT_SHIFT 8 - -/* RGB2YCbCr */ -#define RGB2YCBCR_OFST_MASK 0x7ff -#define RGB2YCBCR_COEF_INT_MASK 0xf -#define RGB2YCBCR_COEF_DECI_MASK 0xff - -/* GBCE */ -#define GBCE_Y_VAL_MASK 0xff -#define GBCE_GAIN_VAL_MASK 0x3ff -#define GBCE_ENTRY_SHIFT 10 - -/* Edge Enhancements */ -#define YEE_HALO_RED_EN_SHIFT 1 -#define YEE_HPF_SHIFT_MASK 0xf -#define YEE_COEF_MASK 0x3ff -#define YEE_THR_MASK 0x3f -#define YEE_ES_GAIN_MASK 0xfff -#define YEE_ES_THR1_MASK 0xfff -#define YEE_ENTRY_SHIFT 9 -#define YEE_ENTRY_MASK 0x1ff - -/* CAR */ -#define CAR_MF_THR 0xff -#define CAR_SW1_SHIFT 8 -#define CAR_GAIN1_SHFT_MASK 7 -#define CAR_GAIN_MIN_MASK 0x1ff -#define CAR_GAIN2_SHFT_MASK 0xf -#define CAR_HPF_SHIFT_MASK 3 - -/* CGS */ -#define CAR_SHIFT_MASK 3 - -/* Resizer */ -#define RSZ_BYPASS_SHIFT 1 -#define RSZ_SRC_IMG_FMT_SHIFT 1 -#define RSZ_SRC_Y_C_SEL_SHIFT 2 -#define IPIPE_RSZ_VPS_MASK 0xffff -#define IPIPE_RSZ_HPS_MASK 0xffff -#define IPIPE_RSZ_VSZ_MASK 0x1fff -#define IPIPE_RSZ_HSZ_MASK 0x1fff -#define RSZ_HPS_MASK 0x1fff -#define RSZ_VPS_MASK 0x1fff -#define RSZ_O_HSZ_MASK 0x1fff -#define RSZ_O_VSZ_MASK 0x1fff -#define RSZ_V_PHS_MASK 0x3fff -#define RSZ_V_DIF_MASK 0x3fff - -#define RSZA_H_FLIP_SHIFT 0 -#define RSZA_V_FLIP_SHIFT 1 -#define RSZB_H_FLIP_SHIFT 2 -#define RSZB_V_FLIP_SHIFT 3 -#define RSZ_A 0 -#define RSZ_B 1 -#define RSZ_CEN_SHIFT 1 -#define RSZ_YEN_SHIFT 0 -#define RSZ_TYP_Y_SHIFT 0 -#define RSZ_TYP_C_SHIFT 1 -#define RSZ_LPF_INT_MASK 0x3f -#define RSZ_LPF_INT_C_SHIFT 6 -#define RSZ_H_PHS_MASK 0x3fff -#define RSZ_H_DIF_MASK 0x3fff -#define RSZ_DIFF_DOWN_THR 256 -#define RSZ_DWN_SCALE_AV_SZ_V_SHIFT 3 -#define RSZ_DWN_SCALE_AV_SZ_MASK 7 -#define RSZ_RGB_MSK1_SHIFT 2 -#define RSZ_RGB_MSK0_SHIFT 1 -#define RSZ_RGB_TYP_SHIFT 0 -#define RSZ_RGB_ALPHA_MASK 0xff - -static inline u32 regr_ip(void __iomem *addr, u32 offset) -{ - return readl(addr + offset); -} - -static inline void regw_ip(void __iomem *addr, u32 val, u32 offset) -{ - writel(val, addr + offset); -} - -static inline u32 w_ip_table(void __iomem *addr, u32 val, u32 offset) -{ - writel(val, addr + offset); - - return val; -} - -static inline u32 regr_rsz(void __iomem *addr, u32 offset) -{ - return readl(addr + offset); -} - -static inline u32 regw_rsz(void __iomem *addr, u32 val, u32 offset) -{ - writel(val, addr + offset); - - return val; -} - -int config_ipipe_hw(struct vpfe_ipipe_device *ipipe); -int resizer_set_outaddr(void __iomem *rsz_base, struct resizer_params *params, - int resize_no, unsigned int address); -int rsz_enable(void __iomem *rsz_base, int rsz_id, int enable); -void rsz_src_enable(void __iomem *rsz_base, int enable); -void rsz_set_in_pix_format(unsigned char y_c); -int config_rsz_hw(struct vpfe_resizer_device *resizer, - struct resizer_params *config); -void ipipe_set_d2f_regs(void __iomem *base_addr, unsigned int id, - struct vpfe_ipipe_nf *noise_filter); -void ipipe_set_rgb2rgb_regs(void __iomem *base_addr, unsigned int id, - struct vpfe_ipipe_rgb2rgb *rgb); -void ipipe_set_yuv422_conv_regs(void __iomem *base_addr, - struct vpfe_ipipe_yuv422_conv *conv); -void ipipe_set_lum_adj_regs(void __iomem *base_addr, - struct ipipe_lum_adj *lum_adj); -void ipipe_set_rgb2ycbcr_regs(void __iomem *base_addr, - struct vpfe_ipipe_rgb2yuv *yuv); -void ipipe_set_lutdpc_regs(void __iomem *base_addr, - void __iomem *isp5_base_addr, struct vpfe_ipipe_lutdpc *lutdpc); -void ipipe_set_otfdpc_regs(void __iomem *base_addr, - struct vpfe_ipipe_otfdpc *otfdpc); -void ipipe_set_3d_lut_regs(void __iomem *base_addr, - void __iomem *isp5_base_addr, struct vpfe_ipipe_3d_lut *lut_3d); -void ipipe_set_gamma_regs(void __iomem *base_addr, - void __iomem *isp5_base_addr, struct vpfe_ipipe_gamma *gamma); -void ipipe_set_ee_regs(void __iomem *base_addr, - void __iomem *isp5_base_addr, struct vpfe_ipipe_yee *ee); -void ipipe_set_gbce_regs(void __iomem *base_addr, - void __iomem *isp5_base_addr, struct vpfe_ipipe_gbce *gbce); -void ipipe_set_gic_regs(void __iomem *base_addr, struct vpfe_ipipe_gic *gic); -void ipipe_set_cfa_regs(void __iomem *base_addr, struct vpfe_ipipe_cfa *cfa); -void ipipe_set_car_regs(void __iomem *base_addr, struct vpfe_ipipe_car *car); -void ipipe_set_cgs_regs(void __iomem *base_addr, struct vpfe_ipipe_cgs *cgs); -void ipipe_set_wb_regs(void __iomem *base_addr, struct vpfe_ipipe_wb *wb); - -#endif /* _DAVINCI_VPFE_DM365_IPIPE_HW_H */ diff --git a/drivers/staging/media/davinci_vpfe/dm365_ipipeif.c b/drivers/staging/media/davinci_vpfe/dm365_ipipeif.c deleted file mode 100644 index 51d4cd1bdb97..000000000000 --- a/drivers/staging/media/davinci_vpfe/dm365_ipipeif.c +++ /dev/null @@ -1,1070 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2012 Texas Instruments Inc - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Contributors: - * Manjunath Hadli - * Prabhakar Lad - */ - -#include "dm365_ipipeif.h" -#include "vpfe_mc_capture.h" - -static const unsigned int ipipeif_input_fmts[] = { - MEDIA_BUS_FMT_UYVY8_2X8, - MEDIA_BUS_FMT_SGRBG12_1X12, - MEDIA_BUS_FMT_Y8_1X8, - MEDIA_BUS_FMT_UV8_1X8, - MEDIA_BUS_FMT_YDYUYDYV8_1X16, - MEDIA_BUS_FMT_SBGGR8_1X8, -}; - -static const unsigned int ipipeif_output_fmts[] = { - MEDIA_BUS_FMT_UYVY8_2X8, - MEDIA_BUS_FMT_SGRBG12_1X12, - MEDIA_BUS_FMT_Y8_1X8, - MEDIA_BUS_FMT_UV8_1X8, - MEDIA_BUS_FMT_YDYUYDYV8_1X16, - MEDIA_BUS_FMT_SBGGR8_1X8, - MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, - MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8, -}; - -static int -ipipeif_get_pack_mode(u32 in_pix_fmt) -{ - switch (in_pix_fmt) { - case MEDIA_BUS_FMT_SBGGR8_1X8: - case MEDIA_BUS_FMT_Y8_1X8: - case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8: - case MEDIA_BUS_FMT_UV8_1X8: - return IPIPEIF_5_1_PACK_8_BIT; - - case MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8: - return IPIPEIF_5_1_PACK_8_BIT_A_LAW; - - case MEDIA_BUS_FMT_SGRBG12_1X12: - return IPIPEIF_5_1_PACK_16_BIT; - - case MEDIA_BUS_FMT_SBGGR12_1X12: - return IPIPEIF_5_1_PACK_12_BIT; - - default: - return IPIPEIF_5_1_PACK_16_BIT; - } -} - -static inline u32 ipipeif_read(void __iomem *addr, u32 offset) -{ - return readl(addr + offset); -} - -static inline void ipipeif_write(u32 val, void __iomem *addr, u32 offset) -{ - writel(val, addr + offset); -} - -static void ipipeif_config_dpc(void __iomem *addr, struct ipipeif_dpc *dpc) -{ - u32 val = 0; - - if (dpc->en) { - val = (dpc->en & 1) << IPIPEIF_DPC2_EN_SHIFT; - val |= dpc->thr & IPIPEIF_DPC2_THR_MASK; - } - ipipeif_write(val, addr, IPIPEIF_DPC2); -} - -#define IPIPEIF_MODE_CONTINUOUS 0 -#define IPIPEIF_MODE_ONE_SHOT 1 - -static int get_oneshot_mode(enum ipipeif_input_entity input) -{ - if (input == IPIPEIF_INPUT_MEMORY) - return IPIPEIF_MODE_ONE_SHOT; - if (input == IPIPEIF_INPUT_ISIF) - return IPIPEIF_MODE_CONTINUOUS; - - return -EINVAL; -} - -static int -ipipeif_get_cfg_src1(struct vpfe_ipipeif_device *ipipeif) -{ - struct v4l2_mbus_framefmt *informat; - - informat = &ipipeif->formats[IPIPEIF_PAD_SINK]; - if (ipipeif->input == IPIPEIF_INPUT_MEMORY && - (informat->code == MEDIA_BUS_FMT_Y8_1X8 || - informat->code == MEDIA_BUS_FMT_UV8_1X8)) - return IPIPEIF_CCDC; - - return IPIPEIF_SRC1_PARALLEL_PORT; -} - -static int -ipipeif_get_data_shift(struct vpfe_ipipeif_device *ipipeif) -{ - struct v4l2_mbus_framefmt *informat; - - informat = &ipipeif->formats[IPIPEIF_PAD_SINK]; - - switch (informat->code) { - case MEDIA_BUS_FMT_SGRBG12_1X12: - return IPIPEIF_5_1_BITS11_0; - - case MEDIA_BUS_FMT_Y8_1X8: - case MEDIA_BUS_FMT_UV8_1X8: - return IPIPEIF_5_1_BITS11_0; - - default: - return IPIPEIF_5_1_BITS7_0; - } -} - -static enum ipipeif_input_source -ipipeif_get_source(struct vpfe_ipipeif_device *ipipeif) -{ - struct v4l2_mbus_framefmt *informat; - - informat = &ipipeif->formats[IPIPEIF_PAD_SINK]; - if (ipipeif->input == IPIPEIF_INPUT_ISIF) - return IPIPEIF_CCDC; - - if (informat->code == MEDIA_BUS_FMT_UYVY8_2X8) - return IPIPEIF_SDRAM_YUV; - - return IPIPEIF_SDRAM_RAW; -} - -void vpfe_ipipeif_ss_buffer_isr(struct vpfe_ipipeif_device *ipipeif) -{ - struct vpfe_video_device *video_in = &ipipeif->video_in; - - if (ipipeif->input != IPIPEIF_INPUT_MEMORY) - return; - - spin_lock(&video_in->dma_queue_lock); - vpfe_video_process_buffer_complete(video_in); - video_in->state = VPFE_VIDEO_BUFFER_NOT_QUEUED; - vpfe_video_schedule_next_buffer(video_in); - spin_unlock(&video_in->dma_queue_lock); -} - -int vpfe_ipipeif_decimation_enabled(struct vpfe_device *vpfe_dev) -{ - struct vpfe_ipipeif_device *ipipeif = &vpfe_dev->vpfe_ipipeif; - - return ipipeif->config.decimation; -} - -int vpfe_ipipeif_get_rsz(struct vpfe_device *vpfe_dev) -{ - struct vpfe_ipipeif_device *ipipeif = &vpfe_dev->vpfe_ipipeif; - - return ipipeif->config.rsz; -} - -#define RD_DATA_15_2 0x7 - -/* - * ipipeif_hw_setup() - This function sets up IPIPEIF - * @sd: pointer to v4l2 subdev structure - * return -EINVAL or zero on success - */ -static int ipipeif_hw_setup(struct v4l2_subdev *sd) -{ - struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *informat, *outformat; - struct ipipeif_params params = ipipeif->config; - enum ipipeif_input_source ipipeif_source; - u32 isif_port_if; - void __iomem *ipipeif_base_addr; - unsigned long val; - int data_shift; - int pack_mode; - int source1; - int tmp; - - ipipeif_base_addr = ipipeif->ipipeif_base_addr; - - /* Enable clock to IPIPEIF and IPIPE */ - vpss_enable_clock(VPSS_IPIPEIF_CLOCK, 1); - - informat = &ipipeif->formats[IPIPEIF_PAD_SINK]; - outformat = &ipipeif->formats[IPIPEIF_PAD_SOURCE]; - - /* Combine all the fields to make CFG1 register of IPIPEIF */ - tmp = val = get_oneshot_mode(ipipeif->input); - if (tmp < 0) { - dev_err(&sd->devnode->dev, "ipipeif: links setup required"); - return -EINVAL; - } - val <<= ONESHOT_SHIFT; - - ipipeif_source = ipipeif_get_source(ipipeif); - val |= ipipeif_source << INPSRC_SHIFT; - - val |= params.clock_select << CLKSEL_SHIFT; - val |= params.avg_filter << AVGFILT_SHIFT; - val |= params.decimation << DECIM_SHIFT; - - pack_mode = ipipeif_get_pack_mode(informat->code); - val |= pack_mode << PACK8IN_SHIFT; - - source1 = ipipeif_get_cfg_src1(ipipeif); - val |= source1 << INPSRC1_SHIFT; - - data_shift = ipipeif_get_data_shift(ipipeif); - if (ipipeif_source != IPIPEIF_SDRAM_YUV) - val |= data_shift << DATASFT_SHIFT; - else - val &= ~(RD_DATA_15_2 << DATASFT_SHIFT); - - ipipeif_write(val, ipipeif_base_addr, IPIPEIF_CFG1); - - switch (ipipeif_source) { - case IPIPEIF_CCDC: - ipipeif_write(ipipeif->gain, ipipeif_base_addr, IPIPEIF_GAIN); - break; - - case IPIPEIF_SDRAM_RAW: - case IPIPEIF_CCDC_DARKFM: - ipipeif_write(ipipeif->gain, ipipeif_base_addr, IPIPEIF_GAIN); - /* fall through */ - case IPIPEIF_SDRAM_YUV: - val |= data_shift << DATASFT_SHIFT; - ipipeif_write(params.ppln, ipipeif_base_addr, IPIPEIF_PPLN); - ipipeif_write(params.lpfr, ipipeif_base_addr, IPIPEIF_LPFR); - ipipeif_write(informat->width, ipipeif_base_addr, IPIPEIF_HNUM); - ipipeif_write(informat->height, - ipipeif_base_addr, IPIPEIF_VNUM); - break; - - default: - return -EINVAL; - } - - /*check if decimation is enable or not */ - if (params.decimation) - ipipeif_write(params.rsz, ipipeif_base_addr, IPIPEIF_RSZ); - - /* Setup sync alignment and initial rsz position */ - val = params.if_5_1.align_sync & 1; - val <<= IPIPEIF_INIRSZ_ALNSYNC_SHIFT; - val |= params.if_5_1.rsz_start & IPIPEIF_INIRSZ_MASK; - ipipeif_write(val, ipipeif_base_addr, IPIPEIF_INIRSZ); - isif_port_if = informat->code; - - if (isif_port_if == MEDIA_BUS_FMT_Y8_1X8) - isif_port_if = MEDIA_BUS_FMT_YUYV8_1X16; - else if (isif_port_if == MEDIA_BUS_FMT_UV8_1X8) - isif_port_if = MEDIA_BUS_FMT_SGRBG12_1X12; - - /* Enable DPCM decompression */ - switch (ipipeif_source) { - case IPIPEIF_SDRAM_RAW: - val = 0; - if (outformat->code == MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8) { - val = 1; - val |= (IPIPEIF_DPCM_8BIT_10BIT & 1) << - IPIPEIF_DPCM_BITS_SHIFT; - val |= (ipipeif->dpcm_predictor & 1) << - IPIPEIF_DPCM_PRED_SHIFT; - } - ipipeif_write(val, ipipeif_base_addr, IPIPEIF_DPCM); - - /* set DPC */ - ipipeif_config_dpc(ipipeif_base_addr, ¶ms.if_5_1.dpc); - - ipipeif_write(params.if_5_1.clip, - ipipeif_base_addr, IPIPEIF_OCLIP); - - /* fall through for SDRAM YUV mode */ - /* configure CFG2 */ - val = ipipeif_read(ipipeif_base_addr, IPIPEIF_CFG2); - switch (isif_port_if) { - case MEDIA_BUS_FMT_YUYV8_1X16: - case MEDIA_BUS_FMT_UYVY8_2X8: - case MEDIA_BUS_FMT_Y8_1X8: - clear_bit(IPIPEIF_CFG2_YUV8_SHIFT, &val); - set_bit(IPIPEIF_CFG2_YUV16_SHIFT, &val); - ipipeif_write(val, ipipeif_base_addr, IPIPEIF_CFG2); - break; - - default: - clear_bit(IPIPEIF_CFG2_YUV8_SHIFT, &val); - clear_bit(IPIPEIF_CFG2_YUV16_SHIFT, &val); - ipipeif_write(val, ipipeif_base_addr, IPIPEIF_CFG2); - break; - } - /* fall through */ - - case IPIPEIF_SDRAM_YUV: - /* Set clock divider */ - if (params.clock_select == IPIPEIF_SDRAM_CLK) { - val = ipipeif_read(ipipeif_base_addr, IPIPEIF_CLKDIV); - val |= (params.if_5_1.clk_div.m - 1) << - IPIPEIF_CLKDIV_M_SHIFT; - val |= (params.if_5_1.clk_div.n - 1); - ipipeif_write(val, ipipeif_base_addr, IPIPEIF_CLKDIV); - } - break; - - case IPIPEIF_CCDC: - case IPIPEIF_CCDC_DARKFM: - /* set DPC */ - ipipeif_config_dpc(ipipeif_base_addr, ¶ms.if_5_1.dpc); - - /* Set DF gain & threshold control */ - val = 0; - if (params.if_5_1.df_gain_en) { - val = params.if_5_1.df_gain_thr & - IPIPEIF_DF_GAIN_THR_MASK; - ipipeif_write(val, ipipeif_base_addr, IPIPEIF_DFSGTH); - val = (params.if_5_1.df_gain_en & 1) << - IPIPEIF_DF_GAIN_EN_SHIFT; - val |= params.if_5_1.df_gain & - IPIPEIF_DF_GAIN_MASK; - } - ipipeif_write(val, ipipeif_base_addr, IPIPEIF_DFSGVL); - /* configure CFG2 */ - val = VPFE_PINPOL_POSITIVE << IPIPEIF_CFG2_HDPOL_SHIFT; - val |= VPFE_PINPOL_POSITIVE << IPIPEIF_CFG2_VDPOL_SHIFT; - - switch (isif_port_if) { - case MEDIA_BUS_FMT_YUYV8_1X16: - case MEDIA_BUS_FMT_YUYV10_1X20: - clear_bit(IPIPEIF_CFG2_YUV8_SHIFT, &val); - set_bit(IPIPEIF_CFG2_YUV16_SHIFT, &val); - break; - - case MEDIA_BUS_FMT_YUYV8_2X8: - case MEDIA_BUS_FMT_UYVY8_2X8: - case MEDIA_BUS_FMT_Y8_1X8: - case MEDIA_BUS_FMT_YUYV10_2X10: - set_bit(IPIPEIF_CFG2_YUV8_SHIFT, &val); - set_bit(IPIPEIF_CFG2_YUV16_SHIFT, &val); - val |= IPIPEIF_CBCR_Y << IPIPEIF_CFG2_YUV8P_SHIFT; - break; - - default: - /* Bayer */ - ipipeif_write(params.if_5_1.clip, ipipeif_base_addr, - IPIPEIF_OCLIP); - } - ipipeif_write(val, ipipeif_base_addr, IPIPEIF_CFG2); - break; - - default: - return -EINVAL; - } - - return 0; -} - -static int -ipipeif_set_config(struct v4l2_subdev *sd, struct ipipeif_params *config) -{ - struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); - struct device *dev = ipipeif->subdev.v4l2_dev->dev; - - if (!config) { - dev_err(dev, "Invalid configuration pointer\n"); - return -EINVAL; - } - - ipipeif->config.clock_select = config->clock_select; - ipipeif->config.ppln = config->ppln; - ipipeif->config.lpfr = config->lpfr; - ipipeif->config.rsz = config->rsz; - ipipeif->config.decimation = config->decimation; - if (ipipeif->config.decimation && - (ipipeif->config.rsz < IPIPEIF_RSZ_MIN || - ipipeif->config.rsz > IPIPEIF_RSZ_MAX)) { - dev_err(dev, "rsz range is %d to %d\n", - IPIPEIF_RSZ_MIN, IPIPEIF_RSZ_MAX); - return -EINVAL; - } - - ipipeif->config.avg_filter = config->avg_filter; - - ipipeif->config.if_5_1.df_gain_thr = config->if_5_1.df_gain_thr; - ipipeif->config.if_5_1.df_gain = config->if_5_1.df_gain; - ipipeif->config.if_5_1.df_gain_en = config->if_5_1.df_gain_en; - - ipipeif->config.if_5_1.rsz_start = config->if_5_1.rsz_start; - ipipeif->config.if_5_1.align_sync = config->if_5_1.align_sync; - ipipeif->config.if_5_1.clip = config->if_5_1.clip; - - ipipeif->config.if_5_1.dpc.en = config->if_5_1.dpc.en; - ipipeif->config.if_5_1.dpc.thr = config->if_5_1.dpc.thr; - - ipipeif->config.if_5_1.clk_div.m = config->if_5_1.clk_div.m; - ipipeif->config.if_5_1.clk_div.n = config->if_5_1.clk_div.n; - - return 0; -} - -static int -ipipeif_get_config(struct v4l2_subdev *sd, void *arg) -{ - struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); - struct ipipeif_params *config = arg; - struct device *dev = ipipeif->subdev.v4l2_dev->dev; - - if (!arg) { - dev_err(dev, "Invalid configuration pointer\n"); - return -EINVAL; - } - - config->clock_select = ipipeif->config.clock_select; - config->ppln = ipipeif->config.ppln; - config->lpfr = ipipeif->config.lpfr; - config->rsz = ipipeif->config.rsz; - config->decimation = ipipeif->config.decimation; - config->avg_filter = ipipeif->config.avg_filter; - - config->if_5_1.df_gain_thr = ipipeif->config.if_5_1.df_gain_thr; - config->if_5_1.df_gain = ipipeif->config.if_5_1.df_gain; - config->if_5_1.df_gain_en = ipipeif->config.if_5_1.df_gain_en; - - config->if_5_1.rsz_start = ipipeif->config.if_5_1.rsz_start; - config->if_5_1.align_sync = ipipeif->config.if_5_1.align_sync; - config->if_5_1.clip = ipipeif->config.if_5_1.clip; - - config->if_5_1.dpc.en = ipipeif->config.if_5_1.dpc.en; - config->if_5_1.dpc.thr = ipipeif->config.if_5_1.dpc.thr; - - config->if_5_1.clk_div.m = ipipeif->config.if_5_1.clk_div.m; - config->if_5_1.clk_div.n = ipipeif->config.if_5_1.clk_div.n; - - return 0; -} - -/* - * ipipeif_ioctl() - Handle ipipeif module private ioctl's - * @sd: pointer to v4l2 subdev structure - * @cmd: configuration command - * @arg: configuration argument - */ -static long ipipeif_ioctl(struct v4l2_subdev *sd, - unsigned int cmd, void *arg) -{ - struct ipipeif_params *config = arg; - int ret = -ENOIOCTLCMD; - - switch (cmd) { - case VIDIOC_VPFE_IPIPEIF_S_CONFIG: - ret = ipipeif_set_config(sd, config); - break; - - case VIDIOC_VPFE_IPIPEIF_G_CONFIG: - ret = ipipeif_get_config(sd, arg); - break; - } - return ret; -} - -/* - * ipipeif_s_ctrl() - Handle set control subdev method - * @ctrl: pointer to v4l2 control structure - */ -static int ipipeif_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct vpfe_ipipeif_device *ipipeif = - container_of(ctrl->handler, struct vpfe_ipipeif_device, ctrls); - - switch (ctrl->id) { - case VPFE_CID_DPCM_PREDICTOR: - ipipeif->dpcm_predictor = ctrl->val; - break; - - case V4L2_CID_GAIN: - ipipeif->gain = ctrl->val; - break; - - default: - return -EINVAL; - } - - return 0; -} - -#define ENABLE_IPIPEIF 0x1 - -void vpfe_ipipeif_enable(struct vpfe_device *vpfe_dev) -{ - struct vpfe_ipipeif_device *ipipeif = &vpfe_dev->vpfe_ipipeif; - void __iomem *ipipeif_base_addr = ipipeif->ipipeif_base_addr; - unsigned char val; - - if (ipipeif->input != IPIPEIF_INPUT_MEMORY) - return; - - do { - val = ipipeif_read(ipipeif_base_addr, IPIPEIF_ENABLE); - } while (val & 0x1); - - ipipeif_write(ENABLE_IPIPEIF, ipipeif_base_addr, IPIPEIF_ENABLE); -} - -/* - * ipipeif_set_stream() - Enable/Disable streaming on ipipeif subdev - * @sd: pointer to v4l2 subdev structure - * @enable: 1 == Enable, 0 == Disable - */ -static int ipipeif_set_stream(struct v4l2_subdev *sd, int enable) -{ - struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); - struct vpfe_device *vpfe_dev = to_vpfe_device(ipipeif); - int ret = 0; - - if (!enable) - return ret; - - ret = ipipeif_hw_setup(sd); - if (!ret) - vpfe_ipipeif_enable(vpfe_dev); - - return ret; -} - -/* - * ipipeif_enum_mbus_code() - Handle pixel format enumeration - * @sd: pointer to v4l2 subdev structure - * @cfg: V4L2 subdev pad config - * @code: pointer to v4l2_subdev_mbus_code_enum structure - * return -EINVAL or zero on success - */ -static int ipipeif_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) -{ - switch (code->pad) { - case IPIPEIF_PAD_SINK: - if (code->index >= ARRAY_SIZE(ipipeif_input_fmts)) - return -EINVAL; - - code->code = ipipeif_input_fmts[code->index]; - break; - - case IPIPEIF_PAD_SOURCE: - if (code->index >= ARRAY_SIZE(ipipeif_output_fmts)) - return -EINVAL; - - code->code = ipipeif_output_fmts[code->index]; - break; - - default: - return -EINVAL; - } - - return 0; -} - -/* - * ipipeif_get_format() - Handle get format by pads subdev method - * @sd: pointer to v4l2 subdev structure - * @cfg: V4L2 subdev pad config - * @fmt: pointer to v4l2 subdev format structure - */ -static int -ipipeif_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *fmt) -{ - struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); - - if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) - fmt->format = ipipeif->formats[fmt->pad]; - else - fmt->format = *(v4l2_subdev_get_try_format(sd, cfg, fmt->pad)); - - return 0; -} - -#define MIN_OUT_WIDTH 32 -#define MIN_OUT_HEIGHT 32 - -/* - * ipipeif_try_format() - Handle try format by pad subdev method - * @ipipeif: VPFE ipipeif device. - * @cfg: V4L2 subdev pad config - * @pad: pad num. - * @fmt: pointer to v4l2 format structure. - * @which : wanted subdev format - */ -static void -ipipeif_try_format(struct vpfe_ipipeif_device *ipipeif, - struct v4l2_subdev_pad_config *cfg, unsigned int pad, - struct v4l2_mbus_framefmt *fmt, - enum v4l2_subdev_format_whence which) -{ - unsigned int max_out_height; - unsigned int max_out_width; - unsigned int i; - - max_out_width = IPIPE_MAX_OUTPUT_WIDTH_A; - max_out_height = IPIPE_MAX_OUTPUT_HEIGHT_A; - - if (pad == IPIPEIF_PAD_SINK) { - for (i = 0; i < ARRAY_SIZE(ipipeif_input_fmts); i++) - if (fmt->code == ipipeif_input_fmts[i]) - break; - - /* If not found, use SBGGR10 as default */ - if (i >= ARRAY_SIZE(ipipeif_input_fmts)) - fmt->code = MEDIA_BUS_FMT_SGRBG12_1X12; - } else if (pad == IPIPEIF_PAD_SOURCE) { - for (i = 0; i < ARRAY_SIZE(ipipeif_output_fmts); i++) - if (fmt->code == ipipeif_output_fmts[i]) - break; - - /* If not found, use UYVY as default */ - if (i >= ARRAY_SIZE(ipipeif_output_fmts)) - fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; - } - - fmt->width = clamp_t(u32, fmt->width, MIN_OUT_HEIGHT, max_out_width); - fmt->height = clamp_t(u32, fmt->height, MIN_OUT_WIDTH, max_out_height); -} - -static int -ipipeif_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_frame_size_enum *fse) -{ - struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt format; - - if (fse->index != 0) - return -EINVAL; - - format.code = fse->code; - format.width = 1; - format.height = 1; - ipipeif_try_format(ipipeif, cfg, fse->pad, &format, fse->which); - fse->min_width = format.width; - fse->min_height = format.height; - - if (format.code != fse->code) - return -EINVAL; - - format.code = fse->code; - format.width = -1; - format.height = -1; - ipipeif_try_format(ipipeif, cfg, fse->pad, &format, fse->which); - fse->max_width = format.width; - fse->max_height = format.height; - - return 0; -} - -/* - * __ipipeif_get_format() - helper function for getting ipipeif format - * @ipipeif: pointer to ipipeif private structure. - * @cfg: V4L2 subdev pad config - * @pad: pad number. - * @which: wanted subdev format. - * - */ -static struct v4l2_mbus_framefmt * -__ipipeif_get_format(struct vpfe_ipipeif_device *ipipeif, - struct v4l2_subdev_pad_config *cfg, unsigned int pad, - enum v4l2_subdev_format_whence which) -{ - if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(&ipipeif->subdev, cfg, pad); - - return &ipipeif->formats[pad]; -} - -/* - * ipipeif_set_format() - Handle set format by pads subdev method - * @sd: pointer to v4l2 subdev structure - * @cfg: V4L2 subdev pad config - * @fmt: pointer to v4l2 subdev format structure - * return -EINVAL or zero on success - */ -static int -ipipeif_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *fmt) -{ - struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *format; - - format = __ipipeif_get_format(ipipeif, cfg, fmt->pad, fmt->which); - if (!format) - return -EINVAL; - - ipipeif_try_format(ipipeif, cfg, fmt->pad, &fmt->format, fmt->which); - *format = fmt->format; - - if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) - return 0; - - if (fmt->pad == IPIPEIF_PAD_SINK && - ipipeif->input != IPIPEIF_INPUT_NONE) - ipipeif->formats[fmt->pad] = fmt->format; - else if (fmt->pad == IPIPEIF_PAD_SOURCE && - ipipeif->output != IPIPEIF_OUTPUT_NONE) - ipipeif->formats[fmt->pad] = fmt->format; - else - return -EINVAL; - - return 0; -} - -static void ipipeif_set_default_config(struct vpfe_ipipeif_device *ipipeif) -{ -#define WIDTH_I 640 -#define HEIGHT_I 480 - - const struct ipipeif_params ipipeif_defaults = { - .clock_select = IPIPEIF_SDRAM_CLK, - .ppln = WIDTH_I + 8, - .lpfr = HEIGHT_I + 10, - .rsz = 16, /* resize ratio 16/rsz */ - .decimation = IPIPEIF_DECIMATION_OFF, - .avg_filter = IPIPEIF_AVG_OFF, - .if_5_1 = { - .clk_div = { - .m = 1, /* clock = sdram clock * (m/n) */ - .n = 6 - }, - .clip = 4095, - }, - }; - memcpy(&ipipeif->config, &ipipeif_defaults, - sizeof(struct ipipeif_params)); -} - -/* - * ipipeif_init_formats() - Initialize formats on all pads - * @sd: VPFE ipipeif V4L2 subdevice - * @fh: V4L2 subdev file handle - * - * Initialize all pad formats with default values. Try formats are initialized - * on the file handle. - */ -static int -ipipeif_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) -{ - struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); - struct v4l2_subdev_format format; - - memset(&format, 0, sizeof(format)); - format.pad = IPIPEIF_PAD_SINK; - format.which = V4L2_SUBDEV_FORMAT_TRY; - format.format.code = MEDIA_BUS_FMT_SGRBG12_1X12; - format.format.width = IPIPE_MAX_OUTPUT_WIDTH_A; - format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_A; - ipipeif_set_format(sd, fh->pad, &format); - - memset(&format, 0, sizeof(format)); - format.pad = IPIPEIF_PAD_SOURCE; - format.which = V4L2_SUBDEV_FORMAT_TRY; - format.format.code = MEDIA_BUS_FMT_UYVY8_2X8; - format.format.width = IPIPE_MAX_OUTPUT_WIDTH_A; - format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_A; - ipipeif_set_format(sd, fh->pad, &format); - - ipipeif_set_default_config(ipipeif); - - return 0; -} - -/* - * ipipeif_video_in_queue() - ipipeif video in queue - * @vpfe_dev: vpfe device pointer - * @addr: buffer address - */ -static int -ipipeif_video_in_queue(struct vpfe_device *vpfe_dev, unsigned long addr) -{ - struct vpfe_ipipeif_device *ipipeif = &vpfe_dev->vpfe_ipipeif; - void __iomem *ipipeif_base_addr = ipipeif->ipipeif_base_addr; - unsigned int adofs; - u32 val; - - if (ipipeif->input != IPIPEIF_INPUT_MEMORY) - return -EINVAL; - - switch (ipipeif->formats[IPIPEIF_PAD_SINK].code) { - case MEDIA_BUS_FMT_Y8_1X8: - case MEDIA_BUS_FMT_UV8_1X8: - case MEDIA_BUS_FMT_YDYUYDYV8_1X16: - adofs = ipipeif->formats[IPIPEIF_PAD_SINK].width; - break; - - default: - adofs = ipipeif->formats[IPIPEIF_PAD_SINK].width << 1; - break; - } - - /* adjust the line len to be a multiple of 32 */ - adofs += 31; - adofs &= ~0x1f; - val = (adofs >> 5) & IPIPEIF_ADOFS_LSB_MASK; - ipipeif_write(val, ipipeif_base_addr, IPIPEIF_ADOFS); - - /* lower sixteen bit */ - val = (addr >> IPIPEIF_ADDRL_SHIFT) & IPIPEIF_ADDRL_MASK; - ipipeif_write(val, ipipeif_base_addr, IPIPEIF_ADDRL); - - /* upper next seven bit */ - val = (addr >> IPIPEIF_ADDRU_SHIFT) & IPIPEIF_ADDRU_MASK; - ipipeif_write(val, ipipeif_base_addr, IPIPEIF_ADDRU); - - return 0; -} - -/* subdev core operations */ -static const struct v4l2_subdev_core_ops ipipeif_v4l2_core_ops = { - .ioctl = ipipeif_ioctl, -}; - -static const struct v4l2_ctrl_ops ipipeif_ctrl_ops = { - .s_ctrl = ipipeif_s_ctrl, -}; - -static const struct v4l2_ctrl_config vpfe_ipipeif_dpcm_pred = { - .ops = &ipipeif_ctrl_ops, - .id = VPFE_CID_DPCM_PREDICTOR, - .name = "DPCM Predictor", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .max = 1, - .step = 1, - .def = 0, -}; - -/* subdev file operations */ -static const struct v4l2_subdev_internal_ops ipipeif_v4l2_internal_ops = { - .open = ipipeif_init_formats, -}; - -/* subdev video operations */ -static const struct v4l2_subdev_video_ops ipipeif_v4l2_video_ops = { - .s_stream = ipipeif_set_stream, -}; - -/* subdev pad operations */ -static const struct v4l2_subdev_pad_ops ipipeif_v4l2_pad_ops = { - .enum_mbus_code = ipipeif_enum_mbus_code, - .enum_frame_size = ipipeif_enum_frame_size, - .get_fmt = ipipeif_get_format, - .set_fmt = ipipeif_set_format, -}; - -/* subdev operations */ -static const struct v4l2_subdev_ops ipipeif_v4l2_ops = { - .core = &ipipeif_v4l2_core_ops, - .video = &ipipeif_v4l2_video_ops, - .pad = &ipipeif_v4l2_pad_ops, -}; - -static const struct vpfe_video_operations video_in_ops = { - .queue = ipipeif_video_in_queue, -}; - -static int -ipipeif_link_setup(struct media_entity *entity, const struct media_pad *local, - const struct media_pad *remote, u32 flags) -{ - struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); - struct vpfe_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd); - struct vpfe_device *vpfe = to_vpfe_device(ipipeif); - unsigned int index = local->index; - - /* FIXME: this is actually a hack! */ - if (is_media_entity_v4l2_subdev(remote->entity)) - index |= 2 << 16; - - switch (index) { - case IPIPEIF_PAD_SINK: - /* Single shot mode */ - if (!(flags & MEDIA_LNK_FL_ENABLED)) { - ipipeif->input = IPIPEIF_INPUT_NONE; - break; - } - ipipeif->input = IPIPEIF_INPUT_MEMORY; - break; - - case IPIPEIF_PAD_SINK | 2 << 16: - /* read from isif */ - if (!(flags & MEDIA_LNK_FL_ENABLED)) { - ipipeif->input = IPIPEIF_INPUT_NONE; - break; - } - if (ipipeif->input != IPIPEIF_INPUT_NONE) - return -EBUSY; - - ipipeif->input = IPIPEIF_INPUT_ISIF; - break; - - case IPIPEIF_PAD_SOURCE | 2 << 16: - if (!(flags & MEDIA_LNK_FL_ENABLED)) { - ipipeif->output = IPIPEIF_OUTPUT_NONE; - break; - } - if (remote->entity == &vpfe->vpfe_ipipe.subdev.entity) - /* connencted to ipipe */ - ipipeif->output = IPIPEIF_OUTPUT_IPIPE; - else if (remote->entity == &vpfe->vpfe_resizer.crop_resizer.subdev.entity) - /* connected to resizer */ - ipipeif->output = IPIPEIF_OUTPUT_RESIZER; - else - return -EINVAL; - break; - - default: - return -EINVAL; - } - - return 0; -} - -static const struct media_entity_operations ipipeif_media_ops = { - .link_setup = ipipeif_link_setup, -}; - -/* - * vpfe_ipipeif_unregister_entities() - Unregister entity - * @ipipeif - pointer to ipipeif subdevice structure. - */ -void vpfe_ipipeif_unregister_entities(struct vpfe_ipipeif_device *ipipeif) -{ - /* unregister video device */ - vpfe_video_unregister(&ipipeif->video_in); - - /* unregister subdev */ - v4l2_device_unregister_subdev(&ipipeif->subdev); - /* cleanup entity */ - media_entity_cleanup(&ipipeif->subdev.entity); -} - -int -vpfe_ipipeif_register_entities(struct vpfe_ipipeif_device *ipipeif, - struct v4l2_device *vdev) -{ - struct vpfe_device *vpfe_dev = to_vpfe_device(ipipeif); - unsigned int flags; - int ret; - - /* Register the subdev */ - ret = v4l2_device_register_subdev(vdev, &ipipeif->subdev); - if (ret < 0) - return ret; - - ret = vpfe_video_register(&ipipeif->video_in, vdev); - if (ret) { - pr_err("Failed to register ipipeif video-in device\n"); - goto fail; - } - ipipeif->video_in.vpfe_dev = vpfe_dev; - - flags = 0; - ret = media_create_pad_link(&ipipeif->video_in.video_dev.entity, 0, - &ipipeif->subdev.entity, 0, flags); - if (ret < 0) - goto fail; - - return 0; -fail: - v4l2_device_unregister_subdev(&ipipeif->subdev); - - return ret; -} - -#define IPIPEIF_GAIN_HIGH 0x3ff -#define IPIPEIF_DEFAULT_GAIN 0x200 - -int vpfe_ipipeif_init(struct vpfe_ipipeif_device *ipipeif, - struct platform_device *pdev) -{ - struct v4l2_subdev *sd = &ipipeif->subdev; - struct media_pad *pads = &ipipeif->pads[0]; - struct media_entity *me = &sd->entity; - static resource_size_t res_len; - struct resource *res; - int ret; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 3); - if (!res) - return -ENOENT; - - res_len = resource_size(res); - res = request_mem_region(res->start, res_len, res->name); - if (!res) - return -EBUSY; - - ipipeif->ipipeif_base_addr = ioremap_nocache(res->start, res_len); - if (!ipipeif->ipipeif_base_addr) { - ret = -EBUSY; - goto fail; - } - - v4l2_subdev_init(sd, &ipipeif_v4l2_ops); - - sd->internal_ops = &ipipeif_v4l2_internal_ops; - strscpy(sd->name, "DAVINCI IPIPEIF", sizeof(sd->name)); - sd->grp_id = 1 << 16; /* group ID for davinci subdevs */ - - v4l2_set_subdevdata(sd, ipipeif); - - sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE; - pads[IPIPEIF_PAD_SINK].flags = MEDIA_PAD_FL_SINK; - pads[IPIPEIF_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; - ipipeif->input = IPIPEIF_INPUT_NONE; - ipipeif->output = IPIPEIF_OUTPUT_NONE; - me->ops = &ipipeif_media_ops; - - ret = media_entity_pads_init(me, IPIPEIF_NUM_PADS, pads); - if (ret) - goto fail; - - v4l2_ctrl_handler_init(&ipipeif->ctrls, 2); - v4l2_ctrl_new_std(&ipipeif->ctrls, &ipipeif_ctrl_ops, - V4L2_CID_GAIN, 0, - IPIPEIF_GAIN_HIGH, 1, IPIPEIF_DEFAULT_GAIN); - v4l2_ctrl_new_custom(&ipipeif->ctrls, &vpfe_ipipeif_dpcm_pred, NULL); - v4l2_ctrl_handler_setup(&ipipeif->ctrls); - sd->ctrl_handler = &ipipeif->ctrls; - - ipipeif->video_in.ops = &video_in_ops; - ipipeif->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - ret = vpfe_video_init(&ipipeif->video_in, "IPIPEIF"); - if (ret) { - pr_err("Failed to init IPIPEIF video-in device\n"); - goto fail; - } - ipipeif_set_default_config(ipipeif); - return 0; -fail: - release_mem_region(res->start, res_len); - return ret; -} - -void -vpfe_ipipeif_cleanup(struct vpfe_ipipeif_device *ipipeif, - struct platform_device *pdev) -{ - struct resource *res; - - v4l2_ctrl_handler_free(&ipipeif->ctrls); - iounmap(ipipeif->ipipeif_base_addr); - res = platform_get_resource(pdev, IORESOURCE_MEM, 3); - if (res) - release_mem_region(res->start, resource_size(res)); - -} diff --git a/drivers/staging/media/davinci_vpfe/dm365_ipipeif.h b/drivers/staging/media/davinci_vpfe/dm365_ipipeif.h deleted file mode 100644 index 4d126fc871f3..000000000000 --- a/drivers/staging/media/davinci_vpfe/dm365_ipipeif.h +++ /dev/null @@ -1,228 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2012 Texas Instruments Inc - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Contributors: - * Manjunath Hadli - * Prabhakar Lad - */ - -#ifndef _DAVINCI_VPFE_DM365_IPIPEIF_H -#define _DAVINCI_VPFE_DM365_IPIPEIF_H - -#include - -#include -#include -#include - -#include "dm365_ipipeif_user.h" -#include "vpfe_video.h" - -/* IPIPE base specific types */ -enum ipipeif_data_shift { - IPIPEIF_BITS15_2 = 0, - IPIPEIF_BITS14_1 = 1, - IPIPEIF_BITS13_0 = 2, - IPIPEIF_BITS12_0 = 3, - IPIPEIF_BITS11_0 = 4, - IPIPEIF_BITS10_0 = 5, - IPIPEIF_BITS9_0 = 6, -}; - -enum ipipeif_clkdiv { - IPIPEIF_DIVIDE_HALF = 0, - IPIPEIF_DIVIDE_THIRD = 1, - IPIPEIF_DIVIDE_FOURTH = 2, - IPIPEIF_DIVIDE_FIFTH = 3, - IPIPEIF_DIVIDE_SIXTH = 4, - IPIPEIF_DIVIDE_EIGHTH = 5, - IPIPEIF_DIVIDE_SIXTEENTH = 6, - IPIPEIF_DIVIDE_THIRTY = 7, -}; - -enum ipipeif_pack_mode { - IPIPEIF_PACK_16_BIT = 0, - IPIPEIF_PACK_8_BIT = 1, -}; - -enum ipipeif_5_1_pack_mode { - IPIPEIF_5_1_PACK_16_BIT = 0, - IPIPEIF_5_1_PACK_8_BIT = 1, - IPIPEIF_5_1_PACK_8_BIT_A_LAW = 2, - IPIPEIF_5_1_PACK_12_BIT = 3 -}; - -enum ipipeif_input_source { - IPIPEIF_CCDC = 0, - IPIPEIF_SDRAM_RAW = 1, - IPIPEIF_CCDC_DARKFM = 2, - IPIPEIF_SDRAM_YUV = 3, -}; - -enum ipipeif_ialaw { - IPIPEIF_ALAW_OFF = 0, - IPIPEIF_ALAW_ON = 1, -}; - -enum ipipeif_input_src1 { - IPIPEIF_SRC1_PARALLEL_PORT = 0, - IPIPEIF_SRC1_SDRAM_RAW = 1, - IPIPEIF_SRC1_ISIF_DARKFM = 2, - IPIPEIF_SRC1_SDRAM_YUV = 3, -}; - -enum ipipeif_dfs_dir { - IPIPEIF_PORT_MINUS_SDRAM = 0, - IPIPEIF_SDRAM_MINUS_PORT = 1, -}; - -enum ipipeif_chroma_phase { - IPIPEIF_CBCR_Y = 0, - IPIPEIF_Y_CBCR = 1, -}; - -enum ipipeif_dpcm_type { - IPIPEIF_DPCM_8BIT_10BIT = 0, - IPIPEIF_DPCM_8BIT_12BIT = 1, -}; - -/* data shift for IPIPE 5.1 */ -enum ipipeif_5_1_data_shift { - IPIPEIF_5_1_BITS11_0 = 0, - IPIPEIF_5_1_BITS10_0 = 1, - IPIPEIF_5_1_BITS9_0 = 2, - IPIPEIF_5_1_BITS8_0 = 3, - IPIPEIF_5_1_BITS7_0 = 4, - IPIPEIF_5_1_BITS15_4 = 5, -}; - -#define IPIPEIF_PAD_SINK 0 -#define IPIPEIF_PAD_SOURCE 1 - -#define IPIPEIF_NUM_PADS 2 - -enum ipipeif_input_entity { - IPIPEIF_INPUT_NONE = 0, - IPIPEIF_INPUT_ISIF = 1, - IPIPEIF_INPUT_MEMORY = 2, -}; - -enum ipipeif_output_entity { - IPIPEIF_OUTPUT_NONE = 0, - IPIPEIF_OUTPUT_IPIPE = 1, - IPIPEIF_OUTPUT_RESIZER = 2, -}; - -struct vpfe_ipipeif_device { - struct v4l2_subdev subdev; - struct media_pad pads[IPIPEIF_NUM_PADS]; - struct v4l2_mbus_framefmt formats[IPIPEIF_NUM_PADS]; - enum ipipeif_input_entity input; - unsigned int output; - struct vpfe_video_device video_in; - struct v4l2_ctrl_handler ctrls; - void __iomem *ipipeif_base_addr; - struct ipipeif_params config; - int dpcm_predictor; - int gain; -}; - -/* IPIPEIF Register Offsets from the base address */ -#define IPIPEIF_ENABLE 0x00 -#define IPIPEIF_CFG1 0x04 -#define IPIPEIF_PPLN 0x08 -#define IPIPEIF_LPFR 0x0c -#define IPIPEIF_HNUM 0x10 -#define IPIPEIF_VNUM 0x14 -#define IPIPEIF_ADDRU 0x18 -#define IPIPEIF_ADDRL 0x1c -#define IPIPEIF_ADOFS 0x20 -#define IPIPEIF_RSZ 0x24 -#define IPIPEIF_GAIN 0x28 - -/* Below registers are available only on IPIPE 5.1 */ -#define IPIPEIF_DPCM 0x2c -#define IPIPEIF_CFG2 0x30 -#define IPIPEIF_INIRSZ 0x34 -#define IPIPEIF_OCLIP 0x38 -#define IPIPEIF_DTUDF 0x3c -#define IPIPEIF_CLKDIV 0x40 -#define IPIPEIF_DPC1 0x44 -#define IPIPEIF_DPC2 0x48 -#define IPIPEIF_DFSGVL 0x4c -#define IPIPEIF_DFSGTH 0x50 -#define IPIPEIF_RSZ3A 0x54 -#define IPIPEIF_INIRSZ3A 0x58 -#define IPIPEIF_RSZ_MIN 16 -#define IPIPEIF_RSZ_MAX 112 -#define IPIPEIF_RSZ_CONST 16 - -#define IPIPEIF_ADOFS_LSB_MASK 0x1ff -#define IPIPEIF_ADOFS_LSB_SHIFT 5 -#define IPIPEIF_ADOFS_MSB_MASK 0x200 -#define IPIPEIF_ADDRU_MASK 0x7ff -#define IPIPEIF_ADDRL_SHIFT 5 -#define IPIPEIF_ADDRL_MASK 0xffff -#define IPIPEIF_ADDRU_SHIFT 21 -#define IPIPEIF_ADDRMSB_SHIFT 31 -#define IPIPEIF_ADDRMSB_LEFT_SHIFT 10 - -/* CFG1 Masks and shifts */ -#define ONESHOT_SHIFT 0 -#define DECIM_SHIFT 1 -#define INPSRC_SHIFT 2 -#define CLKDIV_SHIFT 4 -#define AVGFILT_SHIFT 7 -#define PACK8IN_SHIFT 8 -#define IALAW_SHIFT 9 -#define CLKSEL_SHIFT 10 -#define DATASFT_SHIFT 11 -#define INPSRC1_SHIFT 14 - -/* DPC2 */ -#define IPIPEIF_DPC2_EN_SHIFT 12 -#define IPIPEIF_DPC2_THR_MASK 0xfff -/* Applicable for IPIPE 5.1 */ -#define IPIPEIF_DF_GAIN_EN_SHIFT 10 -#define IPIPEIF_DF_GAIN_MASK 0x3ff -#define IPIPEIF_DF_GAIN_THR_MASK 0xfff -/* DPCM */ -#define IPIPEIF_DPCM_BITS_SHIFT 2 -#define IPIPEIF_DPCM_PRED_SHIFT 1 -/* CFG2 */ -#define IPIPEIF_CFG2_HDPOL_SHIFT 1 -#define IPIPEIF_CFG2_VDPOL_SHIFT 2 -#define IPIPEIF_CFG2_YUV8_SHIFT 6 -#define IPIPEIF_CFG2_YUV16_SHIFT 3 -#define IPIPEIF_CFG2_YUV8P_SHIFT 7 - -/* INIRSZ */ -#define IPIPEIF_INIRSZ_ALNSYNC_SHIFT 13 -#define IPIPEIF_INIRSZ_MASK 0x1fff - -/* CLKDIV */ -#define IPIPEIF_CLKDIV_M_SHIFT 8 - -void vpfe_ipipeif_enable(struct vpfe_device *vpfe_dev); -void vpfe_ipipeif_ss_buffer_isr(struct vpfe_ipipeif_device *ipipeif); -int vpfe_ipipeif_decimation_enabled(struct vpfe_device *vpfe_dev); -int vpfe_ipipeif_get_rsz(struct vpfe_device *vpfe_dev); -void vpfe_ipipeif_cleanup(struct vpfe_ipipeif_device *ipipeif, - struct platform_device *pdev); -int vpfe_ipipeif_init(struct vpfe_ipipeif_device *ipipeif, - struct platform_device *pdev); -int vpfe_ipipeif_register_entities(struct vpfe_ipipeif_device *ipipeif, - struct v4l2_device *vdev); -void vpfe_ipipeif_unregister_entities(struct vpfe_ipipeif_device *ipipeif); - -#endif /* _DAVINCI_VPFE_DM365_IPIPEIF_H */ diff --git a/drivers/staging/media/davinci_vpfe/dm365_ipipeif_user.h b/drivers/staging/media/davinci_vpfe/dm365_ipipeif_user.h deleted file mode 100644 index 046dbdec67d8..000000000000 --- a/drivers/staging/media/davinci_vpfe/dm365_ipipeif_user.h +++ /dev/null @@ -1,90 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2012 Texas Instruments Inc - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Contributors: - * Manjunath Hadli - * Prabhakar Lad - */ - -#ifndef _DAVINCI_VPFE_DM365_IPIPEIF_USER_H -#define _DAVINCI_VPFE_DM365_IPIPEIF_USER_H - -/* clockdiv for IPIPE 5.1 */ -struct ipipeif_5_1_clkdiv { - unsigned char m; - unsigned char n; -}; - -enum ipipeif_decimation { - IPIPEIF_DECIMATION_OFF, - IPIPEIF_DECIMATION_ON -}; - -/* DPC at the if for IPIPE 5.1 */ -struct ipipeif_dpc { - /* 0 - disable, 1 - enable */ - unsigned char en; - /* threshold */ - unsigned short thr; -}; - -enum ipipeif_clock { - IPIPEIF_PIXCEL_CLK, - IPIPEIF_SDRAM_CLK -}; - -enum ipipeif_avg_filter { - IPIPEIF_AVG_OFF, - IPIPEIF_AVG_ON -}; - -struct ipipeif_5_1 { - struct ipipeif_5_1_clkdiv clk_div; - /* Defect pixel correction */ - struct ipipeif_dpc dpc; - /* clipped to this value */ - unsigned short clip; - /* Align HSync and VSync to rsz_start */ - unsigned char align_sync; - /* resizer start position */ - unsigned int rsz_start; - /* DF gain enable */ - unsigned char df_gain_en; - /* DF gain value */ - unsigned short df_gain; - /* DF gain threshold value */ - unsigned short df_gain_thr; -}; - -struct ipipeif_params { - enum ipipeif_clock clock_select; - unsigned int ppln; - unsigned int lpfr; - unsigned char rsz; - enum ipipeif_decimation decimation; - enum ipipeif_avg_filter avg_filter; - /* IPIPE 5.1 */ - struct ipipeif_5_1 if_5_1; -}; - -/* - * Private IOCTL - * VIDIOC_VPFE_IPIPEIF_S_CONFIG: Set IPIEIF configuration - * VIDIOC_VPFE_IPIPEIF_G_CONFIG: Get IPIEIF configuration - */ -#define VIDIOC_VPFE_IPIPEIF_S_CONFIG \ - _IOWR('I', BASE_VIDIOC_PRIVATE + 1, struct ipipeif_params) -#define VIDIOC_VPFE_IPIPEIF_G_CONFIG \ - _IOWR('I', BASE_VIDIOC_PRIVATE + 2, struct ipipeif_params) - -#endif /* _DAVINCI_VPFE_DM365_IPIPEIF_USER_H */ diff --git a/drivers/staging/media/davinci_vpfe/dm365_isif.c b/drivers/staging/media/davinci_vpfe/dm365_isif.c deleted file mode 100644 index 05a997f7aa5d..000000000000 --- a/drivers/staging/media/davinci_vpfe/dm365_isif.c +++ /dev/null @@ -1,2097 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2012 Texas Instruments Inc - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Contributors: - * Manjunath Hadli - * Prabhakar Lad - */ - -#include -#include "dm365_isif.h" -#include "vpfe_mc_capture.h" - -#define MAX_WIDTH 4096 -#define MAX_HEIGHT 4096 - -static const unsigned int isif_fmts[] = { - MEDIA_BUS_FMT_YUYV8_2X8, - MEDIA_BUS_FMT_UYVY8_2X8, - MEDIA_BUS_FMT_YUYV8_1X16, - MEDIA_BUS_FMT_YUYV10_1X20, - MEDIA_BUS_FMT_SGRBG12_1X12, - MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8, - MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, -}; - -#define ISIF_COLPTN_R_Ye 0x0 -#define ISIF_COLPTN_Gr_Cy 0x1 -#define ISIF_COLPTN_Gb_G 0x2 -#define ISIF_COLPTN_B_Mg 0x3 - -#define ISIF_CCOLP_CP01_0 0 -#define ISIF_CCOLP_CP03_2 2 -#define ISIF_CCOLP_CP05_4 4 -#define ISIF_CCOLP_CP07_6 6 -#define ISIF_CCOLP_CP11_0 8 -#define ISIF_CCOLP_CP13_2 10 -#define ISIF_CCOLP_CP15_4 12 -#define ISIF_CCOLP_CP17_6 14 - -static const u32 isif_sgrbg_pattern = - ISIF_COLPTN_Gr_Cy << ISIF_CCOLP_CP01_0 | - ISIF_COLPTN_R_Ye << ISIF_CCOLP_CP03_2 | - ISIF_COLPTN_B_Mg << ISIF_CCOLP_CP05_4 | - ISIF_COLPTN_Gb_G << ISIF_CCOLP_CP07_6 | - ISIF_COLPTN_Gr_Cy << ISIF_CCOLP_CP11_0 | - ISIF_COLPTN_R_Ye << ISIF_CCOLP_CP13_2 | - ISIF_COLPTN_B_Mg << ISIF_CCOLP_CP15_4 | - ISIF_COLPTN_Gb_G << ISIF_CCOLP_CP17_6; - -static const u32 isif_srggb_pattern = - ISIF_COLPTN_R_Ye << ISIF_CCOLP_CP01_0 | - ISIF_COLPTN_Gr_Cy << ISIF_CCOLP_CP03_2 | - ISIF_COLPTN_Gb_G << ISIF_CCOLP_CP05_4 | - ISIF_COLPTN_B_Mg << ISIF_CCOLP_CP07_6 | - ISIF_COLPTN_R_Ye << ISIF_CCOLP_CP11_0 | - ISIF_COLPTN_Gr_Cy << ISIF_CCOLP_CP13_2 | - ISIF_COLPTN_Gb_G << ISIF_CCOLP_CP15_4 | - ISIF_COLPTN_B_Mg << ISIF_CCOLP_CP17_6; - -static inline u32 isif_read(void __iomem *base_addr, u32 offset) -{ - return readl(base_addr + offset); -} - -static inline void isif_write(void __iomem *base_addr, u32 val, u32 offset) -{ - writel(val, base_addr + offset); -} - -static inline u32 isif_merge(void __iomem *base_addr, u32 mask, u32 val, - u32 offset) -{ - u32 new_val = (isif_read(base_addr, offset) & ~mask) | (val & mask); - - isif_write(base_addr, new_val, offset); - - return new_val; -} - -static void isif_enable_output_to_sdram(struct vpfe_isif_device *isif, int en) -{ - isif_merge(isif->isif_cfg.base_addr, ISIF_SYNCEN_WEN_MASK, - en << ISIF_SYNCEN_WEN_SHIFT, SYNCEN); -} - -static inline void -isif_regw_lin_tbl(struct vpfe_isif_device *isif, u32 val, u32 offset, int i) -{ - if (!i) - writel(val, isif->isif_cfg.linear_tbl0_addr + offset); - else - writel(val, isif->isif_cfg.linear_tbl1_addr + offset); -} - -static void isif_disable_all_modules(struct vpfe_isif_device *isif) -{ - /* disable BC */ - isif_write(isif->isif_cfg.base_addr, 0, CLAMPCFG); - /* disable vdfc */ - isif_write(isif->isif_cfg.base_addr, 0, DFCCTL); - /* disable CSC */ - isif_write(isif->isif_cfg.base_addr, 0, CSCCTL); - /* disable linearization */ - isif_write(isif->isif_cfg.base_addr, 0, LINCFG0); -} - -static void isif_enable(struct vpfe_isif_device *isif, int en) -{ - if (!en) - /* Before disable isif, disable all ISIF modules */ - isif_disable_all_modules(isif); - - /* - * wait for next VD. Assume lowest scan rate is 12 Hz. So - * 100 msec delay is good enough - */ - msleep(100); - isif_merge(isif->isif_cfg.base_addr, ISIF_SYNCEN_VDHDEN_MASK, - en, SYNCEN); -} - -/* - * ISIF helper functions - */ - -#define DM365_ISIF_MDFS_OFFSET 15 -#define DM365_ISIF_MDFS_MASK 0x1 - -/* get field id in isif hardware */ -enum v4l2_field vpfe_isif_get_fid(struct vpfe_device *vpfe_dev) -{ - struct vpfe_isif_device *isif = &vpfe_dev->vpfe_isif; - u32 field_status; - - field_status = isif_read(isif->isif_cfg.base_addr, MODESET); - return (field_status >> DM365_ISIF_MDFS_OFFSET) & - DM365_ISIF_MDFS_MASK; -} - -static int -isif_set_pixel_format(struct vpfe_isif_device *isif, unsigned int pixfmt) -{ - if (isif->formats[ISIF_PAD_SINK].code == MEDIA_BUS_FMT_SGRBG12_1X12) { - if (pixfmt == V4L2_PIX_FMT_SBGGR16) - isif->isif_cfg.data_pack = ISIF_PACK_16BIT; - else if ((pixfmt == V4L2_PIX_FMT_SGRBG10DPCM8) || - (pixfmt == V4L2_PIX_FMT_SGRBG10ALAW8)) - isif->isif_cfg.data_pack = ISIF_PACK_8BIT; - else - return -EINVAL; - - isif->isif_cfg.bayer.pix_fmt = ISIF_PIXFMT_RAW; - isif->isif_cfg.bayer.v4l2_pix_fmt = pixfmt; - } else { - if (pixfmt == V4L2_PIX_FMT_YUYV) - isif->isif_cfg.ycbcr.pix_order = ISIF_PIXORDER_YCBYCR; - else if (pixfmt == V4L2_PIX_FMT_UYVY) - isif->isif_cfg.ycbcr.pix_order = ISIF_PIXORDER_CBYCRY; - else - return -EINVAL; - - isif->isif_cfg.data_pack = ISIF_PACK_8BIT; - isif->isif_cfg.ycbcr.v4l2_pix_fmt = pixfmt; - } - - return 0; -} - -static int -isif_set_frame_format(struct vpfe_isif_device *isif, - enum isif_frmfmt frm_fmt) -{ - if (isif->formats[ISIF_PAD_SINK].code == MEDIA_BUS_FMT_SGRBG12_1X12) - isif->isif_cfg.bayer.frm_fmt = frm_fmt; - else - isif->isif_cfg.ycbcr.frm_fmt = frm_fmt; - - return 0; -} - -static int isif_set_image_window(struct vpfe_isif_device *isif) -{ - struct v4l2_rect *win = &isif->crop; - - if (isif->formats[ISIF_PAD_SINK].code == MEDIA_BUS_FMT_SGRBG12_1X12) { - isif->isif_cfg.bayer.win.top = win->top; - isif->isif_cfg.bayer.win.left = win->left; - isif->isif_cfg.bayer.win.width = win->width; - isif->isif_cfg.bayer.win.height = win->height; - return 0; - } - isif->isif_cfg.ycbcr.win.top = win->top; - isif->isif_cfg.ycbcr.win.left = win->left; - isif->isif_cfg.ycbcr.win.width = win->width; - isif->isif_cfg.ycbcr.win.height = win->height; - - return 0; -} - -static int -isif_set_buftype(struct vpfe_isif_device *isif, enum isif_buftype buf_type) -{ - if (isif->formats[ISIF_PAD_SINK].code == MEDIA_BUS_FMT_SGRBG12_1X12) - isif->isif_cfg.bayer.buf_type = buf_type; - else - isif->isif_cfg.ycbcr.buf_type = buf_type; - - return 0; -} - -/* configure format in isif hardware */ -static int -isif_config_format(struct vpfe_device *vpfe_dev, unsigned int pad) -{ - struct vpfe_isif_device *vpfe_isif = &vpfe_dev->vpfe_isif; - enum isif_frmfmt frm_fmt = ISIF_FRMFMT_INTERLACED; - struct v4l2_pix_format format; - int ret = 0; - - v4l2_fill_pix_format(&format, &vpfe_dev->vpfe_isif.formats[pad]); - mbus_to_pix(&vpfe_dev->vpfe_isif.formats[pad], &format); - - if (isif_set_pixel_format(vpfe_isif, format.pixelformat) < 0) { - v4l2_err(&vpfe_dev->v4l2_dev, - "Failed to set pixel format in isif\n"); - return -EINVAL; - } - - /* call for s_crop will override these values */ - vpfe_isif->crop.left = 0; - vpfe_isif->crop.top = 0; - vpfe_isif->crop.width = format.width; - vpfe_isif->crop.height = format.height; - - /* configure the image window */ - isif_set_image_window(vpfe_isif); - - switch (vpfe_dev->vpfe_isif.formats[pad].field) { - case V4L2_FIELD_INTERLACED: - /* do nothing, since it is default */ - ret = isif_set_buftype(vpfe_isif, ISIF_BUFTYPE_FLD_INTERLEAVED); - break; - - case V4L2_FIELD_NONE: - frm_fmt = ISIF_FRMFMT_PROGRESSIVE; - /* buffer type only applicable for interlaced scan */ - break; - - case V4L2_FIELD_SEQ_TB: - ret = isif_set_buftype(vpfe_isif, ISIF_BUFTYPE_FLD_SEPARATED); - break; - - default: - return -EINVAL; - } - - /* set the frame format */ - if (!ret) - ret = isif_set_frame_format(vpfe_isif, frm_fmt); - - return ret; -} - -/* - * isif_try_format() - Try video format on a pad - * @isif: VPFE isif device - * @cfg: V4L2 subdev pad config - * @fmt: pointer to v4l2 subdev format structure - */ -static void -isif_try_format(struct vpfe_isif_device *isif, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *fmt) -{ - unsigned int width = fmt->format.width; - unsigned int height = fmt->format.height; - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(isif_fmts); i++) { - if (fmt->format.code == isif_fmts[i]) - break; - } - - /* If not found, use YUYV8_2x8 as default */ - if (i >= ARRAY_SIZE(isif_fmts)) - fmt->format.code = MEDIA_BUS_FMT_YUYV8_2X8; - - /* Clamp the size. */ - fmt->format.width = clamp_t(u32, width, 32, MAX_WIDTH); - fmt->format.height = clamp_t(u32, height, 32, MAX_HEIGHT); - - /* The data formatter truncates the number of horizontal output - * pixels to a multiple of 16. To avoid clipping data, allow - * callers to request an output size bigger than the input size - * up to the nearest multiple of 16. - */ - if (fmt->pad == ISIF_PAD_SOURCE) - fmt->format.width &= ~15; -} - -/* - * vpfe_isif_buffer_isr() - isif module non-progressive buffer scheduling isr - * @isif: Pointer to isif subdevice. - */ -void vpfe_isif_buffer_isr(struct vpfe_isif_device *isif) -{ - struct vpfe_device *vpfe_dev = to_vpfe_device(isif); - struct vpfe_video_device *video = &isif->video_out; - enum v4l2_field field; - int fid; - - if (!video->started) - return; - - field = video->fmt.fmt.pix.field; - - if (field == V4L2_FIELD_NONE) { - /* handle progressive frame capture */ - if (video->cur_frm != video->next_frm) - vpfe_video_process_buffer_complete(video); - return; - } - - /* interlaced or TB capture check which field we - * are in hardware - */ - fid = vpfe_isif_get_fid(vpfe_dev); - - /* switch the software maintained field id */ - video->field_id ^= 1; - if (fid == video->field_id) { - /* we are in-sync here,continue */ - if (fid == 0) { - /* - * One frame is just being captured. If the - * next frame is available, release the current - * frame and move on - */ - if (video->cur_frm != video->next_frm) - vpfe_video_process_buffer_complete(video); - /* - * based on whether the two fields are stored - * interleavely or separately in memory, - * reconfigure the ISIF memory address - */ - if (field == V4L2_FIELD_SEQ_TB) - vpfe_video_schedule_bottom_field(video); - return; - } - /* - * if one field is just being captured configure - * the next frame get the next frame from the - * empty queue if no frame is available hold on - * to the current buffer - */ - spin_lock(&video->dma_queue_lock); - if (!list_empty(&video->dma_queue) && - video->cur_frm == video->next_frm) - vpfe_video_schedule_next_buffer(video); - spin_unlock(&video->dma_queue_lock); - } else if (fid == 0) { - /* - * out of sync. Recover from any hardware out-of-sync. - * May loose one frame - */ - video->field_id = fid; - } -} - -/* - * vpfe_isif_vidint1_isr() - ISIF module progressive buffer scheduling isr - * @isif: Pointer to isif subdevice. - */ -void vpfe_isif_vidint1_isr(struct vpfe_isif_device *isif) -{ - struct vpfe_video_device *video = &isif->video_out; - - if (!video->started) - return; - - spin_lock(&video->dma_queue_lock); - if (video->fmt.fmt.pix.field == V4L2_FIELD_NONE && - !list_empty(&video->dma_queue) && video->cur_frm == video->next_frm) - vpfe_video_schedule_next_buffer(video); - - spin_unlock(&video->dma_queue_lock); -} - -/* - * VPFE video operations - */ - -static int isif_video_queue(struct vpfe_device *vpfe_dev, unsigned long addr) -{ - struct vpfe_isif_device *isif = &vpfe_dev->vpfe_isif; - - isif_write(isif->isif_cfg.base_addr, (addr >> 21) & - ISIF_CADU_BITS, CADU); - isif_write(isif->isif_cfg.base_addr, (addr >> 5) & - ISIF_CADL_BITS, CADL); - - return 0; -} - -static const struct vpfe_video_operations isif_video_ops = { - .queue = isif_video_queue, -}; - -/* - * V4L2 subdev operations - */ - -/* Parameter operations */ -static int isif_get_params(struct v4l2_subdev *sd, void *params) -{ - struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd); - - /* only raw module parameters can be set through the IOCTL */ - if (isif->formats[ISIF_PAD_SINK].code != MEDIA_BUS_FMT_SGRBG12_1X12) - return -EINVAL; - memcpy(params, &isif->isif_cfg.bayer.config_params, - sizeof(isif->isif_cfg.bayer.config_params)); - return 0; -} - -static int isif_validate_df_csc_params(const struct vpfe_isif_df_csc *df_csc) -{ - const struct vpfe_isif_color_space_conv *csc; - int err = -EINVAL; - int i; - - if (!df_csc->df_or_csc) { - /* csc configuration */ - csc = &df_csc->csc; - if (csc->en) { - for (i = 0; i < VPFE_ISIF_CSC_NUM_COEFF; i++) - if (csc->coeff[i].integer > - ISIF_CSC_COEF_INTEG_MASK || - csc->coeff[i].decimal > - ISIF_CSC_COEF_DECIMAL_MASK) { - pr_err("Invalid CSC coefficients\n"); - return err; - } - } - } - if (df_csc->start_pix > ISIF_DF_CSC_SPH_MASK) { - pr_err("Invalid df_csc start pix value\n"); - return err; - } - - if (df_csc->num_pixels > ISIF_DF_NUMPIX) { - pr_err("Invalid df_csc num pixels value\n"); - return err; - } - - if (df_csc->start_line > ISIF_DF_CSC_LNH_MASK) { - pr_err("Invalid df_csc start_line value\n"); - return err; - } - - if (df_csc->num_lines > ISIF_DF_NUMLINES) { - pr_err("Invalid df_csc num_lines value\n"); - return err; - } - - return 0; -} - -#define DM365_ISIF_MAX_VDFLSFT 4 -#define DM365_ISIF_MAX_VDFSLV 4095 -#define DM365_ISIF_MAX_DFCMEM0 0x1fff -#define DM365_ISIF_MAX_DFCMEM1 0x1fff - -static int isif_validate_dfc_params(const struct vpfe_isif_dfc *dfc) -{ - int err = -EINVAL; - int i; - - if (!dfc->en) - return 0; - - if (dfc->corr_whole_line > 1) { - pr_err("Invalid corr_whole_line value\n"); - return err; - } - - if (dfc->def_level_shift > DM365_ISIF_MAX_VDFLSFT) { - pr_err("Invalid def_level_shift value\n"); - return err; - } - - if (dfc->def_sat_level > DM365_ISIF_MAX_VDFSLV) { - pr_err("Invalid def_sat_level value\n"); - return err; - } - - if (!dfc->num_vdefects || - dfc->num_vdefects > VPFE_ISIF_VDFC_TABLE_SIZE) { - pr_err("Invalid num_vdefects value\n"); - return err; - } - - for (i = 0; i < VPFE_ISIF_VDFC_TABLE_SIZE; i++) { - if (dfc->table[i].pos_vert > DM365_ISIF_MAX_DFCMEM0) { - pr_err("Invalid pos_vert value\n"); - return err; - } - if (dfc->table[i].pos_horz > DM365_ISIF_MAX_DFCMEM1) { - pr_err("Invalid pos_horz value\n"); - return err; - } - } - - return 0; -} - -#define DM365_ISIF_MAX_CLVRV 0xfff -#define DM365_ISIF_MAX_CLDC 0x1fff -#define DM365_ISIF_MAX_CLHSH 0x1fff -#define DM365_ISIF_MAX_CLHSV 0x1fff -#define DM365_ISIF_MAX_CLVSH 0x1fff -#define DM365_ISIF_MAX_CLVSV 0x1fff -#define DM365_ISIF_MAX_HEIGHT_BLACK_REGION 0x1fff - -static int isif_validate_bclamp_params(const struct vpfe_isif_black_clamp *bclamp) -{ - int err = -EINVAL; - - if (bclamp->dc_offset > DM365_ISIF_MAX_CLDC) { - pr_err("Invalid bclamp dc_offset value\n"); - return err; - } - if (!bclamp->en) - return 0; - if (bclamp->horz.clamp_pix_limit > 1) { - pr_err("Invalid bclamp horz clamp_pix_limit value\n"); - return err; - } - if (bclamp->horz.win_count_calc < 1 || - bclamp->horz.win_count_calc > 32) { - pr_err("Invalid bclamp horz win_count_calc value\n"); - return err; - } - if (bclamp->horz.win_start_h_calc > DM365_ISIF_MAX_CLHSH) { - pr_err("Invalid bclamp win_start_v_calc value\n"); - return err; - } - - if (bclamp->horz.win_start_v_calc > DM365_ISIF_MAX_CLHSV) { - pr_err("Invalid bclamp win_start_v_calc value\n"); - return err; - } - if (bclamp->vert.reset_clamp_val > DM365_ISIF_MAX_CLVRV) { - pr_err("Invalid bclamp reset_clamp_val value\n"); - return err; - } - if (bclamp->vert.ob_v_sz_calc > DM365_ISIF_MAX_HEIGHT_BLACK_REGION) { - pr_err("Invalid bclamp ob_v_sz_calc value\n"); - return err; - } - if (bclamp->vert.ob_start_h > DM365_ISIF_MAX_CLVSH) { - pr_err("Invalid bclamp ob_start_h value\n"); - return err; - } - if (bclamp->vert.ob_start_v > DM365_ISIF_MAX_CLVSV) { - pr_err("Invalid bclamp ob_start_h value\n"); - return err; - } - return 0; -} - -static int -isif_validate_raw_params(const struct vpfe_isif_raw_config *params) -{ - int ret; - - ret = isif_validate_df_csc_params(¶ms->df_csc); - if (ret) - return ret; - ret = isif_validate_dfc_params(¶ms->dfc); - if (ret) - return ret; - return isif_validate_bclamp_params(¶ms->bclamp); -} - -static int isif_set_params(struct v4l2_subdev *sd, const struct vpfe_isif_raw_config *params) -{ - struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd); - int ret = -EINVAL; - - /* only raw module parameters can be set through the IOCTL */ - if (isif->formats[ISIF_PAD_SINK].code != MEDIA_BUS_FMT_SGRBG12_1X12) - return ret; - - if (!isif_validate_raw_params(params)) { - memcpy(&isif->isif_cfg.bayer.config_params, params, - sizeof(*params)); - ret = 0; - } - return ret; -} -/* - * isif_ioctl() - isif module private ioctl's - * @sd: VPFE isif V4L2 subdevice - * @cmd: ioctl command - * @arg: ioctl argument - * - * Return 0 on success or a negative error code otherwise. - */ -static long isif_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) -{ - switch (cmd) { - case VIDIOC_VPFE_ISIF_S_RAW_PARAMS: - return isif_set_params(sd, arg); - - case VIDIOC_VPFE_ISIF_G_RAW_PARAMS: - return isif_get_params(sd, arg); - - default: - return -ENOIOCTLCMD; - } -} - -static void isif_config_gain_offset(struct vpfe_isif_device *isif) -{ - struct vpfe_isif_gain_offsets_adj *gain_off_ptr = - &isif->isif_cfg.bayer.config_params.gain_offset; - void __iomem *base = isif->isif_cfg.base_addr; - u32 val; - - val = ((gain_off_ptr->gain_sdram_en & 1) << GAIN_SDRAM_EN_SHIFT) | - ((gain_off_ptr->gain_ipipe_en & 1) << GAIN_IPIPE_EN_SHIFT) | - ((gain_off_ptr->gain_h3a_en & 1) << GAIN_H3A_EN_SHIFT) | - ((gain_off_ptr->offset_sdram_en & 1) << OFST_SDRAM_EN_SHIFT) | - ((gain_off_ptr->offset_ipipe_en & 1) << OFST_IPIPE_EN_SHIFT) | - ((gain_off_ptr->offset_h3a_en & 1) << OFST_H3A_EN_SHIFT); - isif_merge(base, GAIN_OFFSET_EN_MASK, val, CGAMMAWD); - - isif_write(base, isif->isif_cfg.isif_gain_params.cr_gain, CRGAIN); - isif_write(base, isif->isif_cfg.isif_gain_params.cgr_gain, CGRGAIN); - isif_write(base, isif->isif_cfg.isif_gain_params.cgb_gain, CGBGAIN); - isif_write(base, isif->isif_cfg.isif_gain_params.cb_gain, CBGAIN); - isif_write(base, isif->isif_cfg.isif_gain_params.offset & OFFSET_MASK, - COFSTA); - -} - -static void isif_config_bclamp(struct vpfe_isif_device *isif, - struct vpfe_isif_black_clamp *bc) -{ - u32 val; - - /** - * DC Offset is always added to image data irrespective of bc enable - * status - */ - val = bc->dc_offset & ISIF_BC_DCOFFSET_MASK; - isif_write(isif->isif_cfg.base_addr, val, CLDCOFST); - - if (!bc->en) - return; - - val = (bc->bc_mode_color & ISIF_BC_MODE_COLOR_MASK) << - ISIF_BC_MODE_COLOR_SHIFT; - - /* Enable BC and horizontal clamp calculation parameters */ - val = val | 1 | ((bc->horz.mode & ISIF_HORZ_BC_MODE_MASK) << - ISIF_HORZ_BC_MODE_SHIFT); - - isif_write(isif->isif_cfg.base_addr, val, CLAMPCFG); - - if (bc->horz.mode != VPFE_ISIF_HORZ_BC_DISABLE) { - /* - * Window count for calculation - * Base window selection - * pixel limit - * Horizontal size of window - * vertical size of the window - * Horizontal start position of the window - * Vertical start position of the window - */ - val = (bc->horz.win_count_calc & ISIF_HORZ_BC_WIN_COUNT_MASK) | - ((bc->horz.base_win_sel_calc & 1) << - ISIF_HORZ_BC_WIN_SEL_SHIFT) | - ((bc->horz.clamp_pix_limit & 1) << - ISIF_HORZ_BC_PIX_LIMIT_SHIFT) | - ((bc->horz.win_h_sz_calc & - ISIF_HORZ_BC_WIN_H_SIZE_MASK) << - ISIF_HORZ_BC_WIN_H_SIZE_SHIFT) | - ((bc->horz.win_v_sz_calc & - ISIF_HORZ_BC_WIN_V_SIZE_MASK) << - ISIF_HORZ_BC_WIN_V_SIZE_SHIFT); - - isif_write(isif->isif_cfg.base_addr, val, CLHWIN0); - - val = bc->horz.win_start_h_calc & ISIF_HORZ_BC_WIN_START_H_MASK; - isif_write(isif->isif_cfg.base_addr, val, CLHWIN1); - - val = bc->horz.win_start_v_calc & ISIF_HORZ_BC_WIN_START_V_MASK; - isif_write(isif->isif_cfg.base_addr, val, CLHWIN2); - } - - /* vertical clamp calculation parameters */ - /* OB H Valid */ - val = bc->vert.ob_h_sz_calc & ISIF_VERT_BC_OB_H_SZ_MASK; - - /* Reset clamp value sel for previous line */ - val |= (bc->vert.reset_val_sel & ISIF_VERT_BC_RST_VAL_SEL_MASK) << - ISIF_VERT_BC_RST_VAL_SEL_SHIFT; - - /* Line average coefficient */ - val |= bc->vert.line_ave_coef << ISIF_VERT_BC_LINE_AVE_COEF_SHIFT; - isif_write(isif->isif_cfg.base_addr, val, CLVWIN0); - - /* Configured reset value */ - if (bc->vert.reset_val_sel == VPFE_ISIF_VERT_BC_USE_CONFIG_CLAMP_VAL) { - val = bc->vert.reset_clamp_val & ISIF_VERT_BC_RST_VAL_MASK; - isif_write(isif->isif_cfg.base_addr, val, CLVRV); - } - - /* Optical Black horizontal start position */ - val = bc->vert.ob_start_h & ISIF_VERT_BC_OB_START_HORZ_MASK; - isif_write(isif->isif_cfg.base_addr, val, CLVWIN1); - - /* Optical Black vertical start position */ - val = bc->vert.ob_start_v & ISIF_VERT_BC_OB_START_VERT_MASK; - isif_write(isif->isif_cfg.base_addr, val, CLVWIN2); - - val = bc->vert.ob_v_sz_calc & ISIF_VERT_BC_OB_VERT_SZ_MASK; - isif_write(isif->isif_cfg.base_addr, val, CLVWIN3); - - /* Vertical start position for BC subtraction */ - val = bc->vert_start_sub & ISIF_BC_VERT_START_SUB_V_MASK; - isif_write(isif->isif_cfg.base_addr, val, CLSV); -} - -/* This function will configure the window size to be capture in ISIF reg */ -static void -isif_setwin(struct vpfe_isif_device *isif, struct v4l2_rect *image_win, - enum isif_frmfmt frm_fmt, int ppc, int mode) -{ - int horz_nr_pixels; - int vert_nr_lines; - int horz_start; - int vert_start; - int mid_img; - - /* - * ppc - per pixel count. indicates how many pixels per cell - * output to SDRAM. example, for ycbcr, it is one y and one c, so 2. - * raw capture this is 1 - */ - horz_start = image_win->left << (ppc - 1); - horz_nr_pixels = (image_win->width << (ppc - 1)) - 1; - - /* Writing the horizontal info into the registers */ - isif_write(isif->isif_cfg.base_addr, - horz_start & START_PX_HOR_MASK, SPH); - isif_write(isif->isif_cfg.base_addr, - horz_nr_pixels & NUM_PX_HOR_MASK, LNH); - vert_start = image_win->top; - - if (frm_fmt == ISIF_FRMFMT_INTERLACED) { - vert_nr_lines = (image_win->height >> 1) - 1; - vert_start >>= 1; - /* To account for VD since line 0 doesn't have any data */ - vert_start += 1; - } else { - /* To account for VD since line 0 doesn't have any data */ - vert_start += 1; - vert_nr_lines = image_win->height - 1; - /* configure VDINT0 and VDINT1 */ - mid_img = vert_start + (image_win->height / 2); - isif_write(isif->isif_cfg.base_addr, mid_img, VDINT1); - } - - if (!mode) - isif_write(isif->isif_cfg.base_addr, 0, VDINT0); - else - isif_write(isif->isif_cfg.base_addr, vert_nr_lines, VDINT0); - isif_write(isif->isif_cfg.base_addr, - vert_start & START_VER_ONE_MASK, SLV0); - isif_write(isif->isif_cfg.base_addr, - vert_start & START_VER_TWO_MASK, SLV1); - isif_write(isif->isif_cfg.base_addr, - vert_nr_lines & NUM_LINES_VER, LNV); -} - -#define DM365_ISIF_DFCMWR_MEMORY_WRITE 1 -#define DM365_ISIF_DFCMRD_MEMORY_READ 0x2 - -static void -isif_config_dfc(struct vpfe_isif_device *isif, struct vpfe_isif_dfc *vdfc) -{ -#define DFC_WRITE_WAIT_COUNT 1000 - u32 count = DFC_WRITE_WAIT_COUNT; - u32 val; - int i; - - if (!vdfc->en) - return; - - /* Correction mode */ - val = (vdfc->corr_mode & ISIF_VDFC_CORR_MOD_MASK) << - ISIF_VDFC_CORR_MOD_SHIFT; - - /* Correct whole line or partial */ - if (vdfc->corr_whole_line) - val |= BIT(ISIF_VDFC_CORR_WHOLE_LN_SHIFT); - - /* level shift value */ - val |= (vdfc->def_level_shift & ISIF_VDFC_LEVEL_SHFT_MASK) << - ISIF_VDFC_LEVEL_SHFT_SHIFT; - - isif_write(isif->isif_cfg.base_addr, val, DFCCTL); - - /* Defect saturation level */ - val = vdfc->def_sat_level & ISIF_VDFC_SAT_LEVEL_MASK; - isif_write(isif->isif_cfg.base_addr, val, VDFSATLV); - - isif_write(isif->isif_cfg.base_addr, vdfc->table[0].pos_vert & - ISIF_VDFC_POS_MASK, DFCMEM0); - isif_write(isif->isif_cfg.base_addr, vdfc->table[0].pos_horz & - ISIF_VDFC_POS_MASK, DFCMEM1); - if (vdfc->corr_mode == VPFE_ISIF_VDFC_NORMAL || - vdfc->corr_mode == VPFE_ISIF_VDFC_HORZ_INTERPOL_IF_SAT) { - isif_write(isif->isif_cfg.base_addr, - vdfc->table[0].level_at_pos, DFCMEM2); - isif_write(isif->isif_cfg.base_addr, - vdfc->table[0].level_up_pixels, DFCMEM3); - isif_write(isif->isif_cfg.base_addr, - vdfc->table[0].level_low_pixels, DFCMEM4); - } - - val = isif_read(isif->isif_cfg.base_addr, DFCMEMCTL); - /* set DFCMARST and set DFCMWR */ - val |= BIT(ISIF_DFCMEMCTL_DFCMARST_SHIFT); - val |= 1; - isif_write(isif->isif_cfg.base_addr, val, DFCMEMCTL); - - while (count && (isif_read(isif->isif_cfg.base_addr, DFCMEMCTL) & 0x01)) - count--; - - val = isif_read(isif->isif_cfg.base_addr, DFCMEMCTL); - if (!count) { - pr_debug("defect table write timeout !!\n"); - return; - } - - for (i = 1; i < vdfc->num_vdefects; i++) { - isif_write(isif->isif_cfg.base_addr, vdfc->table[i].pos_vert & - ISIF_VDFC_POS_MASK, DFCMEM0); - - isif_write(isif->isif_cfg.base_addr, vdfc->table[i].pos_horz & - ISIF_VDFC_POS_MASK, DFCMEM1); - - if (vdfc->corr_mode == VPFE_ISIF_VDFC_NORMAL || - vdfc->corr_mode == VPFE_ISIF_VDFC_HORZ_INTERPOL_IF_SAT) { - isif_write(isif->isif_cfg.base_addr, - vdfc->table[i].level_at_pos, DFCMEM2); - isif_write(isif->isif_cfg.base_addr, - vdfc->table[i].level_up_pixels, DFCMEM3); - isif_write(isif->isif_cfg.base_addr, - vdfc->table[i].level_low_pixels, DFCMEM4); - } - val = isif_read(isif->isif_cfg.base_addr, DFCMEMCTL); - /* clear DFCMARST and set DFCMWR */ - val &= ~BIT(ISIF_DFCMEMCTL_DFCMARST_SHIFT); - val |= 1; - isif_write(isif->isif_cfg.base_addr, val, DFCMEMCTL); - - count = DFC_WRITE_WAIT_COUNT; - while (count && (isif_read(isif->isif_cfg.base_addr, - DFCMEMCTL) & 0x01)) - count--; - - val = isif_read(isif->isif_cfg.base_addr, DFCMEMCTL); - if (!count) { - pr_debug("defect table write timeout !!\n"); - return; - } - } - if (vdfc->num_vdefects < VPFE_ISIF_VDFC_TABLE_SIZE) { - /* Extra cycle needed */ - isif_write(isif->isif_cfg.base_addr, 0, DFCMEM0); - isif_write(isif->isif_cfg.base_addr, - DM365_ISIF_MAX_DFCMEM1, DFCMEM1); - isif_write(isif->isif_cfg.base_addr, - DM365_ISIF_DFCMWR_MEMORY_WRITE, DFCMEMCTL); - } - /* enable VDFC */ - isif_merge(isif->isif_cfg.base_addr, (1 << ISIF_VDFC_EN_SHIFT), - (1 << ISIF_VDFC_EN_SHIFT), DFCCTL); - - isif_merge(isif->isif_cfg.base_addr, (1 << ISIF_VDFC_EN_SHIFT), - (0 << ISIF_VDFC_EN_SHIFT), DFCCTL); - - isif_write(isif->isif_cfg.base_addr, 0x6, DFCMEMCTL); - for (i = 0; i < vdfc->num_vdefects; i++) { - count = DFC_WRITE_WAIT_COUNT; - while (count && - (isif_read(isif->isif_cfg.base_addr, DFCMEMCTL) & 0x2)) - count--; - val = isif_read(isif->isif_cfg.base_addr, DFCMEMCTL); - if (!count) { - pr_debug("defect table write timeout !!\n"); - return; - } - isif_write(isif->isif_cfg.base_addr, - DM365_ISIF_DFCMRD_MEMORY_READ, DFCMEMCTL); - } -} - -static void -isif_config_csc(struct vpfe_isif_device *isif, struct vpfe_isif_df_csc *df_csc) -{ - u32 val1; - u32 val2; - u32 i; - - if (!df_csc->csc.en) { - isif_write(isif->isif_cfg.base_addr, 0, CSCCTL); - return; - } - /* initialize all bits to 0 */ - val1 = 0; - for (i = 0; i < VPFE_ISIF_CSC_NUM_COEFF; i++) { - if ((i % 2) == 0) { - /* CSCM - LSB */ - val1 = ((df_csc->csc.coeff[i].integer & - ISIF_CSC_COEF_INTEG_MASK) << - ISIF_CSC_COEF_INTEG_SHIFT) | - ((df_csc->csc.coeff[i].decimal & - ISIF_CSC_COEF_DECIMAL_MASK)); - } else { - - /* CSCM - MSB */ - val2 = ((df_csc->csc.coeff[i].integer & - ISIF_CSC_COEF_INTEG_MASK) << - ISIF_CSC_COEF_INTEG_SHIFT) | - ((df_csc->csc.coeff[i].decimal & - ISIF_CSC_COEF_DECIMAL_MASK)); - val2 <<= ISIF_CSCM_MSB_SHIFT; - val2 |= val1; - isif_write(isif->isif_cfg.base_addr, val2, - (CSCM0 + ((i-1) << 1))); - } - } - /* program the active area */ - isif_write(isif->isif_cfg.base_addr, df_csc->start_pix & - ISIF_DF_CSC_SPH_MASK, FMTSPH); - /* - * one extra pixel as required for CSC. Actually number of - * pixel - 1 should be configured in this register. So we - * need to subtract 1 before writing to FMTSPH, but we will - * not do this since csc requires one extra pixel - */ - isif_write(isif->isif_cfg.base_addr, df_csc->num_pixels & - ISIF_DF_CSC_SPH_MASK, FMTLNH); - isif_write(isif->isif_cfg.base_addr, df_csc->start_line & - ISIF_DF_CSC_SPH_MASK, FMTSLV); - /* - * one extra line as required for CSC. See reason documented for - * num_pixels - */ - isif_write(isif->isif_cfg.base_addr, df_csc->num_lines & - ISIF_DF_CSC_SPH_MASK, FMTLNV); - /* Enable CSC */ - isif_write(isif->isif_cfg.base_addr, 1, CSCCTL); -} - -static void -isif_config_linearization(struct vpfe_isif_device *isif, - struct vpfe_isif_linearize *linearize) -{ - u32 val; - u32 i; - - if (!linearize->en) { - isif_write(isif->isif_cfg.base_addr, 0, LINCFG0); - return; - } - /* shift value for correction */ - val = (linearize->corr_shft & ISIF_LIN_CORRSFT_MASK) << - ISIF_LIN_CORRSFT_SHIFT; - /* enable */ - val |= 1; - isif_write(isif->isif_cfg.base_addr, val, LINCFG0); - /* Scale factor */ - val = (linearize->scale_fact.integer & 1) << - ISIF_LIN_SCALE_FACT_INTEG_SHIFT; - val |= linearize->scale_fact.decimal & ISIF_LIN_SCALE_FACT_DECIMAL_MASK; - isif_write(isif->isif_cfg.base_addr, val, LINCFG1); - - for (i = 0; i < VPFE_ISIF_LINEAR_TAB_SIZE; i++) { - val = linearize->table[i] & ISIF_LIN_ENTRY_MASK; - if (i%2) - isif_regw_lin_tbl(isif, val, ((i >> 1) << 2), 1); - else - isif_regw_lin_tbl(isif, val, ((i >> 1) << 2), 0); - } -} - -static void -isif_config_culling(struct vpfe_isif_device *isif, struct vpfe_isif_cul *cul) -{ - u32 val; - - /* Horizontal pattern */ - val = cul->hcpat_even << CULL_PAT_EVEN_LINE_SHIFT; - val |= cul->hcpat_odd; - isif_write(isif->isif_cfg.base_addr, val, CULH); - /* vertical pattern */ - isif_write(isif->isif_cfg.base_addr, cul->vcpat, CULV); - /* LPF */ - isif_merge(isif->isif_cfg.base_addr, ISIF_LPF_MASK << ISIF_LPF_SHIFT, - cul->en_lpf << ISIF_LPF_SHIFT, MODESET); -} - -static int isif_get_pix_fmt(u32 mbus_code) -{ - switch (mbus_code) { - case MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8: - case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8: - case MEDIA_BUS_FMT_SGRBG12_1X12: - return ISIF_PIXFMT_RAW; - - case MEDIA_BUS_FMT_YUYV8_2X8: - case MEDIA_BUS_FMT_UYVY8_2X8: - case MEDIA_BUS_FMT_YUYV10_2X10: - case MEDIA_BUS_FMT_Y8_1X8: - return ISIF_PIXFMT_YCBCR_8BIT; - - case MEDIA_BUS_FMT_YUYV8_1X16: - case MEDIA_BUS_FMT_YUYV10_1X20: - return ISIF_PIXFMT_YCBCR_16BIT; - - default: - break; - } - return -EINVAL; -} - -#define ISIF_INTERLACE_INVERSE_MODE 0x4b6d -#define ISIF_INTERLACE_NON_INVERSE_MODE 0x0b6d -#define ISIF_PROGRESSIVE_INVERSE_MODE 0x4000 -#define ISIF_PROGRESSIVE_NON_INVERSE_MODE 0x0000 - -static int isif_config_raw(struct v4l2_subdev *sd, int mode) -{ - struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd); - struct isif_params_raw *params = &isif->isif_cfg.bayer; - struct vpfe_isif_raw_config *module_params = - &isif->isif_cfg.bayer.config_params; - struct v4l2_mbus_framefmt *format; - int pix_fmt; - u32 val; - - format = &isif->formats[ISIF_PAD_SINK]; - - /* In case of user has set BT656IF earlier, it should be reset - * when configuring for raw input. - */ - isif_write(isif->isif_cfg.base_addr, 0, REC656IF); - /* Configure CCDCFG register - * Set CCD Not to swap input since input is RAW data - * Set FID detection function to Latch at V-Sync - * Set WENLOG - isif valid area - * Set TRGSEL - * Set EXTRG - * Packed to 8 or 16 bits - */ - val = ISIF_YCINSWP_RAW | ISIF_CCDCFG_FIDMD_LATCH_VSYNC | - ISIF_CCDCFG_WENLOG_AND | ISIF_CCDCFG_TRGSEL_WEN | - ISIF_CCDCFG_EXTRG_DISABLE | (isif->isif_cfg.data_pack & - ISIF_DATA_PACK_MASK); - isif_write(isif->isif_cfg.base_addr, val, CCDCFG); - - pix_fmt = isif_get_pix_fmt(format->code); - if (pix_fmt < 0) { - pr_debug("Invalid pix_fmt(input mode)\n"); - return -EINVAL; - } - /* - * Configure the vertical sync polarity(MODESET.VDPOL) - * Configure the horizontal sync polarity (MODESET.HDPOL) - * Configure frame id polarity (MODESET.FLDPOL) - * Configure data polarity - * Configure External WEN Selection - * Configure frame format(progressive or interlace) - * Configure pixel format (Input mode) - * Configure the data shift - */ - val = ISIF_VDHDOUT_INPUT | ((params->vd_pol & ISIF_VD_POL_MASK) << - ISIF_VD_POL_SHIFT) | ((params->hd_pol & ISIF_HD_POL_MASK) << - ISIF_HD_POL_SHIFT) | ((params->fid_pol & ISIF_FID_POL_MASK) << - ISIF_FID_POL_SHIFT) | ((ISIF_DATAPOL_NORMAL & - ISIF_DATAPOL_MASK) << ISIF_DATAPOL_SHIFT) | ((ISIF_EXWEN_DISABLE & - ISIF_EXWEN_MASK) << ISIF_EXWEN_SHIFT) | ((params->frm_fmt & - ISIF_FRM_FMT_MASK) << ISIF_FRM_FMT_SHIFT) | ((pix_fmt & - ISIF_INPUT_MASK) << ISIF_INPUT_SHIFT); - - /* currently only MEDIA_BUS_FMT_SGRBG12_1X12 is - * supported. shift appropriately depending on - * different MBUS fmt's added - */ - if (format->code == MEDIA_BUS_FMT_SGRBG12_1X12) - val |= ((VPFE_ISIF_NO_SHIFT & - ISIF_DATASFT_MASK) << ISIF_DATASFT_SHIFT); - - isif_write(isif->isif_cfg.base_addr, val, MODESET); - /* - * Configure GAMMAWD register - * CFA pattern setting - */ - val = (params->cfa_pat & ISIF_GAMMAWD_CFA_MASK) << - ISIF_GAMMAWD_CFA_SHIFT; - /* Gamma msb */ - if (params->v4l2_pix_fmt == V4L2_PIX_FMT_SGRBG10ALAW8) - val = val | ISIF_ALAW_ENABLE; - - val = val | ((params->data_msb & ISIF_ALAW_GAMA_WD_MASK) << - ISIF_ALAW_GAMA_WD_SHIFT); - - isif_write(isif->isif_cfg.base_addr, val, CGAMMAWD); - /* Configure DPCM compression settings */ - if (params->v4l2_pix_fmt == V4L2_PIX_FMT_SGRBG10DPCM8) { - val = BIT(ISIF_DPCM_EN_SHIFT); - val |= (params->dpcm_predictor & - ISIF_DPCM_PREDICTOR_MASK) << ISIF_DPCM_PREDICTOR_SHIFT; - } - isif_write(isif->isif_cfg.base_addr, val, MISC); - /* Configure Gain & Offset */ - isif_config_gain_offset(isif); - /* Configure Color pattern */ - if (format->code == MEDIA_BUS_FMT_SGRBG12_1X12) - val = isif_sgrbg_pattern; - else - /* default set to rggb */ - val = isif_srggb_pattern; - - isif_write(isif->isif_cfg.base_addr, val, CCOLP); - - /* Configure HSIZE register */ - val = (params->horz_flip_en & ISIF_HSIZE_FLIP_MASK) << - ISIF_HSIZE_FLIP_SHIFT; - - /* calculate line offset in 32 bytes based on pack value */ - if (isif->isif_cfg.data_pack == ISIF_PACK_8BIT) - val |= ((params->win.width + 31) >> 5) & ISIF_LINEOFST_MASK; - else if (isif->isif_cfg.data_pack == ISIF_PACK_12BIT) - val |= ((((params->win.width + (params->win.width >> 2)) + - 31) >> 5) & ISIF_LINEOFST_MASK); - else - val |= (((params->win.width * 2) + 31) >> 5) & - ISIF_LINEOFST_MASK; - isif_write(isif->isif_cfg.base_addr, val, HSIZE); - /* Configure SDOFST register */ - if (params->frm_fmt == ISIF_FRMFMT_INTERLACED) { - if (params->image_invert_en) - /* For interlace inverse mode */ - isif_write(isif->isif_cfg.base_addr, - ISIF_INTERLACE_INVERSE_MODE, SDOFST); - else - /* For interlace non inverse mode */ - isif_write(isif->isif_cfg.base_addr, - ISIF_INTERLACE_NON_INVERSE_MODE, SDOFST); - } else if (params->frm_fmt == ISIF_FRMFMT_PROGRESSIVE) { - if (params->image_invert_en) - isif_write(isif->isif_cfg.base_addr, - ISIF_PROGRESSIVE_INVERSE_MODE, SDOFST); - else - /* For progessive non inverse mode */ - isif_write(isif->isif_cfg.base_addr, - ISIF_PROGRESSIVE_NON_INVERSE_MODE, SDOFST); - } - /* Configure video window */ - isif_setwin(isif, ¶ms->win, params->frm_fmt, 1, mode); - /* Configure Black Clamp */ - isif_config_bclamp(isif, &module_params->bclamp); - /* Configure Vertical Defection Pixel Correction */ - isif_config_dfc(isif, &module_params->dfc); - if (!module_params->df_csc.df_or_csc) - /* Configure Color Space Conversion */ - isif_config_csc(isif, &module_params->df_csc); - - isif_config_linearization(isif, &module_params->linearize); - /* Configure Culling */ - isif_config_culling(isif, &module_params->culling); - /* Configure Horizontal and vertical offsets(DFC,LSC,Gain) */ - val = module_params->horz_offset & ISIF_DATA_H_OFFSET_MASK; - isif_write(isif->isif_cfg.base_addr, val, DATAHOFST); - - val = module_params->vert_offset & ISIF_DATA_V_OFFSET_MASK; - isif_write(isif->isif_cfg.base_addr, val, DATAVOFST); - - return 0; -} - -#define DM365_ISIF_HSIZE_MASK 0xffffffe0 -#define DM365_ISIF_SDOFST_2_LINES 0x00000249 - -/* This function will configure ISIF for YCbCr parameters. */ -static int isif_config_ycbcr(struct v4l2_subdev *sd, int mode) -{ - struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd); - struct isif_ycbcr_config *params = &isif->isif_cfg.ycbcr; - struct v4l2_mbus_framefmt *format; - int pix_fmt; - u32 modeset; - u32 ccdcfg; - - format = &isif->formats[ISIF_PAD_SINK]; - /* - * first reset the ISIF - * all registers have default values after reset - * This is important since we assume default values to be set in - * a lot of registers that we didn't touch - */ - /* start with all bits zero */ - ccdcfg = 0; - modeset = 0; - pix_fmt = isif_get_pix_fmt(format->code); - if (pix_fmt < 0) { - pr_debug("Invalid pix_fmt(input mode)\n"); - return -EINVAL; - } - /* configure pixel format or input mode */ - modeset = modeset | ((pix_fmt & ISIF_INPUT_MASK) << - ISIF_INPUT_SHIFT) | ((params->frm_fmt & ISIF_FRM_FMT_MASK) << - ISIF_FRM_FMT_SHIFT) | (((params->fid_pol & - ISIF_FID_POL_MASK) << ISIF_FID_POL_SHIFT)) | - (((params->hd_pol & ISIF_HD_POL_MASK) << ISIF_HD_POL_SHIFT)) | - (((params->vd_pol & ISIF_VD_POL_MASK) << ISIF_VD_POL_SHIFT)); - /* pack the data to 8-bit CCDCCFG */ - switch (format->code) { - case MEDIA_BUS_FMT_YUYV8_2X8: - case MEDIA_BUS_FMT_UYVY8_2X8: - if (pix_fmt != ISIF_PIXFMT_YCBCR_8BIT) { - pr_debug("Invalid pix_fmt(input mode)\n"); - return -EINVAL; - } - modeset |= ((VPFE_PINPOL_NEGATIVE & ISIF_VD_POL_MASK) << - ISIF_VD_POL_SHIFT); - isif_write(isif->isif_cfg.base_addr, 3, REC656IF); - ccdcfg = ccdcfg | ISIF_PACK_8BIT | ISIF_YCINSWP_YCBCR; - break; - - case MEDIA_BUS_FMT_YUYV10_2X10: - if (pix_fmt != ISIF_PIXFMT_YCBCR_8BIT) { - pr_debug("Invalid pix_fmt(input mode)\n"); - return -EINVAL; - } - /* setup BT.656, embedded sync */ - isif_write(isif->isif_cfg.base_addr, 3, REC656IF); - /* enable 10 bit mode in ccdcfg */ - ccdcfg = ccdcfg | ISIF_PACK_8BIT | ISIF_YCINSWP_YCBCR | - ISIF_BW656_ENABLE; - break; - - case MEDIA_BUS_FMT_YUYV10_1X20: - if (pix_fmt != ISIF_PIXFMT_YCBCR_16BIT) { - pr_debug("Invalid pix_fmt(input mode)\n"); - return -EINVAL; - } - isif_write(isif->isif_cfg.base_addr, 3, REC656IF); - break; - - case MEDIA_BUS_FMT_Y8_1X8: - ccdcfg |= ISIF_PACK_8BIT; - ccdcfg |= ISIF_YCINSWP_YCBCR; - if (pix_fmt != ISIF_PIXFMT_YCBCR_8BIT) { - pr_debug("Invalid pix_fmt(input mode)\n"); - return -EINVAL; - } - break; - - case MEDIA_BUS_FMT_YUYV8_1X16: - if (pix_fmt != ISIF_PIXFMT_YCBCR_16BIT) { - pr_debug("Invalid pix_fmt(input mode)\n"); - return -EINVAL; - } - break; - - default: - /* should never come here */ - pr_debug("Invalid interface type\n"); - return -EINVAL; - } - isif_write(isif->isif_cfg.base_addr, modeset, MODESET); - /* Set up pix order */ - ccdcfg |= (params->pix_order & ISIF_PIX_ORDER_MASK) << - ISIF_PIX_ORDER_SHIFT; - isif_write(isif->isif_cfg.base_addr, ccdcfg, CCDCFG); - /* configure video window */ - if (format->code == MEDIA_BUS_FMT_YUYV10_1X20 || - format->code == MEDIA_BUS_FMT_YUYV8_1X16) - isif_setwin(isif, ¶ms->win, params->frm_fmt, 1, mode); - else - isif_setwin(isif, ¶ms->win, params->frm_fmt, 2, mode); - - /* - * configure the horizontal line offset - * this is done by rounding up width to a multiple of 16 pixels - * and multiply by two to account for y:cb:cr 4:2:2 data - */ - isif_write(isif->isif_cfg.base_addr, - ((((params->win.width * 2) + 31) & - DM365_ISIF_HSIZE_MASK) >> 5), HSIZE); - - /* configure the memory line offset */ - if (params->frm_fmt == ISIF_FRMFMT_INTERLACED && - params->buf_type == ISIF_BUFTYPE_FLD_INTERLEAVED) - /* two fields are interleaved in memory */ - isif_write(isif->isif_cfg.base_addr, - DM365_ISIF_SDOFST_2_LINES, SDOFST); - return 0; -} - -static int isif_configure(struct v4l2_subdev *sd, int mode) -{ - struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *format; - - format = &isif->formats[ISIF_PAD_SINK]; - - switch (format->code) { - case MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8: - case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8: - case MEDIA_BUS_FMT_SGRBG12_1X12: - return isif_config_raw(sd, mode); - - case MEDIA_BUS_FMT_YUYV8_2X8: - case MEDIA_BUS_FMT_UYVY8_2X8: - case MEDIA_BUS_FMT_YUYV10_2X10: - case MEDIA_BUS_FMT_Y8_1X8: - case MEDIA_BUS_FMT_YUYV8_1X16: - case MEDIA_BUS_FMT_YUYV10_1X20: - return isif_config_ycbcr(sd, mode); - - default: - break; - } - return -EINVAL; -} - -/* - * isif_set_stream() - Enable/Disable streaming on the ISIF module - * @sd: VPFE ISIF V4L2 subdevice - * @enable: Enable/disable stream - */ -static int isif_set_stream(struct v4l2_subdev *sd, int enable) -{ - struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd); - int ret; - - if (enable) { - ret = isif_configure(sd, - (isif->output == ISIF_OUTPUT_MEMORY) ? 0 : 1); - if (ret) - return ret; - if (isif->output == ISIF_OUTPUT_MEMORY) - isif_enable_output_to_sdram(isif, 1); - isif_enable(isif, 1); - } else { - isif_enable(isif, 0); - isif_enable_output_to_sdram(isif, 0); - } - - return 0; -} - -/* - * __isif_get_format() - helper function for getting isif format - * @isif: pointer to isif private structure. - * @pad: pad number. - * @cfg: V4L2 subdev pad config - * @which: wanted subdev format. - */ -static struct v4l2_mbus_framefmt * -__isif_get_format(struct vpfe_isif_device *isif, - struct v4l2_subdev_pad_config *cfg, unsigned int pad, - enum v4l2_subdev_format_whence which) -{ - if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(&isif->subdev, cfg, pad); - - return &isif->formats[pad]; -} - -/* - * isif_set_format() - set format on pad - * @sd : VPFE ISIF device - * @cfg : V4L2 subdev pad config - * @fmt : pointer to v4l2 subdev format structure - * - * Return 0 on success or -EINVAL if format or pad is invalid - */ -static int -isif_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *fmt) -{ - struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd); - struct vpfe_device *vpfe_dev = to_vpfe_device(isif); - struct v4l2_mbus_framefmt *format; - - format = __isif_get_format(isif, cfg, fmt->pad, fmt->which); - if (format == NULL) - return -EINVAL; - - isif_try_format(isif, cfg, fmt); - memcpy(format, &fmt->format, sizeof(*format)); - - if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) - return 0; - - if (fmt->pad == ISIF_PAD_SOURCE) - return isif_config_format(vpfe_dev, fmt->pad); - - return 0; -} - -/* - * isif_get_format() - Retrieve the video format on a pad - * @sd: VPFE ISIF V4L2 subdevice - * @cfg: V4L2 subdev pad config - * @fmt: pointer to v4l2 subdev format structure - * - * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond - * to the format type. - */ -static int -isif_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *fmt) -{ - struct vpfe_isif_device *vpfe_isif = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *format; - - format = __isif_get_format(vpfe_isif, cfg, fmt->pad, fmt->which); - if (format == NULL) - return -EINVAL; - - memcpy(&fmt->format, format, sizeof(fmt->format)); - - return 0; -} - -/* - * isif_enum_frame_size() - enum frame sizes on pads - * @sd: VPFE isif V4L2 subdevice - * @cfg: V4L2 subdev pad config - * @code: pointer to v4l2_subdev_frame_size_enum structure - */ -static int -isif_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_frame_size_enum *fse) -{ - struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd); - struct v4l2_subdev_format format; - - if (fse->index != 0) - return -EINVAL; - - format.pad = fse->pad; - format.format.code = fse->code; - format.format.width = 1; - format.format.height = 1; - format.which = fse->which; - isif_try_format(isif, cfg, &format); - fse->min_width = format.format.width; - fse->min_height = format.format.height; - - if (format.format.code != fse->code) - return -EINVAL; - - format.pad = fse->pad; - format.format.code = fse->code; - format.format.width = -1; - format.format.height = -1; - format.which = fse->which; - isif_try_format(isif, cfg, &format); - fse->max_width = format.format.width; - fse->max_height = format.format.height; - - return 0; -} - -/* - * isif_enum_mbus_code() - enum mbus codes for pads - * @sd: VPFE isif V4L2 subdevice - * @cfg: V4L2 subdev pad config - * @code: pointer to v4l2_subdev_mbus_code_enum structure - */ -static int -isif_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) -{ - switch (code->pad) { - case ISIF_PAD_SINK: - case ISIF_PAD_SOURCE: - if (code->index >= ARRAY_SIZE(isif_fmts)) - return -EINVAL; - code->code = isif_fmts[code->index]; - break; - - default: - return -EINVAL; - } - - return 0; -} - -/* - * isif_pad_set_selection() - set crop rectangle on pad - * @sd: VPFE isif V4L2 subdevice - * @cfg: V4L2 subdev pad config - * @code: pointer to v4l2_subdev_mbus_code_enum structure - * - * Return 0 on success, -EINVAL if pad is invalid - */ -static int -isif_pad_set_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) -{ - struct vpfe_isif_device *vpfe_isif = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *format; - - /* check whether it's a valid pad and target */ - if (sel->pad != ISIF_PAD_SINK || sel->target != V4L2_SEL_TGT_CROP) - return -EINVAL; - - format = __isif_get_format(vpfe_isif, cfg, sel->pad, sel->which); - if (format == NULL) - return -EINVAL; - - /* check wether crop rect is within limits */ - if (sel->r.top < 0 || sel->r.left < 0 || - (sel->r.left + sel->r.width > - vpfe_isif->formats[ISIF_PAD_SINK].width) || - (sel->r.top + sel->r.height > - vpfe_isif->formats[ISIF_PAD_SINK].height)) { - sel->r.left = 0; - sel->r.top = 0; - sel->r.width = format->width; - sel->r.height = format->height; - } - /* adjust the width to 16 pixel boundary */ - sel->r.width = (sel->r.width + 15) & ~0xf; - vpfe_isif->crop = sel->r; - if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { - isif_set_image_window(vpfe_isif); - } else { - struct v4l2_rect *rect; - - rect = v4l2_subdev_get_try_crop(sd, cfg, ISIF_PAD_SINK); - memcpy(rect, &vpfe_isif->crop, sizeof(*rect)); - } - return 0; -} - -/* - * isif_pad_get_selection() - get crop rectangle on pad - * @sd: VPFE isif V4L2 subdevice - * @cfg: V4L2 subdev pad config - * @code: pointer to v4l2_subdev_mbus_code_enum structure - * - * Return 0 on success, -EINVAL if pad is invalid - */ -static int -isif_pad_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) -{ - struct vpfe_isif_device *vpfe_isif = v4l2_get_subdevdata(sd); - - /* check whether it's a valid pad and target */ - if (sel->pad != ISIF_PAD_SINK || sel->target != V4L2_SEL_TGT_CROP) - return -EINVAL; - - if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { - struct v4l2_rect *rect; - - rect = v4l2_subdev_get_try_crop(sd, cfg, ISIF_PAD_SINK); - memcpy(&sel->r, rect, sizeof(*rect)); - } else { - sel->r = vpfe_isif->crop; - } - - return 0; -} - -/* - * isif_init_formats() - Initialize formats on all pads - * @sd: VPFE isif V4L2 subdevice - * @fh: V4L2 subdev file handle - * - * Initialize all pad formats with default values. Try formats are initialized - * on the file handle. - */ -static int -isif_init_formats(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh) -{ - struct v4l2_subdev_format format; - struct v4l2_subdev_selection sel; - - memset(&format, 0, sizeof(format)); - format.pad = ISIF_PAD_SINK; - format.which = V4L2_SUBDEV_FORMAT_TRY; - format.format.code = MEDIA_BUS_FMT_SGRBG12_1X12; - format.format.width = MAX_WIDTH; - format.format.height = MAX_HEIGHT; - isif_set_format(sd, fh->pad, &format); - - memset(&format, 0, sizeof(format)); - format.pad = ISIF_PAD_SOURCE; - format.which = V4L2_SUBDEV_FORMAT_TRY; - format.format.code = MEDIA_BUS_FMT_SGRBG12_1X12; - format.format.width = MAX_WIDTH; - format.format.height = MAX_HEIGHT; - isif_set_format(sd, fh->pad, &format); - - memset(&sel, 0, sizeof(sel)); - sel.pad = ISIF_PAD_SINK; - sel.which = V4L2_SUBDEV_FORMAT_TRY; - sel.target = V4L2_SEL_TGT_CROP; - sel.r.width = MAX_WIDTH; - sel.r.height = MAX_HEIGHT; - isif_pad_set_selection(sd, fh->pad, &sel); - - return 0; -} - -/* subdev core operations */ -static const struct v4l2_subdev_core_ops isif_v4l2_core_ops = { - .ioctl = isif_ioctl, -}; - -/* subdev file operations */ -static const struct v4l2_subdev_internal_ops isif_v4l2_internal_ops = { - .open = isif_init_formats, -}; - -/* subdev video operations */ -static const struct v4l2_subdev_video_ops isif_v4l2_video_ops = { - .s_stream = isif_set_stream, -}; - -/* subdev pad operations */ -static const struct v4l2_subdev_pad_ops isif_v4l2_pad_ops = { - .enum_mbus_code = isif_enum_mbus_code, - .enum_frame_size = isif_enum_frame_size, - .get_fmt = isif_get_format, - .set_fmt = isif_set_format, - .set_selection = isif_pad_set_selection, - .get_selection = isif_pad_get_selection, -}; - -/* subdev operations */ -static const struct v4l2_subdev_ops isif_v4l2_ops = { - .core = &isif_v4l2_core_ops, - .video = &isif_v4l2_video_ops, - .pad = &isif_v4l2_pad_ops, -}; - -/* - * Media entity operations - */ - -/* - * isif_link_setup() - Setup isif connections - * @entity: isif media entity - * @local: Pad at the local end of the link - * @remote: Pad at the remote end of the link - * @flags: Link flags - * - * return -EINVAL or zero on success - */ -static int -isif_link_setup(struct media_entity *entity, const struct media_pad *local, - const struct media_pad *remote, u32 flags) -{ - struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); - struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd); - unsigned int index = local->index; - - /* FIXME: this is actually a hack! */ - if (is_media_entity_v4l2_subdev(remote->entity)) - index |= 2 << 16; - - switch (index) { - case ISIF_PAD_SINK | 2 << 16: - /* read from decoder/sensor */ - if (!(flags & MEDIA_LNK_FL_ENABLED)) { - isif->input = ISIF_INPUT_NONE; - break; - } - if (isif->input != ISIF_INPUT_NONE) - return -EBUSY; - isif->input = ISIF_INPUT_PARALLEL; - break; - - case ISIF_PAD_SOURCE: - /* write to memory */ - if (flags & MEDIA_LNK_FL_ENABLED) - isif->output = ISIF_OUTPUT_MEMORY; - else - isif->output = ISIF_OUTPUT_NONE; - break; - - case ISIF_PAD_SOURCE | 2 << 16: - if (flags & MEDIA_LNK_FL_ENABLED) - isif->output = ISIF_OUTPUT_IPIPEIF; - else - isif->output = ISIF_OUTPUT_NONE; - break; - - default: - return -EINVAL; - } - - return 0; -} -static const struct media_entity_operations isif_media_ops = { - .link_setup = isif_link_setup, -}; - -/* - * vpfe_isif_unregister_entities() - isif unregister entity - * @isif - pointer to isif subdevice structure. - */ -void vpfe_isif_unregister_entities(struct vpfe_isif_device *isif) -{ - vpfe_video_unregister(&isif->video_out); - /* unregister subdev */ - v4l2_device_unregister_subdev(&isif->subdev); - /* cleanup entity */ - media_entity_cleanup(&isif->subdev.entity); -} - -static void isif_restore_defaults(struct vpfe_isif_device *isif) -{ - enum vpss_ccdc_source_sel source = VPSS_CCDCIN; - int i; - - memset(&isif->isif_cfg.bayer.config_params, 0, - sizeof(struct vpfe_isif_raw_config)); - - isif->isif_cfg.bayer.config_params.linearize.corr_shft = - VPFE_ISIF_NO_SHIFT; - isif->isif_cfg.bayer.config_params.linearize.scale_fact.integer = 1; - isif->isif_cfg.bayer.config_params.culling.hcpat_odd = - ISIF_CULLING_HCAPT_ODD; - isif->isif_cfg.bayer.config_params.culling.hcpat_even = - ISIF_CULLING_HCAPT_EVEN; - isif->isif_cfg.bayer.config_params.culling.vcpat = ISIF_CULLING_VCAPT; - /* Enable clock to ISIF, IPIPEIF and BL */ - vpss_enable_clock(VPSS_CCDC_CLOCK, 1); - vpss_enable_clock(VPSS_IPIPEIF_CLOCK, 1); - vpss_enable_clock(VPSS_BL_CLOCK, 1); - - /* set all registers to default value */ - for (i = 0; i <= 0x1f8; i += 4) - isif_write(isif->isif_cfg.base_addr, 0, i); - /* no culling support */ - isif_write(isif->isif_cfg.base_addr, 0xffff, CULH); - isif_write(isif->isif_cfg.base_addr, 0xff, CULV); - - /* Set default offset and gain */ - isif_config_gain_offset(isif); - vpss_select_ccdc_source(source); -} - -/* - * vpfe_isif_register_entities() - isif register entity - * @isif - pointer to isif subdevice structure. - * @vdev: pointer to v4l2 device structure. - */ -int vpfe_isif_register_entities(struct vpfe_isif_device *isif, - struct v4l2_device *vdev) -{ - struct vpfe_device *vpfe_dev = to_vpfe_device(isif); - unsigned int flags; - int ret; - - /* Register the subdev */ - ret = v4l2_device_register_subdev(vdev, &isif->subdev); - if (ret < 0) - return ret; - - isif_restore_defaults(isif); - ret = vpfe_video_register(&isif->video_out, vdev); - if (ret) { - pr_err("Failed to register isif video out device\n"); - goto out_video_register; - } - isif->video_out.vpfe_dev = vpfe_dev; - flags = 0; - /* connect isif to video node */ - ret = media_create_pad_link(&isif->subdev.entity, 1, - &isif->video_out.video_dev.entity, - 0, flags); - if (ret < 0) - goto out_create_link; - return 0; -out_create_link: - vpfe_video_unregister(&isif->video_out); -out_video_register: - v4l2_device_unregister_subdev(&isif->subdev); - return ret; -} - -/* ------------------------------------------------------------------- - * V4L2 subdev control operations - */ - -static int vpfe_isif_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct vpfe_isif_device *isif = - container_of(ctrl->handler, struct vpfe_isif_device, ctrls); - struct isif_oper_config *config = &isif->isif_cfg; - - switch (ctrl->id) { - case VPFE_CID_DPCM_PREDICTOR: - config->bayer.dpcm_predictor = ctrl->val; - break; - - case VPFE_ISIF_CID_CRGAIN: - config->isif_gain_params.cr_gain = ctrl->val; - break; - - case VPFE_ISIF_CID_CGRGAIN: - config->isif_gain_params.cgr_gain = ctrl->val; - break; - - case VPFE_ISIF_CID_CGBGAIN: - config->isif_gain_params.cgb_gain = ctrl->val; - break; - - case VPFE_ISIF_CID_CBGAIN: - config->isif_gain_params.cb_gain = ctrl->val; - break; - - case VPFE_ISIF_CID_GAIN_OFFSET: - config->isif_gain_params.offset = ctrl->val; - break; - - default: - return -EINVAL; - } - return 0; -} - -static const struct v4l2_ctrl_ops vpfe_isif_ctrl_ops = { - .s_ctrl = vpfe_isif_s_ctrl, -}; - -static const struct v4l2_ctrl_config vpfe_isif_dpcm_pred = { - .ops = &vpfe_isif_ctrl_ops, - .id = VPFE_CID_DPCM_PREDICTOR, - .name = "DPCM Predictor", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .max = 1, - .step = 1, - .def = 0, -}; - -static const struct v4l2_ctrl_config vpfe_isif_crgain = { - .ops = &vpfe_isif_ctrl_ops, - .id = VPFE_ISIF_CID_CRGAIN, - .name = "CRGAIN", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .max = (1 << 12) - 1, - .step = 1, - .def = 0, -}; - -static const struct v4l2_ctrl_config vpfe_isif_cgrgain = { - .ops = &vpfe_isif_ctrl_ops, - .id = VPFE_ISIF_CID_CGRGAIN, - .name = "CGRGAIN", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .max = (1 << 12) - 1, - .step = 1, - .def = 0, -}; - -static const struct v4l2_ctrl_config vpfe_isif_cgbgain = { - .ops = &vpfe_isif_ctrl_ops, - .id = VPFE_ISIF_CID_CGBGAIN, - .name = "CGBGAIN", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .max = (1 << 12) - 1, - .step = 1, - .def = 0, -}; - -static const struct v4l2_ctrl_config vpfe_isif_cbgain = { - .ops = &vpfe_isif_ctrl_ops, - .id = VPFE_ISIF_CID_CBGAIN, - .name = "CBGAIN", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .max = (1 << 12) - 1, - .step = 1, - .def = 0, -}; - -static const struct v4l2_ctrl_config vpfe_isif_gain_offset = { - .ops = &vpfe_isif_ctrl_ops, - .id = VPFE_ISIF_CID_GAIN_OFFSET, - .name = "Gain Offset", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .max = (1 << 12) - 1, - .step = 1, - .def = 0, -}; - -static void isif_remove(struct vpfe_isif_device *isif, - struct platform_device *pdev) -{ - struct resource *res; - int i = 0; - - iounmap(isif->isif_cfg.base_addr); - iounmap(isif->isif_cfg.linear_tbl0_addr); - iounmap(isif->isif_cfg.linear_tbl1_addr); - - while (i < 3) { - res = platform_get_resource(pdev, IORESOURCE_MEM, i); - if (res) - release_mem_region(res->start, - resource_size(res)); - i++; - } -} - -static void isif_config_defaults(struct vpfe_isif_device *isif) -{ - isif->isif_cfg.ycbcr.v4l2_pix_fmt = V4L2_PIX_FMT_UYVY; - isif->isif_cfg.ycbcr.pix_fmt = ISIF_PIXFMT_YCBCR_8BIT; - isif->isif_cfg.ycbcr.frm_fmt = ISIF_FRMFMT_INTERLACED; - isif->isif_cfg.ycbcr.fid_pol = VPFE_PINPOL_POSITIVE; - isif->isif_cfg.ycbcr.vd_pol = VPFE_PINPOL_POSITIVE; - isif->isif_cfg.ycbcr.hd_pol = VPFE_PINPOL_POSITIVE; - isif->isif_cfg.ycbcr.pix_order = ISIF_PIXORDER_CBYCRY; - isif->isif_cfg.ycbcr.buf_type = ISIF_BUFTYPE_FLD_INTERLEAVED; - - isif->isif_cfg.bayer.v4l2_pix_fmt = V4L2_PIX_FMT_SGRBG10ALAW8; - isif->isif_cfg.bayer.pix_fmt = ISIF_PIXFMT_RAW; - isif->isif_cfg.bayer.frm_fmt = ISIF_FRMFMT_PROGRESSIVE; - isif->isif_cfg.bayer.fid_pol = VPFE_PINPOL_POSITIVE; - isif->isif_cfg.bayer.vd_pol = VPFE_PINPOL_POSITIVE; - isif->isif_cfg.bayer.hd_pol = VPFE_PINPOL_POSITIVE; - isif->isif_cfg.bayer.cfa_pat = ISIF_CFA_PAT_MOSAIC; - isif->isif_cfg.bayer.data_msb = ISIF_BIT_MSB_11; - isif->isif_cfg.data_pack = ISIF_PACK_8BIT; -} -/* - * vpfe_isif_init() - Initialize V4L2 subdev and media entity - * @isif: VPFE isif module - * @pdev: Pointer to platform device structure. - * Return 0 on success and a negative error code on failure. - */ -int vpfe_isif_init(struct vpfe_isif_device *isif, struct platform_device *pdev) -{ - struct v4l2_subdev *sd = &isif->subdev; - struct media_pad *pads = &isif->pads[0]; - struct media_entity *me = &sd->entity; - static resource_size_t res_len; - struct resource *res; - void __iomem *addr; - int status; - int i = 0; - - /* Get the ISIF base address, linearization table0 and table1 addr. */ - while (i < 3) { - res = platform_get_resource(pdev, IORESOURCE_MEM, i); - if (!res) { - status = -ENOENT; - goto fail_nobase_res; - } - res_len = resource_size(res); - res = request_mem_region(res->start, res_len, res->name); - if (!res) { - status = -EBUSY; - goto fail_nobase_res; - } - addr = ioremap_nocache(res->start, res_len); - if (!addr) { - status = -EBUSY; - goto fail_base_iomap; - } - switch (i) { - case 0: - /* ISIF base address */ - isif->isif_cfg.base_addr = addr; - break; - case 1: - /* ISIF linear tbl0 address */ - isif->isif_cfg.linear_tbl0_addr = addr; - break; - default: - /* ISIF linear tbl0 address */ - isif->isif_cfg.linear_tbl1_addr = addr; - break; - } - i++; - } - davinci_cfg_reg(DM365_VIN_CAM_WEN); - davinci_cfg_reg(DM365_VIN_CAM_VD); - davinci_cfg_reg(DM365_VIN_CAM_HD); - davinci_cfg_reg(DM365_VIN_YIN4_7_EN); - davinci_cfg_reg(DM365_VIN_YIN0_3_EN); - - /* queue ops */ - isif->video_out.ops = &isif_video_ops; - v4l2_subdev_init(sd, &isif_v4l2_ops); - sd->internal_ops = &isif_v4l2_internal_ops; - strscpy(sd->name, "DAVINCI ISIF", sizeof(sd->name)); - sd->grp_id = 1 << 16; /* group ID for davinci subdevs */ - v4l2_set_subdevdata(sd, isif); - sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE; - pads[ISIF_PAD_SINK].flags = MEDIA_PAD_FL_SINK; - pads[ISIF_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; - - isif->input = ISIF_INPUT_NONE; - isif->output = ISIF_OUTPUT_NONE; - me->ops = &isif_media_ops; - status = media_entity_pads_init(me, ISIF_PADS_NUM, pads); - if (status) - goto isif_fail; - isif->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - status = vpfe_video_init(&isif->video_out, "ISIF"); - if (status) { - pr_err("Failed to init isif-out video device\n"); - goto isif_fail; - } - v4l2_ctrl_handler_init(&isif->ctrls, 6); - v4l2_ctrl_new_custom(&isif->ctrls, &vpfe_isif_crgain, NULL); - v4l2_ctrl_new_custom(&isif->ctrls, &vpfe_isif_cgrgain, NULL); - v4l2_ctrl_new_custom(&isif->ctrls, &vpfe_isif_cgbgain, NULL); - v4l2_ctrl_new_custom(&isif->ctrls, &vpfe_isif_cbgain, NULL); - v4l2_ctrl_new_custom(&isif->ctrls, &vpfe_isif_gain_offset, NULL); - v4l2_ctrl_new_custom(&isif->ctrls, &vpfe_isif_dpcm_pred, NULL); - - v4l2_ctrl_handler_setup(&isif->ctrls); - sd->ctrl_handler = &isif->ctrls; - isif_config_defaults(isif); - return 0; -fail_base_iomap: - release_mem_region(res->start, res_len); - i--; -fail_nobase_res: - if (isif->isif_cfg.base_addr) - iounmap(isif->isif_cfg.base_addr); - if (isif->isif_cfg.linear_tbl0_addr) - iounmap(isif->isif_cfg.linear_tbl0_addr); - - while (i >= 0) { - res = platform_get_resource(pdev, IORESOURCE_MEM, i); - release_mem_region(res->start, res_len); - i--; - } - return status; -isif_fail: - v4l2_ctrl_handler_free(&isif->ctrls); - isif_remove(isif, pdev); - return status; -} - -/* - * vpfe_isif_cleanup - isif module cleanup - * @isif: pointer to isif subdevice - * @dev: pointer to platform device structure - */ -void -vpfe_isif_cleanup(struct vpfe_isif_device *isif, struct platform_device *pdev) -{ - isif_remove(isif, pdev); -} diff --git a/drivers/staging/media/davinci_vpfe/dm365_isif.h b/drivers/staging/media/davinci_vpfe/dm365_isif.h deleted file mode 100644 index 0e1fe472fb2b..000000000000 --- a/drivers/staging/media/davinci_vpfe/dm365_isif.h +++ /dev/null @@ -1,200 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2012 Texas Instruments Inc - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Contributors: - * Manjunath Hadli - * Prabhakar Lad - */ - -#ifndef _DAVINCI_VPFE_DM365_ISIF_H -#define _DAVINCI_VPFE_DM365_ISIF_H - -#include - -#include - -#include -#include -#include - -#include "davinci_vpfe_user.h" -#include "dm365_isif_regs.h" -#include "vpfe_video.h" - -#define ISIF_CULLING_HCAPT_ODD 0xff -#define ISIF_CULLING_HCAPT_EVEN 0xff -#define ISIF_CULLING_VCAPT 0xff - -#define ISIF_CADU_BITS 0x07ff -#define ISIF_CADL_BITS 0x0ffff - -enum isif_pixfmt { - ISIF_PIXFMT_RAW = 0, - ISIF_PIXFMT_YCBCR_16BIT = 1, - ISIF_PIXFMT_YCBCR_8BIT = 2, -}; - -enum isif_frmfmt { - ISIF_FRMFMT_PROGRESSIVE = 0, - ISIF_FRMFMT_INTERLACED = 1, -}; - -/* PIXEL ORDER IN MEMORY from LSB to MSB */ -/* only applicable for 8-bit input mode */ -enum isif_pixorder { - ISIF_PIXORDER_YCBYCR = 0, - ISIF_PIXORDER_CBYCRY = 1, -}; - -enum isif_buftype { - ISIF_BUFTYPE_FLD_INTERLEAVED = 0, - ISIF_BUFTYPE_FLD_SEPARATED = 1, -}; - -struct isif_ycbcr_config { - /* v4l2 pixel format */ - unsigned long v4l2_pix_fmt; - /* isif pixel format */ - enum isif_pixfmt pix_fmt; - /* isif frame format */ - enum isif_frmfmt frm_fmt; - /* isif crop window */ - struct v4l2_rect win; - /* field polarity */ - enum vpfe_pin_pol fid_pol; - /* interface VD polarity */ - enum vpfe_pin_pol vd_pol; - /* interface HD polarity */ - enum vpfe_pin_pol hd_pol; - /* isif pix order. Only used for ycbcr capture */ - enum isif_pixorder pix_order; - /* isif buffer type. Only used for ycbcr capture */ - enum isif_buftype buf_type; -}; - -enum isif_cfa_pattern { - ISIF_CFA_PAT_MOSAIC = 0, - ISIF_CFA_PAT_STRIPE = 1, -}; - -enum isif_data_msb { - /* MSB b15 */ - ISIF_BIT_MSB_15 = 0, - /* MSB b14 */ - ISIF_BIT_MSB_14 = 1, - /* MSB b13 */ - ISIF_BIT_MSB_13 = 2, - /* MSB b12 */ - ISIF_BIT_MSB_12 = 3, - /* MSB b11 */ - ISIF_BIT_MSB_11 = 4, - /* MSB b10 */ - ISIF_BIT_MSB_10 = 5, - /* MSB b9 */ - ISIF_BIT_MSB_9 = 6, - /* MSB b8 */ - ISIF_BIT_MSB_8 = 7, - /* MSB b7 */ - ISIF_BIT_MSB_7 = 8, -}; - -struct isif_params_raw { - /* v4l2 pixel format */ - unsigned long v4l2_pix_fmt; - /* isif pixel format */ - enum isif_pixfmt pix_fmt; - /* isif frame format */ - enum isif_frmfmt frm_fmt; - /* video window */ - struct v4l2_rect win; - /* field polarity */ - enum vpfe_pin_pol fid_pol; - /* interface VD polarity */ - enum vpfe_pin_pol vd_pol; - /* interface HD polarity */ - enum vpfe_pin_pol hd_pol; - /* buffer type. Applicable for interlaced mode */ - enum isif_buftype buf_type; - /* cfa pattern */ - enum isif_cfa_pattern cfa_pat; - /* Data MSB position */ - enum isif_data_msb data_msb; - /* Enable horizontal flip */ - unsigned char horz_flip_en; - /* Enable image invert vertically */ - unsigned char image_invert_en; - unsigned char dpcm_predictor; - struct vpfe_isif_raw_config config_params; -}; - -enum isif_data_pack { - ISIF_PACK_16BIT = 0, - ISIF_PACK_12BIT = 1, - ISIF_PACK_8BIT = 2, -}; - -struct isif_gain_values { - unsigned int cr_gain; - unsigned int cgr_gain; - unsigned int cgb_gain; - unsigned int cb_gain; - unsigned int offset; -}; - -struct isif_oper_config { - struct isif_ycbcr_config ycbcr; - struct isif_params_raw bayer; - enum isif_data_pack data_pack; - struct isif_gain_values isif_gain_params; - void __iomem *base_addr; - void __iomem *linear_tbl0_addr; - void __iomem *linear_tbl1_addr; -}; - -#define ISIF_PAD_SINK 0 -#define ISIF_PAD_SOURCE 1 - -#define ISIF_PADS_NUM 2 - -enum isif_input_entity { - ISIF_INPUT_NONE = 0, - ISIF_INPUT_PARALLEL = 1, -}; - -#define ISIF_OUTPUT_NONE (0) -#define ISIF_OUTPUT_MEMORY (1 << 0) -#define ISIF_OUTPUT_IPIPEIF (1 << 1) - -struct vpfe_isif_device { - struct v4l2_subdev subdev; - struct media_pad pads[ISIF_PADS_NUM]; - struct v4l2_mbus_framefmt formats[ISIF_PADS_NUM]; - enum isif_input_entity input; - unsigned int output; - struct v4l2_ctrl_handler ctrls; - struct v4l2_rect crop; - struct isif_oper_config isif_cfg; - struct vpfe_video_device video_out; -}; - -enum v4l2_field vpfe_isif_get_fid(struct vpfe_device *vpfe_dev); -void vpfe_isif_unregister_entities(struct vpfe_isif_device *isif); -int vpfe_isif_register_entities(struct vpfe_isif_device *isif, - struct v4l2_device *dev); -int vpfe_isif_init(struct vpfe_isif_device *isif, struct platform_device *pdev); -void vpfe_isif_cleanup(struct vpfe_isif_device *vpfe_isif, - struct platform_device *pdev); -void vpfe_isif_vidint1_isr(struct vpfe_isif_device *isif); -void vpfe_isif_buffer_isr(struct vpfe_isif_device *isif); - -#endif /* _DAVINCI_VPFE_DM365_ISIF_H */ diff --git a/drivers/staging/media/davinci_vpfe/dm365_isif_regs.h b/drivers/staging/media/davinci_vpfe/dm365_isif_regs.h deleted file mode 100644 index 6695680817b9..000000000000 --- a/drivers/staging/media/davinci_vpfe/dm365_isif_regs.h +++ /dev/null @@ -1,291 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2012 Texas Instruments Inc - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Contributors: - * Manjunath Hadli - * Prabhakar Lad - */ - -#ifndef _DAVINCI_VPFE_DM365_ISIF_REGS_H -#define _DAVINCI_VPFE_DM365_ISIF_REGS_H - -/* ISIF registers relative offsets */ -#define SYNCEN 0x00 -#define MODESET 0x04 -#define HDW 0x08 -#define VDW 0x0c -#define PPLN 0x10 -#define LPFR 0x14 -#define SPH 0x18 -#define LNH 0x1c -#define SLV0 0x20 -#define SLV1 0x24 -#define LNV 0x28 -#define CULH 0x2c -#define CULV 0x30 -#define HSIZE 0x34 -#define SDOFST 0x38 -#define CADU 0x3c -#define CADL 0x40 -#define LINCFG0 0x44 -#define LINCFG1 0x48 -#define CCOLP 0x4c -#define CRGAIN 0x50 -#define CGRGAIN 0x54 -#define CGBGAIN 0x58 -#define CBGAIN 0x5c -#define COFSTA 0x60 -#define FLSHCFG0 0x64 -#define FLSHCFG1 0x68 -#define FLSHCFG2 0x6c -#define VDINT0 0x70 -#define VDINT1 0x74 -#define VDINT2 0x78 -#define MISC 0x7c -#define CGAMMAWD 0x80 -#define REC656IF 0x84 -#define CCDCFG 0x88 -/***************************************************** - * Defect Correction registers - *****************************************************/ -#define DFCCTL 0x8c -#define VDFSATLV 0x90 -#define DFCMEMCTL 0x94 -#define DFCMEM0 0x98 -#define DFCMEM1 0x9c -#define DFCMEM2 0xa0 -#define DFCMEM3 0xa4 -#define DFCMEM4 0xa8 -/**************************************************** - * Black Clamp registers - ****************************************************/ -#define CLAMPCFG 0xac -#define CLDCOFST 0xb0 -#define CLSV 0xb4 -#define CLHWIN0 0xb8 -#define CLHWIN1 0xbc -#define CLHWIN2 0xc0 -#define CLVRV 0xc4 -#define CLVWIN0 0xc8 -#define CLVWIN1 0xcc -#define CLVWIN2 0xd0 -#define CLVWIN3 0xd4 -/**************************************************** - * Lense Shading Correction - ****************************************************/ -#define DATAHOFST 0xd8 -#define DATAVOFST 0xdc -#define LSCHVAL 0xe0 -#define LSCVVAL 0xe4 -#define TWODLSCCFG 0xe8 -#define TWODLSCOFST 0xec -#define TWODLSCINI 0xf0 -#define TWODLSCGRBU 0xf4 -#define TWODLSCGRBL 0xf8 -#define TWODLSCGROF 0xfc -#define TWODLSCORBU 0x100 -#define TWODLSCORBL 0x104 -#define TWODLSCOROF 0x108 -#define TWODLSCIRQEN 0x10c -#define TWODLSCIRQST 0x110 -/**************************************************** - * Data formatter - ****************************************************/ -#define FMTCFG 0x114 -#define FMTPLEN 0x118 -#define FMTSPH 0x11c -#define FMTLNH 0x120 -#define FMTSLV 0x124 -#define FMTLNV 0x128 -#define FMTRLEN 0x12c -#define FMTHCNT 0x130 -#define FMTAPTR_BASE 0x134 -/* Below macro for addresses FMTAPTR0 - FMTAPTR15 */ -#define FMTAPTR(i) (FMTAPTR_BASE + (i * 4)) -#define FMTPGMVF0 0x174 -#define FMTPGMVF1 0x178 -#define FMTPGMAPU0 0x17c -#define FMTPGMAPU1 0x180 -#define FMTPGMAPS0 0x184 -#define FMTPGMAPS1 0x188 -#define FMTPGMAPS2 0x18c -#define FMTPGMAPS3 0x190 -#define FMTPGMAPS4 0x194 -#define FMTPGMAPS5 0x198 -#define FMTPGMAPS6 0x19c -#define FMTPGMAPS7 0x1a0 -/************************************************ - * Color Space Converter - ************************************************/ -#define CSCCTL 0x1a4 -#define CSCM0 0x1a8 -#define CSCM1 0x1ac -#define CSCM2 0x1b0 -#define CSCM3 0x1b4 -#define CSCM4 0x1b8 -#define CSCM5 0x1bc -#define CSCM6 0x1c0 -#define CSCM7 0x1c4 -#define OBWIN0 0x1c8 -#define OBWIN1 0x1cc -#define OBWIN2 0x1d0 -#define OBWIN3 0x1d4 -#define OBVAL0 0x1d8 -#define OBVAL1 0x1dc -#define OBVAL2 0x1e0 -#define OBVAL3 0x1e4 -#define OBVAL4 0x1e8 -#define OBVAL5 0x1ec -#define OBVAL6 0x1f0 -#define OBVAL7 0x1f4 -#define CLKCTL 0x1f8 - -/* Masks & Shifts below */ -#define START_PX_HOR_MASK 0x7fff -#define NUM_PX_HOR_MASK 0x7fff -#define START_VER_ONE_MASK 0x7fff -#define START_VER_TWO_MASK 0x7fff -#define NUM_LINES_VER 0x7fff - -/* gain - offset masks */ -#define OFFSET_MASK 0xfff -#define GAIN_SDRAM_EN_SHIFT 12 -#define GAIN_IPIPE_EN_SHIFT 13 -#define GAIN_H3A_EN_SHIFT 14 -#define OFST_SDRAM_EN_SHIFT 8 -#define OFST_IPIPE_EN_SHIFT 9 -#define OFST_H3A_EN_SHIFT 10 -#define GAIN_OFFSET_EN_MASK 0x7700 - -/* Culling */ -#define CULL_PAT_EVEN_LINE_SHIFT 8 - -/* CCDCFG register */ -#define ISIF_YCINSWP_RAW (0x00 << 4) -#define ISIF_YCINSWP_YCBCR (0x01 << 4) -#define ISIF_CCDCFG_FIDMD_LATCH_VSYNC (0x00 << 6) -#define ISIF_CCDCFG_WENLOG_AND (0x00 << 8) -#define ISIF_CCDCFG_TRGSEL_WEN (0x00 << 9) -#define ISIF_CCDCFG_EXTRG_DISABLE (0x00 << 10) -#define ISIF_LATCH_ON_VSYNC_DISABLE (0x01 << 15) -#define ISIF_LATCH_ON_VSYNC_ENABLE (0x00 << 15) -#define ISIF_DATA_PACK_MASK 0x03 -#define ISIF_PIX_ORDER_SHIFT 11 -#define ISIF_PIX_ORDER_MASK 0x01 -#define ISIF_BW656_ENABLE (0x01 << 5) - -/* MODESET registers */ -#define ISIF_VDHDOUT_INPUT (0x00 << 0) -#define ISIF_INPUT_MASK 0x03 -#define ISIF_INPUT_SHIFT 12 -#define ISIF_FID_POL_MASK 0x01 -#define ISIF_FID_POL_SHIFT 4 -#define ISIF_HD_POL_MASK 0x01 -#define ISIF_HD_POL_SHIFT 3 -#define ISIF_VD_POL_MASK 0x01 -#define ISIF_VD_POL_SHIFT 2 -#define ISIF_DATAPOL_NORMAL 0x00 -#define ISIF_DATAPOL_MASK 0x01 -#define ISIF_DATAPOL_SHIFT 6 -#define ISIF_EXWEN_DISABLE 0x00 -#define ISIF_EXWEN_MASK 0x01 -#define ISIF_EXWEN_SHIFT 5 -#define ISIF_FRM_FMT_MASK 0x01 -#define ISIF_FRM_FMT_SHIFT 7 -#define ISIF_DATASFT_MASK 0x07 -#define ISIF_DATASFT_SHIFT 8 -#define ISIF_LPF_SHIFT 14 -#define ISIF_LPF_MASK 0x1 - -/* GAMMAWD registers */ -#define ISIF_ALAW_GAMA_WD_MASK 0xf -#define ISIF_ALAW_GAMA_WD_SHIFT 1 -#define ISIF_ALAW_ENABLE 0x01 -#define ISIF_GAMMAWD_CFA_MASK 0x01 -#define ISIF_GAMMAWD_CFA_SHIFT 5 - -/* HSIZE registers */ -#define ISIF_HSIZE_FLIP_MASK 0x01 -#define ISIF_HSIZE_FLIP_SHIFT 12 -#define ISIF_LINEOFST_MASK 0xfff - -/* MISC registers */ -#define ISIF_DPCM_EN_SHIFT 12 -#define ISIF_DPCM_PREDICTOR_SHIFT 13 -#define ISIF_DPCM_PREDICTOR_MASK 1 - -/* Black clamp related */ -#define ISIF_BC_DCOFFSET_MASK 0x1fff -#define ISIF_BC_MODE_COLOR_MASK 1 -#define ISIF_BC_MODE_COLOR_SHIFT 4 -#define ISIF_HORZ_BC_MODE_MASK 3 -#define ISIF_HORZ_BC_MODE_SHIFT 1 -#define ISIF_HORZ_BC_WIN_COUNT_MASK 0x1f -#define ISIF_HORZ_BC_WIN_SEL_SHIFT 5 -#define ISIF_HORZ_BC_PIX_LIMIT_SHIFT 6 -#define ISIF_HORZ_BC_WIN_H_SIZE_MASK 3 -#define ISIF_HORZ_BC_WIN_H_SIZE_SHIFT 8 -#define ISIF_HORZ_BC_WIN_V_SIZE_MASK 3 -#define ISIF_HORZ_BC_WIN_V_SIZE_SHIFT 12 -#define ISIF_HORZ_BC_WIN_START_H_MASK 0x1fff -#define ISIF_HORZ_BC_WIN_START_V_MASK 0x1fff -#define ISIF_VERT_BC_OB_H_SZ_MASK 7 -#define ISIF_VERT_BC_RST_VAL_SEL_MASK 3 -#define ISIF_VERT_BC_RST_VAL_SEL_SHIFT 4 -#define ISIF_VERT_BC_LINE_AVE_COEF_SHIFT 8 -#define ISIF_VERT_BC_OB_START_HORZ_MASK 0x1fff -#define ISIF_VERT_BC_OB_START_VERT_MASK 0x1fff -#define ISIF_VERT_BC_OB_VERT_SZ_MASK 0x1fff -#define ISIF_VERT_BC_RST_VAL_MASK 0xfff -#define ISIF_BC_VERT_START_SUB_V_MASK 0x1fff - -/* VDFC registers */ -#define ISIF_VDFC_EN_SHIFT 4 -#define ISIF_VDFC_CORR_MOD_MASK 3 -#define ISIF_VDFC_CORR_MOD_SHIFT 5 -#define ISIF_VDFC_CORR_WHOLE_LN_SHIFT 7 -#define ISIF_VDFC_LEVEL_SHFT_MASK 7 -#define ISIF_VDFC_LEVEL_SHFT_SHIFT 8 -#define ISIF_VDFC_SAT_LEVEL_MASK 0xfff -#define ISIF_VDFC_POS_MASK 0x1fff -#define ISIF_DFCMEMCTL_DFCMARST_SHIFT 2 - -/* CSC registers */ -#define ISIF_CSC_COEF_INTEG_MASK 7 -#define ISIF_CSC_COEF_DECIMAL_MASK 0x1f -#define ISIF_CSC_COEF_INTEG_SHIFT 5 -#define ISIF_CSCM_MSB_SHIFT 8 -#define ISIF_DF_CSC_SPH_MASK 0x1fff -#define ISIF_DF_CSC_LNH_MASK 0x1fff -#define ISIF_DF_CSC_SLV_MASK 0x1fff -#define ISIF_DF_CSC_LNV_MASK 0x1fff -#define ISIF_DF_NUMLINES 0x7fff -#define ISIF_DF_NUMPIX 0x1fff - -/* Offsets for LSC/DFC/Gain */ -#define ISIF_DATA_H_OFFSET_MASK 0x1fff -#define ISIF_DATA_V_OFFSET_MASK 0x1fff - -/* Linearization */ -#define ISIF_LIN_CORRSFT_MASK 7 -#define ISIF_LIN_CORRSFT_SHIFT 4 -#define ISIF_LIN_SCALE_FACT_INTEG_SHIFT 10 -#define ISIF_LIN_SCALE_FACT_DECIMAL_MASK 0x3ff -#define ISIF_LIN_ENTRY_MASK 0x3ff - -/* masks and shifts*/ -#define ISIF_SYNCEN_VDHDEN_MASK (1 << 0) -#define ISIF_SYNCEN_WEN_MASK (1 << 1) -#define ISIF_SYNCEN_WEN_SHIFT 1 - -#endif /* _DAVINCI_VPFE_DM365_ISIF_REGS_H */ diff --git a/drivers/staging/media/davinci_vpfe/dm365_resizer.c b/drivers/staging/media/davinci_vpfe/dm365_resizer.c deleted file mode 100644 index 7adf1fae43f6..000000000000 --- a/drivers/staging/media/davinci_vpfe/dm365_resizer.c +++ /dev/null @@ -1,1995 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2012 Texas Instruments Inc - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Contributors: - * Manjunath Hadli - * Prabhakar Lad - * - * - * Resizer allows upscaling or downscaling a image to a desired - * resolution. There are 2 resizer modules. both operating on the - * same input image, but can have different output resolution. - */ - -#include "dm365_ipipe_hw.h" -#include "dm365_resizer.h" - -#define MIN_IN_WIDTH 32 -#define MIN_IN_HEIGHT 32 -#define MAX_IN_WIDTH 4095 -#define MAX_IN_HEIGHT 4095 -#define MIN_OUT_WIDTH 16 -#define MIN_OUT_HEIGHT 2 - -static const unsigned int resizer_input_formats[] = { - MEDIA_BUS_FMT_UYVY8_2X8, - MEDIA_BUS_FMT_Y8_1X8, - MEDIA_BUS_FMT_UV8_1X8, - MEDIA_BUS_FMT_SGRBG12_1X12, -}; - -static const unsigned int resizer_output_formats[] = { - MEDIA_BUS_FMT_UYVY8_2X8, - MEDIA_BUS_FMT_Y8_1X8, - MEDIA_BUS_FMT_UV8_1X8, - MEDIA_BUS_FMT_YDYUYDYV8_1X16, - MEDIA_BUS_FMT_SGRBG12_1X12, -}; - -/* resizer_calculate_line_length() - This function calculates the line length of - * various image planes at the input and - * output. - */ -static void -resizer_calculate_line_length(u32 pix, int width, int height, - int *line_len, int *line_len_c) -{ - *line_len = 0; - *line_len_c = 0; - - if (pix == MEDIA_BUS_FMT_UYVY8_2X8 || - pix == MEDIA_BUS_FMT_SGRBG12_1X12) { - *line_len = width << 1; - } else { - *line_len = width; - *line_len_c = width; - } - - /* adjust the line len to be a multiple of 32 */ - *line_len += 31; - *line_len &= ~0x1f; - *line_len_c += 31; - *line_len_c &= ~0x1f; -} - -static inline int -resizer_validate_output_image_format(struct device *dev, - struct v4l2_mbus_framefmt *format, - int *in_line_len, int *in_line_len_c) -{ - if (format->code != MEDIA_BUS_FMT_UYVY8_2X8 && - format->code != MEDIA_BUS_FMT_Y8_1X8 && - format->code != MEDIA_BUS_FMT_UV8_1X8 && - format->code != MEDIA_BUS_FMT_YDYUYDYV8_1X16 && - format->code != MEDIA_BUS_FMT_SGRBG12_1X12) { - dev_err(dev, "Invalid Mbus format, %d\n", format->code); - return -EINVAL; - } - if (!format->width || !format->height) { - dev_err(dev, "invalid width or height\n"); - return -EINVAL; - } - resizer_calculate_line_length(format->code, format->width, - format->height, in_line_len, in_line_len_c); - return 0; -} - -static void -resizer_configure_passthru(struct vpfe_resizer_device *resizer, int bypass) -{ - struct resizer_params *param = &resizer->config; - - param->rsz_rsc_param[RSZ_A].cen = DISABLE; - param->rsz_rsc_param[RSZ_A].yen = DISABLE; - param->rsz_rsc_param[RSZ_A].v_phs_y = 0; - param->rsz_rsc_param[RSZ_A].v_phs_c = 0; - param->rsz_rsc_param[RSZ_A].v_dif = 256; - param->rsz_rsc_param[RSZ_A].v_lpf_int_y = 0; - param->rsz_rsc_param[RSZ_A].v_lpf_int_c = 0; - param->rsz_rsc_param[RSZ_A].h_phs = 0; - param->rsz_rsc_param[RSZ_A].h_dif = 256; - param->rsz_rsc_param[RSZ_A].h_lpf_int_y = 0; - param->rsz_rsc_param[RSZ_A].h_lpf_int_c = 0; - param->rsz_rsc_param[RSZ_A].dscale_en = DISABLE; - param->rsz2rgb[RSZ_A].rgb_en = DISABLE; - param->rsz_en[RSZ_A] = ENABLE; - param->rsz_en[RSZ_B] = DISABLE; - if (bypass) { - param->rsz_rsc_param[RSZ_A].i_vps = 0; - param->rsz_rsc_param[RSZ_A].i_hps = 0; - /* Raw Bypass */ - param->rsz_common.passthrough = BYPASS_ON; - } -} - -static void -configure_resizer_out_params(struct vpfe_resizer_device *resizer, int index, - void *output_spec, unsigned char partial, - unsigned int flag) -{ - struct resizer_params *param = &resizer->config; - struct v4l2_mbus_framefmt *outformat; - struct vpfe_rsz_output_spec *output; - - if (index == RSZ_A && - resizer->resizer_a.output == RESIZER_OUTPUT_NONE) { - param->rsz_en[index] = DISABLE; - return; - } - if (index == RSZ_B && - resizer->resizer_b.output == RESIZER_OUTPUT_NONE) { - param->rsz_en[index] = DISABLE; - return; - } - output = output_spec; - param->rsz_en[index] = ENABLE; - if (partial) { - param->rsz_rsc_param[index].h_flip = output->h_flip; - param->rsz_rsc_param[index].v_flip = output->v_flip; - param->rsz_rsc_param[index].v_typ_y = output->v_typ_y; - param->rsz_rsc_param[index].v_typ_c = output->v_typ_c; - param->rsz_rsc_param[index].v_lpf_int_y = - output->v_lpf_int_y; - param->rsz_rsc_param[index].v_lpf_int_c = - output->v_lpf_int_c; - param->rsz_rsc_param[index].h_typ_y = output->h_typ_y; - param->rsz_rsc_param[index].h_typ_c = output->h_typ_c; - param->rsz_rsc_param[index].h_lpf_int_y = - output->h_lpf_int_y; - param->rsz_rsc_param[index].h_lpf_int_c = - output->h_lpf_int_c; - param->rsz_rsc_param[index].dscale_en = - output->en_down_scale; - param->rsz_rsc_param[index].h_dscale_ave_sz = - output->h_dscale_ave_sz; - param->rsz_rsc_param[index].v_dscale_ave_sz = - output->v_dscale_ave_sz; - param->ext_mem_param[index].user_y_ofst = - (output->user_y_ofst + 31) & ~0x1f; - param->ext_mem_param[index].user_c_ofst = - (output->user_c_ofst + 31) & ~0x1f; - return; - } - - if (index == RSZ_A) - outformat = &resizer->resizer_a.formats[RESIZER_PAD_SOURCE]; - else - outformat = &resizer->resizer_b.formats[RESIZER_PAD_SOURCE]; - param->rsz_rsc_param[index].o_vsz = outformat->height - 1; - param->rsz_rsc_param[index].o_hsz = outformat->width - 1; - param->ext_mem_param[index].rsz_sdr_ptr_s_y = output->vst_y; - param->ext_mem_param[index].rsz_sdr_ptr_e_y = outformat->height; - param->ext_mem_param[index].rsz_sdr_ptr_s_c = output->vst_c; - param->ext_mem_param[index].rsz_sdr_ptr_e_c = outformat->height; - - if (!flag) - return; - /* update common parameters */ - param->rsz_rsc_param[index].h_flip = output->h_flip; - param->rsz_rsc_param[index].v_flip = output->v_flip; - param->rsz_rsc_param[index].v_typ_y = output->v_typ_y; - param->rsz_rsc_param[index].v_typ_c = output->v_typ_c; - param->rsz_rsc_param[index].v_lpf_int_y = output->v_lpf_int_y; - param->rsz_rsc_param[index].v_lpf_int_c = output->v_lpf_int_c; - param->rsz_rsc_param[index].h_typ_y = output->h_typ_y; - param->rsz_rsc_param[index].h_typ_c = output->h_typ_c; - param->rsz_rsc_param[index].h_lpf_int_y = output->h_lpf_int_y; - param->rsz_rsc_param[index].h_lpf_int_c = output->h_lpf_int_c; - param->rsz_rsc_param[index].dscale_en = output->en_down_scale; - param->rsz_rsc_param[index].h_dscale_ave_sz = output->h_dscale_ave_sz; - param->rsz_rsc_param[index].v_dscale_ave_sz = output->h_dscale_ave_sz; - param->ext_mem_param[index].user_y_ofst = - (output->user_y_ofst + 31) & ~0x1f; - param->ext_mem_param[index].user_c_ofst = - (output->user_c_ofst + 31) & ~0x1f; -} - -/* - * resizer_calculate_resize_ratios() - Calculates resize ratio for resizer - * A or B. This is called after setting - * the input size or output size. - * @resizer: Pointer to VPFE resizer subdevice. - * @index: index RSZ_A-resizer-A RSZ_B-resizer-B. - */ -static void -resizer_calculate_resize_ratios(struct vpfe_resizer_device *resizer, int index) -{ - struct resizer_params *param = &resizer->config; - struct v4l2_mbus_framefmt *informat, *outformat; - - informat = &resizer->crop_resizer.formats[RESIZER_CROP_PAD_SINK]; - - if (index == RSZ_A) - outformat = &resizer->resizer_a.formats[RESIZER_PAD_SOURCE]; - else - outformat = &resizer->resizer_b.formats[RESIZER_PAD_SOURCE]; - - if (outformat->field != V4L2_FIELD_INTERLACED) - param->rsz_rsc_param[index].v_dif = - ((informat->height) * 256) / (outformat->height); - else - param->rsz_rsc_param[index].v_dif = - ((informat->height >> 1) * 256) / (outformat->height); - param->rsz_rsc_param[index].h_dif = - ((informat->width) * 256) / (outformat->width); -} - -static void resizer_enable_422_420_conversion(struct resizer_params *param, - int index, bool en) -{ - param->rsz_rsc_param[index].cen = en; - param->rsz_rsc_param[index].yen = en; -} - -/* resizer_calculate_sdram_offsets() - This function calculates the offsets from - * start of buffer for the C plane when - * output format is YUV420SP. It also - * calculates the offsets from the start of - * the buffer when the image is flipped - * vertically or horizontally for ycbcr/y/c - * planes. - * @resizer: Pointer to resizer subdevice. - * @index: index RSZ_A-resizer-A RSZ_B-resizer-B. - */ -static int -resizer_calculate_sdram_offsets(struct vpfe_resizer_device *resizer, int index) -{ - struct resizer_params *param = &resizer->config; - struct v4l2_mbus_framefmt *outformat; - int bytesperpixel = 2; - int image_height; - int image_width; - int yuv_420 = 0; - int offset = 0; - - if (index == RSZ_A) - outformat = &resizer->resizer_a.formats[RESIZER_PAD_SOURCE]; - else - outformat = &resizer->resizer_b.formats[RESIZER_PAD_SOURCE]; - - image_height = outformat->height + 1; - image_width = outformat->width + 1; - param->ext_mem_param[index].c_offset = 0; - param->ext_mem_param[index].flip_ofst_y = 0; - param->ext_mem_param[index].flip_ofst_c = 0; - if (outformat->code == MEDIA_BUS_FMT_YDYUYDYV8_1X16) { - /* YUV 420 */ - yuv_420 = 1; - bytesperpixel = 1; - } - - if (param->rsz_rsc_param[index].h_flip) - /* width * bytesperpixel - 1 */ - offset = (image_width * bytesperpixel) - 1; - if (param->rsz_rsc_param[index].v_flip) - offset += (image_height - 1) * - param->ext_mem_param[index].rsz_sdr_oft_y; - param->ext_mem_param[index].flip_ofst_y = offset; - if (!yuv_420) - return 0; - offset = 0; - /* half height for c-plane */ - if (param->rsz_rsc_param[index].h_flip) - /* width * bytesperpixel - 1 */ - offset = image_width - 1; - if (param->rsz_rsc_param[index].v_flip) - offset += (((image_height >> 1) - 1) * - param->ext_mem_param[index].rsz_sdr_oft_c); - param->ext_mem_param[index].flip_ofst_c = offset; - param->ext_mem_param[index].c_offset = - param->ext_mem_param[index].rsz_sdr_oft_y * image_height; - return 0; -} - -static int resizer_configure_output_win(struct vpfe_resizer_device *resizer) -{ - struct resizer_params *param = &resizer->config; - struct vpfe_rsz_output_spec output_specs; - struct v4l2_mbus_framefmt *outformat; - int line_len_c; - int line_len; - int ret; - - outformat = &resizer->resizer_a.formats[RESIZER_PAD_SOURCE]; - - memset(&output_specs, 0x0, sizeof(struct vpfe_rsz_output_spec)); - output_specs.vst_y = param->user_config.vst; - if (outformat->code == MEDIA_BUS_FMT_YDYUYDYV8_1X16) - output_specs.vst_c = param->user_config.vst; - - configure_resizer_out_params(resizer, RSZ_A, &output_specs, 0, 0); - resizer_calculate_line_length(outformat->code, - param->rsz_rsc_param[0].o_hsz + 1, - param->rsz_rsc_param[0].o_vsz + 1, - &line_len, &line_len_c); - param->ext_mem_param[0].rsz_sdr_oft_y = line_len; - param->ext_mem_param[0].rsz_sdr_oft_c = line_len_c; - resizer_calculate_resize_ratios(resizer, RSZ_A); - if (param->rsz_en[RSZ_B]) - resizer_calculate_resize_ratios(resizer, RSZ_B); - - if (outformat->code == MEDIA_BUS_FMT_YDYUYDYV8_1X16) - resizer_enable_422_420_conversion(param, RSZ_A, ENABLE); - else - resizer_enable_422_420_conversion(param, RSZ_A, DISABLE); - - ret = resizer_calculate_sdram_offsets(resizer, RSZ_A); - if (!ret && param->rsz_en[RSZ_B]) - ret = resizer_calculate_sdram_offsets(resizer, RSZ_B); - - if (ret) - pr_err("Error in calculating sdram offsets\n"); - return ret; -} - -static int -resizer_calculate_down_scale_f_div_param(struct device *dev, - int input_width, int output_width, - struct resizer_scale_param *param) -{ - /* rsz = R, input_width = H, output width = h in the equation */ - unsigned int two_power; - unsigned int upper_h1; - unsigned int upper_h2; - unsigned int val1; - unsigned int val; - unsigned int rsz; - unsigned int h1; - unsigned int h2; - unsigned int o; - unsigned int n; - - upper_h1 = input_width >> 1; - n = param->h_dscale_ave_sz; - /* 2 ^ (scale+1) */ - two_power = 1 << (n + 1); - upper_h1 = (upper_h1 >> (n + 1)) << (n + 1); - upper_h2 = input_width - upper_h1; - if (upper_h2 % two_power) { - dev_err(dev, "frame halves to be a multiple of 2 power n+1\n"); - return -EINVAL; - } - two_power = 1 << n; - rsz = (input_width << 8) / output_width; - val = rsz * two_power; - val = ((upper_h1 << 8) / val) + 1; - if (!(val % 2)) { - h1 = val; - } else { - val = upper_h1 << 8; - val >>= n + 1; - val -= rsz >> 1; - val /= rsz << 1; - val <<= 1; - val += 2; - h1 = val; - } - o = 10 + (two_power << 2); - if (((input_width << 7) / rsz) % 2) - o += ((DIV_ROUND_UP(rsz, 1024) << 1) << n); - h2 = output_width - h1; - /* phi */ - val = (h1 * rsz) - (((upper_h1 - (o - 10)) / two_power) << 8); - /* skip */ - val1 = ((val - 1024) >> 9) << 1; - param->f_div.num_passes = MAX_PASSES; - param->f_div.pass[0].o_hsz = h1 - 1; - param->f_div.pass[0].i_hps = 0; - param->f_div.pass[0].h_phs = 0; - param->f_div.pass[0].src_hps = 0; - param->f_div.pass[0].src_hsz = upper_h1 + o; - param->f_div.pass[1].o_hsz = h2 - 1; - param->f_div.pass[1].i_hps = 10 + (val1 * two_power); - param->f_div.pass[1].h_phs = val - (val1 << 8); - param->f_div.pass[1].src_hps = upper_h1 - o; - param->f_div.pass[1].src_hsz = upper_h2 + o; - - return 0; -} - -static int -resizer_configure_common_in_params(struct vpfe_resizer_device *resizer) -{ - struct vpfe_device *vpfe_dev = to_vpfe_device(resizer); - struct resizer_params *param = &resizer->config; - struct vpfe_rsz_config_params *user_config; - struct v4l2_mbus_framefmt *informat; - - informat = &resizer->crop_resizer.formats[RESIZER_CROP_PAD_SINK]; - user_config = &resizer->config.user_config; - param->rsz_common.vps = param->user_config.vst; - param->rsz_common.hps = param->user_config.hst; - - if (vpfe_ipipeif_decimation_enabled(vpfe_dev)) - param->rsz_common.hsz = ((informat->width - 1) * - IPIPEIF_RSZ_CONST) / vpfe_ipipeif_get_rsz(vpfe_dev); - else - param->rsz_common.hsz = informat->width - 1; - - if (informat->field == V4L2_FIELD_INTERLACED) - param->rsz_common.vsz = (informat->height - 1) >> 1; - else - param->rsz_common.vsz = informat->height - 1; - - param->rsz_common.raw_flip = 0; - - if (resizer->crop_resizer.input == RESIZER_CROP_INPUT_IPIPEIF) - param->rsz_common.source = IPIPEIF_DATA; - else - param->rsz_common.source = IPIPE_DATA; - - switch (informat->code) { - case MEDIA_BUS_FMT_UYVY8_2X8: - param->rsz_common.src_img_fmt = RSZ_IMG_422; - param->rsz_common.raw_flip = 0; - break; - - case MEDIA_BUS_FMT_Y8_1X8: - param->rsz_common.src_img_fmt = RSZ_IMG_420; - /* Select y */ - param->rsz_common.y_c = 0; - param->rsz_common.raw_flip = 0; - break; - - case MEDIA_BUS_FMT_UV8_1X8: - param->rsz_common.src_img_fmt = RSZ_IMG_420; - /* Select y */ - param->rsz_common.y_c = 1; - param->rsz_common.raw_flip = 0; - break; - - case MEDIA_BUS_FMT_SGRBG12_1X12: - param->rsz_common.raw_flip = 1; - break; - - default: - param->rsz_common.src_img_fmt = RSZ_IMG_422; - param->rsz_common.source = IPIPE_DATA; - } - - param->rsz_common.yuv_y_min = user_config->yuv_y_min; - param->rsz_common.yuv_y_max = user_config->yuv_y_max; - param->rsz_common.yuv_c_min = user_config->yuv_c_min; - param->rsz_common.yuv_c_max = user_config->yuv_c_max; - param->rsz_common.out_chr_pos = user_config->out_chr_pos; - param->rsz_common.rsz_seq_crv = user_config->chroma_sample_even; - - return 0; -} -static int -resizer_configure_in_continuous_mode(struct vpfe_resizer_device *resizer) -{ - struct device *dev = resizer->crop_resizer.subdev.v4l2_dev->dev; - struct resizer_params *param = &resizer->config; - struct vpfe_rsz_config_params *cont_config; - int line_len_c; - int line_len; - int ret; - - if (resizer->resizer_a.output != RESIZER_OUTPUT_MEMORY) { - dev_err(dev, "enable resizer - Resizer-A\n"); - return -EINVAL; - } - - cont_config = &resizer->config.user_config; - param->rsz_en[RSZ_A] = ENABLE; - configure_resizer_out_params(resizer, RSZ_A, - &cont_config->output1, 1, 0); - param->rsz_en[RSZ_B] = DISABLE; - param->oper_mode = RESIZER_MODE_CONTINUOUS; - - if (resizer->resizer_b.output == RESIZER_OUTPUT_MEMORY) { - struct v4l2_mbus_framefmt *outformat2; - - param->rsz_en[RSZ_B] = ENABLE; - outformat2 = &resizer->resizer_b.formats[RESIZER_PAD_SOURCE]; - ret = resizer_validate_output_image_format(dev, outformat2, - &line_len, &line_len_c); - if (ret) - return ret; - param->ext_mem_param[RSZ_B].rsz_sdr_oft_y = line_len; - param->ext_mem_param[RSZ_B].rsz_sdr_oft_c = line_len_c; - configure_resizer_out_params(resizer, RSZ_B, - &cont_config->output2, 0, 1); - if (outformat2->code == MEDIA_BUS_FMT_YDYUYDYV8_1X16) - resizer_enable_422_420_conversion(param, - RSZ_B, ENABLE); - else - resizer_enable_422_420_conversion(param, - RSZ_B, DISABLE); - } - resizer_configure_common_in_params(resizer); - ret = resizer_configure_output_win(resizer); - if (ret) - return ret; - - param->rsz_common.passthrough = cont_config->bypass; - if (cont_config->bypass) - resizer_configure_passthru(resizer, 1); - - return 0; -} - -static inline int -resizer_validate_input_image_format(struct device *dev, - u32 pix, - int width, int height, int *line_len) -{ - int val; - - if (pix != MEDIA_BUS_FMT_UYVY8_2X8 && - pix != MEDIA_BUS_FMT_Y8_1X8 && - pix != MEDIA_BUS_FMT_UV8_1X8 && - pix != MEDIA_BUS_FMT_SGRBG12_1X12) { - dev_err(dev, - "resizer validate output: pix format not supported, %d\n", pix); - return -EINVAL; - } - - if (!width || !height) { - dev_err(dev, - "resizer validate input: invalid width or height\n"); - return -EINVAL; - } - - if (pix == MEDIA_BUS_FMT_UV8_1X8) - resizer_calculate_line_length(pix, width, - height, &val, line_len); - else - resizer_calculate_line_length(pix, width, - height, line_len, &val); - - return 0; -} - -static int -resizer_validate_decimation(struct device *dev, enum ipipeif_decimation dec_en, - unsigned char rsz, unsigned char frame_div_mode_en, - int width) -{ - if (dec_en && frame_div_mode_en) { - dev_err(dev, - "dec_en & frame_div_mode_en can not enabled simultaneously\n"); - return -EINVAL; - } - - if (frame_div_mode_en) { - dev_err(dev, "frame_div_mode mode not supported\n"); - return -EINVAL; - } - - if (!dec_en) - return 0; - - if (width <= VPFE_IPIPE_MAX_INPUT_WIDTH) { - dev_err(dev, - "image width to be more than %d for decimation\n", - VPFE_IPIPE_MAX_INPUT_WIDTH); - return -EINVAL; - } - - if (rsz < IPIPEIF_RSZ_MIN || rsz > IPIPEIF_RSZ_MAX) { - dev_err(dev, "rsz range is %d to %d\n", - IPIPEIF_RSZ_MIN, IPIPEIF_RSZ_MAX); - return -EINVAL; - } - - return 0; -} - -/* resizer_calculate_normal_f_div_param() - Algorithm to calculate the frame - * division parameters for resizer. - * in normal mode. - */ -static int -resizer_calculate_normal_f_div_param(struct device *dev, int input_width, - int output_width, struct resizer_scale_param *param) -{ - /* rsz = R, input_width = H, output width = h in the equation */ - unsigned int val1; - unsigned int rsz; - unsigned int val; - unsigned int h1; - unsigned int h2; - unsigned int o; - - if (output_width > input_width) { - dev_err(dev, "frame div mode is used for scale down only\n"); - return -EINVAL; - } - - rsz = (input_width << 8) / output_width; - val = rsz << 1; - val = ((input_width << 8) / val) + 1; - o = 14; - if (!(val % 2)) { - h1 = val; - } else { - val = input_width << 7; - val -= rsz >> 1; - val /= rsz << 1; - val <<= 1; - val += 2; - o += (DIV_ROUND_UP(rsz, 1024) << 1); - h1 = val; - } - h2 = output_width - h1; - /* phi */ - val = (h1 * rsz) - (((input_width >> 1) - o) << 8); - /* skip */ - val1 = ((val - 1024) >> 9) << 1; - param->f_div.num_passes = MAX_PASSES; - param->f_div.pass[0].o_hsz = h1 - 1; - param->f_div.pass[0].i_hps = 0; - param->f_div.pass[0].h_phs = 0; - param->f_div.pass[0].src_hps = 0; - param->f_div.pass[0].src_hsz = (input_width >> 2) + o; - param->f_div.pass[1].o_hsz = h2 - 1; - param->f_div.pass[1].i_hps = val1; - param->f_div.pass[1].h_phs = val - (val1 << 8); - param->f_div.pass[1].src_hps = (input_width >> 2) - o; - param->f_div.pass[1].src_hsz = (input_width >> 2) + o; - - return 0; -} - -static int -resizer_configure_in_single_shot_mode(struct vpfe_resizer_device *resizer) -{ - struct vpfe_rsz_config_params *config = &resizer->config.user_config; - struct device *dev = resizer->crop_resizer.subdev.v4l2_dev->dev; - struct vpfe_device *vpfe_dev = to_vpfe_device(resizer); - struct v4l2_mbus_framefmt *outformat1, *outformat2; - struct resizer_params *param = &resizer->config; - struct v4l2_mbus_framefmt *informat; - int decimation; - int line_len_c; - int line_len; - int rsz; - int ret; - - informat = &resizer->crop_resizer.formats[RESIZER_CROP_PAD_SINK]; - outformat1 = &resizer->resizer_a.formats[RESIZER_PAD_SOURCE]; - outformat2 = &resizer->resizer_b.formats[RESIZER_PAD_SOURCE]; - - decimation = vpfe_ipipeif_decimation_enabled(vpfe_dev); - rsz = vpfe_ipipeif_get_rsz(vpfe_dev); - if (decimation && param->user_config.frame_div_mode_en) { - dev_err(dev, - "dec_en & frame_div_mode_en cannot enabled simultaneously\n"); - return -EINVAL; - } - - ret = resizer_validate_decimation(dev, decimation, rsz, - param->user_config.frame_div_mode_en, informat->width); - if (ret) - return -EINVAL; - - ret = resizer_validate_input_image_format(dev, informat->code, - informat->width, informat->height, &line_len); - if (ret) - return -EINVAL; - - if (resizer->resizer_a.output != RESIZER_OUTPUT_NONE) { - param->rsz_en[RSZ_A] = ENABLE; - ret = resizer_validate_output_image_format(dev, outformat1, - &line_len, &line_len_c); - if (ret) - return ret; - param->ext_mem_param[RSZ_A].rsz_sdr_oft_y = line_len; - param->ext_mem_param[RSZ_A].rsz_sdr_oft_c = line_len_c; - configure_resizer_out_params(resizer, RSZ_A, - ¶m->user_config.output1, 0, 1); - - if (outformat1->code == MEDIA_BUS_FMT_SGRBG12_1X12) - param->rsz_common.raw_flip = 1; - else - param->rsz_common.raw_flip = 0; - - if (outformat1->code == MEDIA_BUS_FMT_YDYUYDYV8_1X16) - resizer_enable_422_420_conversion(param, - RSZ_A, ENABLE); - else - resizer_enable_422_420_conversion(param, - RSZ_A, DISABLE); - } - - if (resizer->resizer_b.output != RESIZER_OUTPUT_NONE) { - param->rsz_en[RSZ_B] = ENABLE; - ret = resizer_validate_output_image_format(dev, outformat2, - &line_len, &line_len_c); - if (ret) - return ret; - param->ext_mem_param[RSZ_B].rsz_sdr_oft_y = line_len; - param->ext_mem_param[RSZ_B].rsz_sdr_oft_c = line_len_c; - configure_resizer_out_params(resizer, RSZ_B, - ¶m->user_config.output2, 0, 1); - if (outformat2->code == MEDIA_BUS_FMT_YDYUYDYV8_1X16) - resizer_enable_422_420_conversion(param, - RSZ_B, ENABLE); - else - resizer_enable_422_420_conversion(param, - RSZ_B, DISABLE); - } - - resizer_configure_common_in_params(resizer); - if (resizer->resizer_a.output != RESIZER_OUTPUT_NONE) { - resizer_calculate_resize_ratios(resizer, RSZ_A); - resizer_calculate_sdram_offsets(resizer, RSZ_A); - /* Overriding resize ratio calculation */ - if (informat->code == MEDIA_BUS_FMT_UV8_1X8) { - param->rsz_rsc_param[RSZ_A].v_dif = - (((informat->height + 1) * 2) * 256) / - (param->rsz_rsc_param[RSZ_A].o_vsz + 1); - } - } - - if (resizer->resizer_b.output != RESIZER_OUTPUT_NONE) { - resizer_calculate_resize_ratios(resizer, RSZ_B); - resizer_calculate_sdram_offsets(resizer, RSZ_B); - /* Overriding resize ratio calculation */ - if (informat->code == MEDIA_BUS_FMT_UV8_1X8) { - param->rsz_rsc_param[RSZ_B].v_dif = - (((informat->height + 1) * 2) * 256) / - (param->rsz_rsc_param[RSZ_B].o_vsz + 1); - } - } - if (param->user_config.frame_div_mode_en && - param->rsz_en[RSZ_A]) { - if (!param->rsz_rsc_param[RSZ_A].dscale_en) - ret = resizer_calculate_normal_f_div_param(dev, - informat->width, - param->rsz_rsc_param[RSZ_A].o_vsz + 1, - ¶m->rsz_rsc_param[RSZ_A]); - else - ret = resizer_calculate_down_scale_f_div_param(dev, - informat->width, - param->rsz_rsc_param[RSZ_A].o_vsz + 1, - ¶m->rsz_rsc_param[RSZ_A]); - if (ret) - return -EINVAL; - } - if (param->user_config.frame_div_mode_en && - param->rsz_en[RSZ_B]) { - if (!param->rsz_rsc_param[RSZ_B].dscale_en) - ret = resizer_calculate_normal_f_div_param(dev, - informat->width, - param->rsz_rsc_param[RSZ_B].o_vsz + 1, - ¶m->rsz_rsc_param[RSZ_B]); - else - ret = resizer_calculate_down_scale_f_div_param(dev, - informat->width, - param->rsz_rsc_param[RSZ_B].o_vsz + 1, - ¶m->rsz_rsc_param[RSZ_B]); - if (ret) - return -EINVAL; - } - param->rsz_common.passthrough = config->bypass; - if (config->bypass) - resizer_configure_passthru(resizer, 1); - return 0; -} - -static void -resizer_set_default_configuration(struct vpfe_resizer_device *resizer) -{ -#define WIDTH_I 640 -#define HEIGHT_I 480 -#define WIDTH_O 640 -#define HEIGHT_O 480 - const struct resizer_params rsz_default_config = { - .oper_mode = RESIZER_MODE_ONE_SHOT, - .rsz_common = { - .vsz = HEIGHT_I - 1, - .hsz = WIDTH_I - 1, - .src_img_fmt = RSZ_IMG_422, - .raw_flip = 1, /* flip preserve Raw format */ - .source = IPIPE_DATA, - .passthrough = BYPASS_OFF, - .yuv_y_max = 255, - .yuv_c_max = 255, - .rsz_seq_crv = DISABLE, - .out_chr_pos = VPFE_IPIPE_YUV422_CHR_POS_COSITE, - }, - .rsz_rsc_param = { - { - .h_flip = DISABLE, - .v_flip = DISABLE, - .cen = DISABLE, - .yen = DISABLE, - .o_vsz = HEIGHT_O - 1, - .o_hsz = WIDTH_O - 1, - .v_dif = 256, - .v_typ_y = VPFE_RSZ_INTP_CUBIC, - .v_typ_c = VPFE_RSZ_INTP_CUBIC, - .h_dif = 256, - .h_typ_y = VPFE_RSZ_INTP_CUBIC, - .h_typ_c = VPFE_RSZ_INTP_CUBIC, - .h_dscale_ave_sz = - VPFE_IPIPE_DWN_SCALE_1_OVER_2, - .v_dscale_ave_sz = - VPFE_IPIPE_DWN_SCALE_1_OVER_2, - }, - { - .h_flip = DISABLE, - .v_flip = DISABLE, - .cen = DISABLE, - .yen = DISABLE, - .o_vsz = HEIGHT_O - 1, - .o_hsz = WIDTH_O - 1, - .v_dif = 256, - .v_typ_y = VPFE_RSZ_INTP_CUBIC, - .v_typ_c = VPFE_RSZ_INTP_CUBIC, - .h_dif = 256, - .h_typ_y = VPFE_RSZ_INTP_CUBIC, - .h_typ_c = VPFE_RSZ_INTP_CUBIC, - .h_dscale_ave_sz = - VPFE_IPIPE_DWN_SCALE_1_OVER_2, - .v_dscale_ave_sz = - VPFE_IPIPE_DWN_SCALE_1_OVER_2, - }, - }, - .rsz2rgb = { - { - .rgb_en = DISABLE - }, - { - .rgb_en = DISABLE - } - }, - .ext_mem_param = { - { - .rsz_sdr_oft_y = WIDTH_O << 1, - .rsz_sdr_ptr_e_y = HEIGHT_O, - .rsz_sdr_oft_c = WIDTH_O, - .rsz_sdr_ptr_e_c = HEIGHT_O >> 1, - }, - { - .rsz_sdr_oft_y = WIDTH_O << 1, - .rsz_sdr_ptr_e_y = HEIGHT_O, - .rsz_sdr_oft_c = WIDTH_O, - .rsz_sdr_ptr_e_c = HEIGHT_O, - }, - }, - .rsz_en[0] = ENABLE, - .rsz_en[1] = DISABLE, - .user_config = { - .output1 = { - .v_typ_y = VPFE_RSZ_INTP_CUBIC, - .v_typ_c = VPFE_RSZ_INTP_CUBIC, - .h_typ_y = VPFE_RSZ_INTP_CUBIC, - .h_typ_c = VPFE_RSZ_INTP_CUBIC, - .h_dscale_ave_sz = - VPFE_IPIPE_DWN_SCALE_1_OVER_2, - .v_dscale_ave_sz = - VPFE_IPIPE_DWN_SCALE_1_OVER_2, - }, - .output2 = { - .v_typ_y = VPFE_RSZ_INTP_CUBIC, - .v_typ_c = VPFE_RSZ_INTP_CUBIC, - .h_typ_y = VPFE_RSZ_INTP_CUBIC, - .h_typ_c = VPFE_RSZ_INTP_CUBIC, - .h_dscale_ave_sz = - VPFE_IPIPE_DWN_SCALE_1_OVER_2, - .v_dscale_ave_sz = - VPFE_IPIPE_DWN_SCALE_1_OVER_2, - }, - .yuv_y_max = 255, - .yuv_c_max = 255, - .out_chr_pos = VPFE_IPIPE_YUV422_CHR_POS_COSITE, - }, - }; - memcpy(&resizer->config, &rsz_default_config, - sizeof(struct resizer_params)); -} - -/* - * resizer_set_configuration() - set resizer config - * @resizer: vpfe resizer device pointer. - * @chan_config: resizer channel configuration. - */ -static int -resizer_set_configuration(struct vpfe_resizer_device *resizer, - struct vpfe_rsz_config *chan_config) -{ - if (!chan_config->config) - resizer_set_default_configuration(resizer); - else - if (copy_from_user(&resizer->config.user_config, - (void __user *)chan_config->config, - sizeof(struct vpfe_rsz_config_params))) - return -EFAULT; - - return 0; -} - -/* - * resizer_get_configuration() - get resizer config - * @resizer: vpfe resizer device pointer. - * @channel: image processor logical channel. - * @chan_config: resizer channel configuration. - */ -static int -resizer_get_configuration(struct vpfe_resizer_device *resizer, - struct vpfe_rsz_config *chan_config) -{ - struct device *dev = resizer->crop_resizer.subdev.v4l2_dev->dev; - - if (!chan_config->config) { - dev_err(dev, "Resizer channel invalid pointer\n"); - return -EINVAL; - } - - if (copy_to_user((void __user *)chan_config->config, - (void *)&resizer->config.user_config, - sizeof(struct vpfe_rsz_config_params))) { - dev_err(dev, "resizer_get_configuration: Error in copy to user\n"); - return -EFAULT; - } - - return 0; -} - -/* - * VPFE video operations - */ - -/* - * resizer_a_video_out_queue() - RESIZER-A video out queue - * @vpfe_dev: vpfe device pointer. - * @addr: buffer address. - */ -static int resizer_a_video_out_queue(struct vpfe_device *vpfe_dev, - unsigned long addr) -{ - struct vpfe_resizer_device *resizer = &vpfe_dev->vpfe_resizer; - - return resizer_set_outaddr(resizer->base_addr, - &resizer->config, RSZ_A, addr); -} - -/* - * resizer_b_video_out_queue() - RESIZER-B video out queue - * @vpfe_dev: vpfe device pointer. - * @addr: buffer address. - */ -static int resizer_b_video_out_queue(struct vpfe_device *vpfe_dev, - unsigned long addr) -{ - struct vpfe_resizer_device *resizer = &vpfe_dev->vpfe_resizer; - - return resizer_set_outaddr(resizer->base_addr, - &resizer->config, RSZ_B, addr); -} - -static const struct vpfe_video_operations resizer_a_video_ops = { - .queue = resizer_a_video_out_queue, -}; - -static const struct vpfe_video_operations resizer_b_video_ops = { - .queue = resizer_b_video_out_queue, -}; - -static void resizer_enable(struct vpfe_resizer_device *resizer, int en) -{ - struct vpfe_device *vpfe_dev = to_vpfe_device(resizer); - u16 ipipeif_sink = vpfe_dev->vpfe_ipipeif.input; - unsigned char val; - - if (resizer->crop_resizer.input == RESIZER_CROP_INPUT_NONE) - return; - - if (resizer->crop_resizer.input == RESIZER_CROP_INPUT_IPIPEIF && - ipipeif_sink == IPIPEIF_INPUT_MEMORY) { - do { - val = regr_rsz(resizer->base_addr, RSZ_SRC_EN); - } while (val); - - if (resizer->resizer_a.output != RESIZER_OUTPUT_NONE) { - do { - val = regr_rsz(resizer->base_addr, RSZ_A); - } while (val); - } - if (resizer->resizer_b.output != RESIZER_OUTPUT_NONE) { - do { - val = regr_rsz(resizer->base_addr, RSZ_B); - } while (val); - } - } - if (resizer->resizer_a.output != RESIZER_OUTPUT_NONE) - rsz_enable(resizer->base_addr, RSZ_A, en); - - if (resizer->resizer_b.output != RESIZER_OUTPUT_NONE) - rsz_enable(resizer->base_addr, RSZ_B, en); -} - - -/* - * resizer_ss_isr() - resizer module single-shot buffer scheduling isr - * @resizer: vpfe resizer device pointer. - */ -static void resizer_ss_isr(struct vpfe_resizer_device *resizer) -{ - struct vpfe_video_device *video_out = &resizer->resizer_a.video_out; - struct vpfe_video_device *video_out2 = &resizer->resizer_b.video_out; - struct vpfe_device *vpfe_dev = to_vpfe_device(resizer); - struct vpfe_pipeline *pipe = &video_out->pipe; - u16 ipipeif_sink = vpfe_dev->vpfe_ipipeif.input; - u32 val; - - if (ipipeif_sink != IPIPEIF_INPUT_MEMORY) - return; - - if (resizer->resizer_a.output == RESIZER_OUTPUT_MEMORY) { - val = vpss_dma_complete_interrupt(); - if (val != 0 && val != 2) - return; - } - - if (resizer->resizer_a.output == RESIZER_OUTPUT_MEMORY) { - spin_lock(&video_out->dma_queue_lock); - vpfe_video_process_buffer_complete(video_out); - video_out->state = VPFE_VIDEO_BUFFER_NOT_QUEUED; - vpfe_video_schedule_next_buffer(video_out); - spin_unlock(&video_out->dma_queue_lock); - } - - /* If resizer B is enabled */ - if (pipe->output_num > 1 && resizer->resizer_b.output == - RESIZER_OUTPUT_MEMORY) { - spin_lock(&video_out2->dma_queue_lock); - vpfe_video_process_buffer_complete(video_out2); - video_out2->state = VPFE_VIDEO_BUFFER_NOT_QUEUED; - vpfe_video_schedule_next_buffer(video_out2); - spin_unlock(&video_out2->dma_queue_lock); - } - - /* start HW if buffers are queued */ - if (vpfe_video_is_pipe_ready(pipe) && - resizer->resizer_a.output == RESIZER_OUTPUT_MEMORY) { - resizer_enable(resizer, 1); - vpfe_ipipe_enable(vpfe_dev, 1); - vpfe_ipipeif_enable(vpfe_dev); - } -} - -/* - * vpfe_resizer_buffer_isr() - resizer module buffer scheduling isr - * @resizer: vpfe resizer device pointer. - */ -void vpfe_resizer_buffer_isr(struct vpfe_resizer_device *resizer) -{ - struct vpfe_device *vpfe_dev = to_vpfe_device(resizer); - struct vpfe_video_device *video_out = &resizer->resizer_a.video_out; - struct vpfe_video_device *video_out2 = &resizer->resizer_b.video_out; - struct vpfe_pipeline *pipe = &resizer->resizer_a.video_out.pipe; - enum v4l2_field field; - int fid; - - if (!video_out->started) - return; - - if (resizer->crop_resizer.input == RESIZER_CROP_INPUT_NONE) - return; - - field = video_out->fmt.fmt.pix.field; - if (field == V4L2_FIELD_NONE) { - /* handle progressive frame capture */ - if (video_out->cur_frm != video_out->next_frm) { - vpfe_video_process_buffer_complete(video_out); - if (pipe->output_num > 1) - vpfe_video_process_buffer_complete(video_out2); - } - - video_out->skip_frame_count--; - if (!video_out->skip_frame_count) { - video_out->skip_frame_count = - video_out->skip_frame_count_init; - rsz_src_enable(resizer->base_addr, 1); - } else { - rsz_src_enable(resizer->base_addr, 0); - } - return; - } - - /* handle interlaced frame capture */ - fid = vpfe_isif_get_fid(vpfe_dev); - - /* switch the software maintained field id */ - video_out->field_id ^= 1; - if (fid == video_out->field_id) { - /* - * we are in-sync here,continue. - * One frame is just being captured. If the - * next frame is available, release the current - * frame and move on - */ - if (fid == 0 && video_out->cur_frm != video_out->next_frm) { - vpfe_video_process_buffer_complete(video_out); - if (pipe->output_num > 1) - vpfe_video_process_buffer_complete(video_out2); - } - } else if (fid == 0) { - /* - * out of sync. Recover from any hardware out-of-sync. - * May loose one frame - */ - video_out->field_id = fid; - } -} - -/* - * vpfe_resizer_dma_isr() - resizer module dma isr - * @resizer: vpfe resizer device pointer. - */ -void vpfe_resizer_dma_isr(struct vpfe_resizer_device *resizer) -{ - struct vpfe_video_device *video_out2 = &resizer->resizer_b.video_out; - struct vpfe_video_device *video_out = &resizer->resizer_a.video_out; - struct vpfe_device *vpfe_dev = to_vpfe_device(resizer); - struct vpfe_pipeline *pipe = &video_out->pipe; - int schedule_capture = 0; - enum v4l2_field field; - int fid; - - if (!video_out->started) - return; - - if (pipe->state == VPFE_PIPELINE_STREAM_SINGLESHOT) { - resizer_ss_isr(resizer); - return; - } - - field = video_out->fmt.fmt.pix.field; - if (field == V4L2_FIELD_NONE) { - if (!list_empty(&video_out->dma_queue) && - video_out->cur_frm == video_out->next_frm) - schedule_capture = 1; - } else { - fid = vpfe_isif_get_fid(vpfe_dev); - if (fid == video_out->field_id) { - /* we are in-sync here,continue */ - if (fid == 1 && !list_empty(&video_out->dma_queue) && - video_out->cur_frm == video_out->next_frm) - schedule_capture = 1; - } - } - - if (!schedule_capture) - return; - - spin_lock(&video_out->dma_queue_lock); - vpfe_video_schedule_next_buffer(video_out); - spin_unlock(&video_out->dma_queue_lock); - if (pipe->output_num > 1) { - spin_lock(&video_out2->dma_queue_lock); - vpfe_video_schedule_next_buffer(video_out2); - spin_unlock(&video_out2->dma_queue_lock); - } -} - -/* - * V4L2 subdev operations - */ - -/* - * resizer_ioctl() - Handle resizer module private ioctl's - * @sd: pointer to v4l2 subdev structure - * @cmd: configuration command - * @arg: configuration argument - */ -static long resizer_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) -{ - struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd); - struct device *dev = resizer->crop_resizer.subdev.v4l2_dev->dev; - struct vpfe_rsz_config *user_config; - int ret = -ENOIOCTLCMD; - - if (&resizer->crop_resizer.subdev != sd) - return ret; - - switch (cmd) { - case VIDIOC_VPFE_RSZ_S_CONFIG: - user_config = arg; - ret = resizer_set_configuration(resizer, user_config); - break; - - case VIDIOC_VPFE_RSZ_G_CONFIG: - user_config = arg; - if (!user_config->config) { - dev_err(dev, "error in VIDIOC_VPFE_RSZ_G_CONFIG\n"); - return -EINVAL; - } - ret = resizer_get_configuration(resizer, user_config); - break; - } - return ret; -} - -static int resizer_do_hw_setup(struct vpfe_resizer_device *resizer) -{ - struct vpfe_device *vpfe_dev = to_vpfe_device(resizer); - u16 ipipeif_sink = vpfe_dev->vpfe_ipipeif.input; - u16 ipipeif_source = vpfe_dev->vpfe_ipipeif.output; - struct resizer_params *param = &resizer->config; - int ret = 0; - - if (resizer->resizer_a.output == RESIZER_OUTPUT_MEMORY || - resizer->resizer_b.output == RESIZER_OUTPUT_MEMORY) { - if (ipipeif_sink == IPIPEIF_INPUT_MEMORY && - ipipeif_source == IPIPEIF_OUTPUT_RESIZER) - ret = resizer_configure_in_single_shot_mode(resizer); - else - ret = resizer_configure_in_continuous_mode(resizer); - if (ret) - return ret; - ret = config_rsz_hw(resizer, param); - } - return ret; -} - -/* - * resizer_set_stream() - Enable/Disable streaming on resizer subdev - * @sd: pointer to v4l2 subdev structure - * @enable: 1 == Enable, 0 == Disable - */ -static int resizer_set_stream(struct v4l2_subdev *sd, int enable) -{ - struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd); - - if (&resizer->crop_resizer.subdev != sd) - return 0; - - if (resizer->resizer_a.output != RESIZER_OUTPUT_MEMORY) - return 0; - - switch (enable) { - case 1: - if (resizer_do_hw_setup(resizer) < 0) - return -EINVAL; - resizer_enable(resizer, enable); - break; - - case 0: - resizer_enable(resizer, enable); - break; - } - - return 0; -} - -/* - * __resizer_get_format() - helper function for getting resizer format - * @sd: pointer to subdev. - * @cfg: V4L2 subdev pad config - * @pad: pad number. - * @which: wanted subdev format. - * Return wanted mbus frame format. - */ -static struct v4l2_mbus_framefmt * -__resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, - unsigned int pad, enum v4l2_subdev_format_whence which) -{ - struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd); - - if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(sd, cfg, pad); - if (&resizer->crop_resizer.subdev == sd) - return &resizer->crop_resizer.formats[pad]; - if (&resizer->resizer_a.subdev == sd) - return &resizer->resizer_a.formats[pad]; - if (&resizer->resizer_b.subdev == sd) - return &resizer->resizer_b.formats[pad]; - return NULL; -} - -/* - * resizer_try_format() - Handle try format by pad subdev method - * @sd: pointer to subdev. - * @cfg: V4L2 subdev pad config - * @pad: pad num. - * @fmt: pointer to v4l2 format structure. - * @which: wanted subdev format. - */ -static void -resizer_try_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, - unsigned int pad, struct v4l2_mbus_framefmt *fmt, - enum v4l2_subdev_format_whence which) -{ - struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd); - unsigned int max_out_height; - unsigned int max_out_width; - unsigned int i; - - if ((&resizer->resizer_a.subdev == sd && pad == RESIZER_PAD_SINK) || - (&resizer->resizer_b.subdev == sd && pad == RESIZER_PAD_SINK) || - (&resizer->crop_resizer.subdev == sd && - (pad == RESIZER_CROP_PAD_SOURCE || - pad == RESIZER_CROP_PAD_SOURCE2 || pad == RESIZER_CROP_PAD_SINK))) { - for (i = 0; i < ARRAY_SIZE(resizer_input_formats); i++) { - if (fmt->code == resizer_input_formats[i]) - break; - } - /* If not found, use UYVY as default */ - if (i >= ARRAY_SIZE(resizer_input_formats)) - fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; - - fmt->width = clamp_t(u32, fmt->width, MIN_IN_WIDTH, - MAX_IN_WIDTH); - fmt->height = clamp_t(u32, fmt->height, MIN_IN_HEIGHT, - MAX_IN_HEIGHT); - } else if (&resizer->resizer_a.subdev == sd && - pad == RESIZER_PAD_SOURCE) { - max_out_width = IPIPE_MAX_OUTPUT_WIDTH_A; - max_out_height = IPIPE_MAX_OUTPUT_HEIGHT_A; - - for (i = 0; i < ARRAY_SIZE(resizer_output_formats); i++) { - if (fmt->code == resizer_output_formats[i]) - break; - } - /* If not found, use UYVY as default */ - if (i >= ARRAY_SIZE(resizer_output_formats)) - fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; - - fmt->width = clamp_t(u32, fmt->width, MIN_OUT_WIDTH, - max_out_width); - fmt->width &= ~15; - fmt->height = clamp_t(u32, fmt->height, MIN_OUT_HEIGHT, - max_out_height); - } else if (&resizer->resizer_b.subdev == sd && - pad == RESIZER_PAD_SOURCE) { - max_out_width = IPIPE_MAX_OUTPUT_WIDTH_B; - max_out_height = IPIPE_MAX_OUTPUT_HEIGHT_B; - - for (i = 0; i < ARRAY_SIZE(resizer_output_formats); i++) { - if (fmt->code == resizer_output_formats[i]) - break; - } - /* If not found, use UYVY as default */ - if (i >= ARRAY_SIZE(resizer_output_formats)) - fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; - - fmt->width = clamp_t(u32, fmt->width, MIN_OUT_WIDTH, - max_out_width); - fmt->width &= ~15; - fmt->height = clamp_t(u32, fmt->height, MIN_OUT_HEIGHT, - max_out_height); - } -} - -/* - * resizer_set_format() - Handle set format by pads subdev method - * @sd: pointer to v4l2 subdev structure - * @cfg: V4L2 subdev pad config - * @fmt: pointer to v4l2 subdev format structure - * return -EINVAL or zero on success - */ -static int resizer_set_format(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *fmt) -{ - struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *format; - - format = __resizer_get_format(sd, cfg, fmt->pad, fmt->which); - if (format == NULL) - return -EINVAL; - - resizer_try_format(sd, cfg, fmt->pad, &fmt->format, fmt->which); - *format = fmt->format; - - if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) - return 0; - - if (&resizer->crop_resizer.subdev == sd) { - if (fmt->pad == RESIZER_CROP_PAD_SINK) { - resizer->crop_resizer.formats[fmt->pad] = fmt->format; - } else if (fmt->pad == RESIZER_CROP_PAD_SOURCE && - resizer->crop_resizer.output == RESIZER_A) { - resizer->crop_resizer.formats[fmt->pad] = fmt->format; - resizer->crop_resizer. - formats[RESIZER_CROP_PAD_SOURCE2] = fmt->format; - } else if (fmt->pad == RESIZER_CROP_PAD_SOURCE2 && - resizer->crop_resizer.output2 == RESIZER_B) { - resizer->crop_resizer.formats[fmt->pad] = fmt->format; - resizer->crop_resizer. - formats[RESIZER_CROP_PAD_SOURCE] = fmt->format; - } else { - return -EINVAL; - } - } else if (&resizer->resizer_a.subdev == sd) { - if (fmt->pad == RESIZER_PAD_SINK) - resizer->resizer_a.formats[fmt->pad] = fmt->format; - else if (fmt->pad == RESIZER_PAD_SOURCE) - resizer->resizer_a.formats[fmt->pad] = fmt->format; - else - return -EINVAL; - } else if (&resizer->resizer_b.subdev == sd) { - if (fmt->pad == RESIZER_PAD_SINK) - resizer->resizer_b.formats[fmt->pad] = fmt->format; - else if (fmt->pad == RESIZER_PAD_SOURCE) - resizer->resizer_b.formats[fmt->pad] = fmt->format; - else - return -EINVAL; - } else { - return -EINVAL; - } - - return 0; -} - -/* - * resizer_get_format() - Retrieve the video format on a pad - * @sd: pointer to v4l2 subdev structure. - * @cfg: V4L2 subdev pad config - * @fmt: pointer to v4l2 subdev format structure - * return -EINVAL or zero on success - */ -static int resizer_get_format(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *fmt) -{ - struct v4l2_mbus_framefmt *format; - - format = __resizer_get_format(sd, cfg, fmt->pad, fmt->which); - if (format == NULL) - return -EINVAL; - - fmt->format = *format; - - return 0; -} - -/* - * resizer_enum_frame_size() - enum frame sizes on pads - * @sd: Pointer to subdevice. - * @cfg: V4L2 subdev pad config - * @code: pointer to v4l2_subdev_frame_size_enum structure. - */ -static int resizer_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_frame_size_enum *fse) -{ - struct v4l2_mbus_framefmt format; - - if (fse->index != 0) - return -EINVAL; - - format.code = fse->code; - format.width = 1; - format.height = 1; - resizer_try_format(sd, cfg, fse->pad, &format, fse->which); - fse->min_width = format.width; - fse->min_height = format.height; - - if (format.code != fse->code) - return -EINVAL; - - format.code = fse->code; - format.width = -1; - format.height = -1; - resizer_try_format(sd, cfg, fse->pad, &format, fse->which); - fse->max_width = format.width; - fse->max_height = format.height; - - return 0; -} - -/* - * resizer_enum_mbus_code() - enum mbus codes for pads - * @sd: Pointer to subdevice. - * @cfg: V4L2 subdev pad config - * @code: pointer to v4l2_subdev_mbus_code_enum structure - */ -static int resizer_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) -{ - if (code->pad == RESIZER_PAD_SINK) { - if (code->index >= ARRAY_SIZE(resizer_input_formats)) - return -EINVAL; - - code->code = resizer_input_formats[code->index]; - } else if (code->pad == RESIZER_PAD_SOURCE) { - if (code->index >= ARRAY_SIZE(resizer_output_formats)) - return -EINVAL; - - code->code = resizer_output_formats[code->index]; - } - - return 0; -} - -/* - * resizer_init_formats() - Initialize formats on all pads - * @sd: Pointer to subdevice. - * @fh: V4L2 subdev file handle. - * - * Initialize all pad formats with default values. Try formats are - * initialized on the file handle. - */ -static int resizer_init_formats(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh) -{ - __u32 which = V4L2_SUBDEV_FORMAT_TRY; - struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd); - struct v4l2_subdev_format format; - - if (&resizer->crop_resizer.subdev == sd) { - memset(&format, 0, sizeof(format)); - format.pad = RESIZER_CROP_PAD_SINK; - format.which = which; - format.format.code = MEDIA_BUS_FMT_YUYV8_2X8; - format.format.width = MAX_IN_WIDTH; - format.format.height = MAX_IN_HEIGHT; - resizer_set_format(sd, fh->pad, &format); - - memset(&format, 0, sizeof(format)); - format.pad = RESIZER_CROP_PAD_SOURCE; - format.which = which; - format.format.code = MEDIA_BUS_FMT_UYVY8_2X8; - format.format.width = MAX_IN_WIDTH; - format.format.height = MAX_IN_WIDTH; - resizer_set_format(sd, fh->pad, &format); - - memset(&format, 0, sizeof(format)); - format.pad = RESIZER_CROP_PAD_SOURCE2; - format.which = which; - format.format.code = MEDIA_BUS_FMT_UYVY8_2X8; - format.format.width = MAX_IN_WIDTH; - format.format.height = MAX_IN_WIDTH; - resizer_set_format(sd, fh->pad, &format); - } else if (&resizer->resizer_a.subdev == sd) { - memset(&format, 0, sizeof(format)); - format.pad = RESIZER_PAD_SINK; - format.which = which; - format.format.code = MEDIA_BUS_FMT_YUYV8_2X8; - format.format.width = MAX_IN_WIDTH; - format.format.height = MAX_IN_HEIGHT; - resizer_set_format(sd, fh->pad, &format); - - memset(&format, 0, sizeof(format)); - format.pad = RESIZER_PAD_SOURCE; - format.which = which; - format.format.code = MEDIA_BUS_FMT_UYVY8_2X8; - format.format.width = IPIPE_MAX_OUTPUT_WIDTH_A; - format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_A; - resizer_set_format(sd, fh->pad, &format); - } else if (&resizer->resizer_b.subdev == sd) { - memset(&format, 0, sizeof(format)); - format.pad = RESIZER_PAD_SINK; - format.which = which; - format.format.code = MEDIA_BUS_FMT_YUYV8_2X8; - format.format.width = MAX_IN_WIDTH; - format.format.height = MAX_IN_HEIGHT; - resizer_set_format(sd, fh->pad, &format); - - memset(&format, 0, sizeof(format)); - format.pad = RESIZER_PAD_SOURCE; - format.which = which; - format.format.code = MEDIA_BUS_FMT_UYVY8_2X8; - format.format.width = IPIPE_MAX_OUTPUT_WIDTH_B; - format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_B; - resizer_set_format(sd, fh->pad, &format); - } - - return 0; -} - -/* subdev core operations */ -static const struct v4l2_subdev_core_ops resizer_v4l2_core_ops = { - .ioctl = resizer_ioctl, -}; - -/* subdev internal operations */ -static const struct v4l2_subdev_internal_ops resizer_v4l2_internal_ops = { - .open = resizer_init_formats, -}; - -/* subdev video operations */ -static const struct v4l2_subdev_video_ops resizer_v4l2_video_ops = { - .s_stream = resizer_set_stream, -}; - -/* subdev pad operations */ -static const struct v4l2_subdev_pad_ops resizer_v4l2_pad_ops = { - .enum_mbus_code = resizer_enum_mbus_code, - .enum_frame_size = resizer_enum_frame_size, - .get_fmt = resizer_get_format, - .set_fmt = resizer_set_format, -}; - -/* subdev operations */ -static const struct v4l2_subdev_ops resizer_v4l2_ops = { - .core = &resizer_v4l2_core_ops, - .video = &resizer_v4l2_video_ops, - .pad = &resizer_v4l2_pad_ops, -}; - -/* - * Media entity operations - */ - -/* - * resizer_link_setup() - Setup resizer connections - * @entity: Pointer to media entity structure - * @local: Pointer to local pad array - * @remote: Pointer to remote pad array - * @flags: Link flags - * return -EINVAL or zero on success - */ -static int resizer_link_setup(struct media_entity *entity, - const struct media_pad *local, - const struct media_pad *remote, u32 flags) -{ - struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); - struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd); - struct vpfe_device *vpfe_dev = to_vpfe_device(resizer); - u16 ipipeif_source = vpfe_dev->vpfe_ipipeif.output; - u16 ipipe_source = vpfe_dev->vpfe_ipipe.output; - unsigned int index = local->index; - - /* FIXME: this is actually a hack! */ - if (is_media_entity_v4l2_subdev(remote->entity)) - index |= 2 << 16; - - if (&resizer->crop_resizer.subdev == sd) { - switch (index) { - case RESIZER_CROP_PAD_SINK | 2 << 16: - if (!(flags & MEDIA_LNK_FL_ENABLED)) { - resizer->crop_resizer.input = - RESIZER_CROP_INPUT_NONE; - break; - } - - if (resizer->crop_resizer.input != - RESIZER_CROP_INPUT_NONE) - return -EBUSY; - if (ipipeif_source == IPIPEIF_OUTPUT_RESIZER) - resizer->crop_resizer.input = - RESIZER_CROP_INPUT_IPIPEIF; - else if (ipipe_source == IPIPE_OUTPUT_RESIZER) - resizer->crop_resizer.input = - RESIZER_CROP_INPUT_IPIPE; - else - return -EINVAL; - break; - - case RESIZER_CROP_PAD_SOURCE | 2 << 16: - if (!(flags & MEDIA_LNK_FL_ENABLED)) { - resizer->crop_resizer.output = - RESIZER_CROP_OUTPUT_NONE; - break; - } - if (resizer->crop_resizer.output != - RESIZER_CROP_OUTPUT_NONE) - return -EBUSY; - resizer->crop_resizer.output = RESIZER_A; - break; - - case RESIZER_CROP_PAD_SOURCE2 | 2 << 16: - if (!(flags & MEDIA_LNK_FL_ENABLED)) { - resizer->crop_resizer.output2 = - RESIZER_CROP_OUTPUT_NONE; - break; - } - if (resizer->crop_resizer.output2 != - RESIZER_CROP_OUTPUT_NONE) - return -EBUSY; - resizer->crop_resizer.output2 = RESIZER_B; - break; - - default: - return -EINVAL; - } - } else if (&resizer->resizer_a.subdev == sd) { - switch (index) { - case RESIZER_PAD_SINK | 2 << 16: - if (!(flags & MEDIA_LNK_FL_ENABLED)) { - resizer->resizer_a.input = RESIZER_INPUT_NONE; - break; - } - if (resizer->resizer_a.input != RESIZER_INPUT_NONE) - return -EBUSY; - resizer->resizer_a.input = RESIZER_INPUT_CROP_RESIZER; - break; - - case RESIZER_PAD_SOURCE: - if (!(flags & MEDIA_LNK_FL_ENABLED)) { - resizer->resizer_a.output = RESIZER_OUTPUT_NONE; - break; - } - if (resizer->resizer_a.output != RESIZER_OUTPUT_NONE) - return -EBUSY; - resizer->resizer_a.output = RESIZER_OUTPUT_MEMORY; - break; - - default: - return -EINVAL; - } - } else if (&resizer->resizer_b.subdev == sd) { - switch (index) { - case RESIZER_PAD_SINK | 2 << 16: - if (!(flags & MEDIA_LNK_FL_ENABLED)) { - resizer->resizer_b.input = RESIZER_INPUT_NONE; - break; - } - if (resizer->resizer_b.input != RESIZER_INPUT_NONE) - return -EBUSY; - resizer->resizer_b.input = RESIZER_INPUT_CROP_RESIZER; - break; - - case RESIZER_PAD_SOURCE: - if (!(flags & MEDIA_LNK_FL_ENABLED)) { - resizer->resizer_b.output = RESIZER_OUTPUT_NONE; - break; - } - if (resizer->resizer_b.output != RESIZER_OUTPUT_NONE) - return -EBUSY; - resizer->resizer_b.output = RESIZER_OUTPUT_MEMORY; - break; - - default: - return -EINVAL; - } - } else { - return -EINVAL; - } - - return 0; -} - -static const struct media_entity_operations resizer_media_ops = { - .link_setup = resizer_link_setup, -}; - -/* - * vpfe_resizer_unregister_entities() - Unregister entity - * @vpfe_rsz - pointer to resizer subdevice structure. - */ -void vpfe_resizer_unregister_entities(struct vpfe_resizer_device *vpfe_rsz) -{ - /* unregister video devices */ - vpfe_video_unregister(&vpfe_rsz->resizer_a.video_out); - vpfe_video_unregister(&vpfe_rsz->resizer_b.video_out); - - /* unregister subdev */ - v4l2_device_unregister_subdev(&vpfe_rsz->crop_resizer.subdev); - v4l2_device_unregister_subdev(&vpfe_rsz->resizer_a.subdev); - v4l2_device_unregister_subdev(&vpfe_rsz->resizer_b.subdev); - /* cleanup entity */ - media_entity_cleanup(&vpfe_rsz->crop_resizer.subdev.entity); - media_entity_cleanup(&vpfe_rsz->resizer_a.subdev.entity); - media_entity_cleanup(&vpfe_rsz->resizer_b.subdev.entity); -} - -/* - * vpfe_resizer_register_entities() - Register entity - * @resizer - pointer to resizer device. - * @vdev: pointer to v4l2 device structure. - */ -int vpfe_resizer_register_entities(struct vpfe_resizer_device *resizer, - struct v4l2_device *vdev) -{ - struct vpfe_device *vpfe_dev = to_vpfe_device(resizer); - unsigned int flags = 0; - int ret; - - /* Register the crop resizer subdev */ - ret = v4l2_device_register_subdev(vdev, &resizer->crop_resizer.subdev); - if (ret < 0) { - pr_err("Failed to register crop resizer as v4l2-subdev\n"); - return ret; - } - /* Register Resizer-A subdev */ - ret = v4l2_device_register_subdev(vdev, &resizer->resizer_a.subdev); - if (ret < 0) { - pr_err("Failed to register resizer-a as v4l2-subdev\n"); - return ret; - } - /* Register Resizer-B subdev */ - ret = v4l2_device_register_subdev(vdev, &resizer->resizer_b.subdev); - if (ret < 0) { - pr_err("Failed to register resizer-b as v4l2-subdev\n"); - return ret; - } - /* Register video-out device for resizer-a */ - ret = vpfe_video_register(&resizer->resizer_a.video_out, vdev); - if (ret) { - pr_err("Failed to register RSZ-A video-out device\n"); - goto out_video_out2_register; - } - resizer->resizer_a.video_out.vpfe_dev = vpfe_dev; - - /* Register video-out device for resizer-b */ - ret = vpfe_video_register(&resizer->resizer_b.video_out, vdev); - if (ret) { - pr_err("Failed to register RSZ-B video-out device\n"); - goto out_video_out2_register; - } - resizer->resizer_b.video_out.vpfe_dev = vpfe_dev; - - /* create link between Resizer Crop----> Resizer A*/ - ret = media_create_pad_link(&resizer->crop_resizer.subdev.entity, 1, - &resizer->resizer_a.subdev.entity, - 0, flags); - if (ret < 0) - goto out_create_link; - - /* create link between Resizer Crop----> Resizer B*/ - ret = media_create_pad_link(&resizer->crop_resizer.subdev.entity, 2, - &resizer->resizer_b.subdev.entity, - 0, flags); - if (ret < 0) - goto out_create_link; - - /* create link between Resizer A ----> video out */ - ret = media_create_pad_link(&resizer->resizer_a.subdev.entity, 1, - &resizer->resizer_a.video_out.video_dev.entity, 0, flags); - if (ret < 0) - goto out_create_link; - - /* create link between Resizer B ----> video out */ - ret = media_create_pad_link(&resizer->resizer_b.subdev.entity, 1, - &resizer->resizer_b.video_out.video_dev.entity, 0, flags); - if (ret < 0) - goto out_create_link; - - return 0; - -out_create_link: - vpfe_video_unregister(&resizer->resizer_b.video_out); -out_video_out2_register: - vpfe_video_unregister(&resizer->resizer_a.video_out); - v4l2_device_unregister_subdev(&resizer->crop_resizer.subdev); - v4l2_device_unregister_subdev(&resizer->resizer_a.subdev); - v4l2_device_unregister_subdev(&resizer->resizer_b.subdev); - media_entity_cleanup(&resizer->crop_resizer.subdev.entity); - media_entity_cleanup(&resizer->resizer_a.subdev.entity); - media_entity_cleanup(&resizer->resizer_b.subdev.entity); - return ret; -} - -/* - * vpfe_resizer_init() - resizer device initialization. - * @vpfe_rsz - pointer to resizer device - * @pdev: platform device pointer. - */ -int vpfe_resizer_init(struct vpfe_resizer_device *vpfe_rsz, - struct platform_device *pdev) -{ - struct v4l2_subdev *sd = &vpfe_rsz->crop_resizer.subdev; - struct media_pad *pads = &vpfe_rsz->crop_resizer.pads[0]; - struct media_entity *me = &sd->entity; - resource_size_t res_len; - struct resource *res; - int ret; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 5); - if (!res) - return -ENOENT; - - res_len = resource_size(res); - res = request_mem_region(res->start, res_len, res->name); - if (!res) - return -EBUSY; - - vpfe_rsz->base_addr = ioremap_nocache(res->start, res_len); - if (!vpfe_rsz->base_addr) - return -EBUSY; - - v4l2_subdev_init(sd, &resizer_v4l2_ops); - sd->internal_ops = &resizer_v4l2_internal_ops; - strscpy(sd->name, "DAVINCI RESIZER CROP", sizeof(sd->name)); - sd->grp_id = 1 << 16; /* group ID for davinci subdevs */ - v4l2_set_subdevdata(sd, vpfe_rsz); - sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - - pads[RESIZER_CROP_PAD_SINK].flags = MEDIA_PAD_FL_SINK; - pads[RESIZER_CROP_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; - pads[RESIZER_CROP_PAD_SOURCE2].flags = MEDIA_PAD_FL_SOURCE; - - vpfe_rsz->crop_resizer.input = RESIZER_CROP_INPUT_NONE; - vpfe_rsz->crop_resizer.output = RESIZER_CROP_OUTPUT_NONE; - vpfe_rsz->crop_resizer.output2 = RESIZER_CROP_OUTPUT_NONE; - vpfe_rsz->crop_resizer.rsz_device = vpfe_rsz; - me->ops = &resizer_media_ops; - ret = media_entity_pads_init(me, RESIZER_CROP_PADS_NUM, pads); - if (ret) - return ret; - - sd = &vpfe_rsz->resizer_a.subdev; - pads = &vpfe_rsz->resizer_a.pads[0]; - me = &sd->entity; - - v4l2_subdev_init(sd, &resizer_v4l2_ops); - sd->internal_ops = &resizer_v4l2_internal_ops; - strscpy(sd->name, "DAVINCI RESIZER A", sizeof(sd->name)); - sd->grp_id = 1 << 16; /* group ID for davinci subdevs */ - v4l2_set_subdevdata(sd, vpfe_rsz); - sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - - pads[RESIZER_PAD_SINK].flags = MEDIA_PAD_FL_SINK; - pads[RESIZER_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; - - vpfe_rsz->resizer_a.input = RESIZER_INPUT_NONE; - vpfe_rsz->resizer_a.output = RESIZER_OUTPUT_NONE; - vpfe_rsz->resizer_a.rsz_device = vpfe_rsz; - me->ops = &resizer_media_ops; - ret = media_entity_pads_init(me, RESIZER_PADS_NUM, pads); - if (ret) - return ret; - - sd = &vpfe_rsz->resizer_b.subdev; - pads = &vpfe_rsz->resizer_b.pads[0]; - me = &sd->entity; - - v4l2_subdev_init(sd, &resizer_v4l2_ops); - sd->internal_ops = &resizer_v4l2_internal_ops; - strscpy(sd->name, "DAVINCI RESIZER B", sizeof(sd->name)); - sd->grp_id = 1 << 16; /* group ID for davinci subdevs */ - v4l2_set_subdevdata(sd, vpfe_rsz); - sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - - pads[RESIZER_PAD_SINK].flags = MEDIA_PAD_FL_SINK; - pads[RESIZER_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; - - vpfe_rsz->resizer_b.input = RESIZER_INPUT_NONE; - vpfe_rsz->resizer_b.output = RESIZER_OUTPUT_NONE; - vpfe_rsz->resizer_b.rsz_device = vpfe_rsz; - me->ops = &resizer_media_ops; - ret = media_entity_pads_init(me, RESIZER_PADS_NUM, pads); - if (ret) - return ret; - - vpfe_rsz->resizer_a.video_out.ops = &resizer_a_video_ops; - vpfe_rsz->resizer_a.video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - ret = vpfe_video_init(&vpfe_rsz->resizer_a.video_out, "RSZ-A"); - if (ret) { - pr_err("Failed to init RSZ video-out device\n"); - return ret; - } - vpfe_rsz->resizer_b.video_out.ops = &resizer_b_video_ops; - vpfe_rsz->resizer_b.video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - ret = vpfe_video_init(&vpfe_rsz->resizer_b.video_out, "RSZ-B"); - if (ret) { - pr_err("Failed to init RSZ video-out2 device\n"); - return ret; - } - memset(&vpfe_rsz->config, 0, sizeof(struct resizer_params)); - - return 0; -} - -void -vpfe_resizer_cleanup(struct vpfe_resizer_device *vpfe_rsz, - struct platform_device *pdev) -{ - struct resource *res; - - iounmap(vpfe_rsz->base_addr); - res = platform_get_resource(pdev, IORESOURCE_MEM, 5); - if (res) - release_mem_region(res->start, - resource_size(res)); -} diff --git a/drivers/staging/media/davinci_vpfe/dm365_resizer.h b/drivers/staging/media/davinci_vpfe/dm365_resizer.h deleted file mode 100644 index 5e31de96b2c9..000000000000 --- a/drivers/staging/media/davinci_vpfe/dm365_resizer.h +++ /dev/null @@ -1,241 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2012 Texas Instruments Inc - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Contributors: - * Manjunath Hadli - * Prabhakar Lad - */ - -#ifndef _DAVINCI_VPFE_DM365_RESIZER_H -#define _DAVINCI_VPFE_DM365_RESIZER_H - -enum resizer_oper_mode { - RESIZER_MODE_CONTINUOUS = 0, - RESIZER_MODE_ONE_SHOT = 1, -}; - -struct f_div_pass { - unsigned int o_hsz; - unsigned int i_hps; - unsigned int h_phs; - unsigned int src_hps; - unsigned int src_hsz; -}; - -#define MAX_PASSES 2 - -struct f_div_param { - unsigned char en; - unsigned int num_passes; - struct f_div_pass pass[MAX_PASSES]; -}; - -/* Resizer Rescale Parameters*/ -struct resizer_scale_param { - bool h_flip; - bool v_flip; - bool cen; - bool yen; - unsigned short i_vps; - unsigned short i_hps; - unsigned short o_vsz; - unsigned short o_hsz; - unsigned short v_phs_y; - unsigned short v_phs_c; - unsigned short v_dif; - /* resize method - Luminance */ - enum vpfe_rsz_intp_t v_typ_y; - /* resize method - Chrominance */ - enum vpfe_rsz_intp_t v_typ_c; - /* vertical lpf intensity - Luminance */ - unsigned char v_lpf_int_y; - /* vertical lpf intensity - Chrominance */ - unsigned char v_lpf_int_c; - unsigned short h_phs; - unsigned short h_dif; - /* resize method - Luminance */ - enum vpfe_rsz_intp_t h_typ_y; - /* resize method - Chrominance */ - enum vpfe_rsz_intp_t h_typ_c; - /* horizontal lpf intensity - Luminance */ - unsigned char h_lpf_int_y; - /* horizontal lpf intensity - Chrominance */ - unsigned char h_lpf_int_c; - bool dscale_en; - enum vpfe_rsz_down_scale_ave_sz h_dscale_ave_sz; - enum vpfe_rsz_down_scale_ave_sz v_dscale_ave_sz; - /* store the calculated frame division parameter */ - struct f_div_param f_div; -}; - -enum resizer_rgb_t { - OUTPUT_32BIT, - OUTPUT_16BIT -}; - -enum resizer_rgb_msk_t { - NOMASK = 0, - MASKLAST2 = 1, -}; - -/* Resizer RGB Conversion Parameters */ -struct resizer_rgb { - bool rgb_en; - enum resizer_rgb_t rgb_typ; - enum resizer_rgb_msk_t rgb_msk0; - enum resizer_rgb_msk_t rgb_msk1; - unsigned int rgb_alpha_val; -}; - -/* Resizer External Memory Parameters */ -struct rsz_ext_mem_param { - unsigned int rsz_sdr_oft_y; - unsigned int rsz_sdr_ptr_s_y; - unsigned int rsz_sdr_ptr_e_y; - unsigned int rsz_sdr_oft_c; - unsigned int rsz_sdr_ptr_s_c; - unsigned int rsz_sdr_ptr_e_c; - /* offset to be added to buffer start when flipping for y/ycbcr */ - unsigned int flip_ofst_y; - /* offset to be added to buffer start when flipping for c */ - unsigned int flip_ofst_c; - /* c offset for YUV 420SP */ - unsigned int c_offset; - /* User Defined Y offset for YUV 420SP or YUV420ILE data */ - unsigned int user_y_ofst; - /* User Defined C offset for YUV 420SP data */ - unsigned int user_c_ofst; -}; - -enum rsz_data_source { - IPIPE_DATA, - IPIPEIF_DATA -}; - -enum rsz_src_img_fmt { - RSZ_IMG_422, - RSZ_IMG_420 -}; - -enum rsz_dpaths_bypass_t { - BYPASS_OFF = 0, - BYPASS_ON = 1, -}; - -struct rsz_common_params { - unsigned int vps; - unsigned int vsz; - unsigned int hps; - unsigned int hsz; - /* 420 or 422 */ - enum rsz_src_img_fmt src_img_fmt; - /* Y or C when src_fmt is 420, 0 - y, 1 - c */ - unsigned char y_c; - /* flip raw or ycbcr */ - unsigned char raw_flip; - /* IPIPE or IPIPEIF data */ - enum rsz_data_source source; - enum rsz_dpaths_bypass_t passthrough; - unsigned char yuv_y_min; - unsigned char yuv_y_max; - unsigned char yuv_c_min; - unsigned char yuv_c_max; - bool rsz_seq_crv; - enum vpfe_chr_pos out_chr_pos; -}; - -struct resizer_params { - enum resizer_oper_mode oper_mode; - struct rsz_common_params rsz_common; - struct resizer_scale_param rsz_rsc_param[2]; - struct resizer_rgb rsz2rgb[2]; - struct rsz_ext_mem_param ext_mem_param[2]; - bool rsz_en[2]; - struct vpfe_rsz_config_params user_config; -}; - -#define ENABLE 1 -#define DISABLE (!ENABLE) - -#define RESIZER_CROP_PAD_SINK 0 -#define RESIZER_CROP_PAD_SOURCE 1 -#define RESIZER_CROP_PAD_SOURCE2 2 - -#define RESIZER_CROP_PADS_NUM 3 - -enum resizer_crop_input_entity { - RESIZER_CROP_INPUT_NONE = 0, - RESIZER_CROP_INPUT_IPIPEIF = 1, - RESIZER_CROP_INPUT_IPIPE = 2, -}; - -enum resizer_crop_output_entity { - RESIZER_CROP_OUTPUT_NONE, - RESIZER_A, - RESIZER_B, -}; - -struct dm365_crop_resizer_device { - struct v4l2_subdev subdev; - struct media_pad pads[RESIZER_CROP_PADS_NUM]; - struct v4l2_mbus_framefmt formats[RESIZER_CROP_PADS_NUM]; - enum resizer_crop_input_entity input; - enum resizer_crop_output_entity output; - enum resizer_crop_output_entity output2; - struct vpfe_resizer_device *rsz_device; -}; - -#define RESIZER_PAD_SINK 0 -#define RESIZER_PAD_SOURCE 1 - -#define RESIZER_PADS_NUM 2 - -enum resizer_input_entity { - RESIZER_INPUT_NONE = 0, - RESIZER_INPUT_CROP_RESIZER = 1, -}; - -enum resizer_output_entity { - RESIZER_OUTPUT_NONE = 0, - RESIZER_OUTPUT_MEMORY = 1, -}; - -struct dm365_resizer_device { - struct v4l2_subdev subdev; - struct media_pad pads[RESIZER_PADS_NUM]; - struct v4l2_mbus_framefmt formats[RESIZER_PADS_NUM]; - enum resizer_input_entity input; - enum resizer_output_entity output; - struct vpfe_video_device video_out; - struct vpfe_resizer_device *rsz_device; -}; - -struct vpfe_resizer_device { - struct dm365_crop_resizer_device crop_resizer; - struct dm365_resizer_device resizer_a; - struct dm365_resizer_device resizer_b; - struct resizer_params config; - void __iomem *base_addr; -}; - -int vpfe_resizer_init(struct vpfe_resizer_device *vpfe_rsz, - struct platform_device *pdev); -int vpfe_resizer_register_entities(struct vpfe_resizer_device *vpfe_rsz, - struct v4l2_device *v4l2_dev); -void vpfe_resizer_unregister_entities(struct vpfe_resizer_device *vpfe_rsz); -void vpfe_resizer_cleanup(struct vpfe_resizer_device *vpfe_rsz, - struct platform_device *pdev); -void vpfe_resizer_buffer_isr(struct vpfe_resizer_device *resizer); -void vpfe_resizer_dma_isr(struct vpfe_resizer_device *resizer); - -#endif /* _DAVINCI_VPFE_DM365_RESIZER_H */ diff --git a/drivers/staging/media/davinci_vpfe/vpfe.h b/drivers/staging/media/davinci_vpfe/vpfe.h deleted file mode 100644 index 1f8e011fc162..000000000000 --- a/drivers/staging/media/davinci_vpfe/vpfe.h +++ /dev/null @@ -1,83 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2012 Texas Instruments Inc - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Contributors: - * Manjunath Hadli - * Prabhakar Lad - */ - -#ifndef _VPFE_H -#define _VPFE_H - -#ifdef __KERNEL__ -#include -#include -#include - -#include - -#define CAPTURE_DRV_NAME "vpfe-capture" - -struct vpfe_route { - __u32 input; - __u32 output; -}; - -enum vpfe_subdev_id { - VPFE_SUBDEV_TVP5146 = 1, - VPFE_SUBDEV_MT9T031 = 2, - VPFE_SUBDEV_TVP7002 = 3, - VPFE_SUBDEV_MT9P031 = 4, -}; - -struct vpfe_ext_subdev_info { - /* v4l2 subdev */ - struct v4l2_subdev *subdev; - /* Sub device module name */ - char module_name[32]; - /* Sub device group id */ - int grp_id; - /* Number of inputs supported */ - int num_inputs; - /* inputs available at the sub device */ - struct v4l2_input *inputs; - /* Sub dev routing information for each input */ - struct vpfe_route *routes; - /* ccdc bus/interface configuration */ - struct vpfe_hw_if_param ccdc_if_params; - /* i2c subdevice board info */ - struct i2c_board_info board_info; - /* Is this a camera sub device ? */ - unsigned is_camera:1; - /* check if sub dev supports routing */ - unsigned can_route:1; - /* registered ? */ - unsigned registered:1; -}; - -struct vpfe_config { - /* Number of sub devices connected to vpfe */ - int num_subdevs; - /* information about each subdev */ - struct vpfe_ext_subdev_info *sub_devs; - /* evm card info */ - char *card_name; - /* setup function for the input path */ - int (*setup_input)(enum vpfe_subdev_id id); - /* number of clocks */ - int num_clocks; - /* clocks used for vpfe capture */ - char *clocks[]; -}; -#endif -#endif diff --git a/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c b/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c deleted file mode 100644 index 9dc28ffe38d5..000000000000 --- a/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c +++ /dev/null @@ -1,716 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2012 Texas Instruments Inc - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Contributors: - * Manjunath Hadli - * Prabhakar Lad - * - * - * Driver name : VPFE Capture driver - * VPFE Capture driver allows applications to capture and stream video - * frames on DaVinci SoCs (DM6446, DM355 etc) from a YUV source such as - * TVP5146 or Raw Bayer RGB image data from an image sensor - * such as Microns' MT9T001, MT9T031 etc. - * - * These SoCs have, in common, a Video Processing Subsystem (VPSS) that - * consists of a Video Processing Front End (VPFE) for capturing - * video/raw image data and Video Processing Back End (VPBE) for displaying - * YUV data through an in-built analog encoder or Digital LCD port. This - * driver is for capture through VPFE. A typical EVM using these SoCs have - * following high level configuration. - * - * decoder(TVP5146/ YUV/ - * MT9T001) --> Raw Bayer RGB ---> MUX -> VPFE (CCDC/ISIF) - * data input | | - * V | - * SDRAM | - * V - * Image Processor - * | - * V - * SDRAM - * The data flow happens from a decoder connected to the VPFE over a - * YUV embedded (BT.656/BT.1120) or separate sync or raw bayer rgb interface - * and to the input of VPFE through an optional MUX (if more inputs are - * to be interfaced on the EVM). The input data is first passed through - * CCDC (CCD Controller, a.k.a Image Sensor Interface, ISIF). The CCDC - * does very little or no processing on YUV data and does pre-process Raw - * Bayer RGB data through modules such as Defect Pixel Correction (DFC) - * Color Space Conversion (CSC), data gain/offset etc. After this, data - * can be written to SDRAM or can be connected to the image processing - * block such as IPIPE (on DM355/DM365 only). - * - * Features supported - * - MMAP IO - * - USERPTR IO - * - Capture using TVP5146 over BT.656 - * - Support for interfacing decoders using sub device model - * - Work with DM365 or DM355 or DM6446 CCDC to do Raw Bayer - * RGB/YUV data capture to SDRAM. - * - Chaining of Image Processor - * - SINGLE-SHOT mode - */ - -#include -#include -#include - -#include "vpfe.h" -#include "vpfe_mc_capture.h" - -static bool debug; -static bool interface; - -module_param(interface, bool, 0444); -module_param(debug, bool, 0644); - -/* - * VPFE capture can be used for capturing video such as from TVP5146 or TVP7002 - * and for capture raw bayer data from camera sensors such as mt9p031. At this - * point there is problem in co-existence of mt9p031 and tvp5146 due to i2c - * address collision. So set the variable below from bootargs to do either video - * capture or camera capture. - * interface = 0 - video capture (from TVP514x or such), - * interface = 1 - Camera capture (from mt9p031 or such) - * Re-visit this when we fix the co-existence issue - */ -MODULE_PARM_DESC(interface, "interface 0-1 (default:0)"); -MODULE_PARM_DESC(debug, "Debug level 0-1"); - -MODULE_DESCRIPTION("VPFE Video for Linux Capture Driver"); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Texas Instruments"); - -/* map mbus_fmt to pixelformat */ -void mbus_to_pix(const struct v4l2_mbus_framefmt *mbus, - struct v4l2_pix_format *pix) -{ - switch (mbus->code) { - case MEDIA_BUS_FMT_UYVY8_2X8: - pix->pixelformat = V4L2_PIX_FMT_UYVY; - pix->bytesperline = pix->width * 2; - break; - - case MEDIA_BUS_FMT_YUYV8_2X8: - pix->pixelformat = V4L2_PIX_FMT_YUYV; - pix->bytesperline = pix->width * 2; - break; - - case MEDIA_BUS_FMT_YUYV10_1X20: - pix->pixelformat = V4L2_PIX_FMT_UYVY; - pix->bytesperline = pix->width * 2; - break; - - case MEDIA_BUS_FMT_SGRBG12_1X12: - pix->pixelformat = V4L2_PIX_FMT_SBGGR16; - pix->bytesperline = pix->width * 2; - break; - - case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8: - pix->pixelformat = V4L2_PIX_FMT_SGRBG10DPCM8; - pix->bytesperline = pix->width; - break; - - case MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8: - pix->pixelformat = V4L2_PIX_FMT_SGRBG10ALAW8; - pix->bytesperline = pix->width; - break; - - case MEDIA_BUS_FMT_YDYUYDYV8_1X16: - pix->pixelformat = V4L2_PIX_FMT_NV12; - pix->bytesperline = pix->width; - break; - - case MEDIA_BUS_FMT_Y8_1X8: - pix->pixelformat = V4L2_PIX_FMT_GREY; - pix->bytesperline = pix->width; - break; - - case MEDIA_BUS_FMT_UV8_1X8: - pix->pixelformat = V4L2_PIX_FMT_UV8; - pix->bytesperline = pix->width; - break; - - default: - pr_err("Invalid mbus code set\n"); - } - /* pitch should be 32 bytes aligned */ - pix->bytesperline = ALIGN(pix->bytesperline, 32); - if (pix->pixelformat == V4L2_PIX_FMT_NV12) - pix->sizeimage = pix->bytesperline * pix->height + - ((pix->bytesperline * pix->height) >> 1); - else - pix->sizeimage = pix->bytesperline * pix->height; -} - -/* ISR for VINT0*/ -static irqreturn_t vpfe_isr(int irq, void *dev_id) -{ - struct vpfe_device *vpfe_dev = dev_id; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "%s\n", __func__); - vpfe_isif_buffer_isr(&vpfe_dev->vpfe_isif); - vpfe_resizer_buffer_isr(&vpfe_dev->vpfe_resizer); - return IRQ_HANDLED; -} - -/* vpfe_vdint1_isr() - isr handler for VINT1 interrupt */ -static irqreturn_t vpfe_vdint1_isr(int irq, void *dev_id) -{ - struct vpfe_device *vpfe_dev = dev_id; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "%s\n", __func__); - vpfe_isif_vidint1_isr(&vpfe_dev->vpfe_isif); - return IRQ_HANDLED; -} - -/* vpfe_imp_dma_isr() - ISR for ipipe dma completion */ -static irqreturn_t vpfe_imp_dma_isr(int irq, void *dev_id) -{ - struct vpfe_device *vpfe_dev = dev_id; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "%s\n", __func__); - vpfe_ipipeif_ss_buffer_isr(&vpfe_dev->vpfe_ipipeif); - vpfe_resizer_dma_isr(&vpfe_dev->vpfe_resizer); - return IRQ_HANDLED; -} - -/* - * vpfe_disable_clock() - Disable clocks for vpfe capture driver - * @vpfe_dev - ptr to vpfe capture device - * - * Disables clocks defined in vpfe configuration. The function - * assumes that at least one clock is to be defined which is - * true as of now. - */ -static void vpfe_disable_clock(struct vpfe_device *vpfe_dev) -{ - struct vpfe_config *vpfe_cfg = vpfe_dev->cfg; - int i; - - for (i = 0; i < vpfe_cfg->num_clocks; i++) { - clk_disable_unprepare(vpfe_dev->clks[i]); - clk_put(vpfe_dev->clks[i]); - } - kzfree(vpfe_dev->clks); - v4l2_info(vpfe_dev->pdev->driver, "vpfe capture clocks disabled\n"); -} - -/* - * vpfe_enable_clock() - Enable clocks for vpfe capture driver - * @vpfe_dev - ptr to vpfe capture device - * - * Enables clocks defined in vpfe configuration. The function - * assumes that at least one clock is to be defined which is - * true as of now. - */ -static int vpfe_enable_clock(struct vpfe_device *vpfe_dev) -{ - struct vpfe_config *vpfe_cfg = vpfe_dev->cfg; - int ret = -EFAULT; - int i; - - if (!vpfe_cfg->num_clocks) - return 0; - - vpfe_dev->clks = kcalloc(vpfe_cfg->num_clocks, - sizeof(*vpfe_dev->clks), GFP_KERNEL); - if (!vpfe_dev->clks) - return -ENOMEM; - - for (i = 0; i < vpfe_cfg->num_clocks; i++) { - if (vpfe_cfg->clocks[i] == NULL) { - v4l2_err(vpfe_dev->pdev->driver, - "clock %s is not defined in vpfe config\n", - vpfe_cfg->clocks[i]); - goto out; - } - - vpfe_dev->clks[i] = - clk_get(vpfe_dev->pdev, vpfe_cfg->clocks[i]); - if (IS_ERR(vpfe_dev->clks[i])) { - v4l2_err(vpfe_dev->pdev->driver, - "Failed to get clock %s\n", - vpfe_cfg->clocks[i]); - goto out; - } - - if (clk_prepare_enable(vpfe_dev->clks[i])) { - v4l2_err(vpfe_dev->pdev->driver, - "vpfe clock %s not enabled\n", - vpfe_cfg->clocks[i]); - goto out; - } - - v4l2_info(vpfe_dev->pdev->driver, "vpss clock %s enabled", - vpfe_cfg->clocks[i]); - } - - return 0; -out: - for (i = 0; i < vpfe_cfg->num_clocks; i++) - if (!IS_ERR(vpfe_dev->clks[i])) { - clk_disable_unprepare(vpfe_dev->clks[i]); - clk_put(vpfe_dev->clks[i]); - } - - v4l2_err(vpfe_dev->pdev->driver, "Failed to enable clocks\n"); - kzfree(vpfe_dev->clks); - - return ret; -} - -/* - * vpfe_detach_irq() - Detach IRQs for vpfe capture driver - * @vpfe_dev - ptr to vpfe capture device - * - * Detach all IRQs defined in vpfe configuration. - */ -static void vpfe_detach_irq(struct vpfe_device *vpfe_dev) -{ - free_irq(vpfe_dev->ccdc_irq0, vpfe_dev); - free_irq(vpfe_dev->ccdc_irq1, vpfe_dev); - free_irq(vpfe_dev->imp_dma_irq, vpfe_dev); -} - -/* - * vpfe_attach_irq() - Attach IRQs for vpfe capture driver - * @vpfe_dev - ptr to vpfe capture device - * - * Attach all IRQs defined in vpfe configuration. - */ -static int vpfe_attach_irq(struct vpfe_device *vpfe_dev) -{ - int ret; - - ret = request_irq(vpfe_dev->ccdc_irq0, vpfe_isr, 0, - "vpfe_capture0", vpfe_dev); - if (ret < 0) { - v4l2_err(&vpfe_dev->v4l2_dev, - "Error: requesting VINT0 interrupt\n"); - return ret; - } - - ret = request_irq(vpfe_dev->ccdc_irq1, vpfe_vdint1_isr, 0, - "vpfe_capture1", vpfe_dev); - if (ret < 0) { - v4l2_err(&vpfe_dev->v4l2_dev, - "Error: requesting VINT1 interrupt\n"); - free_irq(vpfe_dev->ccdc_irq0, vpfe_dev); - return ret; - } - - ret = request_irq(vpfe_dev->imp_dma_irq, vpfe_imp_dma_isr, - 0, "Imp_Sdram_Irq", vpfe_dev); - if (ret < 0) { - v4l2_err(&vpfe_dev->v4l2_dev, - "Error: requesting IMP IRQ interrupt\n"); - free_irq(vpfe_dev->ccdc_irq1, vpfe_dev); - free_irq(vpfe_dev->ccdc_irq0, vpfe_dev); - return ret; - } - - return 0; -} - -/* - * register_i2c_devices() - register all i2c v4l2 subdevs - * @vpfe_dev - ptr to vpfe capture device - * - * register all i2c v4l2 subdevs - */ -static int register_i2c_devices(struct vpfe_device *vpfe_dev) -{ - struct vpfe_ext_subdev_info *sdinfo; - struct vpfe_config *vpfe_cfg; - struct i2c_adapter *i2c_adap; - unsigned int num_subdevs; - int ret; - int i; - int k; - - vpfe_cfg = vpfe_dev->cfg; - i2c_adap = i2c_get_adapter(1); - num_subdevs = vpfe_cfg->num_subdevs; - vpfe_dev->sd = - kcalloc(num_subdevs, sizeof(struct v4l2_subdev *), - GFP_KERNEL); - if (!vpfe_dev->sd) - return -ENOMEM; - - for (i = 0, k = 0; i < num_subdevs; i++) { - sdinfo = &vpfe_cfg->sub_devs[i]; - /* - * register subdevices based on interface setting. Currently - * tvp5146 and mt9p031 cannot co-exists due to i2c address - * conflicts. So only one of them is registered. Re-visit this - * once we have support for i2c switch handling in i2c driver - * framework - */ - if (interface == sdinfo->is_camera) { - /* setup input path */ - if (vpfe_cfg->setup_input && - vpfe_cfg->setup_input(sdinfo->grp_id) < 0) { - ret = -EFAULT; - v4l2_info(&vpfe_dev->v4l2_dev, - "could not setup input for %s\n", - sdinfo->module_name); - goto probe_sd_out; - } - /* Load up the subdevice */ - vpfe_dev->sd[k] = - v4l2_i2c_new_subdev_board(&vpfe_dev->v4l2_dev, - i2c_adap, &sdinfo->board_info, - NULL); - if (vpfe_dev->sd[k]) { - v4l2_info(&vpfe_dev->v4l2_dev, - "v4l2 sub device %s registered\n", - sdinfo->module_name); - - vpfe_dev->sd[k]->grp_id = sdinfo->grp_id; - k++; - - sdinfo->registered = 1; - } - } else { - v4l2_info(&vpfe_dev->v4l2_dev, - "v4l2 sub device %s is not registered\n", - sdinfo->module_name); - } - } - vpfe_dev->num_ext_subdevs = k; - - return 0; - -probe_sd_out: - kzfree(vpfe_dev->sd); - - return ret; -} - -/* - * vpfe_register_entities() - register all v4l2 subdevs and media entities - * @vpfe_dev - ptr to vpfe capture device - * - * register all v4l2 subdevs, media entities, and creates links - * between entities - */ -static int vpfe_register_entities(struct vpfe_device *vpfe_dev) -{ - unsigned int flags = 0; - int ret; - int i; - - /* register i2c devices first */ - ret = register_i2c_devices(vpfe_dev); - if (ret) - return ret; - - /* register rest of the sub-devs */ - ret = vpfe_isif_register_entities(&vpfe_dev->vpfe_isif, - &vpfe_dev->v4l2_dev); - if (ret) - return ret; - - ret = vpfe_ipipeif_register_entities(&vpfe_dev->vpfe_ipipeif, - &vpfe_dev->v4l2_dev); - if (ret) - goto out_isif_register; - - ret = vpfe_ipipe_register_entities(&vpfe_dev->vpfe_ipipe, - &vpfe_dev->v4l2_dev); - if (ret) - goto out_ipipeif_register; - - ret = vpfe_resizer_register_entities(&vpfe_dev->vpfe_resizer, - &vpfe_dev->v4l2_dev); - if (ret) - goto out_ipipe_register; - - /* create links now, starting with external(i2c) entities */ - for (i = 0; i < vpfe_dev->num_ext_subdevs; i++) - /* - * if entity has no pads (ex: amplifier), - * can't establish link - */ - if (vpfe_dev->sd[i]->entity.num_pads) { - ret = media_create_pad_link(&vpfe_dev->sd[i]->entity, - 0, &vpfe_dev->vpfe_isif.subdev.entity, - 0, flags); - if (ret < 0) - goto out_resizer_register; - } - - ret = media_create_pad_link(&vpfe_dev->vpfe_isif.subdev.entity, 1, - &vpfe_dev->vpfe_ipipeif.subdev.entity, - 0, flags); - if (ret < 0) - goto out_resizer_register; - - ret = media_create_pad_link(&vpfe_dev->vpfe_ipipeif.subdev.entity, 1, - &vpfe_dev->vpfe_ipipe.subdev.entity, - 0, flags); - if (ret < 0) - goto out_resizer_register; - - ret = media_create_pad_link(&vpfe_dev->vpfe_ipipe.subdev.entity, - 1, &vpfe_dev->vpfe_resizer.crop_resizer.subdev.entity, - 0, flags); - if (ret < 0) - goto out_resizer_register; - - ret = media_create_pad_link(&vpfe_dev->vpfe_ipipeif.subdev.entity, 1, - &vpfe_dev->vpfe_resizer.crop_resizer.subdev.entity, - 0, flags); - if (ret < 0) - goto out_resizer_register; - - ret = v4l2_device_register_subdev_nodes(&vpfe_dev->v4l2_dev); - if (ret < 0) - goto out_resizer_register; - - return 0; - -out_resizer_register: - vpfe_resizer_unregister_entities(&vpfe_dev->vpfe_resizer); -out_ipipe_register: - vpfe_ipipe_unregister_entities(&vpfe_dev->vpfe_ipipe); -out_ipipeif_register: - vpfe_ipipeif_unregister_entities(&vpfe_dev->vpfe_ipipeif); -out_isif_register: - vpfe_isif_unregister_entities(&vpfe_dev->vpfe_isif); - - return ret; -} - -/* - * vpfe_unregister_entities() - unregister all v4l2 subdevs and media entities - * @vpfe_dev - ptr to vpfe capture device - * - * unregister all v4l2 subdevs and media entities - */ -static void vpfe_unregister_entities(struct vpfe_device *vpfe_dev) -{ - vpfe_isif_unregister_entities(&vpfe_dev->vpfe_isif); - vpfe_ipipeif_unregister_entities(&vpfe_dev->vpfe_ipipeif); - vpfe_ipipe_unregister_entities(&vpfe_dev->vpfe_ipipe); - vpfe_resizer_unregister_entities(&vpfe_dev->vpfe_resizer); -} - -/* - * vpfe_cleanup_modules() - cleanup all non-i2c v4l2 subdevs - * @vpfe_dev - ptr to vpfe capture device - * @pdev - pointer to platform device - * - * cleanup all v4l2 subdevs - */ -static void vpfe_cleanup_modules(struct vpfe_device *vpfe_dev, - struct platform_device *pdev) -{ - vpfe_isif_cleanup(&vpfe_dev->vpfe_isif, pdev); - vpfe_ipipeif_cleanup(&vpfe_dev->vpfe_ipipeif, pdev); - vpfe_ipipe_cleanup(&vpfe_dev->vpfe_ipipe, pdev); - vpfe_resizer_cleanup(&vpfe_dev->vpfe_resizer, pdev); -} - -/* - * vpfe_initialize_modules() - initialize all non-i2c v4l2 subdevs - * @vpfe_dev - ptr to vpfe capture device - * @pdev - pointer to platform device - * - * initialize all v4l2 subdevs and media entities - */ -static int vpfe_initialize_modules(struct vpfe_device *vpfe_dev, - struct platform_device *pdev) -{ - int ret; - - ret = vpfe_isif_init(&vpfe_dev->vpfe_isif, pdev); - if (ret) - return ret; - - ret = vpfe_ipipeif_init(&vpfe_dev->vpfe_ipipeif, pdev); - if (ret) - goto out_isif_init; - - ret = vpfe_ipipe_init(&vpfe_dev->vpfe_ipipe, pdev); - if (ret) - goto out_ipipeif_init; - - ret = vpfe_resizer_init(&vpfe_dev->vpfe_resizer, pdev); - if (ret) - goto out_ipipe_init; - - return 0; - -out_ipipe_init: - vpfe_ipipe_cleanup(&vpfe_dev->vpfe_ipipe, pdev); -out_ipipeif_init: - vpfe_ipipeif_cleanup(&vpfe_dev->vpfe_ipipeif, pdev); -out_isif_init: - vpfe_isif_cleanup(&vpfe_dev->vpfe_isif, pdev); - - return ret; -} - -/* - * vpfe_probe() : vpfe probe function - * @pdev: platform device pointer - * - * This function creates device entries by register itself to the V4L2 driver - * and initializes fields of each device objects - */ -static int vpfe_probe(struct platform_device *pdev) -{ - struct vpfe_device *vpfe_dev; - struct resource *res1; - int ret = -ENOMEM; - - vpfe_dev = kzalloc(sizeof(*vpfe_dev), GFP_KERNEL); - if (!vpfe_dev) - return ret; - - if (pdev->dev.platform_data == NULL) { - v4l2_err(pdev->dev.driver, "Unable to get vpfe config\n"); - ret = -ENOENT; - goto probe_free_dev_mem; - } - - vpfe_dev->cfg = pdev->dev.platform_data; - if (vpfe_dev->cfg->card_name == NULL || - vpfe_dev->cfg->sub_devs == NULL) { - v4l2_err(pdev->dev.driver, "null ptr in vpfe_cfg\n"); - ret = -ENOENT; - goto probe_free_dev_mem; - } - - /* Get VINT0 irq resource */ - res1 = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res1) { - v4l2_err(pdev->dev.driver, - "Unable to get interrupt for VINT0\n"); - ret = -ENOENT; - goto probe_free_dev_mem; - } - vpfe_dev->ccdc_irq0 = res1->start; - - /* Get VINT1 irq resource */ - res1 = platform_get_resource(pdev, IORESOURCE_IRQ, 1); - if (!res1) { - v4l2_err(pdev->dev.driver, - "Unable to get interrupt for VINT1\n"); - ret = -ENOENT; - goto probe_free_dev_mem; - } - vpfe_dev->ccdc_irq1 = res1->start; - - /* Get DMA irq resource */ - res1 = platform_get_resource(pdev, IORESOURCE_IRQ, 2); - if (!res1) { - v4l2_err(pdev->dev.driver, - "Unable to get interrupt for DMA\n"); - ret = -ENOENT; - goto probe_free_dev_mem; - } - vpfe_dev->imp_dma_irq = res1->start; - - vpfe_dev->pdev = &pdev->dev; - - /* enable vpss clocks */ - ret = vpfe_enable_clock(vpfe_dev); - if (ret) - goto probe_free_dev_mem; - - ret = vpfe_initialize_modules(vpfe_dev, pdev); - if (ret) - goto probe_disable_clock; - - vpfe_dev->media_dev.dev = vpfe_dev->pdev; - strscpy((char *)&vpfe_dev->media_dev.model, "davinci-media", - sizeof(vpfe_dev->media_dev.model)); - - ret = media_device_register(&vpfe_dev->media_dev); - if (ret) { - v4l2_err(pdev->dev.driver, - "Unable to register media device.\n"); - goto probe_out_entities_cleanup; - } - - vpfe_dev->v4l2_dev.mdev = &vpfe_dev->media_dev; - ret = v4l2_device_register(&pdev->dev, &vpfe_dev->v4l2_dev); - if (ret) { - v4l2_err(pdev->dev.driver, "Unable to register v4l2 device.\n"); - goto probe_out_media_unregister; - } - - v4l2_info(&vpfe_dev->v4l2_dev, "v4l2 device registered\n"); - /* set the driver data in platform device */ - platform_set_drvdata(pdev, vpfe_dev); - /* register subdevs/entities */ - ret = vpfe_register_entities(vpfe_dev); - if (ret) - goto probe_out_v4l2_unregister; - - ret = vpfe_attach_irq(vpfe_dev); - if (ret) - goto probe_out_entities_unregister; - - return 0; - -probe_out_entities_unregister: - vpfe_unregister_entities(vpfe_dev); - kzfree(vpfe_dev->sd); -probe_out_v4l2_unregister: - v4l2_device_unregister(&vpfe_dev->v4l2_dev); -probe_out_media_unregister: - media_device_unregister(&vpfe_dev->media_dev); -probe_out_entities_cleanup: - vpfe_cleanup_modules(vpfe_dev, pdev); -probe_disable_clock: - vpfe_disable_clock(vpfe_dev); -probe_free_dev_mem: - kzfree(vpfe_dev); - - return ret; -} - -/* - * vpfe_remove : This function un-registers device from V4L2 driver - */ -static int vpfe_remove(struct platform_device *pdev) -{ - struct vpfe_device *vpfe_dev = platform_get_drvdata(pdev); - - v4l2_info(pdev->dev.driver, "%s\n", __func__); - - kzfree(vpfe_dev->sd); - vpfe_detach_irq(vpfe_dev); - vpfe_unregister_entities(vpfe_dev); - vpfe_cleanup_modules(vpfe_dev, pdev); - v4l2_device_unregister(&vpfe_dev->v4l2_dev); - media_device_unregister(&vpfe_dev->media_dev); - vpfe_disable_clock(vpfe_dev); - kzfree(vpfe_dev); - - return 0; -} - -static struct platform_driver vpfe_driver = { - .driver = { - .name = CAPTURE_DRV_NAME, - }, - .probe = vpfe_probe, - .remove = vpfe_remove, -}; - -module_platform_driver(vpfe_driver); diff --git a/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.h b/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.h deleted file mode 100644 index fe4a421b5dba..000000000000 --- a/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.h +++ /dev/null @@ -1,90 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2012 Texas Instruments Inc - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Contributors: - * Manjunath Hadli - * Prabhakar Lad - */ - -#ifndef _DAVINCI_VPFE_MC_CAPTURE_H -#define _DAVINCI_VPFE_MC_CAPTURE_H - -#include "dm365_ipipe.h" -#include "dm365_ipipeif.h" -#include "dm365_isif.h" -#include "dm365_resizer.h" -#include "vpfe_video.h" - -#define VPFE_MAJOR_RELEASE 0 -#define VPFE_MINOR_RELEASE 0 -#define VPFE_BUILD 1 -#define VPFE_CAPTURE_VERSION_CODE ((VPFE_MAJOR_RELEASE << 16) | \ - (VPFE_MINOR_RELEASE << 8) | \ - VPFE_BUILD) - -/* IPIPE hardware limits */ -#define IPIPE_MAX_OUTPUT_WIDTH_A 2176 -#define IPIPE_MAX_OUTPUT_WIDTH_B 640 - -/* Based on max resolution supported. QXGA */ -#define IPIPE_MAX_OUTPUT_HEIGHT_A 1536 -/* Based on max resolution supported. VGA */ -#define IPIPE_MAX_OUTPUT_HEIGHT_B 480 - -#define to_vpfe_device(ptr_module) \ - container_of(ptr_module, struct vpfe_device, vpfe_##ptr_module) -#define to_device(ptr_module) \ - (to_vpfe_device(ptr_module)->dev) - -struct vpfe_device { - /* external registered sub devices */ - struct v4l2_subdev **sd; - /* number of registered external subdevs */ - unsigned int num_ext_subdevs; - /* vpfe cfg */ - struct vpfe_config *cfg; - /* clock ptrs for vpfe capture */ - struct clk **clks; - /* V4l2 device */ - struct v4l2_device v4l2_dev; - /* parent device */ - struct device *pdev; - /* IRQ number for DMA transfer completion at the image processor */ - unsigned int imp_dma_irq; - /* CCDC IRQs used when CCDC/ISIF output to SDRAM */ - unsigned int ccdc_irq0; - unsigned int ccdc_irq1; - /* media device */ - struct media_device media_dev; - /* ccdc subdevice */ - struct vpfe_isif_device vpfe_isif; - /* ipipeif subdevice */ - struct vpfe_ipipeif_device vpfe_ipipeif; - /* ipipe subdevice */ - struct vpfe_ipipe_device vpfe_ipipe; - /* resizer subdevice */ - struct vpfe_resizer_device vpfe_resizer; -}; - -/* File handle structure */ -struct vpfe_fh { - struct v4l2_fh vfh; - struct vpfe_video_device *video; - /* Indicates whether this file handle is doing IO */ - u8 io_allowed; -}; - -void mbus_to_pix(const struct v4l2_mbus_framefmt *mbus, - struct v4l2_pix_format *pix); - -#endif /* _DAVINCI_VPFE_MC_CAPTURE_H */ diff --git a/drivers/staging/media/davinci_vpfe/vpfe_video.c b/drivers/staging/media/davinci_vpfe/vpfe_video.c deleted file mode 100644 index ab6bc452d9f6..000000000000 --- a/drivers/staging/media/davinci_vpfe/vpfe_video.c +++ /dev/null @@ -1,1646 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2012 Texas Instruments Inc - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Contributors: - * Manjunath Hadli - * Prabhakar Lad - */ - -#include -#include - -#include - -#include "vpfe.h" -#include "vpfe_mc_capture.h" - -static int debug; - -/* get v4l2 subdev pointer to external subdev which is active */ -static struct media_entity *vpfe_get_input_entity - (struct vpfe_video_device *video) -{ - struct vpfe_device *vpfe_dev = video->vpfe_dev; - struct media_pad *remote; - - remote = media_entity_remote_pad(&vpfe_dev->vpfe_isif.pads[0]); - if (!remote) { - pr_err("Invalid media connection to isif/ccdc\n"); - return NULL; - } - return remote->entity; -} - -/* updates external subdev(sensor/decoder) which is active */ -static int vpfe_update_current_ext_subdev(struct vpfe_video_device *video) -{ - struct vpfe_device *vpfe_dev = video->vpfe_dev; - struct vpfe_config *vpfe_cfg; - struct v4l2_subdev *subdev; - struct media_pad *remote; - int i; - - remote = media_entity_remote_pad(&vpfe_dev->vpfe_isif.pads[0]); - if (!remote) { - pr_err("Invalid media connection to isif/ccdc\n"); - return -EINVAL; - } - - subdev = media_entity_to_v4l2_subdev(remote->entity); - vpfe_cfg = vpfe_dev->pdev->platform_data; - for (i = 0; i < vpfe_cfg->num_subdevs; i++) { - if (!strcmp(vpfe_cfg->sub_devs[i].module_name, subdev->name)) { - video->current_ext_subdev = &vpfe_cfg->sub_devs[i]; - break; - } - } - - /* if user not linked decoder/sensor to isif/ccdc */ - if (i == vpfe_cfg->num_subdevs) { - pr_err("Invalid media chain connection to isif/ccdc\n"); - return -EINVAL; - } - /* find the v4l2 subdev pointer */ - for (i = 0; i < vpfe_dev->num_ext_subdevs; i++) { - if (!strcmp(video->current_ext_subdev->module_name, - vpfe_dev->sd[i]->name)) - video->current_ext_subdev->subdev = vpfe_dev->sd[i]; - } - return 0; -} - -/* get the subdev which is connected to the output video node */ -static struct v4l2_subdev * -vpfe_video_remote_subdev(struct vpfe_video_device *video, u32 *pad) -{ - struct media_pad *remote = media_entity_remote_pad(&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); -} - -/* get the format set at output pad of the adjacent subdev */ -static int -__vpfe_video_get_format(struct vpfe_video_device *video, - struct v4l2_format *format) -{ - struct v4l2_subdev_format fmt; - struct v4l2_subdev *subdev; - struct media_pad *remote; - u32 pad; - int ret; - - subdev = vpfe_video_remote_subdev(video, &pad); - if (!subdev) - return -EINVAL; - - fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; - remote = media_entity_remote_pad(&video->pad); - fmt.pad = remote->index; - - ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt); - if (ret == -ENOIOCTLCMD) - return -EINVAL; - - format->type = video->type; - /* convert mbus_format to v4l2_format */ - v4l2_fill_pix_format(&format->fmt.pix, &fmt.format); - mbus_to_pix(&fmt.format, &format->fmt.pix); - - return 0; -} - -/* make a note of pipeline details */ -static int vpfe_prepare_pipeline(struct vpfe_video_device *video) -{ - struct media_graph graph; - struct media_entity *entity = &video->video_dev.entity; - struct media_device *mdev = entity->graph_obj.mdev; - struct vpfe_pipeline *pipe = &video->pipe; - struct vpfe_video_device *far_end = NULL; - int ret; - - pipe->input_num = 0; - pipe->output_num = 0; - - if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) - pipe->inputs[pipe->input_num++] = video; - else - pipe->outputs[pipe->output_num++] = video; - - mutex_lock(&mdev->graph_mutex); - ret = media_graph_walk_init(&graph, mdev); - if (ret) { - mutex_unlock(&mdev->graph_mutex); - return -ENOMEM; - } - media_graph_walk_start(&graph, entity); - while ((entity = media_graph_walk_next(&graph))) { - if (entity == &video->video_dev.entity) - continue; - if (!is_media_entity_v4l2_video_device(entity)) - continue; - far_end = to_vpfe_video(media_entity_to_video_device(entity)); - if (far_end->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) - pipe->inputs[pipe->input_num++] = far_end; - else - pipe->outputs[pipe->output_num++] = far_end; - } - media_graph_walk_cleanup(&graph); - mutex_unlock(&mdev->graph_mutex); - - return 0; -} - -/* update pipe state selected by user */ -static int vpfe_update_pipe_state(struct vpfe_video_device *video) -{ - struct vpfe_pipeline *pipe = &video->pipe; - int ret; - - ret = vpfe_prepare_pipeline(video); - if (ret) - return ret; - - /* - * Find out if there is any input video - * if yes, it is single shot. - */ - if (pipe->input_num == 0) { - pipe->state = VPFE_PIPELINE_STREAM_CONTINUOUS; - ret = vpfe_update_current_ext_subdev(video); - if (ret) { - pr_err("Invalid external subdev\n"); - return ret; - } - } else { - pipe->state = VPFE_PIPELINE_STREAM_SINGLESHOT; - } - video->initialized = 1; - video->skip_frame_count = 1; - video->skip_frame_count_init = 1; - return 0; -} - -/* checks whether pipeline is ready for enabling */ -int vpfe_video_is_pipe_ready(struct vpfe_pipeline *pipe) -{ - int i; - - for (i = 0; i < pipe->input_num; i++) - if (!pipe->inputs[i]->started || - pipe->inputs[i]->state != VPFE_VIDEO_BUFFER_QUEUED) - return 0; - for (i = 0; i < pipe->output_num; i++) - if (!pipe->outputs[i]->started || - pipe->outputs[i]->state != VPFE_VIDEO_BUFFER_QUEUED) - return 0; - return 1; -} - -/* - * Validate a pipeline by checking both ends of all links for format - * discrepancies. - * - * Return 0 if all formats match, or -EPIPE if at least one link is found with - * different formats on its two ends. - */ -static int vpfe_video_validate_pipeline(struct vpfe_pipeline *pipe) -{ - struct v4l2_subdev_format fmt_source; - struct v4l2_subdev_format fmt_sink; - struct v4l2_subdev *subdev; - struct media_pad *pad; - int ret; - - /* - * Should not matter if it is output[0] or 1 as - * the general ideas is to traverse backwards and - * the fact that the out video node always has the - * format of the connected pad. - */ - subdev = vpfe_video_remote_subdev(pipe->outputs[0], NULL); - if (!subdev) - return -EPIPE; - - while (1) { - /* Retrieve the sink format */ - pad = &subdev->entity.pads[0]; - if (!(pad->flags & MEDIA_PAD_FL_SINK)) - break; - - fmt_sink.which = V4L2_SUBDEV_FORMAT_ACTIVE; - fmt_sink.pad = pad->index; - ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, - &fmt_sink); - - if (ret < 0 && ret != -ENOIOCTLCMD) - return -EPIPE; - - /* Retrieve the source format */ - pad = media_entity_remote_pad(pad); - if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) - break; - - subdev = media_entity_to_v4l2_subdev(pad->entity); - - fmt_source.which = V4L2_SUBDEV_FORMAT_ACTIVE; - fmt_source.pad = pad->index; - ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt_source); - if (ret < 0 && ret != -ENOIOCTLCMD) - return -EPIPE; - - /* Check if the two ends match */ - if (fmt_source.format.code != fmt_sink.format.code || - fmt_source.format.width != fmt_sink.format.width || - fmt_source.format.height != fmt_sink.format.height) - return -EPIPE; - } - return 0; -} - -/* - * vpfe_pipeline_enable() - Enable streaming on a pipeline - * @vpfe_dev: vpfe device - * @pipe: vpfe pipeline - * - * Walk the entities chain starting at the pipeline output video node and start - * all modules in the chain in the given mode. - * - * Return 0 if successful, or the return value of the failed video::s_stream - * operation otherwise. - */ -static int vpfe_pipeline_enable(struct vpfe_pipeline *pipe) -{ - struct media_entity *entity; - struct v4l2_subdev *subdev; - struct media_device *mdev; - int ret; - - if (pipe->state == VPFE_PIPELINE_STREAM_CONTINUOUS) - entity = vpfe_get_input_entity(pipe->outputs[0]); - else - entity = &pipe->inputs[0]->video_dev.entity; - - mdev = entity->graph_obj.mdev; - mutex_lock(&mdev->graph_mutex); - ret = media_graph_walk_init(&pipe->graph, mdev); - if (ret) - goto out; - media_graph_walk_start(&pipe->graph, entity); - while ((entity = media_graph_walk_next(&pipe->graph))) { - - if (!is_media_entity_v4l2_subdev(entity)) - continue; - subdev = media_entity_to_v4l2_subdev(entity); - ret = v4l2_subdev_call(subdev, video, s_stream, 1); - if (ret < 0 && ret != -ENOIOCTLCMD) - break; - } -out: - if (ret) - media_graph_walk_cleanup(&pipe->graph); - mutex_unlock(&mdev->graph_mutex); - return ret; -} - -/* - * vpfe_pipeline_disable() - Disable streaming on a pipeline - * @vpfe_dev: vpfe device - * @pipe: VPFE pipeline - * - * Walk the entities chain starting at the pipeline output video node and stop - * all modules in the chain. - * - * Return 0 if all modules have been properly stopped, or -ETIMEDOUT if a module - * can't be stopped. - */ -static int vpfe_pipeline_disable(struct vpfe_pipeline *pipe) -{ - struct media_entity *entity; - struct v4l2_subdev *subdev; - struct media_device *mdev; - int ret = 0; - - if (pipe->state == VPFE_PIPELINE_STREAM_CONTINUOUS) - entity = vpfe_get_input_entity(pipe->outputs[0]); - else - entity = &pipe->inputs[0]->video_dev.entity; - - mdev = entity->graph_obj.mdev; - mutex_lock(&mdev->graph_mutex); - media_graph_walk_start(&pipe->graph, entity); - - while ((entity = media_graph_walk_next(&pipe->graph))) { - - if (!is_media_entity_v4l2_subdev(entity)) - continue; - subdev = media_entity_to_v4l2_subdev(entity); - ret = v4l2_subdev_call(subdev, video, s_stream, 0); - if (ret < 0 && ret != -ENOIOCTLCMD) - break; - } - mutex_unlock(&mdev->graph_mutex); - - media_graph_walk_cleanup(&pipe->graph); - return ret ? -ETIMEDOUT : 0; -} - -/* - * vpfe_pipeline_set_stream() - Enable/disable streaming on a pipeline - * @vpfe_dev: VPFE device - * @pipe: VPFE pipeline - * @state: Stream state (stopped or active) - * - * Set the pipeline to the given stream state. - * - * Return 0 if successful, or the return value of the failed video::s_stream - * operation otherwise. - */ -static int vpfe_pipeline_set_stream(struct vpfe_pipeline *pipe, - enum vpfe_pipeline_stream_state state) -{ - if (state == VPFE_PIPELINE_STREAM_STOPPED) - return vpfe_pipeline_disable(pipe); - - return vpfe_pipeline_enable(pipe); -} - -static int all_videos_stopped(struct vpfe_video_device *video) -{ - struct vpfe_pipeline *pipe = &video->pipe; - int i; - - for (i = 0; i < pipe->input_num; i++) - if (pipe->inputs[i]->started) - return 0; - for (i = 0; i < pipe->output_num; i++) - if (pipe->outputs[i]->started) - return 0; - return 1; -} - -/* - * vpfe_open() - open video device - * @file: file pointer - * - * initialize media pipeline state, allocate memory for file handle - * - * Return 0 if successful, or the return -ENODEV otherwise. - */ -static int vpfe_open(struct file *file) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct vpfe_fh *handle; - - /* Allocate memory for the file handle object */ - handle = kzalloc(sizeof(struct vpfe_fh), GFP_KERNEL); - - if (!handle) - return -ENOMEM; - - v4l2_fh_init(&handle->vfh, &video->video_dev); - v4l2_fh_add(&handle->vfh); - - mutex_lock(&video->lock); - /* If decoder is not initialized. initialize it */ - if (!video->initialized && vpfe_update_pipe_state(video)) { - mutex_unlock(&video->lock); - v4l2_fh_del(&handle->vfh); - v4l2_fh_exit(&handle->vfh); - kfree(handle); - return -ENODEV; - } - /* Increment device users counter */ - video->usrs++; - /* Set io_allowed member to false */ - handle->io_allowed = 0; - handle->video = video; - file->private_data = &handle->vfh; - mutex_unlock(&video->lock); - - return 0; -} - -/* get the next buffer available from dma queue */ -static unsigned long -vpfe_video_get_next_buffer(struct vpfe_video_device *video) -{ - video->cur_frm = video->next_frm = - list_entry(video->dma_queue.next, - struct vpfe_cap_buffer, list); - - list_del(&video->next_frm->list); - video->next_frm->vb.vb2_buf.state = VB2_BUF_STATE_ACTIVE; - return vb2_dma_contig_plane_dma_addr(&video->next_frm->vb.vb2_buf, 0); -} - -/* schedule the next buffer which is available on dma queue */ -void vpfe_video_schedule_next_buffer(struct vpfe_video_device *video) -{ - struct vpfe_device *vpfe_dev = video->vpfe_dev; - unsigned long addr; - - if (list_empty(&video->dma_queue)) - return; - - video->next_frm = list_entry(video->dma_queue.next, - struct vpfe_cap_buffer, list); - - if (video->pipe.state == VPFE_PIPELINE_STREAM_SINGLESHOT) - video->cur_frm = video->next_frm; - - list_del(&video->next_frm->list); - video->next_frm->vb.vb2_buf.state = VB2_BUF_STATE_ACTIVE; - addr = vb2_dma_contig_plane_dma_addr(&video->next_frm->vb.vb2_buf, 0); - video->ops->queue(vpfe_dev, addr); - video->state = VPFE_VIDEO_BUFFER_QUEUED; -} - -/* schedule the buffer for capturing bottom field */ -void vpfe_video_schedule_bottom_field(struct vpfe_video_device *video) -{ - struct vpfe_device *vpfe_dev = video->vpfe_dev; - unsigned long addr; - - addr = vb2_dma_contig_plane_dma_addr(&video->cur_frm->vb.vb2_buf, 0); - addr += video->field_off; - video->ops->queue(vpfe_dev, addr); -} - -/* make buffer available for dequeue */ -void vpfe_video_process_buffer_complete(struct vpfe_video_device *video) -{ - struct vpfe_pipeline *pipe = &video->pipe; - - video->cur_frm->vb.vb2_buf.timestamp = ktime_get_ns(); - vb2_buffer_done(&video->cur_frm->vb.vb2_buf, VB2_BUF_STATE_DONE); - if (pipe->state == VPFE_PIPELINE_STREAM_CONTINUOUS) - video->cur_frm = video->next_frm; -} - -/* vpfe_stop_capture() - stop streaming */ -static void vpfe_stop_capture(struct vpfe_video_device *video) -{ - struct vpfe_pipeline *pipe = &video->pipe; - - video->started = 0; - - if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) - return; - if (all_videos_stopped(video)) - vpfe_pipeline_set_stream(pipe, - VPFE_PIPELINE_STREAM_STOPPED); -} - -/* - * vpfe_release() - release video device - * @file: file pointer - * - * deletes buffer queue, frees the buffers and the vpfe file handle - * - * Return 0 - */ -static int vpfe_release(struct file *file) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct v4l2_fh *vfh = file->private_data; - struct vpfe_device *vpfe_dev = video->vpfe_dev; - struct vpfe_fh *fh = container_of(vfh, struct vpfe_fh, vfh); - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_release\n"); - - /* Get the device lock */ - mutex_lock(&video->lock); - /* if this instance is doing IO */ - if (fh->io_allowed) { - if (video->started) { - vpfe_stop_capture(video); - /* - * mark pipe state as stopped in vpfe_release(), - * as app might call streamon() after streamoff() - * in which case driver has to start streaming. - */ - video->pipe.state = VPFE_PIPELINE_STREAM_STOPPED; - vb2_streamoff(&video->buffer_queue, - video->buffer_queue.type); - } - video->io_usrs = 0; - /* Free buffers allocated */ - vb2_queue_release(&video->buffer_queue); - } - /* Decrement device users counter */ - video->usrs--; - v4l2_fh_del(&fh->vfh); - v4l2_fh_exit(&fh->vfh); - /* If this is the last file handle */ - if (!video->usrs) - video->initialized = 0; - mutex_unlock(&video->lock); - file->private_data = NULL; - /* Free memory allocated to file handle object */ - v4l2_fh_del(vfh); - kzfree(fh); - return 0; -} - -/* - * vpfe_mmap() - It is used to map kernel space buffers - * into user spaces - */ -static int vpfe_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct vpfe_device *vpfe_dev = video->vpfe_dev; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_mmap\n"); - return vb2_mmap(&video->buffer_queue, vma); -} - -/* - * vpfe_poll() - It is used for select/poll system call - */ -static __poll_t vpfe_poll(struct file *file, poll_table *wait) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct vpfe_device *vpfe_dev = video->vpfe_dev; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_poll\n"); - if (video->started) - return vb2_poll(&video->buffer_queue, file, wait); - return 0; -} - -/* vpfe capture driver file operations */ -static const struct v4l2_file_operations vpfe_fops = { - .owner = THIS_MODULE, - .open = vpfe_open, - .release = vpfe_release, - .unlocked_ioctl = video_ioctl2, - .mmap = vpfe_mmap, - .poll = vpfe_poll -}; - -/* - * vpfe_querycap() - query capabilities of video device - * @file: file pointer - * @priv: void pointer - * @cap: pointer to v4l2_capability structure - * - * fills v4l2 capabilities structure - * - * Return 0 - */ -static int vpfe_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct vpfe_device *vpfe_dev = video->vpfe_dev; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querycap\n"); - - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT | - V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS; - strscpy(cap->driver, CAPTURE_DRV_NAME, sizeof(cap->driver)); - strscpy(cap->bus_info, "VPFE", sizeof(cap->bus_info)); - strscpy(cap->card, vpfe_dev->cfg->card_name, sizeof(cap->card)); - - return 0; -} - -/* - * vpfe_g_fmt() - get the format which is active on video device - * @file: file pointer - * @priv: void pointer - * @fmt: pointer to v4l2_format structure - * - * fills v4l2 format structure with active format - * - * Return 0 - */ -static int vpfe_g_fmt(struct file *file, void *priv, - struct v4l2_format *fmt) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct vpfe_device *vpfe_dev = video->vpfe_dev; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_fmt\n"); - /* Fill in the information about format */ - *fmt = video->fmt; - return 0; -} - -/* - * vpfe_enum_fmt() - enum formats supported on media chain - * @file: file pointer - * @priv: void pointer - * @fmt: pointer to v4l2_fmtdesc structure - * - * fills v4l2_fmtdesc structure with output format set on adjacent subdev, - * only one format is enumearted as subdevs are already configured - * - * Return 0 if successful, error code otherwise - */ -static int vpfe_enum_fmt(struct file *file, void *priv, - struct v4l2_fmtdesc *fmt) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct vpfe_device *vpfe_dev = video->vpfe_dev; - struct v4l2_subdev_format sd_fmt; - struct v4l2_mbus_framefmt mbus; - struct v4l2_subdev *subdev; - struct v4l2_format format; - struct media_pad *remote; - int ret; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_fmt\n"); - - /* - * since already subdev pad format is set, - * only one pixel format is available - */ - if (fmt->index > 0) { - v4l2_err(&vpfe_dev->v4l2_dev, "Invalid index\n"); - return -EINVAL; - } - /* get the remote pad */ - remote = media_entity_remote_pad(&video->pad); - if (!remote) { - v4l2_err(&vpfe_dev->v4l2_dev, - "invalid remote pad for video node\n"); - return -EINVAL; - } - /* get the remote subdev */ - subdev = vpfe_video_remote_subdev(video, NULL); - if (!subdev) { - v4l2_err(&vpfe_dev->v4l2_dev, - "invalid remote subdev for video node\n"); - return -EINVAL; - } - sd_fmt.pad = remote->index; - sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; - /* get output format of remote subdev */ - ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &sd_fmt); - if (ret) { - v4l2_err(&vpfe_dev->v4l2_dev, - "invalid remote subdev for video node\n"); - return ret; - } - /* convert to pix format */ - mbus.code = sd_fmt.format.code; - mbus_to_pix(&mbus, &format.fmt.pix); - /* copy the result */ - fmt->pixelformat = format.fmt.pix.pixelformat; - - return 0; -} - -/* - * vpfe_s_fmt() - set the format on video device - * @file: file pointer - * @priv: void pointer - * @fmt: pointer to v4l2_format structure - * - * validate and set the format on video device - * - * Return 0 on success, error code otherwise - */ -static int vpfe_s_fmt(struct file *file, void *priv, - struct v4l2_format *fmt) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct vpfe_device *vpfe_dev = video->vpfe_dev; - struct v4l2_format format; - int ret; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_fmt\n"); - /* If streaming is started, return error */ - if (video->started) { - v4l2_err(&vpfe_dev->v4l2_dev, "Streaming is started\n"); - return -EBUSY; - } - /* get adjacent subdev's output pad format */ - ret = __vpfe_video_get_format(video, &format); - if (ret) - return ret; - *fmt = format; - video->fmt = *fmt; - return 0; -} - -/* - * vpfe_try_fmt() - try the format on video device - * @file: file pointer - * @priv: void pointer - * @fmt: pointer to v4l2_format structure - * - * validate the format, update with correct format - * based on output format set on adjacent subdev - * - * Return 0 on success, error code otherwise - */ -static int vpfe_try_fmt(struct file *file, void *priv, - struct v4l2_format *fmt) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct vpfe_device *vpfe_dev = video->vpfe_dev; - struct v4l2_format format; - int ret; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_try_fmt\n"); - /* get adjacent subdev's output pad format */ - ret = __vpfe_video_get_format(video, &format); - if (ret) - return ret; - - *fmt = format; - return 0; -} - -/* - * vpfe_enum_input() - enum inputs supported on media chain - * @file: file pointer - * @priv: void pointer - * @fmt: pointer to v4l2_fmtdesc structure - * - * fills v4l2_input structure with input available on media chain, - * only one input is enumearted as media chain is setup by this time - * - * Return 0 if successful, -EINVAL is media chain is invalid - */ -static int vpfe_enum_input(struct file *file, void *priv, - struct v4l2_input *inp) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct vpfe_ext_subdev_info *sdinfo = video->current_ext_subdev; - struct vpfe_device *vpfe_dev = video->vpfe_dev; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_input\n"); - /* enumerate from the subdev user has chosen through mc */ - if (inp->index < sdinfo->num_inputs) { - memcpy(inp, &sdinfo->inputs[inp->index], - sizeof(struct v4l2_input)); - return 0; - } - return -EINVAL; -} - -/* - * vpfe_g_input() - get index of the input which is active - * @file: file pointer - * @priv: void pointer - * @index: pointer to unsigned int - * - * set index with input index which is active - */ -static int vpfe_g_input(struct file *file, void *priv, unsigned int *index) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct vpfe_device *vpfe_dev = video->vpfe_dev; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_input\n"); - - *index = video->current_input; - return 0; -} - -/* - * vpfe_s_input() - set input which is pointed by input index - * @file: file pointer - * @priv: void pointer - * @index: pointer to unsigned int - * - * set input on external subdev - * - * Return 0 on success, error code otherwise - */ -static int vpfe_s_input(struct file *file, void *priv, unsigned int index) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct vpfe_device *vpfe_dev = video->vpfe_dev; - struct vpfe_ext_subdev_info *sdinfo; - struct vpfe_route *route; - struct v4l2_input *inps; - u32 output; - u32 input; - int ret; - int i; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_input\n"); - - ret = mutex_lock_interruptible(&video->lock); - if (ret) - return ret; - /* - * If streaming is started return device busy - * error - */ - if (video->started) { - v4l2_err(&vpfe_dev->v4l2_dev, "Streaming is on\n"); - ret = -EBUSY; - goto unlock_out; - } - - sdinfo = video->current_ext_subdev; - if (!sdinfo->registered) { - ret = -EINVAL; - goto unlock_out; - } - if (vpfe_dev->cfg->setup_input && - vpfe_dev->cfg->setup_input(sdinfo->grp_id) < 0) { - ret = -EFAULT; - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, - "couldn't setup input for %s\n", - sdinfo->module_name); - goto unlock_out; - } - route = &sdinfo->routes[index]; - if (route && sdinfo->can_route) { - input = route->input; - output = route->output; - ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, - sdinfo->grp_id, video, - s_routing, input, output, 0); - if (ret) { - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, - "s_input:error in setting input in decoder\n"); - ret = -EINVAL; - goto unlock_out; - } - } - /* set standards set by subdev in video device */ - for (i = 0; i < sdinfo->num_inputs; i++) { - inps = &sdinfo->inputs[i]; - video->video_dev.tvnorms |= inps->std; - } - video->current_input = index; -unlock_out: - mutex_unlock(&video->lock); - return ret; -} - -/* - * vpfe_querystd() - query std which is being input on external subdev - * @file: file pointer - * @priv: void pointer - * @std_id: pointer to v4l2_std_id structure - * - * call external subdev through v4l2_device_call_until_err to - * get the std that is being active. - * - * Return 0 on success, error code otherwise - */ -static int vpfe_querystd(struct file *file, void *priv, v4l2_std_id *std_id) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct vpfe_device *vpfe_dev = video->vpfe_dev; - struct vpfe_ext_subdev_info *sdinfo; - int ret; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querystd\n"); - - ret = mutex_lock_interruptible(&video->lock); - sdinfo = video->current_ext_subdev; - if (ret) - return ret; - /* Call querystd function of decoder device */ - ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, - video, querystd, std_id); - mutex_unlock(&video->lock); - return ret; -} - -/* - * vpfe_s_std() - set std on external subdev - * @file: file pointer - * @priv: void pointer - * @std_id: pointer to v4l2_std_id structure - * - * set std pointed by std_id on external subdev by calling it using - * v4l2_device_call_until_err - * - * Return 0 on success, error code otherwise - */ -static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id std_id) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct vpfe_device *vpfe_dev = video->vpfe_dev; - struct vpfe_ext_subdev_info *sdinfo; - int ret; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_std\n"); - - /* Call decoder driver function to set the standard */ - ret = mutex_lock_interruptible(&video->lock); - if (ret) - return ret; - sdinfo = video->current_ext_subdev; - /* If streaming is started, return device busy error */ - if (video->started) { - v4l2_err(&vpfe_dev->v4l2_dev, "streaming is started\n"); - ret = -EBUSY; - goto unlock_out; - } - ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, - video, s_std, std_id); - if (ret < 0) { - v4l2_err(&vpfe_dev->v4l2_dev, "Failed to set standard\n"); - video->stdid = V4L2_STD_UNKNOWN; - goto unlock_out; - } - video->stdid = std_id; -unlock_out: - mutex_unlock(&video->lock); - return ret; -} - -static int vpfe_g_std(struct file *file, void *priv, v4l2_std_id *tvnorm) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct vpfe_device *vpfe_dev = video->vpfe_dev; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_std\n"); - *tvnorm = video->stdid; - return 0; -} - -/* - * vpfe_enum_dv_timings() - enumerate dv_timings which are supported by - * to external subdev - * @file: file pointer - * @priv: void pointer - * @timings: pointer to v4l2_enum_dv_timings structure - * - * enum dv_timings's which are supported by external subdev through - * v4l2_subdev_call - * - * Return 0 on success, error code otherwise - */ -static int -vpfe_enum_dv_timings(struct file *file, void *fh, - struct v4l2_enum_dv_timings *timings) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct vpfe_device *vpfe_dev = video->vpfe_dev; - struct v4l2_subdev *subdev = video->current_ext_subdev->subdev; - - timings->pad = 0; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_dv_timings\n"); - return v4l2_subdev_call(subdev, pad, enum_dv_timings, timings); -} - -/* - * vpfe_query_dv_timings() - query the dv_timings which is being input - * to external subdev - * @file: file pointer - * @priv: void pointer - * @timings: pointer to v4l2_dv_timings structure - * - * get dv_timings which is being input on external subdev through - * v4l2_subdev_call - * - * Return 0 on success, error code otherwise - */ -static int -vpfe_query_dv_timings(struct file *file, void *fh, - struct v4l2_dv_timings *timings) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct vpfe_device *vpfe_dev = video->vpfe_dev; - struct v4l2_subdev *subdev = video->current_ext_subdev->subdev; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_query_dv_timings\n"); - return v4l2_subdev_call(subdev, video, query_dv_timings, timings); -} - -/* - * vpfe_s_dv_timings() - set dv_timings on external subdev - * @file: file pointer - * @priv: void pointer - * @timings: pointer to v4l2_dv_timings structure - * - * set dv_timings pointed by timings on external subdev through - * v4l2_device_call_until_err, this configures amplifier also - * - * Return 0 on success, error code otherwise - */ -static int -vpfe_s_dv_timings(struct file *file, void *fh, - struct v4l2_dv_timings *timings) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct vpfe_device *vpfe_dev = video->vpfe_dev; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_dv_timings\n"); - - video->stdid = V4L2_STD_UNKNOWN; - return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, - video->current_ext_subdev->grp_id, - video, s_dv_timings, timings); -} - -/* - * vpfe_g_dv_timings() - get dv_timings which is set on external subdev - * @file: file pointer - * @priv: void pointer - * @timings: pointer to v4l2_dv_timings structure - * - * get dv_timings which is set on external subdev through - * v4l2_subdev_call - * - * Return 0 on success, error code otherwise - */ -static int -vpfe_g_dv_timings(struct file *file, void *fh, - struct v4l2_dv_timings *timings) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct vpfe_device *vpfe_dev = video->vpfe_dev; - struct v4l2_subdev *subdev = video->current_ext_subdev->subdev; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_dv_timings\n"); - return v4l2_subdev_call(subdev, video, g_dv_timings, timings); -} - -/* - * Videobuf operations - */ -/* - * vpfe_buffer_queue_setup : Callback function for buffer setup. - * @vq: vb2_queue ptr - * @fmt: v4l2 format - * @nbuffers: ptr to number of buffers requested by application - * @nplanes:: contains number of distinct video planes needed to hold a frame - * @sizes[]: contains the size (in bytes) of each plane. - * @alloc_devs: ptr to allocation context - * - * This callback function is called when reqbuf() is called to adjust - * the buffer nbuffers and buffer size - */ -static int -vpfe_buffer_queue_setup(struct vb2_queue *vq, - unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], struct device *alloc_devs[]) -{ - struct vpfe_fh *fh = vb2_get_drv_priv(vq); - struct vpfe_video_device *video = fh->video; - struct vpfe_device *vpfe_dev = video->vpfe_dev; - unsigned long size; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_queue_setup\n"); - size = video->fmt.fmt.pix.sizeimage; - - if (vq->num_buffers + *nbuffers < 3) - *nbuffers = 3 - vq->num_buffers; - - *nplanes = 1; - sizes[0] = size; - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, - "nbuffers=%d, size=%lu\n", *nbuffers, size); - return 0; -} - -/* - * vpfe_buffer_prepare : callback function for buffer prepare - * @vb: ptr to vb2_buffer - * - * This is the callback function for buffer prepare when vb2_qbuf() - * function is called. The buffer is prepared and user space virtual address - * or user address is converted into physical address - */ -static int vpfe_buffer_prepare(struct vb2_buffer *vb) -{ - struct vpfe_fh *fh = vb2_get_drv_priv(vb->vb2_queue); - struct vpfe_video_device *video = fh->video; - struct vpfe_device *vpfe_dev = video->vpfe_dev; - unsigned long addr; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_prepare\n"); - - /* Initialize buffer */ - vb2_set_plane_payload(vb, 0, video->fmt.fmt.pix.sizeimage); - if (vb2_plane_vaddr(vb, 0) && - vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) - return -EINVAL; - - addr = vb2_dma_contig_plane_dma_addr(vb, 0); - /* Make sure user addresses are aligned to 32 bytes */ - if (!ALIGN(addr, 32)) - return -EINVAL; - - return 0; -} - -static void vpfe_buffer_queue(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - /* Get the file handle object and device object */ - struct vpfe_fh *fh = vb2_get_drv_priv(vb->vb2_queue); - struct vpfe_video_device *video = fh->video; - struct vpfe_device *vpfe_dev = video->vpfe_dev; - struct vpfe_pipeline *pipe = &video->pipe; - struct vpfe_cap_buffer *buf = container_of(vbuf, - struct vpfe_cap_buffer, vb); - unsigned long flags; - unsigned long empty; - unsigned long addr; - - spin_lock_irqsave(&video->dma_queue_lock, flags); - empty = list_empty(&video->dma_queue); - /* add the buffer to the DMA queue */ - list_add_tail(&buf->list, &video->dma_queue); - spin_unlock_irqrestore(&video->dma_queue_lock, flags); - /* this case happens in case of single shot */ - if (empty && video->started && pipe->state == - VPFE_PIPELINE_STREAM_SINGLESHOT && - video->state == VPFE_VIDEO_BUFFER_NOT_QUEUED) { - spin_lock(&video->dma_queue_lock); - addr = vpfe_video_get_next_buffer(video); - video->ops->queue(vpfe_dev, addr); - - video->state = VPFE_VIDEO_BUFFER_QUEUED; - spin_unlock(&video->dma_queue_lock); - - /* enable h/w each time in single shot */ - if (vpfe_video_is_pipe_ready(pipe)) - vpfe_pipeline_set_stream(pipe, - VPFE_PIPELINE_STREAM_SINGLESHOT); - } -} - -/* vpfe_start_capture() - start streaming on all the subdevs */ -static int vpfe_start_capture(struct vpfe_video_device *video) -{ - struct vpfe_pipeline *pipe = &video->pipe; - int ret = 0; - - video->started = 1; - if (vpfe_video_is_pipe_ready(pipe)) - ret = vpfe_pipeline_set_stream(pipe, pipe->state); - - return ret; -} - -static int vpfe_start_streaming(struct vb2_queue *vq, unsigned int count) -{ - struct vpfe_fh *fh = vb2_get_drv_priv(vq); - struct vpfe_video_device *video = fh->video; - struct vpfe_device *vpfe_dev = video->vpfe_dev; - unsigned long addr; - int ret; - - ret = mutex_lock_interruptible(&video->lock); - if (ret) - goto streamoff; - - /* Get the next frame from the buffer queue */ - video->cur_frm = video->next_frm = - list_entry(video->dma_queue.next, struct vpfe_cap_buffer, list); - /* Remove buffer from the buffer queue */ - list_del(&video->cur_frm->list); - /* Mark state of the current frame to active */ - video->cur_frm->vb.vb2_buf.state = VB2_BUF_STATE_ACTIVE; - /* Initialize field_id and started member */ - video->field_id = 0; - addr = vb2_dma_contig_plane_dma_addr(&video->cur_frm->vb.vb2_buf, 0); - video->ops->queue(vpfe_dev, addr); - video->state = VPFE_VIDEO_BUFFER_QUEUED; - - ret = vpfe_start_capture(video); - if (ret) { - struct vpfe_cap_buffer *buf, *tmp; - - vb2_buffer_done(&video->cur_frm->vb.vb2_buf, - VB2_BUF_STATE_QUEUED); - list_for_each_entry_safe(buf, tmp, &video->dma_queue, list) { - list_del(&buf->list); - vb2_buffer_done(&buf->vb.vb2_buf, - VB2_BUF_STATE_QUEUED); - } - goto unlock_out; - } - - mutex_unlock(&video->lock); - - return ret; -unlock_out: - mutex_unlock(&video->lock); -streamoff: - ret = vb2_streamoff(&video->buffer_queue, video->buffer_queue.type); - return 0; -} - -static int vpfe_buffer_init(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct vpfe_cap_buffer *buf = container_of(vbuf, - struct vpfe_cap_buffer, vb); - - INIT_LIST_HEAD(&buf->list); - return 0; -} - -/* abort streaming and wait for last buffer */ -static void vpfe_stop_streaming(struct vb2_queue *vq) -{ - struct vpfe_fh *fh = vb2_get_drv_priv(vq); - struct vpfe_video_device *video = fh->video; - - /* release all active buffers */ - if (video->cur_frm == video->next_frm) { - vb2_buffer_done(&video->cur_frm->vb.vb2_buf, - VB2_BUF_STATE_ERROR); - } else { - if (video->cur_frm != NULL) - vb2_buffer_done(&video->cur_frm->vb.vb2_buf, - VB2_BUF_STATE_ERROR); - if (video->next_frm != NULL) - vb2_buffer_done(&video->next_frm->vb.vb2_buf, - VB2_BUF_STATE_ERROR); - } - - while (!list_empty(&video->dma_queue)) { - video->next_frm = list_entry(video->dma_queue.next, - struct vpfe_cap_buffer, list); - list_del(&video->next_frm->list); - vb2_buffer_done(&video->next_frm->vb.vb2_buf, - VB2_BUF_STATE_ERROR); - } -} - -static void vpfe_buf_cleanup(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct vpfe_fh *fh = vb2_get_drv_priv(vb->vb2_queue); - struct vpfe_video_device *video = fh->video; - struct vpfe_device *vpfe_dev = video->vpfe_dev; - struct vpfe_cap_buffer *buf = container_of(vbuf, - struct vpfe_cap_buffer, vb); - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buf_cleanup\n"); - if (vb->state == VB2_BUF_STATE_ACTIVE) - list_del_init(&buf->list); -} - -static const struct vb2_ops video_qops = { - .queue_setup = vpfe_buffer_queue_setup, - .buf_init = vpfe_buffer_init, - .buf_prepare = vpfe_buffer_prepare, - .start_streaming = vpfe_start_streaming, - .stop_streaming = vpfe_stop_streaming, - .buf_cleanup = vpfe_buf_cleanup, - .buf_queue = vpfe_buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, -}; - -/* - * vpfe_reqbufs() - supported REQBUF only once opening - * the device. - */ -static int vpfe_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *req_buf) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct vpfe_device *vpfe_dev = video->vpfe_dev; - struct vpfe_fh *fh = file->private_data; - struct vb2_queue *q; - int ret; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_reqbufs\n"); - - if (req_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && - req_buf->type != V4L2_BUF_TYPE_VIDEO_OUTPUT){ - v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buffer type\n"); - return -EINVAL; - } - - ret = mutex_lock_interruptible(&video->lock); - if (ret) - return ret; - - if (video->io_usrs != 0) { - v4l2_err(&vpfe_dev->v4l2_dev, "Only one IO user allowed\n"); - ret = -EBUSY; - goto unlock_out; - } - video->memory = req_buf->memory; - - /* Initialize videobuf2 queue as per the buffer type */ - q = &video->buffer_queue; - q->type = req_buf->type; - q->io_modes = VB2_MMAP | VB2_USERPTR; - q->drv_priv = fh; - q->min_buffers_needed = 1; - q->ops = &video_qops; - q->mem_ops = &vb2_dma_contig_memops; - q->buf_struct_size = sizeof(struct vpfe_cap_buffer); - q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - q->dev = vpfe_dev->pdev; - q->lock = &video->lock; - - ret = vb2_queue_init(q); - if (ret) { - v4l2_err(&vpfe_dev->v4l2_dev, "vb2_queue_init() failed\n"); - goto unlock_out; - } - - fh->io_allowed = 1; - video->io_usrs = 1; - INIT_LIST_HEAD(&video->dma_queue); - ret = vb2_reqbufs(&video->buffer_queue, req_buf); - -unlock_out: - mutex_unlock(&video->lock); - return ret; -} - -/* - * vpfe_querybuf() - query buffers for exchange - */ -static int vpfe_querybuf(struct file *file, void *priv, - struct v4l2_buffer *buf) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct vpfe_device *vpfe_dev = video->vpfe_dev; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querybuf\n"); - - if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && - buf->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) { - v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); - return -EINVAL; - } - - if (video->memory != V4L2_MEMORY_MMAP) { - v4l2_err(&vpfe_dev->v4l2_dev, "Invalid memory\n"); - return -EINVAL; - } - - /* Call vb2_querybuf to get information */ - return vb2_querybuf(&video->buffer_queue, buf); -} - -/* - * vpfe_qbuf() - queue buffers for capture or processing - */ -static int vpfe_qbuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct vpfe_device *vpfe_dev = video->vpfe_dev; - struct vpfe_fh *fh = file->private_data; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_qbuf\n"); - - if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && - p->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) { - v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); - return -EINVAL; - } - /* - * If this file handle is not allowed to do IO, - * return error - */ - if (!fh->io_allowed) { - v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n"); - return -EACCES; - } - - return vb2_qbuf(&video->buffer_queue, - video->video_dev.v4l2_dev->mdev, p); -} - -/* - * vpfe_dqbuf() - deque buffer which is done with processing - */ -static int vpfe_dqbuf(struct file *file, void *priv, - struct v4l2_buffer *buf) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct vpfe_device *vpfe_dev = video->vpfe_dev; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_dqbuf\n"); - - if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && - buf->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) { - v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); - return -EINVAL; - } - - return vb2_dqbuf(&video->buffer_queue, - buf, (file->f_flags & O_NONBLOCK)); -} - -/* - * vpfe_streamon() - start streaming - * @file: file pointer - * @priv: void pointer - * @buf_type: enum v4l2_buf_type - * - * queue buffer onto hardware for capture/processing and - * start all the subdevs which are in media chain - * - * Return 0 on success, error code otherwise - */ -static int vpfe_streamon(struct file *file, void *priv, - enum v4l2_buf_type buf_type) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct vpfe_device *vpfe_dev = video->vpfe_dev; - struct vpfe_pipeline *pipe = &video->pipe; - struct vpfe_fh *fh = file->private_data; - int ret = -EINVAL; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_streamon\n"); - - if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE && - buf_type != V4L2_BUF_TYPE_VIDEO_OUTPUT) { - v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); - return ret; - } - /* If file handle is not allowed IO, return error */ - if (!fh->io_allowed) { - v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n"); - return -EACCES; - } - /* If buffer queue is empty, return error */ - if (list_empty(&video->buffer_queue.queued_list)) { - v4l2_err(&vpfe_dev->v4l2_dev, "buffer queue is empty\n"); - return -EIO; - } - /* Validate the pipeline */ - if (buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - ret = vpfe_video_validate_pipeline(pipe); - if (ret < 0) - return ret; - } - /* Call vb2_streamon to start streaming */ - return vb2_streamon(&video->buffer_queue, buf_type); -} - -/* - * vpfe_streamoff() - stop streaming - * @file: file pointer - * @priv: void pointer - * @buf_type: enum v4l2_buf_type - * - * stop all the subdevs which are in media chain - * - * Return 0 on success, error code otherwise - */ -static int vpfe_streamoff(struct file *file, void *priv, - enum v4l2_buf_type buf_type) -{ - struct vpfe_video_device *video = video_drvdata(file); - struct vpfe_device *vpfe_dev = video->vpfe_dev; - struct vpfe_fh *fh = file->private_data; - int ret = 0; - - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_streamoff\n"); - - if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE && - buf_type != V4L2_BUF_TYPE_VIDEO_OUTPUT) { - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "Invalid buf type\n"); - return -EINVAL; - } - - /* If io is allowed for this file handle, return error */ - if (!fh->io_allowed) { - v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "fh->io_allowed\n"); - return -EACCES; - } - - /* If streaming is not started, return error */ - if (!video->started) { - v4l2_err(&vpfe_dev->v4l2_dev, "device is not started\n"); - return -EINVAL; - } - - ret = mutex_lock_interruptible(&video->lock); - if (ret) - return ret; - - vpfe_stop_capture(video); - ret = vb2_streamoff(&video->buffer_queue, buf_type); - mutex_unlock(&video->lock); - - return ret; -} - -/* vpfe capture ioctl operations */ -static const struct v4l2_ioctl_ops vpfe_ioctl_ops = { - .vidioc_querycap = vpfe_querycap, - .vidioc_g_fmt_vid_cap = vpfe_g_fmt, - .vidioc_s_fmt_vid_cap = vpfe_s_fmt, - .vidioc_try_fmt_vid_cap = vpfe_try_fmt, - .vidioc_enum_fmt_vid_cap = vpfe_enum_fmt, - .vidioc_g_fmt_vid_out = vpfe_g_fmt, - .vidioc_s_fmt_vid_out = vpfe_s_fmt, - .vidioc_try_fmt_vid_out = vpfe_try_fmt, - .vidioc_enum_fmt_vid_out = vpfe_enum_fmt, - .vidioc_enum_input = vpfe_enum_input, - .vidioc_g_input = vpfe_g_input, - .vidioc_s_input = vpfe_s_input, - .vidioc_querystd = vpfe_querystd, - .vidioc_s_std = vpfe_s_std, - .vidioc_g_std = vpfe_g_std, - .vidioc_enum_dv_timings = vpfe_enum_dv_timings, - .vidioc_query_dv_timings = vpfe_query_dv_timings, - .vidioc_s_dv_timings = vpfe_s_dv_timings, - .vidioc_g_dv_timings = vpfe_g_dv_timings, - .vidioc_reqbufs = vpfe_reqbufs, - .vidioc_querybuf = vpfe_querybuf, - .vidioc_qbuf = vpfe_qbuf, - .vidioc_dqbuf = vpfe_dqbuf, - .vidioc_streamon = vpfe_streamon, - .vidioc_streamoff = vpfe_streamoff, -}; - -/* VPFE video init function */ -int vpfe_video_init(struct vpfe_video_device *video, const char *name) -{ - const char *direction; - int ret; - - switch (video->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - direction = "output"; - video->pad.flags = MEDIA_PAD_FL_SINK; - video->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - break; - - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - direction = "input"; - video->pad.flags = MEDIA_PAD_FL_SOURCE; - video->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - break; - - default: - return -EINVAL; - } - /* Initialize field of video device */ - mutex_init(&video->lock); - video->video_dev.release = video_device_release; - video->video_dev.fops = &vpfe_fops; - video->video_dev.ioctl_ops = &vpfe_ioctl_ops; - video->video_dev.minor = -1; - video->video_dev.tvnorms = 0; - video->video_dev.lock = &video->lock; - snprintf(video->video_dev.name, sizeof(video->video_dev.name), - "DAVINCI VIDEO %s %s", name, direction); - - spin_lock_init(&video->irqlock); - spin_lock_init(&video->dma_queue_lock); - ret = media_entity_pads_init(&video->video_dev.entity, - 1, &video->pad); - if (ret < 0) - return ret; - - video_set_drvdata(&video->video_dev, video); - - return 0; -} - -/* vpfe video device register function */ -int vpfe_video_register(struct vpfe_video_device *video, - struct v4l2_device *vdev) -{ - int ret; - - video->video_dev.v4l2_dev = vdev; - - if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - video->video_dev.device_caps = V4L2_CAP_VIDEO_CAPTURE; - else - video->video_dev.device_caps = V4L2_CAP_VIDEO_OUTPUT; - video->video_dev.device_caps |= V4L2_CAP_STREAMING; - ret = video_register_device(&video->video_dev, VFL_TYPE_GRABBER, -1); - if (ret < 0) - pr_err("%s: could not register video device (%d)\n", - __func__, ret); - return ret; -} - -/* vpfe video device unregister function */ -void vpfe_video_unregister(struct vpfe_video_device *video) -{ - if (video_is_registered(&video->video_dev)) { - video_unregister_device(&video->video_dev); - media_entity_cleanup(&video->video_dev.entity); - } -} diff --git a/drivers/staging/media/davinci_vpfe/vpfe_video.h b/drivers/staging/media/davinci_vpfe/vpfe_video.h deleted file mode 100644 index 5d01c4883ab4..000000000000 --- a/drivers/staging/media/davinci_vpfe/vpfe_video.h +++ /dev/null @@ -1,150 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2012 Texas Instruments Inc - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Contributors: - * Manjunath Hadli - * Prabhakar Lad - */ - -#ifndef _DAVINCI_VPFE_VIDEO_H -#define _DAVINCI_VPFE_VIDEO_H - -#include -#include - -struct vpfe_device; - -/* - * struct vpfe_video_operations - VPFE video operations - * @queue: Resume streaming when a buffer is queued. Called on VIDIOC_QBUF - * if there was no buffer previously queued. - */ -struct vpfe_video_operations { - int (*queue)(struct vpfe_device *vpfe_dev, unsigned long addr); -}; - -enum vpfe_pipeline_stream_state { - VPFE_PIPELINE_STREAM_STOPPED = 0, - VPFE_PIPELINE_STREAM_CONTINUOUS = 1, - VPFE_PIPELINE_STREAM_SINGLESHOT = 2, -}; - -enum vpfe_video_state { - /* indicates that buffer is not queued */ - VPFE_VIDEO_BUFFER_NOT_QUEUED = 0, - /* indicates that buffer is queued */ - VPFE_VIDEO_BUFFER_QUEUED = 1, -}; - -struct vpfe_pipeline { - /* media pipeline */ - struct media_pipeline *pipe; - struct media_graph graph; - /* state of the pipeline, continuous, - * single-shot or stopped - */ - enum vpfe_pipeline_stream_state state; - /* number of active input video entities */ - unsigned int input_num; - /* number of active output video entities */ - unsigned int output_num; - /* input video nodes in case of single-shot mode */ - struct vpfe_video_device *inputs[10]; - /* capturing video nodes */ - struct vpfe_video_device *outputs[10]; -}; - -#define to_vpfe_pipeline(__e) \ - container_of((__e)->pipe, struct vpfe_pipeline, pipe) - -#define to_vpfe_video(vdev) \ - container_of(vdev, struct vpfe_video_device, video_dev) - -struct vpfe_cap_buffer { - struct vb2_v4l2_buffer vb; - struct list_head list; -}; - -struct vpfe_video_device { - /* vpfe device */ - struct vpfe_device *vpfe_dev; - /* video dev */ - struct video_device video_dev; - /* media pad of video entity */ - struct media_pad pad; - /* video operations supported by video device */ - const struct vpfe_video_operations *ops; - /* type of the video buffers used by user */ - enum v4l2_buf_type type; - /* Indicates id of the field which is being captured */ - u32 field_id; - /* pipeline for which video device is part of */ - struct vpfe_pipeline pipe; - /* Indicates whether streaming started */ - u8 started; - /* Indicates state of the stream */ - unsigned int state; - /* current input at the sub device */ - int current_input; - /* - * This field keeps track of type of buffer exchange mechanism - * user has selected - */ - enum v4l2_memory memory; - /* number of open instances of the channel */ - u32 usrs; - /* flag to indicate whether decoder is initialized */ - u8 initialized; - /* skip frame count */ - u8 skip_frame_count; - /* skip frame count init value */ - u8 skip_frame_count_init; - /* time per frame for skipping */ - struct v4l2_fract timeperframe; - /* ptr to currently selected sub device */ - struct vpfe_ext_subdev_info *current_ext_subdev; - /* Pointer pointing to current vpfe_cap_buffer */ - struct vpfe_cap_buffer *cur_frm; - /* Pointer pointing to next vpfe_cap_buffer */ - struct vpfe_cap_buffer *next_frm; - /* Used to store pixel format */ - struct v4l2_format fmt; - struct vb2_queue buffer_queue; - /* Queue of filled frames */ - struct list_head dma_queue; - spinlock_t irqlock; - /* IRQ lock for DMA queue */ - spinlock_t dma_queue_lock; - /* lock used to serialize all video4linux ioctls */ - struct mutex lock; - /* number of users performing IO */ - u32 io_usrs; - /* Currently selected or default standard */ - v4l2_std_id stdid; - /* - * offset where second field starts from the starting of the - * buffer for field separated YCbCr formats - */ - u32 field_off; -}; - -int vpfe_video_is_pipe_ready(struct vpfe_pipeline *pipe); -void vpfe_video_unregister(struct vpfe_video_device *video); -int vpfe_video_register(struct vpfe_video_device *video, - struct v4l2_device *vdev); -int vpfe_video_init(struct vpfe_video_device *video, const char *name); -void vpfe_video_process_buffer_complete(struct vpfe_video_device *video); -void vpfe_video_schedule_bottom_field(struct vpfe_video_device *video); -void vpfe_video_schedule_next_buffer(struct vpfe_video_device *video); - -#endif /* _DAVINCI_VPFE_VIDEO_H */ -- cgit v1.2.3-59-g8ed1b From 6ddb094a9f8c451c42bc7c58cfed22275e8a1e38 Mon Sep 17 00:00:00 2001 From: Chuhong Yuan Date: Wed, 24 Jul 2019 08:22:19 -0400 Subject: media: staging/intel-ipu3: Use dev_get_drvdata where possible Instead of using to_pci_dev + pci_get_drvdata, use dev_get_drvdata to make code simpler. Signed-off-by: Chuhong Yuan Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/ipu3/ipu3.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/ipu3/ipu3.c b/drivers/staging/media/ipu3/ipu3.c index a7372395a101..06a61f31ca50 100644 --- a/drivers/staging/media/ipu3/ipu3.c +++ b/drivers/staging/media/ipu3/ipu3.c @@ -778,8 +778,7 @@ out: static int __maybe_unused imgu_resume(struct device *dev) { - struct pci_dev *pci_dev = to_pci_dev(dev); - struct imgu_device *imgu = pci_get_drvdata(pci_dev); + struct imgu_device *imgu = dev_get_drvdata(dev); int r = 0; unsigned int pipe; -- cgit v1.2.3-59-g8ed1b From aa0e9e72733b069a655a3fe9167f69de103830cc Mon Sep 17 00:00:00 2001 From: Hariprasad Kelam Date: Wed, 24 Jul 2019 23:06:02 -0400 Subject: media: staging: media: hantro: Remove call to memset after dma_alloc_coherent fix below issue reported by coccicheck /drivers/staging/media/hantro/hantro_vp8.c:149:16-34: WARNING: dma_alloc_coherent use in aux_buf -> cpu already zeroes out memory, so memset is not needed Signed-off-by: Hariprasad Kelam Reviewed-by: Boris Brezillon Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/hantro/hantro_vp8.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/hantro/hantro_vp8.c b/drivers/staging/media/hantro/hantro_vp8.c index 66c45335d871..363dddaac794 100644 --- a/drivers/staging/media/hantro/hantro_vp8.c +++ b/drivers/staging/media/hantro/hantro_vp8.c @@ -151,8 +151,6 @@ int hantro_vp8_dec_init(struct hantro_ctx *ctx) if (!aux_buf->cpu) return -ENOMEM; - memset(aux_buf->cpu, 0, aux_buf->size); - /* * Allocate probability table buffer, * total 1208 bytes, 4K page is far enough. -- cgit v1.2.3-59-g8ed1b From c3c3509b86810293df5c524ef61421d8affc8bf0 Mon Sep 17 00:00:00 2001 From: Francois Buergisser Date: Thu, 25 Jul 2019 10:17:50 -0400 Subject: media: hantro: Set DMA max segment size The Hantro codec is typically used in platforms with an IOMMU, so we need to set a proper DMA segment size. Devices without an IOMMU will still fallback to default 64KiB segments. Cc: stable@vger.kernel.org Fixes: 775fec69008d3 ("media: add Rockchip VPU JPEG encoder driver") Signed-off-by: Francois Buergisser Signed-off-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/hantro/hantro_drv.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/staging') diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c index b71a06e9159e..4eae1dbb1ac8 100644 --- a/drivers/staging/media/hantro/hantro_drv.c +++ b/drivers/staging/media/hantro/hantro_drv.c @@ -731,6 +731,7 @@ static int hantro_probe(struct platform_device *pdev) dev_err(vpu->dev, "Could not set DMA coherent mask.\n"); return ret; } + vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32)); for (i = 0; i < vpu->variant->num_irqs; i++) { const char *irq_name = vpu->variant->irqs[i].name; -- cgit v1.2.3-59-g8ed1b From 9530bbe726a14fea2acd972a13b5d526edc94e87 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Thu, 25 Jul 2019 10:17:51 -0400 Subject: media: hantro: Simplify the controls creation logic v4l2_ctrl_new_custom() should work for any kind of control, including standard ones. With that change, we automatically get support for menu controls. Signed-off-by: Boris Brezillon Signed-off-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/hantro/hantro.h | 2 -- drivers/staging/media/hantro/hantro_drv.c | 28 ++++++++-------------------- 2 files changed, 8 insertions(+), 22 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/hantro/hantro.h b/drivers/staging/media/hantro/hantro.h index 4d7cb7780bde..81e25dfc98b7 100644 --- a/drivers/staging/media/hantro/hantro.h +++ b/drivers/staging/media/hantro/hantro.h @@ -113,12 +113,10 @@ enum hantro_codec_mode { /* * struct hantro_ctrl - helper type to declare supported controls - * @id: V4L2 control ID (V4L2_CID_xxx) * @codec: codec id this control belong to (HANTRO_JPEG_ENCODER, etc.) * @cfg: control configuration */ struct hantro_ctrl { - unsigned int id; unsigned int codec; struct v4l2_ctrl_config cfg; }; diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c index 4eae1dbb1ac8..ff2dcbf43e81 100644 --- a/drivers/staging/media/hantro/hantro_drv.c +++ b/drivers/staging/media/hantro/hantro_drv.c @@ -264,31 +264,29 @@ static const struct v4l2_ctrl_ops hantro_ctrl_ops = { static struct hantro_ctrl controls[] = { { - .id = V4L2_CID_JPEG_COMPRESSION_QUALITY, .codec = HANTRO_JPEG_ENCODER, .cfg = { + .id = V4L2_CID_JPEG_COMPRESSION_QUALITY, .min = 5, .max = 100, .step = 1, .def = 50, + .ops = &hantro_ctrl_ops, }, }, { - .id = V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS, .codec = HANTRO_MPEG2_DECODER, .cfg = { - .elem_size = sizeof(struct v4l2_ctrl_mpeg2_slice_params), + .id = V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS, }, }, { - .id = V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION, .codec = HANTRO_MPEG2_DECODER, .cfg = { - .elem_size = sizeof(struct v4l2_ctrl_mpeg2_quantization), + .id = V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION, }, }, { - .id = V4L2_CID_MPEG_VIDEO_VP8_FRAME_HEADER, .codec = HANTRO_VP8_DECODER, .cfg = { - .elem_size = sizeof(struct v4l2_ctrl_vp8_frame_header), + .id = V4L2_CID_MPEG_VIDEO_VP8_FRAME_HEADER, }, }, }; @@ -304,22 +302,12 @@ static int hantro_ctrls_setup(struct hantro_dev *vpu, for (i = 0; i < num_ctrls; i++) { if (!(allowed_codecs & controls[i].codec)) continue; - if (!controls[i].cfg.elem_size) { - v4l2_ctrl_new_std(&ctx->ctrl_handler, - &hantro_ctrl_ops, - controls[i].id, controls[i].cfg.min, - controls[i].cfg.max, - controls[i].cfg.step, - controls[i].cfg.def); - } else { - controls[i].cfg.id = controls[i].id; - v4l2_ctrl_new_custom(&ctx->ctrl_handler, - &controls[i].cfg, NULL); - } + v4l2_ctrl_new_custom(&ctx->ctrl_handler, + &controls[i].cfg, NULL); if (ctx->ctrl_handler.error) { vpu_err("Adding control (%d) failed %d\n", - controls[i].id, + controls[i].cfg.id, ctx->ctrl_handler.error); v4l2_ctrl_handler_free(&ctx->ctrl_handler); return ctx->ctrl_handler.error; -- cgit v1.2.3-59-g8ed1b From 61e95d81aa28f411ff1238f56702dc2add2fac00 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Thu, 25 Jul 2019 10:17:52 -0400 Subject: media: hantro: Constify the control array controls[] is not supposed to be modified at runtime, let's make it explicit by adding a const specifier. Signed-off-by: Boris Brezillon Signed-off-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/hantro/hantro_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c index ff2dcbf43e81..398618b0d586 100644 --- a/drivers/staging/media/hantro/hantro_drv.c +++ b/drivers/staging/media/hantro/hantro_drv.c @@ -262,7 +262,7 @@ static const struct v4l2_ctrl_ops hantro_ctrl_ops = { .s_ctrl = hantro_s_ctrl, }; -static struct hantro_ctrl controls[] = { +static const struct hantro_ctrl controls[] = { { .codec = HANTRO_JPEG_ENCODER, .cfg = { -- cgit v1.2.3-59-g8ed1b From deff5c37c88921e61a336f1c4eba1f7ad438cebe Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Thu, 25 Jul 2019 10:17:53 -0400 Subject: media: hantro: Add hantro_get_{src, dst}_buf() helpers And replace all calls to v4l2_m2m_next_{src,dst}_buf() by hantro_get_{src,dst}_buf() one. Signed-off-by: Boris Brezillon Signed-off-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/hantro/hantro.h | 13 +++++++++++++ drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c | 4 ++-- drivers/staging/media/hantro/hantro_g1_vp8_dec.c | 8 ++++---- drivers/staging/media/hantro/hantro_h1_jpeg_enc.c | 4 ++-- drivers/staging/media/hantro/rk3399_vpu_hw_jpeg_enc.c | 4 ++-- drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c | 4 ++-- 6 files changed, 25 insertions(+), 12 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/hantro/hantro.h b/drivers/staging/media/hantro/hantro.h index 81e25dfc98b7..c4c86c32ea2d 100644 --- a/drivers/staging/media/hantro/hantro.h +++ b/drivers/staging/media/hantro/hantro.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -373,4 +374,16 @@ bool hantro_is_encoder_ctx(const struct hantro_ctx *ctx); void *hantro_get_ctrl(struct hantro_ctx *ctx, u32 id); dma_addr_t hantro_get_ref(struct vb2_queue *q, u64 ts); +static inline struct vb2_v4l2_buffer * +hantro_get_src_buf(struct hantro_ctx *ctx) +{ + return v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); +} + +static inline struct vb2_v4l2_buffer * +hantro_get_dst_buf(struct hantro_ctx *ctx) +{ + return v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); +} + #endif /* HANTRO_H_ */ diff --git a/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c b/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c index e592c1b66375..55f861e96108 100644 --- a/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c +++ b/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c @@ -167,8 +167,8 @@ void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx) const struct v4l2_mpeg2_picture *picture; u32 reg; - src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); - dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + src_buf = hantro_get_src_buf(ctx); + dst_buf = hantro_get_dst_buf(ctx); /* Apply request controls if any */ v4l2_ctrl_request_setup(src_buf->vb2_buf.req_obj.req, diff --git a/drivers/staging/media/hantro/hantro_g1_vp8_dec.c b/drivers/staging/media/hantro/hantro_g1_vp8_dec.c index 72d983a11ca1..6032cbbecb06 100644 --- a/drivers/staging/media/hantro/hantro_g1_vp8_dec.c +++ b/drivers/staging/media/hantro/hantro_g1_vp8_dec.c @@ -260,7 +260,7 @@ static void cfg_parts(struct hantro_ctx *ctx, u32 count = 0; unsigned int i; - vb2_src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + vb2_src = hantro_get_src_buf(ctx); src_dma = vb2_dma_contig_plane_dma_addr(&vb2_src->vb2_buf, 0); /* @@ -391,7 +391,7 @@ static void cfg_ref(struct hantro_ctx *ctx, struct vb2_v4l2_buffer *vb2_dst; dma_addr_t ref; - vb2_dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + vb2_dst = hantro_get_dst_buf(ctx); ref = hantro_get_ref(cap_q, hdr->last_frame_ts); if (!ref) @@ -424,7 +424,7 @@ static void cfg_buffers(struct hantro_ctx *ctx, dma_addr_t dst_dma; u32 reg; - vb2_dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + vb2_dst = hantro_get_dst_buf(ctx); /* Set probability table buffer address */ vdpu_write_relaxed(vpu, ctx->vp8_dec.prob_tbl.dma, @@ -453,7 +453,7 @@ void hantro_g1_vp8_dec_run(struct hantro_ctx *ctx) u32 mb_width, mb_height; u32 reg; - vb2_src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + vb2_src = hantro_get_src_buf(ctx); v4l2_ctrl_request_setup(vb2_src->vb2_buf.req_obj.req, &ctx->ctrl_handler); diff --git a/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c b/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c index 0c1e3043dc7e..f5adb5cbde50 100644 --- a/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c +++ b/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c @@ -84,8 +84,8 @@ void hantro_h1_jpeg_enc_run(struct hantro_ctx *ctx) struct hantro_jpeg_ctx jpeg_ctx; u32 reg; - src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); - dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + src_buf = hantro_get_src_buf(ctx); + dst_buf = hantro_get_dst_buf(ctx); memset(&jpeg_ctx, 0, sizeof(jpeg_ctx)); jpeg_ctx.buffer = vb2_plane_vaddr(&dst_buf->vb2_buf, 0); diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw_jpeg_enc.c b/drivers/staging/media/hantro/rk3399_vpu_hw_jpeg_enc.c index ae66354d2d93..82c5af822766 100644 --- a/drivers/staging/media/hantro/rk3399_vpu_hw_jpeg_enc.c +++ b/drivers/staging/media/hantro/rk3399_vpu_hw_jpeg_enc.c @@ -116,8 +116,8 @@ void rk3399_vpu_jpeg_enc_run(struct hantro_ctx *ctx) struct media_request *src_req; u32 reg; - src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); - dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + src_buf = hantro_get_src_buf(ctx); + dst_buf = hantro_get_dst_buf(ctx); src_req = src_buf->vb2_buf.req_obj.req; v4l2_ctrl_request_setup(src_req, &ctx->ctrl_handler); diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c b/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c index 8685bddfbcab..451bfcceadba 100644 --- a/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c +++ b/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c @@ -169,8 +169,8 @@ void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx) const struct v4l2_mpeg2_picture *picture; u32 reg; - src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); - dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + src_buf = hantro_get_src_buf(ctx); + dst_buf = hantro_get_dst_buf(ctx); /* Apply request controls if any */ v4l2_ctrl_request_setup(src_buf->vb2_buf.req_obj.req, -- cgit v1.2.3-59-g8ed1b From 932a9317ac492d4b93227357db4e3e2af28f0fbb Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Thu, 25 Jul 2019 10:17:54 -0400 Subject: media: hantro: Add helpers to prepare/finish a run And use them where appropriate. We might want to move hantro_{prepare,finish}_run() calls to device_run() and have a 2-step approach similar to cedrus (prepare + trigger) at some point, but let's keep that for later. Signed-off-by: Boris Brezillon Signed-off-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/hantro/hantro_drv.c | 22 ++++++++++++++++++++++ drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c | 10 ++-------- drivers/staging/media/hantro/hantro_g1_vp8_dec.c | 11 ++--------- drivers/staging/media/hantro/hantro_h1_jpeg_enc.c | 7 +++++-- drivers/staging/media/hantro/hantro_hw.h | 2 ++ .../staging/media/hantro/rk3399_vpu_hw_jpeg_enc.c | 8 ++------ .../staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c | 10 ++-------- 7 files changed, 37 insertions(+), 33 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c index 398618b0d586..4af6ee80229e 100644 --- a/drivers/staging/media/hantro/hantro_drv.c +++ b/drivers/staging/media/hantro/hantro_drv.c @@ -153,6 +153,28 @@ void hantro_watchdog(struct work_struct *work) } } +void hantro_prepare_run(struct hantro_ctx *ctx) +{ + struct vb2_v4l2_buffer *src_buf; + + src_buf = hantro_get_src_buf(ctx); + v4l2_ctrl_request_setup(src_buf->vb2_buf.req_obj.req, + &ctx->ctrl_handler); +} + +void hantro_finish_run(struct hantro_ctx *ctx) +{ + struct vb2_v4l2_buffer *src_buf; + + src_buf = hantro_get_src_buf(ctx); + v4l2_ctrl_request_complete(src_buf->vb2_buf.req_obj.req, + &ctx->ctrl_handler); + + /* Kick the watchdog. */ + schedule_delayed_work(&ctx->dev->watchdog_work, + msecs_to_jiffies(2000)); +} + static void device_run(void *priv) { struct hantro_ctx *ctx = priv; diff --git a/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c b/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c index 55f861e96108..80f0e94f8afa 100644 --- a/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c +++ b/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c @@ -171,8 +171,7 @@ void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx) dst_buf = hantro_get_dst_buf(ctx); /* Apply request controls if any */ - v4l2_ctrl_request_setup(src_buf->vb2_buf.req_obj.req, - &ctx->ctrl_handler); + hantro_prepare_run(ctx); slice_params = hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS); @@ -248,12 +247,7 @@ void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx) &dst_buf->vb2_buf, sequence, picture, slice_params); - /* Controls no longer in-use, we can complete them */ - v4l2_ctrl_request_complete(src_buf->vb2_buf.req_obj.req, - &ctx->ctrl_handler); - - /* Kick the watchdog and start decoding */ - schedule_delayed_work(&vpu->watchdog_work, msecs_to_jiffies(2000)); + hantro_finish_run(ctx); reg = G1_REG_DEC_E(1); vdpu_write(vpu, reg, G1_SWREG(1)); diff --git a/drivers/staging/media/hantro/hantro_g1_vp8_dec.c b/drivers/staging/media/hantro/hantro_g1_vp8_dec.c index 6032cbbecb06..cd1fbd3a0d5f 100644 --- a/drivers/staging/media/hantro/hantro_g1_vp8_dec.c +++ b/drivers/staging/media/hantro/hantro_g1_vp8_dec.c @@ -449,13 +449,10 @@ void hantro_g1_vp8_dec_run(struct hantro_ctx *ctx) struct hantro_dev *vpu = ctx->dev; size_t height = ctx->dst_fmt.height; size_t width = ctx->dst_fmt.width; - struct vb2_v4l2_buffer *vb2_src; u32 mb_width, mb_height; u32 reg; - vb2_src = hantro_get_src_buf(ctx); - v4l2_ctrl_request_setup(vb2_src->vb2_buf.req_obj.req, - &ctx->ctrl_handler); + hantro_prepare_run(ctx); hdr = hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_VP8_FRAME_HEADER); if (WARN_ON(!hdr)) @@ -516,11 +513,7 @@ void hantro_g1_vp8_dec_run(struct hantro_ctx *ctx) cfg_ref(ctx, hdr); cfg_buffers(ctx, hdr); - /* Controls no longer in-use, we can complete them */ - v4l2_ctrl_request_complete(vb2_src->vb2_buf.req_obj.req, - &ctx->ctrl_handler); - - schedule_delayed_work(&vpu->watchdog_work, msecs_to_jiffies(2000)); + hantro_finish_run(ctx); vdpu_write(vpu, G1_REG_INTERRUPT_DEC_E, G1_REG_INTERRUPT); } diff --git a/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c b/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c index f5adb5cbde50..ecd34a7db190 100644 --- a/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c +++ b/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c @@ -87,6 +87,8 @@ void hantro_h1_jpeg_enc_run(struct hantro_ctx *ctx) src_buf = hantro_get_src_buf(ctx); dst_buf = hantro_get_dst_buf(ctx); + hantro_prepare_run(ctx); + memset(&jpeg_ctx, 0, sizeof(jpeg_ctx)); jpeg_ctx.buffer = vb2_plane_vaddr(&dst_buf->vb2_buf, 0); jpeg_ctx.width = ctx->dst_fmt.width; @@ -119,7 +121,8 @@ void hantro_h1_jpeg_enc_run(struct hantro_ctx *ctx) | H1_REG_ENC_CTRL_ENC_MODE_JPEG | H1_REG_ENC_PIC_INTRA | H1_REG_ENC_CTRL_EN_BIT; - /* Kick the watchdog and start encoding */ - schedule_delayed_work(&vpu->watchdog_work, msecs_to_jiffies(2000)); + + hantro_finish_run(ctx); + vepu_write(vpu, reg, H1_REG_ENC_CTRL); } diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/staging/media/hantro/hantro_hw.h index 7849852affde..34ef24e3a9ef 100644 --- a/drivers/staging/media/hantro/hantro_hw.h +++ b/drivers/staging/media/hantro/hantro_hw.h @@ -97,6 +97,8 @@ void hantro_watchdog(struct work_struct *work); void hantro_run(struct hantro_ctx *ctx); void hantro_irq_done(struct hantro_dev *vpu, unsigned int bytesused, enum vb2_buffer_state result); +void hantro_prepare_run(struct hantro_ctx *ctx); +void hantro_finish_run(struct hantro_ctx *ctx); void hantro_h1_jpeg_enc_run(struct hantro_ctx *ctx); void rk3399_vpu_jpeg_enc_run(struct hantro_ctx *ctx); diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw_jpeg_enc.c b/drivers/staging/media/hantro/rk3399_vpu_hw_jpeg_enc.c index 82c5af822766..06162f569b5e 100644 --- a/drivers/staging/media/hantro/rk3399_vpu_hw_jpeg_enc.c +++ b/drivers/staging/media/hantro/rk3399_vpu_hw_jpeg_enc.c @@ -113,14 +113,12 @@ void rk3399_vpu_jpeg_enc_run(struct hantro_ctx *ctx) struct hantro_dev *vpu = ctx->dev; struct vb2_v4l2_buffer *src_buf, *dst_buf; struct hantro_jpeg_ctx jpeg_ctx; - struct media_request *src_req; u32 reg; src_buf = hantro_get_src_buf(ctx); dst_buf = hantro_get_dst_buf(ctx); - src_req = src_buf->vb2_buf.req_obj.req; - v4l2_ctrl_request_setup(src_req, &ctx->ctrl_handler); + hantro_prepare_run(ctx); memset(&jpeg_ctx, 0, sizeof(jpeg_ctx)); jpeg_ctx.buffer = vb2_plane_vaddr(&dst_buf->vb2_buf, 0); @@ -157,9 +155,7 @@ void rk3399_vpu_jpeg_enc_run(struct hantro_ctx *ctx) | VEPU_REG_ENCODE_FORMAT_JPEG | VEPU_REG_ENCODE_ENABLE; - v4l2_ctrl_request_complete(src_req, &ctx->ctrl_handler); - /* Kick the watchdog and start encoding */ - schedule_delayed_work(&vpu->watchdog_work, msecs_to_jiffies(2000)); + hantro_finish_run(ctx); vepu_write(vpu, reg, VEPU_REG_ENCODE_START); } diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c b/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c index 451bfcceadba..e7ba5c0441cc 100644 --- a/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c +++ b/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c @@ -172,9 +172,7 @@ void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx) src_buf = hantro_get_src_buf(ctx); dst_buf = hantro_get_dst_buf(ctx); - /* Apply request controls if any */ - v4l2_ctrl_request_setup(src_buf->vb2_buf.req_obj.req, - &ctx->ctrl_handler); + hantro_prepare_run(ctx); slice_params = hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS); @@ -254,12 +252,8 @@ void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx) &dst_buf->vb2_buf, sequence, picture, slice_params); - /* Controls no longer in-use, we can complete them */ - v4l2_ctrl_request_complete(src_buf->vb2_buf.req_obj.req, - &ctx->ctrl_handler); - /* Kick the watchdog and start decoding */ - schedule_delayed_work(&vpu->watchdog_work, msecs_to_jiffies(2000)); + hantro_finish_run(ctx); reg = vdpu_read(vpu, VDPU_SWREG(57)) | VDPU_REG_DEC_E(1); vdpu_write(vpu, reg, VDPU_SWREG(57)); -- cgit v1.2.3-59-g8ed1b From 613326d62f7975e4f7899ffbf745f7cb52882461 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 25 Jul 2019 10:17:55 -0400 Subject: media: hantro: Move VP8 common code In order to introduce support for RK3399 VP8 decoding, move some common VP8 code. This will be reused by the RK3399 implementation, reducing code duplication. Signed-off-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/hantro/hantro_g1_vp8_dec.c | 17 ----------------- drivers/staging/media/hantro/hantro_hw.h | 4 ++++ drivers/staging/media/hantro/hantro_vp8.c | 15 +++++++++++++++ 3 files changed, 19 insertions(+), 17 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/hantro/hantro_g1_vp8_dec.c b/drivers/staging/media/hantro/hantro_g1_vp8_dec.c index cd1fbd3a0d5f..181e2f76d8cb 100644 --- a/drivers/staging/media/hantro/hantro_g1_vp8_dec.c +++ b/drivers/staging/media/hantro/hantro_g1_vp8_dec.c @@ -16,8 +16,6 @@ #include "hantro.h" #include "hantro_g1_regs.h" -#define DEC_8190_ALIGN_MASK 0x07U - /* DCT partition base address regs */ static const struct hantro_reg vp8_dec_dct_base[8] = { { G1_REG_ADDR_STR, 0, 0xffffffff }, @@ -131,21 +129,6 @@ static const struct hantro_reg vp8_dec_pred_bc_tap[8][4] = { }, }; -/* - * filter taps taken to 7-bit precision, - * reference RFC6386#Page-16, filters[8][6] - */ -static const u32 vp8_dec_mc_filter[8][6] = { - { 0, 0, 128, 0, 0, 0 }, - { 0, -6, 123, 12, -1, 0 }, - { 2, -11, 108, 36, -8, 1 }, - { 0, -9, 93, 50, -6, 0 }, - { 3, -16, 77, 77, -16, 3 }, - { 0, -6, 50, 93, -9, 0 }, - { 1, -8, 36, 108, -11, 2 }, - { 0, -1, 12, 123, -6, 0 } -}; - /* * Set loop filters */ diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/staging/media/hantro/hantro_hw.h index 34ef24e3a9ef..185e27d47e47 100644 --- a/drivers/staging/media/hantro/hantro_hw.h +++ b/drivers/staging/media/hantro/hantro_hw.h @@ -15,6 +15,8 @@ #include #include +#define DEC_8190_ALIGN_MASK 0x07U + struct hantro_dev; struct hantro_ctx; struct hantro_buf; @@ -93,6 +95,8 @@ extern const struct hantro_variant rk3399_vpu_variant; extern const struct hantro_variant rk3328_vpu_variant; extern const struct hantro_variant rk3288_vpu_variant; +extern const u32 vp8_dec_mc_filter[8][6]; + void hantro_watchdog(struct work_struct *work); void hantro_run(struct hantro_ctx *ctx); void hantro_irq_done(struct hantro_dev *vpu, unsigned int bytesused, diff --git a/drivers/staging/media/hantro/hantro_vp8.c b/drivers/staging/media/hantro/hantro_vp8.c index 363dddaac794..cd01661cac21 100644 --- a/drivers/staging/media/hantro/hantro_vp8.c +++ b/drivers/staging/media/hantro/hantro_vp8.c @@ -31,6 +31,21 @@ struct vp8_prob_tbl_packed { u8 padding3[96]; }; +/* + * filter taps taken to 7-bit precision, + * reference RFC6386#Page-16, filters[8][6] + */ +const u32 vp8_dec_mc_filter[8][6] = { + { 0, 0, 128, 0, 0, 0 }, + { 0, -6, 123, 12, -1, 0 }, + { 2, -11, 108, 36, -8, 1 }, + { 0, -9, 93, 50, -6, 0 }, + { 3, -16, 77, 77, -16, 3 }, + { 0, -6, 50, 93, -9, 0 }, + { 1, -8, 36, 108, -11, 2 }, + { 0, -1, 12, 123, -6, 0 } +}; + void hantro_vp8_prob_update(struct hantro_ctx *ctx, const struct v4l2_ctrl_vp8_frame_header *hdr) { -- cgit v1.2.3-59-g8ed1b From 73fb5bfa53e972f4fcf53c1c230fcc07a8cf6801 Mon Sep 17 00:00:00 2001 From: Jeffy Chen Date: Thu, 25 Jul 2019 10:17:56 -0400 Subject: media: hantro: Support RK3399 VP8 decoding Rockchip RK3399 SoC has the same Hantro G1 IP block as RK3288, but the registers are entirely different. In a similar fashion as MPEG-2 decoding, it's simpler to just add a separate implementation. Signed-off-by: Jeffy Chen Signed-off-by: Tomasz Figa Signed-off-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/hantro/Makefile | 1 + drivers/staging/media/hantro/hantro_hw.h | 1 + drivers/staging/media/hantro/rk3399_vpu_hw.c | 22 +- .../staging/media/hantro/rk3399_vpu_hw_vp8_dec.c | 595 +++++++++++++++++++++ 4 files changed, 618 insertions(+), 1 deletion(-) create mode 100644 drivers/staging/media/hantro/rk3399_vpu_hw_vp8_dec.c (limited to 'drivers/staging') diff --git a/drivers/staging/media/hantro/Makefile b/drivers/staging/media/hantro/Makefile index a627aee77f75..f5ec597d9e08 100644 --- a/drivers/staging/media/hantro/Makefile +++ b/drivers/staging/media/hantro/Makefile @@ -8,6 +8,7 @@ hantro-vpu-y += \ hantro_g1_vp8_dec.o \ rk3399_vpu_hw_jpeg_enc.o \ rk3399_vpu_hw_mpeg2_dec.o \ + rk3399_vpu_hw_vp8_dec.o \ hantro_jpeg.o \ hantro_mpeg2.o \ hantro_vp8.o diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/staging/media/hantro/hantro_hw.h index 185e27d47e47..e86c84fbfe1a 100644 --- a/drivers/staging/media/hantro/hantro_hw.h +++ b/drivers/staging/media/hantro/hantro_hw.h @@ -117,6 +117,7 @@ int hantro_mpeg2_dec_init(struct hantro_ctx *ctx); void hantro_mpeg2_dec_exit(struct hantro_ctx *ctx); void hantro_g1_vp8_dec_run(struct hantro_ctx *ctx); +void rk3399_vpu_vp8_dec_run(struct hantro_ctx *ctx); int hantro_vp8_dec_init(struct hantro_ctx *ctx); void hantro_vp8_dec_exit(struct hantro_ctx *ctx); void hantro_vp8_prob_update(struct hantro_ctx *ctx, diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw.c b/drivers/staging/media/hantro/rk3399_vpu_hw.c index f8400e49bc50..414b1d3fbb1f 100644 --- a/drivers/staging/media/hantro/rk3399_vpu_hw.c +++ b/drivers/staging/media/hantro/rk3399_vpu_hw.c @@ -73,6 +73,19 @@ static const struct hantro_fmt rk3399_vpu_dec_fmts[] = { .step_height = MPEG2_MB_DIM, }, }, + { + .fourcc = V4L2_PIX_FMT_VP8_FRAME, + .codec_mode = HANTRO_MODE_VP8_DEC, + .max_depth = 2, + .frmsize = { + .min_width = 48, + .max_width = 3840, + .step_width = VP8_MB_DIM, + .min_height = 48, + .max_height = 2160, + .step_height = VP8_MB_DIM, + }, + }, }; static irqreturn_t rk3399_vepu_irq(int irq, void *dev_id) @@ -154,6 +167,12 @@ static const struct hantro_codec_ops rk3399_vpu_codec_ops[] = { .init = hantro_mpeg2_dec_init, .exit = hantro_mpeg2_dec_exit, }, + [HANTRO_MODE_VP8_DEC] = { + .run = rk3399_vpu_vp8_dec_run, + .reset = rk3399_vpu_dec_reset, + .init = hantro_vp8_dec_init, + .exit = hantro_vp8_dec_exit, + }, }; /* @@ -176,7 +195,8 @@ const struct hantro_variant rk3399_vpu_variant = { .dec_offset = 0x400, .dec_fmts = rk3399_vpu_dec_fmts, .num_dec_fmts = ARRAY_SIZE(rk3399_vpu_dec_fmts), - .codec = HANTRO_JPEG_ENCODER | HANTRO_MPEG2_DECODER, + .codec = HANTRO_JPEG_ENCODER | HANTRO_MPEG2_DECODER | + HANTRO_VP8_DECODER, .codec_ops = rk3399_vpu_codec_ops, .irqs = rk3399_irqs, .num_irqs = ARRAY_SIZE(rk3399_irqs), diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw_vp8_dec.c b/drivers/staging/media/hantro/rk3399_vpu_hw_vp8_dec.c new file mode 100644 index 000000000000..c5e9f8befe9c --- /dev/null +++ b/drivers/staging/media/hantro/rk3399_vpu_hw_vp8_dec.c @@ -0,0 +1,595 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Rockchip VPU codec vp8 decode driver + * + * Copyright (C) 2014 Rockchip Electronics Co., Ltd. + * ZhiChao Yu + * + * Copyright (C) 2014 Google LLC. + * Tomasz Figa + * + * Copyright (C) 2015 Rockchip Electronics Co., Ltd. + * Alpha Lin + */ + +#include +#include + +#include "hantro_hw.h" +#include "hantro.h" +#include "hantro_g1_regs.h" + +#define VDPU_REG_DEC_CTRL0 0x0c8 +#define VDPU_REG_STREAM_LEN 0x0cc +#define VDPU_REG_DEC_FORMAT 0x0d4 +#define VDPU_REG_DEC_CTRL0_DEC_MODE(x) (((x) & 0xf) << 0) +#define VDPU_REG_DATA_ENDIAN 0x0d8 +#define VDPU_REG_CONFIG_DEC_STRENDIAN_E BIT(5) +#define VDPU_REG_CONFIG_DEC_STRSWAP32_E BIT(4) +#define VDPU_REG_CONFIG_DEC_OUTSWAP32_E BIT(3) +#define VDPU_REG_CONFIG_DEC_INSWAP32_E BIT(2) +#define VDPU_REG_CONFIG_DEC_OUT_ENDIAN BIT(1) +#define VDPU_REG_CONFIG_DEC_IN_ENDIAN BIT(0) +#define VDPU_REG_AXI_CTRL 0x0e0 +#define VDPU_REG_CONFIG_DEC_MAX_BURST(x) (((x) & 0x1f) << 16) +#define VDPU_REG_EN_FLAGS 0x0e4 +#define VDPU_REG_DEC_CTRL0_PIC_INTER_E BIT(14) +#define VDPU_REG_CONFIG_DEC_TIMEOUT_E BIT(5) +#define VDPU_REG_CONFIG_DEC_CLK_GATE_E BIT(4) +#define VDPU_REG_PRED_FLT 0x0ec +#define VDPU_REG_ADDR_QTABLE 0x0f4 +#define VDPU_REG_ADDR_DST 0x0fc +#define VDPU_REG_ADDR_STR 0x100 +#define VDPU_REG_VP8_PIC_MB_SIZE 0x1e0 +#define VDPU_REG_VP8_DCT_START_BIT 0x1e4 +#define VDPU_REG_DEC_CTRL4_VC1_HEIGHT_EXT BIT(13) +#define VDPU_REG_DEC_CTRL4_BILIN_MC_E BIT(12) +#define VDPU_REG_VP8_CTRL0 0x1e8 +#define VDPU_REG_VP8_DATA_VAL 0x1f0 +#define VDPU_REG_PRED_FLT7 0x1f4 +#define VDPU_REG_PRED_FLT8 0x1f8 +#define VDPU_REG_PRED_FLT9 0x1fc +#define VDPU_REG_PRED_FLT10 0x200 +#define VDPU_REG_FILTER_LEVEL 0x204 +#define VDPU_REG_VP8_QUANTER0 0x208 +#define VDPU_REG_VP8_ADDR_REF0 0x20c +#define VDPU_REG_FILTER_MB_ADJ 0x210 +#define VDPU_REG_REF_PIC_FILT_TYPE_E BIT(31) +#define VDPU_REG_REF_PIC_FILT_SHARPNESS(x) (((x) & 0x7) << 28) +#define VDPU_REG_FILTER_REF_ADJ 0x214 +#define VDPU_REG_VP8_ADDR_REF2_5(i) (0x218 + ((i) * 0x4)) +#define VDPU_REG_VP8_GREF_SIGN_BIAS BIT(0) +#define VDPU_REG_VP8_AREF_SIGN_BIAS BIT(0) +#define VDPU_REG_VP8_DCT_BASE(i) \ + (0x230 + ((((i) < 5) ? (i) : ((i) + 1)) * 0x4)) +#define VDPU_REG_VP8_ADDR_CTRL_PART 0x244 +#define VDPU_REG_VP8_SEGMENT_VAL 0x254 +#define VDPU_REG_FWD_PIC1_SEGMENT_BASE(x) ((x) << 0) +#define VDPU_REG_FWD_PIC1_SEGMENT_UPD_E BIT(1) +#define VDPU_REG_FWD_PIC1_SEGMENT_E BIT(0) +#define VDPU_REG_VP8_DCT_START_BIT2 0x258 +#define VDPU_REG_VP8_QUANTER1 0x25c +#define VDPU_REG_VP8_QUANTER2 0x260 +#define VDPU_REG_PRED_FLT1 0x264 +#define VDPU_REG_PRED_FLT2 0x268 +#define VDPU_REG_PRED_FLT3 0x26c +#define VDPU_REG_PRED_FLT4 0x270 +#define VDPU_REG_PRED_FLT5 0x274 +#define VDPU_REG_PRED_FLT6 0x278 + +static const struct hantro_reg vp8_dec_dct_base[8] = { + { VDPU_REG_ADDR_STR, 0, 0xffffffff }, + { VDPU_REG_VP8_DCT_BASE(0), 0, 0xffffffff }, + { VDPU_REG_VP8_DCT_BASE(1), 0, 0xffffffff }, + { VDPU_REG_VP8_DCT_BASE(2), 0, 0xffffffff }, + { VDPU_REG_VP8_DCT_BASE(3), 0, 0xffffffff }, + { VDPU_REG_VP8_DCT_BASE(4), 0, 0xffffffff }, + { VDPU_REG_VP8_DCT_BASE(5), 0, 0xffffffff }, + { VDPU_REG_VP8_DCT_BASE(6), 0, 0xffffffff }, +}; + +static const struct hantro_reg vp8_dec_lf_level[4] = { + { VDPU_REG_FILTER_LEVEL, 18, 0x3f }, + { VDPU_REG_FILTER_LEVEL, 12, 0x3f }, + { VDPU_REG_FILTER_LEVEL, 6, 0x3f }, + { VDPU_REG_FILTER_LEVEL, 0, 0x3f }, +}; + +static const struct hantro_reg vp8_dec_mb_adj[4] = { + { VDPU_REG_FILTER_MB_ADJ, 21, 0x7f }, + { VDPU_REG_FILTER_MB_ADJ, 14, 0x7f }, + { VDPU_REG_FILTER_MB_ADJ, 7, 0x7f }, + { VDPU_REG_FILTER_MB_ADJ, 0, 0x7f }, +}; + +static const struct hantro_reg vp8_dec_ref_adj[4] = { + { VDPU_REG_FILTER_REF_ADJ, 21, 0x7f }, + { VDPU_REG_FILTER_REF_ADJ, 14, 0x7f }, + { VDPU_REG_FILTER_REF_ADJ, 7, 0x7f }, + { VDPU_REG_FILTER_REF_ADJ, 0, 0x7f }, +}; + +static const struct hantro_reg vp8_dec_quant[4] = { + { VDPU_REG_VP8_QUANTER0, 11, 0x7ff }, + { VDPU_REG_VP8_QUANTER0, 0, 0x7ff }, + { VDPU_REG_VP8_QUANTER1, 11, 0x7ff }, + { VDPU_REG_VP8_QUANTER1, 0, 0x7ff }, +}; + +static const struct hantro_reg vp8_dec_quant_delta[5] = { + { VDPU_REG_VP8_QUANTER0, 27, 0x1f }, + { VDPU_REG_VP8_QUANTER0, 22, 0x1f }, + { VDPU_REG_VP8_QUANTER1, 27, 0x1f }, + { VDPU_REG_VP8_QUANTER1, 22, 0x1f }, + { VDPU_REG_VP8_QUANTER2, 27, 0x1f }, +}; + +static const struct hantro_reg vp8_dec_dct_start_bits[8] = { + { VDPU_REG_VP8_CTRL0, 26, 0x3f }, + { VDPU_REG_VP8_DCT_START_BIT, 26, 0x3f }, + { VDPU_REG_VP8_DCT_START_BIT, 20, 0x3f }, + { VDPU_REG_VP8_DCT_START_BIT2, 24, 0x3f }, + { VDPU_REG_VP8_DCT_START_BIT2, 18, 0x3f }, + { VDPU_REG_VP8_DCT_START_BIT2, 12, 0x3f }, + { VDPU_REG_VP8_DCT_START_BIT2, 6, 0x3f }, + { VDPU_REG_VP8_DCT_START_BIT2, 0, 0x3f }, +}; + +static const struct hantro_reg vp8_dec_pred_bc_tap[8][6] = { + { + { 0, 0, 0}, + { VDPU_REG_PRED_FLT, 22, 0x3ff }, + { VDPU_REG_PRED_FLT, 12, 0x3ff }, + { VDPU_REG_PRED_FLT, 2, 0x3ff }, + { VDPU_REG_PRED_FLT1, 22, 0x3ff }, + { 0, 0, 0}, + }, { + { 0, 0, 0}, + { VDPU_REG_PRED_FLT1, 12, 0x3ff }, + { VDPU_REG_PRED_FLT1, 2, 0x3ff }, + { VDPU_REG_PRED_FLT2, 22, 0x3ff }, + { VDPU_REG_PRED_FLT2, 12, 0x3ff }, + { 0, 0, 0}, + }, { + { VDPU_REG_PRED_FLT10, 10, 0x3 }, + { VDPU_REG_PRED_FLT2, 2, 0x3ff }, + { VDPU_REG_PRED_FLT3, 22, 0x3ff }, + { VDPU_REG_PRED_FLT3, 12, 0x3ff }, + { VDPU_REG_PRED_FLT3, 2, 0x3ff }, + { VDPU_REG_PRED_FLT10, 8, 0x3}, + }, { + { 0, 0, 0}, + { VDPU_REG_PRED_FLT4, 22, 0x3ff }, + { VDPU_REG_PRED_FLT4, 12, 0x3ff }, + { VDPU_REG_PRED_FLT4, 2, 0x3ff }, + { VDPU_REG_PRED_FLT5, 22, 0x3ff }, + { 0, 0, 0}, + }, { + { VDPU_REG_PRED_FLT10, 6, 0x3 }, + { VDPU_REG_PRED_FLT5, 12, 0x3ff }, + { VDPU_REG_PRED_FLT5, 2, 0x3ff }, + { VDPU_REG_PRED_FLT6, 22, 0x3ff }, + { VDPU_REG_PRED_FLT6, 12, 0x3ff }, + { VDPU_REG_PRED_FLT10, 4, 0x3 }, + }, { + { 0, 0, 0}, + { VDPU_REG_PRED_FLT6, 2, 0x3ff }, + { VDPU_REG_PRED_FLT7, 22, 0x3ff }, + { VDPU_REG_PRED_FLT7, 12, 0x3ff }, + { VDPU_REG_PRED_FLT7, 2, 0x3ff }, + { 0, 0, 0}, + }, { + { VDPU_REG_PRED_FLT10, 2, 0x3 }, + { VDPU_REG_PRED_FLT8, 22, 0x3ff }, + { VDPU_REG_PRED_FLT8, 12, 0x3ff }, + { VDPU_REG_PRED_FLT8, 2, 0x3ff }, + { VDPU_REG_PRED_FLT9, 22, 0x3ff }, + { VDPU_REG_PRED_FLT10, 0, 0x3 }, + }, { + { 0, 0, 0}, + { VDPU_REG_PRED_FLT9, 12, 0x3ff }, + { VDPU_REG_PRED_FLT9, 2, 0x3ff }, + { VDPU_REG_PRED_FLT10, 22, 0x3ff }, + { VDPU_REG_PRED_FLT10, 12, 0x3ff }, + { 0, 0, 0}, + }, +}; + +static const struct hantro_reg vp8_dec_mb_start_bit = { + .base = VDPU_REG_VP8_CTRL0, + .shift = 18, + .mask = 0x3f +}; + +static const struct hantro_reg vp8_dec_mb_aligned_data_len = { + .base = VDPU_REG_VP8_DATA_VAL, + .shift = 0, + .mask = 0x3fffff +}; + +static const struct hantro_reg vp8_dec_num_dct_partitions = { + .base = VDPU_REG_VP8_DATA_VAL, + .shift = 24, + .mask = 0xf +}; + +static const struct hantro_reg vp8_dec_stream_len = { + .base = VDPU_REG_STREAM_LEN, + .shift = 0, + .mask = 0xffffff +}; + +static const struct hantro_reg vp8_dec_mb_width = { + .base = VDPU_REG_VP8_PIC_MB_SIZE, + .shift = 23, + .mask = 0x1ff +}; + +static const struct hantro_reg vp8_dec_mb_height = { + .base = VDPU_REG_VP8_PIC_MB_SIZE, + .shift = 11, + .mask = 0xff +}; + +static const struct hantro_reg vp8_dec_mb_width_ext = { + .base = VDPU_REG_VP8_PIC_MB_SIZE, + .shift = 3, + .mask = 0x7 +}; + +static const struct hantro_reg vp8_dec_mb_height_ext = { + .base = VDPU_REG_VP8_PIC_MB_SIZE, + .shift = 0, + .mask = 0x7 +}; + +static const struct hantro_reg vp8_dec_bool_range = { + .base = VDPU_REG_VP8_CTRL0, + .shift = 0, + .mask = 0xff +}; + +static const struct hantro_reg vp8_dec_bool_value = { + .base = VDPU_REG_VP8_CTRL0, + .shift = 8, + .mask = 0xff +}; + +static const struct hantro_reg vp8_dec_filter_disable = { + .base = VDPU_REG_DEC_CTRL0, + .shift = 8, + .mask = 1 +}; + +static const struct hantro_reg vp8_dec_skip_mode = { + .base = VDPU_REG_DEC_CTRL0, + .shift = 9, + .mask = 1 +}; + +static const struct hantro_reg vp8_dec_start_dec = { + .base = VDPU_REG_EN_FLAGS, + .shift = 0, + .mask = 1 +}; + +static void cfg_lf(struct hantro_ctx *ctx, + const struct v4l2_ctrl_vp8_frame_header *hdr) +{ + const struct v4l2_vp8_segment_header *seg = &hdr->segment_header; + const struct v4l2_vp8_loopfilter_header *lf = &hdr->lf_header; + struct hantro_dev *vpu = ctx->dev; + unsigned int i; + u32 reg; + + if (!(seg->flags & V4L2_VP8_SEGMENT_HEADER_FLAG_ENABLED)) { + hantro_reg_write(vpu, &vp8_dec_lf_level[0], lf->level); + } else if (seg->flags & V4L2_VP8_SEGMENT_HEADER_FLAG_DELTA_VALUE_MODE) { + for (i = 0; i < 4; i++) { + u32 lf_level = clamp(lf->level + seg->lf_update[i], + 0, 63); + + hantro_reg_write(vpu, &vp8_dec_lf_level[i], lf_level); + } + } else { + for (i = 0; i < 4; i++) + hantro_reg_write(vpu, &vp8_dec_lf_level[i], + seg->lf_update[i]); + } + + reg = VDPU_REG_REF_PIC_FILT_SHARPNESS(lf->sharpness_level); + if (lf->flags & V4L2_VP8_LF_FILTER_TYPE_SIMPLE) + reg |= VDPU_REG_REF_PIC_FILT_TYPE_E; + vdpu_write_relaxed(vpu, reg, VDPU_REG_FILTER_MB_ADJ); + + if (lf->flags & V4L2_VP8_LF_HEADER_ADJ_ENABLE) { + for (i = 0; i < 4; i++) { + hantro_reg_write(vpu, &vp8_dec_mb_adj[i], + lf->mb_mode_delta[i]); + hantro_reg_write(vpu, &vp8_dec_ref_adj[i], + lf->ref_frm_delta[i]); + } + } +} + +static void cfg_qp(struct hantro_ctx *ctx, + const struct v4l2_ctrl_vp8_frame_header *hdr) +{ + const struct v4l2_vp8_quantization_header *q = &hdr->quant_header; + const struct v4l2_vp8_segment_header *seg = &hdr->segment_header; + struct hantro_dev *vpu = ctx->dev; + unsigned int i; + + if (!(seg->flags & V4L2_VP8_SEGMENT_HEADER_FLAG_ENABLED)) { + hantro_reg_write(vpu, &vp8_dec_quant[0], q->y_ac_qi); + } else if (seg->flags & V4L2_VP8_SEGMENT_HEADER_FLAG_DELTA_VALUE_MODE) { + for (i = 0; i < 4; i++) { + u32 quant = clamp(q->y_ac_qi + seg->quant_update[i], + 0, 127); + + hantro_reg_write(vpu, &vp8_dec_quant[i], quant); + } + } else { + for (i = 0; i < 4; i++) + hantro_reg_write(vpu, &vp8_dec_quant[i], + seg->quant_update[i]); + } + + hantro_reg_write(vpu, &vp8_dec_quant_delta[0], q->y_dc_delta); + hantro_reg_write(vpu, &vp8_dec_quant_delta[1], q->y2_dc_delta); + hantro_reg_write(vpu, &vp8_dec_quant_delta[2], q->y2_ac_delta); + hantro_reg_write(vpu, &vp8_dec_quant_delta[3], q->uv_dc_delta); + hantro_reg_write(vpu, &vp8_dec_quant_delta[4], q->uv_ac_delta); +} + +static void cfg_parts(struct hantro_ctx *ctx, + const struct v4l2_ctrl_vp8_frame_header *hdr) +{ + struct hantro_dev *vpu = ctx->dev; + struct vb2_v4l2_buffer *vb2_src; + u32 first_part_offset = VP8_FRAME_IS_KEY_FRAME(hdr) ? 10 : 3; + u32 mb_size, mb_offset_bytes, mb_offset_bits, mb_start_bits; + u32 dct_size_part_size, dct_part_offset; + dma_addr_t src_dma; + u32 dct_part_total_len = 0; + u32 count = 0; + unsigned int i; + + vb2_src = hantro_get_src_buf(ctx); + src_dma = vb2_dma_contig_plane_dma_addr(&vb2_src->vb2_buf, 0); + + /* + * Calculate control partition mb data info + * @first_part_header_bits: bits offset of mb data from first + * part start pos + * @mb_offset_bits: bits offset of mb data from src_dma + * base addr + * @mb_offset_byte: bytes offset of mb data from src_dma + * base addr + * @mb_start_bits: bits offset of mb data from mb data + * 64bits alignment addr + */ + mb_offset_bits = first_part_offset * 8 + + hdr->first_part_header_bits + 8; + mb_offset_bytes = mb_offset_bits / 8; + mb_start_bits = mb_offset_bits - + (mb_offset_bytes & (~DEC_8190_ALIGN_MASK)) * 8; + mb_size = hdr->first_part_size - + (mb_offset_bytes - first_part_offset) + + (mb_offset_bytes & DEC_8190_ALIGN_MASK); + + /* Macroblock data aligned base addr */ + vdpu_write_relaxed(vpu, (mb_offset_bytes & (~DEC_8190_ALIGN_MASK)) + + src_dma, VDPU_REG_VP8_ADDR_CTRL_PART); + hantro_reg_write(vpu, &vp8_dec_mb_start_bit, mb_start_bits); + hantro_reg_write(vpu, &vp8_dec_mb_aligned_data_len, mb_size); + + /* + * Calculate DCT partition info + * @dct_size_part_size: Containing sizes of DCT part, every DCT part + * has 3 bytes to store its size, except the last + * DCT part + * @dct_part_offset: bytes offset of DCT parts from src_dma base addr + * @dct_part_total_len: total size of all DCT parts + */ + dct_size_part_size = (hdr->num_dct_parts - 1) * 3; + dct_part_offset = first_part_offset + hdr->first_part_size; + for (i = 0; i < hdr->num_dct_parts; i++) + dct_part_total_len += hdr->dct_part_sizes[i]; + dct_part_total_len += dct_size_part_size; + dct_part_total_len += (dct_part_offset & DEC_8190_ALIGN_MASK); + + /* Number of DCT partitions */ + hantro_reg_write(vpu, &vp8_dec_num_dct_partitions, + hdr->num_dct_parts - 1); + + /* DCT partition length */ + hantro_reg_write(vpu, &vp8_dec_stream_len, dct_part_total_len); + + /* DCT partitions base address */ + for (i = 0; i < hdr->num_dct_parts; i++) { + u32 byte_offset = dct_part_offset + dct_size_part_size + count; + u32 base_addr = byte_offset + src_dma; + + hantro_reg_write(vpu, &vp8_dec_dct_base[i], + base_addr & (~DEC_8190_ALIGN_MASK)); + + hantro_reg_write(vpu, &vp8_dec_dct_start_bits[i], + (byte_offset & DEC_8190_ALIGN_MASK) * 8); + + count += hdr->dct_part_sizes[i]; + } +} + +/* + * prediction filter taps + * normal 6-tap filters + */ +static void cfg_tap(struct hantro_ctx *ctx, + const struct v4l2_ctrl_vp8_frame_header *hdr) +{ + struct hantro_dev *vpu = ctx->dev; + int i, j; + + if ((hdr->version & 0x03) != 0) + return; /* Tap filter not used. */ + + for (i = 0; i < 8; i++) { + for (j = 0; j < 6; j++) { + if (vp8_dec_pred_bc_tap[i][j].base != 0) + hantro_reg_write(vpu, + &vp8_dec_pred_bc_tap[i][j], + vp8_dec_mc_filter[i][j]); + } + } +} + +static void cfg_ref(struct hantro_ctx *ctx, + const struct v4l2_ctrl_vp8_frame_header *hdr) +{ + struct hantro_dev *vpu = ctx->dev; + struct vb2_v4l2_buffer *vb2_dst; + struct vb2_queue *cap_q; + dma_addr_t ref; + + cap_q = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + vb2_dst = hantro_get_dst_buf(ctx); + + ref = hantro_get_ref(cap_q, hdr->last_frame_ts); + if (!ref) + ref = vb2_dma_contig_plane_dma_addr(&vb2_dst->vb2_buf, 0); + vdpu_write_relaxed(vpu, ref, VDPU_REG_VP8_ADDR_REF0); + + ref = hantro_get_ref(cap_q, hdr->golden_frame_ts); + WARN_ON(!ref && hdr->golden_frame_ts); + if (!ref) + ref = vb2_dma_contig_plane_dma_addr(&vb2_dst->vb2_buf, 0); + if (hdr->flags & V4L2_VP8_FRAME_HEADER_FLAG_SIGN_BIAS_GOLDEN) + ref |= VDPU_REG_VP8_GREF_SIGN_BIAS; + vdpu_write_relaxed(vpu, ref, VDPU_REG_VP8_ADDR_REF2_5(2)); + + ref = hantro_get_ref(cap_q, hdr->alt_frame_ts); + WARN_ON(!ref && hdr->alt_frame_ts); + if (!ref) + ref = vb2_dma_contig_plane_dma_addr(&vb2_dst->vb2_buf, 0); + if (hdr->flags & V4L2_VP8_FRAME_HEADER_FLAG_SIGN_BIAS_ALT) + ref |= VDPU_REG_VP8_AREF_SIGN_BIAS; + vdpu_write_relaxed(vpu, ref, VDPU_REG_VP8_ADDR_REF2_5(3)); +} + +static void cfg_buffers(struct hantro_ctx *ctx, + const struct v4l2_ctrl_vp8_frame_header *hdr) +{ + const struct v4l2_vp8_segment_header *seg = &hdr->segment_header; + struct hantro_dev *vpu = ctx->dev; + struct vb2_v4l2_buffer *vb2_dst; + dma_addr_t dst_dma; + u32 reg; + + vb2_dst = hantro_get_dst_buf(ctx); + + /* Set probability table buffer address */ + vdpu_write_relaxed(vpu, ctx->vp8_dec.prob_tbl.dma, + VDPU_REG_ADDR_QTABLE); + + /* Set segment map address */ + reg = VDPU_REG_FWD_PIC1_SEGMENT_BASE(ctx->vp8_dec.segment_map.dma); + if (seg->flags & V4L2_VP8_SEGMENT_HEADER_FLAG_ENABLED) { + reg |= VDPU_REG_FWD_PIC1_SEGMENT_E; + if (seg->flags & V4L2_VP8_SEGMENT_HEADER_FLAG_UPDATE_MAP) + reg |= VDPU_REG_FWD_PIC1_SEGMENT_UPD_E; + } + vdpu_write_relaxed(vpu, reg, VDPU_REG_VP8_SEGMENT_VAL); + + /* set output frame buffer address */ + dst_dma = vb2_dma_contig_plane_dma_addr(&vb2_dst->vb2_buf, 0); + vdpu_write_relaxed(vpu, dst_dma, VDPU_REG_ADDR_DST); +} + +void rk3399_vpu_vp8_dec_run(struct hantro_ctx *ctx) +{ + const struct v4l2_ctrl_vp8_frame_header *hdr; + struct hantro_dev *vpu = ctx->dev; + size_t height = ctx->dst_fmt.height; + size_t width = ctx->dst_fmt.width; + u32 mb_width, mb_height; + u32 reg; + + hantro_prepare_run(ctx); + + hdr = hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_VP8_FRAME_HEADER); + if (WARN_ON(!hdr)) + return; + + /* Reset segment_map buffer in keyframe */ + if (VP8_FRAME_IS_KEY_FRAME(hdr) && ctx->vp8_dec.segment_map.cpu) + memset(ctx->vp8_dec.segment_map.cpu, 0, + ctx->vp8_dec.segment_map.size); + + hantro_vp8_prob_update(ctx, hdr); + + /* + * Extensive testing shows that the hardware does not properly + * clear the internal state from previous a decoding run. This + * causes corruption in decoded frames for multi-instance use cases. + * A soft reset before programming the registers has been found + * to resolve those problems. + */ + ctx->codec_ops->reset(ctx); + + reg = VDPU_REG_CONFIG_DEC_TIMEOUT_E + | VDPU_REG_CONFIG_DEC_CLK_GATE_E; + if (!VP8_FRAME_IS_KEY_FRAME(hdr)) + reg |= VDPU_REG_DEC_CTRL0_PIC_INTER_E; + vdpu_write_relaxed(vpu, reg, VDPU_REG_EN_FLAGS); + + reg = VDPU_REG_CONFIG_DEC_STRENDIAN_E + | VDPU_REG_CONFIG_DEC_INSWAP32_E + | VDPU_REG_CONFIG_DEC_STRSWAP32_E + | VDPU_REG_CONFIG_DEC_OUTSWAP32_E + | VDPU_REG_CONFIG_DEC_IN_ENDIAN + | VDPU_REG_CONFIG_DEC_OUT_ENDIAN; + vdpu_write_relaxed(vpu, reg, VDPU_REG_DATA_ENDIAN); + + reg = VDPU_REG_CONFIG_DEC_MAX_BURST(16); + vdpu_write_relaxed(vpu, reg, VDPU_REG_AXI_CTRL); + + reg = VDPU_REG_DEC_CTRL0_DEC_MODE(10); + vdpu_write_relaxed(vpu, reg, VDPU_REG_DEC_FORMAT); + + if (!(hdr->flags & V4L2_VP8_FRAME_HEADER_FLAG_MB_NO_SKIP_COEFF)) + hantro_reg_write(vpu, &vp8_dec_skip_mode, 1); + if (hdr->lf_header.level == 0) + hantro_reg_write(vpu, &vp8_dec_filter_disable, 1); + + /* Frame dimensions */ + mb_width = VP8_MB_WIDTH(width); + mb_height = VP8_MB_HEIGHT(height); + + hantro_reg_write(vpu, &vp8_dec_mb_width, mb_width); + hantro_reg_write(vpu, &vp8_dec_mb_height, mb_height); + hantro_reg_write(vpu, &vp8_dec_mb_width_ext, mb_width >> 9); + hantro_reg_write(vpu, &vp8_dec_mb_height_ext, mb_height >> 8); + + /* Boolean decoder */ + hantro_reg_write(vpu, &vp8_dec_bool_range, hdr->coder_state.range); + hantro_reg_write(vpu, &vp8_dec_bool_value, hdr->coder_state.value); + + reg = vdpu_read(vpu, VDPU_REG_VP8_DCT_START_BIT); + if (hdr->version != 3) + reg |= VDPU_REG_DEC_CTRL4_VC1_HEIGHT_EXT; + if (hdr->version & 0x3) + reg |= VDPU_REG_DEC_CTRL4_BILIN_MC_E; + vdpu_write_relaxed(vpu, reg, VDPU_REG_VP8_DCT_START_BIT); + + cfg_lf(ctx, hdr); + cfg_qp(ctx, hdr); + cfg_parts(ctx, hdr); + cfg_tap(ctx, hdr); + cfg_ref(ctx, hdr); + cfg_buffers(ctx, hdr); + + hantro_finish_run(ctx); + + hantro_reg_write(vpu, &vp8_dec_start_dec, 1); +} -- cgit v1.2.3-59-g8ed1b From 620428820d0d76de5b29314457a3b27c0634b4f2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 25 Jul 2019 12:25:52 -0400 Subject: media: staging: hantro: avoid future namespace collisions Rename: vp8_dec_mc_filter -> hantro_vp8_dec_mc_filter As other drivers may end implementing something with the same name. So, prepend driver's name here, in order to make symbol namespace cleaner. Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/hantro/hantro_g1_vp8_dec.c | 5 +++-- drivers/staging/media/hantro/hantro_hw.h | 2 +- drivers/staging/media/hantro/hantro_vp8.c | 2 +- drivers/staging/media/hantro/rk3399_vpu_hw_vp8_dec.c | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/hantro/hantro_g1_vp8_dec.c b/drivers/staging/media/hantro/hantro_g1_vp8_dec.c index 181e2f76d8cb..6d99c2be01cf 100644 --- a/drivers/staging/media/hantro/hantro_g1_vp8_dec.c +++ b/drivers/staging/media/hantro/hantro_g1_vp8_dec.c @@ -342,11 +342,12 @@ static void cfg_tap(struct hantro_ctx *ctx, return; /* Tap filter not used. */ for (i = 0; i < 8; i++) { - val = (vp8_dec_mc_filter[i][0] << 2) | vp8_dec_mc_filter[i][5]; + val = (hantro_vp8_dec_mc_filter[i][0] << 2) | + hantro_vp8_dec_mc_filter[i][5]; for (j = 0; j < 4; j++) hantro_reg_write(vpu, &vp8_dec_pred_bc_tap[i][j], - vp8_dec_mc_filter[i][j + 1]); + hantro_vp8_dec_mc_filter[i][j + 1]); switch (i) { case 2: diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/staging/media/hantro/hantro_hw.h index e86c84fbfe1a..2b8029674a75 100644 --- a/drivers/staging/media/hantro/hantro_hw.h +++ b/drivers/staging/media/hantro/hantro_hw.h @@ -95,7 +95,7 @@ extern const struct hantro_variant rk3399_vpu_variant; extern const struct hantro_variant rk3328_vpu_variant; extern const struct hantro_variant rk3288_vpu_variant; -extern const u32 vp8_dec_mc_filter[8][6]; +extern const u32 hantro_vp8_dec_mc_filter[8][6]; void hantro_watchdog(struct work_struct *work); void hantro_run(struct hantro_ctx *ctx); diff --git a/drivers/staging/media/hantro/hantro_vp8.c b/drivers/staging/media/hantro/hantro_vp8.c index cd01661cac21..0e02d147b189 100644 --- a/drivers/staging/media/hantro/hantro_vp8.c +++ b/drivers/staging/media/hantro/hantro_vp8.c @@ -35,7 +35,7 @@ struct vp8_prob_tbl_packed { * filter taps taken to 7-bit precision, * reference RFC6386#Page-16, filters[8][6] */ -const u32 vp8_dec_mc_filter[8][6] = { +const u32 hantro_vp8_dec_mc_filter[8][6] = { { 0, 0, 128, 0, 0, 0 }, { 0, -6, 123, 12, -1, 0 }, { 2, -11, 108, 36, -8, 1 }, diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw_vp8_dec.c b/drivers/staging/media/hantro/rk3399_vpu_hw_vp8_dec.c index c5e9f8befe9c..f17e32620b08 100644 --- a/drivers/staging/media/hantro/rk3399_vpu_hw_vp8_dec.c +++ b/drivers/staging/media/hantro/rk3399_vpu_hw_vp8_dec.c @@ -439,7 +439,7 @@ static void cfg_tap(struct hantro_ctx *ctx, if (vp8_dec_pred_bc_tap[i][j].base != 0) hantro_reg_write(vpu, &vp8_dec_pred_bc_tap[i][j], - vp8_dec_mc_filter[i][j]); + hantro_vp8_dec_mc_filter[i][j]); } } } -- cgit v1.2.3-59-g8ed1b From 6b2265975239ab655069d796b822835a593e1cc7 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 24 Jul 2019 23:41:29 -0300 Subject: media: staging: tegra-vde: Fix build error If IOMMU_SUPPORT is not set, and COMPILE_TEST is y, IOMMU_IOVA may be set to m. So building will fails: drivers/staging/media/tegra-vde/iommu.o: In function `tegra_vde_iommu_map': iommu.c:(.text+0x41): undefined reference to `alloc_iova' iommu.c:(.text+0x56): undefined reference to `__free_iova' Select IOMMU_IOVA while COMPILE_TEST is set to fix this. Reported-by: Hulk Robot Suggested-by: Dmitry Osipenko Fixes: b301f8de1925 ("media: staging: media: tegra-vde: Add IOMMU support") Signed-off-by: YueHaibing Acked-by: Dmitry Osipenko Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/tegra-vde/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/tegra-vde/Kconfig b/drivers/staging/media/tegra-vde/Kconfig index 2e7f644ae591..ba49ea50b8c0 100644 --- a/drivers/staging/media/tegra-vde/Kconfig +++ b/drivers/staging/media/tegra-vde/Kconfig @@ -3,7 +3,7 @@ config TEGRA_VDE tristate "NVIDIA Tegra Video Decoder Engine driver" depends on ARCH_TEGRA || COMPILE_TEST select DMA_SHARED_BUFFER - select IOMMU_IOVA if IOMMU_SUPPORT + select IOMMU_IOVA if (IOMMU_SUPPORT || COMPILE_TEST) select SRAM help Say Y here to enable support for the NVIDIA Tegra video decoder -- cgit v1.2.3-59-g8ed1b From 633eadc9ba1e9a56be09ef94f14578a9839d3634 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Thu, 30 May 2019 18:15:13 -0300 Subject: media: cedrus: Remove dst_bufs from context This array is just duplicated capture buffer queue. Remove it and adjust code to look into capture buffer queue instead. Signed-off-by: Jernej Skrabec Acked-by: Maxime Ripard Acked-by: Paul Kocialkowski Reviewed-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/sunxi/cedrus/cedrus.h | 4 +--- drivers/staging/media/sunxi/cedrus/cedrus_h264.c | 4 ++-- drivers/staging/media/sunxi/cedrus/cedrus_video.c | 22 ---------------------- 3 files changed, 3 insertions(+), 27 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h index 3f476d0fd981..d8e6777e5e27 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.h +++ b/drivers/staging/media/sunxi/cedrus/cedrus.h @@ -100,8 +100,6 @@ struct cedrus_ctx { struct v4l2_ctrl_handler hdl; struct v4l2_ctrl **ctrls; - struct vb2_buffer *dst_bufs[VIDEO_MAX_FRAME]; - union { struct { void *mv_col_buf; @@ -187,7 +185,7 @@ static inline dma_addr_t cedrus_dst_buf_addr(struct cedrus_ctx *ctx, if (index < 0) return 0; - buf = ctx->dst_bufs[index]; + buf = ctx->fh.m2m_ctx->cap_q_ctx.q.bufs[index]; return buf ? cedrus_buf_addr(buf, &ctx->dst_fmt, plane) : 0; } diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c index a30bb283f69f..d6a782703c9b 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c @@ -118,7 +118,7 @@ static void cedrus_write_frame_list(struct cedrus_ctx *ctx, if (buf_idx < 0) continue; - cedrus_buf = vb2_to_cedrus_buffer(ctx->dst_bufs[buf_idx]); + cedrus_buf = vb2_to_cedrus_buffer(cap_q->bufs[buf_idx]); position = cedrus_buf->codec.h264.position; used_dpbs |= BIT(position); @@ -193,7 +193,7 @@ static void _cedrus_write_ref_list(struct cedrus_ctx *ctx, if (buf_idx < 0) continue; - ref_buf = to_vb2_v4l2_buffer(ctx->dst_bufs[buf_idx]); + ref_buf = to_vb2_v4l2_buffer(cap_q->bufs[buf_idx]); cedrus_buf = vb2_v4l2_to_cedrus_buffer(ref_buf); position = cedrus_buf->codec.h264.position; diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_video.c b/drivers/staging/media/sunxi/cedrus/cedrus_video.c index e2b530b1a956..681dfe3367a6 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_video.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.c @@ -411,26 +411,6 @@ static void cedrus_queue_cleanup(struct vb2_queue *vq, u32 state) } } -static int cedrus_buf_init(struct vb2_buffer *vb) -{ - struct vb2_queue *vq = vb->vb2_queue; - struct cedrus_ctx *ctx = vb2_get_drv_priv(vq); - - if (!V4L2_TYPE_IS_OUTPUT(vq->type)) - ctx->dst_bufs[vb->index] = vb; - - return 0; -} - -static void cedrus_buf_cleanup(struct vb2_buffer *vb) -{ - struct vb2_queue *vq = vb->vb2_queue; - struct cedrus_ctx *ctx = vb2_get_drv_priv(vq); - - if (!V4L2_TYPE_IS_OUTPUT(vq->type)) - ctx->dst_bufs[vb->index] = NULL; -} - static int cedrus_buf_out_validate(struct vb2_buffer *vb) { struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); @@ -517,8 +497,6 @@ static void cedrus_buf_request_complete(struct vb2_buffer *vb) static struct vb2_ops cedrus_qops = { .queue_setup = cedrus_queue_setup, .buf_prepare = cedrus_buf_prepare, - .buf_init = cedrus_buf_init, - .buf_cleanup = cedrus_buf_cleanup, .buf_queue = cedrus_buf_queue, .buf_out_validate = cedrus_buf_out_validate, .buf_request_complete = cedrus_buf_request_complete, -- cgit v1.2.3-59-g8ed1b From b557b5073194d63bcd2850c009f9326250b4bd97 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Thu, 30 May 2019 18:15:14 -0300 Subject: media: cedrus: Don't set chroma size for scale & rotation Scale and rotation are currently not implemented, so it makes no sense to set chroma size for it. Signed-off-by: Jernej Skrabec Acked-by: Paul Kocialkowski Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/sunxi/cedrus/cedrus_hw.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_hw.c b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c index c34aec7c6e40..fc8579b90dab 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_hw.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c @@ -79,9 +79,6 @@ void cedrus_dst_format_set(struct cedrus_dev *dev, reg = VE_PRIMARY_OUT_FMT_NV12; cedrus_write(dev, VE_PRIMARY_OUT_FMT, reg); - reg = VE_CHROMA_BUF_LEN_SDRT(chroma_size / 2); - cedrus_write(dev, VE_CHROMA_BUF_LEN, reg); - reg = chroma_size / 2; cedrus_write(dev, VE_PRIMARY_CHROMA_BUF_LEN, reg); -- cgit v1.2.3-59-g8ed1b From 0d5078c7172c46db6c58718d817b9fcf769554b4 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 27 Jun 2019 19:29:12 -0300 Subject: media: imx: mipi csi-2: Don't fail if initial state times-out Not all sensors will be able to guarantee a proper initial state. This may be either because the driver is not properly written, or (probably unlikely) because the hardware won't support it. While the right solution in the former case is to fix the sensor driver, the real world not always allows right solutions, due to lack of available documentation and support on these sensors. Let's relax this requirement, and allow the driver to support stream start, even if the sensor initial sequence wasn't the expected. Also improve the warning message to better explain the problem and provide a hint that the sensor driver needs to be fixed. Signed-off-by: Ezequiel Garcia Signed-off-by: Fabio Estevam Reviewed-by: Steve Longerbeam Reviewed-by: Philipp Zabel Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/imx/imx6-mipi-csi2.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/imx/imx6-mipi-csi2.c b/drivers/staging/media/imx/imx6-mipi-csi2.c index f29e28df36ed..bfa4b254c4e4 100644 --- a/drivers/staging/media/imx/imx6-mipi-csi2.c +++ b/drivers/staging/media/imx/imx6-mipi-csi2.c @@ -243,7 +243,7 @@ static int __maybe_unused csi2_dphy_wait_ulp(struct csi2_dev *csi2) } /* Waits for low-power LP-11 state on data and clock lanes. */ -static int csi2_dphy_wait_stopstate(struct csi2_dev *csi2) +static void csi2_dphy_wait_stopstate(struct csi2_dev *csi2) { u32 mask, reg; int ret; @@ -254,11 +254,9 @@ static int csi2_dphy_wait_stopstate(struct csi2_dev *csi2) ret = readl_poll_timeout(csi2->base + CSI2_PHY_STATE, reg, (reg & mask) == mask, 0, 500000); if (ret) { - v4l2_err(&csi2->sd, "LP-11 timeout, phy_state = 0x%08x\n", reg); - return ret; + v4l2_warn(&csi2->sd, "LP-11 wait timeout, likely a sensor driver bug, expect capture failures.\n"); + v4l2_warn(&csi2->sd, "phy_state = 0x%08x\n", reg); } - - return 0; } /* Wait for active clock on the clock lane. */ @@ -316,9 +314,7 @@ static int csi2_start(struct csi2_dev *csi2) csi2_enable(csi2, true); /* Step 5 */ - ret = csi2_dphy_wait_stopstate(csi2); - if (ret) - goto err_assert_reset; + csi2_dphy_wait_stopstate(csi2); /* Step 6 */ ret = v4l2_subdev_call(csi2->src_sd, video, s_stream, 1); -- cgit v1.2.3-59-g8ed1b From 0486a18ce82bd00d69ddc0fab8faa4b80df2117b Mon Sep 17 00:00:00 2001 From: Sébastien Szymanski Date: Wed, 31 Jul 2019 13:33:30 -0300 Subject: media: imx7-media-csi: add i.MX6UL support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit i.MX7 and i.MX6UL/L have the same CSI controller. So add i.MX6UL/L support to imx7-media-csi driver. Signed-off-by: Sébastien Szymanski Reviewed-by: Rui Miguel Silva Reviewed-by: Fabio Estevam Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/imx/Kconfig | 4 ++-- drivers/staging/media/imx/imx7-media-csi.c | 30 +++++++++++++++++++++--------- 2 files changed, 23 insertions(+), 11 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/imx/Kconfig b/drivers/staging/media/imx/Kconfig index 4c726345dc25..f51476243016 100644 --- a/drivers/staging/media/imx/Kconfig +++ b/drivers/staging/media/imx/Kconfig @@ -22,11 +22,11 @@ config VIDEO_IMX_CSI A video4linux camera sensor interface driver for i.MX5/6. config VIDEO_IMX7_CSI - tristate "i.MX7 Camera Sensor Interface driver" + tristate "i.MX6UL/L / i.MX7 Camera Sensor Interface driver" depends on VIDEO_IMX_MEDIA && VIDEO_DEV && I2C default y help Enable support for video4linux camera sensor interface driver for - i.MX7. + i.MX6UL/L or i.MX7. endmenu endif diff --git a/drivers/staging/media/imx/imx7-media-csi.c b/drivers/staging/media/imx/imx7-media-csi.c index 500b4c08d967..4ca79ff4c9b3 100644 --- a/drivers/staging/media/imx/imx7-media-csi.c +++ b/drivers/staging/media/imx/imx7-media-csi.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * V4L2 Capture CSI Subdev for Freescale i.MX7 SOC + * V4L2 Capture CSI Subdev for Freescale i.MX6UL/L / i.MX7 SOC * * Copyright (c) 2019 Linaro Ltd * @@ -765,6 +765,7 @@ static int imx7_csi_configure(struct imx7_csi *csi) struct v4l2_pix_format *out_pix = &vdev->fmt.fmt.pix; __u32 in_code = csi->format_mbus[IMX7_CSI_PAD_SINK].code; u32 cr1, cr18; + int width = out_pix->width; if (out_pix->field == V4L2_FIELD_INTERLACED) { imx7_csi_deinterlace_enable(csi, true); @@ -774,15 +775,27 @@ static int imx7_csi_configure(struct imx7_csi *csi) imx7_csi_buf_stride_set(csi, 0); } - imx7_csi_set_imagpara(csi, out_pix->width, out_pix->height); + cr18 = imx7_csi_reg_read(csi, CSI_CSICR18); + + if (!csi->is_csi2) { + if (out_pix->pixelformat == V4L2_PIX_FMT_UYVY || + out_pix->pixelformat == V4L2_PIX_FMT_YUYV) + width *= 2; + + imx7_csi_set_imagpara(csi, width, out_pix->height); + + cr18 |= (BIT_BASEADDR_SWITCH_EN | BIT_BASEADDR_SWITCH_SEL | + BIT_BASEADDR_CHG_ERR_EN); + imx7_csi_reg_write(csi, cr18, CSI_CSICR18); - if (!csi->is_csi2) return 0; + } + + imx7_csi_set_imagpara(csi, width, out_pix->height); cr1 = imx7_csi_reg_read(csi, CSI_CSICR1); cr1 &= ~BIT_GCLK_MODE; - cr18 = imx7_csi_reg_read(csi, CSI_CSICR18); cr18 &= BIT_MIPI_DATA_FORMAT_MASK; cr18 |= BIT_DATA_FROM_MIPI; @@ -817,11 +830,9 @@ static void imx7_csi_enable(struct imx7_csi *csi) { imx7_csi_sw_reset(csi); - if (csi->is_csi2) { - imx7_csi_dmareq_rff_enable(csi); - imx7_csi_hw_enable_irq(csi); - imx7_csi_hw_enable(csi); - } + imx7_csi_dmareq_rff_enable(csi); + imx7_csi_hw_enable_irq(csi); + imx7_csi_hw_enable(csi); } static void imx7_csi_disable(struct imx7_csi *csi) @@ -1302,6 +1313,7 @@ static int imx7_csi_remove(struct platform_device *pdev) static const struct of_device_id imx7_csi_of_match[] = { { .compatible = "fsl,imx7-csi" }, + { .compatible = "fsl,imx6ul-csi" }, { }, }; MODULE_DEVICE_TABLE(of, imx7_csi_of_match); -- cgit v1.2.3-59-g8ed1b From 7bb3c32abd7bafd346f667cccb7dfe9686f14ddd Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Fri, 16 Aug 2019 13:01:23 -0300 Subject: media: uapi: h264: Rename pixel format The V4L2_PIX_FMT_H264_SLICE_RAW name was originally suggested because the pixel format would represent H264 slices without any start code. However, as we will now introduce a start code menu control, give the pixel format a more meaningful name, while it's still early enough to do so. Signed-off-by: Ezequiel Garcia Tested-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/media/uapi/v4l/pixfmt-compressed.rst | 4 ++-- drivers/media/v4l2-core/v4l2-ioctl.c | 2 +- drivers/staging/media/sunxi/cedrus/cedrus_dec.c | 2 +- drivers/staging/media/sunxi/cedrus/cedrus_video.c | 6 +++--- include/media/h264-ctrls.h | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/staging') diff --git a/Documentation/media/uapi/v4l/pixfmt-compressed.rst b/Documentation/media/uapi/v4l/pixfmt-compressed.rst index f52a7b67023d..9b65473a2288 100644 --- a/Documentation/media/uapi/v4l/pixfmt-compressed.rst +++ b/Documentation/media/uapi/v4l/pixfmt-compressed.rst @@ -52,9 +52,9 @@ Compressed Formats - ``V4L2_PIX_FMT_H264_MVC`` - 'M264' - H264 MVC video elementary stream. - * .. _V4L2-PIX-FMT-H264-SLICE-RAW: + * .. _V4L2-PIX-FMT-H264-SLICE: - - ``V4L2_PIX_FMT_H264_SLICE_RAW`` + - ``V4L2_PIX_FMT_H264_SLICE`` - 'S264' - H264 parsed slice data, without the start code and as extracted from the H264 bitstream. This format is adapted for diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index bb5b4926538a..39f10621c91b 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1343,7 +1343,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_PIX_FMT_H264: descr = "H.264"; break; case V4L2_PIX_FMT_H264_NO_SC: descr = "H.264 (No Start Codes)"; break; case V4L2_PIX_FMT_H264_MVC: descr = "H.264 MVC"; break; - case V4L2_PIX_FMT_H264_SLICE_RAW: descr = "H.264 Parsed Slice Data"; break; + case V4L2_PIX_FMT_H264_SLICE: descr = "H.264 Parsed Slice Data"; break; case V4L2_PIX_FMT_H263: descr = "H.263"; break; case V4L2_PIX_FMT_MPEG1: descr = "MPEG-1 ES"; break; case V4L2_PIX_FMT_MPEG2: descr = "MPEG-2 ES"; break; diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c index bdad87eb9d79..56ca4c9ad01c 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c @@ -46,7 +46,7 @@ void cedrus_device_run(void *priv) V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION); break; - case V4L2_PIX_FMT_H264_SLICE_RAW: + case V4L2_PIX_FMT_H264_SLICE: run.h264.decode_params = cedrus_find_control_data(ctx, V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS); run.h264.pps = cedrus_find_control_data(ctx, diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_video.c b/drivers/staging/media/sunxi/cedrus/cedrus_video.c index 681dfe3367a6..eeee3efd247b 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_video.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.c @@ -38,7 +38,7 @@ static struct cedrus_format cedrus_formats[] = { .directions = CEDRUS_DECODE_SRC, }, { - .pixelformat = V4L2_PIX_FMT_H264_SLICE_RAW, + .pixelformat = V4L2_PIX_FMT_H264_SLICE, .directions = CEDRUS_DECODE_SRC, }, { @@ -104,7 +104,7 @@ static void cedrus_prepare_format(struct v4l2_pix_format *pix_fmt) switch (pix_fmt->pixelformat) { case V4L2_PIX_FMT_MPEG2_SLICE: - case V4L2_PIX_FMT_H264_SLICE_RAW: + case V4L2_PIX_FMT_H264_SLICE: /* Zero bytes per line for encoded source. */ bytesperline = 0; @@ -449,7 +449,7 @@ static int cedrus_start_streaming(struct vb2_queue *vq, unsigned int count) ctx->current_codec = CEDRUS_CODEC_MPEG2; break; - case V4L2_PIX_FMT_H264_SLICE_RAW: + case V4L2_PIX_FMT_H264_SLICE: ctx->current_codec = CEDRUS_CODEC_H264; break; diff --git a/include/media/h264-ctrls.h b/include/media/h264-ctrls.h index e1404d78d6ff..6160a69c0143 100644 --- a/include/media/h264-ctrls.h +++ b/include/media/h264-ctrls.h @@ -14,7 +14,7 @@ #include /* Our pixel format isn't stable at the moment */ -#define V4L2_PIX_FMT_H264_SLICE_RAW v4l2_fourcc('S', '2', '6', '4') /* H264 parsed slices */ +#define V4L2_PIX_FMT_H264_SLICE v4l2_fourcc('S', '2', '6', '4') /* H264 parsed slices */ /* * This is put insanely high to avoid conflicting with controls that -- cgit v1.2.3-59-g8ed1b From 3f715c64be6e6e1e1bb140fb1179ab0a712f94c3 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Fri, 16 Aug 2019 13:01:27 -0300 Subject: media: cedrus: Cleanup control initialization In order to introduce other controls, the control initialization needs to support an initial struct v4l2_ctrl_control. While here, let's cleanup the control initialization, removing unneeded fields. Signed-off-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/sunxi/cedrus/cedrus.c | 45 +++++++++++++++-------------- drivers/staging/media/sunxi/cedrus/cedrus.h | 3 +- 2 files changed, 25 insertions(+), 23 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c index 370937edfc14..7bdc413bf727 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus.c @@ -29,44 +29,51 @@ static const struct cedrus_control cedrus_controls[] = { { - .id = V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS, - .elem_size = sizeof(struct v4l2_ctrl_mpeg2_slice_params), + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS, + }, .codec = CEDRUS_CODEC_MPEG2, .required = true, }, { - .id = V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION, - .elem_size = sizeof(struct v4l2_ctrl_mpeg2_quantization), + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION, + }, .codec = CEDRUS_CODEC_MPEG2, .required = false, }, { - .id = V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS, - .elem_size = sizeof(struct v4l2_ctrl_h264_decode_params), + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS, + }, .codec = CEDRUS_CODEC_H264, .required = true, }, { - .id = V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS, - .elem_size = sizeof(struct v4l2_ctrl_h264_slice_params), + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS, + }, .codec = CEDRUS_CODEC_H264, .required = true, }, { - .id = V4L2_CID_MPEG_VIDEO_H264_SPS, - .elem_size = sizeof(struct v4l2_ctrl_h264_sps), + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_H264_SPS, + }, .codec = CEDRUS_CODEC_H264, .required = true, }, { - .id = V4L2_CID_MPEG_VIDEO_H264_PPS, - .elem_size = sizeof(struct v4l2_ctrl_h264_pps), + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_H264_PPS, + }, .codec = CEDRUS_CODEC_H264, .required = true, }, { - .id = V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX, - .elem_size = sizeof(struct v4l2_ctrl_h264_scaling_matrix), + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX, + }, .codec = CEDRUS_CODEC_H264, .required = true, }, @@ -106,12 +113,8 @@ static int cedrus_init_ctrls(struct cedrus_dev *dev, struct cedrus_ctx *ctx) return -ENOMEM; for (i = 0; i < CEDRUS_CONTROLS_COUNT; i++) { - struct v4l2_ctrl_config cfg = {}; - - cfg.elem_size = cedrus_controls[i].elem_size; - cfg.id = cedrus_controls[i].id; - - ctrl = v4l2_ctrl_new_custom(hdl, &cfg, NULL); + ctrl = v4l2_ctrl_new_custom(hdl, &cedrus_controls[i].cfg, + NULL); if (hdl->error) { v4l2_err(&dev->v4l2_dev, "Failed to create new custom control\n"); @@ -178,7 +181,7 @@ static int cedrus_request_validate(struct media_request *req) continue; ctrl_test = v4l2_ctrl_request_hdl_ctrl_find(hdl, - cedrus_controls[i].id); + cedrus_controls[i].cfg.id); if (!ctrl_test) { v4l2_info(&ctx->dev->v4l2_dev, "Missing required codec control\n"); diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h index d8e6777e5e27..2f017a651848 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.h +++ b/drivers/staging/media/sunxi/cedrus/cedrus.h @@ -49,8 +49,7 @@ enum cedrus_h264_pic_type { }; struct cedrus_control { - u32 id; - u32 elem_size; + struct v4l2_ctrl_config cfg; enum cedrus_codec codec; unsigned char required:1; }; -- cgit v1.2.3-59-g8ed1b From 341772b82a3b83e7a7a2c0605c8c728e81b38319 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Fri, 16 Aug 2019 13:01:28 -0300 Subject: media: cedrus: Specify H264 startcode and decoding mode The cedrus VPU is slice-based and expects V4L2_PIX_FMT_H264_SLICE buffers to contain H264 slices with no start code. Expose this to userspace with the newly added menu control. These two controls are specified as mandatory for applications, but we mark them as non-required on the driver side for backwards compatibility. Signed-off-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/sunxi/cedrus/cedrus.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers/staging') diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c index 7bdc413bf727..2d3ea8b74dfd 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus.c @@ -77,6 +77,24 @@ static const struct cedrus_control cedrus_controls[] = { .codec = CEDRUS_CODEC_H264, .required = true, }, + { + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_H264_DECODE_MODE, + .max = V4L2_MPEG_VIDEO_H264_DECODE_MODE_SLICE_BASED, + .def = V4L2_MPEG_VIDEO_H264_DECODE_MODE_SLICE_BASED, + }, + .codec = CEDRUS_CODEC_H264, + .required = false, + }, + { + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_H264_START_CODE, + .max = V4L2_MPEG_VIDEO_H264_START_CODE_NONE, + .def = V4L2_MPEG_VIDEO_H264_START_CODE_NONE, + }, + .codec = CEDRUS_CODEC_H264, + .required = false, + }, }; #define CEDRUS_CONTROLS_COUNT ARRAY_SIZE(cedrus_controls) -- cgit v1.2.3-59-g8ed1b From 6c2eb77bf5667c0755f5a9a408f02f949925256d Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 16 Aug 2019 13:01:29 -0300 Subject: media: hantro: Move copy_metadata() before doing a decode operation Some decoders use intra slice/frame references. The capture buffer pointed by these references might be new and thus have invalid timestamp which prevents the decoder logic from retrieving the vb2_buffer object based on the output buf timestamp. Copy all metadata (including the timestamp) before starting the decode operation. Suggested-by: Jonas Karlman Signed-off-by: Boris Brezillon Tested-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/hantro/hantro_drv.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c index 4af6ee80229e..6e2351e46750 100644 --- a/drivers/staging/media/hantro/hantro_drv.c +++ b/drivers/staging/media/hantro/hantro_drv.c @@ -111,8 +111,6 @@ static void hantro_job_finish(struct hantro_dev *vpu, src->sequence = ctx->sequence_out++; dst->sequence = ctx->sequence_cap++; - v4l2_m2m_buf_copy_metadata(src, dst, true); - ret = ctx->buf_finish(ctx, &dst->vb2_buf, bytesused); if (ret) result = VB2_BUF_STATE_ERROR; @@ -178,8 +176,12 @@ void hantro_finish_run(struct hantro_ctx *ctx) static void device_run(void *priv) { struct hantro_ctx *ctx = priv; + struct vb2_v4l2_buffer *src, *dst; int ret; + src = hantro_get_src_buf(ctx); + dst = hantro_get_dst_buf(ctx); + ret = clk_bulk_enable(ctx->dev->variant->num_clocks, ctx->dev->clocks); if (ret) goto err_cancel_job; @@ -187,6 +189,8 @@ static void device_run(void *priv) if (ret < 0) goto err_cancel_job; + v4l2_m2m_buf_copy_metadata(src, dst, true); + ctx->codec_ops->run(ctx); return; -- cgit v1.2.3-59-g8ed1b From a9471e25629b02f8a110232994dc4b63788e766f Mon Sep 17 00:00:00 2001 From: Hertz Wong Date: Fri, 16 Aug 2019 13:01:30 -0300 Subject: media: hantro: Add core bits to support H264 decoding Add helpers and patch hantro_{drv,v4l2}.c to prepare addition of H264 decoding support. Signed-off-by: Hertz Wong Signed-off-by: Boris Brezillon Tested-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/hantro/Makefile | 1 + drivers/staging/media/hantro/hantro.h | 9 +- drivers/staging/media/hantro/hantro_drv.c | 42 ++ drivers/staging/media/hantro/hantro_h264.c | 646 +++++++++++++++++++++++++++++ drivers/staging/media/hantro/hantro_hw.h | 55 +++ drivers/staging/media/hantro/hantro_v4l2.c | 10 + 6 files changed, 762 insertions(+), 1 deletion(-) create mode 100644 drivers/staging/media/hantro/hantro_h264.c (limited to 'drivers/staging') diff --git a/drivers/staging/media/hantro/Makefile b/drivers/staging/media/hantro/Makefile index f5ec597d9e08..0f0d3afb1cca 100644 --- a/drivers/staging/media/hantro/Makefile +++ b/drivers/staging/media/hantro/Makefile @@ -10,6 +10,7 @@ hantro-vpu-y += \ rk3399_vpu_hw_mpeg2_dec.o \ rk3399_vpu_hw_vp8_dec.o \ hantro_jpeg.o \ + hantro_h264.o \ hantro_mpeg2.o \ hantro_vp8.o diff --git a/drivers/staging/media/hantro/hantro.h b/drivers/staging/media/hantro/hantro.h index c4c86c32ea2d..f670bbde4159 100644 --- a/drivers/staging/media/hantro/hantro.h +++ b/drivers/staging/media/hantro/hantro.h @@ -30,6 +30,10 @@ #define VP8_MB_WIDTH(w) DIV_ROUND_UP(w, VP8_MB_DIM) #define VP8_MB_HEIGHT(h) DIV_ROUND_UP(h, VP8_MB_DIM) +#define H264_MB_DIM 16 +#define H264_MB_WIDTH(w) DIV_ROUND_UP(w, H264_MB_DIM) +#define H264_MB_HEIGHT(h) DIV_ROUND_UP(h, H264_MB_DIM) + #define MPEG2_MB_DIM 16 #define MPEG2_MB_WIDTH(w) DIV_ROUND_UP(w, MPEG2_MB_DIM) #define MPEG2_MB_HEIGHT(h) DIV_ROUND_UP(h, MPEG2_MB_DIM) @@ -43,9 +47,9 @@ struct hantro_codec_ops; #define HANTRO_JPEG_ENCODER BIT(0) #define HANTRO_ENCODERS 0x0000ffff - #define HANTRO_MPEG2_DECODER BIT(16) #define HANTRO_VP8_DECODER BIT(17) +#define HANTRO_H264_DECODER BIT(18) #define HANTRO_DECODERS 0xffff0000 /** @@ -102,12 +106,14 @@ struct hantro_variant { * enum hantro_codec_mode - codec operating mode. * @HANTRO_MODE_NONE: No operating mode. Used for RAW video formats. * @HANTRO_MODE_JPEG_ENC: JPEG encoder. + * @HANTRO_MODE_H264_DEC: H264 decoder. * @HANTRO_MODE_MPEG2_DEC: MPEG-2 decoder. * @HANTRO_MODE_VP8_DEC: VP8 decoder. */ enum hantro_codec_mode { HANTRO_MODE_NONE = -1, HANTRO_MODE_JPEG_ENC, + HANTRO_MODE_H264_DEC, HANTRO_MODE_MPEG2_DEC, HANTRO_MODE_VP8_DEC, }; @@ -246,6 +252,7 @@ struct hantro_ctx { /* Specific for particular codec modes. */ union { + struct hantro_h264_dec_hw_ctx h264_dec; struct hantro_jpeg_enc_hw_ctx jpeg_enc; struct hantro_mpeg2_dec_hw_ctx mpeg2_dec; struct hantro_vp8_dec_hw_ctx vp8_dec; diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c index 6e2351e46750..d8b6816b643b 100644 --- a/drivers/staging/media/hantro/hantro_drv.c +++ b/drivers/staging/media/hantro/hantro_drv.c @@ -314,6 +314,48 @@ static const struct hantro_ctrl controls[] = { .cfg = { .id = V4L2_CID_MPEG_VIDEO_VP8_FRAME_HEADER, }, + }, { + .codec = HANTRO_H264_DECODER, + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS, + }, + }, { + .codec = HANTRO_H264_DECODER, + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS, + }, + }, { + .codec = HANTRO_H264_DECODER, + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_H264_SPS, + }, + }, { + .codec = HANTRO_H264_DECODER, + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_H264_PPS, + }, + }, { + .codec = HANTRO_H264_DECODER, + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX, + }, + }, { + .codec = HANTRO_H264_DECODER, + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_H264_DECODE_MODE, + .min = V4L2_MPEG_VIDEO_H264_DECODE_MODE_FRAME_BASED, + .def = V4L2_MPEG_VIDEO_H264_DECODE_MODE_FRAME_BASED, + .max = V4L2_MPEG_VIDEO_H264_DECODE_MODE_FRAME_BASED, + }, + }, { + .codec = HANTRO_H264_DECODER, + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_H264_START_CODE, + .min = V4L2_MPEG_VIDEO_H264_START_CODE_ANNEX_B, + .def = V4L2_MPEG_VIDEO_H264_START_CODE_ANNEX_B, + .max = V4L2_MPEG_VIDEO_H264_START_CODE_ANNEX_B, + }, + }, { }, }; diff --git a/drivers/staging/media/hantro/hantro_h264.c b/drivers/staging/media/hantro/hantro_h264.c new file mode 100644 index 000000000000..0d758e0c0f99 --- /dev/null +++ b/drivers/staging/media/hantro/hantro_h264.c @@ -0,0 +1,646 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Rockchip RK3288 VPU codec driver + * + * Copyright (c) 2014 Rockchip Electronics Co., Ltd. + * Hertz Wong + * Herman Chen + * + * Copyright (C) 2014 Google, Inc. + * Tomasz Figa + */ + +#include +#include +#include + +#include "hantro.h" +#include "hantro_hw.h" + +/* Size with u32 units. */ +#define CABAC_INIT_BUFFER_SIZE (460 * 2) +#define POC_BUFFER_SIZE 34 +#define SCALING_LIST_SIZE (6 * 16 + 6 * 64) + +#define POC_CMP(p0, p1) ((p0) < (p1) ? -1 : 1) + +/* Data structure describing auxiliary buffer format. */ +struct hantro_h264_dec_priv_tbl { + u32 cabac_table[CABAC_INIT_BUFFER_SIZE]; + u32 poc[POC_BUFFER_SIZE]; + u8 scaling_list[SCALING_LIST_SIZE]; +}; + +/* + * Constant CABAC table. + * From drivers/media/platform/rk3288-vpu/rk3288_vpu_hw_h264d.c + * in https://chromium.googlesource.com/chromiumos/third_party/kernel, + * chromeos-3.14 branch. + */ +static const u32 h264_cabac_table[] = { + 0x14f10236, 0x034a14f1, 0x0236034a, 0xe47fe968, 0xfa35ff36, 0x07330000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x0029003f, 0x003f003f, 0xf7530456, 0x0061f948, 0x0d29033e, 0x000b0137, + 0x0045ef7f, 0xf3660052, 0xf94aeb6b, 0xe57fe17f, 0xe87fee5f, 0xe57feb72, + 0xe27fef7b, 0xf473f07a, 0xf573f43f, 0xfe44f154, 0xf368fd46, 0xf85df65a, + 0xe27fff4a, 0xfa61f95b, 0xec7ffc38, 0xfb52f94c, 0xea7df95d, 0xf557fd4d, + 0xfb47fc3f, 0xfc44f454, 0xf93ef941, 0x083d0538, 0xfe420140, 0x003dfe4e, + 0x01320734, 0x0a23002c, 0x0b26012d, 0x002e052c, 0x1f110133, 0x07321c13, + 0x10210e3e, 0xf36cf164, 0xf365f35b, 0xf45ef658, 0xf054f656, 0xf953f357, + 0xed5e0146, 0x0048fb4a, 0x123bf866, 0xf164005f, 0xfc4b0248, 0xf54bfd47, + 0x0f2ef345, 0x003e0041, 0x1525f148, 0x09391036, 0x003e0c48, 0x18000f09, + 0x08190d12, 0x0f090d13, 0x0a250c12, 0x061d1421, 0x0f1e042d, 0x013a003e, + 0x073d0c26, 0x0b2d0f27, 0x0b2a0d2c, 0x102d0c29, 0x0a311e22, 0x122a0a37, + 0x1133112e, 0x00591aed, 0x16ef1aef, 0x1ee71cec, 0x21e925e5, 0x21e928e4, + 0x26ef21f5, 0x28f129fa, 0x26012911, 0x1efa1b03, 0x1a1625f0, 0x23fc26f8, + 0x26fd2503, 0x26052a00, 0x23102716, 0x0e301b25, 0x153c0c44, 0x0261fd47, + 0xfa2afb32, 0xfd36fe3e, 0x003a013f, 0xfe48ff4a, 0xf75bfb43, 0xfb1bfd27, + 0xfe2c002e, 0xf040f844, 0xf64efa4d, 0xf656f45c, 0xf137f63c, 0xfa3efc41, + 0xf449f84c, 0xf950f758, 0xef6ef561, 0xec54f54f, 0xfa49fc4a, 0xf356f360, + 0xf561ed75, 0xf84efb21, 0xfc30fe35, 0xfd3ef347, 0xf64ff456, 0xf35af261, + 0x0000fa5d, 0xfa54f84f, 0x0042ff47, 0x003efe3c, 0xfe3bfb4b, 0xfd3efc3a, + 0xf742ff4f, 0x00470344, 0x0a2cf93e, 0x0f240e28, 0x101b0c1d, 0x012c1424, + 0x1220052a, 0x01300a3e, 0x112e0940, 0xf468f561, 0xf060f958, 0xf855f955, + 0xf755f358, 0x0442fd4d, 0xfd4cfa4c, 0x0a3aff4c, 0xff53f963, 0xf25f025f, + 0x004cfb4a, 0x0046f54b, 0x01440041, 0xf249033e, 0x043eff44, 0xf34b0b37, + 0x05400c46, 0x0f060613, 0x07100c0e, 0x120d0d0b, 0x0d0f0f10, 0x0c170d17, + 0x0f140e1a, 0x0e2c1128, 0x112f1811, 0x15151916, 0x1f1b161d, 0x13230e32, + 0x0a39073f, 0xfe4dfc52, 0xfd5e0945, 0xf46d24dd, 0x24de20e6, 0x25e22ce0, + 0x22ee22f1, 0x28f121f9, 0x23fb2100, 0x2602210d, 0x17230d3a, 0x1dfd1a00, + 0x161e1ff9, 0x23f122fd, 0x220324ff, 0x2205200b, 0x2305220c, 0x270b1e1d, + 0x221a1d27, 0x13421f15, 0x1f1f1932, 0xef78ec70, 0xee72f555, 0xf15cf259, + 0xe647f151, 0xf2500044, 0xf246e838, 0xe944e832, 0xf54a17f3, 0x1af328f1, + 0x31f22c03, 0x2d062c22, 0x21361352, 0xfd4bff17, 0x0122012b, 0x0036fe37, + 0x003d0140, 0x0044f75c, 0xf26af361, 0xf15af45a, 0xee58f649, 0xf74ff256, + 0xf649f646, 0xf645fb42, 0xf740fb3a, 0x023b15f6, 0x18f51cf8, 0x1cff1d03, + 0x1d092314, 0x1d240e43, 0x14f10236, 0x034a14f1, 0x0236034a, 0xe47fe968, + 0xfa35ff36, 0x07331721, 0x17021500, 0x01090031, 0xdb760539, 0xf34ef541, + 0x013e0c31, 0xfc491132, 0x1240092b, 0x1d001a43, 0x105a0968, 0xd27fec68, + 0x0143f34e, 0xf541013e, 0xfa56ef5f, 0xfa3d092d, 0xfd45fa51, 0xf5600637, + 0x0743fb56, 0x0258003a, 0xfd4cf65e, 0x05360445, 0xfd510058, 0xf943fb4a, + 0xfc4afb50, 0xf948013a, 0x0029003f, 0x003f003f, 0xf7530456, 0x0061f948, + 0x0d29033e, 0x002dfc4e, 0xfd60e57e, 0xe462e765, 0xe943e452, 0xec5ef053, + 0xea6eeb5b, 0xee66f35d, 0xe37ff95c, 0xfb59f960, 0xf36cfd2e, 0xff41ff39, + 0xf75dfd4a, 0xf75cf857, 0xe97e0536, 0x063c063b, 0x0645ff30, 0x0044fc45, + 0xf858fe55, 0xfa4eff4b, 0xf94d0236, 0x0532fd44, 0x0132062a, 0xfc51013f, + 0xfc460043, 0x0239fe4c, 0x0b230440, 0x013d0b23, 0x12190c18, 0x0d1d0d24, + 0xf65df949, 0xfe490d2e, 0x0931f964, 0x09350235, 0x0535fe3d, 0x00380038, + 0xf33ffb3c, 0xff3e0439, 0xfa450439, 0x0e270433, 0x0d440340, 0x013d093f, + 0x07321027, 0x052c0434, 0x0b30fb3c, 0xff3b003b, 0x1621052c, 0x0e2bff4e, + 0x003c0945, 0x0b1c0228, 0x032c0031, 0x002e022c, 0x0233002f, 0x0427023e, + 0x062e0036, 0x0336023a, 0x043f0633, 0x06390735, 0x06340637, 0x0b2d0e24, + 0x0835ff52, 0x0737fd4e, 0x0f2e161f, 0xff541907, 0x1ef91c03, 0x1c042000, + 0x22ff1e06, 0x1e062009, 0x1f131a1b, 0x1a1e2514, 0x1c221146, 0x0143053b, + 0x0943101e, 0x12201223, 0x161d181f, 0x1726122b, 0x14290b3f, 0x093b0940, + 0xff5efe59, 0xf76cfa4c, 0xfe2c002d, 0x0034fd40, 0xfe3bfc46, 0xfc4bf852, + 0xef66f74d, 0x0318002a, 0x00300037, 0xfa3bf947, 0xf453f557, 0xe277013a, + 0xfd1dff24, 0x0126022b, 0xfa37003a, 0x0040fd4a, 0xf65a0046, 0xfc1d051f, + 0x072a013b, 0xfe3afd48, 0xfd51f561, 0x003a0805, 0x0a0e0e12, 0x0d1b0228, + 0x003afd46, 0xfa4ff855, 0x0000f36a, 0xf06af657, 0xeb72ee6e, 0xf262ea6e, + 0xeb6aee67, 0xeb6be96c, 0xe670f660, 0xf45ffb5b, 0xf75dea5e, 0xfb560943, + 0xfc50f655, 0xff46073c, 0x093a053d, 0x0c320f32, 0x12311136, 0x0a29072e, + 0xff330731, 0x08340929, 0x062f0237, 0x0d290a2c, 0x06320535, 0x0d31043f, + 0x0640fe45, 0xfe3b0646, 0x0a2c091f, 0x0c2b0335, 0x0e220a26, 0xfd340d28, + 0x1120072c, 0x07260d32, 0x0a391a2b, 0x0e0b0b0e, 0x090b120b, 0x150917fe, + 0x20f120f1, 0x22eb27e9, 0x2adf29e1, 0x2ee426f4, 0x151d2de8, 0x35d330e6, + 0x41d52bed, 0x27f61e09, 0x121a141b, 0x0039f252, 0xfb4bed61, 0xdd7d1b00, + 0x1c001ffc, 0x1b062208, 0x1e0a1816, 0x21131620, 0x1a1f1529, 0x1a2c172f, + 0x10410e47, 0x083c063f, 0x11411518, 0x17141a17, 0x1b201c17, 0x1c181728, + 0x18201c1d, 0x172a1339, 0x1635163d, 0x0b560c28, 0x0b330e3b, 0xfc4ff947, + 0xfb45f746, 0xf842f644, 0xed49f445, 0xf046f143, 0xec3eed46, 0xf042ea41, + 0xec3f09fe, 0x1af721f7, 0x27f929fe, 0x2d033109, 0x2d1b243b, 0xfa42f923, + 0xf92af82d, 0xfb30f438, 0xfa3cfb3e, 0xf842f84c, 0xfb55fa51, 0xf64df951, + 0xef50ee49, 0xfc4af653, 0xf747f743, 0xff3df842, 0xf242003b, 0x023b15f3, + 0x21f227f9, 0x2efe3302, 0x3c063d11, 0x37222a3e, 0x14f10236, 0x034a14f1, + 0x0236034a, 0xe47fe968, 0xfa35ff36, 0x07331619, 0x22001000, 0xfe090429, + 0xe3760241, 0xfa47f34f, 0x05340932, 0xfd460a36, 0x1a221316, 0x28003902, + 0x29241a45, 0xd37ff165, 0xfc4cfa47, 0xf34f0534, 0x0645f35a, 0x0034082b, + 0xfe45fb52, 0xf660023b, 0x024bfd57, 0xfd640138, 0xfd4afa55, 0x003bfd51, + 0xf956fb5f, 0xff42ff4d, 0x0146fe56, 0xfb48003d, 0x0029003f, 0x003f003f, + 0xf7530456, 0x0061f948, 0x0d29033e, 0x0d0f0733, 0x0250d97f, 0xee5bef60, + 0xe651dd62, 0xe866e961, 0xe577e863, 0xeb6eee66, 0xdc7f0050, 0xfb59f95e, + 0xfc5c0027, 0x0041f154, 0xdd7ffe49, 0xf468f75b, 0xe17f0337, 0x07380737, + 0x083dfd35, 0x0044f94a, 0xf758f367, 0xf35bf759, 0xf25cf84c, 0xf457e96e, + 0xe869f64e, 0xec70ef63, 0xb27fba7f, 0xce7fd27f, 0xfc42fb4e, 0xfc47f848, + 0x023bff37, 0xf946fa4b, 0xf859de77, 0xfd4b2014, 0x1e16d47f, 0x0036fb3d, + 0x003aff3c, 0xfd3df843, 0xe754f24a, 0xfb410534, 0x0239003d, 0xf745f546, + 0x1237fc47, 0x003a073d, 0x09291219, 0x0920052b, 0x092f002c, 0x0033022e, + 0x1326fc42, 0x0f260c2a, 0x09220059, 0x042d0a1c, 0x0a1f21f5, 0x34d5120f, + 0x1c0023ea, 0x26e72200, 0x27ee20f4, 0x66a20000, 0x38f121fc, 0x1d0a25fb, + 0x33e327f7, 0x34de45c6, 0x43c12cfb, 0x200737e3, 0x20010000, 0x1b2421e7, + 0x22e224e4, 0x26e426e5, 0x22ee23f0, 0x22f220f8, 0x25fa2300, 0x1e0a1c12, + 0x1a191d29, 0x004b0248, 0x084d0e23, 0x121f1123, 0x151e112d, 0x142a122d, + 0x1b1a1036, 0x07421038, 0x0b490a43, 0xf674e970, 0xf147f93d, 0x0035fb42, + 0xf54df750, 0xf754f657, 0xde7feb65, 0xfd27fb35, 0xf93df54b, 0xf14def5b, + 0xe76be76f, 0xe47af54c, 0xf62cf634, 0xf639f73a, 0xf048f945, 0xfc45fb4a, + 0xf7560242, 0xf7220120, 0x0b1f0534, 0xfe37fe43, 0x0049f859, 0x03340704, + 0x0a081108, 0x10130325, 0xff3dfb49, 0xff46fc4e, 0x0000eb7e, 0xe97cec6e, + 0xe67ee77c, 0xef69e579, 0xe575ef66, 0xe675e574, 0xdf7af65f, 0xf264f85f, + 0xef6fe472, 0xfa59fe50, 0xfc52f755, 0xf851ff48, 0x05400143, 0x09380045, + 0x01450745, 0xf945fa43, 0xf04dfe40, 0x023dfa43, 0xfd400239, 0xfd41fd42, + 0x003e0933, 0xff42fe47, 0xfe4bff46, 0xf7480e3c, 0x1025002f, 0x12230b25, + 0x0c290a29, 0x02300c29, 0x0d29003b, 0x03321328, 0x03421232, 0x13fa12fa, + 0x0e001af4, 0x1ff021e7, 0x21ea25e4, 0x27e22ae2, 0x2fd62ddc, 0x31de29ef, + 0x200945b9, 0x3fc142c0, 0x4db636d9, 0x34dd29f6, 0x240028ff, 0x1e0e1c1a, + 0x17250c37, 0x0b4125df, 0x27dc28db, 0x26e22edf, 0x2ae228e8, 0x31e326f4, + 0x28f626fd, 0x2efb1f14, 0x1d1e192c, 0x0c300b31, 0x1a2d1616, 0x17161b15, + 0x21141a1c, 0x1e181b22, 0x122a1927, 0x12320c46, 0x15360e47, 0x0b531920, + 0x15311536, 0xfb55fa51, 0xf64df951, 0xef50ee49, 0xfc4af653, 0xf747f743, + 0xff3df842, 0xf242003b, 0x023b11f6, 0x20f32af7, 0x31fb3500, 0x4003440a, + 0x421b2f39, 0xfb470018, 0xff24fe2a, 0xfe34f739, 0xfa3ffc41, 0xfc43f952, + 0xfd51fd4c, 0xf948fa4e, 0xf448f244, 0xfd46fa4c, 0xfb42fb3e, 0x0039fc3d, + 0xf73c0136, 0x023a11f6, 0x20f32af7, 0x31fb3500, 0x4003440a, 0x421b2f39, + 0x14f10236, 0x034a14f1, 0x0236034a, 0xe47fe968, 0xfa35ff36, 0x07331d10, + 0x19000e00, 0xf633fd3e, 0xe5631a10, 0xfc55e866, 0x05390639, 0xef490e39, + 0x1428140a, 0x1d003600, 0x252a0c61, 0xe07fea75, 0xfe4afc55, 0xe8660539, + 0xfa5df258, 0xfa2c0437, 0xf559f167, 0xeb741339, 0x143a0454, 0x0660013f, + 0xfb55f36a, 0x053f064b, 0xfd5aff65, 0x0337fc4f, 0xfe4bf461, 0xf932013c, + 0x0029003f, 0x003f003f, 0xf7530456, 0x0061f948, 0x0d29033e, 0x0722f758, + 0xec7fdc7f, 0xef5bf25f, 0xe754e756, 0xf459ef5b, 0xe17ff24c, 0xee67f35a, + 0xdb7f0b50, 0x054c0254, 0x054efa37, 0x043df253, 0xdb7ffb4f, 0xf568f55b, + 0xe27f0041, 0xfe4f0048, 0xfc5cfa38, 0x0344f847, 0xf362fc56, 0xf458fb52, + 0xfd48fc43, 0xf848f059, 0xf745ff3b, 0x05420439, 0xfc47fe47, 0x023aff4a, + 0xfc2cff45, 0x003ef933, 0xfc2ffa2a, 0xfd29fa35, 0x084cf74e, 0xf5530934, + 0x0043fb5a, 0x0143f148, 0xfb4bf850, 0xeb53eb40, 0xf31fe740, 0xe35e094b, + 0x113ff84a, 0xfb23fe1b, 0x0d5b0341, 0xf945084d, 0xf642033e, 0xfd44ec51, + 0x001e0107, 0xfd17eb4a, 0x1042e97c, 0x11252cee, 0x32deea7f, 0x0427002a, + 0x07220b1d, 0x081f0625, 0x072a0328, 0x08210d2b, 0x0d24042f, 0x0337023a, + 0x063c082c, 0x0b2c0e2a, 0x07300438, 0x04340d25, 0x0931133a, 0x0a300c2d, + 0x00451421, 0x083f23ee, 0x21e71cfd, 0x180a1b00, 0x22f234d4, 0x27e81311, + 0x1f19241d, 0x1821220f, 0x1e141649, 0x1422131f, 0x1b2c1310, 0x0f240f24, + 0x151c1915, 0x1e141f0c, 0x1b10182a, 0x005d0e38, 0x0f391a26, 0xe87fe873, + 0xea52f73e, 0x0035003b, 0xf255f359, 0xf35ef55c, 0xe37feb64, 0xf239f443, + 0xf547f64d, 0xeb55f058, 0xe968f162, 0xdb7ff652, 0xf830f83d, 0xf842f946, + 0xf24bf64f, 0xf753f45c, 0xee6cfc4f, 0xea45f04b, 0xfe3a013a, 0xf34ef753, + 0xfc51f363, 0xf351fa26, 0xf33efa3a, 0xfe3bf049, 0xf64cf356, 0xf753f657, + 0x0000ea7f, 0xe77fe778, 0xe57fed72, 0xe975e776, 0xe675e871, 0xe476e178, + 0xdb7cf65e, 0xf166f663, 0xf36ace7f, 0xfb5c1139, 0xfb56f35e, 0xf45bfe4d, + 0x0047ff49, 0x0440f951, 0x05400f39, 0x01430044, 0xf6430144, 0x004d0240, + 0x0044fb4e, 0x0737053b, 0x02410e36, 0x0f2c053c, 0x0246fe4c, 0xee560c46, + 0x0540f446, 0x0b370538, 0x00450241, 0xfa4a0536, 0x0736fa4c, 0xf552fe4d, + 0xfe4d192a, 0x11f310f7, 0x11f41beb, 0x25e229d8, 0x2ad730d1, 0x27e02ed8, + 0x34cd2ed7, 0x34d92bed, 0x200b3dc9, 0x38d23ece, 0x51bd2dec, 0x23fe1c0f, + 0x22012701, 0x1e111426, 0x122d0f36, 0x004f24f0, 0x25f225ef, 0x2001220f, + 0x1d0f1819, 0x22161f10, 0x23121f1c, 0x2129241c, 0x1b2f153e, 0x121f131a, + 0x24181817, 0x1b10181e, 0x1f1d1629, 0x162a103c, 0x0f340e3c, 0x034ef07b, + 0x15351638, 0x193d1521, 0x1332113d, 0xfd4ef84a, 0xf748f648, 0xee4bf447, + 0xf53ffb46, 0xef4bf248, 0xf043f835, 0xf23bf734, 0xf54409fe, 0x1ef61ffc, + 0x21ff2107, 0x1f0c2517, 0x1f261440, 0xf747f925, 0xf82cf531, 0xf638f43b, + 0xf83ff743, 0xfa44f64f, 0xfd4ef84a, 0xf748f648, 0xee4bf447, 0xf53ffb46, + 0xef4bf248, 0xf043f835, 0xf23bf734, 0xf54409fe, 0x1ef61ffc, 0x21ff2107, + 0x1f0c2517, 0x1f261440 +}; + +/* + * NOTE: The scaling lists are in zig-zag order, apply inverse scanning process + * to get the values in matrix order. In addition, the hardware requires bytes + * swapped within each subsequent 4 bytes. Both arrays below include both + * transformations. + */ +static const u32 zig_zag_4x4[] = { + 3, 2, 7, 11, 6, 1, 0, 5, 10, 15, 14, 9, 4, 8, 13, 12 +}; + +static const u32 zig_zag_8x8[] = { + 3, 2, 11, 19, 10, 1, 0, 9, 18, 27, 35, 26, 17, 8, 7, 6, + 15, 16, 25, 34, 43, 51, 42, 33, 24, 23, 14, 5, 4, 13, 22, 31, + 32, 41, 50, 59, 58, 49, 40, 39, 30, 21, 12, 20, 29, 38, 47, 48, + 57, 56, 55, 46, 37, 28, 36, 45, 54, 63, 62, 53, 44, 52, 61, 60 +}; + +static void +reorder_scaling_list(struct hantro_ctx *ctx) +{ + const struct hantro_h264_dec_ctrls *ctrls = &ctx->h264_dec.ctrls; + const struct v4l2_ctrl_h264_scaling_matrix *scaling = ctrls->scaling; + const size_t num_list_4x4 = ARRAY_SIZE(scaling->scaling_list_4x4); + const size_t list_len_4x4 = ARRAY_SIZE(scaling->scaling_list_4x4[0]); + const size_t num_list_8x8 = ARRAY_SIZE(scaling->scaling_list_8x8); + const size_t list_len_8x8 = ARRAY_SIZE(scaling->scaling_list_8x8[0]); + struct hantro_h264_dec_priv_tbl *tbl = ctx->h264_dec.priv.cpu; + u8 *dst = tbl->scaling_list; + const u8 *src; + int i, j; + + BUILD_BUG_ON(ARRAY_SIZE(zig_zag_4x4) != list_len_4x4); + BUILD_BUG_ON(ARRAY_SIZE(zig_zag_8x8) != list_len_8x8); + BUILD_BUG_ON(ARRAY_SIZE(tbl->scaling_list) != + num_list_4x4 * list_len_4x4 + + num_list_8x8 * list_len_8x8); + + src = &scaling->scaling_list_4x4[0][0]; + for (i = 0; i < num_list_4x4; ++i) { + for (j = 0; j < list_len_4x4; ++j) + dst[zig_zag_4x4[j]] = src[j]; + src += list_len_4x4; + dst += list_len_4x4; + } + + src = &scaling->scaling_list_8x8[0][0]; + for (i = 0; i < num_list_8x8; ++i) { + for (j = 0; j < list_len_8x8; ++j) + dst[zig_zag_8x8[j]] = src[j]; + src += list_len_8x8; + dst += list_len_8x8; + } +} + +static void prepare_table(struct hantro_ctx *ctx) +{ + const struct hantro_h264_dec_ctrls *ctrls = &ctx->h264_dec.ctrls; + const struct v4l2_ctrl_h264_decode_params *dec_param = ctrls->decode; + struct hantro_h264_dec_priv_tbl *tbl = ctx->h264_dec.priv.cpu; + const struct v4l2_h264_dpb_entry *dpb = ctx->h264_dec.dpb; + int i; + + for (i = 0; i < HANTRO_H264_DPB_SIZE; ++i) { + tbl->poc[i * 2] = dpb[i].top_field_order_cnt; + tbl->poc[i * 2 + 1] = dpb[i].bottom_field_order_cnt; + } + + tbl->poc[32] = dec_param->top_field_order_cnt; + tbl->poc[33] = dec_param->bottom_field_order_cnt; + + reorder_scaling_list(ctx); +} + +struct hantro_h264_reflist_builder { + const struct v4l2_h264_dpb_entry *dpb; + s32 pocs[HANTRO_H264_DPB_SIZE]; + u8 unordered_reflist[HANTRO_H264_DPB_SIZE]; + s32 curpoc; + u8 num_valid; +}; + +static s32 get_poc(enum v4l2_field field, s32 top_field_order_cnt, + s32 bottom_field_order_cnt) +{ + switch (field) { + case V4L2_FIELD_TOP: + return top_field_order_cnt; + case V4L2_FIELD_BOTTOM: + return bottom_field_order_cnt; + default: + break; + } + + return min(top_field_order_cnt, bottom_field_order_cnt); +} + +static void +init_reflist_builder(struct hantro_ctx *ctx, + struct hantro_h264_reflist_builder *b) +{ + const struct v4l2_ctrl_h264_decode_params *dec_param; + struct vb2_v4l2_buffer *buf = hantro_get_dst_buf(ctx); + const struct v4l2_h264_dpb_entry *dpb = ctx->h264_dec.dpb; + struct vb2_queue *cap_q = &ctx->fh.m2m_ctx->cap_q_ctx.q; + unsigned int i; + + dec_param = ctx->h264_dec.ctrls.decode; + + memset(b, 0, sizeof(*b)); + b->dpb = dpb; + b->curpoc = get_poc(buf->field, dec_param->top_field_order_cnt, + dec_param->bottom_field_order_cnt); + + for (i = 0; i < ARRAY_SIZE(ctx->h264_dec.dpb); i++) { + int buf_idx; + + if (!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) + continue; + + buf_idx = vb2_find_timestamp(cap_q, dpb[i].reference_ts, 0); + if (buf_idx < 0) + continue; + + buf = to_vb2_v4l2_buffer(vb2_get_buffer(cap_q, buf_idx)); + b->pocs[i] = get_poc(buf->field, dpb[i].top_field_order_cnt, + dpb[i].bottom_field_order_cnt); + b->unordered_reflist[b->num_valid] = i; + b->num_valid++; + } + + for (i = b->num_valid; i < ARRAY_SIZE(ctx->h264_dec.dpb); i++) + b->unordered_reflist[i] = i; +} + +static int p_ref_list_cmp(const void *ptra, const void *ptrb, const void *data) +{ + const struct hantro_h264_reflist_builder *builder = data; + const struct v4l2_h264_dpb_entry *a, *b; + u8 idxa, idxb; + + idxa = *((u8 *)ptra); + idxb = *((u8 *)ptrb); + a = &builder->dpb[idxa]; + b = &builder->dpb[idxb]; + + if ((a->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) != + (b->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)) { + /* Short term pics firt. */ + if (!(a->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)) + return -1; + else + return 1; + } + + /* + * Short term pics in descending pic num order, long term ones in + * ascending order. + */ + if (!(a->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)) + return b->frame_num - a->frame_num; + + return a->pic_num - b->pic_num; +} + +static int b0_ref_list_cmp(const void *ptra, const void *ptrb, const void *data) +{ + const struct hantro_h264_reflist_builder *builder = data; + const struct v4l2_h264_dpb_entry *a, *b; + s32 poca, pocb; + u8 idxa, idxb; + + idxa = *((u8 *)ptra); + idxb = *((u8 *)ptrb); + a = &builder->dpb[idxa]; + b = &builder->dpb[idxb]; + + if ((a->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) != + (b->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)) { + /* Short term pics firt. */ + if (!(a->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)) + return -1; + else + return 1; + } + + /* Long term pics in ascending pic num order. */ + if (a->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) + return a->pic_num - b->pic_num; + + poca = builder->pocs[idxa]; + pocb = builder->pocs[idxb]; + + /* + * Short term pics with POC < cur POC first in POC descending order + * followed by short term pics with POC > cur POC in POC ascending + * order. + */ + if ((poca < builder->curpoc) != (pocb < builder->curpoc)) + return POC_CMP(poca, pocb); + else if (poca < builder->curpoc) + return POC_CMP(pocb, poca); + + return POC_CMP(poca, pocb); +} + +static int b1_ref_list_cmp(const void *ptra, const void *ptrb, const void *data) +{ + const struct hantro_h264_reflist_builder *builder = data; + const struct v4l2_h264_dpb_entry *a, *b; + s32 poca, pocb; + u8 idxa, idxb; + + idxa = *((u8 *)ptra); + idxb = *((u8 *)ptrb); + a = &builder->dpb[idxa]; + b = &builder->dpb[idxb]; + + if ((a->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) != + (b->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)) { + /* Short term pics firt. */ + if (!(a->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)) + return -1; + else + return 1; + } + + /* Long term pics in ascending pic num order. */ + if (a->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) + return a->pic_num - b->pic_num; + + poca = builder->pocs[idxa]; + pocb = builder->pocs[idxb]; + + /* + * Short term pics with POC > cur POC first in POC ascending order + * followed by short term pics with POC > cur POC in POC descending + * order. + */ + if ((poca < builder->curpoc) != (pocb < builder->curpoc)) + return POC_CMP(pocb, poca); + else if (poca < builder->curpoc) + return POC_CMP(pocb, poca); + + return POC_CMP(poca, pocb); +} + +static void +build_p_ref_list(const struct hantro_h264_reflist_builder *builder, + u8 *reflist) +{ + memcpy(reflist, builder->unordered_reflist, + sizeof(builder->unordered_reflist)); + sort_r(reflist, builder->num_valid, sizeof(*reflist), + p_ref_list_cmp, NULL, builder); +} + +static void +build_b_ref_lists(const struct hantro_h264_reflist_builder *builder, + u8 *b0_reflist, u8 *b1_reflist) +{ + memcpy(b0_reflist, builder->unordered_reflist, + sizeof(builder->unordered_reflist)); + sort_r(b0_reflist, builder->num_valid, sizeof(*b0_reflist), + b0_ref_list_cmp, NULL, builder); + + memcpy(b1_reflist, builder->unordered_reflist, + sizeof(builder->unordered_reflist)); + sort_r(b1_reflist, builder->num_valid, sizeof(*b1_reflist), + b1_ref_list_cmp, NULL, builder); + + if (builder->num_valid > 1 && + !memcmp(b1_reflist, b0_reflist, builder->num_valid)) + swap(b1_reflist[0], b1_reflist[1]); +} + +static bool dpb_entry_match(const struct v4l2_h264_dpb_entry *a, + const struct v4l2_h264_dpb_entry *b) +{ + return a->top_field_order_cnt == b->top_field_order_cnt && + a->bottom_field_order_cnt == b->bottom_field_order_cnt; +} + +static void update_dpb(struct hantro_ctx *ctx) +{ + const struct v4l2_ctrl_h264_decode_params *dec_param; + DECLARE_BITMAP(new, ARRAY_SIZE(dec_param->dpb)) = { 0, }; + DECLARE_BITMAP(used, ARRAY_SIZE(dec_param->dpb)) = { 0, }; + unsigned int i, j; + + dec_param = ctx->h264_dec.ctrls.decode; + + /* Disable all entries by default. */ + for (i = 0; i < ARRAY_SIZE(ctx->h264_dec.dpb); i++) + ctx->h264_dec.dpb[i].flags &= ~V4L2_H264_DPB_ENTRY_FLAG_ACTIVE; + + /* Try to match new DPB entries with existing ones by their POCs. */ + for (i = 0; i < ARRAY_SIZE(dec_param->dpb); i++) { + const struct v4l2_h264_dpb_entry *ndpb = &dec_param->dpb[i]; + + if (!(ndpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) + continue; + + /* + * To cut off some comparisons, iterate only on target DPB + * entries which are not used yet. + */ + for_each_clear_bit(j, used, ARRAY_SIZE(ctx->h264_dec.dpb)) { + struct v4l2_h264_dpb_entry *cdpb; + + cdpb = &ctx->h264_dec.dpb[j]; + if (cdpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE || + !dpb_entry_match(cdpb, ndpb)) + continue; + + *cdpb = *ndpb; + set_bit(j, used); + break; + } + + if (j == ARRAY_SIZE(ctx->h264_dec.dpb)) + set_bit(i, new); + } + + /* For entries that could not be matched, use remaining free slots. */ + for_each_set_bit(i, new, ARRAY_SIZE(dec_param->dpb)) { + const struct v4l2_h264_dpb_entry *ndpb = &dec_param->dpb[i]; + struct v4l2_h264_dpb_entry *cdpb; + + /* + * Both arrays are of the same sizes, so there is no way + * we can end up with no space in target array, unless + * something is buggy. + */ + j = find_first_zero_bit(used, ARRAY_SIZE(ctx->h264_dec.dpb)); + if (WARN_ON(j >= ARRAY_SIZE(ctx->h264_dec.dpb))) + return; + + cdpb = &ctx->h264_dec.dpb[j]; + *cdpb = *ndpb; + set_bit(j, used); + } +} + +struct vb2_buffer *hantro_h264_get_ref_buf(struct hantro_ctx *ctx, + unsigned int dpb_idx) +{ + struct vb2_queue *cap_q = &ctx->fh.m2m_ctx->cap_q_ctx.q; + struct v4l2_h264_dpb_entry *dpb = ctx->h264_dec.dpb; + struct vb2_buffer *buf; + int buf_idx = -1; + + if (dpb[dpb_idx].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) + buf_idx = vb2_find_timestamp(cap_q, + dpb[dpb_idx].reference_ts, 0); + + if (buf_idx >= 0) { + buf = vb2_get_buffer(cap_q, buf_idx); + } else { + struct vb2_v4l2_buffer *dst_buf; + + /* + * If a DPB entry is unused or invalid, address of current + * destination buffer is returned. + */ + dst_buf = hantro_get_dst_buf(ctx); + buf = &dst_buf->vb2_buf; + } + + return buf; +} + +int hantro_h264_dec_prepare_run(struct hantro_ctx *ctx) +{ + struct hantro_h264_dec_hw_ctx *h264_ctx = &ctx->h264_dec; + struct hantro_h264_dec_ctrls *ctrls = &h264_ctx->ctrls; + struct hantro_h264_reflist_builder reflist_builder; + + hantro_prepare_run(ctx); + + ctrls->scaling = + hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX); + if (WARN_ON(!ctrls->scaling)) + return -EINVAL; + + ctrls->decode = + hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS); + if (WARN_ON(!ctrls->decode)) + return -EINVAL; + + ctrls->slices = + hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS); + if (WARN_ON(!ctrls->slices)) + return -EINVAL; + + ctrls->sps = + hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_H264_SPS); + if (WARN_ON(!ctrls->sps)) + return -EINVAL; + + ctrls->pps = + hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_H264_PPS); + if (WARN_ON(!ctrls->pps)) + return -EINVAL; + + /* Update the DPB with new refs. */ + update_dpb(ctx); + + /* Prepare data in memory. */ + prepare_table(ctx); + + /* Build the P/B{0,1} ref lists. */ + init_reflist_builder(ctx, &reflist_builder); + build_p_ref_list(&reflist_builder, h264_ctx->reflists.p); + build_b_ref_lists(&reflist_builder, h264_ctx->reflists.b0, + h264_ctx->reflists.b1); + return 0; +} + +void hantro_h264_dec_exit(struct hantro_ctx *ctx) +{ + struct hantro_dev *vpu = ctx->dev; + struct hantro_h264_dec_hw_ctx *h264_dec = &ctx->h264_dec; + struct hantro_aux_buf *priv = &h264_dec->priv; + + dma_free_coherent(vpu->dev, priv->size, priv->cpu, priv->dma); +} + +int hantro_h264_dec_init(struct hantro_ctx *ctx) +{ + struct hantro_dev *vpu = ctx->dev; + struct hantro_h264_dec_hw_ctx *h264_dec = &ctx->h264_dec; + struct hantro_aux_buf *priv = &h264_dec->priv; + struct hantro_h264_dec_priv_tbl *tbl; + struct v4l2_pix_format_mplane pix_mp; + + priv->cpu = dma_alloc_coherent(vpu->dev, sizeof(*tbl), &priv->dma, + GFP_KERNEL); + if (!priv->cpu) + return -ENOMEM; + + priv->size = sizeof(*tbl); + tbl = priv->cpu; + memcpy(tbl->cabac_table, h264_cabac_table, sizeof(tbl->cabac_table)); + + v4l2_fill_pixfmt_mp(&pix_mp, ctx->dst_fmt.pixelformat, + ctx->dst_fmt.width, ctx->dst_fmt.height); + h264_dec->pic_size = pix_mp.plane_fmt[0].sizeimage; + + return 0; +} diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/staging/media/hantro/hantro_hw.h index 2b8029674a75..75f1ce45a21f 100644 --- a/drivers/staging/media/hantro/hantro_hw.h +++ b/drivers/staging/media/hantro/hantro_hw.h @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -42,6 +43,54 @@ struct hantro_jpeg_enc_hw_ctx { struct hantro_aux_buf bounce_buffer; }; +/* Max. number of entries in the DPB (HW limitation). */ +#define HANTRO_H264_DPB_SIZE 16 + +/** + * struct hantro_h264_dec_ctrls + * @decode: Decode params + * @scaling: Scaling info + * @slice: Slice params + * @sps: SPS info + * @pps: PPS info + */ +struct hantro_h264_dec_ctrls { + const struct v4l2_ctrl_h264_decode_params *decode; + const struct v4l2_ctrl_h264_scaling_matrix *scaling; + const struct v4l2_ctrl_h264_slice_params *slices; + const struct v4l2_ctrl_h264_sps *sps; + const struct v4l2_ctrl_h264_pps *pps; +}; + +/** + * struct hantro_h264_dec_reflists + * @p: P reflist + * @b0: B0 reflist + * @b1: B1 reflist + */ +struct hantro_h264_dec_reflists { + u8 p[HANTRO_H264_DPB_SIZE]; + u8 b0[HANTRO_H264_DPB_SIZE]; + u8 b1[HANTRO_H264_DPB_SIZE]; +}; + +/** + * struct hantro_h264_dec_hw_ctx + * @priv: Private auxiliary buffer for hardware. + * @dpb: DPB + * @reflists: P/B0/B1 reflists + * @ctrls: V4L2 controls attached to a run + * @pic_size: Size in bytes of decoded picture, this is needed + * to pass the location of motion vectors. + */ +struct hantro_h264_dec_hw_ctx { + struct hantro_aux_buf priv; + struct v4l2_h264_dpb_entry dpb[HANTRO_H264_DPB_SIZE]; + struct hantro_h264_dec_reflists reflists; + struct hantro_h264_dec_ctrls ctrls; + size_t pic_size; +}; + /** * struct hantro_mpeg2_dec_hw_ctx * @qtable: Quantization table @@ -109,6 +158,12 @@ void rk3399_vpu_jpeg_enc_run(struct hantro_ctx *ctx); int hantro_jpeg_enc_init(struct hantro_ctx *ctx); void hantro_jpeg_enc_exit(struct hantro_ctx *ctx); +struct vb2_buffer *hantro_h264_get_ref_buf(struct hantro_ctx *ctx, + unsigned int dpb_idx); +int hantro_h264_dec_prepare_run(struct hantro_ctx *ctx); +int hantro_h264_dec_init(struct hantro_ctx *ctx); +void hantro_h264_dec_exit(struct hantro_ctx *ctx); + void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx); void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx); void hantro_mpeg2_dec_copy_qtable(u8 *qtable, diff --git a/drivers/staging/media/hantro/hantro_v4l2.c b/drivers/staging/media/hantro/hantro_v4l2.c index cd4eaa256e8b..3dae52abb96c 100644 --- a/drivers/staging/media/hantro/hantro_v4l2.c +++ b/drivers/staging/media/hantro/hantro_v4l2.c @@ -239,6 +239,15 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f, /* Fill remaining fields */ v4l2_fill_pixfmt_mp(pix_mp, fmt->fourcc, pix_mp->width, pix_mp->height); + /* + * The H264 decoder needs extra space on the output buffers + * to store motion vectors. This is needed for reference + * frames. + */ + if (ctx->vpu_src_fmt->fourcc == V4L2_PIX_FMT_H264_SLICE) + pix_mp->plane_fmt[0].sizeimage += + 128 * DIV_ROUND_UP(pix_mp->width, 16) * + DIV_ROUND_UP(pix_mp->height, 16); } else if (!pix_mp->plane_fmt[0].sizeimage) { /* * For coded formats the application can specify @@ -345,6 +354,7 @@ hantro_update_requires_request(struct hantro_ctx *ctx, u32 fourcc) break; case V4L2_PIX_FMT_MPEG2_SLICE: case V4L2_PIX_FMT_VP8_FRAME: + case V4L2_PIX_FMT_H264_SLICE: ctx->fh.m2m_ctx->out_q_ctx.q.requires_requests = true; break; default: -- cgit v1.2.3-59-g8ed1b From dea0a82f3d22ad8a4e113a60ca94aa173af36756 Mon Sep 17 00:00:00 2001 From: Hertz Wong Date: Fri, 16 Aug 2019 13:01:31 -0300 Subject: media: hantro: Add support for H264 decoding on G1 Add the G1 specific bits to support H264 decoding. Signed-off-by: Hertz Wong Signed-off-by: Boris Brezillon Tested-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/hantro/Makefile | 1 + drivers/staging/media/hantro/hantro_g1_h264_dec.c | 292 ++++++++++++++++++++++ drivers/staging/media/hantro/hantro_hw.h | 1 + 3 files changed, 294 insertions(+) create mode 100644 drivers/staging/media/hantro/hantro_g1_h264_dec.c (limited to 'drivers/staging') diff --git a/drivers/staging/media/hantro/Makefile b/drivers/staging/media/hantro/Makefile index 0f0d3afb1cca..5d6b0383d280 100644 --- a/drivers/staging/media/hantro/Makefile +++ b/drivers/staging/media/hantro/Makefile @@ -4,6 +4,7 @@ hantro-vpu-y += \ hantro_drv.o \ hantro_v4l2.o \ hantro_h1_jpeg_enc.o \ + hantro_g1_h264_dec.o \ hantro_g1_mpeg2_dec.o \ hantro_g1_vp8_dec.o \ rk3399_vpu_hw_jpeg_enc.o \ diff --git a/drivers/staging/media/hantro/hantro_g1_h264_dec.c b/drivers/staging/media/hantro/hantro_g1_h264_dec.c new file mode 100644 index 000000000000..7ab534936843 --- /dev/null +++ b/drivers/staging/media/hantro/hantro_g1_h264_dec.c @@ -0,0 +1,292 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Rockchip RK3288 VPU codec driver + * + * Copyright (c) 2014 Rockchip Electronics Co., Ltd. + * Hertz Wong + * Herman Chen + * + * Copyright (C) 2014 Google, Inc. + * Tomasz Figa + */ + +#include +#include + +#include + +#include "hantro_g1_regs.h" +#include "hantro_hw.h" +#include "hantro_v4l2.h" + +static void set_params(struct hantro_ctx *ctx) +{ + const struct hantro_h264_dec_ctrls *ctrls = &ctx->h264_dec.ctrls; + const struct v4l2_ctrl_h264_decode_params *dec_param = ctrls->decode; + const struct v4l2_ctrl_h264_slice_params *slices = ctrls->slices; + const struct v4l2_ctrl_h264_sps *sps = ctrls->sps; + const struct v4l2_ctrl_h264_pps *pps = ctrls->pps; + struct vb2_v4l2_buffer *src_buf = hantro_get_src_buf(ctx); + struct hantro_dev *vpu = ctx->dev; + u32 reg; + + /* Decoder control register 0. */ + reg = G1_REG_DEC_CTRL0_DEC_AXI_WR_ID(0x0); + if (sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD) + reg |= G1_REG_DEC_CTRL0_SEQ_MBAFF_E; + reg |= G1_REG_DEC_CTRL0_PICORD_COUNT_E; + if (dec_param->nal_ref_idc) + reg |= G1_REG_DEC_CTRL0_WRITE_MVS_E; + + if (!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY) && + (sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD || + slices[0].flags & V4L2_H264_SLICE_FLAG_FIELD_PIC)) + reg |= G1_REG_DEC_CTRL0_PIC_INTERLACE_E; + if (slices[0].flags & V4L2_H264_SLICE_FLAG_FIELD_PIC) + reg |= G1_REG_DEC_CTRL0_PIC_FIELDMODE_E; + if (!(slices[0].flags & V4L2_H264_SLICE_FLAG_BOTTOM_FIELD)) + reg |= G1_REG_DEC_CTRL0_PIC_TOPFIELD_E; + vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL0); + + /* Decoder control register 1. */ + reg = G1_REG_DEC_CTRL1_PIC_MB_WIDTH(sps->pic_width_in_mbs_minus1 + 1) | + G1_REG_DEC_CTRL1_PIC_MB_HEIGHT_P(sps->pic_height_in_map_units_minus1 + 1) | + G1_REG_DEC_CTRL1_REF_FRAMES(sps->max_num_ref_frames); + vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL1); + + /* Decoder control register 2. */ + reg = G1_REG_DEC_CTRL2_CH_QP_OFFSET(pps->chroma_qp_index_offset) | + G1_REG_DEC_CTRL2_CH_QP_OFFSET2(pps->second_chroma_qp_index_offset); + + /* always use the matrix sent from userspace */ + reg |= G1_REG_DEC_CTRL2_TYPE1_QUANT_E; + + if (slices[0].flags & V4L2_H264_SLICE_FLAG_FIELD_PIC) + reg |= G1_REG_DEC_CTRL2_FIELDPIC_FLAG_E; + vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL2); + + /* Decoder control register 3. */ + reg = G1_REG_DEC_CTRL3_START_CODE_E | + G1_REG_DEC_CTRL3_INIT_QP(pps->pic_init_qp_minus26 + 26) | + G1_REG_DEC_CTRL3_STREAM_LEN(vb2_get_plane_payload(&src_buf->vb2_buf, 0)); + vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL3); + + /* Decoder control register 4. */ + reg = G1_REG_DEC_CTRL4_FRAMENUM_LEN(sps->log2_max_frame_num_minus4 + 4) | + G1_REG_DEC_CTRL4_FRAMENUM(slices[0].frame_num) | + G1_REG_DEC_CTRL4_WEIGHT_BIPR_IDC(pps->weighted_bipred_idc); + if (pps->flags & V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE) + reg |= G1_REG_DEC_CTRL4_CABAC_E; + if (sps->flags & V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE) + reg |= G1_REG_DEC_CTRL4_DIR_8X8_INFER_E; + if (sps->chroma_format_idc == 0) + reg |= G1_REG_DEC_CTRL4_BLACKWHITE_E; + if (pps->flags & V4L2_H264_PPS_FLAG_WEIGHTED_PRED) + reg |= G1_REG_DEC_CTRL4_WEIGHT_PRED_E; + vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL4); + + /* Decoder control register 5. */ + reg = G1_REG_DEC_CTRL5_REFPIC_MK_LEN(slices[0].dec_ref_pic_marking_bit_size) | + G1_REG_DEC_CTRL5_IDR_PIC_ID(slices[0].idr_pic_id); + if (pps->flags & V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED) + reg |= G1_REG_DEC_CTRL5_CONST_INTRA_E; + if (pps->flags & V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT) + reg |= G1_REG_DEC_CTRL5_FILT_CTRL_PRES; + if (pps->flags & V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT) + reg |= G1_REG_DEC_CTRL5_RDPIC_CNT_PRES; + if (pps->flags & V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE) + reg |= G1_REG_DEC_CTRL5_8X8TRANS_FLAG_E; + if (dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC) + reg |= G1_REG_DEC_CTRL5_IDR_PIC_E; + vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL5); + + /* Decoder control register 6. */ + reg = G1_REG_DEC_CTRL6_PPS_ID(slices[0].pic_parameter_set_id) | + G1_REG_DEC_CTRL6_REFIDX0_ACTIVE(pps->num_ref_idx_l0_default_active_minus1 + 1) | + G1_REG_DEC_CTRL6_REFIDX1_ACTIVE(pps->num_ref_idx_l1_default_active_minus1 + 1) | + G1_REG_DEC_CTRL6_POC_LENGTH(slices[0].pic_order_cnt_bit_size); + vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL6); + + /* Error concealment register. */ + vdpu_write_relaxed(vpu, 0, G1_REG_ERR_CONC); + + /* Prediction filter tap register. */ + vdpu_write_relaxed(vpu, + G1_REG_PRED_FLT_PRED_BC_TAP_0_0(1) | + G1_REG_PRED_FLT_PRED_BC_TAP_0_1(-5 & 0x3ff) | + G1_REG_PRED_FLT_PRED_BC_TAP_0_2(20), + G1_REG_PRED_FLT); + + /* Reference picture buffer control register. */ + vdpu_write_relaxed(vpu, 0, G1_REG_REF_BUF_CTRL); + + /* Reference picture buffer control register 2. */ + vdpu_write_relaxed(vpu, G1_REG_REF_BUF_CTRL2_APF_THRESHOLD(8), + G1_REG_REF_BUF_CTRL2); +} + +static void set_ref(struct hantro_ctx *ctx) +{ + struct v4l2_h264_dpb_entry *dpb = ctx->h264_dec.dpb; + const u8 *b0_reflist, *b1_reflist, *p_reflist; + struct hantro_dev *vpu = ctx->dev; + u32 dpb_longterm = 0; + u32 dpb_valid = 0; + int reg_num; + u32 reg; + int i; + + /* + * Set up bit maps of valid and long term DPBs. + * NOTE: The bits are reversed, i.e. MSb is DPB 0. + */ + for (i = 0; i < HANTRO_H264_DPB_SIZE; ++i) { + if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) + dpb_valid |= BIT(HANTRO_H264_DPB_SIZE - 1 - i); + + if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) + dpb_longterm |= BIT(HANTRO_H264_DPB_SIZE - 1 - i); + } + vdpu_write_relaxed(vpu, dpb_valid << 16, G1_REG_VALID_REF); + vdpu_write_relaxed(vpu, dpb_longterm << 16, G1_REG_LT_REF); + + /* + * Set up reference frame picture numbers. + * + * Each G1_REG_REF_PIC(x) register contains numbers of two + * subsequential reference pictures. + */ + for (i = 0; i < HANTRO_H264_DPB_SIZE; i += 2) { + reg = 0; + if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) + reg |= G1_REG_REF_PIC_REFER0_NBR(dpb[i].pic_num); + else + reg |= G1_REG_REF_PIC_REFER0_NBR(dpb[i].frame_num); + + if (dpb[i + 1].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) + reg |= G1_REG_REF_PIC_REFER1_NBR(dpb[i + 1].pic_num); + else + reg |= G1_REG_REF_PIC_REFER1_NBR(dpb[i + 1].frame_num); + + vdpu_write_relaxed(vpu, reg, G1_REG_REF_PIC(i / 2)); + } + + b0_reflist = ctx->h264_dec.reflists.b0; + b1_reflist = ctx->h264_dec.reflists.b1; + p_reflist = ctx->h264_dec.reflists.p; + + /* + * Each G1_REG_BD_REF_PIC(x) register contains three entries + * of each forward and backward picture list. + */ + reg_num = 0; + for (i = 0; i < 15; i += 3) { + reg = G1_REG_BD_REF_PIC_BINIT_RLIST_F0(b0_reflist[i]) | + G1_REG_BD_REF_PIC_BINIT_RLIST_F1(b0_reflist[i + 1]) | + G1_REG_BD_REF_PIC_BINIT_RLIST_F2(b0_reflist[i + 2]) | + G1_REG_BD_REF_PIC_BINIT_RLIST_B0(b1_reflist[i]) | + G1_REG_BD_REF_PIC_BINIT_RLIST_B1(b1_reflist[i + 1]) | + G1_REG_BD_REF_PIC_BINIT_RLIST_B2(b1_reflist[i + 2]); + vdpu_write_relaxed(vpu, reg, G1_REG_BD_REF_PIC(reg_num++)); + } + + /* + * G1_REG_BD_P_REF_PIC register contains last entries (index 15) + * of forward and backward reference picture lists and first 4 entries + * of P forward picture list. + */ + reg = G1_REG_BD_P_REF_PIC_BINIT_RLIST_F15(b0_reflist[15]) | + G1_REG_BD_P_REF_PIC_BINIT_RLIST_B15(b1_reflist[15]) | + G1_REG_BD_P_REF_PIC_PINIT_RLIST_F0(p_reflist[0]) | + G1_REG_BD_P_REF_PIC_PINIT_RLIST_F1(p_reflist[1]) | + G1_REG_BD_P_REF_PIC_PINIT_RLIST_F2(p_reflist[2]) | + G1_REG_BD_P_REF_PIC_PINIT_RLIST_F3(p_reflist[3]); + vdpu_write_relaxed(vpu, reg, G1_REG_BD_P_REF_PIC); + + /* + * Each G1_REG_FWD_PIC(x) register contains six consecutive + * entries of P forward picture list, starting from index 4. + */ + reg_num = 0; + for (i = 4; i < HANTRO_H264_DPB_SIZE; i += 6) { + reg = G1_REG_FWD_PIC_PINIT_RLIST_F0(p_reflist[i]) | + G1_REG_FWD_PIC_PINIT_RLIST_F1(p_reflist[i + 1]) | + G1_REG_FWD_PIC_PINIT_RLIST_F2(p_reflist[i + 2]) | + G1_REG_FWD_PIC_PINIT_RLIST_F3(p_reflist[i + 3]) | + G1_REG_FWD_PIC_PINIT_RLIST_F4(p_reflist[i + 4]) | + G1_REG_FWD_PIC_PINIT_RLIST_F5(p_reflist[i + 5]); + vdpu_write_relaxed(vpu, reg, G1_REG_FWD_PIC(reg_num++)); + } + + /* Set up addresses of DPB buffers. */ + for (i = 0; i < HANTRO_H264_DPB_SIZE; i++) { + struct vb2_buffer *buf = hantro_h264_get_ref_buf(ctx, i); + + vdpu_write_relaxed(vpu, vb2_dma_contig_plane_dma_addr(buf, 0), + G1_REG_ADDR_REF(i)); + } +} + +static void set_buffers(struct hantro_ctx *ctx) +{ + const struct hantro_h264_dec_ctrls *ctrls = &ctx->h264_dec.ctrls; + struct vb2_v4l2_buffer *src_buf, *dst_buf; + struct hantro_dev *vpu = ctx->dev; + dma_addr_t src_dma, dst_dma; + + src_buf = hantro_get_src_buf(ctx); + dst_buf = hantro_get_dst_buf(ctx); + + /* Source (stream) buffer. */ + src_dma = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0); + vdpu_write_relaxed(vpu, src_dma, G1_REG_ADDR_STR); + + /* Destination (decoded frame) buffer. */ + dst_dma = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0); + vdpu_write_relaxed(vpu, dst_dma, G1_REG_ADDR_DST); + + /* Higher profiles require DMV buffer appended to reference frames. */ + if (ctrls->sps->profile_idc > 66) { + size_t pic_size = ctx->h264_dec.pic_size; + size_t mv_offset = round_up(pic_size, 8); + + if (ctrls->slices[0].flags & V4L2_H264_SLICE_FLAG_BOTTOM_FIELD) + mv_offset += 32 * H264_MB_WIDTH(ctx->dst_fmt.width); + + vdpu_write_relaxed(vpu, dst_dma + mv_offset, + G1_REG_ADDR_DIR_MV); + } + + /* Auxiliary buffer prepared in hantro_g1_h264_dec_prepare_table(). */ + vdpu_write_relaxed(vpu, ctx->h264_dec.priv.dma, G1_REG_ADDR_QTABLE); +} + +void hantro_g1_h264_dec_run(struct hantro_ctx *ctx) +{ + struct hantro_dev *vpu = ctx->dev; + + /* Prepare the H264 decoder context. */ + if (hantro_h264_dec_prepare_run(ctx)) + return; + + /* Configure hardware registers. */ + set_params(ctx); + set_ref(ctx); + set_buffers(ctx); + + hantro_finish_run(ctx); + + /* Start decoding! */ + vdpu_write_relaxed(vpu, + G1_REG_CONFIG_DEC_AXI_RD_ID(0xffu) | + G1_REG_CONFIG_DEC_TIMEOUT_E | + G1_REG_CONFIG_DEC_OUT_ENDIAN | + G1_REG_CONFIG_DEC_STRENDIAN_E | + G1_REG_CONFIG_DEC_MAX_BURST(16) | + G1_REG_CONFIG_DEC_OUTSWAP32_E | + G1_REG_CONFIG_DEC_INSWAP32_E | + G1_REG_CONFIG_DEC_STRSWAP32_E | + G1_REG_CONFIG_DEC_CLK_GATE_E, + G1_REG_CONFIG); + vdpu_write(vpu, G1_REG_INTERRUPT_DEC_E, G1_REG_INTERRUPT); +} diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/staging/media/hantro/hantro_hw.h index 75f1ce45a21f..2fab655bf098 100644 --- a/drivers/staging/media/hantro/hantro_hw.h +++ b/drivers/staging/media/hantro/hantro_hw.h @@ -161,6 +161,7 @@ void hantro_jpeg_enc_exit(struct hantro_ctx *ctx); struct vb2_buffer *hantro_h264_get_ref_buf(struct hantro_ctx *ctx, unsigned int dpb_idx); int hantro_h264_dec_prepare_run(struct hantro_ctx *ctx); +void hantro_g1_h264_dec_run(struct hantro_ctx *ctx); int hantro_h264_dec_init(struct hantro_ctx *ctx); void hantro_h264_dec_exit(struct hantro_ctx *ctx); -- cgit v1.2.3-59-g8ed1b From 760327930e10f6108ce9e44854ec3b5ef30cdcbd Mon Sep 17 00:00:00 2001 From: Hertz Wong Date: Fri, 16 Aug 2019 13:01:32 -0300 Subject: media: hantro: Enable H264 decoding on rk3288 Now that the generic bits have been added, we can activate H264 decoding on rk3288. Signed-off-by: Hertz Wong Signed-off-by: Boris Brezillon Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/hantro/rk3288_vpu_hw.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/hantro/rk3288_vpu_hw.c b/drivers/staging/media/hantro/rk3288_vpu_hw.c index f1b573a006ae..6bfcc47d1e58 100644 --- a/drivers/staging/media/hantro/rk3288_vpu_hw.c +++ b/drivers/staging/media/hantro/rk3288_vpu_hw.c @@ -61,6 +61,19 @@ static const struct hantro_fmt rk3288_vpu_dec_fmts[] = { .fourcc = V4L2_PIX_FMT_NV12, .codec_mode = HANTRO_MODE_NONE, }, + { + .fourcc = V4L2_PIX_FMT_H264_SLICE, + .codec_mode = HANTRO_MODE_H264_DEC, + .max_depth = 2, + .frmsize = { + .min_width = 48, + .max_width = 3840, + .step_width = H264_MB_DIM, + .min_height = 48, + .max_height = 2160, + .step_height = H264_MB_DIM, + }, + }, { .fourcc = V4L2_PIX_FMT_MPEG2_SLICE, .codec_mode = HANTRO_MODE_MPEG2_DEC, @@ -162,6 +175,12 @@ static const struct hantro_codec_ops rk3288_vpu_codec_ops[] = { .init = hantro_jpeg_enc_init, .exit = hantro_jpeg_enc_exit, }, + [HANTRO_MODE_H264_DEC] = { + .run = hantro_g1_h264_dec_run, + .reset = rk3288_vpu_dec_reset, + .init = hantro_h264_dec_init, + .exit = hantro_h264_dec_exit, + }, [HANTRO_MODE_MPEG2_DEC] = { .run = hantro_g1_mpeg2_dec_run, .reset = rk3288_vpu_dec_reset, @@ -197,7 +216,7 @@ const struct hantro_variant rk3288_vpu_variant = { .dec_fmts = rk3288_vpu_dec_fmts, .num_dec_fmts = ARRAY_SIZE(rk3288_vpu_dec_fmts), .codec = HANTRO_JPEG_ENCODER | HANTRO_MPEG2_DECODER | - HANTRO_VP8_DECODER, + HANTRO_VP8_DECODER | HANTRO_H264_DECODER, .codec_ops = rk3288_vpu_codec_ops, .irqs = rk3288_irqs, .num_irqs = ARRAY_SIZE(rk3288_irqs), -- cgit v1.2.3-59-g8ed1b From a8ef0488cc592921a917362cca66af4a601987b9 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 14 Aug 2019 09:24:44 -0300 Subject: media: imx: add csc/scaler mem2mem device Add a single imx-media mem2mem video device that uses the IPU IC PP (image converter post processing) task for scaling and colorspace conversion. On i.MX6Q/DL SoCs with two IPUs currently only the first IPU is used. The hardware only supports writing to destination buffers up to 1024x1024 pixels in a single pass, arbitrary sizes can be achieved by rendering multiple tiles per frame. [slongerbeam@gmail.com: use ipu_image_convert_adjust(), fix device_run() error handling, add missing media-device header, unregister and remove the mem2mem device in error paths in imx_media_probe_complete() and in imx_media_remove(), updated for sync subdev registration] Signed-off-by: Philipp Zabel Signed-off-by: Steve Longerbeam Signed-off-by: Hans Verkuil [hverkuil-cisco@xs4all.nl: correct two minor checkpatch issues] [hverkuil-cisco@xs4all.nl: sparse warning: make imx6_media_probe_complete static] Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/imx/Kconfig | 1 + drivers/staging/media/imx/Makefile | 3 +- drivers/staging/media/imx/imx-media-csc-scaler.c | 926 ++++++++++++++++++++++ drivers/staging/media/imx/imx-media-dev.c | 28 +- drivers/staging/media/imx/imx-media-internal-sd.c | 4 + drivers/staging/media/imx/imx-media.h | 12 + 6 files changed, 972 insertions(+), 2 deletions(-) create mode 100644 drivers/staging/media/imx/imx-media-csc-scaler.c (limited to 'drivers/staging') diff --git a/drivers/staging/media/imx/Kconfig b/drivers/staging/media/imx/Kconfig index f51476243016..8f1ae50a4abd 100644 --- a/drivers/staging/media/imx/Kconfig +++ b/drivers/staging/media/imx/Kconfig @@ -7,6 +7,7 @@ config VIDEO_IMX_MEDIA depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG select V4L2_FWNODE + select V4L2_MEM2MEM_DEV help Say yes here to enable support for video4linux media controller driver for the i.MX5/6 SOC. diff --git a/drivers/staging/media/imx/Makefile b/drivers/staging/media/imx/Makefile index aa6c4b4ad37e..9bd9e873ba7c 100644 --- a/drivers/staging/media/imx/Makefile +++ b/drivers/staging/media/imx/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 imx6-media-objs := imx-media-dev.o imx-media-internal-sd.o \ - imx-ic-common.o imx-ic-prp.o imx-ic-prpencvf.o imx-media-vdic.o + imx-ic-common.o imx-ic-prp.o imx-ic-prpencvf.o imx-media-vdic.o \ + imx-media-csc-scaler.o imx-media-common-objs := imx-media-capture.o imx-media-dev-common.o \ imx-media-of.o imx-media-utils.o diff --git a/drivers/staging/media/imx/imx-media-csc-scaler.c b/drivers/staging/media/imx/imx-media-csc-scaler.c new file mode 100644 index 000000000000..de599af59ffc --- /dev/null +++ b/drivers/staging/media/imx/imx-media-csc-scaler.c @@ -0,0 +1,926 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * i.MX IPUv3 IC PP mem2mem CSC/Scaler driver + * + * Copyright (C) 2011 Pengutronix, Sascha Hauer + * Copyright (C) 2018 Pengutronix, Philipp Zabel + */ +#include +#include +#include +#include +#include +#include +#include