From f20387dfd065693ba7ea2788a2f893bf653c9cb8 Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Tue, 28 May 2019 13:11:19 -0400 Subject: media: allegro: add Allegro DVT video IP core driver Add a V4L2 mem-to-mem driver for Allegro DVT video IP cores as found in the EV family of the Xilinx ZynqMP SoC. The Zynq UltraScale+ Device Technical Reference Manual uses the term VCU (Video Codec Unit) for the encoder, decoder and system integration block. This driver takes care of interacting with the MicroBlaze MCU that controls the actual IP cores. The IP cores and MCU are integrated in the FPGA. The xlnx_vcu driver is responsible for configuring the clocks and providing information about the codec configuration. The driver currently only supports the H.264 video encoder. Signed-off-by: Michael Tretter Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'MAINTAINERS') diff --git a/MAINTAINERS b/MAINTAINERS index 429c6c624861..b8fbf41865c2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -668,6 +668,13 @@ S: Maintained F: Documentation/i2c/busses/i2c-ali1563 F: drivers/i2c/busses/i2c-ali1563.c +ALLEGRO DVT VIDEO IP CORE DRIVER +M: Michael Tretter +R: Pengutronix Kernel Team +L: linux-media@vger.kernel.org +S: Maintained +F: drivers/staging/media/allegro-dvt/ + ALLWINNER SECURITY SYSTEM M: Corentin Labbe L: linux-crypto@vger.kernel.org -- cgit v1.2.3 From edadd68031e5b7c1ba0c413a9549dce62a02844c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 5 Jun 2019 10:32:11 -0400 Subject: media: MAINTAINERS: update email address Use hverkuil-cisco@xs4all.nl instead of hans.verkuil@cisco.com. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'MAINTAINERS') diff --git a/MAINTAINERS b/MAINTAINERS index b8fbf41865c2..16a97ba91874 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -916,7 +916,7 @@ F: drivers/iio/adc/ad7768-1.c F: Documentation/devicetree/bindings/iio/adc/adi,ad7768-1.txt ANALOG DEVICES INC AD9389B DRIVER -M: Hans Verkuil +M: Hans Verkuil L: linux-media@vger.kernel.org S: Maintained F: drivers/media/i2c/ad9389b* @@ -948,19 +948,19 @@ S: Maintained F: drivers/media/i2c/adv748x/* ANALOG DEVICES INC ADV7511 DRIVER -M: Hans Verkuil +M: Hans Verkuil L: linux-media@vger.kernel.org S: Maintained F: drivers/media/i2c/adv7511* ANALOG DEVICES INC ADV7604 DRIVER -M: Hans Verkuil +M: Hans Verkuil L: linux-media@vger.kernel.org S: Maintained F: drivers/media/i2c/adv7604* ANALOG DEVICES INC ADV7842 DRIVER -M: Hans Verkuil +M: Hans Verkuil L: linux-media@vger.kernel.org S: Maintained F: drivers/media/i2c/adv7842* @@ -2343,7 +2343,7 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained ARM/TEGRA HDMI CEC SUBSYSTEM SUPPORT -M: Hans Verkuil +M: Hans Verkuil L: linux-tegra@vger.kernel.org L: linux-media@vger.kernel.org S: Maintained @@ -3672,7 +3672,7 @@ F: drivers/crypto/ccree/ W: https://developer.arm.com/products/system-ip/trustzone-cryptocell/cryptocell-700-family CEC FRAMEWORK -M: Hans Verkuil +M: Hans Verkuil L: linux-media@vger.kernel.org T: git git://linuxtv.org/media_tree.git W: http://linuxtv.org @@ -3689,7 +3689,7 @@ F: Documentation/devicetree/bindings/media/cec.txt F: Documentation/ABI/testing/debugfs-cec-error-inj CEC GPIO DRIVER -M: Hans Verkuil +M: Hans Verkuil L: linux-media@vger.kernel.org T: git git://linuxtv.org/media_tree.git W: http://linuxtv.org @@ -3965,7 +3965,7 @@ S: Supported F: drivers/platform/x86/classmate-laptop.c COBALT MEDIA DRIVER -M: Hans Verkuil +M: Hans Verkuil L: linux-media@vger.kernel.org T: git git://linuxtv.org/media_tree.git W: https://linuxtv.org @@ -6700,7 +6700,7 @@ F: drivers/gnss/ F: include/linux/gnss.h GO7007 MPEG CODEC -M: Hans Verkuil +M: Hans Verkuil L: linux-media@vger.kernel.org S: Maintained F: drivers/media/usb/go7007/ @@ -16672,7 +16672,7 @@ S: Maintained F: drivers/net/ethernet/via/via-velocity.* VICODEC VIRTUAL CODEC DRIVER -M: Hans Verkuil +M: Hans Verkuil L: linux-media@vger.kernel.org T: git git://linuxtv.org/media_tree.git W: https://linuxtv.org -- cgit v1.2.3 From 22670e77724d9141267c2db8f557b43575220bf7 Mon Sep 17 00:00:00 2001 From: Maxime Jourdan Date: Thu, 6 Jun 2019 12:05:12 -0400 Subject: media: MAINTAINERS: Add meson video decoder Add an entry for the meson video decoder for amlogic SoCs. Signed-off-by: Maxime Jourdan Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'MAINTAINERS') diff --git a/MAINTAINERS b/MAINTAINERS index 16a97ba91874..e7d4fb46a2f7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10222,6 +10222,14 @@ S: Maintained F: drivers/mtd/nand/raw/meson_* F: Documentation/devicetree/bindings/mtd/amlogic,meson-nand.txt +MESON VIDEO DECODER DRIVER FOR AMLOGIC SOCS +M: Maxime Jourdan +L: linux-media@lists.freedesktop.org +L: linux-amlogic@lists.infradead.org +S: Supported +F: drivers/staging/media/meson/vdec/ +T: git git://linuxtv.org/media_tree.git + METHODE UDPU SUPPORT M: Vladimir Vid S: Maintained -- cgit v1.2.3 From a29add8c9bb29dfa8dc47c71b2702e9cc4f332a6 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 12 Jun 2019 05:39:06 -0400 Subject: media: rockchip/vpu: rename from rockchip to hantro Rename the driver and all relevant identifiers from Rockchip to Hantro, as other Hantro IP based VPU implementations can be supported by the same driver. The RK3288 decoder is Hantro G1 based, the encoder is Hantro H1. This patch just renames, no functional changes. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 4 +- drivers/staging/media/Kconfig | 4 +- drivers/staging/media/Makefile | 2 +- drivers/staging/media/hantro/Kconfig | 23 + drivers/staging/media/hantro/Makefile | 15 + drivers/staging/media/hantro/TODO | 13 + drivers/staging/media/hantro/hantro.h | 334 ++++++++ drivers/staging/media/hantro/hantro_drv.c | 854 ++++++++++++++++++++ drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c | 260 +++++++ drivers/staging/media/hantro/hantro_g1_regs.h | 301 ++++++++ drivers/staging/media/hantro/hantro_h1_jpeg_enc.c | 125 +++ drivers/staging/media/hantro/hantro_h1_regs.h | 154 ++++ drivers/staging/media/hantro/hantro_hw.h | 102 +++ drivers/staging/media/hantro/hantro_jpeg.c | 319 ++++++++ drivers/staging/media/hantro/hantro_jpeg.h | 13 + drivers/staging/media/hantro/hantro_mpeg2.c | 61 ++ drivers/staging/media/hantro/hantro_v4l2.c | 686 +++++++++++++++++ drivers/staging/media/hantro/hantro_v4l2.h | 26 + drivers/staging/media/hantro/rk3288_vpu_hw.c | 178 +++++ drivers/staging/media/hantro/rk3399_vpu_hw.c | 177 +++++ .../staging/media/hantro/rk3399_vpu_hw_jpeg_enc.c | 165 ++++ .../staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c | 266 +++++++ drivers/staging/media/hantro/rk3399_vpu_regs.h | 600 +++++++++++++++ drivers/staging/media/rockchip/vpu/Kconfig | 14 - drivers/staging/media/rockchip/vpu/Makefile | 14 - drivers/staging/media/rockchip/vpu/TODO | 13 - drivers/staging/media/rockchip/vpu/rk3288_vpu_hw.c | 177 ----- .../media/rockchip/vpu/rk3288_vpu_hw_jpeg_enc.c | 125 --- .../media/rockchip/vpu/rk3288_vpu_hw_mpeg2_dec.c | 261 ------- .../staging/media/rockchip/vpu/rk3288_vpu_regs.h | 443 ----------- drivers/staging/media/rockchip/vpu/rk3399_vpu_hw.c | 177 ----- .../media/rockchip/vpu/rk3399_vpu_hw_jpeg_enc.c | 165 ---- .../media/rockchip/vpu/rk3399_vpu_hw_mpeg2_dec.c | 267 ------- .../staging/media/rockchip/vpu/rk3399_vpu_regs.h | 600 --------------- drivers/staging/media/rockchip/vpu/rockchip_vpu.h | 334 -------- .../staging/media/rockchip/vpu/rockchip_vpu_drv.c | 857 --------------------- .../staging/media/rockchip/vpu/rockchip_vpu_hw.h | 102 --- .../staging/media/rockchip/vpu/rockchip_vpu_jpeg.c | 319 -------- .../staging/media/rockchip/vpu/rockchip_vpu_jpeg.h | 14 - .../media/rockchip/vpu/rockchip_vpu_mpeg2.c | 61 -- .../staging/media/rockchip/vpu/rockchip_vpu_v4l2.c | 692 ----------------- .../staging/media/rockchip/vpu/rockchip_vpu_v4l2.h | 26 - 42 files changed, 4677 insertions(+), 4666 deletions(-) create mode 100644 drivers/staging/media/hantro/Kconfig create mode 100644 drivers/staging/media/hantro/Makefile create mode 100644 drivers/staging/media/hantro/TODO create mode 100644 drivers/staging/media/hantro/hantro.h create mode 100644 drivers/staging/media/hantro/hantro_drv.c create mode 100644 drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c create mode 100644 drivers/staging/media/hantro/hantro_g1_regs.h create mode 100644 drivers/staging/media/hantro/hantro_h1_jpeg_enc.c create mode 100644 drivers/staging/media/hantro/hantro_h1_regs.h create mode 100644 drivers/staging/media/hantro/hantro_hw.h create mode 100644 drivers/staging/media/hantro/hantro_jpeg.c create mode 100644 drivers/staging/media/hantro/hantro_jpeg.h create mode 100644 drivers/staging/media/hantro/hantro_mpeg2.c create mode 100644 drivers/staging/media/hantro/hantro_v4l2.c create mode 100644 drivers/staging/media/hantro/hantro_v4l2.h create mode 100644 drivers/staging/media/hantro/rk3288_vpu_hw.c create mode 100644 drivers/staging/media/hantro/rk3399_vpu_hw.c create mode 100644 drivers/staging/media/hantro/rk3399_vpu_hw_jpeg_enc.c create mode 100644 drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c create mode 100644 drivers/staging/media/hantro/rk3399_vpu_regs.h delete mode 100644 drivers/staging/media/rockchip/vpu/Kconfig delete mode 100644 drivers/staging/media/rockchip/vpu/Makefile delete mode 100644 drivers/staging/media/rockchip/vpu/TODO delete mode 100644 drivers/staging/media/rockchip/vpu/rk3288_vpu_hw.c delete mode 100644 drivers/staging/media/rockchip/vpu/rk3288_vpu_hw_jpeg_enc.c delete mode 100644 drivers/staging/media/rockchip/vpu/rk3288_vpu_hw_mpeg2_dec.c delete mode 100644 drivers/staging/media/rockchip/vpu/rk3288_vpu_regs.h delete mode 100644 drivers/staging/media/rockchip/vpu/rk3399_vpu_hw.c delete mode 100644 drivers/staging/media/rockchip/vpu/rk3399_vpu_hw_jpeg_enc.c delete mode 100644 drivers/staging/media/rockchip/vpu/rk3399_vpu_hw_mpeg2_dec.c delete mode 100644 drivers/staging/media/rockchip/vpu/rk3399_vpu_regs.h delete mode 100644 drivers/staging/media/rockchip/vpu/rockchip_vpu.h delete mode 100644 drivers/staging/media/rockchip/vpu/rockchip_vpu_drv.c delete mode 100644 drivers/staging/media/rockchip/vpu/rockchip_vpu_hw.h delete mode 100644 drivers/staging/media/rockchip/vpu/rockchip_vpu_jpeg.c delete mode 100644 drivers/staging/media/rockchip/vpu/rockchip_vpu_jpeg.h delete mode 100644 drivers/staging/media/rockchip/vpu/rockchip_vpu_mpeg2.c delete mode 100644 drivers/staging/media/rockchip/vpu/rockchip_vpu_v4l2.c delete mode 100644 drivers/staging/media/rockchip/vpu/rockchip_vpu_v4l2.h (limited to 'MAINTAINERS') diff --git a/MAINTAINERS b/MAINTAINERS index 6a3bac28ebb4..29cca8aabf19 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13512,11 +13512,11 @@ S: Maintained F: drivers/media/platform/rockchip/rga/ F: Documentation/devicetree/bindings/media/rockchip-rga.txt -ROCKCHIP VPU CODEC DRIVER +HANTRO VPU CODEC DRIVER M: Ezequiel Garcia L: linux-media@vger.kernel.org S: Maintained -F: drivers/staging/media/platform/rockchip/vpu/ +F: drivers/staging/media/platform/hantro/ F: Documentation/devicetree/bindings/media/rockchip-vpu.txt ROCKER DRIVER diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig index 7212762035b4..534d85d6c5e3 100644 --- a/drivers/staging/media/Kconfig +++ b/drivers/staging/media/Kconfig @@ -26,14 +26,14 @@ source "drivers/staging/media/bcm2048/Kconfig" source "drivers/staging/media/davinci_vpfe/Kconfig" +source "drivers/staging/media/hantro/Kconfig" + source "drivers/staging/media/imx/Kconfig" source "drivers/staging/media/meson/vdec/Kconfig" source "drivers/staging/media/omap4iss/Kconfig" -source "drivers/staging/media/rockchip/vpu/Kconfig" - source "drivers/staging/media/sunxi/Kconfig" source "drivers/staging/media/tegra-vde/Kconfig" diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile index 4222584a9bcb..c486298194da 100644 --- a/drivers/staging/media/Makefile +++ b/drivers/staging/media/Makefile @@ -7,6 +7,6 @@ obj-$(CONFIG_VIDEO_MESON_VDEC) += meson/vdec/ obj-$(CONFIG_VIDEO_OMAP4) += omap4iss/ obj-$(CONFIG_VIDEO_SUNXI) += sunxi/ obj-$(CONFIG_TEGRA_VDE) += tegra-vde/ -obj-$(CONFIG_VIDEO_ROCKCHIP_VPU) += rockchip/vpu/ +obj-$(CONFIG_VIDEO_HANTRO) += hantro/ obj-$(CONFIG_VIDEO_IPU3_IMGU) += ipu3/ obj-$(CONFIG_SOC_CAMERA) += soc_camera/ diff --git a/drivers/staging/media/hantro/Kconfig b/drivers/staging/media/hantro/Kconfig new file mode 100644 index 000000000000..be133bbaa68a --- /dev/null +++ b/drivers/staging/media/hantro/Kconfig @@ -0,0 +1,23 @@ +# SPDX-License-Identifier: GPL-2.0 +config VIDEO_HANTRO + tristate "Hantro VPU driver" + depends on ARCH_ROCKCHIP || COMPILE_TEST + depends on VIDEO_DEV && VIDEO_V4L2 && MEDIA_CONTROLLER + depends on MEDIA_CONTROLLER_REQUEST_API + select VIDEOBUF2_DMA_CONTIG + select VIDEOBUF2_VMALLOC + select V4L2_MEM2MEM_DEV + help + Support for the Hantro IP based Video Processing Unit present on + Rockchip SoC, which accelerates video and image encoding and + decoding. + To compile this driver as a module, choose M here: the module + will be called hantro-vpu. + +config VIDEO_HANTRO_ROCKCHIP + bool "Hantro VPU Rockchip support" + depends on VIDEO_HANTRO + depends on ARCH_ROCKCHIP || COMPILE_TEST + default y + help + Enable support for RK3288 and RK3399 SoCs. diff --git a/drivers/staging/media/hantro/Makefile b/drivers/staging/media/hantro/Makefile new file mode 100644 index 000000000000..1584acdbf4a3 --- /dev/null +++ b/drivers/staging/media/hantro/Makefile @@ -0,0 +1,15 @@ +obj-$(CONFIG_VIDEO_HANTRO) += hantro-vpu.o + +hantro-vpu-y += \ + hantro_drv.o \ + hantro_v4l2.o \ + hantro_h1_jpeg_enc.o \ + hantro_g1_mpeg2_dec.o \ + rk3399_vpu_hw_jpeg_enc.o \ + rk3399_vpu_hw_mpeg2_dec.o \ + hantro_jpeg.o \ + hantro_mpeg2.o + +hantro-vpu-$(CONFIG_VIDEO_HANTRO_ROCKCHIP) += \ + rk3288_vpu_hw.o \ + rk3399_vpu_hw.o diff --git a/drivers/staging/media/hantro/TODO b/drivers/staging/media/hantro/TODO new file mode 100644 index 000000000000..fa0c94057007 --- /dev/null +++ b/drivers/staging/media/hantro/TODO @@ -0,0 +1,13 @@ +* Support for VP8, VP9 and H264 is planned for this driver. + + Given the V4L controls for those CODECs will be part of + the uABI, it will be required to have the driver in staging. + + For this reason, we are keeping this driver in staging for now. + +* Add support for the S_SELECTION API. + See the comment for VEPU_REG_ENC_OVER_FILL_STRM_OFFSET. + +* Instead of having a DMA bounce buffer, it could be possible to use a + normal buffer and memmove() the payload to make space for the header. + This might need to use extra JPEG markers for padding reasons. diff --git a/drivers/staging/media/hantro/hantro.h b/drivers/staging/media/hantro/hantro.h new file mode 100644 index 000000000000..14e685428203 --- /dev/null +++ b/drivers/staging/media/hantro/hantro.h @@ -0,0 +1,334 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Hantro VPU codec driver + * + * Copyright 2018 Google LLC. + * Tomasz Figa + * + * Based on s5p-mfc driver by Samsung Electronics Co., Ltd. + * Copyright (C) 2011 Samsung Electronics Co., Ltd. + */ + +#ifndef HANTRO_H_ +#define HANTRO_H_ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "hantro_hw.h" + +#define HANTRO_MAX_CLOCKS 4 + +#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) + +#define JPEG_MB_DIM 16 +#define JPEG_MB_WIDTH(w) DIV_ROUND_UP(w, JPEG_MB_DIM) +#define JPEG_MB_HEIGHT(h) DIV_ROUND_UP(h, JPEG_MB_DIM) + +struct hantro_ctx; +struct hantro_codec_ops; + +#define HANTRO_JPEG_ENCODER BIT(0) +#define HANTRO_ENCODERS 0x0000ffff + +#define HANTRO_MPEG2_DECODER BIT(16) +#define HANTRO_DECODERS 0xffff0000 + +/** + * struct hantro_variant - information about VPU hardware variant + * + * @enc_offset: Offset from VPU base to encoder registers. + * @dec_offset: Offset from VPU base to decoder registers. + * @enc_fmts: Encoder formats. + * @num_enc_fmts: Number of encoder formats. + * @dec_fmts: Decoder formats. + * @num_dec_fmts: Number of decoder formats. + * @codec: Supported codecs + * @codec_ops: Codec ops. + * @init: Initialize hardware. + * @vepu_irq: encoder interrupt handler + * @vdpu_irq: decoder interrupt handler + * @clk_names: array of clock names + * @num_clocks: number of clocks in the array + */ +struct hantro_variant { + unsigned int enc_offset; + unsigned int dec_offset; + const struct hantro_fmt *enc_fmts; + unsigned int num_enc_fmts; + const struct hantro_fmt *dec_fmts; + unsigned int num_dec_fmts; + unsigned int codec; + const struct hantro_codec_ops *codec_ops; + int (*init)(struct hantro_dev *vpu); + irqreturn_t (*vepu_irq)(int irq, void *priv); + irqreturn_t (*vdpu_irq)(int irq, void *priv); + const char *clk_names[HANTRO_MAX_CLOCKS]; + int num_clocks; +}; + +/** + * 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_MPEG2_DEC: MPEG-2 decoder. + */ +enum hantro_codec_mode { + HANTRO_MODE_NONE = -1, + HANTRO_MODE_JPEG_ENC, + HANTRO_MODE_MPEG2_DEC, +}; + +/* + * 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; +}; + +/* + * struct hantro_func - Hantro VPU functionality + * + * @id: processing functionality ID (can be + * %MEDIA_ENT_F_PROC_VIDEO_ENCODER or + * %MEDIA_ENT_F_PROC_VIDEO_DECODER) + * @vdev: &struct video_device that exposes the encoder or + * decoder functionality + * @source_pad: &struct media_pad with the source pad. + * @sink: &struct media_entity pointer with the sink entity + * @sink_pad: &struct media_pad with the sink pad. + * @proc: &struct media_entity pointer with the M2M device itself. + * @proc_pads: &struct media_pad with the @proc pads. + * @intf_devnode: &struct media_intf devnode pointer with the interface + * with controls the M2M device. + * + * Contains everything needed to attach the video device to the media device. + */ +struct hantro_func { + unsigned int id; + struct video_device vdev; + struct media_pad source_pad; + struct media_entity sink; + struct media_pad sink_pad; + struct media_entity proc; + struct media_pad proc_pads[2]; + struct media_intf_devnode *intf_devnode; +}; + +static inline struct hantro_func * +hantro_vdev_to_func(struct video_device *vdev) +{ + return container_of(vdev, struct hantro_func, vdev); +} + +/** + * struct hantro_dev - driver data + * @v4l2_dev: V4L2 device to register video devices for. + * @m2m_dev: mem2mem device associated to this device. + * @mdev: media device associated to this device. + * @encoder: encoder functionality. + * @decoder: decoder functionality. + * @pdev: Pointer to VPU platform device. + * @dev: Pointer to device for convenient logging using + * dev_ macros. + * @clocks: Array of clock handles. + * @base: Mapped address of VPU registers. + * @enc_base: Mapped address of VPU encoder register for convenience. + * @dec_base: Mapped address of VPU decoder register for convenience. + * @vpu_mutex: Mutex to synchronize V4L2 calls. + * @irqlock: Spinlock to synchronize access to data structures + * shared with interrupt handlers. + * @variant: Hardware variant-specific parameters. + * @watchdog_work: Delayed work for hardware timeout handling. + */ +struct hantro_dev { + struct v4l2_device v4l2_dev; + struct v4l2_m2m_dev *m2m_dev; + struct media_device mdev; + struct hantro_func *encoder; + struct hantro_func *decoder; + struct platform_device *pdev; + struct device *dev; + struct clk_bulk_data clocks[HANTRO_MAX_CLOCKS]; + void __iomem *base; + void __iomem *enc_base; + void __iomem *dec_base; + + struct mutex vpu_mutex; /* video_device lock */ + spinlock_t irqlock; + const struct hantro_variant *variant; + struct delayed_work watchdog_work; +}; + +/** + * struct hantro_ctx - Context (instance) private data. + * + * @dev: VPU driver data to which the context belongs. + * @fh: V4L2 file handler. + * + * @sequence_cap: Sequence counter for capture queue + * @sequence_out: Sequence counter for output queue + * + * @vpu_src_fmt: Descriptor of active source format. + * @src_fmt: V4L2 pixel format of active source format. + * @vpu_dst_fmt: Descriptor of active destination format. + * @dst_fmt: V4L2 pixel format of active destination format. + * + * @ctrl_handler: Control handler used to register controls. + * @jpeg_quality: User-specified JPEG compression quality. + * + * @buf_finish: Buffer finish. This depends on encoder or decoder + * context, and it's called right before + * calling v4l2_m2m_job_finish. + * @codec_ops: Set of operations related to codec mode. + * @jpeg_enc: JPEG-encoding context. + * @mpeg2_dec: MPEG-2-decoding context. + */ +struct hantro_ctx { + struct hantro_dev *dev; + struct v4l2_fh fh; + + u32 sequence_cap; + u32 sequence_out; + + const struct hantro_fmt *vpu_src_fmt; + struct v4l2_pix_format_mplane src_fmt; + const struct hantro_fmt *vpu_dst_fmt; + struct v4l2_pix_format_mplane dst_fmt; + + struct v4l2_ctrl_handler ctrl_handler; + int jpeg_quality; + + int (*buf_finish)(struct hantro_ctx *ctx, + struct vb2_buffer *buf, + unsigned int bytesused); + + const struct hantro_codec_ops *codec_ops; + + /* Specific for particular codec modes. */ + union { + struct hantro_jpeg_enc_hw_ctx jpeg_enc; + struct hantro_mpeg2_dec_hw_ctx mpeg2_dec; + }; +}; + +/** + * struct hantro_fmt - information about supported video formats. + * @name: Human readable name of the format. + * @fourcc: FourCC code of the format. See V4L2_PIX_FMT_*. + * @codec_mode: Codec mode related to this format. See + * enum hantro_codec_mode. + * @header_size: Optional header size. Currently used by JPEG encoder. + * @max_depth: Maximum depth, for bitstream formats + * @enc_fmt: Format identifier for encoder registers. + * @frmsize: Supported range of frame sizes (only for bitstream formats). + */ +struct hantro_fmt { + char *name; + u32 fourcc; + enum hantro_codec_mode codec_mode; + int header_size; + int max_depth; + enum hantro_enc_fmt enc_fmt; + struct v4l2_frmsize_stepwise frmsize; +}; + +/* Logging helpers */ + +/** + * debug - Module parameter to control level of debugging messages. + * + * Level of debugging messages can be controlled by bits of + * module parameter called "debug". Meaning of particular + * bits is as follows: + * + * bit 0 - global information: mode, size, init, release + * bit 1 - each run start/result information + * bit 2 - contents of small controls from userspace + * bit 3 - contents of big controls from userspace + * bit 4 - detail fmt, ctrl, buffer q/dq information + * bit 5 - detail function enter/leave trace information + * bit 6 - register write/read information + */ +extern int hantro_debug; + +#define vpu_debug(level, fmt, args...) \ + do { \ + if (hantro_debug & BIT(level)) \ + pr_info("%s:%d: " fmt, \ + __func__, __LINE__, ##args); \ + } while (0) + +#define vpu_err(fmt, args...) \ + pr_err("%s:%d: " fmt, __func__, __LINE__, ##args) + +/* Structure access helpers. */ +static inline struct hantro_ctx *fh_to_ctx(struct v4l2_fh *fh) +{ + return container_of(fh, struct hantro_ctx, fh); +} + +/* Register accessors. */ +static inline void vepu_write_relaxed(struct hantro_dev *vpu, + u32 val, u32 reg) +{ + vpu_debug(6, "0x%04x = 0x%08x\n", reg / 4, val); + writel_relaxed(val, vpu->enc_base + reg); +} + +static inline void vepu_write(struct hantro_dev *vpu, u32 val, u32 reg) +{ + vpu_debug(6, "0x%04x = 0x%08x\n", reg / 4, val); + writel(val, vpu->enc_base + reg); +} + +static inline u32 vepu_read(struct hantro_dev *vpu, u32 reg) +{ + u32 val = readl(vpu->enc_base + reg); + + vpu_debug(6, "0x%04x = 0x%08x\n", reg / 4, val); + return val; +} + +static inline void vdpu_write_relaxed(struct hantro_dev *vpu, + u32 val, u32 reg) +{ + vpu_debug(6, "0x%04x = 0x%08x\n", reg / 4, val); + writel_relaxed(val, vpu->dec_base + reg); +} + +static inline void vdpu_write(struct hantro_dev *vpu, u32 val, u32 reg) +{ + vpu_debug(6, "0x%04x = 0x%08x\n", reg / 4, val); + writel(val, vpu->dec_base + reg); +} + +static inline u32 vdpu_read(struct hantro_dev *vpu, u32 reg) +{ + u32 val = readl(vpu->dec_base + reg); + + vpu_debug(6, "0x%04x = 0x%08x\n", reg / 4, val); + return val; +} + +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); + +#endif /* HANTRO_H_ */ diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c new file mode 100644 index 000000000000..d325f63c7412 --- /dev/null +++ b/drivers/staging/media/hantro/hantro_drv.c @@ -0,0 +1,854 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Hantro VPU codec driver + * + * Copyright (C) 2018 Collabora, Ltd. + * Copyright 2018 Google LLC. + * Tomasz Figa + * + * Based on s5p-mfc driver by Samsung Electronics Co., Ltd. + * Copyright (C) 2011 Samsung Electronics Co., Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hantro_v4l2.h" +#include "hantro.h" +#include "hantro_hw.h" + +#define DRIVER_NAME "hantro-vpu" + +int hantro_debug; +module_param_named(debug, hantro_debug, int, 0644); +MODULE_PARM_DESC(debug, + "Debug level - higher value produces more verbose messages"); + +void *hantro_get_ctrl(struct hantro_ctx *ctx, u32 id) +{ + struct v4l2_ctrl *ctrl; + + ctrl = v4l2_ctrl_find(&ctx->ctrl_handler, id); + return ctrl ? ctrl->p_cur.p : NULL; +} + +dma_addr_t hantro_get_ref(struct vb2_queue *q, u64 ts) +{ + int index; + + index = vb2_find_timestamp(q, ts, 0); + if (index >= 0) + return vb2_dma_contig_plane_dma_addr(q->bufs[index], 0); + return 0; +} + +static int +hantro_enc_buf_finish(struct hantro_ctx *ctx, struct vb2_buffer *buf, + unsigned int bytesused) +{ + size_t avail_size; + + avail_size = vb2_plane_size(buf, 0) - ctx->vpu_dst_fmt->header_size; + if (bytesused > avail_size) + return -EINVAL; + /* + * The bounce buffer is only for the JPEG encoder. + * TODO: Rework the JPEG encoder to eliminate the need + * for a bounce buffer. + */ + if (ctx->jpeg_enc.bounce_buffer.cpu) { + memcpy(vb2_plane_vaddr(buf, 0) + + ctx->vpu_dst_fmt->header_size, + ctx->jpeg_enc.bounce_buffer.cpu, bytesused); + } + buf->planes[0].bytesused = + ctx->vpu_dst_fmt->header_size + bytesused; + return 0; +} + +static int +hantro_dec_buf_finish(struct hantro_ctx *ctx, struct vb2_buffer *buf, + unsigned int bytesused) +{ + /* For decoders set bytesused as per the output picture. */ + buf->planes[0].bytesused = ctx->dst_fmt.plane_fmt[0].sizeimage; + return 0; +} + +static void hantro_job_finish(struct hantro_dev *vpu, + struct hantro_ctx *ctx, + unsigned int bytesused, + enum vb2_buffer_state result) +{ + struct vb2_v4l2_buffer *src, *dst; + int ret; + + pm_runtime_mark_last_busy(vpu->dev); + pm_runtime_put_autosuspend(vpu->dev); + clk_bulk_disable(vpu->variant->num_clocks, vpu->clocks); + + src = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + dst = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + + if (WARN_ON(!src)) + return; + if (WARN_ON(!dst)) + return; + + 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; + + v4l2_m2m_buf_done(src, result); + v4l2_m2m_buf_done(dst, result); + + v4l2_m2m_job_finish(vpu->m2m_dev, ctx->fh.m2m_ctx); +} + +void hantro_irq_done(struct hantro_dev *vpu, unsigned int bytesused, + enum vb2_buffer_state result) +{ + struct hantro_ctx *ctx = + v4l2_m2m_get_curr_priv(vpu->m2m_dev); + + /* + * If cancel_delayed_work returns false + * the timeout expired. The watchdog is running, + * and will take care of finishing the job. + */ + if (cancel_delayed_work(&vpu->watchdog_work)) + hantro_job_finish(vpu, ctx, bytesused, result); +} + +void hantro_watchdog(struct work_struct *work) +{ + struct hantro_dev *vpu; + struct hantro_ctx *ctx; + + vpu = container_of(to_delayed_work(work), + struct hantro_dev, watchdog_work); + ctx = v4l2_m2m_get_curr_priv(vpu->m2m_dev); + if (ctx) { + vpu_err("frame processing timed out!\n"); + ctx->codec_ops->reset(ctx); + hantro_job_finish(vpu, ctx, 0, VB2_BUF_STATE_ERROR); + } +} + +static void device_run(void *priv) +{ + struct hantro_ctx *ctx = priv; + int ret; + + ret = clk_bulk_enable(ctx->dev->variant->num_clocks, ctx->dev->clocks); + if (ret) + goto err_cancel_job; + ret = pm_runtime_get_sync(ctx->dev->dev); + if (ret < 0) + goto err_cancel_job; + + ctx->codec_ops->run(ctx); + return; + +err_cancel_job: + hantro_job_finish(ctx->dev, ctx, 0, VB2_BUF_STATE_ERROR); +} + +bool hantro_is_encoder_ctx(const struct hantro_ctx *ctx) +{ + return ctx->buf_finish == hantro_enc_buf_finish; +} + +static struct v4l2_m2m_ops vpu_m2m_ops = { + .device_run = device_run, +}; + +static int +queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) +{ + struct hantro_ctx *ctx = priv; + int ret; + + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + src_vq->io_modes = VB2_MMAP | VB2_DMABUF; + src_vq->drv_priv = ctx; + src_vq->ops = &hantro_queue_ops; + src_vq->mem_ops = &vb2_dma_contig_memops; + + /* + * Driver does mostly sequential access, so sacrifice TLB efficiency + * for faster allocation. Also, no CPU access on the source queue, + * so no kernel mapping needed. + */ + src_vq->dma_attrs = DMA_ATTR_ALLOC_SINGLE_PAGES | + DMA_ATTR_NO_KERNEL_MAPPING; + src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + src_vq->lock = &ctx->dev->vpu_mutex; + src_vq->dev = ctx->dev->v4l2_dev.dev; + src_vq->supports_requests = true; + + ret = vb2_queue_init(src_vq); + if (ret) + return ret; + + /* + * When encoding, the CAPTURE queue doesn't need dma memory, + * as the CPU needs to create the JPEG frames, from the + * hardware-produced JPEG payload. + * + * For the DMA destination buffer, we use a bounce buffer. + */ + if (hantro_is_encoder_ctx(ctx)) { + dst_vq->mem_ops = &vb2_vmalloc_memops; + } else { + dst_vq->bidirectional = true; + dst_vq->mem_ops = &vb2_dma_contig_memops; + dst_vq->dma_attrs = DMA_ATTR_ALLOC_SINGLE_PAGES | + DMA_ATTR_NO_KERNEL_MAPPING; + } + + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; + dst_vq->drv_priv = ctx; + dst_vq->ops = &hantro_queue_ops; + dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + dst_vq->lock = &ctx->dev->vpu_mutex; + dst_vq->dev = ctx->dev->v4l2_dev.dev; + + return vb2_queue_init(dst_vq); +} + +static int hantro_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct hantro_ctx *ctx; + + ctx = container_of(ctrl->handler, + struct hantro_ctx, ctrl_handler); + + vpu_debug(1, "s_ctrl: id = %d, val = %d\n", ctrl->id, ctrl->val); + + switch (ctrl->id) { + case V4L2_CID_JPEG_COMPRESSION_QUALITY: + ctx->jpeg_quality = ctrl->val; + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct v4l2_ctrl_ops hantro_ctrl_ops = { + .s_ctrl = hantro_s_ctrl, +}; + +static struct hantro_ctrl controls[] = { + { + .id = V4L2_CID_JPEG_COMPRESSION_QUALITY, + .codec = HANTRO_JPEG_ENCODER, + .cfg = { + .min = 5, + .max = 100, + .step = 1, + .def = 50, + }, + }, { + .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_QUANTIZATION, + .codec = HANTRO_MPEG2_DECODER, + .cfg = { + .elem_size = sizeof(struct v4l2_ctrl_mpeg2_quantization), + }, + }, +}; + +static int hantro_ctrls_setup(struct hantro_dev *vpu, + struct hantro_ctx *ctx, + int allowed_codecs) +{ + int i, num_ctrls = ARRAY_SIZE(controls); + + v4l2_ctrl_handler_init(&ctx->ctrl_handler, num_ctrls); + + 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); + } + + if (ctx->ctrl_handler.error) { + vpu_err("Adding control (%d) failed %d\n", + controls[i].id, + ctx->ctrl_handler.error); + v4l2_ctrl_handler_free(&ctx->ctrl_handler); + return ctx->ctrl_handler.error; + } + } + return v4l2_ctrl_handler_setup(&ctx->ctrl_handler); +} + +/* + * V4L2 file operations. + */ + +static int hantro_open(struct file *filp) +{ + struct hantro_dev *vpu = video_drvdata(filp); + struct video_device *vdev = video_devdata(filp); + struct hantro_func *func = hantro_vdev_to_func(vdev); + struct hantro_ctx *ctx; + int allowed_codecs, ret; + + /* + * We do not need any extra locking here, because we operate only + * on local data here, except reading few fields from dev, which + * do not change through device's lifetime (which is guaranteed by + * reference on module from open()) and V4L2 internal objects (such + * as vdev and ctx->fh), which have proper locking done in respective + * helper functions used here. + */ + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ctx->dev = vpu; + if (func->id == MEDIA_ENT_F_PROC_VIDEO_ENCODER) { + allowed_codecs = vpu->variant->codec & HANTRO_ENCODERS; + ctx->buf_finish = hantro_enc_buf_finish; + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(vpu->m2m_dev, ctx, + queue_init); + } else if (func->id == MEDIA_ENT_F_PROC_VIDEO_DECODER) { + allowed_codecs = vpu->variant->codec & HANTRO_DECODERS; + ctx->buf_finish = hantro_dec_buf_finish; + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(vpu->m2m_dev, ctx, + queue_init); + } else { + ctx->fh.m2m_ctx = ERR_PTR(-ENODEV); + } + if (IS_ERR(ctx->fh.m2m_ctx)) { + ret = PTR_ERR(ctx->fh.m2m_ctx); + kfree(ctx); + return ret; + } + + v4l2_fh_init(&ctx->fh, vdev); + filp->private_data = &ctx->fh; + v4l2_fh_add(&ctx->fh); + + hantro_reset_fmts(ctx); + + ret = hantro_ctrls_setup(vpu, ctx, allowed_codecs); + if (ret) { + vpu_err("Failed to set up controls\n"); + goto err_fh_free; + } + ctx->fh.ctrl_handler = &ctx->ctrl_handler; + + return 0; + +err_fh_free: + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + kfree(ctx); + return ret; +} + +static int hantro_release(struct file *filp) +{ + struct hantro_ctx *ctx = + container_of(filp->private_data, struct hantro_ctx, fh); + + /* + * No need for extra locking because this was the last reference + * to this file. + */ + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + v4l2_ctrl_handler_free(&ctx->ctrl_handler); + kfree(ctx); + + return 0; +} + +static const struct v4l2_file_operations hantro_fops = { + .owner = THIS_MODULE, + .open = hantro_open, + .release = hantro_release, + .poll = v4l2_m2m_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = v4l2_m2m_fop_mmap, +}; + +static const struct of_device_id of_hantro_match[] = { +#ifdef CONFIG_VIDEO_HANTRO_ROCKCHIP + { .compatible = "rockchip,rk3399-vpu", .data = &rk3399_vpu_variant, }, + { .compatible = "rockchip,rk3288-vpu", .data = &rk3288_vpu_variant, }, +#endif + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_hantro_match); + +static int hantro_register_entity(struct media_device *mdev, + struct media_entity *entity, + const char *entity_name, + struct media_pad *pads, int num_pads, + int function, struct video_device *vdev) +{ + char *name; + int ret; + + entity->obj_type = MEDIA_ENTITY_TYPE_BASE; + if (function == MEDIA_ENT_F_IO_V4L) { + entity->info.dev.major = VIDEO_MAJOR; + entity->info.dev.minor = vdev->minor; + } + + name = devm_kasprintf(mdev->dev, GFP_KERNEL, "%s-%s", vdev->name, + entity_name); + if (!name) + return -ENOMEM; + + entity->name = name; + entity->function = function; + + ret = media_entity_pads_init(entity, num_pads, pads); + if (ret) + return ret; + + ret = media_device_register_entity(mdev, entity); + if (ret) + return ret; + + return 0; +} + +static int hantro_attach_func(struct hantro_dev *vpu, + struct hantro_func *func) +{ + struct media_device *mdev = &vpu->mdev; + struct media_link *link; + int ret; + + /* Create the three encoder entities with their pads */ + func->source_pad.flags = MEDIA_PAD_FL_SOURCE; + ret = hantro_register_entity(mdev, &func->vdev.entity, "source", + &func->source_pad, 1, MEDIA_ENT_F_IO_V4L, + &func->vdev); + if (ret) + return ret; + + func->proc_pads[0].flags = MEDIA_PAD_FL_SINK; + func->proc_pads[1].flags = MEDIA_PAD_FL_SOURCE; + ret = hantro_register_entity(mdev, &func->proc, "proc", + func->proc_pads, 2, func->id, + &func->vdev); + if (ret) + goto err_rel_entity0; + + func->sink_pad.flags = MEDIA_PAD_FL_SINK; + ret = hantro_register_entity(mdev, &func->sink, "sink", + &func->sink_pad, 1, MEDIA_ENT_F_IO_V4L, + &func->vdev); + if (ret) + goto err_rel_entity1; + + /* Connect the three entities */ + ret = media_create_pad_link(&func->vdev.entity, 0, &func->proc, 1, + MEDIA_LNK_FL_IMMUTABLE | + MEDIA_LNK_FL_ENABLED); + if (ret) + goto err_rel_entity2; + + ret = media_create_pad_link(&func->proc, 0, &func->sink, 0, + MEDIA_LNK_FL_IMMUTABLE | + MEDIA_LNK_FL_ENABLED); + if (ret) + goto err_rm_links0; + + /* Create video interface */ + func->intf_devnode = media_devnode_create(mdev, MEDIA_INTF_T_V4L_VIDEO, + 0, VIDEO_MAJOR, + func->vdev.minor); + if (!func->intf_devnode) { + ret = -ENOMEM; + goto err_rm_links1; + } + + /* Connect the two DMA engines to the interface */ + link = media_create_intf_link(&func->vdev.entity, + &func->intf_devnode->intf, + MEDIA_LNK_FL_IMMUTABLE | + MEDIA_LNK_FL_ENABLED); + if (!link) { + ret = -ENOMEM; + goto err_rm_devnode; + } + + link = media_create_intf_link(&func->sink, &func->intf_devnode->intf, + MEDIA_LNK_FL_IMMUTABLE | + MEDIA_LNK_FL_ENABLED); + if (!link) { + ret = -ENOMEM; + goto err_rm_devnode; + } + return 0; + +err_rm_devnode: + media_devnode_remove(func->intf_devnode); + +err_rm_links1: + media_entity_remove_links(&func->sink); + +err_rm_links0: + media_entity_remove_links(&func->proc); + media_entity_remove_links(&func->vdev.entity); + +err_rel_entity2: + media_device_unregister_entity(&func->sink); + +err_rel_entity1: + media_device_unregister_entity(&func->proc); + +err_rel_entity0: + media_device_unregister_entity(&func->vdev.entity); + return ret; +} + +static void hantro_detach_func(struct hantro_func *func) +{ + media_devnode_remove(func->intf_devnode); + media_entity_remove_links(&func->sink); + media_entity_remove_links(&func->proc); + media_entity_remove_links(&func->vdev.entity); + media_device_unregister_entity(&func->sink); + media_device_unregister_entity(&func->proc); + media_device_unregister_entity(&func->vdev.entity); +} + +static int hantro_add_func(struct hantro_dev *vpu, unsigned int funcid) +{ + const struct of_device_id *match; + struct hantro_func *func; + struct video_device *vfd; + int ret; + + match = of_match_node(of_hantro_match, vpu->dev->of_node); + func = devm_kzalloc(vpu->dev, sizeof(*func), GFP_KERNEL); + if (!func) { + v4l2_err(&vpu->v4l2_dev, "Failed to allocate video device\n"); + return -ENOMEM; + } + + func->id = funcid; + + vfd = &func->vdev; + vfd->fops = &hantro_fops; + vfd->release = video_device_release_empty; + vfd->lock = &vpu->vpu_mutex; + vfd->v4l2_dev = &vpu->v4l2_dev; + vfd->vfl_dir = VFL_DIR_M2M; + vfd->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE; + vfd->ioctl_ops = &hantro_ioctl_ops; + snprintf(vfd->name, sizeof(vfd->name), "%s-%s", match->compatible, + funcid == MEDIA_ENT_F_PROC_VIDEO_ENCODER ? "enc" : "dec"); + + if (funcid == MEDIA_ENT_F_PROC_VIDEO_ENCODER) + vpu->encoder = func; + else + vpu->decoder = func; + + video_set_drvdata(vfd, vpu); + + ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1); + if (ret) { + v4l2_err(&vpu->v4l2_dev, "Failed to register video device\n"); + return ret; + } + + ret = hantro_attach_func(vpu, func); + if (ret) { + v4l2_err(&vpu->v4l2_dev, + "Failed to attach functionality to the media device\n"); + goto err_unreg_dev; + } + + v4l2_info(&vpu->v4l2_dev, "registered as /dev/video%d\n", vfd->num); + + return 0; + +err_unreg_dev: + video_unregister_device(vfd); + return ret; +} + +static int hantro_add_enc_func(struct hantro_dev *vpu) +{ + if (!vpu->variant->enc_fmts) + return 0; + + return hantro_add_func(vpu, MEDIA_ENT_F_PROC_VIDEO_ENCODER); +} + +static int hantro_add_dec_func(struct hantro_dev *vpu) +{ + if (!vpu->variant->dec_fmts) + return 0; + + return hantro_add_func(vpu, MEDIA_ENT_F_PROC_VIDEO_DECODER); +} + +static void hantro_remove_func(struct hantro_dev *vpu, + unsigned int funcid) +{ + struct hantro_func *func; + + if (funcid == MEDIA_ENT_F_PROC_VIDEO_ENCODER) + func = vpu->encoder; + else + func = vpu->decoder; + + if (!func) + return; + + hantro_detach_func(func); + video_unregister_device(&func->vdev); +} + +static void hantro_remove_enc_func(struct hantro_dev *vpu) +{ + hantro_remove_func(vpu, MEDIA_ENT_F_PROC_VIDEO_ENCODER); +} + +static void hantro_remove_dec_func(struct hantro_dev *vpu) +{ + hantro_remove_func(vpu, MEDIA_ENT_F_PROC_VIDEO_DECODER); +} + +static const struct media_device_ops hantro_m2m_media_ops = { + .req_validate = vb2_request_validate, + .req_queue = v4l2_m2m_request_queue, +}; + +static int hantro_probe(struct platform_device *pdev) +{ + const struct of_device_id *match; + struct hantro_dev *vpu; + struct resource *res; + int i, ret; + + vpu = devm_kzalloc(&pdev->dev, sizeof(*vpu), GFP_KERNEL); + if (!vpu) + return -ENOMEM; + + vpu->dev = &pdev->dev; + vpu->pdev = pdev; + mutex_init(&vpu->vpu_mutex); + spin_lock_init(&vpu->irqlock); + + match = of_match_node(of_hantro_match, pdev->dev.of_node); + vpu->variant = match->data; + + INIT_DELAYED_WORK(&vpu->watchdog_work, hantro_watchdog); + + for (i = 0; i < vpu->variant->num_clocks; i++) + vpu->clocks[i].id = vpu->variant->clk_names[i]; + ret = devm_clk_bulk_get(&pdev->dev, vpu->variant->num_clocks, + vpu->clocks); + if (ret) + return ret; + + res = platform_get_resource(vpu->pdev, IORESOURCE_MEM, 0); + vpu->base = devm_ioremap_resource(vpu->dev, res); + if (IS_ERR(vpu->base)) + return PTR_ERR(vpu->base); + vpu->enc_base = vpu->base + vpu->variant->enc_offset; + vpu->dec_base = vpu->base + vpu->variant->dec_offset; + + ret = dma_set_coherent_mask(vpu->dev, DMA_BIT_MASK(32)); + if (ret) { + dev_err(vpu->dev, "Could not set DMA coherent mask.\n"); + return ret; + } + + if (vpu->variant->vdpu_irq) { + int irq; + + irq = platform_get_irq_byname(vpu->pdev, "vdpu"); + if (irq <= 0) { + dev_err(vpu->dev, "Could not get vdpu IRQ.\n"); + return -ENXIO; + } + + ret = devm_request_irq(vpu->dev, irq, vpu->variant->vdpu_irq, + 0, dev_name(vpu->dev), vpu); + if (ret) { + dev_err(vpu->dev, "Could not request vdpu IRQ.\n"); + return ret; + } + } + + if (vpu->variant->vepu_irq) { + int irq; + + irq = platform_get_irq_byname(vpu->pdev, "vepu"); + if (irq <= 0) { + dev_err(vpu->dev, "Could not get vepu IRQ.\n"); + return -ENXIO; + } + + ret = devm_request_irq(vpu->dev, irq, vpu->variant->vepu_irq, + 0, dev_name(vpu->dev), vpu); + if (ret) { + dev_err(vpu->dev, "Could not request vepu IRQ.\n"); + return ret; + } + } + + ret = vpu->variant->init(vpu); + if (ret) { + dev_err(&pdev->dev, "Failed to init VPU hardware\n"); + return ret; + } + + pm_runtime_set_autosuspend_delay(vpu->dev, 100); + pm_runtime_use_autosuspend(vpu->dev); + pm_runtime_enable(vpu->dev); + + ret = clk_bulk_prepare(vpu->variant->num_clocks, vpu->clocks); + if (ret) { + dev_err(&pdev->dev, "Failed to prepare clocks\n"); + return ret; + } + + ret = v4l2_device_register(&pdev->dev, &vpu->v4l2_dev); + if (ret) { + dev_err(&pdev->dev, "Failed to register v4l2 device\n"); + goto err_clk_unprepare; + } + platform_set_drvdata(pdev, vpu); + + vpu->m2m_dev = v4l2_m2m_init(&vpu_m2m_ops); + if (IS_ERR(vpu->m2m_dev)) { + v4l2_err(&vpu->v4l2_dev, "Failed to init mem2mem device\n"); + ret = PTR_ERR(vpu->m2m_dev); + goto err_v4l2_unreg; + } + + vpu->mdev.dev = vpu->dev; + strscpy(vpu->mdev.model, DRIVER_NAME, sizeof(vpu->mdev.model)); + strscpy(vpu->mdev.bus_info, "platform: " DRIVER_NAME, + sizeof(vpu->mdev.model)); + media_device_init(&vpu->mdev); + vpu->mdev.ops = &hantro_m2m_media_ops; + vpu->v4l2_dev.mdev = &vpu->mdev; + + ret = hantro_add_enc_func(vpu); + if (ret) { + dev_err(&pdev->dev, "Failed to register encoder\n"); + goto err_m2m_rel; + } + + ret = hantro_add_dec_func(vpu); + if (ret) { + dev_err(&pdev->dev, "Failed to register decoder\n"); + goto err_rm_enc_func; + } + + ret = media_device_register(&vpu->mdev); + if (ret) { + v4l2_err(&vpu->v4l2_dev, "Failed to register mem2mem media device\n"); + goto err_rm_dec_func; + } + + return 0; + +err_rm_dec_func: + hantro_remove_dec_func(vpu); +err_rm_enc_func: + hantro_remove_enc_func(vpu); +err_m2m_rel: + media_device_cleanup(&vpu->mdev); + v4l2_m2m_release(vpu->m2m_dev); +err_v4l2_unreg: + v4l2_device_unregister(&vpu->v4l2_dev); +err_clk_unprepare: + clk_bulk_unprepare(vpu->variant->num_clocks, vpu->clocks); + pm_runtime_dont_use_autosuspend(vpu->dev); + pm_runtime_disable(vpu->dev); + return ret; +} + +static int hantro_remove(struct platform_device *pdev) +{ + struct hantro_dev *vpu = platform_get_drvdata(pdev); + + v4l2_info(&vpu->v4l2_dev, "Removing %s\n", pdev->name); + + media_device_unregister(&vpu->mdev); + hantro_remove_dec_func(vpu); + hantro_remove_enc_func(vpu); + media_device_cleanup(&vpu->mdev); + v4l2_m2m_release(vpu->m2m_dev); + v4l2_device_unregister(&vpu->v4l2_dev); + clk_bulk_unprepare(vpu->variant->num_clocks, vpu->clocks); + pm_runtime_dont_use_autosuspend(vpu->dev); + pm_runtime_disable(vpu->dev); + return 0; +} + +static const struct dev_pm_ops hantro_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) +}; + +static struct platform_driver hantro_driver = { + .probe = hantro_probe, + .remove = hantro_remove, + .driver = { + .name = DRIVER_NAME, + .of_match_table = of_match_ptr(of_hantro_match), + .pm = &hantro_pm_ops, + }, +}; +module_platform_driver(hantro_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Alpha Lin "); +MODULE_AUTHOR("Tomasz Figa "); +MODULE_AUTHOR("Ezequiel Garcia "); +MODULE_DESCRIPTION("Hantro VPU codec driver"); diff --git a/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c b/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c new file mode 100644 index 000000000000..e592c1b66375 --- /dev/null +++ b/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c @@ -0,0 +1,260 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Hantro VPU codec driver + * + * Copyright (C) 2018 Rockchip Electronics Co., Ltd. + */ + +#include +#include +#include +#include "hantro.h" +#include "hantro_hw.h" + +#define G1_SWREG(nr) ((nr) * 4) + +#define G1_REG_RLC_VLC_BASE G1_SWREG(12) +#define G1_REG_DEC_OUT_BASE G1_SWREG(13) +#define G1_REG_REFER0_BASE G1_SWREG(14) +#define G1_REG_REFER1_BASE G1_SWREG(15) +#define G1_REG_REFER2_BASE G1_SWREG(16) +#define G1_REG_REFER3_BASE G1_SWREG(17) +#define G1_REG_QTABLE_BASE G1_SWREG(40) +#define G1_REG_DEC_E(v) ((v) ? BIT(0) : 0) + +#define G1_REG_DEC_AXI_RD_ID(v) (((v) << 24) & GENMASK(31, 24)) +#define G1_REG_DEC_TIMEOUT_E(v) ((v) ? BIT(23) : 0) +#define G1_REG_DEC_STRSWAP32_E(v) ((v) ? BIT(22) : 0) +#define G1_REG_DEC_STRENDIAN_E(v) ((v) ? BIT(21) : 0) +#define G1_REG_DEC_INSWAP32_E(v) ((v) ? BIT(20) : 0) +#define G1_REG_DEC_OUTSWAP32_E(v) ((v) ? BIT(19) : 0) +#define G1_REG_DEC_DATA_DISC_E(v) ((v) ? BIT(18) : 0) +#define G1_REG_DEC_LATENCY(v) (((v) << 11) & GENMASK(16, 11)) +#define G1_REG_DEC_CLK_GATE_E(v) ((v) ? BIT(10) : 0) +#define G1_REG_DEC_IN_ENDIAN(v) ((v) ? BIT(9) : 0) +#define G1_REG_DEC_OUT_ENDIAN(v) ((v) ? BIT(8) : 0) +#define G1_REG_DEC_ADV_PRE_DIS(v) ((v) ? BIT(6) : 0) +#define G1_REG_DEC_SCMD_DIS(v) ((v) ? BIT(5) : 0) +#define G1_REG_DEC_MAX_BURST(v) (((v) << 0) & GENMASK(4, 0)) + +#define G1_REG_DEC_MODE(v) (((v) << 28) & GENMASK(31, 28)) +#define G1_REG_RLC_MODE_E(v) ((v) ? BIT(27) : 0) +#define G1_REG_PIC_INTERLACE_E(v) ((v) ? BIT(23) : 0) +#define G1_REG_PIC_FIELDMODE_E(v) ((v) ? BIT(22) : 0) +#define G1_REG_PIC_B_E(v) ((v) ? BIT(21) : 0) +#define G1_REG_PIC_INTER_E(v) ((v) ? BIT(20) : 0) +#define G1_REG_PIC_TOPFIELD_E(v) ((v) ? BIT(19) : 0) +#define G1_REG_FWD_INTERLACE_E(v) ((v) ? BIT(18) : 0) +#define G1_REG_FILTERING_DIS(v) ((v) ? BIT(14) : 0) +#define G1_REG_WRITE_MVS_E(v) ((v) ? BIT(12) : 0) +#define G1_REG_DEC_AXI_WR_ID(v) (((v) << 0) & GENMASK(7, 0)) + +#define G1_REG_PIC_MB_WIDTH(v) (((v) << 23) & GENMASK(31, 23)) +#define G1_REG_PIC_MB_HEIGHT_P(v) (((v) << 11) & GENMASK(18, 11)) +#define G1_REG_ALT_SCAN_E(v) ((v) ? BIT(6) : 0) +#define G1_REG_TOPFIELDFIRST_E(v) ((v) ? BIT(5) : 0) + +#define G1_REG_STRM_START_BIT(v) (((v) << 26) & GENMASK(31, 26)) +#define G1_REG_QSCALE_TYPE(v) ((v) ? BIT(24) : 0) +#define G1_REG_CON_MV_E(v) ((v) ? BIT(4) : 0) +#define G1_REG_INTRA_DC_PREC(v) (((v) << 2) & GENMASK(3, 2)) +#define G1_REG_INTRA_VLC_TAB(v) ((v) ? BIT(1) : 0) +#define G1_REG_FRAME_PRED_DCT(v) ((v) ? BIT(0) : 0) + +#define G1_REG_INIT_QP(v) (((v) << 25) & GENMASK(30, 25)) +#define G1_REG_STREAM_LEN(v) (((v) << 0) & GENMASK(23, 0)) + +#define G1_REG_ALT_SCAN_FLAG_E(v) ((v) ? BIT(19) : 0) +#define G1_REG_FCODE_FWD_HOR(v) (((v) << 15) & GENMASK(18, 15)) +#define G1_REG_FCODE_FWD_VER(v) (((v) << 11) & GENMASK(14, 11)) +#define G1_REG_FCODE_BWD_HOR(v) (((v) << 7) & GENMASK(10, 7)) +#define G1_REG_FCODE_BWD_VER(v) (((v) << 3) & GENMASK(6, 3)) +#define G1_REG_MV_ACCURACY_FWD(v) ((v) ? BIT(2) : 0) +#define G1_REG_MV_ACCURACY_BWD(v) ((v) ? BIT(1) : 0) + +#define G1_REG_STARTMB_X(v) (((v) << 23) & GENMASK(31, 23)) +#define G1_REG_STARTMB_Y(v) (((v) << 15) & GENMASK(22, 15)) + +#define G1_REG_APF_THRESHOLD(v) (((v) << 0) & GENMASK(13, 0)) + +#define PICT_TOP_FIELD 1 +#define PICT_BOTTOM_FIELD 2 +#define PICT_FRAME 3 + +static void +hantro_g1_mpeg2_dec_set_quantization(struct hantro_dev *vpu, + struct hantro_ctx *ctx) +{ + struct v4l2_ctrl_mpeg2_quantization *quantization; + + quantization = hantro_get_ctrl(ctx, + V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION); + hantro_mpeg2_dec_copy_qtable(ctx->mpeg2_dec.qtable.cpu, + quantization); + vdpu_write_relaxed(vpu, ctx->mpeg2_dec.qtable.dma, + G1_REG_QTABLE_BASE); +} + +static void +hantro_g1_mpeg2_dec_set_buffers(struct hantro_dev *vpu, struct hantro_ctx *ctx, + struct vb2_buffer *src_buf, + struct vb2_buffer *dst_buf, + const struct v4l2_mpeg2_sequence *sequence, + const struct v4l2_mpeg2_picture *picture, + const struct v4l2_ctrl_mpeg2_slice_params *slice_params) +{ + dma_addr_t forward_addr = 0, backward_addr = 0; + dma_addr_t current_addr, addr; + struct vb2_queue *vq; + + vq = v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx); + + switch (picture->picture_coding_type) { + case V4L2_MPEG2_PICTURE_CODING_TYPE_B: + backward_addr = hantro_get_ref(vq, + slice_params->backward_ref_ts); + /* fall-through */ + case V4L2_MPEG2_PICTURE_CODING_TYPE_P: + forward_addr = hantro_get_ref(vq, + slice_params->forward_ref_ts); + } + + /* Source bitstream buffer */ + addr = vb2_dma_contig_plane_dma_addr(src_buf, 0); + vdpu_write_relaxed(vpu, addr, G1_REG_RLC_VLC_BASE); + + /* Destination frame buffer */ + addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0); + current_addr = addr; + + if (picture->picture_structure == PICT_BOTTOM_FIELD) + addr += ALIGN(ctx->dst_fmt.width, 16); + vdpu_write_relaxed(vpu, addr, G1_REG_DEC_OUT_BASE); + + if (!forward_addr) + forward_addr = current_addr; + if (!backward_addr) + backward_addr = current_addr; + + /* Set forward ref frame (top/bottom field) */ + if (picture->picture_structure == PICT_FRAME || + picture->picture_coding_type == V4L2_MPEG2_PICTURE_CODING_TYPE_B || + (picture->picture_structure == PICT_TOP_FIELD && + picture->top_field_first) || + (picture->picture_structure == PICT_BOTTOM_FIELD && + !picture->top_field_first)) { + vdpu_write_relaxed(vpu, forward_addr, G1_REG_REFER0_BASE); + vdpu_write_relaxed(vpu, forward_addr, G1_REG_REFER1_BASE); + } else if (picture->picture_structure == PICT_TOP_FIELD) { + vdpu_write_relaxed(vpu, forward_addr, G1_REG_REFER0_BASE); + vdpu_write_relaxed(vpu, current_addr, G1_REG_REFER1_BASE); + } else if (picture->picture_structure == PICT_BOTTOM_FIELD) { + vdpu_write_relaxed(vpu, current_addr, G1_REG_REFER0_BASE); + vdpu_write_relaxed(vpu, forward_addr, G1_REG_REFER1_BASE); + } + + /* Set backward ref frame (top/bottom field) */ + vdpu_write_relaxed(vpu, backward_addr, G1_REG_REFER2_BASE); + vdpu_write_relaxed(vpu, backward_addr, G1_REG_REFER3_BASE); +} + +void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx) +{ + struct hantro_dev *vpu = ctx->dev; + struct vb2_v4l2_buffer *src_buf, *dst_buf; + const struct v4l2_ctrl_mpeg2_slice_params *slice_params; + const struct v4l2_mpeg2_sequence *sequence; + 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); + + /* Apply request controls if any */ + v4l2_ctrl_request_setup(src_buf->vb2_buf.req_obj.req, + &ctx->ctrl_handler); + + slice_params = hantro_get_ctrl(ctx, + V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS); + sequence = &slice_params->sequence; + picture = &slice_params->picture; + + reg = G1_REG_DEC_AXI_RD_ID(0) | + G1_REG_DEC_TIMEOUT_E(1) | + G1_REG_DEC_STRSWAP32_E(1) | + G1_REG_DEC_STRENDIAN_E(1) | + G1_REG_DEC_INSWAP32_E(1) | + G1_REG_DEC_OUTSWAP32_E(1) | + G1_REG_DEC_DATA_DISC_E(0) | + G1_REG_DEC_LATENCY(0) | + G1_REG_DEC_CLK_GATE_E(1) | + G1_REG_DEC_IN_ENDIAN(1) | + G1_REG_DEC_OUT_ENDIAN(1) | + G1_REG_DEC_ADV_PRE_DIS(0) | + G1_REG_DEC_SCMD_DIS(0) | + G1_REG_DEC_MAX_BURST(16); + vdpu_write_relaxed(vpu, reg, G1_SWREG(2)); + + reg = G1_REG_DEC_MODE(5) | + G1_REG_RLC_MODE_E(0) | + G1_REG_PIC_INTERLACE_E(!sequence->progressive_sequence) | + G1_REG_PIC_FIELDMODE_E(picture->picture_structure != PICT_FRAME) | + G1_REG_PIC_B_E(picture->picture_coding_type == V4L2_MPEG2_PICTURE_CODING_TYPE_B) | + G1_REG_PIC_INTER_E(picture->picture_coding_type != V4L2_MPEG2_PICTURE_CODING_TYPE_I) | + G1_REG_PIC_TOPFIELD_E(picture->picture_structure == PICT_TOP_FIELD) | + G1_REG_FWD_INTERLACE_E(0) | + G1_REG_FILTERING_DIS(1) | + G1_REG_WRITE_MVS_E(0) | + G1_REG_DEC_AXI_WR_ID(0); + vdpu_write_relaxed(vpu, reg, G1_SWREG(3)); + + reg = G1_REG_PIC_MB_WIDTH(MPEG2_MB_WIDTH(ctx->dst_fmt.width)) | + G1_REG_PIC_MB_HEIGHT_P(MPEG2_MB_HEIGHT(ctx->dst_fmt.height)) | + G1_REG_ALT_SCAN_E(picture->alternate_scan) | + G1_REG_TOPFIELDFIRST_E(picture->top_field_first); + vdpu_write_relaxed(vpu, reg, G1_SWREG(4)); + + reg = G1_REG_STRM_START_BIT(slice_params->data_bit_offset) | + G1_REG_QSCALE_TYPE(picture->q_scale_type) | + G1_REG_CON_MV_E(picture->concealment_motion_vectors) | + G1_REG_INTRA_DC_PREC(picture->intra_dc_precision) | + G1_REG_INTRA_VLC_TAB(picture->intra_vlc_format) | + G1_REG_FRAME_PRED_DCT(picture->frame_pred_frame_dct); + vdpu_write_relaxed(vpu, reg, G1_SWREG(5)); + + reg = G1_REG_INIT_QP(1) | + G1_REG_STREAM_LEN(slice_params->bit_size >> 3); + vdpu_write_relaxed(vpu, reg, G1_SWREG(6)); + + reg = G1_REG_ALT_SCAN_FLAG_E(picture->alternate_scan) | + G1_REG_FCODE_FWD_HOR(picture->f_code[0][0]) | + G1_REG_FCODE_FWD_VER(picture->f_code[0][1]) | + G1_REG_FCODE_BWD_HOR(picture->f_code[1][0]) | + G1_REG_FCODE_BWD_VER(picture->f_code[1][1]) | + G1_REG_MV_ACCURACY_FWD(1) | + G1_REG_MV_ACCURACY_BWD(1); + vdpu_write_relaxed(vpu, reg, G1_SWREG(18)); + + reg = G1_REG_STARTMB_X(0) | + G1_REG_STARTMB_Y(0); + vdpu_write_relaxed(vpu, reg, G1_SWREG(48)); + + reg = G1_REG_APF_THRESHOLD(8); + vdpu_write_relaxed(vpu, reg, G1_SWREG(55)); + + hantro_g1_mpeg2_dec_set_quantization(vpu, ctx); + + hantro_g1_mpeg2_dec_set_buffers(vpu, ctx, &src_buf->vb2_buf, + &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)); + + reg = G1_REG_DEC_E(1); + vdpu_write(vpu, reg, G1_SWREG(1)); +} diff --git a/drivers/staging/media/hantro/hantro_g1_regs.h b/drivers/staging/media/hantro/hantro_g1_regs.h new file mode 100644 index 000000000000..5c0ea7994336 --- /dev/null +++ b/drivers/staging/media/hantro/hantro_g1_regs.h @@ -0,0 +1,301 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Hantro VPU codec driver + * + * Copyright 2018 Google LLC. + * Tomasz Figa + */ + +#ifndef HANTRO_G1_REGS_H_ +#define HANTRO_G1_REGS_H_ + +/* Decoder registers. */ +#define G1_REG_INTERRUPT 0x004 +#define G1_REG_INTERRUPT_DEC_PIC_INF BIT(24) +#define G1_REG_INTERRUPT_DEC_TIMEOUT BIT(18) +#define G1_REG_INTERRUPT_DEC_SLICE_INT BIT(17) +#define G1_REG_INTERRUPT_DEC_ERROR_INT BIT(16) +#define G1_REG_INTERRUPT_DEC_ASO_INT BIT(15) +#define G1_REG_INTERRUPT_DEC_BUFFER_INT BIT(14) +#define G1_REG_INTERRUPT_DEC_BUS_INT BIT(13) +#define G1_REG_INTERRUPT_DEC_RDY_INT BIT(12) +#define G1_REG_INTERRUPT_DEC_IRQ BIT(8) +#define G1_REG_INTERRUPT_DEC_IRQ_DIS BIT(4) +#define G1_REG_INTERRUPT_DEC_E BIT(0) +#define G1_REG_CONFIG 0x008 +#define G1_REG_CONFIG_DEC_AXI_RD_ID(x) (((x) & 0xff) << 24) +#define G1_REG_CONFIG_DEC_TIMEOUT_E BIT(23) +#define G1_REG_CONFIG_DEC_STRSWAP32_E BIT(22) +#define G1_REG_CONFIG_DEC_STRENDIAN_E BIT(21) +#define G1_REG_CONFIG_DEC_INSWAP32_E BIT(20) +#define G1_REG_CONFIG_DEC_OUTSWAP32_E BIT(19) +#define G1_REG_CONFIG_DEC_DATA_DISC_E BIT(18) +#define G1_REG_CONFIG_TILED_MODE_MSB BIT(17) +#define G1_REG_CONFIG_DEC_OUT_TILED_E BIT(17) +#define G1_REG_CONFIG_DEC_LATENCY(x) (((x) & 0x3f) << 11) +#define G1_REG_CONFIG_DEC_CLK_GATE_E BIT(10) +#define G1_REG_CONFIG_DEC_IN_ENDIAN BIT(9) +#define G1_REG_CONFIG_DEC_OUT_ENDIAN BIT(8) +#define G1_REG_CONFIG_PRIORITY_MODE(x) (((x) & 0x7) << 5) +#define G1_REG_CONFIG_TILED_MODE_LSB BIT(7) +#define G1_REG_CONFIG_DEC_ADV_PRE_DIS BIT(6) +#define G1_REG_CONFIG_DEC_SCMD_DIS BIT(5) +#define G1_REG_CONFIG_DEC_MAX_BURST(x) (((x) & 0x1f) << 0) +#define G1_REG_DEC_CTRL0 0x00c +#define G1_REG_DEC_CTRL0_DEC_MODE(x) (((x) & 0xf) << 28) +#define G1_REG_DEC_CTRL0_RLC_MODE_E BIT(27) +#define G1_REG_DEC_CTRL0_SKIP_MODE BIT(26) +#define G1_REG_DEC_CTRL0_DIVX3_E BIT(25) +#define G1_REG_DEC_CTRL0_PJPEG_E BIT(24) +#define G1_REG_DEC_CTRL0_PIC_INTERLACE_E BIT(23) +#define G1_REG_DEC_CTRL0_PIC_FIELDMODE_E BIT(22) +#define G1_REG_DEC_CTRL0_PIC_B_E BIT(21) +#define G1_REG_DEC_CTRL0_PIC_INTER_E BIT(20) +#define G1_REG_DEC_CTRL0_PIC_TOPFIELD_E BIT(19) +#define G1_REG_DEC_CTRL0_FWD_INTERLACE_E BIT(18) +#define G1_REG_DEC_CTRL0_SORENSON_E BIT(17) +#define G1_REG_DEC_CTRL0_REF_TOPFIELD_E BIT(16) +#define G1_REG_DEC_CTRL0_DEC_OUT_DIS BIT(15) +#define G1_REG_DEC_CTRL0_FILTERING_DIS BIT(14) +#define G1_REG_DEC_CTRL0_WEBP_E BIT(13) +#define G1_REG_DEC_CTRL0_MVC_E BIT(13) +#define G1_REG_DEC_CTRL0_PIC_FIXED_QUANT BIT(13) +#define G1_REG_DEC_CTRL0_WRITE_MVS_E BIT(12) +#define G1_REG_DEC_CTRL0_REFTOPFIRST_E BIT(11) +#define G1_REG_DEC_CTRL0_SEQ_MBAFF_E BIT(10) +#define G1_REG_DEC_CTRL0_PICORD_COUNT_E BIT(9) +#define G1_REG_DEC_CTRL0_DEC_AHB_HLOCK_E BIT(8) +#define G1_REG_DEC_CTRL0_DEC_AXI_WR_ID(x) (((x) & 0xff) << 0) +#define G1_REG_DEC_CTRL1 0x010 +#define G1_REG_DEC_CTRL1_PIC_MB_WIDTH(x) (((x) & 0x1ff) << 23) +#define G1_REG_DEC_CTRL1_MB_WIDTH_OFF(x) (((x) & 0xf) << 19) +#define G1_REG_DEC_CTRL1_PIC_MB_HEIGHT_P(x) (((x) & 0xff) << 11) +#define G1_REG_DEC_CTRL1_MB_HEIGHT_OFF(x) (((x) & 0xf) << 7) +#define G1_REG_DEC_CTRL1_ALT_SCAN_E BIT(6) +#define G1_REG_DEC_CTRL1_TOPFIELDFIRST_E BIT(5) +#define G1_REG_DEC_CTRL1_REF_FRAMES(x) (((x) & 0x1f) << 0) +#define G1_REG_DEC_CTRL1_PIC_MB_W_EXT(x) (((x) & 0x7) << 3) +#define G1_REG_DEC_CTRL1_PIC_MB_H_EXT(x) (((x) & 0x7) << 0) +#define G1_REG_DEC_CTRL1_PIC_REFER_FLAG BIT(0) +#define G1_REG_DEC_CTRL2 0x014 +#define G1_REG_DEC_CTRL2_STRM_START_BIT(x) (((x) & 0x3f) << 26) +#define G1_REG_DEC_CTRL2_SYNC_MARKER_E BIT(25) +#define G1_REG_DEC_CTRL2_TYPE1_QUANT_E BIT(24) +#define G1_REG_DEC_CTRL2_CH_QP_OFFSET(x) (((x) & 0x1f) << 19) +#define G1_REG_DEC_CTRL2_CH_QP_OFFSET2(x) (((x) & 0x1f) << 14) +#define G1_REG_DEC_CTRL2_FIELDPIC_FLAG_E BIT(0) +#define G1_REG_DEC_CTRL2_INTRADC_VLC_THR(x) (((x) & 0x7) << 16) +#define G1_REG_DEC_CTRL2_VOP_TIME_INCR(x) (((x) & 0xffff) << 0) +#define G1_REG_DEC_CTRL2_DQ_PROFILE BIT(24) +#define G1_REG_DEC_CTRL2_DQBI_LEVEL BIT(23) +#define G1_REG_DEC_CTRL2_RANGE_RED_FRM_E BIT(22) +#define G1_REG_DEC_CTRL2_FAST_UVMC_E BIT(20) +#define G1_REG_DEC_CTRL2_TRANSDCTAB BIT(17) +#define G1_REG_DEC_CTRL2_TRANSACFRM(x) (((x) & 0x3) << 15) +#define G1_REG_DEC_CTRL2_TRANSACFRM2(x) (((x) & 0x3) << 13) +#define G1_REG_DEC_CTRL2_MB_MODE_TAB(x) (((x) & 0x7) << 10) +#define G1_REG_DEC_CTRL2_MVTAB(x) (((x) & 0x7) << 7) +#define G1_REG_DEC_CTRL2_CBPTAB(x) (((x) & 0x7) << 4) +#define G1_REG_DEC_CTRL2_2MV_BLK_PAT_TAB(x) (((x) & 0x3) << 2) +#define G1_REG_DEC_CTRL2_4MV_BLK_PAT_TAB(x) (((x) & 0x3) << 0) +#define G1_REG_DEC_CTRL2_QSCALE_TYPE BIT(24) +#define G1_REG_DEC_CTRL2_CON_MV_E BIT(4) +#define G1_REG_DEC_CTRL2_INTRA_DC_PREC(x) (((x) & 0x3) << 2) +#define G1_REG_DEC_CTRL2_INTRA_VLC_TAB BIT(1) +#define G1_REG_DEC_CTRL2_FRAME_PRED_DCT BIT(0) +#define G1_REG_DEC_CTRL2_JPEG_QTABLES(x) (((x) & 0x3) << 11) +#define G1_REG_DEC_CTRL2_JPEG_MODE(x) (((x) & 0x7) << 8) +#define G1_REG_DEC_CTRL2_JPEG_FILRIGHT_E BIT(7) +#define G1_REG_DEC_CTRL2_JPEG_STREAM_ALL BIT(6) +#define G1_REG_DEC_CTRL2_CR_AC_VLCTABLE BIT(5) +#define G1_REG_DEC_CTRL2_CB_AC_VLCTABLE BIT(4) +#define G1_REG_DEC_CTRL2_CR_DC_VLCTABLE BIT(3) +#define G1_REG_DEC_CTRL2_CB_DC_VLCTABLE BIT(2) +#define G1_REG_DEC_CTRL2_CR_DC_VLCTABLE3 BIT(1) +#define G1_REG_DEC_CTRL2_CB_DC_VLCTABLE3 BIT(0) +#define G1_REG_DEC_CTRL2_STRM1_START_BIT(x) (((x) & 0x3f) << 18) +#define G1_REG_DEC_CTRL2_HUFFMAN_E BIT(17) +#define G1_REG_DEC_CTRL2_MULTISTREAM_E BIT(16) +#define G1_REG_DEC_CTRL2_BOOLEAN_VALUE(x) (((x) & 0xff) << 8) +#define G1_REG_DEC_CTRL2_BOOLEAN_RANGE(x) (((x) & 0xff) << 0) +#define G1_REG_DEC_CTRL2_ALPHA_OFFSET(x) (((x) & 0x1f) << 5) +#define G1_REG_DEC_CTRL2_BETA_OFFSET(x) (((x) & 0x1f) << 0) +#define G1_REG_DEC_CTRL3 0x018 +#define G1_REG_DEC_CTRL3_START_CODE_E BIT(31) +#define G1_REG_DEC_CTRL3_INIT_QP(x) (((x) & 0x3f) << 25) +#define G1_REG_DEC_CTRL3_CH_8PIX_ILEAV_E BIT(24) +#define G1_REG_DEC_CTRL3_STREAM_LEN_EXT(x) (((x) & 0xff) << 24) +#define G1_REG_DEC_CTRL3_STREAM_LEN(x) (((x) & 0xffffff) << 0) +#define G1_REG_DEC_CTRL4 0x01c +#define G1_REG_DEC_CTRL4_CABAC_E BIT(31) +#define G1_REG_DEC_CTRL4_BLACKWHITE_E BIT(30) +#define G1_REG_DEC_CTRL4_DIR_8X8_INFER_E BIT(29) +#define G1_REG_DEC_CTRL4_WEIGHT_PRED_E BIT(28) +#define G1_REG_DEC_CTRL4_WEIGHT_BIPR_IDC(x) (((x) & 0x3) << 26) +#define G1_REG_DEC_CTRL4_AVS_H264_H_EXT BIT(25) +#define G1_REG_DEC_CTRL4_FRAMENUM_LEN(x) (((x) & 0x1f) << 16) +#define G1_REG_DEC_CTRL4_FRAMENUM(x) (((x) & 0xffff) << 0) +#define G1_REG_DEC_CTRL4_BITPLANE0_E BIT(31) +#define G1_REG_DEC_CTRL4_BITPLANE1_E BIT(30) +#define G1_REG_DEC_CTRL4_BITPLANE2_E BIT(29) +#define G1_REG_DEC_CTRL4_ALT_PQUANT(x) (((x) & 0x1f) << 24) +#define G1_REG_DEC_CTRL4_DQ_EDGES(x) (((x) & 0xf) << 20) +#define G1_REG_DEC_CTRL4_TTMBF BIT(19) +#define G1_REG_DEC_CTRL4_PQINDEX(x) (((x) & 0x1f) << 14) +#define G1_REG_DEC_CTRL4_VC1_HEIGHT_EXT BIT(13) +#define G1_REG_DEC_CTRL4_BILIN_MC_E BIT(12) +#define G1_REG_DEC_CTRL4_UNIQP_E BIT(11) +#define G1_REG_DEC_CTRL4_HALFQP_E BIT(10) +#define G1_REG_DEC_CTRL4_TTFRM(x) (((x) & 0x3) << 8) +#define G1_REG_DEC_CTRL4_2ND_BYTE_EMUL_E BIT(7) +#define G1_REG_DEC_CTRL4_DQUANT_E BIT(6) +#define G1_REG_DEC_CTRL4_VC1_ADV_E BIT(5) +#define G1_REG_DEC_CTRL4_PJPEG_FILDOWN_E BIT(26) +#define G1_REG_DEC_CTRL4_PJPEG_WDIV8 BIT(25) +#define G1_REG_DEC_CTRL4_PJPEG_HDIV8 BIT(24) +#define G1_REG_DEC_CTRL4_PJPEG_AH(x) (((x) & 0xf) << 20) +#define G1_REG_DEC_CTRL4_PJPEG_AL(x) (((x) & 0xf) << 16) +#define G1_REG_DEC_CTRL4_PJPEG_SS(x) (((x) & 0xff) << 8) +#define G1_REG_DEC_CTRL4_PJPEG_SE(x) (((x) & 0xff) << 0) +#define G1_REG_DEC_CTRL4_DCT1_START_BIT(x) (((x) & 0x3f) << 26) +#define G1_REG_DEC_CTRL4_DCT2_START_BIT(x) (((x) & 0x3f) << 20) +#define G1_REG_DEC_CTRL4_CH_MV_RES BIT(13) +#define G1_REG_DEC_CTRL4_INIT_DC_MATCH0(x) (((x) & 0x7) << 9) +#define G1_REG_DEC_CTRL4_INIT_DC_MATCH1(x) (((x) & 0x7) << 6) +#define G1_REG_DEC_CTRL4_VP7_VERSION BIT(5) +#define G1_REG_DEC_CTRL5 0x020 +#define G1_REG_DEC_CTRL5_CONST_INTRA_E BIT(31) +#define G1_REG_DEC_CTRL5_FILT_CTRL_PRES BIT(30) +#define G1_REG_DEC_CTRL5_RDPIC_CNT_PRES BIT(29) +#define G1_REG_DEC_CTRL5_8X8TRANS_FLAG_E BIT(28) +#define G1_REG_DEC_CTRL5_REFPIC_MK_LEN(x) (((x) & 0x7ff) << 17) +#define G1_REG_DEC_CTRL5_IDR_PIC_E BIT(16) +#define G1_REG_DEC_CTRL5_IDR_PIC_ID(x) (((x) & 0xffff) << 0) +#define G1_REG_DEC_CTRL5_MV_SCALEFACTOR(x) (((x) & 0xff) << 24) +#define G1_REG_DEC_CTRL5_REF_DIST_FWD(x) (((x) & 0x1f) << 19) +#define G1_REG_DEC_CTRL5_REF_DIST_BWD(x) (((x) & 0x1f) << 14) +#define G1_REG_DEC_CTRL5_LOOP_FILT_LIMIT(x) (((x) & 0xf) << 14) +#define G1_REG_DEC_CTRL5_VARIANCE_TEST_E BIT(13) +#define G1_REG_DEC_CTRL5_MV_THRESHOLD(x) (((x) & 0x7) << 10) +#define G1_REG_DEC_CTRL5_VAR_THRESHOLD(x) (((x) & 0x3ff) << 0) +#define G1_REG_DEC_CTRL5_DIVX_IDCT_E BIT(8) +#define G1_REG_DEC_CTRL5_DIVX3_SLICE_SIZE(x) (((x) & 0xff) << 0) +#define G1_REG_DEC_CTRL5_PJPEG_REST_FREQ(x) (((x) & 0xffff) << 0) +#define G1_REG_DEC_CTRL5_RV_PROFILE(x) (((x) & 0x3) << 30) +#define G1_REG_DEC_CTRL5_RV_OSV_QUANT(x) (((x) & 0x3) << 28) +#define G1_REG_DEC_CTRL5_RV_FWD_SCALE(x) (((x) & 0x3fff) << 14) +#define G1_REG_DEC_CTRL5_RV_BWD_SCALE(x) (((x) & 0x3fff) << 0) +#define G1_REG_DEC_CTRL5_INIT_DC_COMP0(x) (((x) & 0xffff) << 16) +#define G1_REG_DEC_CTRL5_INIT_DC_COMP1(x) (((x) & 0xffff) << 0) +#define G1_REG_DEC_CTRL6 0x024 +#define G1_REG_DEC_CTRL6_PPS_ID(x) (((x) & 0xff) << 24) +#define G1_REG_DEC_CTRL6_REFIDX1_ACTIVE(x) (((x) & 0x1f) << 19) +#define G1_REG_DEC_CTRL6_REFIDX0_ACTIVE(x) (((x) & 0x1f) << 14) +#define G1_REG_DEC_CTRL6_POC_LENGTH(x) (((x) & 0xff) << 0) +#define G1_REG_DEC_CTRL6_ICOMP0_E BIT(24) +#define G1_REG_DEC_CTRL6_ISCALE0(x) (((x) & 0xff) << 16) +#define G1_REG_DEC_CTRL6_ISHIFT0(x) (((x) & 0xffff) << 0) +#define G1_REG_DEC_CTRL6_STREAM1_LEN(x) (((x) & 0xffffff) << 0) +#define G1_REG_DEC_CTRL6_PIC_SLICE_AM(x) (((x) & 0x1fff) << 0) +#define G1_REG_DEC_CTRL6_COEFFS_PART_AM(x) (((x) & 0xf) << 24) +#define G1_REG_FWD_PIC(i) (0x028 + ((i) * 0x4)) +#define G1_REG_FWD_PIC_PINIT_RLIST_F5(x) (((x) & 0x1f) << 25) +#define G1_REG_FWD_PIC_PINIT_RLIST_F4(x) (((x) & 0x1f) << 20) +#define G1_REG_FWD_PIC_PINIT_RLIST_F3(x) (((x) & 0x1f) << 15) +#define G1_REG_FWD_PIC_PINIT_RLIST_F2(x) (((x) & 0x1f) << 10) +#define G1_REG_FWD_PIC_PINIT_RLIST_F1(x) (((x) & 0x1f) << 5) +#define G1_REG_FWD_PIC_PINIT_RLIST_F0(x) (((x) & 0x1f) << 0) +#define G1_REG_FWD_PIC1_ICOMP1_E BIT(24) +#define G1_REG_FWD_PIC1_ISCALE1(x) (((x) & 0xff) << 16) +#define G1_REG_FWD_PIC1_ISHIFT1(x) (((x) & 0xffff) << 0) +#define G1_REG_FWD_PIC1_SEGMENT_BASE(x) ((x) << 0) +#define G1_REG_FWD_PIC1_SEGMENT_UPD_E BIT(1) +#define G1_REG_FWD_PIC1_SEGMENT_E BIT(0) +#define G1_REG_DEC_CTRL7 0x02c +#define G1_REG_DEC_CTRL7_PINIT_RLIST_F15(x) (((x) & 0x1f) << 25) +#define G1_REG_DEC_CTRL7_PINIT_RLIST_F14(x) (((x) & 0x1f) << 20) +#define G1_REG_DEC_CTRL7_PINIT_RLIST_F13(x) (((x) & 0x1f) << 15) +#define G1_REG_DEC_CTRL7_PINIT_RLIST_F12(x) (((x) & 0x1f) << 10) +#define G1_REG_DEC_CTRL7_PINIT_RLIST_F11(x) (((x) & 0x1f) << 5) +#define G1_REG_DEC_CTRL7_PINIT_RLIST_F10(x) (((x) & 0x1f) << 0) +#define G1_REG_DEC_CTRL7_ICOMP2_E BIT(24) +#define G1_REG_DEC_CTRL7_ISCALE2(x) (((x) & 0xff) << 16) +#define G1_REG_DEC_CTRL7_ISHIFT2(x) (((x) & 0xffff) << 0) +#define G1_REG_DEC_CTRL7_DCT3_START_BIT(x) (((x) & 0x3f) << 24) +#define G1_REG_DEC_CTRL7_DCT4_START_BIT(x) (((x) & 0x3f) << 18) +#define G1_REG_DEC_CTRL7_DCT5_START_BIT(x) (((x) & 0x3f) << 12) +#define G1_REG_DEC_CTRL7_DCT6_START_BIT(x) (((x) & 0x3f) << 6) +#define G1_REG_DEC_CTRL7_DCT7_START_BIT(x) (((x) & 0x3f) << 0) +#define G1_REG_ADDR_STR 0x030 +#define G1_REG_ADDR_DST 0x034 +#define G1_REG_ADDR_REF(i) (0x038 + ((i) * 0x4)) +#define G1_REG_ADDR_REF_FIELD_E BIT(1) +#define G1_REG_ADDR_REF_TOPC_E BIT(0) +#define G1_REG_REF_PIC(i) (0x078 + ((i) * 0x4)) +#define G1_REG_REF_PIC_FILT_TYPE_E BIT(31) +#define G1_REG_REF_PIC_FILT_SHARPNESS(x) (((x) & 0x7) << 28) +#define G1_REG_REF_PIC_MB_ADJ_0(x) (((x) & 0x7f) << 21) +#define G1_REG_REF_PIC_MB_ADJ_1(x) (((x) & 0x7f) << 14) +#define G1_REG_REF_PIC_MB_ADJ_2(x) (((x) & 0x7f) << 7) +#define G1_REG_REF_PIC_MB_ADJ_3(x) (((x) & 0x7f) << 0) +#define G1_REG_REF_PIC_REFER1_NBR(x) (((x) & 0xffff) << 16) +#define G1_REG_REF_PIC_REFER0_NBR(x) (((x) & 0xffff) << 0) +#define G1_REG_REF_PIC_LF_LEVEL_0(x) (((x) & 0x3f) << 18) +#define G1_REG_REF_PIC_LF_LEVEL_1(x) (((x) & 0x3f) << 12) +#define G1_REG_REF_PIC_LF_LEVEL_2(x) (((x) & 0x3f) << 6) +#define G1_REG_REF_PIC_LF_LEVEL_3(x) (((x) & 0x3f) << 0) +#define G1_REG_REF_PIC_QUANT_DELTA_0(x) (((x) & 0x1f) << 27) +#define G1_REG_REF_PIC_QUANT_DELTA_1(x) (((x) & 0x1f) << 22) +#define G1_REG_REF_PIC_QUANT_0(x) (((x) & 0x7ff) << 11) +#define G1_REG_REF_PIC_QUANT_1(x) (((x) & 0x7ff) << 0) +#define G1_REG_LT_REF 0x098 +#define G1_REG_VALID_REF 0x09c +#define G1_REG_ADDR_QTABLE 0x0a0 +#define G1_REG_ADDR_DIR_MV 0x0a4 +#define G1_REG_BD_REF_PIC(i) (0x0a8 + ((i) * 0x4)) +#define G1_REG_BD_REF_PIC_BINIT_RLIST_B2(x) (((x) & 0x1f) << 25) +#define G1_REG_BD_REF_PIC_BINIT_RLIST_F2(x) (((x) & 0x1f) << 20) +#define G1_REG_BD_REF_PIC_BINIT_RLIST_B1(x) (((x) & 0x1f) << 15) +#define G1_REG_BD_REF_PIC_BINIT_RLIST_F1(x) (((x) & 0x1f) << 10) +#define G1_REG_BD_REF_PIC_BINIT_RLIST_B0(x) (((x) & 0x1f) << 5) +#define G1_REG_BD_REF_PIC_BINIT_RLIST_F0(x) (((x) & 0x1f) << 0) +#define G1_REG_BD_REF_PIC_PRED_TAP_2_M1(x) (((x) & 0x3) << 10) +#define G1_REG_BD_REF_PIC_PRED_TAP_2_4(x) (((x) & 0x3) << 8) +#define G1_REG_BD_REF_PIC_PRED_TAP_4_M1(x) (((x) & 0x3) << 6) +#define G1_REG_BD_REF_PIC_PRED_TAP_4_4(x) (((x) & 0x3) << 4) +#define G1_REG_BD_REF_PIC_PRED_TAP_6_M1(x) (((x) & 0x3) << 2) +#define G1_REG_BD_REF_PIC_PRED_TAP_6_4(x) (((x) & 0x3) << 0) +#define G1_REG_BD_REF_PIC_QUANT_DELTA_2(x) (((x) & 0x1f) << 27) +#define G1_REG_BD_REF_PIC_QUANT_DELTA_3(x) (((x) & 0x1f) << 22) +#define G1_REG_BD_REF_PIC_QUANT_2(x) (((x) & 0x7ff) << 11) +#define G1_REG_BD_REF_PIC_QUANT_3(x) (((x) & 0x7ff) << 0) +#define G1_REG_BD_P_REF_PIC 0x0bc +#define G1_REG_BD_P_REF_PIC_QUANT_DELTA_4(x) (((x) & 0x1f) << 27) +#define G1_REG_BD_P_REF_PIC_PINIT_RLIST_F3(x) (((x) & 0x1f) << 25) +#define G1_REG_BD_P_REF_PIC_PINIT_RLIST_F2(x) (((x) & 0x1f) << 20) +#define G1_REG_BD_P_REF_PIC_PINIT_RLIST_F1(x) (((x) & 0x1f) << 15) +#define G1_REG_BD_P_REF_PIC_PINIT_RLIST_F0(x) (((x) & 0x1f) << 10) +#define G1_REG_BD_P_REF_PIC_BINIT_RLIST_B15(x) (((x) & 0x1f) << 5) +#define G1_REG_BD_P_REF_PIC_BINIT_RLIST_F15(x) (((x) & 0x1f) << 0) +#define G1_REG_ERR_CONC 0x0c0 +#define G1_REG_ERR_CONC_STARTMB_X(x) (((x) & 0x1ff) << 23) +#define G1_REG_ERR_CONC_STARTMB_Y(x) (((x) & 0xff) << 15) +#define G1_REG_PRED_FLT 0x0c4 +#define G1_REG_PRED_FLT_PRED_BC_TAP_0_0(x) (((x) & 0x3ff) << 22) +#define G1_REG_PRED_FLT_PRED_BC_TAP_0_1(x) (((x) & 0x3ff) << 12) +#define G1_REG_PRED_FLT_PRED_BC_TAP_0_2(x) (((x) & 0x3ff) << 2) +#define G1_REG_REF_BUF_CTRL 0x0cc +#define G1_REG_REF_BUF_CTRL_REFBU_E BIT(31) +#define G1_REG_REF_BUF_CTRL_REFBU_THR(x) (((x) & 0xfff) << 19) +#define G1_REG_REF_BUF_CTRL_REFBU_PICID(x) (((x) & 0x1f) << 14) +#define G1_REG_REF_BUF_CTRL_REFBU_EVAL_E BIT(13) +#define G1_REG_REF_BUF_CTRL_REFBU_FPARMOD_E BIT(12) +#define G1_REG_REF_BUF_CTRL_REFBU_Y_OFFSET(x) (((x) & 0x1ff) << 0) +#define G1_REG_REF_BUF_CTRL2 0x0dc +#define G1_REG_REF_BUF_CTRL2_REFBU2_BUF_E BIT(31) +#define G1_REG_REF_BUF_CTRL2_REFBU2_THR(x) (((x) & 0xfff) << 19) +#define G1_REG_REF_BUF_CTRL2_REFBU2_PICID(x) (((x) & 0x1f) << 14) +#define G1_REG_REF_BUF_CTRL2_APF_THRESHOLD(x) (((x) & 0x3fff) << 0) +#define G1_REG_SOFT_RESET 0x194 + +#endif /* HANTRO_G1_REGS_H_ */ diff --git a/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c b/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c new file mode 100644 index 000000000000..0c1e3043dc7e --- /dev/null +++ b/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Hantro VPU codec driver + * + * Copyright (C) 2018 Rockchip Electronics Co., Ltd. + */ + +#include +#include +#include "hantro_jpeg.h" +#include "hantro.h" +#include "hantro_v4l2.h" +#include "hantro_hw.h" +#include "hantro_h1_regs.h" + +#define H1_JPEG_QUANT_TABLE_COUNT 16 + +static void hantro_h1_set_src_img_ctrl(struct hantro_dev *vpu, + struct hantro_ctx *ctx) +{ + struct v4l2_pix_format_mplane *pix_fmt = &ctx->src_fmt; + u32 reg; + + reg = H1_REG_IN_IMG_CTRL_ROW_LEN(pix_fmt->width) + | H1_REG_IN_IMG_CTRL_OVRFLR_D4(0) + | H1_REG_IN_IMG_CTRL_OVRFLB_D4(0) + | H1_REG_IN_IMG_CTRL_FMT(ctx->vpu_src_fmt->enc_fmt); + vepu_write_relaxed(vpu, reg, H1_REG_IN_IMG_CTRL); +} + +static void hantro_h1_jpeg_enc_set_buffers(struct hantro_dev *vpu, + struct hantro_ctx *ctx, + struct vb2_buffer *src_buf) +{ + struct v4l2_pix_format_mplane *pix_fmt = &ctx->src_fmt; + dma_addr_t src[3]; + + WARN_ON(pix_fmt->num_planes > 3); + + vepu_write_relaxed(vpu, ctx->jpeg_enc.bounce_buffer.dma, + H1_REG_ADDR_OUTPUT_STREAM); + vepu_write_relaxed(vpu, ctx->jpeg_enc.bounce_buffer.size, + H1_REG_STR_BUF_LIMIT); + + if (pix_fmt->num_planes == 1) { + src[0] = vb2_dma_contig_plane_dma_addr(src_buf, 0); + /* single plane formats we supported are all interlaced */ + vepu_write_relaxed(vpu, src[0], H1_REG_ADDR_IN_PLANE_0); + } else if (pix_fmt->num_planes == 2) { + src[0] = vb2_dma_contig_plane_dma_addr(src_buf, 0); + src[1] = vb2_dma_contig_plane_dma_addr(src_buf, 1); + vepu_write_relaxed(vpu, src[0], H1_REG_ADDR_IN_PLANE_0); + vepu_write_relaxed(vpu, src[1], H1_REG_ADDR_IN_PLANE_1); + } else { + src[0] = vb2_dma_contig_plane_dma_addr(src_buf, 0); + src[1] = vb2_dma_contig_plane_dma_addr(src_buf, 1); + src[2] = vb2_dma_contig_plane_dma_addr(src_buf, 2); + vepu_write_relaxed(vpu, src[0], H1_REG_ADDR_IN_PLANE_0); + vepu_write_relaxed(vpu, src[1], H1_REG_ADDR_IN_PLANE_1); + vepu_write_relaxed(vpu, src[2], H1_REG_ADDR_IN_PLANE_2); + } +} + +static void +hantro_h1_jpeg_enc_set_qtable(struct hantro_dev *vpu, + unsigned char *luma_qtable, + unsigned char *chroma_qtable) +{ + u32 reg, i; + + for (i = 0; i < H1_JPEG_QUANT_TABLE_COUNT; i++) { + reg = get_unaligned_be32(&luma_qtable[i]); + vepu_write_relaxed(vpu, reg, H1_REG_JPEG_LUMA_QUAT(i)); + + reg = get_unaligned_be32(&chroma_qtable[i]); + vepu_write_relaxed(vpu, reg, H1_REG_JPEG_CHROMA_QUAT(i)); + } +} + +void hantro_h1_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; + u32 reg; + + src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_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; + jpeg_ctx.height = ctx->dst_fmt.height; + jpeg_ctx.quality = ctx->jpeg_quality; + hantro_jpeg_header_assemble(&jpeg_ctx); + + /* Switch to JPEG encoder mode before writing registers */ + vepu_write_relaxed(vpu, H1_REG_ENC_CTRL_ENC_MODE_JPEG, + H1_REG_ENC_CTRL); + + hantro_h1_set_src_img_ctrl(vpu, ctx); + hantro_h1_jpeg_enc_set_buffers(vpu, ctx, &src_buf->vb2_buf); + hantro_h1_jpeg_enc_set_qtable(vpu, + hantro_jpeg_get_qtable(&jpeg_ctx, 0), + hantro_jpeg_get_qtable(&jpeg_ctx, 1)); + + reg = H1_REG_AXI_CTRL_OUTPUT_SWAP16 + | H1_REG_AXI_CTRL_INPUT_SWAP16 + | H1_REG_AXI_CTRL_BURST_LEN(16) + | H1_REG_AXI_CTRL_OUTPUT_SWAP32 + | H1_REG_AXI_CTRL_INPUT_SWAP32 + | H1_REG_AXI_CTRL_OUTPUT_SWAP8 + | H1_REG_AXI_CTRL_INPUT_SWAP8; + /* Make sure that all registers are written at this point. */ + vepu_write(vpu, reg, H1_REG_AXI_CTRL); + + reg = H1_REG_ENC_CTRL_WIDTH(JPEG_MB_WIDTH(ctx->src_fmt.width)) + | H1_REG_ENC_CTRL_HEIGHT(JPEG_MB_HEIGHT(ctx->src_fmt.height)) + | 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)); + vepu_write(vpu, reg, H1_REG_ENC_CTRL); +} diff --git a/drivers/staging/media/hantro/hantro_h1_regs.h b/drivers/staging/media/hantro/hantro_h1_regs.h new file mode 100644 index 000000000000..d6e9825bb5c7 --- /dev/null +++ b/drivers/staging/media/hantro/hantro_h1_regs.h @@ -0,0 +1,154 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Hantro VPU codec driver + * + * Copyright 2018 Google LLC. + * Tomasz Figa + */ + +#ifndef HANTRO_H1_REGS_H_ +#define HANTRO_H1_REGS_H_ + +/* Encoder registers. */ +#define H1_REG_INTERRUPT 0x004 +#define H1_REG_INTERRUPT_FRAME_RDY BIT(2) +#define H1_REG_INTERRUPT_DIS_BIT BIT(1) +#define H1_REG_INTERRUPT_BIT BIT(0) +#define H1_REG_AXI_CTRL 0x008 +#define H1_REG_AXI_CTRL_OUTPUT_SWAP16 BIT(15) +#define H1_REG_AXI_CTRL_INPUT_SWAP16 BIT(14) +#define H1_REG_AXI_CTRL_BURST_LEN(x) ((x) << 8) +#define H1_REG_AXI_CTRL_GATE_BIT BIT(4) +#define H1_REG_AXI_CTRL_OUTPUT_SWAP32 BIT(3) +#define H1_REG_AXI_CTRL_INPUT_SWAP32 BIT(2) +#define H1_REG_AXI_CTRL_OUTPUT_SWAP8 BIT(1) +#define H1_REG_AXI_CTRL_INPUT_SWAP8 BIT(0) +#define H1_REG_ADDR_OUTPUT_STREAM 0x014 +#define H1_REG_ADDR_OUTPUT_CTRL 0x018 +#define H1_REG_ADDR_REF_LUMA 0x01c +#define H1_REG_ADDR_REF_CHROMA 0x020 +#define H1_REG_ADDR_REC_LUMA 0x024 +#define H1_REG_ADDR_REC_CHROMA 0x028 +#define H1_REG_ADDR_IN_PLANE_0 0x02c +#define H1_REG_ADDR_IN_PLANE_1 0x030 +#define H1_REG_ADDR_IN_PLANE_2 0x034 +#define H1_REG_ENC_CTRL 0x038 +#define H1_REG_ENC_CTRL_TIMEOUT_EN BIT(31) +#define H1_REG_ENC_CTRL_NAL_MODE_BIT BIT(29) +#define H1_REG_ENC_CTRL_WIDTH(w) ((w) << 19) +#define H1_REG_ENC_CTRL_HEIGHT(h) ((h) << 10) +#define H1_REG_ENC_PIC_INTER (0x0 << 3) +#define H1_REG_ENC_PIC_INTRA (0x1 << 3) +#define H1_REG_ENC_PIC_MVCINTER (0x2 << 3) +#define H1_REG_ENC_CTRL_ENC_MODE_H264 (0x3 << 1) +#define H1_REG_ENC_CTRL_ENC_MODE_JPEG (0x2 << 1) +#define H1_REG_ENC_CTRL_ENC_MODE_VP8 (0x1 << 1) +#define H1_REG_ENC_CTRL_EN_BIT BIT(0) +#define H1_REG_IN_IMG_CTRL 0x03c +#define H1_REG_IN_IMG_CTRL_ROW_LEN(x) ((x) << 12) +#define H1_REG_IN_IMG_CTRL_OVRFLR_D4(x) ((x) << 10) +#define H1_REG_IN_IMG_CTRL_OVRFLB_D4(x) ((x) << 6) +#define H1_REG_IN_IMG_CTRL_FMT(x) ((x) << 2) +#define H1_REG_ENC_CTRL0 0x040 +#define H1_REG_ENC_CTRL0_INIT_QP(x) ((x) << 26) +#define H1_REG_ENC_CTRL0_SLICE_ALPHA(x) ((x) << 22) +#define H1_REG_ENC_CTRL0_SLICE_BETA(x) ((x) << 18) +#define H1_REG_ENC_CTRL0_CHROMA_QP_OFFSET(x) ((x) << 13) +#define H1_REG_ENC_CTRL0_FILTER_DIS(x) ((x) << 5) +#define H1_REG_ENC_CTRL0_IDR_PICID(x) ((x) << 1) +#define H1_REG_ENC_CTRL0_CONSTR_INTRA_PRED BIT(0) +#define H1_REG_ENC_CTRL1 0x044 +#define H1_REG_ENC_CTRL1_PPS_ID(x) ((x) << 24) +#define H1_REG_ENC_CTRL1_INTRA_PRED_MODE(x) ((x) << 16) +#define H1_REG_ENC_CTRL1_FRAME_NUM(x) ((x)) +#define H1_REG_ENC_CTRL2 0x048 +#define H1_REG_ENC_CTRL2_DEBLOCKING_FILETER_MODE(x) ((x) << 30) +#define H1_REG_ENC_CTRL2_H264_SLICE_SIZE(x) ((x) << 23) +#define H1_REG_ENC_CTRL2_DISABLE_QUARTER_PIXMV BIT(22) +#define H1_REG_ENC_CTRL2_TRANS8X8_MODE_EN BIT(21) +#define H1_REG_ENC_CTRL2_CABAC_INIT_IDC(x) ((x) << 19) +#define H1_REG_ENC_CTRL2_ENTROPY_CODING_MODE BIT(18) +#define H1_REG_ENC_CTRL2_H264_INTER4X4_MODE BIT(17) +#define H1_REG_ENC_CTRL2_H264_STREAM_MODE BIT(16) +#define H1_REG_ENC_CTRL2_INTRA16X16_MODE(x) ((x)) +#define H1_REG_ENC_CTRL3 0x04c +#define H1_REG_ENC_CTRL3_MUTIMV_EN BIT(30) +#define H1_REG_ENC_CTRL3_MV_PENALTY_1_4P(x) ((x) << 20) +#define H1_REG_ENC_CTRL3_MV_PENALTY_4P(x) ((x) << 10) +#define H1_REG_ENC_CTRL3_MV_PENALTY_1P(x) ((x)) +#define H1_REG_ENC_CTRL4 0x050 +#define H1_REG_ENC_CTRL4_MV_PENALTY_16X8_8X16(x) ((x) << 20) +#define H1_REG_ENC_CTRL4_MV_PENALTY_8X8(x) ((x) << 10) +#define H1_REG_ENC_CTRL4_8X4_4X8(x) ((x)) +#define H1_REG_ENC_CTRL5 0x054 +#define H1_REG_ENC_CTRL5_MACROBLOCK_PENALTY(x) ((x) << 24) +#define H1_REG_ENC_CTRL5_COMPLETE_SLICES(x) ((x) << 16) +#define H1_REG_ENC_CTRL5_INTER_MODE(x) ((x)) +#define H1_REG_STR_HDR_REM_MSB 0x058 +#define H1_REG_STR_HDR_REM_LSB 0x05c +#define H1_REG_STR_BUF_LIMIT 0x060 +#define H1_REG_MAD_CTRL 0x064 +#define H1_REG_MAD_CTRL_QP_ADJUST(x) ((x) << 28) +#define H1_REG_MAD_CTRL_MAD_THREDHOLD(x) ((x) << 22) +#define H1_REG_MAD_CTRL_QP_SUM_DIV2(x) ((x)) +#define H1_REG_ADDR_VP8_PROB_CNT 0x068 +#define H1_REG_QP_VAL 0x06c +#define H1_REG_QP_VAL_LUM(x) ((x) << 26) +#define H1_REG_QP_VAL_MAX(x) ((x) << 20) +#define H1_REG_QP_VAL_MIN(x) ((x) << 14) +#define H1_REG_QP_VAL_CHECKPOINT_DISTAN(x) ((x)) +#define H1_REG_VP8_QP_VAL(i) (0x06c + ((i) * 0x4)) +#define H1_REG_CHECKPOINT(i) (0x070 + ((i) * 0x4)) +#define H1_REG_CHECKPOINT_CHECK0(x) (((x) & 0xffff)) +#define H1_REG_CHECKPOINT_CHECK1(x) (((x) & 0xffff) << 16) +#define H1_REG_CHECKPOINT_RESULT(x) ((((x) >> (16 - 16 \ + * (i & 1))) & 0xffff) \ + * 32) +#define H1_REG_CHKPT_WORD_ERR(i) (0x084 + ((i) * 0x4)) +#define H1_REG_CHKPT_WORD_ERR_CHK0(x) (((x) & 0xffff)) +#define H1_REG_CHKPT_WORD_ERR_CHK1(x) (((x) & 0xffff) << 16) +#define H1_REG_VP8_BOOL_ENC 0x08c +#define H1_REG_CHKPT_DELTA_QP 0x090 +#define H1_REG_CHKPT_DELTA_QP_CHK0(x) (((x) & 0x0f) << 0) +#define H1_REG_CHKPT_DELTA_QP_CHK1(x) (((x) & 0x0f) << 4) +#define H1_REG_CHKPT_DELTA_QP_CHK2(x) (((x) & 0x0f) << 8) +#define H1_REG_CHKPT_DELTA_QP_CHK3(x) (((x) & 0x0f) << 12) +#define H1_REG_CHKPT_DELTA_QP_CHK4(x) (((x) & 0x0f) << 16) +#define H1_REG_CHKPT_DELTA_QP_CHK5(x) (((x) & 0x0f) << 20) +#define H1_REG_CHKPT_DELTA_QP_CHK6(x) (((x) & 0x0f) << 24) +#define H1_REG_VP8_CTRL0 0x090 +#define H1_REG_RLC_CTRL 0x094 +#define H1_REG_RLC_CTRL_STR_OFFS_SHIFT 23 +#define H1_REG_RLC_CTRL_STR_OFFS_MASK (0x3f << 23) +#define H1_REG_RLC_CTRL_RLC_SUM(x) ((x)) +#define H1_REG_MB_CTRL 0x098 +#define H1_REG_MB_CNT_OUT(x) (((x) & 0xffff)) +#define H1_REG_MB_CNT_SET(x) (((x) & 0xffff) << 16) +#define H1_REG_ADDR_NEXT_PIC 0x09c +#define H1_REG_JPEG_LUMA_QUAT(i) (0x100 + ((i) * 0x4)) +#define H1_REG_JPEG_CHROMA_QUAT(i) (0x140 + ((i) * 0x4)) +#define H1_REG_STABILIZATION_OUTPUT 0x0A0 +#define H1_REG_ADDR_CABAC_TBL 0x0cc +#define H1_REG_ADDR_MV_OUT 0x0d0 +#define H1_REG_RGB_YUV_COEFF(i) (0x0d4 + ((i) * 0x4)) +#define H1_REG_RGB_MASK_MSB 0x0dc +#define H1_REG_INTRA_AREA_CTRL 0x0e0 +#define H1_REG_CIR_INTRA_CTRL 0x0e4 +#define H1_REG_INTRA_SLICE_BITMAP(i) (0x0e8 + ((i) * 0x4)) +#define H1_REG_ADDR_VP8_DCT_PART(i) (0x0e8 + ((i) * 0x4)) +#define H1_REG_FIRST_ROI_AREA 0x0f0 +#define H1_REG_SECOND_ROI_AREA 0x0f4 +#define H1_REG_MVC_CTRL 0x0f8 +#define H1_REG_MVC_CTRL_MV16X16_FAVOR(x) ((x) << 28) +#define H1_REG_VP8_INTRA_PENALTY(i) (0x100 + ((i) * 0x4)) +#define H1_REG_ADDR_VP8_SEG_MAP 0x11c +#define H1_REG_VP8_SEG_QP(i) (0x120 + ((i) * 0x4)) +#define H1_REG_DMV_4P_1P_PENALTY(i) (0x180 + ((i) * 0x4)) +#define H1_REG_DMV_4P_1P_PENALTY_BIT(x, i) ((x) << (i) * 8) +#define H1_REG_DMV_QPEL_PENALTY(i) (0x200 + ((i) * 0x4)) +#define H1_REG_DMV_QPEL_PENALTY_BIT(x, i) ((x) << (i) * 8) +#define H1_REG_VP8_CTRL1 0x280 +#define H1_REG_VP8_BIT_COST_GOLDEN 0x284 +#define H1_REG_VP8_LOOP_FLT_DELTA(i) (0x288 + ((i) * 0x4)) + +#endif /* HANTRO_H1_REGS_H_ */ diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/staging/media/hantro/hantro_hw.h new file mode 100644 index 000000000000..3c361c2e9b88 --- /dev/null +++ b/drivers/staging/media/hantro/hantro_hw.h @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Hantro VPU codec driver + * + * Copyright 2018 Google LLC. + * Tomasz Figa + */ + +#ifndef HANTRO_HW_H_ +#define HANTRO_HW_H_ + +#include +#include +#include +#include + +struct hantro_dev; +struct hantro_ctx; +struct hantro_buf; +struct hantro_variant; + +/** + * struct hantro_aux_buf - auxiliary DMA buffer for hardware data + * @cpu: CPU pointer to the buffer. + * @dma: DMA address of the buffer. + * @size: Size of the buffer. + */ +struct hantro_aux_buf { + void *cpu; + dma_addr_t dma; + size_t size; +}; + +/** + * struct hantro_jpeg_enc_hw_ctx + * @bounce_buffer: Bounce buffer + */ +struct hantro_jpeg_enc_hw_ctx { + struct hantro_aux_buf bounce_buffer; +}; + +/** + * struct hantro_mpeg2_dec_hw_ctx + * @qtable: Quantization table + */ +struct hantro_mpeg2_dec_hw_ctx { + struct hantro_aux_buf qtable; +}; + +/** + * struct hantro_codec_ops - codec mode specific operations + * + * @init: If needed, can be used for initialization. + * Optional and called from process context. + * @exit: If needed, can be used to undo the .init phase. + * Optional and called from process context. + * @run: Start single {en,de)coding job. Called from atomic context + * to indicate that a pair of buffers is ready and the hardware + * should be programmed and started. + * @done: Read back processing results and additional data from hardware. + * @reset: Reset the hardware in case of a timeout. + */ +struct hantro_codec_ops { + int (*init)(struct hantro_ctx *ctx); + void (*exit)(struct hantro_ctx *ctx); + void (*run)(struct hantro_ctx *ctx); + void (*done)(struct hantro_ctx *ctx, enum vb2_buffer_state); + void (*reset)(struct hantro_ctx *ctx); +}; + +/** + * enum hantro_enc_fmt - source format ID for hardware registers. + */ +enum hantro_enc_fmt { + RK3288_VPU_ENC_FMT_YUV420P = 0, + RK3288_VPU_ENC_FMT_YUV420SP = 1, + RK3288_VPU_ENC_FMT_YUYV422 = 2, + RK3288_VPU_ENC_FMT_UYVY422 = 3, +}; + +extern const struct hantro_variant rk3399_vpu_variant; +extern const struct hantro_variant rk3328_vpu_variant; +extern const struct hantro_variant rk3288_vpu_variant; + +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_h1_jpeg_enc_run(struct hantro_ctx *ctx); +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); + +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, + const struct v4l2_ctrl_mpeg2_quantization *ctrl); +int hantro_mpeg2_dec_init(struct hantro_ctx *ctx); +void hantro_mpeg2_dec_exit(struct hantro_ctx *ctx); + +#endif /* HANTRO_HW_H_ */ diff --git a/drivers/staging/media/hantro/hantro_jpeg.c b/drivers/staging/media/hantro/hantro_jpeg.c new file mode 100644 index 000000000000..125eb41f2ede --- /dev/null +++ b/drivers/staging/media/hantro/hantro_jpeg.c @@ -0,0 +1,319 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) Collabora, Ltd. + * + * Based on GSPCA and CODA drivers: + * Copyright (C) Jean-Francois Moine (http://moinejf.free.fr) + * Copyright (C) 2014 Philipp Zabel, Pengutronix + */ +#include +#include +#include +#include "hantro_jpeg.h" +#include "hantro.h" + +#define LUMA_QUANT_OFF 7 +#define CHROMA_QUANT_OFF 72 +#define HEIGHT_OFF 141 +#define WIDTH_OFF 143 + +#define HUFF_LUMA_DC_OFF 160 +#define HUFF_LUMA_AC_OFF 193 +#define HUFF_CHROMA_DC_OFF 376 +#define HUFF_CHROMA_AC_OFF 409 + +/* Default tables from JPEG ITU-T.81 + * (ISO/IEC 10918-1) Annex K.3, I + */ +static const unsigned char luma_q_table[] = { + 0x10, 0x0b, 0x0a, 0x10, 0x7c, 0x8c, 0x97, 0xa1, + 0x0c, 0x0c, 0x0e, 0x13, 0x7e, 0x9e, 0xa0, 0x9b, + 0x0e, 0x0d, 0x10, 0x18, 0x8c, 0x9d, 0xa9, 0x9c, + 0x0e, 0x11, 0x16, 0x1d, 0x97, 0xbb, 0xb4, 0xa2, + 0x12, 0x16, 0x25, 0x38, 0xa8, 0x6d, 0x67, 0xb1, + 0x18, 0x23, 0x37, 0x40, 0xb5, 0x68, 0x71, 0xc0, + 0x31, 0x40, 0x4e, 0x57, 0x67, 0x79, 0x78, 0x65, + 0x48, 0x5c, 0x5f, 0x62, 0x70, 0x64, 0x67, 0xc7, +}; + +static const unsigned char chroma_q_table[] = { + 0x11, 0x12, 0x18, 0x2f, 0x63, 0x63, 0x63, 0x63, + 0x12, 0x15, 0x1a, 0x42, 0x63, 0x63, 0x63, 0x63, + 0x18, 0x1a, 0x38, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x2f, 0x42, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63 +}; + +/* Huffman tables are shared with CODA */ +static const unsigned char luma_dc_table[] = { + 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, +}; + +static const unsigned char chroma_dc_table[] = { + 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, +}; + +static const unsigned char luma_ac_table[] = { + 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, + 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d, + 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, + 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, + 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, + 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, + 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, + 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, + 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, + 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, + 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, + 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, + 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, + 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, + 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, + 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, + 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, + 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa, +}; + +static const unsigned char chroma_ac_table[] = { + 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, + 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, + 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, + 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, + 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, + 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, + 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, + 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, + 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, + 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, + 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, + 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, + 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, + 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, + 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, + 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, + 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, + 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, + 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, + 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, + 0xf9, 0xfa, +}; + +/* For simplicity, we keep a pre-formatted JPEG header, + * and we'll use fixed offsets to change the width, height + * quantization tables, etc. + */ +static const unsigned char hantro_jpeg_header[JPEG_HEADER_SIZE] = { + /* SOI */ + 0xff, 0xd8, + + /* DQT */ + 0xff, 0xdb, 0x00, 0x84, + + 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* SOF */ + 0xff, 0xc0, 0x00, 0x11, 0x08, 0x00, 0xf0, 0x01, + 0x40, 0x03, 0x01, 0x22, 0x00, 0x02, 0x11, 0x01, + 0x03, 0x11, 0x01, + + /* DHT */ + 0xff, 0xc4, 0x00, 0x1f, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + + /* DHT */ + 0xff, 0xc4, 0x00, 0xb5, 0x10, + + 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* DHT */ + 0xff, 0xc4, 0x00, 0x1f, 0x01, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + + /* DHT */ + 0xff, 0xc4, 0x00, 0xb5, 0x11, + + 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* SOS */ + 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, + 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00, +}; + +static void +jpeg_scale_quant_table(unsigned char *q_tab, + const unsigned char *tab, int scale) +{ + unsigned int temp; + int i; + + for (i = 0; i < 64; i++) { + temp = DIV_ROUND_CLOSEST((unsigned int)tab[i] * scale, 100); + if (temp <= 0) + temp = 1; + if (temp > 255) + temp = 255; + q_tab[i] = (unsigned char)temp; + } +} + +static void jpeg_set_quality(unsigned char *buffer, int quality) +{ + int scale; + + /* + * Non-linear scaling factor: + * [5,50] -> [1000..100], [51,100] -> [98..0] + */ + if (quality < 50) + scale = 5000 / quality; + else + scale = 200 - 2 * quality; + + jpeg_scale_quant_table(buffer + LUMA_QUANT_OFF, + luma_q_table, scale); + jpeg_scale_quant_table(buffer + CHROMA_QUANT_OFF, + chroma_q_table, scale); +} + +unsigned char * +hantro_jpeg_get_qtable(struct hantro_jpeg_ctx *ctx, int index) +{ + if (index == 0) + return ctx->buffer + LUMA_QUANT_OFF; + return ctx->buffer + CHROMA_QUANT_OFF; +} + +void hantro_jpeg_header_assemble(struct hantro_jpeg_ctx *ctx) +{ + char *buf = ctx->buffer; + + memcpy(buf, hantro_jpeg_header, + sizeof(hantro_jpeg_header)); + + buf[HEIGHT_OFF + 0] = ctx->height >> 8; + buf[HEIGHT_OFF + 1] = ctx->height; + buf[WIDTH_OFF + 0] = ctx->width >> 8; + buf[WIDTH_OFF + 1] = ctx->width; + + memcpy(buf + HUFF_LUMA_DC_OFF, luma_dc_table, sizeof(luma_dc_table)); + memcpy(buf + HUFF_LUMA_AC_OFF, luma_ac_table, sizeof(luma_ac_table)); + memcpy(buf + HUFF_CHROMA_DC_OFF, chroma_dc_table, + sizeof(chroma_dc_table)); + memcpy(buf + HUFF_CHROMA_AC_OFF, chroma_ac_table, + sizeof(chroma_ac_table)); + + jpeg_set_quality(buf, ctx->quality); +} + +int hantro_jpeg_enc_init(struct hantro_ctx *ctx) +{ + ctx->jpeg_enc.bounce_buffer.size = + ctx->dst_fmt.plane_fmt[0].sizeimage - + ctx->vpu_dst_fmt->header_size; + + ctx->jpeg_enc.bounce_buffer.cpu = + dma_alloc_attrs(ctx->dev->dev, + ctx->jpeg_enc.bounce_buffer.size, + &ctx->jpeg_enc.bounce_buffer.dma, + GFP_KERNEL, + DMA_ATTR_ALLOC_SINGLE_PAGES); + if (!ctx->jpeg_enc.bounce_buffer.cpu) + return -ENOMEM; + + return 0; +} + +void hantro_jpeg_enc_exit(struct hantro_ctx *ctx) +{ + dma_free_attrs(ctx->dev->dev, + ctx->jpeg_enc.bounce_buffer.size, + ctx->jpeg_enc.bounce_buffer.cpu, + ctx->jpeg_enc.bounce_buffer.dma, + DMA_ATTR_ALLOC_SINGLE_PAGES); +} diff --git a/drivers/staging/media/hantro/hantro_jpeg.h b/drivers/staging/media/hantro/hantro_jpeg.h new file mode 100644 index 000000000000..9e8397c71388 --- /dev/null +++ b/drivers/staging/media/hantro/hantro_jpeg.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + +#define JPEG_HEADER_SIZE 601 + +struct hantro_jpeg_ctx { + int width; + int height; + int quality; + unsigned char *buffer; +}; + +unsigned char *hantro_jpeg_get_qtable(struct hantro_jpeg_ctx *ctx, int index); +void hantro_jpeg_header_assemble(struct hantro_jpeg_ctx *ctx); diff --git a/drivers/staging/media/hantro/hantro_mpeg2.c b/drivers/staging/media/hantro/hantro_mpeg2.c new file mode 100644 index 000000000000..1d334e6fcd06 --- /dev/null +++ b/drivers/staging/media/hantro/hantro_mpeg2.c @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Hantro VPU codec driver + * + * Copyright (C) 2018 Rockchip Electronics Co., Ltd. + */ + +#include "hantro.h" + +static const u8 zigzag[64] = { + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63 +}; + +void hantro_mpeg2_dec_copy_qtable(u8 *qtable, + const struct v4l2_ctrl_mpeg2_quantization *ctrl) +{ + int i, n; + + if (!qtable || !ctrl) + return; + + for (i = 0; i < ARRAY_SIZE(zigzag); i++) { + n = zigzag[i]; + qtable[n + 0] = ctrl->intra_quantiser_matrix[i]; + qtable[n + 64] = ctrl->non_intra_quantiser_matrix[i]; + qtable[n + 128] = ctrl->chroma_intra_quantiser_matrix[i]; + qtable[n + 192] = ctrl->chroma_non_intra_quantiser_matrix[i]; + } +} + +int hantro_mpeg2_dec_init(struct hantro_ctx *ctx) +{ + struct hantro_dev *vpu = ctx->dev; + + ctx->mpeg2_dec.qtable.size = ARRAY_SIZE(zigzag) * 4; + ctx->mpeg2_dec.qtable.cpu = + dma_alloc_coherent(vpu->dev, + ctx->mpeg2_dec.qtable.size, + &ctx->mpeg2_dec.qtable.dma, + GFP_KERNEL); + if (!ctx->mpeg2_dec.qtable.cpu) + return -ENOMEM; + return 0; +} + +void hantro_mpeg2_dec_exit(struct hantro_ctx *ctx) +{ + struct hantro_dev *vpu = ctx->dev; + + dma_free_coherent(vpu->dev, + ctx->mpeg2_dec.qtable.size, + ctx->mpeg2_dec.qtable.cpu, + ctx->mpeg2_dec.qtable.dma); +} diff --git a/drivers/staging/media/hantro/hantro_v4l2.c b/drivers/staging/media/hantro/hantro_v4l2.c new file mode 100644 index 000000000000..b4af8c659a98 --- /dev/null +++ b/drivers/staging/media/hantro/hantro_v4l2.c @@ -0,0 +1,686 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Hantro VPU codec driver + * + * Copyright (C) 2018 Collabora, Ltd. + * Copyright (C) 2018 Rockchip Electronics Co., Ltd. + * Alpha Lin + * Jeffy Chen + * + * Copyright 2018 Google LLC. + * Tomasz Figa + * + * Based on s5p-mfc driver by Samsung Electronics Co., Ltd. + * Copyright (C) 2010-2011 Samsung Electronics Co., Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hantro.h" +#include "hantro_hw.h" +#include "hantro_v4l2.h" + +static const struct hantro_fmt * +hantro_get_formats(const struct hantro_ctx *ctx, unsigned int *num_fmts) +{ + const struct hantro_fmt *formats; + + if (hantro_is_encoder_ctx(ctx)) { + formats = ctx->dev->variant->enc_fmts; + *num_fmts = ctx->dev->variant->num_enc_fmts; + } else { + formats = ctx->dev->variant->dec_fmts; + *num_fmts = ctx->dev->variant->num_dec_fmts; + } + + return formats; +} + +static const struct hantro_fmt * +hantro_find_format(const struct hantro_fmt *formats, unsigned int num_fmts, + u32 fourcc) +{ + unsigned int i; + + for (i = 0; i < num_fmts; i++) + if (formats[i].fourcc == fourcc) + return &formats[i]; + return NULL; +} + +static const struct hantro_fmt * +hantro_get_default_fmt(const struct hantro_fmt *formats, unsigned int num_fmts, + bool bitstream) +{ + unsigned int i; + + for (i = 0; i < num_fmts; i++) { + if (bitstream == (formats[i].codec_mode != + HANTRO_MODE_NONE)) + return &formats[i]; + } + return NULL; +} + +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct hantro_dev *vpu = video_drvdata(file); + struct video_device *vdev = video_devdata(file); + + strscpy(cap->driver, vpu->dev->driver->name, sizeof(cap->driver)); + strscpy(cap->card, vdev->name, sizeof(cap->card)); + snprintf(cap->bus_info, sizeof(cap->bus_info), "platform: %s", + vpu->dev->driver->name); + return 0; +} + +static int vidioc_enum_framesizes(struct file *file, void *priv, + struct v4l2_frmsizeenum *fsize) +{ + struct hantro_ctx *ctx = fh_to_ctx(priv); + const struct hantro_fmt *formats, *fmt; + unsigned int num_fmts; + + if (fsize->index != 0) { + vpu_debug(0, "invalid frame size index (expected 0, got %d)\n", + fsize->index); + return -EINVAL; + } + + formats = hantro_get_formats(ctx, &num_fmts); + fmt = hantro_find_format(formats, num_fmts, fsize->pixel_format); + if (!fmt) { + vpu_debug(0, "unsupported bitstream format (%08x)\n", + fsize->pixel_format); + return -EINVAL; + } + + /* This only makes sense for coded formats */ + if (fmt->codec_mode == HANTRO_MODE_NONE) + return -EINVAL; + + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; + fsize->stepwise = fmt->frmsize; + + return 0; +} + +static int vidioc_enum_fmt(struct file *file, void *priv, + struct v4l2_fmtdesc *f, bool capture) + +{ + struct hantro_ctx *ctx = fh_to_ctx(priv); + const struct hantro_fmt *fmt, *formats; + unsigned int num_fmts, i, j = 0; + bool skip_mode_none; + + /* + * When dealing with an encoder: + * - on the capture side we want to filter out all MODE_NONE formats. + * - on the output side we want to filter out all formats that are + * not MODE_NONE. + * When dealing with a decoder: + * - on the capture side we want to filter out all formats that are + * not MODE_NONE. + * - on the output side we want to filter out all MODE_NONE formats. + */ + skip_mode_none = capture == hantro_is_encoder_ctx(ctx); + + formats = hantro_get_formats(ctx, &num_fmts); + for (i = 0; i < num_fmts; i++) { + bool mode_none = formats[i].codec_mode == HANTRO_MODE_NONE; + + if (skip_mode_none == mode_none) + continue; + if (j == f->index) { + fmt = &formats[i]; + f->pixelformat = fmt->fourcc; + return 0; + } + ++j; + } + return -EINVAL; +} + +static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + return vidioc_enum_fmt(file, priv, f, true); +} + +static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + return vidioc_enum_fmt(file, priv, f, false); +} + +static int vidioc_g_fmt_out_mplane(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; + struct hantro_ctx *ctx = fh_to_ctx(priv); + + vpu_debug(4, "f->type = %d\n", f->type); + + *pix_mp = ctx->src_fmt; + + return 0; +} + +static int vidioc_g_fmt_cap_mplane(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; + struct hantro_ctx *ctx = fh_to_ctx(priv); + + vpu_debug(4, "f->type = %d\n", f->type); + + *pix_mp = ctx->dst_fmt; + + return 0; +} + +static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f, + bool capture) +{ + struct hantro_ctx *ctx = fh_to_ctx(priv); + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; + const struct hantro_fmt *formats, *fmt, *vpu_fmt; + unsigned int num_fmts; + bool coded; + + coded = capture == hantro_is_encoder_ctx(ctx); + + vpu_debug(4, "trying format %c%c%c%c\n", + (pix_mp->pixelformat & 0x7f), + (pix_mp->pixelformat >> 8) & 0x7f, + (pix_mp->pixelformat >> 16) & 0x7f, + (pix_mp->pixelformat >> 24) & 0x7f); + + formats = hantro_get_formats(ctx, &num_fmts); + fmt = hantro_find_format(formats, num_fmts, pix_mp->pixelformat); + if (!fmt) { + fmt = hantro_get_default_fmt(formats, num_fmts, coded); + f->fmt.pix_mp.pixelformat = fmt->fourcc; + } + + if (coded) { + pix_mp->num_planes = 1; + vpu_fmt = fmt; + } else if (hantro_is_encoder_ctx(ctx)) { + vpu_fmt = ctx->vpu_dst_fmt; + } else { + vpu_fmt = ctx->vpu_src_fmt; + /* + * Width/height on the CAPTURE end of a decoder are ignored and + * replaced by the OUTPUT ones. + */ + pix_mp->width = ctx->src_fmt.width; + pix_mp->height = ctx->src_fmt.height; + } + + pix_mp->field = V4L2_FIELD_NONE; + + v4l2_apply_frmsize_constraints(&pix_mp->width, &pix_mp->height, + &vpu_fmt->frmsize); + + if (!coded) { + /* Fill remaining fields */ + v4l2_fill_pixfmt_mp(pix_mp, fmt->fourcc, pix_mp->width, + pix_mp->height); + } else if (!pix_mp->plane_fmt[0].sizeimage) { + /* + * For coded formats the application can specify + * sizeimage. If the application passes a zero sizeimage, + * let's default to the maximum frame size. + */ + pix_mp->plane_fmt[0].sizeimage = fmt->header_size + + pix_mp->width * pix_mp->height * fmt->max_depth; + } + + return 0; +} + +static int vidioc_try_fmt_cap_mplane(struct file *file, void *priv, + struct v4l2_format *f) +{ + return vidioc_try_fmt(file, priv, f, true); +} + +static int vidioc_try_fmt_out_mplane(struct file *file, void *priv, + struct v4l2_format *f) +{ + return vidioc_try_fmt(file, priv, f, false); +} + +static void +hantro_reset_fmt(struct v4l2_pix_format_mplane *fmt, + const struct hantro_fmt *vpu_fmt) +{ + memset(fmt, 0, sizeof(*fmt)); + + fmt->pixelformat = vpu_fmt->fourcc; + fmt->field = V4L2_FIELD_NONE; + fmt->colorspace = V4L2_COLORSPACE_JPEG, + fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + fmt->quantization = V4L2_QUANTIZATION_DEFAULT; + fmt->xfer_func = V4L2_XFER_FUNC_DEFAULT; +} + +static void +hantro_reset_encoded_fmt(struct hantro_ctx *ctx) +{ + const struct hantro_fmt *vpu_fmt, *formats; + struct v4l2_pix_format_mplane *fmt; + unsigned int num_fmts; + + formats = hantro_get_formats(ctx, &num_fmts); + vpu_fmt = hantro_get_default_fmt(formats, num_fmts, true); + + if (hantro_is_encoder_ctx(ctx)) { + ctx->vpu_dst_fmt = vpu_fmt; + fmt = &ctx->dst_fmt; + } else { + ctx->vpu_src_fmt = vpu_fmt; + fmt = &ctx->src_fmt; + } + + hantro_reset_fmt(fmt, vpu_fmt); + fmt->num_planes = 1; + fmt->width = vpu_fmt->frmsize.min_width; + fmt->height = vpu_fmt->frmsize.min_height; + fmt->plane_fmt[0].sizeimage = vpu_fmt->header_size + + fmt->width * fmt->height * vpu_fmt->max_depth; +} + +static void +hantro_reset_raw_fmt(struct hantro_ctx *ctx) +{ + const struct hantro_fmt *raw_vpu_fmt, *formats; + struct v4l2_pix_format_mplane *raw_fmt, *encoded_fmt; + unsigned int num_fmts; + + formats = hantro_get_formats(ctx, &num_fmts); + raw_vpu_fmt = hantro_get_default_fmt(formats, num_fmts, false); + + if (hantro_is_encoder_ctx(ctx)) { + ctx->vpu_src_fmt = raw_vpu_fmt; + raw_fmt = &ctx->src_fmt; + encoded_fmt = &ctx->dst_fmt; + } else { + ctx->vpu_dst_fmt = raw_vpu_fmt; + raw_fmt = &ctx->dst_fmt; + encoded_fmt = &ctx->src_fmt; + } + + hantro_reset_fmt(raw_fmt, raw_vpu_fmt); + v4l2_fill_pixfmt_mp(raw_fmt, raw_vpu_fmt->fourcc, + encoded_fmt->width, + encoded_fmt->height); +} + +void hantro_reset_fmts(struct hantro_ctx *ctx) +{ + hantro_reset_encoded_fmt(ctx); + hantro_reset_raw_fmt(ctx); +} + +static void +hantro_update_requires_request(struct hantro_ctx *ctx, u32 fourcc) +{ + switch (fourcc) { + case V4L2_PIX_FMT_JPEG: + ctx->fh.m2m_ctx->out_q_ctx.q.requires_requests = false; + break; + case V4L2_PIX_FMT_MPEG2_SLICE: + ctx->fh.m2m_ctx->out_q_ctx.q.requires_requests = true; + break; + default: + break; + } +} + +static int +vidioc_s_fmt_out_mplane(struct file *file, void *priv, struct v4l2_format *f) +{ + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; + struct hantro_ctx *ctx = fh_to_ctx(priv); + const struct hantro_fmt *formats; + unsigned int num_fmts; + struct vb2_queue *vq; + int ret; + + /* Change not allowed if queue is busy. */ + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); + if (vb2_is_busy(vq)) + return -EBUSY; + + if (!hantro_is_encoder_ctx(ctx)) { + struct vb2_queue *peer_vq; + + /* + * Since format change on the OUTPUT queue will reset + * the CAPTURE queue, we can't allow doing so + * when the CAPTURE queue has buffers allocated. + */ + peer_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + if (vb2_is_busy(peer_vq)) + return -EBUSY; + } + + ret = vidioc_try_fmt_out_mplane(file, priv, f); + if (ret) + return ret; + + formats = hantro_get_formats(ctx, &num_fmts); + ctx->vpu_src_fmt = hantro_find_format(formats, num_fmts, + pix_mp->pixelformat); + ctx->src_fmt = *pix_mp; + + /* + * Current raw format might have become invalid with newly + * selected codec, so reset it to default just to be safe and + * keep internal driver state sane. User is mandated to set + * the raw format again after we return, so we don't need + * anything smarter. + * Note that hantro_reset_raw_fmt() also propagates size + * changes to the raw format. + */ + if (!hantro_is_encoder_ctx(ctx)) + hantro_reset_raw_fmt(ctx); + + /* Colorimetry information are always propagated. */ + ctx->dst_fmt.colorspace = pix_mp->colorspace; + ctx->dst_fmt.ycbcr_enc = pix_mp->ycbcr_enc; + ctx->dst_fmt.xfer_func = pix_mp->xfer_func; + ctx->dst_fmt.quantization = pix_mp->quantization; + + hantro_update_requires_request(ctx, pix_mp->pixelformat); + + vpu_debug(0, "OUTPUT codec mode: %d\n", ctx->vpu_src_fmt->codec_mode); + vpu_debug(0, "fmt - w: %d, h: %d\n", + pix_mp->width, pix_mp->height); + return 0; +} + +static int vidioc_s_fmt_cap_mplane(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; + struct hantro_ctx *ctx = fh_to_ctx(priv); + const struct hantro_fmt *formats; + struct vb2_queue *vq; + unsigned int num_fmts; + int ret; + + /* Change not allowed if queue is busy. */ + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); + if (vb2_is_busy(vq)) + return -EBUSY; + + if (hantro_is_encoder_ctx(ctx)) { + struct vb2_queue *peer_vq; + + /* + * Since format change on the CAPTURE queue will reset + * the OUTPUT queue, we can't allow doing so + * when the OUTPUT queue has buffers allocated. + */ + peer_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + if (vb2_is_busy(peer_vq) && + (pix_mp->pixelformat != ctx->dst_fmt.pixelformat || + pix_mp->height != ctx->dst_fmt.height || + pix_mp->width != ctx->dst_fmt.width)) + return -EBUSY; + } + + ret = vidioc_try_fmt_cap_mplane(file, priv, f); + if (ret) + return ret; + + formats = hantro_get_formats(ctx, &num_fmts); + ctx->vpu_dst_fmt = hantro_find_format(formats, num_fmts, + pix_mp->pixelformat); + ctx->dst_fmt = *pix_mp; + + /* + * Current raw format might have become invalid with newly + * selected codec, so reset it to default just to be safe and + * keep internal driver state sane. User is mandated to set + * the raw format again after we return, so we don't need + * anything smarter. + * Note that hantro_reset_raw_fmt() also propagates size + * changes to the raw format. + */ + if (hantro_is_encoder_ctx(ctx)) + hantro_reset_raw_fmt(ctx); + + /* Colorimetry information are always propagated. */ + ctx->src_fmt.colorspace = pix_mp->colorspace; + ctx->src_fmt.ycbcr_enc = pix_mp->ycbcr_enc; + ctx->src_fmt.xfer_func = pix_mp->xfer_func; + ctx->src_fmt.quantization = pix_mp->quantization; + + vpu_debug(0, "CAPTURE codec mode: %d\n", ctx->vpu_dst_fmt->codec_mode); + vpu_debug(0, "fmt - w: %d, h: %d\n", + pix_mp->width, pix_mp->height); + + hantro_update_requires_request(ctx, pix_mp->pixelformat); + + return 0; +} + +const struct v4l2_ioctl_ops hantro_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + .vidioc_enum_framesizes = vidioc_enum_framesizes, + + .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_cap_mplane, + .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt_out_mplane, + .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt_out_mplane, + .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_cap_mplane, + .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt_out_mplane, + .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt_cap_mplane, + .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, + + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, + .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, + .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, + + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + + .vidioc_streamon = v4l2_m2m_ioctl_streamon, + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, +}; + +static int +hantro_queue_setup(struct vb2_queue *vq, unsigned int *num_buffers, + unsigned int *num_planes, unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct hantro_ctx *ctx = vb2_get_drv_priv(vq); + struct v4l2_pix_format_mplane *pixfmt; + int i; + + switch (vq->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + pixfmt = &ctx->dst_fmt; + break; + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + pixfmt = &ctx->src_fmt; + break; + default: + vpu_err("invalid queue type: %d\n", vq->type); + return -EINVAL; + } + + if (*num_planes) { + if (*num_planes != pixfmt->num_planes) + return -EINVAL; + for (i = 0; i < pixfmt->num_planes; ++i) + if (sizes[i] < pixfmt->plane_fmt[i].sizeimage) + return -EINVAL; + return 0; + } + + *num_planes = pixfmt->num_planes; + for (i = 0; i < pixfmt->num_planes; ++i) + sizes[i] = pixfmt->plane_fmt[i].sizeimage; + return 0; +} + +static int +hantro_buf_plane_check(struct vb2_buffer *vb, const struct hantro_fmt *vpu_fmt, + struct v4l2_pix_format_mplane *pixfmt) +{ + unsigned int sz; + int i; + + for (i = 0; i < pixfmt->num_planes; ++i) { + sz = pixfmt->plane_fmt[i].sizeimage; + vpu_debug(4, "plane %d size: %ld, sizeimage: %u\n", + i, vb2_plane_size(vb, i), sz); + if (vb2_plane_size(vb, i) < sz) { + vpu_err("plane %d is too small for output\n", i); + return -EINVAL; + } + } + return 0; +} + +static int hantro_buf_prepare(struct vb2_buffer *vb) +{ + struct vb2_queue *vq = vb->vb2_queue; + struct hantro_ctx *ctx = vb2_get_drv_priv(vq); + + if (V4L2_TYPE_IS_OUTPUT(vq->type)) + return hantro_buf_plane_check(vb, ctx->vpu_src_fmt, + &ctx->src_fmt); + + return hantro_buf_plane_check(vb, ctx->vpu_dst_fmt, &ctx->dst_fmt); +} + +static void hantro_buf_queue(struct vb2_buffer *vb) +{ + struct hantro_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); +} + +static bool hantro_vq_is_coded(struct vb2_queue *q) +{ + struct hantro_ctx *ctx = vb2_get_drv_priv(q); + + return hantro_is_encoder_ctx(ctx) != V4L2_TYPE_IS_OUTPUT(q->type); +} + +static int hantro_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct hantro_ctx *ctx = vb2_get_drv_priv(q); + int ret = 0; + + if (V4L2_TYPE_IS_OUTPUT(q->type)) + ctx->sequence_out = 0; + else + ctx->sequence_cap = 0; + + if (hantro_vq_is_coded(q)) { + enum hantro_codec_mode codec_mode; + + if (V4L2_TYPE_IS_OUTPUT(q->type)) + codec_mode = ctx->vpu_src_fmt->codec_mode; + else + codec_mode = ctx->vpu_dst_fmt->codec_mode; + + vpu_debug(4, "Codec mode = %d\n", codec_mode); + ctx->codec_ops = &ctx->dev->variant->codec_ops[codec_mode]; + if (ctx->codec_ops && ctx->codec_ops->init) + ret = ctx->codec_ops->init(ctx); + } + + return ret; +} + +static void +hantro_return_bufs(struct vb2_queue *q, + struct vb2_v4l2_buffer *(*buf_remove)(struct v4l2_m2m_ctx *)) +{ + struct hantro_ctx *ctx = vb2_get_drv_priv(q); + + for (;;) { + struct vb2_v4l2_buffer *vbuf; + + vbuf = buf_remove(ctx->fh.m2m_ctx); + if (!vbuf) + break; + v4l2_ctrl_request_complete(vbuf->vb2_buf.req_obj.req, + &ctx->ctrl_handler); + v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); + } +} + +static void hantro_stop_streaming(struct vb2_queue *q) +{ + struct hantro_ctx *ctx = vb2_get_drv_priv(q); + + if (hantro_vq_is_coded(q)) { + if (ctx->codec_ops && ctx->codec_ops->exit) + ctx->codec_ops->exit(ctx); + } + + /* + * The mem2mem framework calls v4l2_m2m_cancel_job before + * .stop_streaming, so there isn't any job running and + * it is safe to return all the buffers. + */ + if (V4L2_TYPE_IS_OUTPUT(q->type)) + hantro_return_bufs(q, v4l2_m2m_src_buf_remove); + else + hantro_return_bufs(q, v4l2_m2m_dst_buf_remove); +} + +static void hantro_buf_request_complete(struct vb2_buffer *vb) +{ + struct hantro_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + + v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->ctrl_handler); +} + +static int hantro_buf_out_validate(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + + vbuf->field = V4L2_FIELD_NONE; + return 0; +} + +const struct vb2_ops hantro_queue_ops = { + .queue_setup = hantro_queue_setup, + .buf_prepare = hantro_buf_prepare, + .buf_queue = hantro_buf_queue, + .buf_out_validate = hantro_buf_out_validate, + .buf_request_complete = hantro_buf_request_complete, + .start_streaming = hantro_start_streaming, + .stop_streaming = hantro_stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; diff --git a/drivers/staging/media/hantro/hantro_v4l2.h b/drivers/staging/media/hantro/hantro_v4l2.h new file mode 100644 index 000000000000..18bc682c8556 --- /dev/null +++ b/drivers/staging/media/hantro/hantro_v4l2.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Hantro VPU codec driver + * + * Copyright (C) 2018 Rockchip Electronics Co., Ltd. + * Alpha Lin + * Jeffy Chen + * + * Copyright 2018 Google LLC. + * Tomasz Figa + * + * Based on s5p-mfc driver by Samsung Electronics Co., Ltd. + * Copyright (C) 2011 Samsung Electronics Co., Ltd. + */ + +#ifndef HANTRO_V4L2_H_ +#define HANTRO_V4L2_H_ + +#include "hantro.h" + +extern const struct v4l2_ioctl_ops hantro_ioctl_ops; +extern const struct vb2_ops hantro_queue_ops; + +void hantro_reset_fmts(struct hantro_ctx *ctx); + +#endif /* HANTRO_V4L2_H_ */ diff --git a/drivers/staging/media/hantro/rk3288_vpu_hw.c b/drivers/staging/media/hantro/rk3288_vpu_hw.c new file mode 100644 index 000000000000..f0d3f0eec07b --- /dev/null +++ b/drivers/staging/media/hantro/rk3288_vpu_hw.c @@ -0,0 +1,178 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Hantro VPU codec driver + * + * Copyright (C) 2018 Rockchip Electronics Co., Ltd. + * Jeffy Chen + */ + +#include + +#include "hantro.h" +#include "hantro_jpeg.h" +#include "hantro_g1_regs.h" +#include "hantro_h1_regs.h" + +#define RK3288_ACLK_MAX_FREQ (400 * 1000 * 1000) + +/* + * Supported formats. + */ + +static const struct hantro_fmt rk3288_vpu_enc_fmts[] = { + { + .fourcc = V4L2_PIX_FMT_YUV420M, + .codec_mode = HANTRO_MODE_NONE, + .enc_fmt = RK3288_VPU_ENC_FMT_YUV420P, + }, + { + .fourcc = V4L2_PIX_FMT_NV12M, + .codec_mode = HANTRO_MODE_NONE, + .enc_fmt = RK3288_VPU_ENC_FMT_YUV420SP, + }, + { + .fourcc = V4L2_PIX_FMT_YUYV, + .codec_mode = HANTRO_MODE_NONE, + .enc_fmt = RK3288_VPU_ENC_FMT_YUYV422, + }, + { + .fourcc = V4L2_PIX_FMT_UYVY, + .codec_mode = HANTRO_MODE_NONE, + .enc_fmt = RK3288_VPU_ENC_FMT_UYVY422, + }, + { + .fourcc = V4L2_PIX_FMT_JPEG, + .codec_mode = HANTRO_MODE_JPEG_ENC, + .max_depth = 2, + .header_size = JPEG_HEADER_SIZE, + .frmsize = { + .min_width = 96, + .max_width = 8192, + .step_width = JPEG_MB_DIM, + .min_height = 32, + .max_height = 8192, + .step_height = JPEG_MB_DIM, + }, + }, +}; + +static const struct hantro_fmt rk3288_vpu_dec_fmts[] = { + { + .fourcc = V4L2_PIX_FMT_NV12, + .codec_mode = HANTRO_MODE_NONE, + }, + { + .fourcc = V4L2_PIX_FMT_MPEG2_SLICE, + .codec_mode = HANTRO_MODE_MPEG2_DEC, + .max_depth = 2, + .frmsize = { + .min_width = 48, + .max_width = 1920, + .step_width = MPEG2_MB_DIM, + .min_height = 48, + .max_height = 1088, + .step_height = MPEG2_MB_DIM, + }, + }, +}; + +static irqreturn_t rk3288_vepu_irq(int irq, void *dev_id) +{ + struct hantro_dev *vpu = dev_id; + enum vb2_buffer_state state; + u32 status, bytesused; + + status = vepu_read(vpu, H1_REG_INTERRUPT); + bytesused = vepu_read(vpu, H1_REG_STR_BUF_LIMIT) / 8; + state = (status & H1_REG_INTERRUPT_FRAME_RDY) ? + VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR; + + vepu_write(vpu, 0, H1_REG_INTERRUPT); + vepu_write(vpu, 0, H1_REG_AXI_CTRL); + + hantro_irq_done(vpu, bytesused, state); + + return IRQ_HANDLED; +} + +static irqreturn_t rk3288_vdpu_irq(int irq, void *dev_id) +{ + struct hantro_dev *vpu = dev_id; + enum vb2_buffer_state state; + u32 status; + + status = vdpu_read(vpu, G1_REG_INTERRUPT); + state = (status & G1_REG_INTERRUPT_DEC_RDY_INT) ? + VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR; + + vdpu_write(vpu, 0, G1_REG_INTERRUPT); + vdpu_write(vpu, G1_REG_CONFIG_DEC_CLK_GATE_E, G1_REG_CONFIG); + + hantro_irq_done(vpu, 0, state); + + return IRQ_HANDLED; +} + +static int rk3288_vpu_hw_init(struct hantro_dev *vpu) +{ + /* Bump ACLK to max. possible freq. to improve performance. */ + clk_set_rate(vpu->clocks[0].clk, RK3288_ACLK_MAX_FREQ); + return 0; +} + +static void rk3288_vpu_enc_reset(struct hantro_ctx *ctx) +{ + struct hantro_dev *vpu = ctx->dev; + + vepu_write(vpu, H1_REG_INTERRUPT_DIS_BIT, H1_REG_INTERRUPT); + vepu_write(vpu, 0, H1_REG_ENC_CTRL); + vepu_write(vpu, 0, H1_REG_AXI_CTRL); +} + +static void rk3288_vpu_dec_reset(struct hantro_ctx *ctx) +{ + struct hantro_dev *vpu = ctx->dev; + + vdpu_write(vpu, G1_REG_INTERRUPT_DEC_IRQ_DIS, G1_REG_INTERRUPT); + vdpu_write(vpu, G1_REG_CONFIG_DEC_CLK_GATE_E, G1_REG_CONFIG); + vdpu_write(vpu, 1, G1_REG_SOFT_RESET); +} + +/* + * Supported codec ops. + */ + +static const struct hantro_codec_ops rk3288_vpu_codec_ops[] = { + [HANTRO_MODE_JPEG_ENC] = { + .run = hantro_h1_jpeg_enc_run, + .reset = rk3288_vpu_enc_reset, + .init = hantro_jpeg_enc_init, + .exit = hantro_jpeg_enc_exit, + }, + [HANTRO_MODE_MPEG2_DEC] = { + .run = hantro_g1_mpeg2_dec_run, + .reset = rk3288_vpu_dec_reset, + .init = hantro_mpeg2_dec_init, + .exit = hantro_mpeg2_dec_exit, + }, +}; + +/* + * VPU variant. + */ + +const struct hantro_variant rk3288_vpu_variant = { + .enc_offset = 0x0, + .enc_fmts = rk3288_vpu_enc_fmts, + .num_enc_fmts = ARRAY_SIZE(rk3288_vpu_enc_fmts), + .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_ops = rk3288_vpu_codec_ops, + .vepu_irq = rk3288_vepu_irq, + .vdpu_irq = rk3288_vdpu_irq, + .init = rk3288_vpu_hw_init, + .clk_names = {"aclk", "hclk"}, + .num_clocks = 2 +}; diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw.c b/drivers/staging/media/hantro/rk3399_vpu_hw.c new file mode 100644 index 000000000000..0a43e0777189 --- /dev/null +++ b/drivers/staging/media/hantro/rk3399_vpu_hw.c @@ -0,0 +1,177 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Hantro VPU codec driver + * + * Copyright (C) 2018 Rockchip Electronics Co., Ltd. + * Jeffy Chen + */ + +#include + +#include "hantro.h" +#include "hantro_jpeg.h" +#include "rk3399_vpu_regs.h" + +#define RK3399_ACLK_MAX_FREQ (400 * 1000 * 1000) + +/* + * Supported formats. + */ + +static const struct hantro_fmt rk3399_vpu_enc_fmts[] = { + { + .fourcc = V4L2_PIX_FMT_YUV420M, + .codec_mode = HANTRO_MODE_NONE, + .enc_fmt = RK3288_VPU_ENC_FMT_YUV420P, + }, + { + .fourcc = V4L2_PIX_FMT_NV12M, + .codec_mode = HANTRO_MODE_NONE, + .enc_fmt = RK3288_VPU_ENC_FMT_YUV420SP, + }, + { + .fourcc = V4L2_PIX_FMT_YUYV, + .codec_mode = HANTRO_MODE_NONE, + .enc_fmt = RK3288_VPU_ENC_FMT_YUYV422, + }, + { + .fourcc = V4L2_PIX_FMT_UYVY, + .codec_mode = HANTRO_MODE_NONE, + .enc_fmt = RK3288_VPU_ENC_FMT_UYVY422, + }, + { + .fourcc = V4L2_PIX_FMT_JPEG, + .codec_mode = HANTRO_MODE_JPEG_ENC, + .max_depth = 2, + .header_size = JPEG_HEADER_SIZE, + .frmsize = { + .min_width = 96, + .max_width = 8192, + .step_width = JPEG_MB_DIM, + .min_height = 32, + .max_height = 8192, + .step_height = JPEG_MB_DIM, + }, + }, +}; + +static const struct hantro_fmt rk3399_vpu_dec_fmts[] = { + { + .fourcc = V4L2_PIX_FMT_NV12, + .codec_mode = HANTRO_MODE_NONE, + }, + { + .fourcc = V4L2_PIX_FMT_MPEG2_SLICE, + .codec_mode = HANTRO_MODE_MPEG2_DEC, + .max_depth = 2, + .frmsize = { + .min_width = 48, + .max_width = 1920, + .step_width = MPEG2_MB_DIM, + .min_height = 48, + .max_height = 1088, + .step_height = MPEG2_MB_DIM, + }, + }, +}; + +static irqreturn_t rk3399_vepu_irq(int irq, void *dev_id) +{ + struct hantro_dev *vpu = dev_id; + enum vb2_buffer_state state; + u32 status, bytesused; + + status = vepu_read(vpu, VEPU_REG_INTERRUPT); + bytesused = vepu_read(vpu, VEPU_REG_STR_BUF_LIMIT) / 8; + state = (status & VEPU_REG_INTERRUPT_FRAME_READY) ? + VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR; + + vepu_write(vpu, 0, VEPU_REG_INTERRUPT); + vepu_write(vpu, 0, VEPU_REG_AXI_CTRL); + + hantro_irq_done(vpu, bytesused, state); + + return IRQ_HANDLED; +} + +static irqreturn_t rk3399_vdpu_irq(int irq, void *dev_id) +{ + struct hantro_dev *vpu = dev_id; + enum vb2_buffer_state state; + u32 status; + + status = vdpu_read(vpu, VDPU_REG_INTERRUPT); + state = (status & VDPU_REG_INTERRUPT_DEC_IRQ) ? + VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR; + + vdpu_write(vpu, 0, VDPU_REG_INTERRUPT); + vdpu_write(vpu, 0, VDPU_REG_AXI_CTRL); + + hantro_irq_done(vpu, 0, state); + + return IRQ_HANDLED; +} + +static int rk3399_vpu_hw_init(struct hantro_dev *vpu) +{ + /* Bump ACLK to max. possible freq. to improve performance. */ + clk_set_rate(vpu->clocks[0].clk, RK3399_ACLK_MAX_FREQ); + return 0; +} + +static void rk3399_vpu_enc_reset(struct hantro_ctx *ctx) +{ + struct hantro_dev *vpu = ctx->dev; + + vepu_write(vpu, VEPU_REG_INTERRUPT_DIS_BIT, VEPU_REG_INTERRUPT); + vepu_write(vpu, 0, VEPU_REG_ENCODE_START); + vepu_write(vpu, 0, VEPU_REG_AXI_CTRL); +} + +static void rk3399_vpu_dec_reset(struct hantro_ctx *ctx) +{ + struct hantro_dev *vpu = ctx->dev; + + vdpu_write(vpu, VDPU_REG_INTERRUPT_DEC_IRQ_DIS, VDPU_REG_INTERRUPT); + vdpu_write(vpu, 0, VDPU_REG_EN_FLAGS); + vdpu_write(vpu, 1, VDPU_REG_SOFT_RESET); +} + +/* + * Supported codec ops. + */ + +static const struct hantro_codec_ops rk3399_vpu_codec_ops[] = { + [HANTRO_MODE_JPEG_ENC] = { + .run = rk3399_vpu_jpeg_enc_run, + .reset = rk3399_vpu_enc_reset, + .init = hantro_jpeg_enc_init, + .exit = hantro_jpeg_enc_exit, + }, + [HANTRO_MODE_MPEG2_DEC] = { + .run = rk3399_vpu_mpeg2_dec_run, + .reset = rk3399_vpu_dec_reset, + .init = hantro_mpeg2_dec_init, + .exit = hantro_mpeg2_dec_exit, + }, +}; + +/* + * VPU variant. + */ + +const struct hantro_variant rk3399_vpu_variant = { + .enc_offset = 0x0, + .enc_fmts = rk3399_vpu_enc_fmts, + .num_enc_fmts = ARRAY_SIZE(rk3399_vpu_enc_fmts), + .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_ops = rk3399_vpu_codec_ops, + .vepu_irq = rk3399_vepu_irq, + .vdpu_irq = rk3399_vdpu_irq, + .init = rk3399_vpu_hw_init, + .clk_names = {"aclk", "hclk"}, + .num_clocks = 2 +}; diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw_jpeg_enc.c b/drivers/staging/media/hantro/rk3399_vpu_hw_jpeg_enc.c new file mode 100644 index 000000000000..ae66354d2d93 --- /dev/null +++ b/drivers/staging/media/hantro/rk3399_vpu_hw_jpeg_enc.c @@ -0,0 +1,165 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Hantro VPU codec driver + * + * Copyright (C) 2018 Rockchip Electronics Co., Ltd. + * + * JPEG encoder + * ------------ + * The VPU JPEG encoder produces JPEG baseline sequential format. + * The quantization coefficients are 8-bit values, complying with + * the baseline specification. Therefore, it requires + * luma and chroma quantization tables. The hardware does entropy + * encoding using internal Huffman tables, as specified in the JPEG + * specification. + * + * In other words, only the luma and chroma quantization tables are + * required for the encoding operation. + * + * Quantization luma table values are written to registers + * VEPU_swreg_0-VEPU_swreg_15, and chroma table values to + * VEPU_swreg_16-VEPU_swreg_31. + * + * JPEG zigzag order is expected on the quantization tables. + */ + +#include +#include +#include "hantro_jpeg.h" +#include "hantro.h" +#include "hantro_v4l2.h" +#include "hantro_hw.h" +#include "rk3399_vpu_regs.h" + +#define VEPU_JPEG_QUANT_TABLE_COUNT 16 + +static void rk3399_vpu_set_src_img_ctrl(struct hantro_dev *vpu, + struct hantro_ctx *ctx) +{ + struct v4l2_pix_format_mplane *pix_fmt = &ctx->src_fmt; + u32 reg; + + /* + * The pix fmt width/height are already macroblock aligned + * by .vidioc_s_fmt_vid_cap_mplane() callback + */ + reg = VEPU_REG_IN_IMG_CTRL_ROW_LEN(pix_fmt->width); + vepu_write_relaxed(vpu, reg, VEPU_REG_INPUT_LUMA_INFO); + + reg = VEPU_REG_IN_IMG_CTRL_OVRFLR_D4(0) | + VEPU_REG_IN_IMG_CTRL_OVRFLB(0); + /* + * This register controls the input crop, as the offset + * from the right/bottom within the last macroblock. The offset from the + * right must be divided by 4 and so the crop must be aligned to 4 pixels + * horizontally. + */ + vepu_write_relaxed(vpu, reg, VEPU_REG_ENC_OVER_FILL_STRM_OFFSET); + + reg = VEPU_REG_IN_IMG_CTRL_FMT(ctx->vpu_src_fmt->enc_fmt); + vepu_write_relaxed(vpu, reg, VEPU_REG_ENC_CTRL1); +} + +static void rk3399_vpu_jpeg_enc_set_buffers(struct hantro_dev *vpu, + struct hantro_ctx *ctx, + struct vb2_buffer *src_buf) +{ + struct v4l2_pix_format_mplane *pix_fmt = &ctx->src_fmt; + dma_addr_t src[3]; + + WARN_ON(pix_fmt->num_planes > 3); + + vepu_write_relaxed(vpu, ctx->jpeg_enc.bounce_buffer.dma, + VEPU_REG_ADDR_OUTPUT_STREAM); + vepu_write_relaxed(vpu, ctx->jpeg_enc.bounce_buffer.size, + VEPU_REG_STR_BUF_LIMIT); + + if (pix_fmt->num_planes == 1) { + src[0] = vb2_dma_contig_plane_dma_addr(src_buf, 0); + vepu_write_relaxed(vpu, src[0], VEPU_REG_ADDR_IN_PLANE_0); + } else if (pix_fmt->num_planes == 2) { + src[0] = vb2_dma_contig_plane_dma_addr(src_buf, 0); + src[1] = vb2_dma_contig_plane_dma_addr(src_buf, 1); + vepu_write_relaxed(vpu, src[0], VEPU_REG_ADDR_IN_PLANE_0); + vepu_write_relaxed(vpu, src[1], VEPU_REG_ADDR_IN_PLANE_1); + } else { + src[0] = vb2_dma_contig_plane_dma_addr(src_buf, 0); + src[1] = vb2_dma_contig_plane_dma_addr(src_buf, 1); + src[2] = vb2_dma_contig_plane_dma_addr(src_buf, 2); + vepu_write_relaxed(vpu, src[0], VEPU_REG_ADDR_IN_PLANE_0); + vepu_write_relaxed(vpu, src[1], VEPU_REG_ADDR_IN_PLANE_1); + vepu_write_relaxed(vpu, src[2], VEPU_REG_ADDR_IN_PLANE_2); + } +} + +static void +rk3399_vpu_jpeg_enc_set_qtable(struct hantro_dev *vpu, + unsigned char *luma_qtable, + unsigned char *chroma_qtable) +{ + u32 reg, i; + + for (i = 0; i < VEPU_JPEG_QUANT_TABLE_COUNT; i++) { + reg = get_unaligned_be32(&luma_qtable[i]); + vepu_write_relaxed(vpu, reg, VEPU_REG_JPEG_LUMA_QUAT(i)); + + reg = get_unaligned_be32(&chroma_qtable[i]); + vepu_write_relaxed(vpu, reg, VEPU_REG_JPEG_CHROMA_QUAT(i)); + } +} + +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 = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + + src_req = src_buf->vb2_buf.req_obj.req; + v4l2_ctrl_request_setup(src_req, &ctx->ctrl_handler); + + 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; + jpeg_ctx.height = ctx->dst_fmt.height; + jpeg_ctx.quality = ctx->jpeg_quality; + hantro_jpeg_header_assemble(&jpeg_ctx); + + /* Switch to JPEG encoder mode before writing registers */ + vepu_write_relaxed(vpu, VEPU_REG_ENCODE_FORMAT_JPEG, + VEPU_REG_ENCODE_START); + + rk3399_vpu_set_src_img_ctrl(vpu, ctx); + rk3399_vpu_jpeg_enc_set_buffers(vpu, ctx, &src_buf->vb2_buf); + rk3399_vpu_jpeg_enc_set_qtable(vpu, + hantro_jpeg_get_qtable(&jpeg_ctx, 0), + hantro_jpeg_get_qtable(&jpeg_ctx, 1)); + + reg = VEPU_REG_OUTPUT_SWAP32 + | VEPU_REG_OUTPUT_SWAP16 + | VEPU_REG_OUTPUT_SWAP8 + | VEPU_REG_INPUT_SWAP8 + | VEPU_REG_INPUT_SWAP16 + | VEPU_REG_INPUT_SWAP32; + /* Make sure that all registers are written at this point. */ + vepu_write(vpu, reg, VEPU_REG_DATA_ENDIAN); + + reg = VEPU_REG_AXI_CTRL_BURST_LEN(16); + vepu_write_relaxed(vpu, reg, VEPU_REG_AXI_CTRL); + + reg = VEPU_REG_MB_WIDTH(JPEG_MB_WIDTH(ctx->src_fmt.width)) + | VEPU_REG_MB_HEIGHT(JPEG_MB_HEIGHT(ctx->src_fmt.height)) + | VEPU_REG_FRAME_TYPE_INTRA + | 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)); + 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 new file mode 100644 index 000000000000..8685bddfbcab --- /dev/null +++ b/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c @@ -0,0 +1,266 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Hantro VPU codec driver + * + * Copyright (C) 2018 Rockchip Electronics Co., Ltd. + */ + +#include +#include +#include +#include "hantro.h" +#include "hantro_hw.h" + +#define VDPU_SWREG(nr) ((nr) * 4) + +#define VDPU_REG_DEC_OUT_BASE VDPU_SWREG(63) +#define VDPU_REG_RLC_VLC_BASE VDPU_SWREG(64) +#define VDPU_REG_QTABLE_BASE VDPU_SWREG(61) +#define VDPU_REG_REFER0_BASE VDPU_SWREG(131) +#define VDPU_REG_REFER2_BASE VDPU_SWREG(134) +#define VDPU_REG_REFER3_BASE VDPU_SWREG(135) +#define VDPU_REG_REFER1_BASE VDPU_SWREG(148) +#define VDPU_REG_DEC_E(v) ((v) ? BIT(0) : 0) + +#define VDPU_REG_DEC_ADV_PRE_DIS(v) ((v) ? BIT(11) : 0) +#define VDPU_REG_DEC_SCMD_DIS(v) ((v) ? BIT(10) : 0) +#define VDPU_REG_FILTERING_DIS(v) ((v) ? BIT(8) : 0) +#define VDPU_REG_DEC_LATENCY(v) (((v) << 1) & GENMASK(6, 1)) + +#define VDPU_REG_INIT_QP(v) (((v) << 25) & GENMASK(30, 25)) +#define VDPU_REG_STREAM_LEN(v) (((v) << 0) & GENMASK(23, 0)) + +#define VDPU_REG_APF_THRESHOLD(v) (((v) << 17) & GENMASK(30, 17)) +#define VDPU_REG_STARTMB_X(v) (((v) << 8) & GENMASK(16, 8)) +#define VDPU_REG_STARTMB_Y(v) (((v) << 0) & GENMASK(7, 0)) + +#define VDPU_REG_DEC_MODE(v) (((v) << 0) & GENMASK(3, 0)) + +#define VDPU_REG_DEC_STRENDIAN_E(v) ((v) ? BIT(5) : 0) +#define VDPU_REG_DEC_STRSWAP32_E(v) ((v) ? BIT(4) : 0) +#define VDPU_REG_DEC_OUTSWAP32_E(v) ((v) ? BIT(3) : 0) +#define VDPU_REG_DEC_INSWAP32_E(v) ((v) ? BIT(2) : 0) +#define VDPU_REG_DEC_OUT_ENDIAN(v) ((v) ? BIT(1) : 0) +#define VDPU_REG_DEC_IN_ENDIAN(v) ((v) ? BIT(0) : 0) + +#define VDPU_REG_DEC_DATA_DISC_E(v) ((v) ? BIT(22) : 0) +#define VDPU_REG_DEC_MAX_BURST(v) (((v) << 16) & GENMASK(20, 16)) +#define VDPU_REG_DEC_AXI_WR_ID(v) (((v) << 8) & GENMASK(15, 8)) +#define VDPU_REG_DEC_AXI_RD_ID(v) (((v) << 0) & GENMASK(7, 0)) + +#define VDPU_REG_RLC_MODE_E(v) ((v) ? BIT(20) : 0) +#define VDPU_REG_PIC_INTERLACE_E(v) ((v) ? BIT(17) : 0) +#define VDPU_REG_PIC_FIELDMODE_E(v) ((v) ? BIT(16) : 0) +#define VDPU_REG_PIC_B_E(v) ((v) ? BIT(15) : 0) +#define VDPU_REG_PIC_INTER_E(v) ((v) ? BIT(14) : 0) +#define VDPU_REG_PIC_TOPFIELD_E(v) ((v) ? BIT(13) : 0) +#define VDPU_REG_FWD_INTERLACE_E(v) ((v) ? BIT(12) : 0) +#define VDPU_REG_WRITE_MVS_E(v) ((v) ? BIT(10) : 0) +#define VDPU_REG_DEC_TIMEOUT_E(v) ((v) ? BIT(5) : 0) +#define VDPU_REG_DEC_CLK_GATE_E(v) ((v) ? BIT(4) : 0) + +#define VDPU_REG_PIC_MB_WIDTH(v) (((v) << 23) & GENMASK(31, 23)) +#define VDPU_REG_PIC_MB_HEIGHT_P(v) (((v) << 11) & GENMASK(18, 11)) +#define VDPU_REG_ALT_SCAN_E(v) ((v) ? BIT(6) : 0) +#define VDPU_REG_TOPFIELDFIRST_E(v) ((v) ? BIT(5) : 0) + +#define VDPU_REG_STRM_START_BIT(v) (((v) << 26) & GENMASK(31, 26)) +#define VDPU_REG_QSCALE_TYPE(v) ((v) ? BIT(24) : 0) +#define VDPU_REG_CON_MV_E(v) ((v) ? BIT(4) : 0) +#define VDPU_REG_INTRA_DC_PREC(v) (((v) << 2) & GENMASK(3, 2)) +#define VDPU_REG_INTRA_VLC_TAB(v) ((v) ? BIT(1) : 0) +#define VDPU_REG_FRAME_PRED_DCT(v) ((v) ? BIT(0) : 0) + +#define VDPU_REG_ALT_SCAN_FLAG_E(v) ((v) ? BIT(19) : 0) +#define VDPU_REG_FCODE_FWD_HOR(v) (((v) << 15) & GENMASK(18, 15)) +#define VDPU_REG_FCODE_FWD_VER(v) (((v) << 11) & GENMASK(14, 11)) +#define VDPU_REG_FCODE_BWD_HOR(v) (((v) << 7) & GENMASK(10, 7)) +#define VDPU_REG_FCODE_BWD_VER(v) (((v) << 3) & GENMASK(6, 3)) +#define VDPU_REG_MV_ACCURACY_FWD(v) ((v) ? BIT(2) : 0) +#define VDPU_REG_MV_ACCURACY_BWD(v) ((v) ? BIT(1) : 0) + +#define PICT_TOP_FIELD 1 +#define PICT_BOTTOM_FIELD 2 +#define PICT_FRAME 3 + +static void +rk3399_vpu_mpeg2_dec_set_quantization(struct hantro_dev *vpu, + struct hantro_ctx *ctx) +{ + struct v4l2_ctrl_mpeg2_quantization *quantization; + + quantization = hantro_get_ctrl(ctx, + V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION); + hantro_mpeg2_dec_copy_qtable(ctx->mpeg2_dec.qtable.cpu, quantization); + vdpu_write_relaxed(vpu, ctx->mpeg2_dec.qtable.dma, + VDPU_REG_QTABLE_BASE); +} + +static void +rk3399_vpu_mpeg2_dec_set_buffers(struct hantro_dev *vpu, + struct hantro_ctx *ctx, + struct vb2_buffer *src_buf, + struct vb2_buffer *dst_buf, + const struct v4l2_mpeg2_sequence *sequence, + const struct v4l2_mpeg2_picture *picture, + const struct v4l2_ctrl_mpeg2_slice_params *slice_params) +{ + dma_addr_t forward_addr = 0, backward_addr = 0; + dma_addr_t current_addr, addr; + struct vb2_queue *vq; + + vq = v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx); + + switch (picture->picture_coding_type) { + case V4L2_MPEG2_PICTURE_CODING_TYPE_B: + backward_addr = hantro_get_ref(vq, + slice_params->backward_ref_ts); + /* fall-through */ + case V4L2_MPEG2_PICTURE_CODING_TYPE_P: + forward_addr = hantro_get_ref(vq, + slice_params->forward_ref_ts); + } + + /* Source bitstream buffer */ + addr = vb2_dma_contig_plane_dma_addr(src_buf, 0); + vdpu_write_relaxed(vpu, addr, VDPU_REG_RLC_VLC_BASE); + + /* Destination frame buffer */ + addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0); + current_addr = addr; + + if (picture->picture_structure == PICT_BOTTOM_FIELD) + addr += ALIGN(ctx->dst_fmt.width, 16); + vdpu_write_relaxed(vpu, addr, VDPU_REG_DEC_OUT_BASE); + + if (!forward_addr) + forward_addr = current_addr; + if (!backward_addr) + backward_addr = current_addr; + + /* Set forward ref frame (top/bottom field) */ + if (picture->picture_structure == PICT_FRAME || + picture->picture_coding_type == V4L2_MPEG2_PICTURE_CODING_TYPE_B || + (picture->picture_structure == PICT_TOP_FIELD && + picture->top_field_first) || + (picture->picture_structure == PICT_BOTTOM_FIELD && + !picture->top_field_first)) { + vdpu_write_relaxed(vpu, forward_addr, VDPU_REG_REFER0_BASE); + vdpu_write_relaxed(vpu, forward_addr, VDPU_REG_REFER1_BASE); + } else if (picture->picture_structure == PICT_TOP_FIELD) { + vdpu_write_relaxed(vpu, forward_addr, VDPU_REG_REFER0_BASE); + vdpu_write_relaxed(vpu, current_addr, VDPU_REG_REFER1_BASE); + } else if (picture->picture_structure == PICT_BOTTOM_FIELD) { + vdpu_write_relaxed(vpu, current_addr, VDPU_REG_REFER0_BASE); + vdpu_write_relaxed(vpu, forward_addr, VDPU_REG_REFER1_BASE); + } + + /* Set backward ref frame (top/bottom field) */ + vdpu_write_relaxed(vpu, backward_addr, VDPU_REG_REFER2_BASE); + vdpu_write_relaxed(vpu, backward_addr, VDPU_REG_REFER3_BASE); +} + +void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx) +{ + struct hantro_dev *vpu = ctx->dev; + struct vb2_v4l2_buffer *src_buf, *dst_buf; + const struct v4l2_ctrl_mpeg2_slice_params *slice_params; + const struct v4l2_mpeg2_sequence *sequence; + 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); + + /* Apply request controls if any */ + v4l2_ctrl_request_setup(src_buf->vb2_buf.req_obj.req, + &ctx->ctrl_handler); + + slice_params = hantro_get_ctrl(ctx, + V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS); + sequence = &slice_params->sequence; + picture = &slice_params->picture; + + reg = VDPU_REG_DEC_ADV_PRE_DIS(0) | + VDPU_REG_DEC_SCMD_DIS(0) | + VDPU_REG_FILTERING_DIS(1) | + VDPU_REG_DEC_LATENCY(0); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(50)); + + reg = VDPU_REG_INIT_QP(1) | + VDPU_REG_STREAM_LEN(slice_params->bit_size >> 3); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(51)); + + reg = VDPU_REG_APF_THRESHOLD(8) | + VDPU_REG_STARTMB_X(0) | + VDPU_REG_STARTMB_Y(0); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(52)); + + reg = VDPU_REG_DEC_MODE(5); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(53)); + + reg = VDPU_REG_DEC_STRENDIAN_E(1) | + VDPU_REG_DEC_STRSWAP32_E(1) | + VDPU_REG_DEC_OUTSWAP32_E(1) | + VDPU_REG_DEC_INSWAP32_E(1) | + VDPU_REG_DEC_OUT_ENDIAN(1) | + VDPU_REG_DEC_IN_ENDIAN(1); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(54)); + + reg = VDPU_REG_DEC_DATA_DISC_E(0) | + VDPU_REG_DEC_MAX_BURST(16) | + VDPU_REG_DEC_AXI_WR_ID(0) | + VDPU_REG_DEC_AXI_RD_ID(0); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(56)); + + reg = VDPU_REG_RLC_MODE_E(0) | + VDPU_REG_PIC_INTERLACE_E(!sequence->progressive_sequence) | + VDPU_REG_PIC_FIELDMODE_E(picture->picture_structure != PICT_FRAME) | + VDPU_REG_PIC_B_E(picture->picture_coding_type == V4L2_MPEG2_PICTURE_CODING_TYPE_B) | + VDPU_REG_PIC_INTER_E(picture->picture_coding_type != V4L2_MPEG2_PICTURE_CODING_TYPE_I) | + VDPU_REG_PIC_TOPFIELD_E(picture->picture_structure == PICT_TOP_FIELD) | + VDPU_REG_FWD_INTERLACE_E(0) | + VDPU_REG_WRITE_MVS_E(0) | + VDPU_REG_DEC_TIMEOUT_E(1) | + VDPU_REG_DEC_CLK_GATE_E(1); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(57)); + + reg = VDPU_REG_PIC_MB_WIDTH(MPEG2_MB_WIDTH(ctx->dst_fmt.width)) | + VDPU_REG_PIC_MB_HEIGHT_P(MPEG2_MB_HEIGHT(ctx->dst_fmt.height)) | + VDPU_REG_ALT_SCAN_E(picture->alternate_scan) | + VDPU_REG_TOPFIELDFIRST_E(picture->top_field_first); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(120)); + + reg = VDPU_REG_STRM_START_BIT(slice_params->data_bit_offset) | + VDPU_REG_QSCALE_TYPE(picture->q_scale_type) | + VDPU_REG_CON_MV_E(picture->concealment_motion_vectors) | + VDPU_REG_INTRA_DC_PREC(picture->intra_dc_precision) | + VDPU_REG_INTRA_VLC_TAB(picture->intra_vlc_format) | + VDPU_REG_FRAME_PRED_DCT(picture->frame_pred_frame_dct); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(122)); + + reg = VDPU_REG_ALT_SCAN_FLAG_E(picture->alternate_scan) | + VDPU_REG_FCODE_FWD_HOR(picture->f_code[0][0]) | + VDPU_REG_FCODE_FWD_VER(picture->f_code[0][1]) | + VDPU_REG_FCODE_BWD_HOR(picture->f_code[1][0]) | + VDPU_REG_FCODE_BWD_VER(picture->f_code[1][1]) | + VDPU_REG_MV_ACCURACY_FWD(1) | + VDPU_REG_MV_ACCURACY_BWD(1); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(136)); + + rk3399_vpu_mpeg2_dec_set_quantization(vpu, ctx); + + rk3399_vpu_mpeg2_dec_set_buffers(vpu, ctx, &src_buf->vb2_buf, + &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)); + + reg = vdpu_read(vpu, VDPU_SWREG(57)) | VDPU_REG_DEC_E(1); + vdpu_write(vpu, reg, VDPU_SWREG(57)); +} diff --git a/drivers/staging/media/hantro/rk3399_vpu_regs.h b/drivers/staging/media/hantro/rk3399_vpu_regs.h new file mode 100644 index 000000000000..88d096920f30 --- /dev/null +++ b/drivers/staging/media/hantro/rk3399_vpu_regs.h @@ -0,0 +1,600 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Hantro VPU codec driver + * + * Copyright (C) 2018 Rockchip Electronics Co., Ltd. + * Alpha Lin + */ + +#ifndef RK3399_VPU_REGS_H_ +#define RK3399_VPU_REGS_H_ + +/* Encoder registers. */ +#define VEPU_REG_VP8_QUT_1ST(i) (0x000 + ((i) * 0x24)) +#define VEPU_REG_VP8_QUT_DC_Y2(x) (((x) & 0x3fff) << 16) +#define VEPU_REG_VP8_QUT_DC_Y1(x) (((x) & 0x3fff) << 0) +#define VEPU_REG_VP8_QUT_2ND(i) (0x004 + ((i) * 0x24)) +#define VEPU_REG_VP8_QUT_AC_Y1(x) (((x) & 0x3fff) << 16) +#define VEPU_REG_VP8_QUT_DC_CHR(x) (((x) & 0x3fff) << 0) +#define VEPU_REG_VP8_QUT_3RD(i) (0x008 + ((i) * 0x24)) +#define VEPU_REG_VP8_QUT_AC_CHR(x) (((x) & 0x3fff) << 16) +#define VEPU_REG_VP8_QUT_AC_Y2(x) (((x) & 0x3fff) << 0) +#define VEPU_REG_VP8_QUT_4TH(i) (0x00c + ((i) * 0x24)) +#define VEPU_REG_VP8_QUT_ZB_DC_CHR(x) (((x) & 0x1ff) << 18) +#define VEPU_REG_VP8_QUT_ZB_DC_Y2(x) (((x) & 0x1ff) << 9) +#define VEPU_REG_VP8_QUT_ZB_DC_Y1(x) (((x) & 0x1ff) << 0) +#define VEPU_REG_VP8_QUT_5TH(i) (0x010 + ((i) * 0x24)) +#define VEPU_REG_VP8_QUT_ZB_AC_CHR(x) (((x) & 0x1ff) << 18) +#define VEPU_REG_VP8_QUT_ZB_AC_Y2(x) (((x) & 0x1ff) << 9) +#define VEPU_REG_VP8_QUT_ZB_AC_Y1(x) (((x) & 0x1ff) << 0) +#define VEPU_REG_VP8_QUT_6TH(i) (0x014 + ((i) * 0x24)) +#define VEPU_REG_VP8_QUT_RND_DC_CHR(x) (((x) & 0xff) << 16) +#define VEPU_REG_VP8_QUT_RND_DC_Y2(x) (((x) & 0xff) << 8) +#define VEPU_REG_VP8_QUT_RND_DC_Y1(x) (((x) & 0xff) << 0) +#define VEPU_REG_VP8_QUT_7TH(i) (0x018 + ((i) * 0x24)) +#define VEPU_REG_VP8_QUT_RND_AC_CHR(x) (((x) & 0xff) << 16) +#define VEPU_REG_VP8_QUT_RND_AC_Y2(x) (((x) & 0xff) << 8) +#define VEPU_REG_VP8_QUT_RND_AC_Y1(x) (((x) & 0xff) << 0) +#define VEPU_REG_VP8_QUT_8TH(i) (0x01c + ((i) * 0x24)) +#define VEPU_REG_VP8_SEG_FILTER_LEVEL(x) (((x) & 0x3f) << 25) +#define VEPU_REG_VP8_DEQUT_DC_CHR(x) (((x) & 0xff) << 17) +#define VEPU_REG_VP8_DEQUT_DC_Y2(x) (((x) & 0x1ff) << 8) +#define VEPU_REG_VP8_DEQUT_DC_Y1(x) (((x) & 0xff) << 0) +#define VEPU_REG_VP8_QUT_9TH(i) (0x020 + ((i) * 0x24)) +#define VEPU_REG_VP8_DEQUT_AC_CHR(x) (((x) & 0x1ff) << 18) +#define VEPU_REG_VP8_DEQUT_AC_Y2(x) (((x) & 0x1ff) << 9) +#define VEPU_REG_VP8_DEQUT_AC_Y1(x) (((x) & 0x1ff) << 0) +#define VEPU_REG_ADDR_VP8_SEG_MAP 0x06c +#define VEPU_REG_VP8_INTRA_4X4_PENALTY(i) (0x070 + ((i) * 0x4)) +#define VEPU_REG_VP8_INTRA_4X4_PENALTY_0(x) (((x) & 0xfff) << 0) +#define VEPU_REG_VP8_INTRA_4x4_PENALTY_1(x) (((x) & 0xfff) << 16) +#define VEPU_REG_VP8_INTRA_16X16_PENALTY(i) (0x084 + ((i) * 0x4)) +#define VEPU_REG_VP8_INTRA_16X16_PENALTY_0(x) (((x) & 0xfff) << 0) +#define VEPU_REG_VP8_INTRA_16X16_PENALTY_1(x) (((x) & 0xfff) << 16) +#define VEPU_REG_VP8_CONTROL 0x0a0 +#define VEPU_REG_VP8_LF_MODE_DELTA_BPRED(x) (((x) & 0x1f) << 24) +#define VEPU_REG_VP8_LF_REF_DELTA_INTRA_MB(x) (((x) & 0x7f) << 16) +#define VEPU_REG_VP8_INTER_TYPE_BIT_COST(x) (((x) & 0xfff) << 0) +#define VEPU_REG_VP8_REF_FRAME_VAL 0x0a4 +#define VEPU_REG_VP8_COEF_DMV_PENALTY(x) (((x) & 0xfff) << 16) +#define VEPU_REG_VP8_REF_FRAME(x) (((x) & 0xfff) << 0) +#define VEPU_REG_VP8_LOOP_FILTER_REF_DELTA 0x0a8 +#define VEPU_REG_VP8_LF_REF_DELTA_ALT_REF(x) (((x) & 0x7f) << 16) +#define VEPU_REG_VP8_LF_REF_DELTA_LAST_REF(x) (((x) & 0x7f) << 8) +#define VEPU_REG_VP8_LF_REF_DELTA_GOLDEN(x) (((x) & 0x7f) << 0) +#define VEPU_REG_VP8_LOOP_FILTER_MODE_DELTA 0x0ac +#define VEPU_REG_VP8_LF_MODE_DELTA_SPLITMV(x) (((x) & 0x7f) << 16) +#define VEPU_REG_VP8_LF_MODE_DELTA_ZEROMV(x) (((x) & 0x7f) << 8) +#define VEPU_REG_VP8_LF_MODE_DELTA_NEWMV(x) (((x) & 0x7f) << 0) +#define VEPU_REG_JPEG_LUMA_QUAT(i) (0x000 + ((i) * 0x4)) +#define VEPU_REG_JPEG_CHROMA_QUAT(i) (0x040 + ((i) * 0x4)) +#define VEPU_REG_INTRA_SLICE_BITMAP(i) (0x0b0 + ((i) * 0x4)) +#define VEPU_REG_ADDR_VP8_DCT_PART(i) (0x0b0 + ((i) * 0x4)) +#define VEPU_REG_INTRA_AREA_CTRL 0x0b8 +#define VEPU_REG_INTRA_AREA_TOP(x) (((x) & 0xff) << 24) +#define VEPU_REG_INTRA_AREA_BOTTOM(x) (((x) & 0xff) << 16) +#define VEPU_REG_INTRA_AREA_LEFT(x) (((x) & 0xff) << 8) +#define VEPU_REG_INTRA_AREA_RIGHT(x) (((x) & 0xff) << 0) +#define VEPU_REG_CIR_INTRA_CTRL 0x0bc +#define VEPU_REG_CIR_INTRA_FIRST_MB(x) (((x) & 0xffff) << 16) +#define VEPU_REG_CIR_INTRA_INTERVAL(x) (((x) & 0xffff) << 0) +#define VEPU_REG_ADDR_IN_PLANE_0 0x0c0 +#define VEPU_REG_ADDR_IN_PLANE_1 0x0c4 +#define VEPU_REG_ADDR_IN_PLANE_2 0x0c8 +#define VEPU_REG_STR_HDR_REM_MSB 0x0cc +#define VEPU_REG_STR_HDR_REM_LSB 0x0d0 +#define VEPU_REG_STR_BUF_LIMIT 0x0d4 +#define VEPU_REG_AXI_CTRL 0x0d8 +#define VEPU_REG_AXI_CTRL_READ_ID(x) (((x) & 0xff) << 24) +#define VEPU_REG_AXI_CTRL_WRITE_ID(x) (((x) & 0xff) << 16) +#define VEPU_REG_AXI_CTRL_BURST_LEN(x) (((x) & 0x3f) << 8) +#define VEPU_REG_AXI_CTRL_INCREMENT_MODE(x) (((x) & 0x01) << 2) +#define VEPU_REG_AXI_CTRL_BIRST_DISCARD(x) (((x) & 0x01) << 1) +#define VEPU_REG_AXI_CTRL_BIRST_DISABLE BIT(0) +#define VEPU_QP_ADJUST_MAD_DELTA_ROI 0x0dc +#define VEPU_REG_ROI_QP_DELTA_1 (((x) & 0xf) << 12) +#define VEPU_REG_ROI_QP_DELTA_2 (((x) & 0xf) << 8) +#define VEPU_REG_MAD_QP_ADJUSTMENT (((x) & 0xf) << 0) +#define VEPU_REG_ADDR_REF_LUMA 0x0e0 +#define VEPU_REG_ADDR_REF_CHROMA 0x0e4 +#define VEPU_REG_QP_SUM_DIV2 0x0e8 +#define VEPU_REG_QP_SUM(x) (((x) & 0x001fffff) * 2) +#define VEPU_REG_ENC_CTRL0 0x0ec +#define VEPU_REG_DISABLE_QUARTER_PIXEL_MV BIT(28) +#define VEPU_REG_DEBLOCKING_FILTER_MODE(x) (((x) & 0x3) << 24) +#define VEPU_REG_CABAC_INIT_IDC(x) (((x) & 0x3) << 21) +#define VEPU_REG_ENTROPY_CODING_MODE BIT(20) +#define VEPU_REG_H264_TRANS8X8_MODE BIT(17) +#define VEPU_REG_H264_INTER4X4_MODE BIT(16) +#define VEPU_REG_H264_STREAM_MODE BIT(15) +#define VEPU_REG_H264_SLICE_SIZE(x) (((x) & 0x7f) << 8) +#define VEPU_REG_ENC_OVER_FILL_STRM_OFFSET 0x0f0 +#define VEPU_REG_STREAM_START_OFFSET(x) (((x) & 0x3f) << 16) +#define VEPU_REG_SKIP_MACROBLOCK_PENALTY(x) (((x) & 0xff) << 8) +#define VEPU_REG_IN_IMG_CTRL_OVRFLR_D4(x) (((x) & 0x3) << 4) +#define VEPU_REG_IN_IMG_CTRL_OVRFLB(x) (((x) & 0xf) << 0) +#define VEPU_REG_INPUT_LUMA_INFO 0x0f4 +#define VEPU_REG_IN_IMG_CHROMA_OFFSET(x) (((x) & 0x7) << 20) +#define VEPU_REG_IN_IMG_LUMA_OFFSET(x) (((x) & 0x7) << 16) +#define VEPU_REG_IN_IMG_CTRL_ROW_LEN(x) (((x) & 0x3fff) << 0) +#define VEPU_REG_RLC_SUM 0x0f8 +#define VEPU_REG_RLC_SUM_OUT(x) (((x) & 0x007fffff) * 4) +#define VEPU_REG_SPLIT_PENALTY_4X4 0x0f8 +#define VEPU_REG_VP8_SPLIT_PENALTY_4X4 (((x) & 0x1ff) << 19) +#define VEPU_REG_ADDR_REC_LUMA 0x0fc +#define VEPU_REG_ADDR_REC_CHROMA 0x100 +#define VEPU_REG_CHECKPOINT(i) (0x104 + ((i) * 0x4)) +#define VEPU_REG_CHECKPOINT_CHECK0(x) (((x) & 0xffff)) +#define VEPU_REG_CHECKPOINT_CHECK1(x) (((x) & 0xffff) << 16) +#define VEPU_REG_CHECKPOINT_RESULT(x) \ + ((((x) >> (16 - 16 * ((i) & 1))) & 0xffff) * 32) +#define VEPU_REG_VP8_SEG0_QUANT_AC_Y1 0x104 +#define VEPU_REG_VP8_SEG0_RND_AC_Y1(x) (((x) & 0xff) << 23) +#define VEPU_REG_VP8_SEG0_ZBIN_AC_Y1(x) (((x) & 0x1ff) << 14) +#define VEPU_REG_VP8_SEG0_QUT_AC_Y1(x) (((x) & 0x3fff) << 0) +#define VEPU_REG_VP8_SEG0_QUANT_DC_Y2 0x108 +#define VEPU_REG_VP8_SEG0_RND_DC_Y2(x) (((x) & 0xff) << 23) +#define VEPU_REG_VP8_SEG0_ZBIN_DC_Y2(x) (((x) & 0x1ff) << 14) +#define VEPU_REG_VP8_SEG0_QUT_DC_Y2(x) (((x) & 0x3fff) << 0) +#define VEPU_REG_VP8_SEG0_QUANT_AC_Y2 0x10c +#define VEPU_REG_VP8_SEG0_RND_AC_Y2(x) (((x) & 0xff) << 23) +#define VEPU_REG_VP8_SEG0_ZBIN_AC_Y2(x) (((x) & 0x1ff) << 14) +#define VEPU_REG_VP8_SEG0_QUT_AC_Y2(x) (((x) & 0x3fff) << 0) +#define VEPU_REG_VP8_SEG0_QUANT_DC_CHR 0x110 +#define VEPU_REG_VP8_SEG0_RND_DC_CHR(x) (((x) & 0xff) << 23) +#define VEPU_REG_VP8_SEG0_ZBIN_DC_CHR(x) (((x) & 0x1ff) << 14) +#define VEPU_REG_VP8_SEG0_QUT_DC_CHR(x) (((x) & 0x3fff) << 0) +#define VEPU_REG_VP8_SEG0_QUANT_AC_CHR 0x114 +#define VEPU_REG_VP8_SEG0_RND_AC_CHR(x) (((x) & 0xff) << 23) +#define VEPU_REG_VP8_SEG0_ZBIN_AC_CHR(x) (((x) & 0x1ff) << 14) +#define VEPU_REG_VP8_SEG0_QUT_AC_CHR(x) (((x) & 0x3fff) << 0) +#define VEPU_REG_VP8_SEG0_QUANT_DQUT 0x118 +#define VEPU_REG_VP8_MV_REF_IDX1(x) (((x) & 0x03) << 26) +#define VEPU_REG_VP8_SEG0_DQUT_DC_Y2(x) (((x) & 0x1ff) << 17) +#define VEPU_REG_VP8_SEG0_DQUT_AC_Y1(x) (((x) & 0x1ff) << 8) +#define VEPU_REG_VP8_SEG0_DQUT_DC_Y1(x) (((x) & 0xff) << 0) +#define VEPU_REG_CHKPT_WORD_ERR(i) (0x118 + ((i) * 0x4)) +#define VEPU_REG_CHKPT_WORD_ERR_CHK0(x) (((x) & 0xffff)) +#define VEPU_REG_CHKPT_WORD_ERR_CHK1(x) (((x) & 0xffff) << 16) +#define VEPU_REG_VP8_SEG0_QUANT_DQUT_1 0x11c +#define VEPU_REG_VP8_SEGMENT_MAP_UPDATE BIT(30) +#define VEPU_REG_VP8_SEGMENT_EN BIT(29) +#define VEPU_REG_VP8_MV_REF_IDX2_EN BIT(28) +#define VEPU_REG_VP8_MV_REF_IDX2(x) (((x) & 0x03) << 26) +#define VEPU_REG_VP8_SEG0_DQUT_AC_CHR(x) (((x) & 0x1ff) << 17) +#define VEPU_REG_VP8_SEG0_DQUT_DC_CHR(x) (((x) & 0xff) << 9) +#define VEPU_REG_VP8_SEG0_DQUT_AC_Y2(x) (((x) & 0x1ff) << 0) +#define VEPU_REG_VP8_BOOL_ENC_VALUE 0x120 +#define VEPU_REG_CHKPT_DELTA_QP 0x124 +#define VEPU_REG_CHKPT_DELTA_QP_CHK0(x) (((x) & 0x0f) << 0) +#define VEPU_REG_CHKPT_DELTA_QP_CHK1(x) (((x) & 0x0f) << 4) +#define VEPU_REG_CHKPT_DELTA_QP_CHK2(x) (((x) & 0x0f) << 8) +#define VEPU_REG_CHKPT_DELTA_QP_CHK3(x) (((x) & 0x0f) << 12) +#define VEPU_REG_CHKPT_DELTA_QP_CHK4(x) (((x) & 0x0f) << 16) +#define VEPU_REG_CHKPT_DELTA_QP_CHK5(x) (((x) & 0x0f) << 20) +#define VEPU_REG_CHKPT_DELTA_QP_CHK6(x) (((x) & 0x0f) << 24) +#define VEPU_REG_VP8_ENC_CTRL2 0x124 +#define VEPU_REG_VP8_ZERO_MV_PENALTY_FOR_REF2(x) (((x) & 0xff) << 24) +#define VEPU_REG_VP8_FILTER_SHARPNESS(x) (((x) & 0x07) << 21) +#define VEPU_REG_VP8_FILTER_LEVEL(x) (((x) & 0x3f) << 15) +#define VEPU_REG_VP8_DCT_PARTITION_CNT(x) (((x) & 0x03) << 13) +#define VEPU_REG_VP8_BOOL_ENC_VALUE_BITS(x) (((x) & 0x1f) << 8) +#define VEPU_REG_VP8_BOOL_ENC_RANGE(x) (((x) & 0xff) << 0) +#define VEPU_REG_ENC_CTRL1 0x128 +#define VEPU_REG_MAD_THRESHOLD(x) (((x) & 0x3f) << 24) +#define VEPU_REG_COMPLETED_SLICES(x) (((x) & 0xff) << 16) +#define VEPU_REG_IN_IMG_CTRL_FMT(x) (((x) & 0xf) << 4) +#define VEPU_REG_IN_IMG_ROTATE_MODE(x) (((x) & 0x3) << 2) +#define VEPU_REG_SIZE_TABLE_PRESENT BIT(0) +#define VEPU_REG_INTRA_INTER_MODE 0x12c +#define VEPU_REG_INTRA16X16_MODE(x) (((x) & 0xffff) << 16) +#define VEPU_REG_INTER_MODE(x) (((x) & 0xffff) << 0) +#define VEPU_REG_ENC_CTRL2 0x130 +#define VEPU_REG_PPS_INIT_QP(x) (((x) & 0x3f) << 26) +#define VEPU_REG_SLICE_FILTER_ALPHA(x) (((x) & 0xf) << 22) +#define VEPU_REG_SLICE_FILTER_BETA(x) (((x) & 0xf) << 18) +#define VEPU_REG_CHROMA_QP_OFFSET(x) (((x) & 0x1f) << 13) +#define VEPU_REG_FILTER_DISABLE BIT(5) +#define VEPU_REG_IDR_PIC_ID(x) (((x) & 0xf) << 1) +#define VEPU_REG_CONSTRAINED_INTRA_PREDICTION BIT(0) +#define VEPU_REG_ADDR_OUTPUT_STREAM 0x134 +#define VEPU_REG_ADDR_OUTPUT_CTRL 0x138 +#define VEPU_REG_ADDR_NEXT_PIC 0x13c +#define VEPU_REG_ADDR_MV_OUT 0x140 +#define VEPU_REG_ADDR_CABAC_TBL 0x144 +#define VEPU_REG_ROI1 0x148 +#define VEPU_REG_ROI1_TOP_MB(x) (((x) & 0xff) << 24) +#define VEPU_REG_ROI1_BOTTOM_MB(x) (((x) & 0xff) << 16) +#define VEPU_REG_ROI1_LEFT_MB(x) (((x) & 0xff) << 8) +#define VEPU_REG_ROI1_RIGHT_MB(x) (((x) & 0xff) << 0) +#define VEPU_REG_ROI2 0x14c +#define VEPU_REG_ROI2_TOP_MB(x) (((x) & 0xff) << 24) +#define VEPU_REG_ROI2_BOTTOM_MB(x) (((x) & 0xff) << 16) +#define VEPU_REG_ROI2_LEFT_MB(x) (((x) & 0xff) << 8) +#define VEPU_REG_ROI2_RIGHT_MB(x) (((x) & 0xff) << 0) +#define VEPU_REG_STABLE_MATRIX(i) (0x150 + ((i) * 0x4)) +#define VEPU_REG_STABLE_MOTION_SUM 0x174 +#define VEPU_REG_STABILIZATION_OUTPUT 0x178 +#define VEPU_REG_STABLE_MIN_VALUE(x) (((x) & 0xffffff) << 8) +#define VEPU_REG_STABLE_MODE_SEL(x) (((x) & 0x3) << 6) +#define VEPU_REG_STABLE_HOR_GMV(x) (((x) & 0x3f) << 0) +#define VEPU_REG_RGB2YUV_CONVERSION_COEF1 0x17c +#define VEPU_REG_RGB2YUV_CONVERSION_COEFB(x) (((x) & 0xffff) << 16) +#define VEPU_REG_RGB2YUV_CONVERSION_COEFA(x) (((x) & 0xffff) << 0) +#define VEPU_REG_RGB2YUV_CONVERSION_COEF2 0x180 +#define VEPU_REG_RGB2YUV_CONVERSION_COEFE(x) (((x) & 0xffff) << 16) +#define VEPU_REG_RGB2YUV_CONVERSION_COEFC(x) (((x) & 0xffff) << 0) +#define VEPU_REG_RGB2YUV_CONVERSION_COEF3 0x184 +#define VEPU_REG_RGB2YUV_CONVERSION_COEFF(x) (((x) & 0xffff) << 0) +#define VEPU_REG_RGB_MASK_MSB 0x188 +#define VEPU_REG_RGB_MASK_B_MSB(x) (((x) & 0x1f) << 16) +#define VEPU_REG_RGB_MASK_G_MSB(x) (((x) & 0x1f) << 8) +#define VEPU_REG_RGB_MASK_R_MSB(x) (((x) & 0x1f) << 0) +#define VEPU_REG_MV_PENALTY 0x18c +#define VEPU_REG_1MV_PENALTY(x) (((x) & 0x3ff) << 21) +#define VEPU_REG_QMV_PENALTY(x) (((x) & 0x3ff) << 11) +#define VEPU_REG_4MV_PENALTY(x) (((x) & 0x3ff) << 1) +#define VEPU_REG_SPLIT_MV_MODE_EN BIT(0) +#define VEPU_REG_QP_VAL 0x190 +#define VEPU_REG_H264_LUMA_INIT_QP(x) (((x) & 0x3f) << 26) +#define VEPU_REG_H264_QP_MAX(x) (((x) & 0x3f) << 20) +#define VEPU_REG_H264_QP_MIN(x) (((x) & 0x3f) << 14) +#define VEPU_REG_H264_CHKPT_DISTANCE(x) (((x) & 0xfff) << 0) +#define VEPU_REG_VP8_SEG0_QUANT_DC_Y1 0x190 +#define VEPU_REG_VP8_SEG0_RND_DC_Y1(x) (((x) & 0xff) << 23) +#define VEPU_REG_VP8_SEG0_ZBIN_DC_Y1(x) (((x) & 0x1ff) << 14) +#define VEPU_REG_VP8_SEG0_QUT_DC_Y1(x) (((x) & 0x3fff) << 0) +#define VEPU_REG_MVC_RELATE 0x198 +#define VEPU_REG_ZERO_MV_FAVOR_D2(x) (((x) & 0xf) << 20) +#define VEPU_REG_PENALTY_4X4MV(x) (((x) & 0x1ff) << 11) +#define VEPU_REG_MVC_VIEW_ID(x) (((x) & 0x7) << 8) +#define VEPU_REG_MVC_ANCHOR_PIC_FLAG BIT(7) +#define VEPU_REG_MVC_PRIORITY_ID(x) (((x) & 0x7) << 4) +#define VEPU_REG_MVC_TEMPORAL_ID(x) (((x) & 0x7) << 1) +#define VEPU_REG_MVC_INTER_VIEW_FLAG BIT(0) +#define VEPU_REG_ENCODE_START 0x19c +#define VEPU_REG_MB_HEIGHT(x) (((x) & 0x1ff) << 20) +#define VEPU_REG_MB_WIDTH(x) (((x) & 0x1ff) << 8) +#define VEPU_REG_FRAME_TYPE_INTER (0x0 << 6) +#define VEPU_REG_FRAME_TYPE_INTRA (0x1 << 6) +#define VEPU_REG_FRAME_TYPE_MVCINTER (0x2 << 6) +#define VEPU_REG_ENCODE_FORMAT_JPEG (0x2 << 4) +#define VEPU_REG_ENCODE_FORMAT_H264 (0x3 << 4) +#define VEPU_REG_ENCODE_ENABLE BIT(0) +#define VEPU_REG_MB_CTRL 0x1a0 +#define VEPU_REG_MB_CNT_OUT(x) (((x) & 0xffff) << 16) +#define VEPU_REG_MB_CNT_SET(x) (((x) & 0xffff) << 0) +#define VEPU_REG_DATA_ENDIAN 0x1a4 +#define VEPU_REG_INPUT_SWAP8 BIT(31) +#define VEPU_REG_INPUT_SWAP16 BIT(30) +#define VEPU_REG_INPUT_SWAP32 BIT(29) +#define VEPU_REG_OUTPUT_SWAP8 BIT(28) +#define VEPU_REG_OUTPUT_SWAP16 BIT(27) +#define VEPU_REG_OUTPUT_SWAP32 BIT(26) +#define VEPU_REG_TEST_IRQ BIT(24) +#define VEPU_REG_TEST_COUNTER(x) (((x) & 0xf) << 20) +#define VEPU_REG_TEST_REG BIT(19) +#define VEPU_REG_TEST_MEMORY BIT(18) +#define VEPU_REG_TEST_LEN(x) (((x) & 0x3ffff) << 0) +#define VEPU_REG_ENC_CTRL3 0x1a8 +#define VEPU_REG_PPS_ID(x) (((x) & 0xff) << 24) +#define VEPU_REG_INTRA_PRED_MODE(x) (((x) & 0xff) << 16) +#define VEPU_REG_FRAME_NUM(x) (((x) & 0xffff) << 0) +#define VEPU_REG_ENC_CTRL4 0x1ac +#define VEPU_REG_MV_PENALTY_16X8_8X16(x) (((x) & 0x3ff) << 20) +#define VEPU_REG_MV_PENALTY_8X8(x) (((x) & 0x3ff) << 10) +#define VEPU_REG_MV_PENALTY_8X4_4X8(x) (((x) & 0x3ff) << 0) +#define VEPU_REG_ADDR_VP8_PROB_CNT 0x1b0 +#define VEPU_REG_INTERRUPT 0x1b4 +#define VEPU_REG_INTERRUPT_NON BIT(28) +#define VEPU_REG_MV_WRITE_EN BIT(24) +#define VEPU_REG_RECON_WRITE_DIS BIT(20) +#define VEPU_REG_INTERRUPT_SLICE_READY_EN BIT(16) +#define VEPU_REG_CLK_GATING_EN BIT(12) +#define VEPU_REG_INTERRUPT_TIMEOUT_EN BIT(10) +#define VEPU_REG_INTERRUPT_RESET BIT(9) +#define VEPU_REG_INTERRUPT_DIS_BIT BIT(8) +#define VEPU_REG_INTERRUPT_TIMEOUT BIT(6) +#define VEPU_REG_INTERRUPT_BUFFER_FULL BIT(5) +#define VEPU_REG_INTERRUPT_BUS_ERROR BIT(4) +#define VEPU_REG_INTERRUPT_FUSE BIT(3) +#define VEPU_REG_INTERRUPT_SLICE_READY BIT(2) +#define VEPU_REG_INTERRUPT_FRAME_READY BIT(1) +#define VEPU_REG_INTERRUPT_BIT BIT(0) +#define VEPU_REG_DMV_PENALTY_TBL(i) (0x1E0 + ((i) * 0x4)) +#define VEPU_REG_DMV_PENALTY_TABLE_BIT(x, i) ((x) << (i) * 8) +#define VEPU_REG_DMV_Q_PIXEL_PENALTY_TBL(i) (0x260 + ((i) * 0x4)) +#define VEPU_REG_DMV_Q_PIXEL_PENALTY_TABLE_BIT(x, i) ((x) << (i) * 8) + +/* vpu decoder register */ +#define VDPU_REG_DEC_CTRL0 0x0c8 // 50 +#define VDPU_REG_REF_BUF_CTRL2_REFBU2_PICID(x) (((x) & 0x1f) << 25) +#define VDPU_REG_REF_BUF_CTRL2_REFBU2_THR(x) (((x) & 0xfff) << 13) +#define VDPU_REG_CONFIG_TILED_MODE_LSB BIT(12) +#define VDPU_REG_CONFIG_DEC_ADV_PRE_DIS BIT(11) +#define VDPU_REG_CONFIG_DEC_SCMD_DIS BIT(10) +#define VDPU_REG_DEC_CTRL0_SKIP_MODE BIT(9) +#define VDPU_REG_DEC_CTRL0_FILTERING_DIS BIT(8) +#define VDPU_REG_DEC_CTRL0_PIC_FIXED_QUANT BIT(7) +#define VDPU_REG_CONFIG_DEC_LATENCY(x) (((x) & 0x3f) << 1) +#define VDPU_REG_CONFIG_TILED_MODE_MSB(x) BIT(0) +#define VDPU_REG_CONFIG_DEC_OUT_TILED_E BIT(0) +#define VDPU_REG_STREAM_LEN 0x0cc +#define VDPU_REG_DEC_CTRL3_INIT_QP(x) (((x) & 0x3f) << 25) +#define VDPU_REG_DEC_STREAM_LEN_HI BIT(24) +#define VDPU_REG_DEC_CTRL3_STREAM_LEN(x) (((x) & 0xffffff) << 0) +#define VDPU_REG_ERROR_CONCEALMENT 0x0d0 +#define VDPU_REG_REF_BUF_CTRL2_APF_THRESHOLD(x) (((x) & 0x3fff) << 17) +#define VDPU_REG_ERR_CONC_STARTMB_X(x) (((x) & 0x1ff) << 8) +#define VDPU_REG_ERR_CONC_STARTMB_Y(x) (((x) & 0xff) << 0) +#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_INTERRUPT 0x0dc +#define VDPU_REG_INTERRUPT_DEC_TIMEOUT BIT(13) +#define VDPU_REG_INTERRUPT_DEC_ERROR_INT BIT(12) +#define VDPU_REG_INTERRUPT_DEC_PIC_INF BIT(10) +#define VDPU_REG_INTERRUPT_DEC_SLICE_INT BIT(9) +#define VDPU_REG_INTERRUPT_DEC_ASO_INT BIT(8) +#define VDPU_REG_INTERRUPT_DEC_BUFFER_INT BIT(6) +#define VDPU_REG_INTERRUPT_DEC_BUS_INT BIT(5) +#define VDPU_REG_INTERRUPT_DEC_RDY_INT BIT(4) +#define VDPU_REG_INTERRUPT_DEC_IRQ_DIS BIT(1) +#define VDPU_REG_INTERRUPT_DEC_IRQ BIT(0) +#define VDPU_REG_AXI_CTRL 0x0e0 +#define VDPU_REG_AXI_DEC_SEL BIT(23) +#define VDPU_REG_CONFIG_DEC_DATA_DISC_E BIT(22) +#define VDPU_REG_PARAL_BUS_E(x) BIT(21) +#define VDPU_REG_CONFIG_DEC_MAX_BURST(x) (((x) & 0x1f) << 16) +#define VDPU_REG_DEC_CTRL0_DEC_AXI_WR_ID(x) (((x) & 0xff) << 8) +#define VDPU_REG_CONFIG_DEC_AXI_RD_ID(x) (((x) & 0xff) << 0) +#define VDPU_REG_EN_FLAGS 0x0e4 +#define VDPU_REG_AHB_HLOCK_E BIT(31) +#define VDPU_REG_CACHE_E BIT(29) +#define VDPU_REG_PREFETCH_SINGLE_CHANNEL_E BIT(28) +#define VDPU_REG_INTRA_3_CYCLE_ENHANCE BIT(27) +#define VDPU_REG_INTRA_DOUBLE_SPEED BIT(26) +#define VDPU_REG_INTER_DOUBLE_SPEED BIT(25) +#define VDPU_REG_DEC_CTRL3_START_CODE_E BIT(22) +#define VDPU_REG_DEC_CTRL3_CH_8PIX_ILEAV_E BIT(21) +#define VDPU_REG_DEC_CTRL0_RLC_MODE_E BIT(20) +#define VDPU_REG_DEC_CTRL0_DIVX3_E BIT(19) +#define VDPU_REG_DEC_CTRL0_PJPEG_E BIT(18) +#define VDPU_REG_DEC_CTRL0_PIC_INTERLACE_E BIT(17) +#define VDPU_REG_DEC_CTRL0_PIC_FIELDMODE_E BIT(16) +#define VDPU_REG_DEC_CTRL0_PIC_B_E BIT(15) +#define VDPU_REG_DEC_CTRL0_PIC_INTER_E BIT(14) +#define VDPU_REG_DEC_CTRL0_PIC_TOPFIELD_E BIT(13) +#define VDPU_REG_DEC_CTRL0_FWD_INTERLACE_E BIT(12) +#define VDPU_REG_DEC_CTRL0_SORENSON_E BIT(11) +#define VDPU_REG_DEC_CTRL0_WRITE_MVS_E BIT(10) +#define VDPU_REG_DEC_CTRL0_REF_TOPFIELD_E BIT(9) +#define VDPU_REG_DEC_CTRL0_REFTOPFIRST_E BIT(8) +#define VDPU_REG_DEC_CTRL0_SEQ_MBAFF_E BIT(7) +#define VDPU_REG_DEC_CTRL0_PICORD_COUNT_E BIT(6) +#define VDPU_REG_CONFIG_DEC_TIMEOUT_E BIT(5) +#define VDPU_REG_CONFIG_DEC_CLK_GATE_E BIT(4) +#define VDPU_REG_DEC_CTRL0_DEC_OUT_DIS BIT(2) +#define VDPU_REG_REF_BUF_CTRL2_REFBU2_BUF_E BIT(1) +#define VDPU_REG_INTERRUPT_DEC_E BIT(0) +#define VDPU_REG_SOFT_RESET 0x0e8 +#define VDPU_REG_PRED_FLT 0x0ec +#define VDPU_REG_PRED_FLT_PRED_BC_TAP_0_0(x) (((x) & 0x3ff) << 22) +#define VDPU_REG_PRED_FLT_PRED_BC_TAP_0_1(x) (((x) & 0x3ff) << 12) +#define VDPU_REG_PRED_FLT_PRED_BC_TAP_0_2(x) (((x) & 0x3ff) << 2) +#define VDPU_REG_ADDITIONAL_CHROMA_ADDRESS 0x0f0 +#define VDPU_REG_ADDR_QTABLE 0x0f4 +#define VDPU_REG_DIRECT_MV_ADDR 0x0f8 +#define VDPU_REG_ADDR_DST 0x0fc +#define VDPU_REG_ADDR_STR 0x100 +#define VDPU_REG_REFBUF_RELATED 0x104 +#define VDPU_REG_FWD_PIC(i) (0x128 + ((i) * 0x4)) +#define VDPU_REG_FWD_PIC_PINIT_RLIST_F5(x) (((x) & 0x1f) << 25) +#define VDPU_REG_FWD_PIC_PINIT_RLIST_F4(x) (((x) & 0x1f) << 20) +#define VDPU_REG_FWD_PIC_PINIT_RLIST_F3(x) (((x) & 0x1f) << 15) +#define VDPU_REG_FWD_PIC_PINIT_RLIST_F2(x) (((x) & 0x1f) << 10) +#define VDPU_REG_FWD_PIC_PINIT_RLIST_F1(x) (((x) & 0x1f) << 5) +#define VDPU_REG_FWD_PIC_PINIT_RLIST_F0(x) (((x) & 0x1f) << 0) +#define VDPU_REG_REF_PIC(i) (0x130 + ((i) * 0x4)) +#define VDPU_REG_REF_PIC_REFER1_NBR(x) (((x) & 0xffff) << 16) +#define VDPU_REG_REF_PIC_REFER0_NBR(x) (((x) & 0xffff) << 0) +#define VDPU_REG_H264_ADDR_REF(i) (0x150 + ((i) * 0x4)) +#define VDPU_REG_ADDR_REF_FIELD_E BIT(1) +#define VDPU_REG_ADDR_REF_TOPC_E BIT(0) +#define VDPU_REG_INITIAL_REF_PIC_LIST0 0x190 +#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_F5(x) (((x) & 0x1f) << 25) +#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_F4(x) (((x) & 0x1f) << 20) +#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_F3(x) (((x) & 0x1f) << 15) +#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_F2(x) (((x) & 0x1f) << 10) +#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_F1(x) (((x) & 0x1f) << 5) +#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_F0(x) (((x) & 0x1f) << 0) +#define VDPU_REG_INITIAL_REF_PIC_LIST1 0x194 +#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_F11(x) (((x) & 0x1f) << 25) +#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_F10(x) (((x) & 0x1f) << 20) +#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_F9(x) (((x) & 0x1f) << 15) +#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_F8(x) (((x) & 0x1f) << 10) +#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_F7(x) (((x) & 0x1f) << 5) +#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_F6(x) (((x) & 0x1f) << 0) +#define VDPU_REG_INITIAL_REF_PIC_LIST2 0x198 +#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_F15(x) (((x) & 0x1f) << 15) +#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_F14(x) (((x) & 0x1f) << 10) +#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_F13(x) (((x) & 0x1f) << 5) +#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_F12(x) (((x) & 0x1f) << 0) +#define VDPU_REG_INITIAL_REF_PIC_LIST3 0x19c +#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_B5(x) (((x) & 0x1f) << 25) +#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_B4(x) (((x) & 0x1f) << 20) +#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_B3(x) (((x) & 0x1f) << 15) +#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_B2(x) (((x) & 0x1f) << 10) +#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_B1(x) (((x) & 0x1f) << 5) +#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_B0(x) (((x) & 0x1f) << 0) +#define VDPU_REG_INITIAL_REF_PIC_LIST4 0x1a0 +#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_B11(x) (((x) & 0x1f) << 25) +#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_B10(x) (((x) & 0x1f) << 20) +#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_B9(x) (((x) & 0x1f) << 15) +#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_B8(x) (((x) & 0x1f) << 10) +#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_B7(x) (((x) & 0x1f) << 5) +#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_B6(x) (((x) & 0x1f) << 0) +#define VDPU_REG_INITIAL_REF_PIC_LIST5 0x1a4 +#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_B15(x) (((x) & 0x1f) << 15) +#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_B14(x) (((x) & 0x1f) << 10) +#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_B13(x) (((x) & 0x1f) << 5) +#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_B12(x) (((x) & 0x1f) << 0) +#define VDPU_REG_INITIAL_REF_PIC_LIST6 0x1a8 +#define VDPU_REG_BD_P_REF_PIC_PINIT_RLIST_F3(x) (((x) & 0x1f) << 15) +#define VDPU_REG_BD_P_REF_PIC_PINIT_RLIST_F2(x) (((x) & 0x1f) << 10) +#define VDPU_REG_BD_P_REF_PIC_PINIT_RLIST_F1(x) (((x) & 0x1f) << 5) +#define VDPU_REG_BD_P_REF_PIC_PINIT_RLIST_F0(x) (((x) & 0x1f) << 0) +#define VDPU_REG_LT_REF 0x1ac +#define VDPU_REG_VALID_REF 0x1b0 +#define VDPU_REG_H264_PIC_MB_SIZE 0x1b8 +#define VDPU_REG_DEC_CTRL2_CH_QP_OFFSET2(x) (((x) & 0x1f) << 22) +#define VDPU_REG_DEC_CTRL2_CH_QP_OFFSET(x) (((x) & 0x1f) << 17) +#define VDPU_REG_DEC_CTRL1_PIC_MB_HEIGHT_P(x) (((x) & 0xff) << 9) +#define VDPU_REG_DEC_CTRL1_PIC_MB_WIDTH(x) (((x) & 0x1ff) << 0) +#define VDPU_REG_H264_CTRL 0x1bc +#define VDPU_REG_DEC_CTRL4_WEIGHT_BIPR_IDC(x) (((x) & 0x3) << 16) +#define VDPU_REG_DEC_CTRL1_REF_FRAMES(x) (((x) & 0x1f) << 0) +#define VDPU_REG_CURRENT_FRAME 0x1c0 +#define VDPU_REG_DEC_CTRL5_FILT_CTRL_PRES BIT(31) +#define VDPU_REG_DEC_CTRL5_RDPIC_CNT_PRES BIT(30) +#define VDPU_REG_DEC_CTRL4_FRAMENUM_LEN(x) (((x) & 0x1f) << 16) +#define VDPU_REG_DEC_CTRL4_FRAMENUM(x) (((x) & 0xffff) << 0) +#define VDPU_REG_REF_FRAME 0x1c4 +#define VDPU_REG_DEC_CTRL5_REFPIC_MK_LEN(x) (((x) & 0x7ff) << 16) +#define VDPU_REG_DEC_CTRL5_IDR_PIC_ID(x) (((x) & 0xffff) << 0) +#define VDPU_REG_DEC_CTRL6 0x1c8 +#define VDPU_REG_DEC_CTRL6_PPS_ID(x) (((x) & 0xff) << 24) +#define VDPU_REG_DEC_CTRL6_REFIDX1_ACTIVE(x) (((x) & 0x1f) << 19) +#define VDPU_REG_DEC_CTRL6_REFIDX0_ACTIVE(x) (((x) & 0x1f) << 14) +#define VDPU_REG_DEC_CTRL6_POC_LENGTH(x) (((x) & 0xff) << 0) +#define VDPU_REG_ENABLE_FLAG 0x1cc +#define VDPU_REG_DEC_CTRL5_IDR_PIC_E BIT(8) +#define VDPU_REG_DEC_CTRL4_DIR_8X8_INFER_E BIT(7) +#define VDPU_REG_DEC_CTRL4_BLACKWHITE_E BIT(6) +#define VDPU_REG_DEC_CTRL4_CABAC_E BIT(5) +#define VDPU_REG_DEC_CTRL4_WEIGHT_PRED_E BIT(4) +#define VDPU_REG_DEC_CTRL5_CONST_INTRA_E BIT(3) +#define VDPU_REG_DEC_CTRL5_8X8TRANS_FLAG_E BIT(2) +#define VDPU_REG_DEC_CTRL2_TYPE1_QUANT_E BIT(1) +#define VDPU_REG_DEC_CTRL2_FIELDPIC_FLAG_E BIT(0) +#define VDPU_REG_VP8_PIC_MB_SIZE 0x1e0 +#define VDPU_REG_DEC_PIC_MB_WIDTH(x) (((x) & 0x1ff) << 23) +#define VDPU_REG_DEC_MB_WIDTH_OFF(x) (((x) & 0xf) << 19) +#define VDPU_REG_DEC_PIC_MB_HEIGHT_P(x) (((x) & 0xff) << 11) +#define VDPU_REG_DEC_MB_HEIGHT_OFF(x) (((x) & 0xf) << 7) +#define VDPU_REG_DEC_CTRL1_PIC_MB_W_EXT(x) (((x) & 0x7) << 3) +#define VDPU_REG_DEC_CTRL1_PIC_MB_H_EXT(x) (((x) & 0x7) << 0) +#define VDPU_REG_VP8_DCT_START_BIT 0x1e4 +#define VDPU_REG_DEC_CTRL4_DCT1_START_BIT(x) (((x) & 0x3f) << 26) +#define VDPU_REG_DEC_CTRL4_DCT2_START_BIT(x) (((x) & 0x3f) << 20) +#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_DEC_CTRL2_STRM_START_BIT(x) (((x) & 0x3f) << 26) +#define VDPU_REG_DEC_CTRL2_STRM1_START_BIT(x) (((x) & 0x3f) << 18) +#define VDPU_REG_DEC_CTRL2_BOOLEAN_VALUE(x) (((x) & 0xff) << 8) +#define VDPU_REG_DEC_CTRL2_BOOLEAN_RANGE(x) (((x) & 0xff) << 0) +#define VDPU_REG_VP8_DATA_VAL 0x1f0 +#define VDPU_REG_DEC_CTRL6_COEFFS_PART_AM(x) (((x) & 0xf) << 24) +#define VDPU_REG_DEC_CTRL6_STREAM1_LEN(x) (((x) & 0xffffff) << 0) +#define VDPU_REG_PRED_FLT7 0x1f4 +#define VDPU_REG_PRED_FLT_PRED_BC_TAP_5_1(x) (((x) & 0x3ff) << 22) +#define VDPU_REG_PRED_FLT_PRED_BC_TAP_5_2(x) (((x) & 0x3ff) << 12) +#define VDPU_REG_PRED_FLT_PRED_BC_TAP_5_3(x) (((x) & 0x3ff) << 2) +#define VDPU_REG_PRED_FLT8 0x1f8 +#define VDPU_REG_PRED_FLT_PRED_BC_TAP_6_0(x) (((x) & 0x3ff) << 22) +#define VDPU_REG_PRED_FLT_PRED_BC_TAP_6_1(x) (((x) & 0x3ff) << 12) +#define VDPU_REG_PRED_FLT_PRED_BC_TAP_6_2(x) (((x) & 0x3ff) << 2) +#define VDPU_REG_PRED_FLT9 0x1fc +#define VDPU_REG_PRED_FLT_PRED_BC_TAP_6_3(x) (((x) & 0x3ff) << 22) +#define VDPU_REG_PRED_FLT_PRED_BC_TAP_7_0(x) (((x) & 0x3ff) << 12) +#define VDPU_REG_PRED_FLT_PRED_BC_TAP_7_1(x) (((x) & 0x3ff) << 2) +#define VDPU_REG_PRED_FLT10 0x200 +#define VDPU_REG_PRED_FLT_PRED_BC_TAP_7_2(x) (((x) & 0x3ff) << 22) +#define VDPU_REG_PRED_FLT_PRED_BC_TAP_7_3(x) (((x) & 0x3ff) << 12) +#define VDPU_REG_BD_REF_PIC_PRED_TAP_2_M1(x) (((x) & 0x3) << 10) +#define VDPU_REG_BD_REF_PIC_PRED_TAP_2_4(x) (((x) & 0x3) << 8) +#define VDPU_REG_BD_REF_PIC_PRED_TAP_4_M1(x) (((x) & 0x3) << 6) +#define VDPU_REG_BD_REF_PIC_PRED_TAP_4_4(x) (((x) & 0x3) << 4) +#define VDPU_REG_BD_REF_PIC_PRED_TAP_6_M1(x) (((x) & 0x3) << 2) +#define VDPU_REG_BD_REF_PIC_PRED_TAP_6_4(x) (((x) & 0x3) << 0) +#define VDPU_REG_FILTER_LEVEL 0x204 +#define VDPU_REG_REF_PIC_LF_LEVEL_0(x) (((x) & 0x3f) << 18) +#define VDPU_REG_REF_PIC_LF_LEVEL_1(x) (((x) & 0x3f) << 12) +#define VDPU_REG_REF_PIC_LF_LEVEL_2(x) (((x) & 0x3f) << 6) +#define VDPU_REG_REF_PIC_LF_LEVEL_3(x) (((x) & 0x3f) << 0) +#define VDPU_REG_VP8_QUANTER0 0x208 +#define VDPU_REG_REF_PIC_QUANT_DELTA_0(x) (((x) & 0x1f) << 27) +#define VDPU_REG_REF_PIC_QUANT_DELTA_1(x) (((x) & 0x1f) << 22) +#define VDPU_REG_REF_PIC_QUANT_0(x) (((x) & 0x7ff) << 11) +#define VDPU_REG_REF_PIC_QUANT_1(x) (((x) & 0x7ff) << 0) +#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_FILT_MB_ADJ_0(x) (((x) & 0x7f) << 21) +#define VDPU_REG_FILT_MB_ADJ_1(x) (((x) & 0x7f) << 14) +#define VDPU_REG_FILT_MB_ADJ_2(x) (((x) & 0x7f) << 7) +#define VDPU_REG_FILT_MB_ADJ_3(x) (((x) & 0x7f) << 0) +#define VDPU_REG_FILTER_REF_ADJ 0x214 +#define VDPU_REG_REF_PIC_ADJ_0(x) (((x) & 0x7f) << 21) +#define VDPU_REG_REF_PIC_ADJ_1(x) (((x) & 0x7f) << 14) +#define VDPU_REG_REF_PIC_ADJ_2(x) (((x) & 0x7f) << 7) +#define VDPU_REG_REF_PIC_ADJ_3(x) (((x) & 0x7f) << 0) +#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) * 0x4)) +#define VDPU_REG_VP8_ADDR_CTRL_PART 0x244 +#define VDPU_REG_VP8_ADDR_REF1 0x250 +#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_DEC_CTRL7_DCT3_START_BIT(x) (((x) & 0x3f) << 24) +#define VDPU_REG_DEC_CTRL7_DCT4_START_BIT(x) (((x) & 0x3f) << 18) +#define VDPU_REG_DEC_CTRL7_DCT5_START_BIT(x) (((x) & 0x3f) << 12) +#define VDPU_REG_DEC_CTRL7_DCT6_START_BIT(x) (((x) & 0x3f) << 6) +#define VDPU_REG_DEC_CTRL7_DCT7_START_BIT(x) (((x) & 0x3f) << 0) +#define VDPU_REG_VP8_QUANTER1 0x25c +#define VDPU_REG_REF_PIC_QUANT_DELTA_2(x) (((x) & 0x1f) << 27) +#define VDPU_REG_REF_PIC_QUANT_DELTA_3(x) (((x) & 0x1f) << 22) +#define VDPU_REG_REF_PIC_QUANT_2(x) (((x) & 0x7ff) << 11) +#define VDPU_REG_REF_PIC_QUANT_3(x) (((x) & 0x7ff) << 0) +#define VDPU_REG_VP8_QUANTER2 0x260 +#define VDPU_REG_REF_PIC_QUANT_DELTA_4(x) (((x) & 0x1f) << 27) +#define VDPU_REG_REF_PIC_QUANT_4(x) (((x) & 0x7ff) << 11) +#define VDPU_REG_REF_PIC_QUANT_5(x) (((x) & 0x7ff) << 0) +#define VDPU_REG_PRED_FLT1 0x264 +#define VDPU_REG_PRED_FLT_PRED_BC_TAP_0_3(x) (((x) & 0x3ff) << 22) +#define VDPU_REG_PRED_FLT_PRED_BC_TAP_1_0(x) (((x) & 0x3ff) << 12) +#define VDPU_REG_PRED_FLT_PRED_BC_TAP_1_1(x) (((x) & 0x3ff) << 2) +#define VDPU_REG_PRED_FLT2 0x268 +#define VDPU_REG_PRED_FLT_PRED_BC_TAP_1_2(x) (((x) & 0x3ff) << 22) +#define VDPU_REG_PRED_FLT_PRED_BC_TAP_1_3(x) (((x) & 0x3ff) << 12) +#define VDPU_REG_PRED_FLT_PRED_BC_TAP_2_0(x) (((x) & 0x3ff) << 2) +#define VDPU_REG_PRED_FLT3 0x26c +#define VDPU_REG_PRED_FLT_PRED_BC_TAP_2_1(x) (((x) & 0x3ff) << 22) +#define VDPU_REG_PRED_FLT_PRED_BC_TAP_2_2(x) (((x) & 0x3ff) << 12) +#define VDPU_REG_PRED_FLT_PRED_BC_TAP_2_3(x) (((x) & 0x3ff) << 2) +#define VDPU_REG_PRED_FLT4 0x270 +#define VDPU_REG_PRED_FLT_PRED_BC_TAP_3_0(x) (((x) & 0x3ff) << 22) +#define VDPU_REG_PRED_FLT_PRED_BC_TAP_3_1(x) (((x) & 0x3ff) << 12) +#define VDPU_REG_PRED_FLT_PRED_BC_TAP_3_2(x) (((x) & 0x3ff) << 2) +#define VDPU_REG_PRED_FLT5 0x274 +#define VDPU_REG_PRED_FLT_PRED_BC_TAP_3_3(x) (((x) & 0x3ff) << 22) +#define VDPU_REG_PRED_FLT_PRED_BC_TAP_4_0(x) (((x) & 0x3ff) << 12) +#define VDPU_REG_PRED_FLT_PRED_BC_TAP_4_1(x) (((x) & 0x3ff) << 2) +#define VDPU_REG_PRED_FLT6 0x278 +#define VDPU_REG_PRED_FLT_PRED_BC_TAP_4_2(x) (((x) & 0x3ff) << 22) +#define VDPU_REG_PRED_FLT_PRED_BC_TAP_4_3(x) (((x) & 0x3ff) << 12) +#define VDPU_REG_PRED_FLT_PRED_BC_TAP_5_0(x) (((x) & 0x3ff) << 2) + +#endif /* RK3399_VPU_REGS_H_ */ diff --git a/drivers/staging/media/rockchip/vpu/Kconfig b/drivers/staging/media/rockchip/vpu/Kconfig deleted file mode 100644 index 842b003e08b8..000000000000 --- a/drivers/staging/media/rockchip/vpu/Kconfig +++ /dev/null @@ -1,14 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -config VIDEO_ROCKCHIP_VPU - tristate "Rockchip VPU driver" - depends on ARCH_ROCKCHIP || COMPILE_TEST - depends on VIDEO_DEV && VIDEO_V4L2 && MEDIA_CONTROLLER - depends on MEDIA_CONTROLLER_REQUEST_API - select VIDEOBUF2_DMA_CONTIG - select VIDEOBUF2_VMALLOC - select V4L2_MEM2MEM_DEV - help - Support for the Video Processing Unit present on Rockchip SoC, - which accelerates video and image encoding and decoding. - To compile this driver as a module, choose M here: the module - will be called rockchip-vpu. diff --git a/drivers/staging/media/rockchip/vpu/Makefile b/drivers/staging/media/rockchip/vpu/Makefile deleted file mode 100644 index be278157d196..000000000000 --- a/drivers/staging/media/rockchip/vpu/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_VIDEO_ROCKCHIP_VPU) += rockchip-vpu.o - -rockchip-vpu-y += \ - rockchip_vpu_drv.o \ - rockchip_vpu_v4l2.o \ - rk3288_vpu_hw.o \ - rk3288_vpu_hw_jpeg_enc.o \ - rk3288_vpu_hw_mpeg2_dec.o \ - rk3399_vpu_hw.o \ - rk3399_vpu_hw_jpeg_enc.o \ - rk3399_vpu_hw_mpeg2_dec.o \ - rockchip_vpu_jpeg.o \ - rockchip_vpu_mpeg2.o diff --git a/drivers/staging/media/rockchip/vpu/TODO b/drivers/staging/media/rockchip/vpu/TODO deleted file mode 100644 index fa0c94057007..000000000000 --- a/drivers/staging/media/rockchip/vpu/TODO +++ /dev/null @@ -1,13 +0,0 @@ -* Support for VP8, VP9 and H264 is planned for this driver. - - Given the V4L controls for those CODECs will be part of - the uABI, it will be required to have the driver in staging. - - For this reason, we are keeping this driver in staging for now. - -* Add support for the S_SELECTION API. - See the comment for VEPU_REG_ENC_OVER_FILL_STRM_OFFSET. - -* Instead of having a DMA bounce buffer, it could be possible to use a - normal buffer and memmove() the payload to make space for the header. - This might need to use extra JPEG markers for padding reasons. diff --git a/drivers/staging/media/rockchip/vpu/rk3288_vpu_hw.c b/drivers/staging/media/rockchip/vpu/rk3288_vpu_hw.c deleted file mode 100644 index 003143c77d37..000000000000 --- a/drivers/staging/media/rockchip/vpu/rk3288_vpu_hw.c +++ /dev/null @@ -1,177 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Rockchip VPU codec driver - * - * Copyright (C) 2018 Rockchip Electronics Co., Ltd. - * Jeffy Chen - */ - -#include - -#include "rockchip_vpu.h" -#include "rockchip_vpu_jpeg.h" -#include "rk3288_vpu_regs.h" - -#define RK3288_ACLK_MAX_FREQ (400 * 1000 * 1000) - -/* - * Supported formats. - */ - -static const struct rockchip_vpu_fmt rk3288_vpu_enc_fmts[] = { - { - .fourcc = V4L2_PIX_FMT_YUV420M, - .codec_mode = RK_VPU_MODE_NONE, - .enc_fmt = RK3288_VPU_ENC_FMT_YUV420P, - }, - { - .fourcc = V4L2_PIX_FMT_NV12M, - .codec_mode = RK_VPU_MODE_NONE, - .enc_fmt = RK3288_VPU_ENC_FMT_YUV420SP, - }, - { - .fourcc = V4L2_PIX_FMT_YUYV, - .codec_mode = RK_VPU_MODE_NONE, - .enc_fmt = RK3288_VPU_ENC_FMT_YUYV422, - }, - { - .fourcc = V4L2_PIX_FMT_UYVY, - .codec_mode = RK_VPU_MODE_NONE, - .enc_fmt = RK3288_VPU_ENC_FMT_UYVY422, - }, - { - .fourcc = V4L2_PIX_FMT_JPEG, - .codec_mode = RK_VPU_MODE_JPEG_ENC, - .max_depth = 2, - .header_size = JPEG_HEADER_SIZE, - .frmsize = { - .min_width = 96, - .max_width = 8192, - .step_width = JPEG_MB_DIM, - .min_height = 32, - .max_height = 8192, - .step_height = JPEG_MB_DIM, - }, - }, -}; - -static const struct rockchip_vpu_fmt rk3288_vpu_dec_fmts[] = { - { - .fourcc = V4L2_PIX_FMT_NV12, - .codec_mode = RK_VPU_MODE_NONE, - }, - { - .fourcc = V4L2_PIX_FMT_MPEG2_SLICE, - .codec_mode = RK_VPU_MODE_MPEG2_DEC, - .max_depth = 2, - .frmsize = { - .min_width = 48, - .max_width = 1920, - .step_width = MPEG2_MB_DIM, - .min_height = 48, - .max_height = 1088, - .step_height = MPEG2_MB_DIM, - }, - }, -}; - -static irqreturn_t rk3288_vepu_irq(int irq, void *dev_id) -{ - struct rockchip_vpu_dev *vpu = dev_id; - enum vb2_buffer_state state; - u32 status, bytesused; - - status = vepu_read(vpu, VEPU_REG_INTERRUPT); - bytesused = vepu_read(vpu, VEPU_REG_STR_BUF_LIMIT) / 8; - state = (status & VEPU_REG_INTERRUPT_FRAME_RDY) ? - VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR; - - vepu_write(vpu, 0, VEPU_REG_INTERRUPT); - vepu_write(vpu, 0, VEPU_REG_AXI_CTRL); - - rockchip_vpu_irq_done(vpu, bytesused, state); - - return IRQ_HANDLED; -} - -static irqreturn_t rk3288_vdpu_irq(int irq, void *dev_id) -{ - struct rockchip_vpu_dev *vpu = dev_id; - enum vb2_buffer_state state; - u32 status; - - status = vdpu_read(vpu, VDPU_REG_INTERRUPT); - state = (status & VDPU_REG_INTERRUPT_DEC_RDY_INT) ? - VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR; - - vdpu_write(vpu, 0, VDPU_REG_INTERRUPT); - vdpu_write(vpu, VDPU_REG_CONFIG_DEC_CLK_GATE_E, VDPU_REG_CONFIG); - - rockchip_vpu_irq_done(vpu, 0, state); - - return IRQ_HANDLED; -} - -static int rk3288_vpu_hw_init(struct rockchip_vpu_dev *vpu) -{ - /* Bump ACLK to max. possible freq. to improve performance. */ - clk_set_rate(vpu->clocks[0].clk, RK3288_ACLK_MAX_FREQ); - return 0; -} - -static void rk3288_vpu_enc_reset(struct rockchip_vpu_ctx *ctx) -{ - struct rockchip_vpu_dev *vpu = ctx->dev; - - vepu_write(vpu, VEPU_REG_INTERRUPT_DIS_BIT, VEPU_REG_INTERRUPT); - vepu_write(vpu, 0, VEPU_REG_ENC_CTRL); - vepu_write(vpu, 0, VEPU_REG_AXI_CTRL); -} - -static void rk3288_vpu_dec_reset(struct rockchip_vpu_ctx *ctx) -{ - struct rockchip_vpu_dev *vpu = ctx->dev; - - vdpu_write(vpu, VDPU_REG_INTERRUPT_DEC_IRQ_DIS, VDPU_REG_INTERRUPT); - vdpu_write(vpu, VDPU_REG_CONFIG_DEC_CLK_GATE_E, VDPU_REG_CONFIG); - vdpu_write(vpu, 1, VDPU_REG_SOFT_RESET); -} - -/* - * Supported codec ops. - */ - -static const struct rockchip_vpu_codec_ops rk3288_vpu_codec_ops[] = { - [RK_VPU_MODE_JPEG_ENC] = { - .run = rk3288_vpu_jpeg_enc_run, - .reset = rk3288_vpu_enc_reset, - .init = rockchip_vpu_jpeg_enc_init, - .exit = rockchip_vpu_jpeg_enc_exit, - }, - [RK_VPU_MODE_MPEG2_DEC] = { - .run = rk3288_vpu_mpeg2_dec_run, - .reset = rk3288_vpu_dec_reset, - .init = rockchip_vpu_mpeg2_dec_init, - .exit = rockchip_vpu_mpeg2_dec_exit, - }, -}; - -/* - * VPU variant. - */ - -const struct rockchip_vpu_variant rk3288_vpu_variant = { - .enc_offset = 0x0, - .enc_fmts = rk3288_vpu_enc_fmts, - .num_enc_fmts = ARRAY_SIZE(rk3288_vpu_enc_fmts), - .dec_offset = 0x400, - .dec_fmts = rk3288_vpu_dec_fmts, - .num_dec_fmts = ARRAY_SIZE(rk3288_vpu_dec_fmts), - .codec = RK_VPU_JPEG_ENCODER | RK_VPU_MPEG2_DECODER, - .codec_ops = rk3288_vpu_codec_ops, - .vepu_irq = rk3288_vepu_irq, - .vdpu_irq = rk3288_vdpu_irq, - .init = rk3288_vpu_hw_init, - .clk_names = {"aclk", "hclk"}, - .num_clocks = 2 -}; diff --git a/drivers/staging/media/rockchip/vpu/rk3288_vpu_hw_jpeg_enc.c b/drivers/staging/media/rockchip/vpu/rk3288_vpu_hw_jpeg_enc.c deleted file mode 100644 index 68176e91330a..000000000000 --- a/drivers/staging/media/rockchip/vpu/rk3288_vpu_hw_jpeg_enc.c +++ /dev/null @@ -1,125 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Rockchip VPU codec driver - * - * Copyright (C) 2018 Rockchip Electronics Co., Ltd. - */ - -#include -#include -#include "rockchip_vpu_jpeg.h" -#include "rockchip_vpu.h" -#include "rockchip_vpu_v4l2.h" -#include "rockchip_vpu_hw.h" -#include "rk3288_vpu_regs.h" - -#define VEPU_JPEG_QUANT_TABLE_COUNT 16 - -static void rk3288_vpu_set_src_img_ctrl(struct rockchip_vpu_dev *vpu, - struct rockchip_vpu_ctx *ctx) -{ - struct v4l2_pix_format_mplane *pix_fmt = &ctx->src_fmt; - u32 reg; - - reg = VEPU_REG_IN_IMG_CTRL_ROW_LEN(pix_fmt->width) - | VEPU_REG_IN_IMG_CTRL_OVRFLR_D4(0) - | VEPU_REG_IN_IMG_CTRL_OVRFLB_D4(0) - | VEPU_REG_IN_IMG_CTRL_FMT(ctx->vpu_src_fmt->enc_fmt); - vepu_write_relaxed(vpu, reg, VEPU_REG_IN_IMG_CTRL); -} - -static void rk3288_vpu_jpeg_enc_set_buffers(struct rockchip_vpu_dev *vpu, - struct rockchip_vpu_ctx *ctx, - struct vb2_buffer *src_buf) -{ - struct v4l2_pix_format_mplane *pix_fmt = &ctx->src_fmt; - dma_addr_t src[3]; - - WARN_ON(pix_fmt->num_planes > 3); - - vepu_write_relaxed(vpu, ctx->jpeg_enc.bounce_buffer.dma, - VEPU_REG_ADDR_OUTPUT_STREAM); - vepu_write_relaxed(vpu, ctx->jpeg_enc.bounce_buffer.size, - VEPU_REG_STR_BUF_LIMIT); - - if (pix_fmt->num_planes == 1) { - src[0] = vb2_dma_contig_plane_dma_addr(src_buf, 0); - /* single plane formats we supported are all interlaced */ - vepu_write_relaxed(vpu, src[0], VEPU_REG_ADDR_IN_PLANE_0); - } else if (pix_fmt->num_planes == 2) { - src[0] = vb2_dma_contig_plane_dma_addr(src_buf, 0); - src[1] = vb2_dma_contig_plane_dma_addr(src_buf, 1); - vepu_write_relaxed(vpu, src[0], VEPU_REG_ADDR_IN_PLANE_0); - vepu_write_relaxed(vpu, src[1], VEPU_REG_ADDR_IN_PLANE_1); - } else { - src[0] = vb2_dma_contig_plane_dma_addr(src_buf, 0); - src[1] = vb2_dma_contig_plane_dma_addr(src_buf, 1); - src[2] = vb2_dma_contig_plane_dma_addr(src_buf, 2); - vepu_write_relaxed(vpu, src[0], VEPU_REG_ADDR_IN_PLANE_0); - vepu_write_relaxed(vpu, src[1], VEPU_REG_ADDR_IN_PLANE_1); - vepu_write_relaxed(vpu, src[2], VEPU_REG_ADDR_IN_PLANE_2); - } -} - -static void -rk3288_vpu_jpeg_enc_set_qtable(struct rockchip_vpu_dev *vpu, - unsigned char *luma_qtable, - unsigned char *chroma_qtable) -{ - u32 reg, i; - - for (i = 0; i < VEPU_JPEG_QUANT_TABLE_COUNT; i++) { - reg = get_unaligned_be32(&luma_qtable[i]); - vepu_write_relaxed(vpu, reg, VEPU_REG_JPEG_LUMA_QUAT(i)); - - reg = get_unaligned_be32(&chroma_qtable[i]); - vepu_write_relaxed(vpu, reg, VEPU_REG_JPEG_CHROMA_QUAT(i)); - } -} - -void rk3288_vpu_jpeg_enc_run(struct rockchip_vpu_ctx *ctx) -{ - struct rockchip_vpu_dev *vpu = ctx->dev; - struct vb2_v4l2_buffer *src_buf, *dst_buf; - struct rockchip_vpu_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); - - 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; - jpeg_ctx.height = ctx->dst_fmt.height; - jpeg_ctx.quality = ctx->jpeg_quality; - rockchip_vpu_jpeg_header_assemble(&jpeg_ctx); - - /* Switch to JPEG encoder mode before writing registers */ - vepu_write_relaxed(vpu, VEPU_REG_ENC_CTRL_ENC_MODE_JPEG, - VEPU_REG_ENC_CTRL); - - rk3288_vpu_set_src_img_ctrl(vpu, ctx); - rk3288_vpu_jpeg_enc_set_buffers(vpu, ctx, &src_buf->vb2_buf); - rk3288_vpu_jpeg_enc_set_qtable(vpu, - rockchip_vpu_jpeg_get_qtable(&jpeg_ctx, 0), - rockchip_vpu_jpeg_get_qtable(&jpeg_ctx, 1)); - - reg = VEPU_REG_AXI_CTRL_OUTPUT_SWAP16 - | VEPU_REG_AXI_CTRL_INPUT_SWAP16 - | VEPU_REG_AXI_CTRL_BURST_LEN(16) - | VEPU_REG_AXI_CTRL_OUTPUT_SWAP32 - | VEPU_REG_AXI_CTRL_INPUT_SWAP32 - | VEPU_REG_AXI_CTRL_OUTPUT_SWAP8 - | VEPU_REG_AXI_CTRL_INPUT_SWAP8; - /* Make sure that all registers are written at this point. */ - vepu_write(vpu, reg, VEPU_REG_AXI_CTRL); - - reg = VEPU_REG_ENC_CTRL_WIDTH(JPEG_MB_WIDTH(ctx->src_fmt.width)) - | VEPU_REG_ENC_CTRL_HEIGHT(JPEG_MB_HEIGHT(ctx->src_fmt.height)) - | VEPU_REG_ENC_CTRL_ENC_MODE_JPEG - | VEPU_REG_ENC_PIC_INTRA - | VEPU_REG_ENC_CTRL_EN_BIT; - /* Kick the watchdog and start encoding */ - schedule_delayed_work(&vpu->watchdog_work, msecs_to_jiffies(2000)); - vepu_write(vpu, reg, VEPU_REG_ENC_CTRL); -} diff --git a/drivers/staging/media/rockchip/vpu/rk3288_vpu_hw_mpeg2_dec.c b/drivers/staging/media/rockchip/vpu/rk3288_vpu_hw_mpeg2_dec.c deleted file mode 100644 index e9eee47fcea1..000000000000 --- a/drivers/staging/media/rockchip/vpu/rk3288_vpu_hw_mpeg2_dec.c +++ /dev/null @@ -1,261 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Rockchip VPU codec driver - * - * Copyright (C) 2018 Rockchip Electronics Co., Ltd. - */ - -#include -#include -#include -#include "rockchip_vpu.h" -#include "rockchip_vpu_hw.h" - -#define VDPU_SWREG(nr) ((nr) * 4) - -#define VDPU_REG_RLC_VLC_BASE VDPU_SWREG(12) -#define VDPU_REG_DEC_OUT_BASE VDPU_SWREG(13) -#define VDPU_REG_REFER0_BASE VDPU_SWREG(14) -#define VDPU_REG_REFER1_BASE VDPU_SWREG(15) -#define VDPU_REG_REFER2_BASE VDPU_SWREG(16) -#define VDPU_REG_REFER3_BASE VDPU_SWREG(17) -#define VDPU_REG_QTABLE_BASE VDPU_SWREG(40) -#define VDPU_REG_DEC_E(v) ((v) ? BIT(0) : 0) - -#define VDPU_REG_DEC_AXI_RD_ID(v) (((v) << 24) & GENMASK(31, 24)) -#define VDPU_REG_DEC_TIMEOUT_E(v) ((v) ? BIT(23) : 0) -#define VDPU_REG_DEC_STRSWAP32_E(v) ((v) ? BIT(22) : 0) -#define VDPU_REG_DEC_STRENDIAN_E(v) ((v) ? BIT(21) : 0) -#define VDPU_REG_DEC_INSWAP32_E(v) ((v) ? BIT(20) : 0) -#define VDPU_REG_DEC_OUTSWAP32_E(v) ((v) ? BIT(19) : 0) -#define VDPU_REG_DEC_DATA_DISC_E(v) ((v) ? BIT(18) : 0) -#define VDPU_REG_DEC_LATENCY(v) (((v) << 11) & GENMASK(16, 11)) -#define VDPU_REG_DEC_CLK_GATE_E(v) ((v) ? BIT(10) : 0) -#define VDPU_REG_DEC_IN_ENDIAN(v) ((v) ? BIT(9) : 0) -#define VDPU_REG_DEC_OUT_ENDIAN(v) ((v) ? BIT(8) : 0) -#define VDPU_REG_DEC_ADV_PRE_DIS(v) ((v) ? BIT(6) : 0) -#define VDPU_REG_DEC_SCMD_DIS(v) ((v) ? BIT(5) : 0) -#define VDPU_REG_DEC_MAX_BURST(v) (((v) << 0) & GENMASK(4, 0)) - -#define VDPU_REG_DEC_MODE(v) (((v) << 28) & GENMASK(31, 28)) -#define VDPU_REG_RLC_MODE_E(v) ((v) ? BIT(27) : 0) -#define VDPU_REG_PIC_INTERLACE_E(v) ((v) ? BIT(23) : 0) -#define VDPU_REG_PIC_FIELDMODE_E(v) ((v) ? BIT(22) : 0) -#define VDPU_REG_PIC_B_E(v) ((v) ? BIT(21) : 0) -#define VDPU_REG_PIC_INTER_E(v) ((v) ? BIT(20) : 0) -#define VDPU_REG_PIC_TOPFIELD_E(v) ((v) ? BIT(19) : 0) -#define VDPU_REG_FWD_INTERLACE_E(v) ((v) ? BIT(18) : 0) -#define VDPU_REG_FILTERING_DIS(v) ((v) ? BIT(14) : 0) -#define VDPU_REG_WRITE_MVS_E(v) ((v) ? BIT(12) : 0) -#define VDPU_REG_DEC_AXI_WR_ID(v) (((v) << 0) & GENMASK(7, 0)) - -#define VDPU_REG_PIC_MB_WIDTH(v) (((v) << 23) & GENMASK(31, 23)) -#define VDPU_REG_PIC_MB_HEIGHT_P(v) (((v) << 11) & GENMASK(18, 11)) -#define VDPU_REG_ALT_SCAN_E(v) ((v) ? BIT(6) : 0) -#define VDPU_REG_TOPFIELDFIRST_E(v) ((v) ? BIT(5) : 0) - -#define VDPU_REG_STRM_START_BIT(v) (((v) << 26) & GENMASK(31, 26)) -#define VDPU_REG_QSCALE_TYPE(v) ((v) ? BIT(24) : 0) -#define VDPU_REG_CON_MV_E(v) ((v) ? BIT(4) : 0) -#define VDPU_REG_INTRA_DC_PREC(v) (((v) << 2) & GENMASK(3, 2)) -#define VDPU_REG_INTRA_VLC_TAB(v) ((v) ? BIT(1) : 0) -#define VDPU_REG_FRAME_PRED_DCT(v) ((v) ? BIT(0) : 0) - -#define VDPU_REG_INIT_QP(v) (((v) << 25) & GENMASK(30, 25)) -#define VDPU_REG_STREAM_LEN(v) (((v) << 0) & GENMASK(23, 0)) - -#define VDPU_REG_ALT_SCAN_FLAG_E(v) ((v) ? BIT(19) : 0) -#define VDPU_REG_FCODE_FWD_HOR(v) (((v) << 15) & GENMASK(18, 15)) -#define VDPU_REG_FCODE_FWD_VER(v) (((v) << 11) & GENMASK(14, 11)) -#define VDPU_REG_FCODE_BWD_HOR(v) (((v) << 7) & GENMASK(10, 7)) -#define VDPU_REG_FCODE_BWD_VER(v) (((v) << 3) & GENMASK(6, 3)) -#define VDPU_REG_MV_ACCURACY_FWD(v) ((v) ? BIT(2) : 0) -#define VDPU_REG_MV_ACCURACY_BWD(v) ((v) ? BIT(1) : 0) - -#define VDPU_REG_STARTMB_X(v) (((v) << 23) & GENMASK(31, 23)) -#define VDPU_REG_STARTMB_Y(v) (((v) << 15) & GENMASK(22, 15)) - -#define VDPU_REG_APF_THRESHOLD(v) (((v) << 0) & GENMASK(13, 0)) - -#define PICT_TOP_FIELD 1 -#define PICT_BOTTOM_FIELD 2 -#define PICT_FRAME 3 - -static void -rk3288_vpu_mpeg2_dec_set_quantization(struct rockchip_vpu_dev *vpu, - struct rockchip_vpu_ctx *ctx) -{ - struct v4l2_ctrl_mpeg2_quantization *quantization; - - quantization = rockchip_vpu_get_ctrl(ctx, - V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION); - rockchip_vpu_mpeg2_dec_copy_qtable(ctx->mpeg2_dec.qtable.cpu, - quantization); - vdpu_write_relaxed(vpu, ctx->mpeg2_dec.qtable.dma, - VDPU_REG_QTABLE_BASE); -} - -static void -rk3288_vpu_mpeg2_dec_set_buffers(struct rockchip_vpu_dev *vpu, - struct rockchip_vpu_ctx *ctx, - struct vb2_buffer *src_buf, - struct vb2_buffer *dst_buf, - const struct v4l2_mpeg2_sequence *sequence, - const struct v4l2_mpeg2_picture *picture, - const struct v4l2_ctrl_mpeg2_slice_params *slice_params) -{ - dma_addr_t forward_addr = 0, backward_addr = 0; - dma_addr_t current_addr, addr; - struct vb2_queue *vq; - - vq = v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx); - - switch (picture->picture_coding_type) { - case V4L2_MPEG2_PICTURE_CODING_TYPE_B: - backward_addr = rockchip_vpu_get_ref(vq, - slice_params->backward_ref_ts); - /* fall-through */ - case V4L2_MPEG2_PICTURE_CODING_TYPE_P: - forward_addr = rockchip_vpu_get_ref(vq, - slice_params->forward_ref_ts); - } - - /* Source bitstream buffer */ - addr = vb2_dma_contig_plane_dma_addr(src_buf, 0); - vdpu_write_relaxed(vpu, addr, VDPU_REG_RLC_VLC_BASE); - - /* Destination frame buffer */ - addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0); - current_addr = addr; - - if (picture->picture_structure == PICT_BOTTOM_FIELD) - addr += ALIGN(ctx->dst_fmt.width, 16); - vdpu_write_relaxed(vpu, addr, VDPU_REG_DEC_OUT_BASE); - - if (!forward_addr) - forward_addr = current_addr; - if (!backward_addr) - backward_addr = current_addr; - - /* Set forward ref frame (top/bottom field) */ - if (picture->picture_structure == PICT_FRAME || - picture->picture_coding_type == V4L2_MPEG2_PICTURE_CODING_TYPE_B || - (picture->picture_structure == PICT_TOP_FIELD && - picture->top_field_first) || - (picture->picture_structure == PICT_BOTTOM_FIELD && - !picture->top_field_first)) { - vdpu_write_relaxed(vpu, forward_addr, VDPU_REG_REFER0_BASE); - vdpu_write_relaxed(vpu, forward_addr, VDPU_REG_REFER1_BASE); - } else if (picture->picture_structure == PICT_TOP_FIELD) { - vdpu_write_relaxed(vpu, forward_addr, VDPU_REG_REFER0_BASE); - vdpu_write_relaxed(vpu, current_addr, VDPU_REG_REFER1_BASE); - } else if (picture->picture_structure == PICT_BOTTOM_FIELD) { - vdpu_write_relaxed(vpu, current_addr, VDPU_REG_REFER0_BASE); - vdpu_write_relaxed(vpu, forward_addr, VDPU_REG_REFER1_BASE); - } - - /* Set backward ref frame (top/bottom field) */ - vdpu_write_relaxed(vpu, backward_addr, VDPU_REG_REFER2_BASE); - vdpu_write_relaxed(vpu, backward_addr, VDPU_REG_REFER3_BASE); -} - -void rk3288_vpu_mpeg2_dec_run(struct rockchip_vpu_ctx *ctx) -{ - struct rockchip_vpu_dev *vpu = ctx->dev; - struct vb2_v4l2_buffer *src_buf, *dst_buf; - const struct v4l2_ctrl_mpeg2_slice_params *slice_params; - const struct v4l2_mpeg2_sequence *sequence; - 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); - - /* Apply request controls if any */ - v4l2_ctrl_request_setup(src_buf->vb2_buf.req_obj.req, - &ctx->ctrl_handler); - - slice_params = rockchip_vpu_get_ctrl(ctx, - V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS); - sequence = &slice_params->sequence; - picture = &slice_params->picture; - - reg = VDPU_REG_DEC_AXI_RD_ID(0) | - VDPU_REG_DEC_TIMEOUT_E(1) | - VDPU_REG_DEC_STRSWAP32_E(1) | - VDPU_REG_DEC_STRENDIAN_E(1) | - VDPU_REG_DEC_INSWAP32_E(1) | - VDPU_REG_DEC_OUTSWAP32_E(1) | - VDPU_REG_DEC_DATA_DISC_E(0) | - VDPU_REG_DEC_LATENCY(0) | - VDPU_REG_DEC_CLK_GATE_E(1) | - VDPU_REG_DEC_IN_ENDIAN(1) | - VDPU_REG_DEC_OUT_ENDIAN(1) | - VDPU_REG_DEC_ADV_PRE_DIS(0) | - VDPU_REG_DEC_SCMD_DIS(0) | - VDPU_REG_DEC_MAX_BURST(16); - vdpu_write_relaxed(vpu, reg, VDPU_SWREG(2)); - - reg = VDPU_REG_DEC_MODE(5) | - VDPU_REG_RLC_MODE_E(0) | - VDPU_REG_PIC_INTERLACE_E(!sequence->progressive_sequence) | - VDPU_REG_PIC_FIELDMODE_E(picture->picture_structure != PICT_FRAME) | - VDPU_REG_PIC_B_E(picture->picture_coding_type == V4L2_MPEG2_PICTURE_CODING_TYPE_B) | - VDPU_REG_PIC_INTER_E(picture->picture_coding_type != V4L2_MPEG2_PICTURE_CODING_TYPE_I) | - VDPU_REG_PIC_TOPFIELD_E(picture->picture_structure == PICT_TOP_FIELD) | - VDPU_REG_FWD_INTERLACE_E(0) | - VDPU_REG_FILTERING_DIS(1) | - VDPU_REG_WRITE_MVS_E(0) | - VDPU_REG_DEC_AXI_WR_ID(0); - vdpu_write_relaxed(vpu, reg, VDPU_SWREG(3)); - - reg = VDPU_REG_PIC_MB_WIDTH(MPEG2_MB_WIDTH(ctx->dst_fmt.width)) | - VDPU_REG_PIC_MB_HEIGHT_P(MPEG2_MB_HEIGHT(ctx->dst_fmt.height)) | - VDPU_REG_ALT_SCAN_E(picture->alternate_scan) | - VDPU_REG_TOPFIELDFIRST_E(picture->top_field_first); - vdpu_write_relaxed(vpu, reg, VDPU_SWREG(4)); - - reg = VDPU_REG_STRM_START_BIT(slice_params->data_bit_offset) | - VDPU_REG_QSCALE_TYPE(picture->q_scale_type) | - VDPU_REG_CON_MV_E(picture->concealment_motion_vectors) | - VDPU_REG_INTRA_DC_PREC(picture->intra_dc_precision) | - VDPU_REG_INTRA_VLC_TAB(picture->intra_vlc_format) | - VDPU_REG_FRAME_PRED_DCT(picture->frame_pred_frame_dct); - vdpu_write_relaxed(vpu, reg, VDPU_SWREG(5)); - - reg = VDPU_REG_INIT_QP(1) | - VDPU_REG_STREAM_LEN(slice_params->bit_size >> 3); - vdpu_write_relaxed(vpu, reg, VDPU_SWREG(6)); - - reg = VDPU_REG_ALT_SCAN_FLAG_E(picture->alternate_scan) | - VDPU_REG_FCODE_FWD_HOR(picture->f_code[0][0]) | - VDPU_REG_FCODE_FWD_VER(picture->f_code[0][1]) | - VDPU_REG_FCODE_BWD_HOR(picture->f_code[1][0]) | - VDPU_REG_FCODE_BWD_VER(picture->f_code[1][1]) | - VDPU_REG_MV_ACCURACY_FWD(1) | - VDPU_REG_MV_ACCURACY_BWD(1); - vdpu_write_relaxed(vpu, reg, VDPU_SWREG(18)); - - reg = VDPU_REG_STARTMB_X(0) | - VDPU_REG_STARTMB_Y(0); - vdpu_write_relaxed(vpu, reg, VDPU_SWREG(48)); - - reg = VDPU_REG_APF_THRESHOLD(8); - vdpu_write_relaxed(vpu, reg, VDPU_SWREG(55)); - - rk3288_vpu_mpeg2_dec_set_quantization(vpu, ctx); - - rk3288_vpu_mpeg2_dec_set_buffers(vpu, ctx, &src_buf->vb2_buf, - &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)); - - reg = VDPU_REG_DEC_E(1); - vdpu_write(vpu, reg, VDPU_SWREG(1)); -} diff --git a/drivers/staging/media/rockchip/vpu/rk3288_vpu_regs.h b/drivers/staging/media/rockchip/vpu/rk3288_vpu_regs.h deleted file mode 100644 index c9631b713804..000000000000 --- a/drivers/staging/media/rockchip/vpu/rk3288_vpu_regs.h +++ /dev/null @@ -1,443 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Rockchip VPU codec driver - * - * Copyright 2018 Google LLC. - * Tomasz Figa - */ - -#ifndef RK3288_VPU_REGS_H_ -#define RK3288_VPU_REGS_H_ - -/* Encoder registers. */ -#define VEPU_REG_INTERRUPT 0x004 -#define VEPU_REG_INTERRUPT_FRAME_RDY BIT(2) -#define VEPU_REG_INTERRUPT_DIS_BIT BIT(1) -#define VEPU_REG_INTERRUPT_BIT BIT(0) -#define VEPU_REG_AXI_CTRL 0x008 -#define VEPU_REG_AXI_CTRL_OUTPUT_SWAP16 BIT(15) -#define VEPU_REG_AXI_CTRL_INPUT_SWAP16 BIT(14) -#define VEPU_REG_AXI_CTRL_BURST_LEN(x) ((x) << 8) -#define VEPU_REG_AXI_CTRL_GATE_BIT BIT(4) -#define VEPU_REG_AXI_CTRL_OUTPUT_SWAP32 BIT(3) -#define VEPU_REG_AXI_CTRL_INPUT_SWAP32 BIT(2) -#define VEPU_REG_AXI_CTRL_OUTPUT_SWAP8 BIT(1) -#define VEPU_REG_AXI_CTRL_INPUT_SWAP8 BIT(0) -#define VEPU_REG_ADDR_OUTPUT_STREAM 0x014 -#define VEPU_REG_ADDR_OUTPUT_CTRL 0x018 -#define VEPU_REG_ADDR_REF_LUMA 0x01c -#define VEPU_REG_ADDR_REF_CHROMA 0x020 -#define VEPU_REG_ADDR_REC_LUMA 0x024 -#define VEPU_REG_ADDR_REC_CHROMA 0x028 -#define VEPU_REG_ADDR_IN_PLANE_0 0x02c -#define VEPU_REG_ADDR_IN_PLANE_1 0x030 -#define VEPU_REG_ADDR_IN_PLANE_2 0x034 -#define VEPU_REG_ENC_CTRL 0x038 -#define VEPU_REG_ENC_CTRL_TIMEOUT_EN BIT(31) -#define VEPU_REG_ENC_CTRL_NAL_MODE_BIT BIT(29) -#define VEPU_REG_ENC_CTRL_WIDTH(w) ((w) << 19) -#define VEPU_REG_ENC_CTRL_HEIGHT(h) ((h) << 10) -#define VEPU_REG_ENC_PIC_INTER (0x0 << 3) -#define VEPU_REG_ENC_PIC_INTRA (0x1 << 3) -#define VEPU_REG_ENC_PIC_MVCINTER (0x2 << 3) -#define VEPU_REG_ENC_CTRL_ENC_MODE_H264 (0x3 << 1) -#define VEPU_REG_ENC_CTRL_ENC_MODE_JPEG (0x2 << 1) -#define VEPU_REG_ENC_CTRL_ENC_MODE_VP8 (0x1 << 1) -#define VEPU_REG_ENC_CTRL_EN_BIT BIT(0) -#define VEPU_REG_IN_IMG_CTRL 0x03c -#define VEPU_REG_IN_IMG_CTRL_ROW_LEN(x) ((x) << 12) -#define VEPU_REG_IN_IMG_CTRL_OVRFLR_D4(x) ((x) << 10) -#define VEPU_REG_IN_IMG_CTRL_OVRFLB_D4(x) ((x) << 6) -#define VEPU_REG_IN_IMG_CTRL_FMT(x) ((x) << 2) -#define VEPU_REG_ENC_CTRL0 0x040 -#define VEPU_REG_ENC_CTRL0_INIT_QP(x) ((x) << 26) -#define VEPU_REG_ENC_CTRL0_SLICE_ALPHA(x) ((x) << 22) -#define VEPU_REG_ENC_CTRL0_SLICE_BETA(x) ((x) << 18) -#define VEPU_REG_ENC_CTRL0_CHROMA_QP_OFFSET(x) ((x) << 13) -#define VEPU_REG_ENC_CTRL0_FILTER_DIS(x) ((x) << 5) -#define VEPU_REG_ENC_CTRL0_IDR_PICID(x) ((x) << 1) -#define VEPU_REG_ENC_CTRL0_CONSTR_INTRA_PRED BIT(0) -#define VEPU_REG_ENC_CTRL1 0x044 -#define VEPU_REG_ENC_CTRL1_PPS_ID(x) ((x) << 24) -#define VEPU_REG_ENC_CTRL1_INTRA_PRED_MODE(x) ((x) << 16) -#define VEPU_REG_ENC_CTRL1_FRAME_NUM(x) ((x)) -#define VEPU_REG_ENC_CTRL2 0x048 -#define VEPU_REG_ENC_CTRL2_DEBLOCKING_FILETER_MODE(x) ((x) << 30) -#define VEPU_REG_ENC_CTRL2_H264_SLICE_SIZE(x) ((x) << 23) -#define VEPU_REG_ENC_CTRL2_DISABLE_QUARTER_PIXMV BIT(22) -#define VEPU_REG_ENC_CTRL2_TRANS8X8_MODE_EN BIT(21) -#define VEPU_REG_ENC_CTRL2_CABAC_INIT_IDC(x) ((x) << 19) -#define VEPU_REG_ENC_CTRL2_ENTROPY_CODING_MODE BIT(18) -#define VEPU_REG_ENC_CTRL2_H264_INTER4X4_MODE BIT(17) -#define VEPU_REG_ENC_CTRL2_H264_STREAM_MODE BIT(16) -#define VEPU_REG_ENC_CTRL2_INTRA16X16_MODE(x) ((x)) -#define VEPU_REG_ENC_CTRL3 0x04c -#define VEPU_REG_ENC_CTRL3_MUTIMV_EN BIT(30) -#define VEPU_REG_ENC_CTRL3_MV_PENALTY_1_4P(x) ((x) << 20) -#define VEPU_REG_ENC_CTRL3_MV_PENALTY_4P(x) ((x) << 10) -#define VEPU_REG_ENC_CTRL3_MV_PENALTY_1P(x) ((x)) -#define VEPU_REG_ENC_CTRL4 0x050 -#define VEPU_REG_ENC_CTRL4_MV_PENALTY_16X8_8X16(x) ((x) << 20) -#define VEPU_REG_ENC_CTRL4_MV_PENALTY_8X8(x) ((x) << 10) -#define VEPU_REG_ENC_CTRL4_8X4_4X8(x) ((x)) -#define VEPU_REG_ENC_CTRL5 0x054 -#define VEPU_REG_ENC_CTRL5_MACROBLOCK_PENALTY(x) ((x) << 24) -#define VEPU_REG_ENC_CTRL5_COMPLETE_SLICES(x) ((x) << 16) -#define VEPU_REG_ENC_CTRL5_INTER_MODE(x) ((x)) -#define VEPU_REG_STR_HDR_REM_MSB 0x058 -#define VEPU_REG_STR_HDR_REM_LSB 0x05c -#define VEPU_REG_STR_BUF_LIMIT 0x060 -#define VEPU_REG_MAD_CTRL 0x064 -#define VEPU_REG_MAD_CTRL_QP_ADJUST(x) ((x) << 28) -#define VEPU_REG_MAD_CTRL_MAD_THREDHOLD(x) ((x) << 22) -#define VEPU_REG_MAD_CTRL_QP_SUM_DIV2(x) ((x)) -#define VEPU_REG_ADDR_VP8_PROB_CNT 0x068 -#define VEPU_REG_QP_VAL 0x06c -#define VEPU_REG_QP_VAL_LUM(x) ((x) << 26) -#define VEPU_REG_QP_VAL_MAX(x) ((x) << 20) -#define VEPU_REG_QP_VAL_MIN(x) ((x) << 14) -#define VEPU_REG_QP_VAL_CHECKPOINT_DISTAN(x) ((x)) -#define VEPU_REG_VP8_QP_VAL(i) (0x06c + ((i) * 0x4)) -#define VEPU_REG_CHECKPOINT(i) (0x070 + ((i) * 0x4)) -#define VEPU_REG_CHECKPOINT_CHECK0(x) (((x) & 0xffff)) -#define VEPU_REG_CHECKPOINT_CHECK1(x) (((x) & 0xffff) << 16) -#define VEPU_REG_CHECKPOINT_RESULT(x) ((((x) >> (16 - 16 \ - * (i & 1))) & 0xffff) \ - * 32) -#define VEPU_REG_CHKPT_WORD_ERR(i) (0x084 + ((i) * 0x4)) -#define VEPU_REG_CHKPT_WORD_ERR_CHK0(x) (((x) & 0xffff)) -#define VEPU_REG_CHKPT_WORD_ERR_CHK1(x) (((x) & 0xffff) << 16) -#define VEPU_REG_VP8_BOOL_ENC 0x08c -#define VEPU_REG_CHKPT_DELTA_QP 0x090 -#define VEPU_REG_CHKPT_DELTA_QP_CHK0(x) (((x) & 0x0f) << 0) -#define VEPU_REG_CHKPT_DELTA_QP_CHK1(x) (((x) & 0x0f) << 4) -#define VEPU_REG_CHKPT_DELTA_QP_CHK2(x) (((x) & 0x0f) << 8) -#define VEPU_REG_CHKPT_DELTA_QP_CHK3(x) (((x) & 0x0f) << 12) -#define VEPU_REG_CHKPT_DELTA_QP_CHK4(x) (((x) & 0x0f) << 16) -#define VEPU_REG_CHKPT_DELTA_QP_CHK5(x) (((x) & 0x0f) << 20) -#define VEPU_REG_CHKPT_DELTA_QP_CHK6(x) (((x) & 0x0f) << 24) -#define VEPU_REG_VP8_CTRL0 0x090 -#define VEPU_REG_RLC_CTRL 0x094 -#define VEPU_REG_RLC_CTRL_STR_OFFS_SHIFT 23 -#define VEPU_REG_RLC_CTRL_STR_OFFS_MASK (0x3f << 23) -#define VEPU_REG_RLC_CTRL_RLC_SUM(x) ((x)) -#define VEPU_REG_MB_CTRL 0x098 -#define VEPU_REG_MB_CNT_OUT(x) (((x) & 0xffff)) -#define VEPU_REG_MB_CNT_SET(x) (((x) & 0xffff) << 16) -#define VEPU_REG_ADDR_NEXT_PIC 0x09c -#define VEPU_REG_JPEG_LUMA_QUAT(i) (0x100 + ((i) * 0x4)) -#define VEPU_REG_JPEG_CHROMA_QUAT(i) (0x140 + ((i) * 0x4)) -#define VEPU_REG_STABILIZATION_OUTPUT 0x0A0 -#define VEPU_REG_ADDR_CABAC_TBL 0x0cc -#define VEPU_REG_ADDR_MV_OUT 0x0d0 -#define VEPU_REG_RGB_YUV_COEFF(i) (0x0d4 + ((i) * 0x4)) -#define VEPU_REG_RGB_MASK_MSB 0x0dc -#define VEPU_REG_INTRA_AREA_CTRL 0x0e0 -#define VEPU_REG_CIR_INTRA_CTRL 0x0e4 -#define VEPU_REG_INTRA_SLICE_BITMAP(i) (0x0e8 + ((i) * 0x4)) -#define VEPU_REG_ADDR_VP8_DCT_PART(i) (0x0e8 + ((i) * 0x4)) -#define VEPU_REG_FIRST_ROI_AREA 0x0f0 -#define VEPU_REG_SECOND_ROI_AREA 0x0f4 -#define VEPU_REG_MVC_CTRL 0x0f8 -#define VEPU_REG_MVC_CTRL_MV16X16_FAVOR(x) ((x) << 28) -#define VEPU_REG_VP8_INTRA_PENALTY(i) (0x100 + ((i) * 0x4)) -#define VEPU_REG_ADDR_VP8_SEG_MAP 0x11c -#define VEPU_REG_VP8_SEG_QP(i) (0x120 + ((i) * 0x4)) -#define VEPU_REG_DMV_4P_1P_PENALTY(i) (0x180 + ((i) * 0x4)) -#define VEPU_REG_DMV_4P_1P_PENALTY_BIT(x, i) ((x) << (i) * 8) -#define VEPU_REG_DMV_QPEL_PENALTY(i) (0x200 + ((i) * 0x4)) -#define VEPU_REG_DMV_QPEL_PENALTY_BIT(x, i) ((x) << (i) * 8) -#define VEPU_REG_VP8_CTRL1 0x280 -#define VEPU_REG_VP8_BIT_COST_GOLDEN 0x284 -#define VEPU_REG_VP8_LOOP_FLT_DELTA(i) (0x288 + ((i) * 0x4)) - -/* Decoder registers. */ -#define VDPU_REG_INTERRUPT 0x004 -#define VDPU_REG_INTERRUPT_DEC_PIC_INF BIT(24) -#define VDPU_REG_INTERRUPT_DEC_TIMEOUT BIT(18) -#define VDPU_REG_INTERRUPT_DEC_SLICE_INT BIT(17) -#define VDPU_REG_INTERRUPT_DEC_ERROR_INT BIT(16) -#define VDPU_REG_INTERRUPT_DEC_ASO_INT BIT(15) -#define VDPU_REG_INTERRUPT_DEC_BUFFER_INT BIT(14) -#define VDPU_REG_INTERRUPT_DEC_BUS_INT BIT(13) -#define VDPU_REG_INTERRUPT_DEC_RDY_INT BIT(12) -#define VDPU_REG_INTERRUPT_DEC_IRQ BIT(8) -#define VDPU_REG_INTERRUPT_DEC_IRQ_DIS BIT(4) -#define VDPU_REG_INTERRUPT_DEC_E BIT(0) -#define VDPU_REG_CONFIG 0x008 -#define VDPU_REG_CONFIG_DEC_AXI_RD_ID(x) (((x) & 0xff) << 24) -#define VDPU_REG_CONFIG_DEC_TIMEOUT_E BIT(23) -#define VDPU_REG_CONFIG_DEC_STRSWAP32_E BIT(22) -#define VDPU_REG_CONFIG_DEC_STRENDIAN_E BIT(21) -#define VDPU_REG_CONFIG_DEC_INSWAP32_E BIT(20) -#define VDPU_REG_CONFIG_DEC_OUTSWAP32_E BIT(19) -#define VDPU_REG_CONFIG_DEC_DATA_DISC_E BIT(18) -#define VDPU_REG_CONFIG_TILED_MODE_MSB BIT(17) -#define VDPU_REG_CONFIG_DEC_OUT_TILED_E BIT(17) -#define VDPU_REG_CONFIG_DEC_LATENCY(x) (((x) & 0x3f) << 11) -#define VDPU_REG_CONFIG_DEC_CLK_GATE_E BIT(10) -#define VDPU_REG_CONFIG_DEC_IN_ENDIAN BIT(9) -#define VDPU_REG_CONFIG_DEC_OUT_ENDIAN BIT(8) -#define VDPU_REG_CONFIG_PRIORITY_MODE(x) (((x) & 0x7) << 5) -#define VDPU_REG_CONFIG_TILED_MODE_LSB BIT(7) -#define VDPU_REG_CONFIG_DEC_ADV_PRE_DIS BIT(6) -#define VDPU_REG_CONFIG_DEC_SCMD_DIS BIT(5) -#define VDPU_REG_CONFIG_DEC_MAX_BURST(x) (((x) & 0x1f) << 0) -#define VDPU_REG_DEC_CTRL0 0x00c -#define VDPU_REG_DEC_CTRL0_DEC_MODE(x) (((x) & 0xf) << 28) -#define VDPU_REG_DEC_CTRL0_RLC_MODE_E BIT(27) -#define VDPU_REG_DEC_CTRL0_SKIP_MODE BIT(26) -#define VDPU_REG_DEC_CTRL0_DIVX3_E BIT(25) -#define VDPU_REG_DEC_CTRL0_PJPEG_E BIT(24) -#define VDPU_REG_DEC_CTRL0_PIC_INTERLACE_E BIT(23) -#define VDPU_REG_DEC_CTRL0_PIC_FIELDMODE_E BIT(22) -#define VDPU_REG_DEC_CTRL0_PIC_B_E BIT(21) -#define VDPU_REG_DEC_CTRL0_PIC_INTER_E BIT(20) -#define VDPU_REG_DEC_CTRL0_PIC_TOPFIELD_E BIT(19) -#define VDPU_REG_DEC_CTRL0_FWD_INTERLACE_E BIT(18) -#define VDPU_REG_DEC_CTRL0_SORENSON_E BIT(17) -#define VDPU_REG_DEC_CTRL0_REF_TOPFIELD_E BIT(16) -#define VDPU_REG_DEC_CTRL0_DEC_OUT_DIS BIT(15) -#define VDPU_REG_DEC_CTRL0_FILTERING_DIS BIT(14) -#define VDPU_REG_DEC_CTRL0_WEBP_E BIT(13) -#define VDPU_REG_DEC_CTRL0_MVC_E BIT(13) -#define VDPU_REG_DEC_CTRL0_PIC_FIXED_QUANT BIT(13) -#define VDPU_REG_DEC_CTRL0_WRITE_MVS_E BIT(12) -#define VDPU_REG_DEC_CTRL0_REFTOPFIRST_E BIT(11) -#define VDPU_REG_DEC_CTRL0_SEQ_MBAFF_E BIT(10) -#define VDPU_REG_DEC_CTRL0_PICORD_COUNT_E BIT(9) -#define VDPU_REG_DEC_CTRL0_DEC_AHB_HLOCK_E BIT(8) -#define VDPU_REG_DEC_CTRL0_DEC_AXI_WR_ID(x) (((x) & 0xff) << 0) -#define VDPU_REG_DEC_CTRL1 0x010 -#define VDPU_REG_DEC_CTRL1_PIC_MB_WIDTH(x) (((x) & 0x1ff) << 23) -#define VDPU_REG_DEC_CTRL1_MB_WIDTH_OFF(x) (((x) & 0xf) << 19) -#define VDPU_REG_DEC_CTRL1_PIC_MB_HEIGHT_P(x) (((x) & 0xff) << 11) -#define VDPU_REG_DEC_CTRL1_MB_HEIGHT_OFF(x) (((x) & 0xf) << 7) -#define VDPU_REG_DEC_CTRL1_ALT_SCAN_E BIT(6) -#define VDPU_REG_DEC_CTRL1_TOPFIELDFIRST_E BIT(5) -#define VDPU_REG_DEC_CTRL1_REF_FRAMES(x) (((x) & 0x1f) << 0) -#define VDPU_REG_DEC_CTRL1_PIC_MB_W_EXT(x) (((x) & 0x7) << 3) -#define VDPU_REG_DEC_CTRL1_PIC_MB_H_EXT(x) (((x) & 0x7) << 0) -#define VDPU_REG_DEC_CTRL1_PIC_REFER_FLAG BIT(0) -#define VDPU_REG_DEC_CTRL2 0x014 -#define VDPU_REG_DEC_CTRL2_STRM_START_BIT(x) (((x) & 0x3f) << 26) -#define VDPU_REG_DEC_CTRL2_SYNC_MARKER_E BIT(25) -#define VDPU_REG_DEC_CTRL2_TYPE1_QUANT_E BIT(24) -#define VDPU_REG_DEC_CTRL2_CH_QP_OFFSET(x) (((x) & 0x1f) << 19) -#define VDPU_REG_DEC_CTRL2_CH_QP_OFFSET2(x) (((x) & 0x1f) << 14) -#define VDPU_REG_DEC_CTRL2_FIELDPIC_FLAG_E BIT(0) -#define VDPU_REG_DEC_CTRL2_INTRADC_VLC_THR(x) (((x) & 0x7) << 16) -#define VDPU_REG_DEC_CTRL2_VOP_TIME_INCR(x) (((x) & 0xffff) << 0) -#define VDPU_REG_DEC_CTRL2_DQ_PROFILE BIT(24) -#define VDPU_REG_DEC_CTRL2_DQBI_LEVEL BIT(23) -#define VDPU_REG_DEC_CTRL2_RANGE_RED_FRM_E BIT(22) -#define VDPU_REG_DEC_CTRL2_FAST_UVMC_E BIT(20) -#define VDPU_REG_DEC_CTRL2_TRANSDCTAB BIT(17) -#define VDPU_REG_DEC_CTRL2_TRANSACFRM(x) (((x) & 0x3) << 15) -#define VDPU_REG_DEC_CTRL2_TRANSACFRM2(x) (((x) & 0x3) << 13) -#define VDPU_REG_DEC_CTRL2_MB_MODE_TAB(x) (((x) & 0x7) << 10) -#define VDPU_REG_DEC_CTRL2_MVTAB(x) (((x) & 0x7) << 7) -#define VDPU_REG_DEC_CTRL2_CBPTAB(x) (((x) & 0x7) << 4) -#define VDPU_REG_DEC_CTRL2_2MV_BLK_PAT_TAB(x) (((x) & 0x3) << 2) -#define VDPU_REG_DEC_CTRL2_4MV_BLK_PAT_TAB(x) (((x) & 0x3) << 0) -#define VDPU_REG_DEC_CTRL2_QSCALE_TYPE BIT(24) -#define VDPU_REG_DEC_CTRL2_CON_MV_E BIT(4) -#define VDPU_REG_DEC_CTRL2_INTRA_DC_PREC(x) (((x) & 0x3) << 2) -#define VDPU_REG_DEC_CTRL2_INTRA_VLC_TAB BIT(1) -#define VDPU_REG_DEC_CTRL2_FRAME_PRED_DCT BIT(0) -#define VDPU_REG_DEC_CTRL2_JPEG_QTABLES(x) (((x) & 0x3) << 11) -#define VDPU_REG_DEC_CTRL2_JPEG_MODE(x) (((x) & 0x7) << 8) -#define VDPU_REG_DEC_CTRL2_JPEG_FILRIGHT_E BIT(7) -#define VDPU_REG_DEC_CTRL2_JPEG_STREAM_ALL BIT(6) -#define VDPU_REG_DEC_CTRL2_CR_AC_VLCTABLE BIT(5) -#define VDPU_REG_DEC_CTRL2_CB_AC_VLCTABLE BIT(4) -#define VDPU_REG_DEC_CTRL2_CR_DC_VLCTABLE BIT(3) -#define VDPU_REG_DEC_CTRL2_CB_DC_VLCTABLE BIT(2) -#define VDPU_REG_DEC_CTRL2_CR_DC_VLCTABLE3 BIT(1) -#define VDPU_REG_DEC_CTRL2_CB_DC_VLCTABLE3 BIT(0) -#define VDPU_REG_DEC_CTRL2_STRM1_START_BIT(x) (((x) & 0x3f) << 18) -#define VDPU_REG_DEC_CTRL2_HUFFMAN_E BIT(17) -#define VDPU_REG_DEC_CTRL2_MULTISTREAM_E BIT(16) -#define VDPU_REG_DEC_CTRL2_BOOLEAN_VALUE(x) (((x) & 0xff) << 8) -#define VDPU_REG_DEC_CTRL2_BOOLEAN_RANGE(x) (((x) & 0xff) << 0) -#define VDPU_REG_DEC_CTRL2_ALPHA_OFFSET(x) (((x) & 0x1f) << 5) -#define VDPU_REG_DEC_CTRL2_BETA_OFFSET(x) (((x) & 0x1f) << 0) -#define VDPU_REG_DEC_CTRL3 0x018 -#define VDPU_REG_DEC_CTRL3_START_CODE_E BIT(31) -#define VDPU_REG_DEC_CTRL3_INIT_QP(x) (((x) & 0x3f) << 25) -#define VDPU_REG_DEC_CTRL3_CH_8PIX_ILEAV_E BIT(24) -#define VDPU_REG_DEC_CTRL3_STREAM_LEN_EXT(x) (((x) & 0xff) << 24) -#define VDPU_REG_DEC_CTRL3_STREAM_LEN(x) (((x) & 0xffffff) << 0) -#define VDPU_REG_DEC_CTRL4 0x01c -#define VDPU_REG_DEC_CTRL4_CABAC_E BIT(31) -#define VDPU_REG_DEC_CTRL4_BLACKWHITE_E BIT(30) -#define VDPU_REG_DEC_CTRL4_DIR_8X8_INFER_E BIT(29) -#define VDPU_REG_DEC_CTRL4_WEIGHT_PRED_E BIT(28) -#define VDPU_REG_DEC_CTRL4_WEIGHT_BIPR_IDC(x) (((x) & 0x3) << 26) -#define VDPU_REG_DEC_CTRL4_AVS_H264_H_EXT BIT(25) -#define VDPU_REG_DEC_CTRL4_FRAMENUM_LEN(x) (((x) & 0x1f) << 16) -#define VDPU_REG_DEC_CTRL4_FRAMENUM(x) (((x) & 0xffff) << 0) -#define VDPU_REG_DEC_CTRL4_BITPLANE0_E BIT(31) -#define VDPU_REG_DEC_CTRL4_BITPLANE1_E BIT(30) -#define VDPU_REG_DEC_CTRL4_BITPLANE2_E BIT(29) -#define VDPU_REG_DEC_CTRL4_ALT_PQUANT(x) (((x) & 0x1f) << 24) -#define VDPU_REG_DEC_CTRL4_DQ_EDGES(x) (((x) & 0xf) << 20) -#define VDPU_REG_DEC_CTRL4_TTMBF BIT(19) -#define VDPU_REG_DEC_CTRL4_PQINDEX(x) (((x) & 0x1f) << 14) -#define VDPU_REG_DEC_CTRL4_VC1_HEIGHT_EXT BIT(13) -#define VDPU_REG_DEC_CTRL4_BILIN_MC_E BIT(12) -#define VDPU_REG_DEC_CTRL4_UNIQP_E BIT(11) -#define VDPU_REG_DEC_CTRL4_HALFQP_E BIT(10) -#define VDPU_REG_DEC_CTRL4_TTFRM(x) (((x) & 0x3) << 8) -#define VDPU_REG_DEC_CTRL4_2ND_BYTE_EMUL_E BIT(7) -#define VDPU_REG_DEC_CTRL4_DQUANT_E BIT(6) -#define VDPU_REG_DEC_CTRL4_VC1_ADV_E BIT(5) -#define VDPU_REG_DEC_CTRL4_PJPEG_FILDOWN_E BIT(26) -#define VDPU_REG_DEC_CTRL4_PJPEG_WDIV8 BIT(25) -#define VDPU_REG_DEC_CTRL4_PJPEG_HDIV8 BIT(24) -#define VDPU_REG_DEC_CTRL4_PJPEG_AH(x) (((x) & 0xf) << 20) -#define VDPU_REG_DEC_CTRL4_PJPEG_AL(x) (((x) & 0xf) << 16) -#define VDPU_REG_DEC_CTRL4_PJPEG_SS(x) (((x) & 0xff) << 8) -#define VDPU_REG_DEC_CTRL4_PJPEG_SE(x) (((x) & 0xff) << 0) -#define VDPU_REG_DEC_CTRL4_DCT1_START_BIT(x) (((x) & 0x3f) << 26) -#define VDPU_REG_DEC_CTRL4_DCT2_START_BIT(x) (((x) & 0x3f) << 20) -#define VDPU_REG_DEC_CTRL4_CH_MV_RES BIT(13) -#define VDPU_REG_DEC_CTRL4_INIT_DC_MATCH0(x) (((x) & 0x7) << 9) -#define VDPU_REG_DEC_CTRL4_INIT_DC_MATCH1(x) (((x) & 0x7) << 6) -#define VDPU_REG_DEC_CTRL4_VP7_VERSION BIT(5) -#define VDPU_REG_DEC_CTRL5 0x020 -#define VDPU_REG_DEC_CTRL5_CONST_INTRA_E BIT(31) -#define VDPU_REG_DEC_CTRL5_FILT_CTRL_PRES BIT(30) -#define VDPU_REG_DEC_CTRL5_RDPIC_CNT_PRES BIT(29) -#define VDPU_REG_DEC_CTRL5_8X8TRANS_FLAG_E BIT(28) -#define VDPU_REG_DEC_CTRL5_REFPIC_MK_LEN(x) (((x) & 0x7ff) << 17) -#define VDPU_REG_DEC_CTRL5_IDR_PIC_E BIT(16) -#define VDPU_REG_DEC_CTRL5_IDR_PIC_ID(x) (((x) & 0xffff) << 0) -#define VDPU_REG_DEC_CTRL5_MV_SCALEFACTOR(x) (((x) & 0xff) << 24) -#define VDPU_REG_DEC_CTRL5_REF_DIST_FWD(x) (((x) & 0x1f) << 19) -#define VDPU_REG_DEC_CTRL5_REF_DIST_BWD(x) (((x) & 0x1f) << 14) -#define VDPU_REG_DEC_CTRL5_LOOP_FILT_LIMIT(x) (((x) & 0xf) << 14) -#define VDPU_REG_DEC_CTRL5_VARIANCE_TEST_E BIT(13) -#define VDPU_REG_DEC_CTRL5_MV_THRESHOLD(x) (((x) & 0x7) << 10) -#define VDPU_REG_DEC_CTRL5_VAR_THRESHOLD(x) (((x) & 0x3ff) << 0) -#define VDPU_REG_DEC_CTRL5_DIVX_IDCT_E BIT(8) -#define VDPU_REG_DEC_CTRL5_DIVX3_SLICE_SIZE(x) (((x) & 0xff) << 0) -#define VDPU_REG_DEC_CTRL5_PJPEG_REST_FREQ(x) (((x) & 0xffff) << 0) -#define VDPU_REG_DEC_CTRL5_RV_PROFILE(x) (((x) & 0x3) << 30) -#define VDPU_REG_DEC_CTRL5_RV_OSV_QUANT(x) (((x) & 0x3) << 28) -#define VDPU_REG_DEC_CTRL5_RV_FWD_SCALE(x) (((x) & 0x3fff) << 14) -#define VDPU_REG_DEC_CTRL5_RV_BWD_SCALE(x) (((x) & 0x3fff) << 0) -#define VDPU_REG_DEC_CTRL5_INIT_DC_COMP0(x) (((x) & 0xffff) << 16) -#define VDPU_REG_DEC_CTRL5_INIT_DC_COMP1(x) (((x) & 0xffff) << 0) -#define VDPU_REG_DEC_CTRL6 0x024 -#define VDPU_REG_DEC_CTRL6_PPS_ID(x) (((x) & 0xff) << 24) -#define VDPU_REG_DEC_CTRL6_REFIDX1_ACTIVE(x) (((x) & 0x1f) << 19) -#define VDPU_REG_DEC_CTRL6_REFIDX0_ACTIVE(x) (((x) & 0x1f) << 14) -#define VDPU_REG_DEC_CTRL6_POC_LENGTH(x) (((x) & 0xff) << 0) -#define VDPU_REG_DEC_CTRL6_ICOMP0_E BIT(24) -#define VDPU_REG_DEC_CTRL6_ISCALE0(x) (((x) & 0xff) << 16) -#define VDPU_REG_DEC_CTRL6_ISHIFT0(x) (((x) & 0xffff) << 0) -#define VDPU_REG_DEC_CTRL6_STREAM1_LEN(x) (((x) & 0xffffff) << 0) -#define VDPU_REG_DEC_CTRL6_PIC_SLICE_AM(x) (((x) & 0x1fff) << 0) -#define VDPU_REG_DEC_CTRL6_COEFFS_PART_AM(x) (((x) & 0xf) << 24) -#define VDPU_REG_FWD_PIC(i) (0x028 + ((i) * 0x4)) -#define VDPU_REG_FWD_PIC_PINIT_RLIST_F5(x) (((x) & 0x1f) << 25) -#define VDPU_REG_FWD_PIC_PINIT_RLIST_F4(x) (((x) & 0x1f) << 20) -#define VDPU_REG_FWD_PIC_PINIT_RLIST_F3(x) (((x) & 0x1f) << 15) -#define VDPU_REG_FWD_PIC_PINIT_RLIST_F2(x) (((x) & 0x1f) << 10) -#define VDPU_REG_FWD_PIC_PINIT_RLIST_F1(x) (((x) & 0x1f) << 5) -#define VDPU_REG_FWD_PIC_PINIT_RLIST_F0(x) (((x) & 0x1f) << 0) -#define VDPU_REG_FWD_PIC1_ICOMP1_E BIT(24) -#define VDPU_REG_FWD_PIC1_ISCALE1(x) (((x) & 0xff) << 16) -#define VDPU_REG_FWD_PIC1_ISHIFT1(x) (((x) & 0xffff) << 0) -#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_DEC_CTRL7 0x02c -#define VDPU_REG_DEC_CTRL7_PINIT_RLIST_F15(x) (((x) & 0x1f) << 25) -#define VDPU_REG_DEC_CTRL7_PINIT_RLIST_F14(x) (((x) & 0x1f) << 20) -#define VDPU_REG_DEC_CTRL7_PINIT_RLIST_F13(x) (((x) & 0x1f) << 15) -#define VDPU_REG_DEC_CTRL7_PINIT_RLIST_F12(x) (((x) & 0x1f) << 10) -#define VDPU_REG_DEC_CTRL7_PINIT_RLIST_F11(x) (((x) & 0x1f) << 5) -#define VDPU_REG_DEC_CTRL7_PINIT_RLIST_F10(x) (((x) & 0x1f) << 0) -#define VDPU_REG_DEC_CTRL7_ICOMP2_E BIT(24) -#define VDPU_REG_DEC_CTRL7_ISCALE2(x) (((x) & 0xff) << 16) -#define VDPU_REG_DEC_CTRL7_ISHIFT2(x) (((x) & 0xffff) << 0) -#define VDPU_REG_DEC_CTRL7_DCT3_START_BIT(x) (((x) & 0x3f) << 24) -#define VDPU_REG_DEC_CTRL7_DCT4_START_BIT(x) (((x) & 0x3f) << 18) -#define VDPU_REG_DEC_CTRL7_DCT5_START_BIT(x) (((x) & 0x3f) << 12) -#define VDPU_REG_DEC_CTRL7_DCT6_START_BIT(x) (((x) & 0x3f) << 6) -#define VDPU_REG_DEC_CTRL7_DCT7_START_BIT(x) (((x) & 0x3f) << 0) -#define VDPU_REG_ADDR_STR 0x030 -#define VDPU_REG_ADDR_DST 0x034 -#define VDPU_REG_ADDR_REF(i) (0x038 + ((i) * 0x4)) -#define VDPU_REG_ADDR_REF_FIELD_E BIT(1) -#define VDPU_REG_ADDR_REF_TOPC_E BIT(0) -#define VDPU_REG_REF_PIC(i) (0x078 + ((i) * 0x4)) -#define VDPU_REG_REF_PIC_FILT_TYPE_E BIT(31) -#define VDPU_REG_REF_PIC_FILT_SHARPNESS(x) (((x) & 0x7) << 28) -#define VDPU_REG_REF_PIC_MB_ADJ_0(x) (((x) & 0x7f) << 21) -#define VDPU_REG_REF_PIC_MB_ADJ_1(x) (((x) & 0x7f) << 14) -#define VDPU_REG_REF_PIC_MB_ADJ_2(x) (((x) & 0x7f) << 7) -#define VDPU_REG_REF_PIC_MB_ADJ_3(x) (((x) & 0x7f) << 0) -#define VDPU_REG_REF_PIC_REFER1_NBR(x) (((x) & 0xffff) << 16) -#define VDPU_REG_REF_PIC_REFER0_NBR(x) (((x) & 0xffff) << 0) -#define VDPU_REG_REF_PIC_LF_LEVEL_0(x) (((x) & 0x3f) << 18) -#define VDPU_REG_REF_PIC_LF_LEVEL_1(x) (((x) & 0x3f) << 12) -#define VDPU_REG_REF_PIC_LF_LEVEL_2(x) (((x) & 0x3f) << 6) -#define VDPU_REG_REF_PIC_LF_LEVEL_3(x) (((x) & 0x3f) << 0) -#define VDPU_REG_REF_PIC_QUANT_DELTA_0(x) (((x) & 0x1f) << 27) -#define VDPU_REG_REF_PIC_QUANT_DELTA_1(x) (((x) & 0x1f) << 22) -#define VDPU_REG_REF_PIC_QUANT_0(x) (((x) & 0x7ff) << 11) -#define VDPU_REG_REF_PIC_QUANT_1(x) (((x) & 0x7ff) << 0) -#define VDPU_REG_LT_REF 0x098 -#define VDPU_REG_VALID_REF 0x09c -#define VDPU_REG_ADDR_QTABLE 0x0a0 -#define VDPU_REG_ADDR_DIR_MV 0x0a4 -#define VDPU_REG_BD_REF_PIC(i) (0x0a8 + ((i) * 0x4)) -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_B2(x) (((x) & 0x1f) << 25) -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_F2(x) (((x) & 0x1f) << 20) -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_B1(x) (((x) & 0x1f) << 15) -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_F1(x) (((x) & 0x1f) << 10) -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_B0(x) (((x) & 0x1f) << 5) -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_F0(x) (((x) & 0x1f) << 0) -#define VDPU_REG_BD_REF_PIC_PRED_TAP_2_M1(x) (((x) & 0x3) << 10) -#define VDPU_REG_BD_REF_PIC_PRED_TAP_2_4(x) (((x) & 0x3) << 8) -#define VDPU_REG_BD_REF_PIC_PRED_TAP_4_M1(x) (((x) & 0x3) << 6) -#define VDPU_REG_BD_REF_PIC_PRED_TAP_4_4(x) (((x) & 0x3) << 4) -#define VDPU_REG_BD_REF_PIC_PRED_TAP_6_M1(x) (((x) & 0x3) << 2) -#define VDPU_REG_BD_REF_PIC_PRED_TAP_6_4(x) (((x) & 0x3) << 0) -#define VDPU_REG_BD_REF_PIC_QUANT_DELTA_2(x) (((x) & 0x1f) << 27) -#define VDPU_REG_BD_REF_PIC_QUANT_DELTA_3(x) (((x) & 0x1f) << 22) -#define VDPU_REG_BD_REF_PIC_QUANT_2(x) (((x) & 0x7ff) << 11) -#define VDPU_REG_BD_REF_PIC_QUANT_3(x) (((x) & 0x7ff) << 0) -#define VDPU_REG_BD_P_REF_PIC 0x0bc -#define VDPU_REG_BD_P_REF_PIC_QUANT_DELTA_4(x) (((x) & 0x1f) << 27) -#define VDPU_REG_BD_P_REF_PIC_PINIT_RLIST_F3(x) (((x) & 0x1f) << 25) -#define VDPU_REG_BD_P_REF_PIC_PINIT_RLIST_F2(x) (((x) & 0x1f) << 20) -#define VDPU_REG_BD_P_REF_PIC_PINIT_RLIST_F1(x) (((x) & 0x1f) << 15) -#define VDPU_REG_BD_P_REF_PIC_PINIT_RLIST_F0(x) (((x) & 0x1f) << 10) -#define VDPU_REG_BD_P_REF_PIC_BINIT_RLIST_B15(x) (((x) & 0x1f) << 5) -#define VDPU_REG_BD_P_REF_PIC_BINIT_RLIST_F15(x) (((x) & 0x1f) << 0) -#define VDPU_REG_ERR_CONC 0x0c0 -#define VDPU_REG_ERR_CONC_STARTMB_X(x) (((x) & 0x1ff) << 23) -#define VDPU_REG_ERR_CONC_STARTMB_Y(x) (((x) & 0xff) << 15) -#define VDPU_REG_PRED_FLT 0x0c4 -#define VDPU_REG_PRED_FLT_PRED_BC_TAP_0_0(x) (((x) & 0x3ff) << 22) -#define VDPU_REG_PRED_FLT_PRED_BC_TAP_0_1(x) (((x) & 0x3ff) << 12) -#define VDPU_REG_PRED_FLT_PRED_BC_TAP_0_2(x) (((x) & 0x3ff) << 2) -#define VDPU_REG_REF_BUF_CTRL 0x0cc -#define VDPU_REG_REF_BUF_CTRL_REFBU_E BIT(31) -#define VDPU_REG_REF_BUF_CTRL_REFBU_THR(x) (((x) & 0xfff) << 19) -#define VDPU_REG_REF_BUF_CTRL_REFBU_PICID(x) (((x) & 0x1f) << 14) -#define VDPU_REG_REF_BUF_CTRL_REFBU_EVAL_E BIT(13) -#define VDPU_REG_REF_BUF_CTRL_REFBU_FPARMOD_E BIT(12) -#define VDPU_REG_REF_BUF_CTRL_REFBU_Y_OFFSET(x) (((x) & 0x1ff) << 0) -#define VDPU_REG_REF_BUF_CTRL2 0x0dc -#define VDPU_REG_REF_BUF_CTRL2_REFBU2_BUF_E BIT(31) -#define VDPU_REG_REF_BUF_CTRL2_REFBU2_THR(x) (((x) & 0xfff) << 19) -#define VDPU_REG_REF_BUF_CTRL2_REFBU2_PICID(x) (((x) & 0x1f) << 14) -#define VDPU_REG_REF_BUF_CTRL2_APF_THRESHOLD(x) (((x) & 0x3fff) << 0) -#define VDPU_REG_SOFT_RESET 0x194 - -#endif /* RK3288_VPU_REGS_H_ */ diff --git a/drivers/staging/media/rockchip/vpu/rk3399_vpu_hw.c b/drivers/staging/media/rockchip/vpu/rk3399_vpu_hw.c deleted file mode 100644 index 2b3689968ef4..000000000000 --- a/drivers/staging/media/rockchip/vpu/rk3399_vpu_hw.c +++ /dev/null @@ -1,177 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Rockchip VPU codec driver - * - * Copyright (C) 2018 Rockchip Electronics Co., Ltd. - * Jeffy Chen - */ - -#include - -#include "rockchip_vpu.h" -#include "rockchip_vpu_jpeg.h" -#include "rk3399_vpu_regs.h" - -#define RK3399_ACLK_MAX_FREQ (400 * 1000 * 1000) - -/* - * Supported formats. - */ - -static const struct rockchip_vpu_fmt rk3399_vpu_enc_fmts[] = { - { - .fourcc = V4L2_PIX_FMT_YUV420M, - .codec_mode = RK_VPU_MODE_NONE, - .enc_fmt = RK3288_VPU_ENC_FMT_YUV420P, - }, - { - .fourcc = V4L2_PIX_FMT_NV12M, - .codec_mode = RK_VPU_MODE_NONE, - .enc_fmt = RK3288_VPU_ENC_FMT_YUV420SP, - }, - { - .fourcc = V4L2_PIX_FMT_YUYV, - .codec_mode = RK_VPU_MODE_NONE, - .enc_fmt = RK3288_VPU_ENC_FMT_YUYV422, - }, - { - .fourcc = V4L2_PIX_FMT_UYVY, - .codec_mode = RK_VPU_MODE_NONE, - .enc_fmt = RK3288_VPU_ENC_FMT_UYVY422, - }, - { - .fourcc = V4L2_PIX_FMT_JPEG, - .codec_mode = RK_VPU_MODE_JPEG_ENC, - .max_depth = 2, - .header_size = JPEG_HEADER_SIZE, - .frmsize = { - .min_width = 96, - .max_width = 8192, - .step_width = JPEG_MB_DIM, - .min_height = 32, - .max_height = 8192, - .step_height = JPEG_MB_DIM, - }, - }, -}; - -static const struct rockchip_vpu_fmt rk3399_vpu_dec_fmts[] = { - { - .fourcc = V4L2_PIX_FMT_NV12, - .codec_mode = RK_VPU_MODE_NONE, - }, - { - .fourcc = V4L2_PIX_FMT_MPEG2_SLICE, - .codec_mode = RK_VPU_MODE_MPEG2_DEC, - .max_depth = 2, - .frmsize = { - .min_width = 48, - .max_width = 1920, - .step_width = MPEG2_MB_DIM, - .min_height = 48, - .max_height = 1088, - .step_height = MPEG2_MB_DIM, - }, - }, -}; - -static irqreturn_t rk3399_vepu_irq(int irq, void *dev_id) -{ - struct rockchip_vpu_dev *vpu = dev_id; - enum vb2_buffer_state state; - u32 status, bytesused; - - status = vepu_read(vpu, VEPU_REG_INTERRUPT); - bytesused = vepu_read(vpu, VEPU_REG_STR_BUF_LIMIT) / 8; - state = (status & VEPU_REG_INTERRUPT_FRAME_READY) ? - VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR; - - vepu_write(vpu, 0, VEPU_REG_INTERRUPT); - vepu_write(vpu, 0, VEPU_REG_AXI_CTRL); - - rockchip_vpu_irq_done(vpu, bytesused, state); - - return IRQ_HANDLED; -} - -static irqreturn_t rk3399_vdpu_irq(int irq, void *dev_id) -{ - struct rockchip_vpu_dev *vpu = dev_id; - enum vb2_buffer_state state; - u32 status; - - status = vdpu_read(vpu, VDPU_REG_INTERRUPT); - state = (status & VDPU_REG_INTERRUPT_DEC_IRQ) ? - VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR; - - vdpu_write(vpu, 0, VDPU_REG_INTERRUPT); - vdpu_write(vpu, 0, VDPU_REG_AXI_CTRL); - - rockchip_vpu_irq_done(vpu, 0, state); - - return IRQ_HANDLED; -} - -static int rk3399_vpu_hw_init(struct rockchip_vpu_dev *vpu) -{ - /* Bump ACLK to max. possible freq. to improve performance. */ - clk_set_rate(vpu->clocks[0].clk, RK3399_ACLK_MAX_FREQ); - return 0; -} - -static void rk3399_vpu_enc_reset(struct rockchip_vpu_ctx *ctx) -{ - struct rockchip_vpu_dev *vpu = ctx->dev; - - vepu_write(vpu, VEPU_REG_INTERRUPT_DIS_BIT, VEPU_REG_INTERRUPT); - vepu_write(vpu, 0, VEPU_REG_ENCODE_START); - vepu_write(vpu, 0, VEPU_REG_AXI_CTRL); -} - -static void rk3399_vpu_dec_reset(struct rockchip_vpu_ctx *ctx) -{ - struct rockchip_vpu_dev *vpu = ctx->dev; - - vdpu_write(vpu, VDPU_REG_INTERRUPT_DEC_IRQ_DIS, VDPU_REG_INTERRUPT); - vdpu_write(vpu, 0, VDPU_REG_EN_FLAGS); - vdpu_write(vpu, 1, VDPU_REG_SOFT_RESET); -} - -/* - * Supported codec ops. - */ - -static const struct rockchip_vpu_codec_ops rk3399_vpu_codec_ops[] = { - [RK_VPU_MODE_JPEG_ENC] = { - .run = rk3399_vpu_jpeg_enc_run, - .reset = rk3399_vpu_enc_reset, - .init = rockchip_vpu_jpeg_enc_init, - .exit = rockchip_vpu_jpeg_enc_exit, - }, - [RK_VPU_MODE_MPEG2_DEC] = { - .run = rk3399_vpu_mpeg2_dec_run, - .reset = rk3399_vpu_dec_reset, - .init = rockchip_vpu_mpeg2_dec_init, - .exit = rockchip_vpu_mpeg2_dec_exit, - }, -}; - -/* - * VPU variant. - */ - -const struct rockchip_vpu_variant rk3399_vpu_variant = { - .enc_offset = 0x0, - .enc_fmts = rk3399_vpu_enc_fmts, - .num_enc_fmts = ARRAY_SIZE(rk3399_vpu_enc_fmts), - .dec_offset = 0x400, - .dec_fmts = rk3399_vpu_dec_fmts, - .num_dec_fmts = ARRAY_SIZE(rk3399_vpu_dec_fmts), - .codec = RK_VPU_JPEG_ENCODER | RK_VPU_MPEG2_DECODER, - .codec_ops = rk3399_vpu_codec_ops, - .vepu_irq = rk3399_vepu_irq, - .vdpu_irq = rk3399_vdpu_irq, - .init = rk3399_vpu_hw_init, - .clk_names = {"aclk", "hclk"}, - .num_clocks = 2 -}; diff --git a/drivers/staging/media/rockchip/vpu/rk3399_vpu_hw_jpeg_enc.c b/drivers/staging/media/rockchip/vpu/rk3399_vpu_hw_jpeg_enc.c deleted file mode 100644 index 460edc5ebe4d..000000000000 --- a/drivers/staging/media/rockchip/vpu/rk3399_vpu_hw_jpeg_enc.c +++ /dev/null @@ -1,165 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Rockchip VPU codec driver - * - * Copyright (C) 2018 Rockchip Electronics Co., Ltd. - * - * JPEG encoder - * ------------ - * The VPU JPEG encoder produces JPEG baseline sequential format. - * The quantization coefficients are 8-bit values, complying with - * the baseline specification. Therefore, it requires - * luma and chroma quantization tables. The hardware does entropy - * encoding using internal Huffman tables, as specified in the JPEG - * specification. - * - * In other words, only the luma and chroma quantization tables are - * required for the encoding operation. - * - * Quantization luma table values are written to registers - * VEPU_swreg_0-VEPU_swreg_15, and chroma table values to - * VEPU_swreg_16-VEPU_swreg_31. - * - * JPEG zigzag order is expected on the quantization tables. - */ - -#include -#include -#include "rockchip_vpu_jpeg.h" -#include "rockchip_vpu.h" -#include "rockchip_vpu_v4l2.h" -#include "rockchip_vpu_hw.h" -#include "rk3399_vpu_regs.h" - -#define VEPU_JPEG_QUANT_TABLE_COUNT 16 - -static void rk3399_vpu_set_src_img_ctrl(struct rockchip_vpu_dev *vpu, - struct rockchip_vpu_ctx *ctx) -{ - struct v4l2_pix_format_mplane *pix_fmt = &ctx->src_fmt; - u32 reg; - - /* - * The pix fmt width/height are already macroblock aligned - * by .vidioc_s_fmt_vid_cap_mplane() callback - */ - reg = VEPU_REG_IN_IMG_CTRL_ROW_LEN(pix_fmt->width); - vepu_write_relaxed(vpu, reg, VEPU_REG_INPUT_LUMA_INFO); - - reg = VEPU_REG_IN_IMG_CTRL_OVRFLR_D4(0) | - VEPU_REG_IN_IMG_CTRL_OVRFLB(0); - /* - * This register controls the input crop, as the offset - * from the right/bottom within the last macroblock. The offset from the - * right must be divided by 4 and so the crop must be aligned to 4 pixels - * horizontally. - */ - vepu_write_relaxed(vpu, reg, VEPU_REG_ENC_OVER_FILL_STRM_OFFSET); - - reg = VEPU_REG_IN_IMG_CTRL_FMT(ctx->vpu_src_fmt->enc_fmt); - vepu_write_relaxed(vpu, reg, VEPU_REG_ENC_CTRL1); -} - -static void rk3399_vpu_jpeg_enc_set_buffers(struct rockchip_vpu_dev *vpu, - struct rockchip_vpu_ctx *ctx, - struct vb2_buffer *src_buf) -{ - struct v4l2_pix_format_mplane *pix_fmt = &ctx->src_fmt; - dma_addr_t src[3]; - - WARN_ON(pix_fmt->num_planes > 3); - - vepu_write_relaxed(vpu, ctx->jpeg_enc.bounce_buffer.dma, - VEPU_REG_ADDR_OUTPUT_STREAM); - vepu_write_relaxed(vpu, ctx->jpeg_enc.bounce_buffer.size, - VEPU_REG_STR_BUF_LIMIT); - - if (pix_fmt->num_planes == 1) { - src[0] = vb2_dma_contig_plane_dma_addr(src_buf, 0); - vepu_write_relaxed(vpu, src[0], VEPU_REG_ADDR_IN_PLANE_0); - } else if (pix_fmt->num_planes == 2) { - src[0] = vb2_dma_contig_plane_dma_addr(src_buf, 0); - src[1] = vb2_dma_contig_plane_dma_addr(src_buf, 1); - vepu_write_relaxed(vpu, src[0], VEPU_REG_ADDR_IN_PLANE_0); - vepu_write_relaxed(vpu, src[1], VEPU_REG_ADDR_IN_PLANE_1); - } else { - src[0] = vb2_dma_contig_plane_dma_addr(src_buf, 0); - src[1] = vb2_dma_contig_plane_dma_addr(src_buf, 1); - src[2] = vb2_dma_contig_plane_dma_addr(src_buf, 2); - vepu_write_relaxed(vpu, src[0], VEPU_REG_ADDR_IN_PLANE_0); - vepu_write_relaxed(vpu, src[1], VEPU_REG_ADDR_IN_PLANE_1); - vepu_write_relaxed(vpu, src[2], VEPU_REG_ADDR_IN_PLANE_2); - } -} - -static void -rk3399_vpu_jpeg_enc_set_qtable(struct rockchip_vpu_dev *vpu, - unsigned char *luma_qtable, - unsigned char *chroma_qtable) -{ - u32 reg, i; - - for (i = 0; i < VEPU_JPEG_QUANT_TABLE_COUNT; i++) { - reg = get_unaligned_be32(&luma_qtable[i]); - vepu_write_relaxed(vpu, reg, VEPU_REG_JPEG_LUMA_QUAT(i)); - - reg = get_unaligned_be32(&chroma_qtable[i]); - vepu_write_relaxed(vpu, reg, VEPU_REG_JPEG_CHROMA_QUAT(i)); - } -} - -void rk3399_vpu_jpeg_enc_run(struct rockchip_vpu_ctx *ctx) -{ - struct rockchip_vpu_dev *vpu = ctx->dev; - struct vb2_v4l2_buffer *src_buf, *dst_buf; - struct rockchip_vpu_jpeg_ctx jpeg_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_req = src_buf->vb2_buf.req_obj.req; - v4l2_ctrl_request_setup(src_req, &ctx->ctrl_handler); - - 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; - jpeg_ctx.height = ctx->dst_fmt.height; - jpeg_ctx.quality = ctx->jpeg_quality; - rockchip_vpu_jpeg_header_assemble(&jpeg_ctx); - - /* Switch to JPEG encoder mode before writing registers */ - vepu_write_relaxed(vpu, VEPU_REG_ENCODE_FORMAT_JPEG, - VEPU_REG_ENCODE_START); - - rk3399_vpu_set_src_img_ctrl(vpu, ctx); - rk3399_vpu_jpeg_enc_set_buffers(vpu, ctx, &src_buf->vb2_buf); - rk3399_vpu_jpeg_enc_set_qtable(vpu, - rockchip_vpu_jpeg_get_qtable(&jpeg_ctx, 0), - rockchip_vpu_jpeg_get_qtable(&jpeg_ctx, 1)); - - reg = VEPU_REG_OUTPUT_SWAP32 - | VEPU_REG_OUTPUT_SWAP16 - | VEPU_REG_OUTPUT_SWAP8 - | VEPU_REG_INPUT_SWAP8 - | VEPU_REG_INPUT_SWAP16 - | VEPU_REG_INPUT_SWAP32; - /* Make sure that all registers are written at this point. */ - vepu_write(vpu, reg, VEPU_REG_DATA_ENDIAN); - - reg = VEPU_REG_AXI_CTRL_BURST_LEN(16); - vepu_write_relaxed(vpu, reg, VEPU_REG_AXI_CTRL); - - reg = VEPU_REG_MB_WIDTH(JPEG_MB_WIDTH(ctx->src_fmt.width)) - | VEPU_REG_MB_HEIGHT(JPEG_MB_HEIGHT(ctx->src_fmt.height)) - | VEPU_REG_FRAME_TYPE_INTRA - | 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)); - vepu_write(vpu, reg, VEPU_REG_ENCODE_START); -} diff --git a/drivers/staging/media/rockchip/vpu/rk3399_vpu_hw_mpeg2_dec.c b/drivers/staging/media/rockchip/vpu/rk3399_vpu_hw_mpeg2_dec.c deleted file mode 100644 index c4c092c2004a..000000000000 --- a/drivers/staging/media/rockchip/vpu/rk3399_vpu_hw_mpeg2_dec.c +++ /dev/null @@ -1,267 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Rockchip VPU codec driver - * - * Copyright (C) 2018 Rockchip Electronics Co., Ltd. - */ - -#include -#include -#include -#include "rockchip_vpu.h" -#include "rockchip_vpu_hw.h" - -#define VDPU_SWREG(nr) ((nr) * 4) - -#define VDPU_REG_DEC_OUT_BASE VDPU_SWREG(63) -#define VDPU_REG_RLC_VLC_BASE VDPU_SWREG(64) -#define VDPU_REG_QTABLE_BASE VDPU_SWREG(61) -#define VDPU_REG_REFER0_BASE VDPU_SWREG(131) -#define VDPU_REG_REFER2_BASE VDPU_SWREG(134) -#define VDPU_REG_REFER3_BASE VDPU_SWREG(135) -#define VDPU_REG_REFER1_BASE VDPU_SWREG(148) -#define VDPU_REG_DEC_E(v) ((v) ? BIT(0) : 0) - -#define VDPU_REG_DEC_ADV_PRE_DIS(v) ((v) ? BIT(11) : 0) -#define VDPU_REG_DEC_SCMD_DIS(v) ((v) ? BIT(10) : 0) -#define VDPU_REG_FILTERING_DIS(v) ((v) ? BIT(8) : 0) -#define VDPU_REG_DEC_LATENCY(v) (((v) << 1) & GENMASK(6, 1)) - -#define VDPU_REG_INIT_QP(v) (((v) << 25) & GENMASK(30, 25)) -#define VDPU_REG_STREAM_LEN(v) (((v) << 0) & GENMASK(23, 0)) - -#define VDPU_REG_APF_THRESHOLD(v) (((v) << 17) & GENMASK(30, 17)) -#define VDPU_REG_STARTMB_X(v) (((v) << 8) & GENMASK(16, 8)) -#define VDPU_REG_STARTMB_Y(v) (((v) << 0) & GENMASK(7, 0)) - -#define VDPU_REG_DEC_MODE(v) (((v) << 0) & GENMASK(3, 0)) - -#define VDPU_REG_DEC_STRENDIAN_E(v) ((v) ? BIT(5) : 0) -#define VDPU_REG_DEC_STRSWAP32_E(v) ((v) ? BIT(4) : 0) -#define VDPU_REG_DEC_OUTSWAP32_E(v) ((v) ? BIT(3) : 0) -#define VDPU_REG_DEC_INSWAP32_E(v) ((v) ? BIT(2) : 0) -#define VDPU_REG_DEC_OUT_ENDIAN(v) ((v) ? BIT(1) : 0) -#define VDPU_REG_DEC_IN_ENDIAN(v) ((v) ? BIT(0) : 0) - -#define VDPU_REG_DEC_DATA_DISC_E(v) ((v) ? BIT(22) : 0) -#define VDPU_REG_DEC_MAX_BURST(v) (((v) << 16) & GENMASK(20, 16)) -#define VDPU_REG_DEC_AXI_WR_ID(v) (((v) << 8) & GENMASK(15, 8)) -#define VDPU_REG_DEC_AXI_RD_ID(v) (((v) << 0) & GENMASK(7, 0)) - -#define VDPU_REG_RLC_MODE_E(v) ((v) ? BIT(20) : 0) -#define VDPU_REG_PIC_INTERLACE_E(v) ((v) ? BIT(17) : 0) -#define VDPU_REG_PIC_FIELDMODE_E(v) ((v) ? BIT(16) : 0) -#define VDPU_REG_PIC_B_E(v) ((v) ? BIT(15) : 0) -#define VDPU_REG_PIC_INTER_E(v) ((v) ? BIT(14) : 0) -#define VDPU_REG_PIC_TOPFIELD_E(v) ((v) ? BIT(13) : 0) -#define VDPU_REG_FWD_INTERLACE_E(v) ((v) ? BIT(12) : 0) -#define VDPU_REG_WRITE_MVS_E(v) ((v) ? BIT(10) : 0) -#define VDPU_REG_DEC_TIMEOUT_E(v) ((v) ? BIT(5) : 0) -#define VDPU_REG_DEC_CLK_GATE_E(v) ((v) ? BIT(4) : 0) - -#define VDPU_REG_PIC_MB_WIDTH(v) (((v) << 23) & GENMASK(31, 23)) -#define VDPU_REG_PIC_MB_HEIGHT_P(v) (((v) << 11) & GENMASK(18, 11)) -#define VDPU_REG_ALT_SCAN_E(v) ((v) ? BIT(6) : 0) -#define VDPU_REG_TOPFIELDFIRST_E(v) ((v) ? BIT(5) : 0) - -#define VDPU_REG_STRM_START_BIT(v) (((v) << 26) & GENMASK(31, 26)) -#define VDPU_REG_QSCALE_TYPE(v) ((v) ? BIT(24) : 0) -#define VDPU_REG_CON_MV_E(v) ((v) ? BIT(4) : 0) -#define VDPU_REG_INTRA_DC_PREC(v) (((v) << 2) & GENMASK(3, 2)) -#define VDPU_REG_INTRA_VLC_TAB(v) ((v) ? BIT(1) : 0) -#define VDPU_REG_FRAME_PRED_DCT(v) ((v) ? BIT(0) : 0) - -#define VDPU_REG_ALT_SCAN_FLAG_E(v) ((v) ? BIT(19) : 0) -#define VDPU_REG_FCODE_FWD_HOR(v) (((v) << 15) & GENMASK(18, 15)) -#define VDPU_REG_FCODE_FWD_VER(v) (((v) << 11) & GENMASK(14, 11)) -#define VDPU_REG_FCODE_BWD_HOR(v) (((v) << 7) & GENMASK(10, 7)) -#define VDPU_REG_FCODE_BWD_VER(v) (((v) << 3) & GENMASK(6, 3)) -#define VDPU_REG_MV_ACCURACY_FWD(v) ((v) ? BIT(2) : 0) -#define VDPU_REG_MV_ACCURACY_BWD(v) ((v) ? BIT(1) : 0) - -#define PICT_TOP_FIELD 1 -#define PICT_BOTTOM_FIELD 2 -#define PICT_FRAME 3 - -static void -rk3399_vpu_mpeg2_dec_set_quantization(struct rockchip_vpu_dev *vpu, - struct rockchip_vpu_ctx *ctx) -{ - struct v4l2_ctrl_mpeg2_quantization *quantization; - - quantization = rockchip_vpu_get_ctrl(ctx, - V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION); - rockchip_vpu_mpeg2_dec_copy_qtable(ctx->mpeg2_dec.qtable.cpu, - quantization); - vdpu_write_relaxed(vpu, ctx->mpeg2_dec.qtable.dma, - VDPU_REG_QTABLE_BASE); -} - -static void -rk3399_vpu_mpeg2_dec_set_buffers(struct rockchip_vpu_dev *vpu, - struct rockchip_vpu_ctx *ctx, - struct vb2_buffer *src_buf, - struct vb2_buffer *dst_buf, - const struct v4l2_mpeg2_sequence *sequence, - const struct v4l2_mpeg2_picture *picture, - const struct v4l2_ctrl_mpeg2_slice_params *slice_params) -{ - dma_addr_t forward_addr = 0, backward_addr = 0; - dma_addr_t current_addr, addr; - struct vb2_queue *vq; - - vq = v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx); - - switch (picture->picture_coding_type) { - case V4L2_MPEG2_PICTURE_CODING_TYPE_B: - backward_addr = rockchip_vpu_get_ref(vq, - slice_params->backward_ref_ts); - /* fall-through */ - case V4L2_MPEG2_PICTURE_CODING_TYPE_P: - forward_addr = rockchip_vpu_get_ref(vq, - slice_params->forward_ref_ts); - } - - /* Source bitstream buffer */ - addr = vb2_dma_contig_plane_dma_addr(src_buf, 0); - vdpu_write_relaxed(vpu, addr, VDPU_REG_RLC_VLC_BASE); - - /* Destination frame buffer */ - addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0); - current_addr = addr; - - if (picture->picture_structure == PICT_BOTTOM_FIELD) - addr += ALIGN(ctx->dst_fmt.width, 16); - vdpu_write_relaxed(vpu, addr, VDPU_REG_DEC_OUT_BASE); - - if (!forward_addr) - forward_addr = current_addr; - if (!backward_addr) - backward_addr = current_addr; - - /* Set forward ref frame (top/bottom field) */ - if (picture->picture_structure == PICT_FRAME || - picture->picture_coding_type == V4L2_MPEG2_PICTURE_CODING_TYPE_B || - (picture->picture_structure == PICT_TOP_FIELD && - picture->top_field_first) || - (picture->picture_structure == PICT_BOTTOM_FIELD && - !picture->top_field_first)) { - vdpu_write_relaxed(vpu, forward_addr, VDPU_REG_REFER0_BASE); - vdpu_write_relaxed(vpu, forward_addr, VDPU_REG_REFER1_BASE); - } else if (picture->picture_structure == PICT_TOP_FIELD) { - vdpu_write_relaxed(vpu, forward_addr, VDPU_REG_REFER0_BASE); - vdpu_write_relaxed(vpu, current_addr, VDPU_REG_REFER1_BASE); - } else if (picture->picture_structure == PICT_BOTTOM_FIELD) { - vdpu_write_relaxed(vpu, current_addr, VDPU_REG_REFER0_BASE); - vdpu_write_relaxed(vpu, forward_addr, VDPU_REG_REFER1_BASE); - } - - /* Set backward ref frame (top/bottom field) */ - vdpu_write_relaxed(vpu, backward_addr, VDPU_REG_REFER2_BASE); - vdpu_write_relaxed(vpu, backward_addr, VDPU_REG_REFER3_BASE); -} - -void rk3399_vpu_mpeg2_dec_run(struct rockchip_vpu_ctx *ctx) -{ - struct rockchip_vpu_dev *vpu = ctx->dev; - struct vb2_v4l2_buffer *src_buf, *dst_buf; - const struct v4l2_ctrl_mpeg2_slice_params *slice_params; - const struct v4l2_mpeg2_sequence *sequence; - 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); - - /* Apply request controls if any */ - v4l2_ctrl_request_setup(src_buf->vb2_buf.req_obj.req, - &ctx->ctrl_handler); - - slice_params = rockchip_vpu_get_ctrl(ctx, - V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS); - sequence = &slice_params->sequence; - picture = &slice_params->picture; - - reg = VDPU_REG_DEC_ADV_PRE_DIS(0) | - VDPU_REG_DEC_SCMD_DIS(0) | - VDPU_REG_FILTERING_DIS(1) | - VDPU_REG_DEC_LATENCY(0); - vdpu_write_relaxed(vpu, reg, VDPU_SWREG(50)); - - reg = VDPU_REG_INIT_QP(1) | - VDPU_REG_STREAM_LEN(slice_params->bit_size >> 3); - vdpu_write_relaxed(vpu, reg, VDPU_SWREG(51)); - - reg = VDPU_REG_APF_THRESHOLD(8) | - VDPU_REG_STARTMB_X(0) | - VDPU_REG_STARTMB_Y(0); - vdpu_write_relaxed(vpu, reg, VDPU_SWREG(52)); - - reg = VDPU_REG_DEC_MODE(5); - vdpu_write_relaxed(vpu, reg, VDPU_SWREG(53)); - - reg = VDPU_REG_DEC_STRENDIAN_E(1) | - VDPU_REG_DEC_STRSWAP32_E(1) | - VDPU_REG_DEC_OUTSWAP32_E(1) | - VDPU_REG_DEC_INSWAP32_E(1) | - VDPU_REG_DEC_OUT_ENDIAN(1) | - VDPU_REG_DEC_IN_ENDIAN(1); - vdpu_write_relaxed(vpu, reg, VDPU_SWREG(54)); - - reg = VDPU_REG_DEC_DATA_DISC_E(0) | - VDPU_REG_DEC_MAX_BURST(16) | - VDPU_REG_DEC_AXI_WR_ID(0) | - VDPU_REG_DEC_AXI_RD_ID(0); - vdpu_write_relaxed(vpu, reg, VDPU_SWREG(56)); - - reg = VDPU_REG_RLC_MODE_E(0) | - VDPU_REG_PIC_INTERLACE_E(!sequence->progressive_sequence) | - VDPU_REG_PIC_FIELDMODE_E(picture->picture_structure != PICT_FRAME) | - VDPU_REG_PIC_B_E(picture->picture_coding_type == V4L2_MPEG2_PICTURE_CODING_TYPE_B) | - VDPU_REG_PIC_INTER_E(picture->picture_coding_type != V4L2_MPEG2_PICTURE_CODING_TYPE_I) | - VDPU_REG_PIC_TOPFIELD_E(picture->picture_structure == PICT_TOP_FIELD) | - VDPU_REG_FWD_INTERLACE_E(0) | - VDPU_REG_WRITE_MVS_E(0) | - VDPU_REG_DEC_TIMEOUT_E(1) | - VDPU_REG_DEC_CLK_GATE_E(1); - vdpu_write_relaxed(vpu, reg, VDPU_SWREG(57)); - - reg = VDPU_REG_PIC_MB_WIDTH(MPEG2_MB_WIDTH(ctx->dst_fmt.width)) | - VDPU_REG_PIC_MB_HEIGHT_P(MPEG2_MB_HEIGHT(ctx->dst_fmt.height)) | - VDPU_REG_ALT_SCAN_E(picture->alternate_scan) | - VDPU_REG_TOPFIELDFIRST_E(picture->top_field_first); - vdpu_write_relaxed(vpu, reg, VDPU_SWREG(120)); - - reg = VDPU_REG_STRM_START_BIT(slice_params->data_bit_offset) | - VDPU_REG_QSCALE_TYPE(picture->q_scale_type) | - VDPU_REG_CON_MV_E(picture->concealment_motion_vectors) | - VDPU_REG_INTRA_DC_PREC(picture->intra_dc_precision) | - VDPU_REG_INTRA_VLC_TAB(picture->intra_vlc_format) | - VDPU_REG_FRAME_PRED_DCT(picture->frame_pred_frame_dct); - vdpu_write_relaxed(vpu, reg, VDPU_SWREG(122)); - - reg = VDPU_REG_ALT_SCAN_FLAG_E(picture->alternate_scan) | - VDPU_REG_FCODE_FWD_HOR(picture->f_code[0][0]) | - VDPU_REG_FCODE_FWD_VER(picture->f_code[0][1]) | - VDPU_REG_FCODE_BWD_HOR(picture->f_code[1][0]) | - VDPU_REG_FCODE_BWD_VER(picture->f_code[1][1]) | - VDPU_REG_MV_ACCURACY_FWD(1) | - VDPU_REG_MV_ACCURACY_BWD(1); - vdpu_write_relaxed(vpu, reg, VDPU_SWREG(136)); - - rk3399_vpu_mpeg2_dec_set_quantization(vpu, ctx); - - rk3399_vpu_mpeg2_dec_set_buffers(vpu, ctx, &src_buf->vb2_buf, - &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)); - - reg = vdpu_read(vpu, VDPU_SWREG(57)) | VDPU_REG_DEC_E(1); - vdpu_write(vpu, reg, VDPU_SWREG(57)); -} diff --git a/drivers/staging/media/rockchip/vpu/rk3399_vpu_regs.h b/drivers/staging/media/rockchip/vpu/rk3399_vpu_regs.h deleted file mode 100644 index fbe294177ec9..000000000000 --- a/drivers/staging/media/rockchip/vpu/rk3399_vpu_regs.h +++ /dev/null @@ -1,600 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Rockchip VPU codec driver - * - * Copyright (C) 2018 Rockchip Electronics Co., Ltd. - * Alpha Lin - */ - -#ifndef RK3399_VPU_REGS_H_ -#define RK3399_VPU_REGS_H_ - -/* Encoder registers. */ -#define VEPU_REG_VP8_QUT_1ST(i) (0x000 + ((i) * 0x24)) -#define VEPU_REG_VP8_QUT_DC_Y2(x) (((x) & 0x3fff) << 16) -#define VEPU_REG_VP8_QUT_DC_Y1(x) (((x) & 0x3fff) << 0) -#define VEPU_REG_VP8_QUT_2ND(i) (0x004 + ((i) * 0x24)) -#define VEPU_REG_VP8_QUT_AC_Y1(x) (((x) & 0x3fff) << 16) -#define VEPU_REG_VP8_QUT_DC_CHR(x) (((x) & 0x3fff) << 0) -#define VEPU_REG_VP8_QUT_3RD(i) (0x008 + ((i) * 0x24)) -#define VEPU_REG_VP8_QUT_AC_CHR(x) (((x) & 0x3fff) << 16) -#define VEPU_REG_VP8_QUT_AC_Y2(x) (((x) & 0x3fff) << 0) -#define VEPU_REG_VP8_QUT_4TH(i) (0x00c + ((i) * 0x24)) -#define VEPU_REG_VP8_QUT_ZB_DC_CHR(x) (((x) & 0x1ff) << 18) -#define VEPU_REG_VP8_QUT_ZB_DC_Y2(x) (((x) & 0x1ff) << 9) -#define VEPU_REG_VP8_QUT_ZB_DC_Y1(x) (((x) & 0x1ff) << 0) -#define VEPU_REG_VP8_QUT_5TH(i) (0x010 + ((i) * 0x24)) -#define VEPU_REG_VP8_QUT_ZB_AC_CHR(x) (((x) & 0x1ff) << 18) -#define VEPU_REG_VP8_QUT_ZB_AC_Y2(x) (((x) & 0x1ff) << 9) -#define VEPU_REG_VP8_QUT_ZB_AC_Y1(x) (((x) & 0x1ff) << 0) -#define VEPU_REG_VP8_QUT_6TH(i) (0x014 + ((i) * 0x24)) -#define VEPU_REG_VP8_QUT_RND_DC_CHR(x) (((x) & 0xff) << 16) -#define VEPU_REG_VP8_QUT_RND_DC_Y2(x) (((x) & 0xff) << 8) -#define VEPU_REG_VP8_QUT_RND_DC_Y1(x) (((x) & 0xff) << 0) -#define VEPU_REG_VP8_QUT_7TH(i) (0x018 + ((i) * 0x24)) -#define VEPU_REG_VP8_QUT_RND_AC_CHR(x) (((x) & 0xff) << 16) -#define VEPU_REG_VP8_QUT_RND_AC_Y2(x) (((x) & 0xff) << 8) -#define VEPU_REG_VP8_QUT_RND_AC_Y1(x) (((x) & 0xff) << 0) -#define VEPU_REG_VP8_QUT_8TH(i) (0x01c + ((i) * 0x24)) -#define VEPU_REG_VP8_SEG_FILTER_LEVEL(x) (((x) & 0x3f) << 25) -#define VEPU_REG_VP8_DEQUT_DC_CHR(x) (((x) & 0xff) << 17) -#define VEPU_REG_VP8_DEQUT_DC_Y2(x) (((x) & 0x1ff) << 8) -#define VEPU_REG_VP8_DEQUT_DC_Y1(x) (((x) & 0xff) << 0) -#define VEPU_REG_VP8_QUT_9TH(i) (0x020 + ((i) * 0x24)) -#define VEPU_REG_VP8_DEQUT_AC_CHR(x) (((x) & 0x1ff) << 18) -#define VEPU_REG_VP8_DEQUT_AC_Y2(x) (((x) & 0x1ff) << 9) -#define VEPU_REG_VP8_DEQUT_AC_Y1(x) (((x) & 0x1ff) << 0) -#define VEPU_REG_ADDR_VP8_SEG_MAP 0x06c -#define VEPU_REG_VP8_INTRA_4X4_PENALTY(i) (0x070 + ((i) * 0x4)) -#define VEPU_REG_VP8_INTRA_4X4_PENALTY_0(x) (((x) & 0xfff) << 0) -#define VEPU_REG_VP8_INTRA_4x4_PENALTY_1(x) (((x) & 0xfff) << 16) -#define VEPU_REG_VP8_INTRA_16X16_PENALTY(i) (0x084 + ((i) * 0x4)) -#define VEPU_REG_VP8_INTRA_16X16_PENALTY_0(x) (((x) & 0xfff) << 0) -#define VEPU_REG_VP8_INTRA_16X16_PENALTY_1(x) (((x) & 0xfff) << 16) -#define VEPU_REG_VP8_CONTROL 0x0a0 -#define VEPU_REG_VP8_LF_MODE_DELTA_BPRED(x) (((x) & 0x1f) << 24) -#define VEPU_REG_VP8_LF_REF_DELTA_INTRA_MB(x) (((x) & 0x7f) << 16) -#define VEPU_REG_VP8_INTER_TYPE_BIT_COST(x) (((x) & 0xfff) << 0) -#define VEPU_REG_VP8_REF_FRAME_VAL 0x0a4 -#define VEPU_REG_VP8_COEF_DMV_PENALTY(x) (((x) & 0xfff) << 16) -#define VEPU_REG_VP8_REF_FRAME(x) (((x) & 0xfff) << 0) -#define VEPU_REG_VP8_LOOP_FILTER_REF_DELTA 0x0a8 -#define VEPU_REG_VP8_LF_REF_DELTA_ALT_REF(x) (((x) & 0x7f) << 16) -#define VEPU_REG_VP8_LF_REF_DELTA_LAST_REF(x) (((x) & 0x7f) << 8) -#define VEPU_REG_VP8_LF_REF_DELTA_GOLDEN(x) (((x) & 0x7f) << 0) -#define VEPU_REG_VP8_LOOP_FILTER_MODE_DELTA 0x0ac -#define VEPU_REG_VP8_LF_MODE_DELTA_SPLITMV(x) (((x) & 0x7f) << 16) -#define VEPU_REG_VP8_LF_MODE_DELTA_ZEROMV(x) (((x) & 0x7f) << 8) -#define VEPU_REG_VP8_LF_MODE_DELTA_NEWMV(x) (((x) & 0x7f) << 0) -#define VEPU_REG_JPEG_LUMA_QUAT(i) (0x000 + ((i) * 0x4)) -#define VEPU_REG_JPEG_CHROMA_QUAT(i) (0x040 + ((i) * 0x4)) -#define VEPU_REG_INTRA_SLICE_BITMAP(i) (0x0b0 + ((i) * 0x4)) -#define VEPU_REG_ADDR_VP8_DCT_PART(i) (0x0b0 + ((i) * 0x4)) -#define VEPU_REG_INTRA_AREA_CTRL 0x0b8 -#define VEPU_REG_INTRA_AREA_TOP(x) (((x) & 0xff) << 24) -#define VEPU_REG_INTRA_AREA_BOTTOM(x) (((x) & 0xff) << 16) -#define VEPU_REG_INTRA_AREA_LEFT(x) (((x) & 0xff) << 8) -#define VEPU_REG_INTRA_AREA_RIGHT(x) (((x) & 0xff) << 0) -#define VEPU_REG_CIR_INTRA_CTRL 0x0bc -#define VEPU_REG_CIR_INTRA_FIRST_MB(x) (((x) & 0xffff) << 16) -#define VEPU_REG_CIR_INTRA_INTERVAL(x) (((x) & 0xffff) << 0) -#define VEPU_REG_ADDR_IN_PLANE_0 0x0c0 -#define VEPU_REG_ADDR_IN_PLANE_1 0x0c4 -#define VEPU_REG_ADDR_IN_PLANE_2 0x0c8 -#define VEPU_REG_STR_HDR_REM_MSB 0x0cc -#define VEPU_REG_STR_HDR_REM_LSB 0x0d0 -#define VEPU_REG_STR_BUF_LIMIT 0x0d4 -#define VEPU_REG_AXI_CTRL 0x0d8 -#define VEPU_REG_AXI_CTRL_READ_ID(x) (((x) & 0xff) << 24) -#define VEPU_REG_AXI_CTRL_WRITE_ID(x) (((x) & 0xff) << 16) -#define VEPU_REG_AXI_CTRL_BURST_LEN(x) (((x) & 0x3f) << 8) -#define VEPU_REG_AXI_CTRL_INCREMENT_MODE(x) (((x) & 0x01) << 2) -#define VEPU_REG_AXI_CTRL_BIRST_DISCARD(x) (((x) & 0x01) << 1) -#define VEPU_REG_AXI_CTRL_BIRST_DISABLE BIT(0) -#define VEPU_QP_ADJUST_MAD_DELTA_ROI 0x0dc -#define VEPU_REG_ROI_QP_DELTA_1 (((x) & 0xf) << 12) -#define VEPU_REG_ROI_QP_DELTA_2 (((x) & 0xf) << 8) -#define VEPU_REG_MAD_QP_ADJUSTMENT (((x) & 0xf) << 0) -#define VEPU_REG_ADDR_REF_LUMA 0x0e0 -#define VEPU_REG_ADDR_REF_CHROMA 0x0e4 -#define VEPU_REG_QP_SUM_DIV2 0x0e8 -#define VEPU_REG_QP_SUM(x) (((x) & 0x001fffff) * 2) -#define VEPU_REG_ENC_CTRL0 0x0ec -#define VEPU_REG_DISABLE_QUARTER_PIXEL_MV BIT(28) -#define VEPU_REG_DEBLOCKING_FILTER_MODE(x) (((x) & 0x3) << 24) -#define VEPU_REG_CABAC_INIT_IDC(x) (((x) & 0x3) << 21) -#define VEPU_REG_ENTROPY_CODING_MODE BIT(20) -#define VEPU_REG_H264_TRANS8X8_MODE BIT(17) -#define VEPU_REG_H264_INTER4X4_MODE BIT(16) -#define VEPU_REG_H264_STREAM_MODE BIT(15) -#define VEPU_REG_H264_SLICE_SIZE(x) (((x) & 0x7f) << 8) -#define VEPU_REG_ENC_OVER_FILL_STRM_OFFSET 0x0f0 -#define VEPU_REG_STREAM_START_OFFSET(x) (((x) & 0x3f) << 16) -#define VEPU_REG_SKIP_MACROBLOCK_PENALTY(x) (((x) & 0xff) << 8) -#define VEPU_REG_IN_IMG_CTRL_OVRFLR_D4(x) (((x) & 0x3) << 4) -#define VEPU_REG_IN_IMG_CTRL_OVRFLB(x) (((x) & 0xf) << 0) -#define VEPU_REG_INPUT_LUMA_INFO 0x0f4 -#define VEPU_REG_IN_IMG_CHROMA_OFFSET(x) (((x) & 0x7) << 20) -#define VEPU_REG_IN_IMG_LUMA_OFFSET(x) (((x) & 0x7) << 16) -#define VEPU_REG_IN_IMG_CTRL_ROW_LEN(x) (((x) & 0x3fff) << 0) -#define VEPU_REG_RLC_SUM 0x0f8 -#define VEPU_REG_RLC_SUM_OUT(x) (((x) & 0x007fffff) * 4) -#define VEPU_REG_SPLIT_PENALTY_4X4 0x0f8 -#define VEPU_REG_VP8_SPLIT_PENALTY_4X4 (((x) & 0x1ff) << 19) -#define VEPU_REG_ADDR_REC_LUMA 0x0fc -#define VEPU_REG_ADDR_REC_CHROMA 0x100 -#define VEPU_REG_CHECKPOINT(i) (0x104 + ((i) * 0x4)) -#define VEPU_REG_CHECKPOINT_CHECK0(x) (((x) & 0xffff)) -#define VEPU_REG_CHECKPOINT_CHECK1(x) (((x) & 0xffff) << 16) -#define VEPU_REG_CHECKPOINT_RESULT(x) \ - ((((x) >> (16 - 16 * ((i) & 1))) & 0xffff) * 32) -#define VEPU_REG_VP8_SEG0_QUANT_AC_Y1 0x104 -#define VEPU_REG_VP8_SEG0_RND_AC_Y1(x) (((x) & 0xff) << 23) -#define VEPU_REG_VP8_SEG0_ZBIN_AC_Y1(x) (((x) & 0x1ff) << 14) -#define VEPU_REG_VP8_SEG0_QUT_AC_Y1(x) (((x) & 0x3fff) << 0) -#define VEPU_REG_VP8_SEG0_QUANT_DC_Y2 0x108 -#define VEPU_REG_VP8_SEG0_RND_DC_Y2(x) (((x) & 0xff) << 23) -#define VEPU_REG_VP8_SEG0_ZBIN_DC_Y2(x) (((x) & 0x1ff) << 14) -#define VEPU_REG_VP8_SEG0_QUT_DC_Y2(x) (((x) & 0x3fff) << 0) -#define VEPU_REG_VP8_SEG0_QUANT_AC_Y2 0x10c -#define VEPU_REG_VP8_SEG0_RND_AC_Y2(x) (((x) & 0xff) << 23) -#define VEPU_REG_VP8_SEG0_ZBIN_AC_Y2(x) (((x) & 0x1ff) << 14) -#define VEPU_REG_VP8_SEG0_QUT_AC_Y2(x) (((x) & 0x3fff) << 0) -#define VEPU_REG_VP8_SEG0_QUANT_DC_CHR 0x110 -#define VEPU_REG_VP8_SEG0_RND_DC_CHR(x) (((x) & 0xff) << 23) -#define VEPU_REG_VP8_SEG0_ZBIN_DC_CHR(x) (((x) & 0x1ff) << 14) -#define VEPU_REG_VP8_SEG0_QUT_DC_CHR(x) (((x) & 0x3fff) << 0) -#define VEPU_REG_VP8_SEG0_QUANT_AC_CHR 0x114 -#define VEPU_REG_VP8_SEG0_RND_AC_CHR(x) (((x) & 0xff) << 23) -#define VEPU_REG_VP8_SEG0_ZBIN_AC_CHR(x) (((x) & 0x1ff) << 14) -#define VEPU_REG_VP8_SEG0_QUT_AC_CHR(x) (((x) & 0x3fff) << 0) -#define VEPU_REG_VP8_SEG0_QUANT_DQUT 0x118 -#define VEPU_REG_VP8_MV_REF_IDX1(x) (((x) & 0x03) << 26) -#define VEPU_REG_VP8_SEG0_DQUT_DC_Y2(x) (((x) & 0x1ff) << 17) -#define VEPU_REG_VP8_SEG0_DQUT_AC_Y1(x) (((x) & 0x1ff) << 8) -#define VEPU_REG_VP8_SEG0_DQUT_DC_Y1(x) (((x) & 0xff) << 0) -#define VEPU_REG_CHKPT_WORD_ERR(i) (0x118 + ((i) * 0x4)) -#define VEPU_REG_CHKPT_WORD_ERR_CHK0(x) (((x) & 0xffff)) -#define VEPU_REG_CHKPT_WORD_ERR_CHK1(x) (((x) & 0xffff) << 16) -#define VEPU_REG_VP8_SEG0_QUANT_DQUT_1 0x11c -#define VEPU_REG_VP8_SEGMENT_MAP_UPDATE BIT(30) -#define VEPU_REG_VP8_SEGMENT_EN BIT(29) -#define VEPU_REG_VP8_MV_REF_IDX2_EN BIT(28) -#define VEPU_REG_VP8_MV_REF_IDX2(x) (((x) & 0x03) << 26) -#define VEPU_REG_VP8_SEG0_DQUT_AC_CHR(x) (((x) & 0x1ff) << 17) -#define VEPU_REG_VP8_SEG0_DQUT_DC_CHR(x) (((x) & 0xff) << 9) -#define VEPU_REG_VP8_SEG0_DQUT_AC_Y2(x) (((x) & 0x1ff) << 0) -#define VEPU_REG_VP8_BOOL_ENC_VALUE 0x120 -#define VEPU_REG_CHKPT_DELTA_QP 0x124 -#define VEPU_REG_CHKPT_DELTA_QP_CHK0(x) (((x) & 0x0f) << 0) -#define VEPU_REG_CHKPT_DELTA_QP_CHK1(x) (((x) & 0x0f) << 4) -#define VEPU_REG_CHKPT_DELTA_QP_CHK2(x) (((x) & 0x0f) << 8) -#define VEPU_REG_CHKPT_DELTA_QP_CHK3(x) (((x) & 0x0f) << 12) -#define VEPU_REG_CHKPT_DELTA_QP_CHK4(x) (((x) & 0x0f) << 16) -#define VEPU_REG_CHKPT_DELTA_QP_CHK5(x) (((x) & 0x0f) << 20) -#define VEPU_REG_CHKPT_DELTA_QP_CHK6(x) (((x) & 0x0f) << 24) -#define VEPU_REG_VP8_ENC_CTRL2 0x124 -#define VEPU_REG_VP8_ZERO_MV_PENALTY_FOR_REF2(x) (((x) & 0xff) << 24) -#define VEPU_REG_VP8_FILTER_SHARPNESS(x) (((x) & 0x07) << 21) -#define VEPU_REG_VP8_FILTER_LEVEL(x) (((x) & 0x3f) << 15) -#define VEPU_REG_VP8_DCT_PARTITION_CNT(x) (((x) & 0x03) << 13) -#define VEPU_REG_VP8_BOOL_ENC_VALUE_BITS(x) (((x) & 0x1f) << 8) -#define VEPU_REG_VP8_BOOL_ENC_RANGE(x) (((x) & 0xff) << 0) -#define VEPU_REG_ENC_CTRL1 0x128 -#define VEPU_REG_MAD_THRESHOLD(x) (((x) & 0x3f) << 24) -#define VEPU_REG_COMPLETED_SLICES(x) (((x) & 0xff) << 16) -#define VEPU_REG_IN_IMG_CTRL_FMT(x) (((x) & 0xf) << 4) -#define VEPU_REG_IN_IMG_ROTATE_MODE(x) (((x) & 0x3) << 2) -#define VEPU_REG_SIZE_TABLE_PRESENT BIT(0) -#define VEPU_REG_INTRA_INTER_MODE 0x12c -#define VEPU_REG_INTRA16X16_MODE(x) (((x) & 0xffff) << 16) -#define VEPU_REG_INTER_MODE(x) (((x) & 0xffff) << 0) -#define VEPU_REG_ENC_CTRL2 0x130 -#define VEPU_REG_PPS_INIT_QP(x) (((x) & 0x3f) << 26) -#define VEPU_REG_SLICE_FILTER_ALPHA(x) (((x) & 0xf) << 22) -#define VEPU_REG_SLICE_FILTER_BETA(x) (((x) & 0xf) << 18) -#define VEPU_REG_CHROMA_QP_OFFSET(x) (((x) & 0x1f) << 13) -#define VEPU_REG_FILTER_DISABLE BIT(5) -#define VEPU_REG_IDR_PIC_ID(x) (((x) & 0xf) << 1) -#define VEPU_REG_CONSTRAINED_INTRA_PREDICTION BIT(0) -#define VEPU_REG_ADDR_OUTPUT_STREAM 0x134 -#define VEPU_REG_ADDR_OUTPUT_CTRL 0x138 -#define VEPU_REG_ADDR_NEXT_PIC 0x13c -#define VEPU_REG_ADDR_MV_OUT 0x140 -#define VEPU_REG_ADDR_CABAC_TBL 0x144 -#define VEPU_REG_ROI1 0x148 -#define VEPU_REG_ROI1_TOP_MB(x) (((x) & 0xff) << 24) -#define VEPU_REG_ROI1_BOTTOM_MB(x) (((x) & 0xff) << 16) -#define VEPU_REG_ROI1_LEFT_MB(x) (((x) & 0xff) << 8) -#define VEPU_REG_ROI1_RIGHT_MB(x) (((x) & 0xff) << 0) -#define VEPU_REG_ROI2 0x14c -#define VEPU_REG_ROI2_TOP_MB(x) (((x) & 0xff) << 24) -#define VEPU_REG_ROI2_BOTTOM_MB(x) (((x) & 0xff) << 16) -#define VEPU_REG_ROI2_LEFT_MB(x) (((x) & 0xff) << 8) -#define VEPU_REG_ROI2_RIGHT_MB(x) (((x) & 0xff) << 0) -#define VEPU_REG_STABLE_MATRIX(i) (0x150 + ((i) * 0x4)) -#define VEPU_REG_STABLE_MOTION_SUM 0x174 -#define VEPU_REG_STABILIZATION_OUTPUT 0x178 -#define VEPU_REG_STABLE_MIN_VALUE(x) (((x) & 0xffffff) << 8) -#define VEPU_REG_STABLE_MODE_SEL(x) (((x) & 0x3) << 6) -#define VEPU_REG_STABLE_HOR_GMV(x) (((x) & 0x3f) << 0) -#define VEPU_REG_RGB2YUV_CONVERSION_COEF1 0x17c -#define VEPU_REG_RGB2YUV_CONVERSION_COEFB(x) (((x) & 0xffff) << 16) -#define VEPU_REG_RGB2YUV_CONVERSION_COEFA(x) (((x) & 0xffff) << 0) -#define VEPU_REG_RGB2YUV_CONVERSION_COEF2 0x180 -#define VEPU_REG_RGB2YUV_CONVERSION_COEFE(x) (((x) & 0xffff) << 16) -#define VEPU_REG_RGB2YUV_CONVERSION_COEFC(x) (((x) & 0xffff) << 0) -#define VEPU_REG_RGB2YUV_CONVERSION_COEF3 0x184 -#define VEPU_REG_RGB2YUV_CONVERSION_COEFF(x) (((x) & 0xffff) << 0) -#define VEPU_REG_RGB_MASK_MSB 0x188 -#define VEPU_REG_RGB_MASK_B_MSB(x) (((x) & 0x1f) << 16) -#define VEPU_REG_RGB_MASK_G_MSB(x) (((x) & 0x1f) << 8) -#define VEPU_REG_RGB_MASK_R_MSB(x) (((x) & 0x1f) << 0) -#define VEPU_REG_MV_PENALTY 0x18c -#define VEPU_REG_1MV_PENALTY(x) (((x) & 0x3ff) << 21) -#define VEPU_REG_QMV_PENALTY(x) (((x) & 0x3ff) << 11) -#define VEPU_REG_4MV_PENALTY(x) (((x) & 0x3ff) << 1) -#define VEPU_REG_SPLIT_MV_MODE_EN BIT(0) -#define VEPU_REG_QP_VAL 0x190 -#define VEPU_REG_H264_LUMA_INIT_QP(x) (((x) & 0x3f) << 26) -#define VEPU_REG_H264_QP_MAX(x) (((x) & 0x3f) << 20) -#define VEPU_REG_H264_QP_MIN(x) (((x) & 0x3f) << 14) -#define VEPU_REG_H264_CHKPT_DISTANCE(x) (((x) & 0xfff) << 0) -#define VEPU_REG_VP8_SEG0_QUANT_DC_Y1 0x190 -#define VEPU_REG_VP8_SEG0_RND_DC_Y1(x) (((x) & 0xff) << 23) -#define VEPU_REG_VP8_SEG0_ZBIN_DC_Y1(x) (((x) & 0x1ff) << 14) -#define VEPU_REG_VP8_SEG0_QUT_DC_Y1(x) (((x) & 0x3fff) << 0) -#define VEPU_REG_MVC_RELATE 0x198 -#define VEPU_REG_ZERO_MV_FAVOR_D2(x) (((x) & 0xf) << 20) -#define VEPU_REG_PENALTY_4X4MV(x) (((x) & 0x1ff) << 11) -#define VEPU_REG_MVC_VIEW_ID(x) (((x) & 0x7) << 8) -#define VEPU_REG_MVC_ANCHOR_PIC_FLAG BIT(7) -#define VEPU_REG_MVC_PRIORITY_ID(x) (((x) & 0x7) << 4) -#define VEPU_REG_MVC_TEMPORAL_ID(x) (((x) & 0x7) << 1) -#define VEPU_REG_MVC_INTER_VIEW_FLAG BIT(0) -#define VEPU_REG_ENCODE_START 0x19c -#define VEPU_REG_MB_HEIGHT(x) (((x) & 0x1ff) << 20) -#define VEPU_REG_MB_WIDTH(x) (((x) & 0x1ff) << 8) -#define VEPU_REG_FRAME_TYPE_INTER (0x0 << 6) -#define VEPU_REG_FRAME_TYPE_INTRA (0x1 << 6) -#define VEPU_REG_FRAME_TYPE_MVCINTER (0x2 << 6) -#define VEPU_REG_ENCODE_FORMAT_JPEG (0x2 << 4) -#define VEPU_REG_ENCODE_FORMAT_H264 (0x3 << 4) -#define VEPU_REG_ENCODE_ENABLE BIT(0) -#define VEPU_REG_MB_CTRL 0x1a0 -#define VEPU_REG_MB_CNT_OUT(x) (((x) & 0xffff) << 16) -#define VEPU_REG_MB_CNT_SET(x) (((x) & 0xffff) << 0) -#define VEPU_REG_DATA_ENDIAN 0x1a4 -#define VEPU_REG_INPUT_SWAP8 BIT(31) -#define VEPU_REG_INPUT_SWAP16 BIT(30) -#define VEPU_REG_INPUT_SWAP32 BIT(29) -#define VEPU_REG_OUTPUT_SWAP8 BIT(28) -#define VEPU_REG_OUTPUT_SWAP16 BIT(27) -#define VEPU_REG_OUTPUT_SWAP32 BIT(26) -#define VEPU_REG_TEST_IRQ BIT(24) -#define VEPU_REG_TEST_COUNTER(x) (((x) & 0xf) << 20) -#define VEPU_REG_TEST_REG BIT(19) -#define VEPU_REG_TEST_MEMORY BIT(18) -#define VEPU_REG_TEST_LEN(x) (((x) & 0x3ffff) << 0) -#define VEPU_REG_ENC_CTRL3 0x1a8 -#define VEPU_REG_PPS_ID(x) (((x) & 0xff) << 24) -#define VEPU_REG_INTRA_PRED_MODE(x) (((x) & 0xff) << 16) -#define VEPU_REG_FRAME_NUM(x) (((x) & 0xffff) << 0) -#define VEPU_REG_ENC_CTRL4 0x1ac -#define VEPU_REG_MV_PENALTY_16X8_8X16(x) (((x) & 0x3ff) << 20) -#define VEPU_REG_MV_PENALTY_8X8(x) (((x) & 0x3ff) << 10) -#define VEPU_REG_MV_PENALTY_8X4_4X8(x) (((x) & 0x3ff) << 0) -#define VEPU_REG_ADDR_VP8_PROB_CNT 0x1b0 -#define VEPU_REG_INTERRUPT 0x1b4 -#define VEPU_REG_INTERRUPT_NON BIT(28) -#define VEPU_REG_MV_WRITE_EN BIT(24) -#define VEPU_REG_RECON_WRITE_DIS BIT(20) -#define VEPU_REG_INTERRUPT_SLICE_READY_EN BIT(16) -#define VEPU_REG_CLK_GATING_EN BIT(12) -#define VEPU_REG_INTERRUPT_TIMEOUT_EN BIT(10) -#define VEPU_REG_INTERRUPT_RESET BIT(9) -#define VEPU_REG_INTERRUPT_DIS_BIT BIT(8) -#define VEPU_REG_INTERRUPT_TIMEOUT BIT(6) -#define VEPU_REG_INTERRUPT_BUFFER_FULL BIT(5) -#define VEPU_REG_INTERRUPT_BUS_ERROR BIT(4) -#define VEPU_REG_INTERRUPT_FUSE BIT(3) -#define VEPU_REG_INTERRUPT_SLICE_READY BIT(2) -#define VEPU_REG_INTERRUPT_FRAME_READY BIT(1) -#define VEPU_REG_INTERRUPT_BIT BIT(0) -#define VEPU_REG_DMV_PENALTY_TBL(i) (0x1E0 + ((i) * 0x4)) -#define VEPU_REG_DMV_PENALTY_TABLE_BIT(x, i) ((x) << (i) * 8) -#define VEPU_REG_DMV_Q_PIXEL_PENALTY_TBL(i) (0x260 + ((i) * 0x4)) -#define VEPU_REG_DMV_Q_PIXEL_PENALTY_TABLE_BIT(x, i) ((x) << (i) * 8) - -/* vpu decoder register */ -#define VDPU_REG_DEC_CTRL0 0x0c8 // 50 -#define VDPU_REG_REF_BUF_CTRL2_REFBU2_PICID(x) (((x) & 0x1f) << 25) -#define VDPU_REG_REF_BUF_CTRL2_REFBU2_THR(x) (((x) & 0xfff) << 13) -#define VDPU_REG_CONFIG_TILED_MODE_LSB BIT(12) -#define VDPU_REG_CONFIG_DEC_ADV_PRE_DIS BIT(11) -#define VDPU_REG_CONFIG_DEC_SCMD_DIS BIT(10) -#define VDPU_REG_DEC_CTRL0_SKIP_MODE BIT(9) -#define VDPU_REG_DEC_CTRL0_FILTERING_DIS BIT(8) -#define VDPU_REG_DEC_CTRL0_PIC_FIXED_QUANT BIT(7) -#define VDPU_REG_CONFIG_DEC_LATENCY(x) (((x) & 0x3f) << 1) -#define VDPU_REG_CONFIG_TILED_MODE_MSB(x) BIT(0) -#define VDPU_REG_CONFIG_DEC_OUT_TILED_E BIT(0) -#define VDPU_REG_STREAM_LEN 0x0cc -#define VDPU_REG_DEC_CTRL3_INIT_QP(x) (((x) & 0x3f) << 25) -#define VDPU_REG_DEC_STREAM_LEN_HI BIT(24) -#define VDPU_REG_DEC_CTRL3_STREAM_LEN(x) (((x) & 0xffffff) << 0) -#define VDPU_REG_ERROR_CONCEALMENT 0x0d0 -#define VDPU_REG_REF_BUF_CTRL2_APF_THRESHOLD(x) (((x) & 0x3fff) << 17) -#define VDPU_REG_ERR_CONC_STARTMB_X(x) (((x) & 0x1ff) << 8) -#define VDPU_REG_ERR_CONC_STARTMB_Y(x) (((x) & 0xff) << 0) -#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_INTERRUPT 0x0dc -#define VDPU_REG_INTERRUPT_DEC_TIMEOUT BIT(13) -#define VDPU_REG_INTERRUPT_DEC_ERROR_INT BIT(12) -#define VDPU_REG_INTERRUPT_DEC_PIC_INF BIT(10) -#define VDPU_REG_INTERRUPT_DEC_SLICE_INT BIT(9) -#define VDPU_REG_INTERRUPT_DEC_ASO_INT BIT(8) -#define VDPU_REG_INTERRUPT_DEC_BUFFER_INT BIT(6) -#define VDPU_REG_INTERRUPT_DEC_BUS_INT BIT(5) -#define VDPU_REG_INTERRUPT_DEC_RDY_INT BIT(4) -#define VDPU_REG_INTERRUPT_DEC_IRQ_DIS BIT(1) -#define VDPU_REG_INTERRUPT_DEC_IRQ BIT(0) -#define VDPU_REG_AXI_CTRL 0x0e0 -#define VDPU_REG_AXI_DEC_SEL BIT(23) -#define VDPU_REG_CONFIG_DEC_DATA_DISC_E BIT(22) -#define VDPU_REG_PARAL_BUS_E(x) BIT(21) -#define VDPU_REG_CONFIG_DEC_MAX_BURST(x) (((x) & 0x1f) << 16) -#define VDPU_REG_DEC_CTRL0_DEC_AXI_WR_ID(x) (((x) & 0xff) << 8) -#define VDPU_REG_CONFIG_DEC_AXI_RD_ID(x) (((x) & 0xff) << 0) -#define VDPU_REG_EN_FLAGS 0x0e4 -#define VDPU_REG_AHB_HLOCK_E BIT(31) -#define VDPU_REG_CACHE_E BIT(29) -#define VDPU_REG_PREFETCH_SINGLE_CHANNEL_E BIT(28) -#define VDPU_REG_INTRA_3_CYCLE_ENHANCE BIT(27) -#define VDPU_REG_INTRA_DOUBLE_SPEED BIT(26) -#define VDPU_REG_INTER_DOUBLE_SPEED BIT(25) -#define VDPU_REG_DEC_CTRL3_START_CODE_E BIT(22) -#define VDPU_REG_DEC_CTRL3_CH_8PIX_ILEAV_E BIT(21) -#define VDPU_REG_DEC_CTRL0_RLC_MODE_E BIT(20) -#define VDPU_REG_DEC_CTRL0_DIVX3_E BIT(19) -#define VDPU_REG_DEC_CTRL0_PJPEG_E BIT(18) -#define VDPU_REG_DEC_CTRL0_PIC_INTERLACE_E BIT(17) -#define VDPU_REG_DEC_CTRL0_PIC_FIELDMODE_E BIT(16) -#define VDPU_REG_DEC_CTRL0_PIC_B_E BIT(15) -#define VDPU_REG_DEC_CTRL0_PIC_INTER_E BIT(14) -#define VDPU_REG_DEC_CTRL0_PIC_TOPFIELD_E BIT(13) -#define VDPU_REG_DEC_CTRL0_FWD_INTERLACE_E BIT(12) -#define VDPU_REG_DEC_CTRL0_SORENSON_E BIT(11) -#define VDPU_REG_DEC_CTRL0_WRITE_MVS_E BIT(10) -#define VDPU_REG_DEC_CTRL0_REF_TOPFIELD_E BIT(9) -#define VDPU_REG_DEC_CTRL0_REFTOPFIRST_E BIT(8) -#define VDPU_REG_DEC_CTRL0_SEQ_MBAFF_E BIT(7) -#define VDPU_REG_DEC_CTRL0_PICORD_COUNT_E BIT(6) -#define VDPU_REG_CONFIG_DEC_TIMEOUT_E BIT(5) -#define VDPU_REG_CONFIG_DEC_CLK_GATE_E BIT(4) -#define VDPU_REG_DEC_CTRL0_DEC_OUT_DIS BIT(2) -#define VDPU_REG_REF_BUF_CTRL2_REFBU2_BUF_E BIT(1) -#define VDPU_REG_INTERRUPT_DEC_E BIT(0) -#define VDPU_REG_SOFT_RESET 0x0e8 -#define VDPU_REG_PRED_FLT 0x0ec -#define VDPU_REG_PRED_FLT_PRED_BC_TAP_0_0(x) (((x) & 0x3ff) << 22) -#define VDPU_REG_PRED_FLT_PRED_BC_TAP_0_1(x) (((x) & 0x3ff) << 12) -#define VDPU_REG_PRED_FLT_PRED_BC_TAP_0_2(x) (((x) & 0x3ff) << 2) -#define VDPU_REG_ADDITIONAL_CHROMA_ADDRESS 0x0f0 -#define VDPU_REG_ADDR_QTABLE 0x0f4 -#define VDPU_REG_DIRECT_MV_ADDR 0x0f8 -#define VDPU_REG_ADDR_DST 0x0fc -#define VDPU_REG_ADDR_STR 0x100 -#define VDPU_REG_REFBUF_RELATED 0x104 -#define VDPU_REG_FWD_PIC(i) (0x128 + ((i) * 0x4)) -#define VDPU_REG_FWD_PIC_PINIT_RLIST_F5(x) (((x) & 0x1f) << 25) -#define VDPU_REG_FWD_PIC_PINIT_RLIST_F4(x) (((x) & 0x1f) << 20) -#define VDPU_REG_FWD_PIC_PINIT_RLIST_F3(x) (((x) & 0x1f) << 15) -#define VDPU_REG_FWD_PIC_PINIT_RLIST_F2(x) (((x) & 0x1f) << 10) -#define VDPU_REG_FWD_PIC_PINIT_RLIST_F1(x) (((x) & 0x1f) << 5) -#define VDPU_REG_FWD_PIC_PINIT_RLIST_F0(x) (((x) & 0x1f) << 0) -#define VDPU_REG_REF_PIC(i) (0x130 + ((i) * 0x4)) -#define VDPU_REG_REF_PIC_REFER1_NBR(x) (((x) & 0xffff) << 16) -#define VDPU_REG_REF_PIC_REFER0_NBR(x) (((x) & 0xffff) << 0) -#define VDPU_REG_H264_ADDR_REF(i) (0x150 + ((i) * 0x4)) -#define VDPU_REG_ADDR_REF_FIELD_E BIT(1) -#define VDPU_REG_ADDR_REF_TOPC_E BIT(0) -#define VDPU_REG_INITIAL_REF_PIC_LIST0 0x190 -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_F5(x) (((x) & 0x1f) << 25) -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_F4(x) (((x) & 0x1f) << 20) -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_F3(x) (((x) & 0x1f) << 15) -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_F2(x) (((x) & 0x1f) << 10) -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_F1(x) (((x) & 0x1f) << 5) -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_F0(x) (((x) & 0x1f) << 0) -#define VDPU_REG_INITIAL_REF_PIC_LIST1 0x194 -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_F11(x) (((x) & 0x1f) << 25) -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_F10(x) (((x) & 0x1f) << 20) -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_F9(x) (((x) & 0x1f) << 15) -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_F8(x) (((x) & 0x1f) << 10) -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_F7(x) (((x) & 0x1f) << 5) -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_F6(x) (((x) & 0x1f) << 0) -#define VDPU_REG_INITIAL_REF_PIC_LIST2 0x198 -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_F15(x) (((x) & 0x1f) << 15) -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_F14(x) (((x) & 0x1f) << 10) -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_F13(x) (((x) & 0x1f) << 5) -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_F12(x) (((x) & 0x1f) << 0) -#define VDPU_REG_INITIAL_REF_PIC_LIST3 0x19c -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_B5(x) (((x) & 0x1f) << 25) -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_B4(x) (((x) & 0x1f) << 20) -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_B3(x) (((x) & 0x1f) << 15) -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_B2(x) (((x) & 0x1f) << 10) -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_B1(x) (((x) & 0x1f) << 5) -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_B0(x) (((x) & 0x1f) << 0) -#define VDPU_REG_INITIAL_REF_PIC_LIST4 0x1a0 -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_B11(x) (((x) & 0x1f) << 25) -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_B10(x) (((x) & 0x1f) << 20) -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_B9(x) (((x) & 0x1f) << 15) -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_B8(x) (((x) & 0x1f) << 10) -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_B7(x) (((x) & 0x1f) << 5) -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_B6(x) (((x) & 0x1f) << 0) -#define VDPU_REG_INITIAL_REF_PIC_LIST5 0x1a4 -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_B15(x) (((x) & 0x1f) << 15) -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_B14(x) (((x) & 0x1f) << 10) -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_B13(x) (((x) & 0x1f) << 5) -#define VDPU_REG_BD_REF_PIC_BINIT_RLIST_B12(x) (((x) & 0x1f) << 0) -#define VDPU_REG_INITIAL_REF_PIC_LIST6 0x1a8 -#define VDPU_REG_BD_P_REF_PIC_PINIT_RLIST_F3(x) (((x) & 0x1f) << 15) -#define VDPU_REG_BD_P_REF_PIC_PINIT_RLIST_F2(x) (((x) & 0x1f) << 10) -#define VDPU_REG_BD_P_REF_PIC_PINIT_RLIST_F1(x) (((x) & 0x1f) << 5) -#define VDPU_REG_BD_P_REF_PIC_PINIT_RLIST_F0(x) (((x) & 0x1f) << 0) -#define VDPU_REG_LT_REF 0x1ac -#define VDPU_REG_VALID_REF 0x1b0 -#define VDPU_REG_H264_PIC_MB_SIZE 0x1b8 -#define VDPU_REG_DEC_CTRL2_CH_QP_OFFSET2(x) (((x) & 0x1f) << 22) -#define VDPU_REG_DEC_CTRL2_CH_QP_OFFSET(x) (((x) & 0x1f) << 17) -#define VDPU_REG_DEC_CTRL1_PIC_MB_HEIGHT_P(x) (((x) & 0xff) << 9) -#define VDPU_REG_DEC_CTRL1_PIC_MB_WIDTH(x) (((x) & 0x1ff) << 0) -#define VDPU_REG_H264_CTRL 0x1bc -#define VDPU_REG_DEC_CTRL4_WEIGHT_BIPR_IDC(x) (((x) & 0x3) << 16) -#define VDPU_REG_DEC_CTRL1_REF_FRAMES(x) (((x) & 0x1f) << 0) -#define VDPU_REG_CURRENT_FRAME 0x1c0 -#define VDPU_REG_DEC_CTRL5_FILT_CTRL_PRES BIT(31) -#define VDPU_REG_DEC_CTRL5_RDPIC_CNT_PRES BIT(30) -#define VDPU_REG_DEC_CTRL4_FRAMENUM_LEN(x) (((x) & 0x1f) << 16) -#define VDPU_REG_DEC_CTRL4_FRAMENUM(x) (((x) & 0xffff) << 0) -#define VDPU_REG_REF_FRAME 0x1c4 -#define VDPU_REG_DEC_CTRL5_REFPIC_MK_LEN(x) (((x) & 0x7ff) << 16) -#define VDPU_REG_DEC_CTRL5_IDR_PIC_ID(x) (((x) & 0xffff) << 0) -#define VDPU_REG_DEC_CTRL6 0x1c8 -#define VDPU_REG_DEC_CTRL6_PPS_ID(x) (((x) & 0xff) << 24) -#define VDPU_REG_DEC_CTRL6_REFIDX1_ACTIVE(x) (((x) & 0x1f) << 19) -#define VDPU_REG_DEC_CTRL6_REFIDX0_ACTIVE(x) (((x) & 0x1f) << 14) -#define VDPU_REG_DEC_CTRL6_POC_LENGTH(x) (((x) & 0xff) << 0) -#define VDPU_REG_ENABLE_FLAG 0x1cc -#define VDPU_REG_DEC_CTRL5_IDR_PIC_E BIT(8) -#define VDPU_REG_DEC_CTRL4_DIR_8X8_INFER_E BIT(7) -#define VDPU_REG_DEC_CTRL4_BLACKWHITE_E BIT(6) -#define VDPU_REG_DEC_CTRL4_CABAC_E BIT(5) -#define VDPU_REG_DEC_CTRL4_WEIGHT_PRED_E BIT(4) -#define VDPU_REG_DEC_CTRL5_CONST_INTRA_E BIT(3) -#define VDPU_REG_DEC_CTRL5_8X8TRANS_FLAG_E BIT(2) -#define VDPU_REG_DEC_CTRL2_TYPE1_QUANT_E BIT(1) -#define VDPU_REG_DEC_CTRL2_FIELDPIC_FLAG_E BIT(0) -#define VDPU_REG_VP8_PIC_MB_SIZE 0x1e0 -#define VDPU_REG_DEC_PIC_MB_WIDTH(x) (((x) & 0x1ff) << 23) -#define VDPU_REG_DEC_MB_WIDTH_OFF(x) (((x) & 0xf) << 19) -#define VDPU_REG_DEC_PIC_MB_HEIGHT_P(x) (((x) & 0xff) << 11) -#define VDPU_REG_DEC_MB_HEIGHT_OFF(x) (((x) & 0xf) << 7) -#define VDPU_REG_DEC_CTRL1_PIC_MB_W_EXT(x) (((x) & 0x7) << 3) -#define VDPU_REG_DEC_CTRL1_PIC_MB_H_EXT(x) (((x) & 0x7) << 0) -#define VDPU_REG_VP8_DCT_START_BIT 0x1e4 -#define VDPU_REG_DEC_CTRL4_DCT1_START_BIT(x) (((x) & 0x3f) << 26) -#define VDPU_REG_DEC_CTRL4_DCT2_START_BIT(x) (((x) & 0x3f) << 20) -#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_DEC_CTRL2_STRM_START_BIT(x) (((x) & 0x3f) << 26) -#define VDPU_REG_DEC_CTRL2_STRM1_START_BIT(x) (((x) & 0x3f) << 18) -#define VDPU_REG_DEC_CTRL2_BOOLEAN_VALUE(x) (((x) & 0xff) << 8) -#define VDPU_REG_DEC_CTRL2_BOOLEAN_RANGE(x) (((x) & 0xff) << 0) -#define VDPU_REG_VP8_DATA_VAL 0x1f0 -#define VDPU_REG_DEC_CTRL6_COEFFS_PART_AM(x) (((x) & 0xf) << 24) -#define VDPU_REG_DEC_CTRL6_STREAM1_LEN(x) (((x) & 0xffffff) << 0) -#define VDPU_REG_PRED_FLT7 0x1f4 -#define VDPU_REG_PRED_FLT_PRED_BC_TAP_5_1(x) (((x) & 0x3ff) << 22) -#define VDPU_REG_PRED_FLT_PRED_BC_TAP_5_2(x) (((x) & 0x3ff) << 12) -#define VDPU_REG_PRED_FLT_PRED_BC_TAP_5_3(x) (((x) & 0x3ff) << 2) -#define VDPU_REG_PRED_FLT8 0x1f8 -#define VDPU_REG_PRED_FLT_PRED_BC_TAP_6_0(x) (((x) & 0x3ff) << 22) -#define VDPU_REG_PRED_FLT_PRED_BC_TAP_6_1(x) (((x) & 0x3ff) << 12) -#define VDPU_REG_PRED_FLT_PRED_BC_TAP_6_2(x) (((x) & 0x3ff) << 2) -#define VDPU_REG_PRED_FLT9 0x1fc -#define VDPU_REG_PRED_FLT_PRED_BC_TAP_6_3(x) (((x) & 0x3ff) << 22) -#define VDPU_REG_PRED_FLT_PRED_BC_TAP_7_0(x) (((x) & 0x3ff) << 12) -#define VDPU_REG_PRED_FLT_PRED_BC_TAP_7_1(x) (((x) & 0x3ff) << 2) -#define VDPU_REG_PRED_FLT10 0x200 -#define VDPU_REG_PRED_FLT_PRED_BC_TAP_7_2(x) (((x) & 0x3ff) << 22) -#define VDPU_REG_PRED_FLT_PRED_BC_TAP_7_3(x) (((x) & 0x3ff) << 12) -#define VDPU_REG_BD_REF_PIC_PRED_TAP_2_M1(x) (((x) & 0x3) << 10) -#define VDPU_REG_BD_REF_PIC_PRED_TAP_2_4(x) (((x) & 0x3) << 8) -#define VDPU_REG_BD_REF_PIC_PRED_TAP_4_M1(x) (((x) & 0x3) << 6) -#define VDPU_REG_BD_REF_PIC_PRED_TAP_4_4(x) (((x) & 0x3) << 4) -#define VDPU_REG_BD_REF_PIC_PRED_TAP_6_M1(x) (((x) & 0x3) << 2) -#define VDPU_REG_BD_REF_PIC_PRED_TAP_6_4(x) (((x) & 0x3) << 0) -#define VDPU_REG_FILTER_LEVEL 0x204 -#define VDPU_REG_REF_PIC_LF_LEVEL_0(x) (((x) & 0x3f) << 18) -#define VDPU_REG_REF_PIC_LF_LEVEL_1(x) (((x) & 0x3f) << 12) -#define VDPU_REG_REF_PIC_LF_LEVEL_2(x) (((x) & 0x3f) << 6) -#define VDPU_REG_REF_PIC_LF_LEVEL_3(x) (((x) & 0x3f) << 0) -#define VDPU_REG_VP8_QUANTER0 0x208 -#define VDPU_REG_REF_PIC_QUANT_DELTA_0(x) (((x) & 0x1f) << 27) -#define VDPU_REG_REF_PIC_QUANT_DELTA_1(x) (((x) & 0x1f) << 22) -#define VDPU_REG_REF_PIC_QUANT_0(x) (((x) & 0x7ff) << 11) -#define VDPU_REG_REF_PIC_QUANT_1(x) (((x) & 0x7ff) << 0) -#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_FILT_MB_ADJ_0(x) (((x) & 0x7f) << 21) -#define VDPU_REG_FILT_MB_ADJ_1(x) (((x) & 0x7f) << 14) -#define VDPU_REG_FILT_MB_ADJ_2(x) (((x) & 0x7f) << 7) -#define VDPU_REG_FILT_MB_ADJ_3(x) (((x) & 0x7f) << 0) -#define VDPU_REG_FILTER_REF_ADJ 0x214 -#define VDPU_REG_REF_PIC_ADJ_0(x) (((x) & 0x7f) << 21) -#define VDPU_REG_REF_PIC_ADJ_1(x) (((x) & 0x7f) << 14) -#define VDPU_REG_REF_PIC_ADJ_2(x) (((x) & 0x7f) << 7) -#define VDPU_REG_REF_PIC_ADJ_3(x) (((x) & 0x7f) << 0) -#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) * 0x4)) -#define VDPU_REG_VP8_ADDR_CTRL_PART 0x244 -#define VDPU_REG_VP8_ADDR_REF1 0x250 -#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_DEC_CTRL7_DCT3_START_BIT(x) (((x) & 0x3f) << 24) -#define VDPU_REG_DEC_CTRL7_DCT4_START_BIT(x) (((x) & 0x3f) << 18) -#define VDPU_REG_DEC_CTRL7_DCT5_START_BIT(x) (((x) & 0x3f) << 12) -#define VDPU_REG_DEC_CTRL7_DCT6_START_BIT(x) (((x) & 0x3f) << 6) -#define VDPU_REG_DEC_CTRL7_DCT7_START_BIT(x) (((x) & 0x3f) << 0) -#define VDPU_REG_VP8_QUANTER1 0x25c -#define VDPU_REG_REF_PIC_QUANT_DELTA_2(x) (((x) & 0x1f) << 27) -#define VDPU_REG_REF_PIC_QUANT_DELTA_3(x) (((x) & 0x1f) << 22) -#define VDPU_REG_REF_PIC_QUANT_2(x) (((x) & 0x7ff) << 11) -#define VDPU_REG_REF_PIC_QUANT_3(x) (((x) & 0x7ff) << 0) -#define VDPU_REG_VP8_QUANTER2 0x260 -#define VDPU_REG_REF_PIC_QUANT_DELTA_4(x) (((x) & 0x1f) << 27) -#define VDPU_REG_REF_PIC_QUANT_4(x) (((x) & 0x7ff) << 11) -#define VDPU_REG_REF_PIC_QUANT_5(x) (((x) & 0x7ff) << 0) -#define VDPU_REG_PRED_FLT1 0x264 -#define VDPU_REG_PRED_FLT_PRED_BC_TAP_0_3(x) (((x) & 0x3ff) << 22) -#define VDPU_REG_PRED_FLT_PRED_BC_TAP_1_0(x) (((x) & 0x3ff) << 12) -#define VDPU_REG_PRED_FLT_PRED_BC_TAP_1_1(x) (((x) & 0x3ff) << 2) -#define VDPU_REG_PRED_FLT2 0x268 -#define VDPU_REG_PRED_FLT_PRED_BC_TAP_1_2(x) (((x) & 0x3ff) << 22) -#define VDPU_REG_PRED_FLT_PRED_BC_TAP_1_3(x) (((x) & 0x3ff) << 12) -#define VDPU_REG_PRED_FLT_PRED_BC_TAP_2_0(x) (((x) & 0x3ff) << 2) -#define VDPU_REG_PRED_FLT3 0x26c -#define VDPU_REG_PRED_FLT_PRED_BC_TAP_2_1(x) (((x) & 0x3ff) << 22) -#define VDPU_REG_PRED_FLT_PRED_BC_TAP_2_2(x) (((x) & 0x3ff) << 12) -#define VDPU_REG_PRED_FLT_PRED_BC_TAP_2_3(x) (((x) & 0x3ff) << 2) -#define VDPU_REG_PRED_FLT4 0x270 -#define VDPU_REG_PRED_FLT_PRED_BC_TAP_3_0(x) (((x) & 0x3ff) << 22) -#define VDPU_REG_PRED_FLT_PRED_BC_TAP_3_1(x) (((x) & 0x3ff) << 12) -#define VDPU_REG_PRED_FLT_PRED_BC_TAP_3_2(x) (((x) & 0x3ff) << 2) -#define VDPU_REG_PRED_FLT5 0x274 -#define VDPU_REG_PRED_FLT_PRED_BC_TAP_3_3(x) (((x) & 0x3ff) << 22) -#define VDPU_REG_PRED_FLT_PRED_BC_TAP_4_0(x) (((x) & 0x3ff) << 12) -#define VDPU_REG_PRED_FLT_PRED_BC_TAP_4_1(x) (((x) & 0x3ff) << 2) -#define VDPU_REG_PRED_FLT6 0x278 -#define VDPU_REG_PRED_FLT_PRED_BC_TAP_4_2(x) (((x) & 0x3ff) << 22) -#define VDPU_REG_PRED_FLT_PRED_BC_TAP_4_3(x) (((x) & 0x3ff) << 12) -#define VDPU_REG_PRED_FLT_PRED_BC_TAP_5_0(x) (((x) & 0x3ff) << 2) - -#endif /* RK3399_VPU_REGS_H_ */ diff --git a/drivers/staging/media/rockchip/vpu/rockchip_vpu.h b/drivers/staging/media/rockchip/vpu/rockchip_vpu.h deleted file mode 100644 index 3093821440c0..000000000000 --- a/drivers/staging/media/rockchip/vpu/rockchip_vpu.h +++ /dev/null @@ -1,334 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Rockchip VPU codec driver - * - * Copyright 2018 Google LLC. - * Tomasz Figa - * - * Based on s5p-mfc driver by Samsung Electronics Co., Ltd. - * Copyright (C) 2011 Samsung Electronics Co., Ltd. - */ - -#ifndef ROCKCHIP_VPU_H_ -#define ROCKCHIP_VPU_H_ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "rockchip_vpu_hw.h" - -#define ROCKCHIP_VPU_MAX_CLOCKS 4 - -#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) - -#define JPEG_MB_DIM 16 -#define JPEG_MB_WIDTH(w) DIV_ROUND_UP(w, JPEG_MB_DIM) -#define JPEG_MB_HEIGHT(h) DIV_ROUND_UP(h, JPEG_MB_DIM) - -struct rockchip_vpu_ctx; -struct rockchip_vpu_codec_ops; - -#define RK_VPU_JPEG_ENCODER BIT(0) -#define RK_VPU_ENCODERS 0x0000ffff - -#define RK_VPU_MPEG2_DECODER BIT(16) -#define RK_VPU_DECODERS 0xffff0000 - -/** - * struct rockchip_vpu_variant - information about VPU hardware variant - * - * @enc_offset: Offset from VPU base to encoder registers. - * @dec_offset: Offset from VPU base to decoder registers. - * @enc_fmts: Encoder formats. - * @num_enc_fmts: Number of encoder formats. - * @dec_fmts: Decoder formats. - * @num_dec_fmts: Number of decoder formats. - * @codec: Supported codecs - * @codec_ops: Codec ops. - * @init: Initialize hardware. - * @vepu_irq: encoder interrupt handler - * @vdpu_irq: decoder interrupt handler - * @clk_names: array of clock names - * @num_clocks: number of clocks in the array - */ -struct rockchip_vpu_variant { - unsigned int enc_offset; - unsigned int dec_offset; - const struct rockchip_vpu_fmt *enc_fmts; - unsigned int num_enc_fmts; - const struct rockchip_vpu_fmt *dec_fmts; - unsigned int num_dec_fmts; - unsigned int codec; - const struct rockchip_vpu_codec_ops *codec_ops; - int (*init)(struct rockchip_vpu_dev *vpu); - irqreturn_t (*vepu_irq)(int irq, void *priv); - irqreturn_t (*vdpu_irq)(int irq, void *priv); - const char *clk_names[ROCKCHIP_VPU_MAX_CLOCKS]; - int num_clocks; -}; - -/** - * enum rockchip_vpu_codec_mode - codec operating mode. - * @RK_VPU_MODE_NONE: No operating mode. Used for RAW video formats. - * @RK_VPU_MODE_JPEG_ENC: JPEG encoder. - * @RK_VPU_MODE_MPEG2_DEC: MPEG-2 decoder. - */ -enum rockchip_vpu_codec_mode { - RK_VPU_MODE_NONE = -1, - RK_VPU_MODE_JPEG_ENC, - RK_VPU_MODE_MPEG2_DEC, -}; - -/* - * struct rockchip_vpu_ctrl - helper type to declare supported controls - * @id: V4L2 control ID (V4L2_CID_xxx) - * @codec: codec id this control belong to (RK_VPU_JPEG_ENCODER, etc.) - * @cfg: control configuration - */ -struct rockchip_vpu_ctrl { - unsigned int id; - unsigned int codec; - struct v4l2_ctrl_config cfg; -}; - -/* - * struct rockchip_vpu_func - rockchip VPU functionality - * - * @id: processing functionality ID (can be - * %MEDIA_ENT_F_PROC_VIDEO_ENCODER or - * %MEDIA_ENT_F_PROC_VIDEO_DECODER) - * @vdev: &struct video_device that exposes the encoder or - * decoder functionality - * @source_pad: &struct media_pad with the source pad. - * @sink: &struct media_entity pointer with the sink entity - * @sink_pad: &struct media_pad with the sink pad. - * @proc: &struct media_entity pointer with the M2M device itself. - * @proc_pads: &struct media_pad with the @proc pads. - * @intf_devnode: &struct media_intf devnode pointer with the interface - * with controls the M2M device. - * - * Contains everything needed to attach the video device to the media device. - */ -struct rockchip_vpu_func { - unsigned int id; - struct video_device vdev; - struct media_pad source_pad; - struct media_entity sink; - struct media_pad sink_pad; - struct media_entity proc; - struct media_pad proc_pads[2]; - struct media_intf_devnode *intf_devnode; -}; - -static inline struct rockchip_vpu_func * -rockchip_vpu_vdev_to_func(struct video_device *vdev) -{ - return container_of(vdev, struct rockchip_vpu_func, vdev); -} - -/** - * struct rockchip_vpu_dev - driver data - * @v4l2_dev: V4L2 device to register video devices for. - * @m2m_dev: mem2mem device associated to this device. - * @mdev: media device associated to this device. - * @encoder: encoder functionality. - * @decoder: decoder functionality. - * @pdev: Pointer to VPU platform device. - * @dev: Pointer to device for convenient logging using - * dev_ macros. - * @clocks: Array of clock handles. - * @base: Mapped address of VPU registers. - * @enc_base: Mapped address of VPU encoder register for convenience. - * @dec_base: Mapped address of VPU decoder register for convenience. - * @vpu_mutex: Mutex to synchronize V4L2 calls. - * @irqlock: Spinlock to synchronize access to data structures - * shared with interrupt handlers. - * @variant: Hardware variant-specific parameters. - * @watchdog_work: Delayed work for hardware timeout handling. - */ -struct rockchip_vpu_dev { - struct v4l2_device v4l2_dev; - struct v4l2_m2m_dev *m2m_dev; - struct media_device mdev; - struct rockchip_vpu_func *encoder; - struct rockchip_vpu_func *decoder; - struct platform_device *pdev; - struct device *dev; - struct clk_bulk_data clocks[ROCKCHIP_VPU_MAX_CLOCKS]; - void __iomem *base; - void __iomem *enc_base; - void __iomem *dec_base; - - struct mutex vpu_mutex; /* video_device lock */ - spinlock_t irqlock; - const struct rockchip_vpu_variant *variant; - struct delayed_work watchdog_work; -}; - -/** - * struct rockchip_vpu_ctx - Context (instance) private data. - * - * @dev: VPU driver data to which the context belongs. - * @fh: V4L2 file handler. - * - * @sequence_cap: Sequence counter for capture queue - * @sequence_out: Sequence counter for output queue - * - * @vpu_src_fmt: Descriptor of active source format. - * @src_fmt: V4L2 pixel format of active source format. - * @vpu_dst_fmt: Descriptor of active destination format. - * @dst_fmt: V4L2 pixel format of active destination format. - * - * @ctrl_handler: Control handler used to register controls. - * @jpeg_quality: User-specified JPEG compression quality. - * - * @buf_finish: Buffer finish. This depends on encoder or decoder - * context, and it's called right before - * calling v4l2_m2m_job_finish. - * @codec_ops: Set of operations related to codec mode. - * @jpeg_enc: JPEG-encoding context. - * @mpeg2_dec: MPEG-2-decoding context. - */ -struct rockchip_vpu_ctx { - struct rockchip_vpu_dev *dev; - struct v4l2_fh fh; - - u32 sequence_cap; - u32 sequence_out; - - const struct rockchip_vpu_fmt *vpu_src_fmt; - struct v4l2_pix_format_mplane src_fmt; - const struct rockchip_vpu_fmt *vpu_dst_fmt; - struct v4l2_pix_format_mplane dst_fmt; - - struct v4l2_ctrl_handler ctrl_handler; - int jpeg_quality; - - int (*buf_finish)(struct rockchip_vpu_ctx *ctx, - struct vb2_buffer *buf, - unsigned int bytesused); - - const struct rockchip_vpu_codec_ops *codec_ops; - - /* Specific for particular codec modes. */ - union { - struct rockchip_vpu_jpeg_enc_hw_ctx jpeg_enc; - struct rockchip_vpu_mpeg2_dec_hw_ctx mpeg2_dec; - }; -}; - -/** - * struct rockchip_vpu_fmt - information about supported video formats. - * @name: Human readable name of the format. - * @fourcc: FourCC code of the format. See V4L2_PIX_FMT_*. - * @codec_mode: Codec mode related to this format. See - * enum rockchip_vpu_codec_mode. - * @header_size: Optional header size. Currently used by JPEG encoder. - * @max_depth: Maximum depth, for bitstream formats - * @enc_fmt: Format identifier for encoder registers. - * @frmsize: Supported range of frame sizes (only for bitstream formats). - */ -struct rockchip_vpu_fmt { - char *name; - u32 fourcc; - enum rockchip_vpu_codec_mode codec_mode; - int header_size; - int max_depth; - enum rockchip_vpu_enc_fmt enc_fmt; - struct v4l2_frmsize_stepwise frmsize; -}; - -/* Logging helpers */ - -/** - * debug - Module parameter to control level of debugging messages. - * - * Level of debugging messages can be controlled by bits of - * module parameter called "debug". Meaning of particular - * bits is as follows: - * - * bit 0 - global information: mode, size, init, release - * bit 1 - each run start/result information - * bit 2 - contents of small controls from userspace - * bit 3 - contents of big controls from userspace - * bit 4 - detail fmt, ctrl, buffer q/dq information - * bit 5 - detail function enter/leave trace information - * bit 6 - register write/read information - */ -extern int rockchip_vpu_debug; - -#define vpu_debug(level, fmt, args...) \ - do { \ - if (rockchip_vpu_debug & BIT(level)) \ - pr_info("%s:%d: " fmt, \ - __func__, __LINE__, ##args); \ - } while (0) - -#define vpu_err(fmt, args...) \ - pr_err("%s:%d: " fmt, __func__, __LINE__, ##args) - -/* Structure access helpers. */ -static inline struct rockchip_vpu_ctx *fh_to_ctx(struct v4l2_fh *fh) -{ - return container_of(fh, struct rockchip_vpu_ctx, fh); -} - -/* Register accessors. */ -static inline void vepu_write_relaxed(struct rockchip_vpu_dev *vpu, - u32 val, u32 reg) -{ - vpu_debug(6, "0x%04x = 0x%08x\n", reg / 4, val); - writel_relaxed(val, vpu->enc_base + reg); -} - -static inline void vepu_write(struct rockchip_vpu_dev *vpu, u32 val, u32 reg) -{ - vpu_debug(6, "0x%04x = 0x%08x\n", reg / 4, val); - writel(val, vpu->enc_base + reg); -} - -static inline u32 vepu_read(struct rockchip_vpu_dev *vpu, u32 reg) -{ - u32 val = readl(vpu->enc_base + reg); - - vpu_debug(6, "0x%04x = 0x%08x\n", reg / 4, val); - return val; -} - -static inline void vdpu_write_relaxed(struct rockchip_vpu_dev *vpu, - u32 val, u32 reg) -{ - vpu_debug(6, "0x%04x = 0x%08x\n", reg / 4, val); - writel_relaxed(val, vpu->dec_base + reg); -} - -static inline void vdpu_write(struct rockchip_vpu_dev *vpu, u32 val, u32 reg) -{ - vpu_debug(6, "0x%04x = 0x%08x\n", reg / 4, val); - writel(val, vpu->dec_base + reg); -} - -static inline u32 vdpu_read(struct rockchip_vpu_dev *vpu, u32 reg) -{ - u32 val = readl(vpu->dec_base + reg); - - vpu_debug(6, "0x%04x = 0x%08x\n", reg / 4, val); - return val; -} - -bool rockchip_vpu_is_encoder_ctx(const struct rockchip_vpu_ctx *ctx); - -void *rockchip_vpu_get_ctrl(struct rockchip_vpu_ctx *ctx, u32 id); -dma_addr_t rockchip_vpu_get_ref(struct vb2_queue *q, u64 ts); - -#endif /* ROCKCHIP_VPU_H_ */ diff --git a/drivers/staging/media/rockchip/vpu/rockchip_vpu_drv.c b/drivers/staging/media/rockchip/vpu/rockchip_vpu_drv.c deleted file mode 100644 index b94ff97451db..000000000000 --- a/drivers/staging/media/rockchip/vpu/rockchip_vpu_drv.c +++ /dev/null @@ -1,857 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Rockchip VPU codec driver - * - * Copyright (C) 2018 Collabora, Ltd. - * Copyright 2018 Google LLC. - * Tomasz Figa - * - * Based on s5p-mfc driver by Samsung Electronics Co., Ltd. - * Copyright (C) 2011 Samsung Electronics Co., Ltd. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "rockchip_vpu_v4l2.h" -#include "rockchip_vpu.h" -#include "rockchip_vpu_hw.h" - -#define DRIVER_NAME "rockchip-vpu" - -int rockchip_vpu_debug; -module_param_named(debug, rockchip_vpu_debug, int, 0644); -MODULE_PARM_DESC(debug, - "Debug level - higher value produces more verbose messages"); - -void *rockchip_vpu_get_ctrl(struct rockchip_vpu_ctx *ctx, u32 id) -{ - struct v4l2_ctrl *ctrl; - - ctrl = v4l2_ctrl_find(&ctx->ctrl_handler, id); - return ctrl ? ctrl->p_cur.p : NULL; -} - -dma_addr_t rockchip_vpu_get_ref(struct vb2_queue *q, u64 ts) -{ - int index; - - index = vb2_find_timestamp(q, ts, 0); - if (index >= 0) - return vb2_dma_contig_plane_dma_addr(q->bufs[index], 0); - return 0; -} - -static int -rockchip_vpu_enc_buf_finish(struct rockchip_vpu_ctx *ctx, - struct vb2_buffer *buf, - unsigned int bytesused) -{ - size_t avail_size; - - avail_size = vb2_plane_size(buf, 0) - ctx->vpu_dst_fmt->header_size; - if (bytesused > avail_size) - return -EINVAL; - /* - * The bounce buffer is only for the JPEG encoder. - * TODO: Rework the JPEG encoder to eliminate the need - * for a bounce buffer. - */ - if (ctx->jpeg_enc.bounce_buffer.cpu) { - memcpy(vb2_plane_vaddr(buf, 0) + - ctx->vpu_dst_fmt->header_size, - ctx->jpeg_enc.bounce_buffer.cpu, bytesused); - } - buf->planes[0].bytesused = - ctx->vpu_dst_fmt->header_size + bytesused; - return 0; -} - -static int -rockchip_vpu_dec_buf_finish(struct rockchip_vpu_ctx *ctx, - struct vb2_buffer *buf, - unsigned int bytesused) -{ - /* For decoders set bytesused as per the output picture. */ - buf->planes[0].bytesused = ctx->dst_fmt.plane_fmt[0].sizeimage; - return 0; -} - -static void rockchip_vpu_job_finish(struct rockchip_vpu_dev *vpu, - struct rockchip_vpu_ctx *ctx, - unsigned int bytesused, - enum vb2_buffer_state result) -{ - struct vb2_v4l2_buffer *src, *dst; - int ret; - - pm_runtime_mark_last_busy(vpu->dev); - pm_runtime_put_autosuspend(vpu->dev); - clk_bulk_disable(vpu->variant->num_clocks, vpu->clocks); - - src = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); - dst = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); - - if (WARN_ON(!src)) - return; - if (WARN_ON(!dst)) - return; - - 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; - - v4l2_m2m_buf_done(src, result); - v4l2_m2m_buf_done(dst, result); - - v4l2_m2m_job_finish(vpu->m2m_dev, ctx->fh.m2m_ctx); -} - -void rockchip_vpu_irq_done(struct rockchip_vpu_dev *vpu, - unsigned int bytesused, - enum vb2_buffer_state result) -{ - struct rockchip_vpu_ctx *ctx = - v4l2_m2m_get_curr_priv(vpu->m2m_dev); - - /* - * If cancel_delayed_work returns false - * the timeout expired. The watchdog is running, - * and will take care of finishing the job. - */ - if (cancel_delayed_work(&vpu->watchdog_work)) - rockchip_vpu_job_finish(vpu, ctx, bytesused, result); -} - -void rockchip_vpu_watchdog(struct work_struct *work) -{ - struct rockchip_vpu_dev *vpu; - struct rockchip_vpu_ctx *ctx; - - vpu = container_of(to_delayed_work(work), - struct rockchip_vpu_dev, watchdog_work); - ctx = v4l2_m2m_get_curr_priv(vpu->m2m_dev); - if (ctx) { - vpu_err("frame processing timed out!\n"); - ctx->codec_ops->reset(ctx); - rockchip_vpu_job_finish(vpu, ctx, 0, VB2_BUF_STATE_ERROR); - } -} - -static void device_run(void *priv) -{ - struct rockchip_vpu_ctx *ctx = priv; - int ret; - - ret = clk_bulk_enable(ctx->dev->variant->num_clocks, ctx->dev->clocks); - if (ret) - goto err_cancel_job; - ret = pm_runtime_get_sync(ctx->dev->dev); - if (ret < 0) - goto err_cancel_job; - - ctx->codec_ops->run(ctx); - return; - -err_cancel_job: - rockchip_vpu_job_finish(ctx->dev, ctx, 0, VB2_BUF_STATE_ERROR); -} - -bool rockchip_vpu_is_encoder_ctx(const struct rockchip_vpu_ctx *ctx) -{ - return ctx->buf_finish == rockchip_vpu_enc_buf_finish; -} - -static struct v4l2_m2m_ops vpu_m2m_ops = { - .device_run = device_run, -}; - -static int -queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) -{ - struct rockchip_vpu_ctx *ctx = priv; - int ret; - - src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; - src_vq->io_modes = VB2_MMAP | VB2_DMABUF; - src_vq->drv_priv = ctx; - src_vq->ops = &rockchip_vpu_queue_ops; - src_vq->mem_ops = &vb2_dma_contig_memops; - - /* - * Driver does mostly sequential access, so sacrifice TLB efficiency - * for faster allocation. Also, no CPU access on the source queue, - * so no kernel mapping needed. - */ - src_vq->dma_attrs = DMA_ATTR_ALLOC_SINGLE_PAGES | - DMA_ATTR_NO_KERNEL_MAPPING; - src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); - src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; - src_vq->lock = &ctx->dev->vpu_mutex; - src_vq->dev = ctx->dev->v4l2_dev.dev; - src_vq->supports_requests = true; - - ret = vb2_queue_init(src_vq); - if (ret) - return ret; - - /* - * When encoding, the CAPTURE queue doesn't need dma memory, - * as the CPU needs to create the JPEG frames, from the - * hardware-produced JPEG payload. - * - * For the DMA destination buffer, we use a bounce buffer. - */ - if (rockchip_vpu_is_encoder_ctx(ctx)) { - dst_vq->mem_ops = &vb2_vmalloc_memops; - } else { - dst_vq->bidirectional = true; - dst_vq->mem_ops = &vb2_dma_contig_memops; - dst_vq->dma_attrs = DMA_ATTR_ALLOC_SINGLE_PAGES | - DMA_ATTR_NO_KERNEL_MAPPING; - } - - dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; - dst_vq->drv_priv = ctx; - dst_vq->ops = &rockchip_vpu_queue_ops; - dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); - dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; - dst_vq->lock = &ctx->dev->vpu_mutex; - dst_vq->dev = ctx->dev->v4l2_dev.dev; - - return vb2_queue_init(dst_vq); -} - -static int rockchip_vpu_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct rockchip_vpu_ctx *ctx; - - ctx = container_of(ctrl->handler, - struct rockchip_vpu_ctx, ctrl_handler); - - vpu_debug(1, "s_ctrl: id = %d, val = %d\n", ctrl->id, ctrl->val); - - switch (ctrl->id) { - case V4L2_CID_JPEG_COMPRESSION_QUALITY: - ctx->jpeg_quality = ctrl->val; - break; - default: - return -EINVAL; - } - - return 0; -} - -static const struct v4l2_ctrl_ops rockchip_vpu_ctrl_ops = { - .s_ctrl = rockchip_vpu_s_ctrl, -}; - -static struct rockchip_vpu_ctrl controls[] = { - { - .id = V4L2_CID_JPEG_COMPRESSION_QUALITY, - .codec = RK_VPU_JPEG_ENCODER, - .cfg = { - .min = 5, - .max = 100, - .step = 1, - .def = 50, - }, - }, { - .id = V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS, - .codec = RK_VPU_MPEG2_DECODER, - .cfg = { - .elem_size = sizeof(struct v4l2_ctrl_mpeg2_slice_params), - }, - }, { - .id = V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION, - .codec = RK_VPU_MPEG2_DECODER, - .cfg = { - .elem_size = sizeof(struct v4l2_ctrl_mpeg2_quantization), - }, - }, -}; - -static int rockchip_vpu_ctrls_setup(struct rockchip_vpu_dev *vpu, - struct rockchip_vpu_ctx *ctx, - int allowed_codecs) -{ - int i, num_ctrls = ARRAY_SIZE(controls); - - v4l2_ctrl_handler_init(&ctx->ctrl_handler, num_ctrls); - - 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, - &rockchip_vpu_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); - } - - if (ctx->ctrl_handler.error) { - vpu_err("Adding control (%d) failed %d\n", - controls[i].id, - ctx->ctrl_handler.error); - v4l2_ctrl_handler_free(&ctx->ctrl_handler); - return ctx->ctrl_handler.error; - } - } - return v4l2_ctrl_handler_setup(&ctx->ctrl_handler); -} - -/* - * V4L2 file operations. - */ - -static int rockchip_vpu_open(struct file *filp) -{ - struct rockchip_vpu_dev *vpu = video_drvdata(filp); - struct video_device *vdev = video_devdata(filp); - struct rockchip_vpu_func *func = rockchip_vpu_vdev_to_func(vdev); - struct rockchip_vpu_ctx *ctx; - int allowed_codecs, ret; - - /* - * We do not need any extra locking here, because we operate only - * on local data here, except reading few fields from dev, which - * do not change through device's lifetime (which is guaranteed by - * reference on module from open()) and V4L2 internal objects (such - * as vdev and ctx->fh), which have proper locking done in respective - * helper functions used here. - */ - - ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - ctx->dev = vpu; - if (func->id == MEDIA_ENT_F_PROC_VIDEO_ENCODER) { - allowed_codecs = vpu->variant->codec & RK_VPU_ENCODERS; - ctx->buf_finish = rockchip_vpu_enc_buf_finish; - ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(vpu->m2m_dev, ctx, - queue_init); - } else if (func->id == MEDIA_ENT_F_PROC_VIDEO_DECODER) { - allowed_codecs = vpu->variant->codec & RK_VPU_DECODERS; - ctx->buf_finish = rockchip_vpu_dec_buf_finish; - ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(vpu->m2m_dev, ctx, - queue_init); - } else { - ctx->fh.m2m_ctx = ERR_PTR(-ENODEV); - } - if (IS_ERR(ctx->fh.m2m_ctx)) { - ret = PTR_ERR(ctx->fh.m2m_ctx); - kfree(ctx); - return ret; - } - - v4l2_fh_init(&ctx->fh, vdev); - filp->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); - - rockchip_vpu_reset_fmts(ctx); - - ret = rockchip_vpu_ctrls_setup(vpu, ctx, allowed_codecs); - if (ret) { - vpu_err("Failed to set up controls\n"); - goto err_fh_free; - } - ctx->fh.ctrl_handler = &ctx->ctrl_handler; - - return 0; - -err_fh_free: - v4l2_fh_del(&ctx->fh); - v4l2_fh_exit(&ctx->fh); - kfree(ctx); - return ret; -} - -static int rockchip_vpu_release(struct file *filp) -{ - struct rockchip_vpu_ctx *ctx = - container_of(filp->private_data, struct rockchip_vpu_ctx, fh); - - /* - * No need for extra locking because this was the last reference - * to this file. - */ - v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); - v4l2_fh_del(&ctx->fh); - v4l2_fh_exit(&ctx->fh); - v4l2_ctrl_handler_free(&ctx->ctrl_handler); - kfree(ctx); - - return 0; -} - -static const struct v4l2_file_operations rockchip_vpu_fops = { - .owner = THIS_MODULE, - .open = rockchip_vpu_open, - .release = rockchip_vpu_release, - .poll = v4l2_m2m_fop_poll, - .unlocked_ioctl = video_ioctl2, - .mmap = v4l2_m2m_fop_mmap, -}; - -static const struct of_device_id of_rockchip_vpu_match[] = { - { .compatible = "rockchip,rk3399-vpu", .data = &rk3399_vpu_variant, }, - { .compatible = "rockchip,rk3288-vpu", .data = &rk3288_vpu_variant, }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, of_rockchip_vpu_match); - -static int rockchip_vpu_register_entity(struct media_device *mdev, - struct media_entity *entity, - const char *entity_name, - struct media_pad *pads, int num_pads, - int function, - struct video_device *vdev) -{ - char *name; - int ret; - - entity->obj_type = MEDIA_ENTITY_TYPE_BASE; - if (function == MEDIA_ENT_F_IO_V4L) { - entity->info.dev.major = VIDEO_MAJOR; - entity->info.dev.minor = vdev->minor; - } - - name = devm_kasprintf(mdev->dev, GFP_KERNEL, "%s-%s", vdev->name, - entity_name); - if (!name) - return -ENOMEM; - - entity->name = name; - entity->function = function; - - ret = media_entity_pads_init(entity, num_pads, pads); - if (ret) - return ret; - - ret = media_device_register_entity(mdev, entity); - if (ret) - return ret; - - return 0; -} - -static int rockchip_attach_func(struct rockchip_vpu_dev *vpu, - struct rockchip_vpu_func *func) -{ - struct media_device *mdev = &vpu->mdev; - struct media_link *link; - int ret; - - /* Create the three encoder entities with their pads */ - func->source_pad.flags = MEDIA_PAD_FL_SOURCE; - ret = rockchip_vpu_register_entity(mdev, &func->vdev.entity, - "source", &func->source_pad, 1, - MEDIA_ENT_F_IO_V4L, &func->vdev); - if (ret) - return ret; - - func->proc_pads[0].flags = MEDIA_PAD_FL_SINK; - func->proc_pads[1].flags = MEDIA_PAD_FL_SOURCE; - ret = rockchip_vpu_register_entity(mdev, &func->proc, "proc", - func->proc_pads, 2, func->id, - &func->vdev); - if (ret) - goto err_rel_entity0; - - func->sink_pad.flags = MEDIA_PAD_FL_SINK; - ret = rockchip_vpu_register_entity(mdev, &func->sink, "sink", - &func->sink_pad, 1, - MEDIA_ENT_F_IO_V4L, &func->vdev); - if (ret) - goto err_rel_entity1; - - /* Connect the three entities */ - ret = media_create_pad_link(&func->vdev.entity, 0, &func->proc, 1, - MEDIA_LNK_FL_IMMUTABLE | - MEDIA_LNK_FL_ENABLED); - if (ret) - goto err_rel_entity2; - - ret = media_create_pad_link(&func->proc, 0, &func->sink, 0, - MEDIA_LNK_FL_IMMUTABLE | - MEDIA_LNK_FL_ENABLED); - if (ret) - goto err_rm_links0; - - /* Create video interface */ - func->intf_devnode = media_devnode_create(mdev, MEDIA_INTF_T_V4L_VIDEO, - 0, VIDEO_MAJOR, - func->vdev.minor); - if (!func->intf_devnode) { - ret = -ENOMEM; - goto err_rm_links1; - } - - /* Connect the two DMA engines to the interface */ - link = media_create_intf_link(&func->vdev.entity, - &func->intf_devnode->intf, - MEDIA_LNK_FL_IMMUTABLE | - MEDIA_LNK_FL_ENABLED); - if (!link) { - ret = -ENOMEM; - goto err_rm_devnode; - } - - link = media_create_intf_link(&func->sink, &func->intf_devnode->intf, - MEDIA_LNK_FL_IMMUTABLE | - MEDIA_LNK_FL_ENABLED); - if (!link) { - ret = -ENOMEM; - goto err_rm_devnode; - } - return 0; - -err_rm_devnode: - media_devnode_remove(func->intf_devnode); - -err_rm_links1: - media_entity_remove_links(&func->sink); - -err_rm_links0: - media_entity_remove_links(&func->proc); - media_entity_remove_links(&func->vdev.entity); - -err_rel_entity2: - media_device_unregister_entity(&func->sink); - -err_rel_entity1: - media_device_unregister_entity(&func->proc); - -err_rel_entity0: - media_device_unregister_entity(&func->vdev.entity); - return ret; -} - -static void rockchip_detach_func(struct rockchip_vpu_func *func) -{ - media_devnode_remove(func->intf_devnode); - media_entity_remove_links(&func->sink); - media_entity_remove_links(&func->proc); - media_entity_remove_links(&func->vdev.entity); - media_device_unregister_entity(&func->sink); - media_device_unregister_entity(&func->proc); - media_device_unregister_entity(&func->vdev.entity); -} - -static int rockchip_vpu_add_func(struct rockchip_vpu_dev *vpu, - unsigned int funcid) -{ - const struct of_device_id *match; - struct rockchip_vpu_func *func; - struct video_device *vfd; - int ret; - - match = of_match_node(of_rockchip_vpu_match, vpu->dev->of_node); - func = devm_kzalloc(vpu->dev, sizeof(*func), GFP_KERNEL); - if (!func) { - v4l2_err(&vpu->v4l2_dev, "Failed to allocate video device\n"); - return -ENOMEM; - } - - func->id = funcid; - - vfd = &func->vdev; - vfd->fops = &rockchip_vpu_fops; - vfd->release = video_device_release_empty; - vfd->lock = &vpu->vpu_mutex; - vfd->v4l2_dev = &vpu->v4l2_dev; - vfd->vfl_dir = VFL_DIR_M2M; - vfd->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE; - vfd->ioctl_ops = &rockchip_vpu_ioctl_ops; - snprintf(vfd->name, sizeof(vfd->name), "%s-%s", match->compatible, - funcid == MEDIA_ENT_F_PROC_VIDEO_ENCODER ? "enc" : "dec"); - - if (funcid == MEDIA_ENT_F_PROC_VIDEO_ENCODER) - vpu->encoder = func; - else - vpu->decoder = func; - - video_set_drvdata(vfd, vpu); - - ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1); - if (ret) { - v4l2_err(&vpu->v4l2_dev, "Failed to register video device\n"); - return ret; - } - - ret = rockchip_attach_func(vpu, func); - if (ret) { - v4l2_err(&vpu->v4l2_dev, - "Failed to attach functionality to the media device\n"); - goto err_unreg_dev; - } - - v4l2_info(&vpu->v4l2_dev, "registered as /dev/video%d\n", vfd->num); - - return 0; - -err_unreg_dev: - video_unregister_device(vfd); - return ret; -} - -static int rockchip_vpu_add_enc_func(struct rockchip_vpu_dev *vpu) -{ - if (!vpu->variant->enc_fmts) - return 0; - - return rockchip_vpu_add_func(vpu, MEDIA_ENT_F_PROC_VIDEO_ENCODER); -} - -static int rockchip_vpu_add_dec_func(struct rockchip_vpu_dev *vpu) -{ - if (!vpu->variant->dec_fmts) - return 0; - - return rockchip_vpu_add_func(vpu, MEDIA_ENT_F_PROC_VIDEO_DECODER); -} - -static void rockchip_vpu_remove_func(struct rockchip_vpu_dev *vpu, - unsigned int funcid) -{ - struct rockchip_vpu_func *func; - - if (funcid == MEDIA_ENT_F_PROC_VIDEO_ENCODER) - func = vpu->encoder; - else - func = vpu->decoder; - - if (!func) - return; - - rockchip_detach_func(func); - video_unregister_device(&func->vdev); -} - -static void rockchip_vpu_remove_enc_func(struct rockchip_vpu_dev *vpu) -{ - rockchip_vpu_remove_func(vpu, MEDIA_ENT_F_PROC_VIDEO_ENCODER); -} - -static void rockchip_vpu_remove_dec_func(struct rockchip_vpu_dev *vpu) -{ - rockchip_vpu_remove_func(vpu, MEDIA_ENT_F_PROC_VIDEO_DECODER); -} - -static const struct media_device_ops rockchip_m2m_media_ops = { - .req_validate = vb2_request_validate, - .req_queue = v4l2_m2m_request_queue, -}; - -static int rockchip_vpu_probe(struct platform_device *pdev) -{ - const struct of_device_id *match; - struct rockchip_vpu_dev *vpu; - struct resource *res; - int i, ret; - - vpu = devm_kzalloc(&pdev->dev, sizeof(*vpu), GFP_KERNEL); - if (!vpu) - return -ENOMEM; - - vpu->dev = &pdev->dev; - vpu->pdev = pdev; - mutex_init(&vpu->vpu_mutex); - spin_lock_init(&vpu->irqlock); - - match = of_match_node(of_rockchip_vpu_match, pdev->dev.of_node); - vpu->variant = match->data; - - INIT_DELAYED_WORK(&vpu->watchdog_work, rockchip_vpu_watchdog); - - for (i = 0; i < vpu->variant->num_clocks; i++) - vpu->clocks[i].id = vpu->variant->clk_names[i]; - ret = devm_clk_bulk_get(&pdev->dev, vpu->variant->num_clocks, - vpu->clocks); - if (ret) - return ret; - - res = platform_get_resource(vpu->pdev, IORESOURCE_MEM, 0); - vpu->base = devm_ioremap_resource(vpu->dev, res); - if (IS_ERR(vpu->base)) - return PTR_ERR(vpu->base); - vpu->enc_base = vpu->base + vpu->variant->enc_offset; - vpu->dec_base = vpu->base + vpu->variant->dec_offset; - - ret = dma_set_coherent_mask(vpu->dev, DMA_BIT_MASK(32)); - if (ret) { - dev_err(vpu->dev, "Could not set DMA coherent mask.\n"); - return ret; - } - - if (vpu->variant->vdpu_irq) { - int irq; - - irq = platform_get_irq_byname(vpu->pdev, "vdpu"); - if (irq <= 0) { - dev_err(vpu->dev, "Could not get vdpu IRQ.\n"); - return -ENXIO; - } - - ret = devm_request_irq(vpu->dev, irq, vpu->variant->vdpu_irq, - 0, dev_name(vpu->dev), vpu); - if (ret) { - dev_err(vpu->dev, "Could not request vdpu IRQ.\n"); - return ret; - } - } - - if (vpu->variant->vepu_irq) { - int irq; - - irq = platform_get_irq_byname(vpu->pdev, "vepu"); - if (irq <= 0) { - dev_err(vpu->dev, "Could not get vepu IRQ.\n"); - return -ENXIO; - } - - ret = devm_request_irq(vpu->dev, irq, vpu->variant->vepu_irq, - 0, dev_name(vpu->dev), vpu); - if (ret) { - dev_err(vpu->dev, "Could not request vepu IRQ.\n"); - return ret; - } - } - - ret = vpu->variant->init(vpu); - if (ret) { - dev_err(&pdev->dev, "Failed to init VPU hardware\n"); - return ret; - } - - pm_runtime_set_autosuspend_delay(vpu->dev, 100); - pm_runtime_use_autosuspend(vpu->dev); - pm_runtime_enable(vpu->dev); - - ret = clk_bulk_prepare(vpu->variant->num_clocks, vpu->clocks); - if (ret) { - dev_err(&pdev->dev, "Failed to prepare clocks\n"); - return ret; - } - - ret = v4l2_device_register(&pdev->dev, &vpu->v4l2_dev); - if (ret) { - dev_err(&pdev->dev, "Failed to register v4l2 device\n"); - goto err_clk_unprepare; - } - platform_set_drvdata(pdev, vpu); - - vpu->m2m_dev = v4l2_m2m_init(&vpu_m2m_ops); - if (IS_ERR(vpu->m2m_dev)) { - v4l2_err(&vpu->v4l2_dev, "Failed to init mem2mem device\n"); - ret = PTR_ERR(vpu->m2m_dev); - goto err_v4l2_unreg; - } - - vpu->mdev.dev = vpu->dev; - strscpy(vpu->mdev.model, DRIVER_NAME, sizeof(vpu->mdev.model)); - strscpy(vpu->mdev.bus_info, "platform: " DRIVER_NAME, - sizeof(vpu->mdev.model)); - media_device_init(&vpu->mdev); - vpu->mdev.ops = &rockchip_m2m_media_ops; - vpu->v4l2_dev.mdev = &vpu->mdev; - - ret = rockchip_vpu_add_enc_func(vpu); - if (ret) { - dev_err(&pdev->dev, "Failed to register encoder\n"); - goto err_m2m_rel; - } - - ret = rockchip_vpu_add_dec_func(vpu); - if (ret) { - dev_err(&pdev->dev, "Failed to register decoder\n"); - goto err_rm_enc_func; - } - - ret = media_device_register(&vpu->mdev); - if (ret) { - v4l2_err(&vpu->v4l2_dev, "Failed to register mem2mem media device\n"); - goto err_rm_dec_func; - } - - return 0; - -err_rm_dec_func: - rockchip_vpu_remove_dec_func(vpu); -err_rm_enc_func: - rockchip_vpu_remove_enc_func(vpu); -err_m2m_rel: - media_device_cleanup(&vpu->mdev); - v4l2_m2m_release(vpu->m2m_dev); -err_v4l2_unreg: - v4l2_device_unregister(&vpu->v4l2_dev); -err_clk_unprepare: - clk_bulk_unprepare(vpu->variant->num_clocks, vpu->clocks); - pm_runtime_dont_use_autosuspend(vpu->dev); - pm_runtime_disable(vpu->dev); - return ret; -} - -static int rockchip_vpu_remove(struct platform_device *pdev) -{ - struct rockchip_vpu_dev *vpu = platform_get_drvdata(pdev); - - v4l2_info(&vpu->v4l2_dev, "Removing %s\n", pdev->name); - - media_device_unregister(&vpu->mdev); - rockchip_vpu_remove_dec_func(vpu); - rockchip_vpu_remove_enc_func(vpu); - media_device_cleanup(&vpu->mdev); - v4l2_m2m_release(vpu->m2m_dev); - v4l2_device_unregister(&vpu->v4l2_dev); - clk_bulk_unprepare(vpu->variant->num_clocks, vpu->clocks); - pm_runtime_dont_use_autosuspend(vpu->dev); - pm_runtime_disable(vpu->dev); - return 0; -} - -static const struct dev_pm_ops rockchip_vpu_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) -}; - -static struct platform_driver rockchip_vpu_driver = { - .probe = rockchip_vpu_probe, - .remove = rockchip_vpu_remove, - .driver = { - .name = DRIVER_NAME, - .of_match_table = of_match_ptr(of_rockchip_vpu_match), - .pm = &rockchip_vpu_pm_ops, - }, -}; -module_platform_driver(rockchip_vpu_driver); - -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Alpha Lin "); -MODULE_AUTHOR("Tomasz Figa "); -MODULE_AUTHOR("Ezequiel Garcia "); -MODULE_DESCRIPTION("Rockchip VPU codec driver"); diff --git a/drivers/staging/media/rockchip/vpu/rockchip_vpu_hw.h b/drivers/staging/media/rockchip/vpu/rockchip_vpu_hw.h deleted file mode 100644 index 6cecb528f994..000000000000 --- a/drivers/staging/media/rockchip/vpu/rockchip_vpu_hw.h +++ /dev/null @@ -1,102 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Rockchip VPU codec driver - * - * Copyright 2018 Google LLC. - * Tomasz Figa - */ - -#ifndef ROCKCHIP_VPU_HW_H_ -#define ROCKCHIP_VPU_HW_H_ - -#include -#include -#include -#include - -struct rockchip_vpu_dev; -struct rockchip_vpu_ctx; -struct rockchip_vpu_buf; -struct rockchip_vpu_variant; - -/** - * struct rockchip_vpu_aux_buf - auxiliary DMA buffer for hardware data - * @cpu: CPU pointer to the buffer. - * @dma: DMA address of the buffer. - * @size: Size of the buffer. - */ -struct rockchip_vpu_aux_buf { - void *cpu; - dma_addr_t dma; - size_t size; -}; - -/** - * struct rockchip_vpu_jpeg_enc_hw_ctx - * @bounce_buffer: Bounce buffer - */ -struct rockchip_vpu_jpeg_enc_hw_ctx { - struct rockchip_vpu_aux_buf bounce_buffer; -}; - -/** - * struct rockchip_vpu_mpeg2_dec_hw_ctx - * @qtable: Quantization table - */ -struct rockchip_vpu_mpeg2_dec_hw_ctx { - struct rockchip_vpu_aux_buf qtable; -}; - -/** - * struct rockchip_vpu_codec_ops - codec mode specific operations - * - * @init: If needed, can be used for initialization. - * Optional and called from process context. - * @exit: If needed, can be used to undo the .init phase. - * Optional and called from process context. - * @run: Start single {en,de)coding job. Called from atomic context - * to indicate that a pair of buffers is ready and the hardware - * should be programmed and started. - * @done: Read back processing results and additional data from hardware. - * @reset: Reset the hardware in case of a timeout. - */ -struct rockchip_vpu_codec_ops { - int (*init)(struct rockchip_vpu_ctx *ctx); - void (*exit)(struct rockchip_vpu_ctx *ctx); - void (*run)(struct rockchip_vpu_ctx *ctx); - void (*done)(struct rockchip_vpu_ctx *ctx, enum vb2_buffer_state); - void (*reset)(struct rockchip_vpu_ctx *ctx); -}; - -/** - * enum rockchip_vpu_enc_fmt - source format ID for hardware registers. - */ -enum rockchip_vpu_enc_fmt { - RK3288_VPU_ENC_FMT_YUV420P = 0, - RK3288_VPU_ENC_FMT_YUV420SP = 1, - RK3288_VPU_ENC_FMT_YUYV422 = 2, - RK3288_VPU_ENC_FMT_UYVY422 = 3, -}; - -extern const struct rockchip_vpu_variant rk3399_vpu_variant; -extern const struct rockchip_vpu_variant rk3288_vpu_variant; - -void rockchip_vpu_watchdog(struct work_struct *work); -void rockchip_vpu_run(struct rockchip_vpu_ctx *ctx); -void rockchip_vpu_irq_done(struct rockchip_vpu_dev *vpu, - unsigned int bytesused, - enum vb2_buffer_state result); - -void rk3288_vpu_jpeg_enc_run(struct rockchip_vpu_ctx *ctx); -void rk3399_vpu_jpeg_enc_run(struct rockchip_vpu_ctx *ctx); -int rockchip_vpu_jpeg_enc_init(struct rockchip_vpu_ctx *ctx); -void rockchip_vpu_jpeg_enc_exit(struct rockchip_vpu_ctx *ctx); - -void rk3288_vpu_mpeg2_dec_run(struct rockchip_vpu_ctx *ctx); -void rk3399_vpu_mpeg2_dec_run(struct rockchip_vpu_ctx *ctx); -void rockchip_vpu_mpeg2_dec_copy_qtable(u8 *qtable, - const struct v4l2_ctrl_mpeg2_quantization *ctrl); -int rockchip_vpu_mpeg2_dec_init(struct rockchip_vpu_ctx *ctx); -void rockchip_vpu_mpeg2_dec_exit(struct rockchip_vpu_ctx *ctx); - -#endif /* ROCKCHIP_VPU_HW_H_ */ diff --git a/drivers/staging/media/rockchip/vpu/rockchip_vpu_jpeg.c b/drivers/staging/media/rockchip/vpu/rockchip_vpu_jpeg.c deleted file mode 100644 index 30b97d207dc5..000000000000 --- a/drivers/staging/media/rockchip/vpu/rockchip_vpu_jpeg.c +++ /dev/null @@ -1,319 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) Collabora, Ltd. - * - * Based on GSPCA and CODA drivers: - * Copyright (C) Jean-Francois Moine (http://moinejf.free.fr) - * Copyright (C) 2014 Philipp Zabel, Pengutronix - */ -#include -#include -#include -#include "rockchip_vpu_jpeg.h" -#include "rockchip_vpu.h" - -#define LUMA_QUANT_OFF 7 -#define CHROMA_QUANT_OFF 72 -#define HEIGHT_OFF 141 -#define WIDTH_OFF 143 - -#define HUFF_LUMA_DC_OFF 160 -#define HUFF_LUMA_AC_OFF 193 -#define HUFF_CHROMA_DC_OFF 376 -#define HUFF_CHROMA_AC_OFF 409 - -/* Default tables from JPEG ITU-T.81 - * (ISO/IEC 10918-1) Annex K.3, I - */ -static const unsigned char luma_q_table[] = { - 0x10, 0x0b, 0x0a, 0x10, 0x7c, 0x8c, 0x97, 0xa1, - 0x0c, 0x0c, 0x0e, 0x13, 0x7e, 0x9e, 0xa0, 0x9b, - 0x0e, 0x0d, 0x10, 0x18, 0x8c, 0x9d, 0xa9, 0x9c, - 0x0e, 0x11, 0x16, 0x1d, 0x97, 0xbb, 0xb4, 0xa2, - 0x12, 0x16, 0x25, 0x38, 0xa8, 0x6d, 0x67, 0xb1, - 0x18, 0x23, 0x37, 0x40, 0xb5, 0x68, 0x71, 0xc0, - 0x31, 0x40, 0x4e, 0x57, 0x67, 0x79, 0x78, 0x65, - 0x48, 0x5c, 0x5f, 0x62, 0x70, 0x64, 0x67, 0xc7, -}; - -static const unsigned char chroma_q_table[] = { - 0x11, 0x12, 0x18, 0x2f, 0x63, 0x63, 0x63, 0x63, - 0x12, 0x15, 0x1a, 0x42, 0x63, 0x63, 0x63, 0x63, - 0x18, 0x1a, 0x38, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x2f, 0x42, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63 -}; - -/* Huffman tables are shared with CODA */ -static const unsigned char luma_dc_table[] = { - 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, -}; - -static const unsigned char chroma_dc_table[] = { - 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, -}; - -static const unsigned char luma_ac_table[] = { - 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, - 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d, - 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, - 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, - 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, - 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, - 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, - 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, - 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, - 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, - 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, - 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, - 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, - 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, - 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, - 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, - 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, - 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, - 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, - 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, - 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, - 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, - 0xf9, 0xfa, -}; - -static const unsigned char chroma_ac_table[] = { - 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, - 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, - 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, - 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, - 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, - 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, - 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, - 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, - 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, - 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, - 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, - 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, - 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, - 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, - 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, - 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, - 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, - 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, - 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, - 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, - 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, - 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, - 0xf9, 0xfa, -}; - -/* For simplicity, we keep a pre-formatted JPEG header, - * and we'll use fixed offsets to change the width, height - * quantization tables, etc. - */ -static const unsigned char rockchip_vpu_jpeg_header[JPEG_HEADER_SIZE] = { - /* SOI */ - 0xff, 0xd8, - - /* DQT */ - 0xff, 0xdb, 0x00, 0x84, - - 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - /* SOF */ - 0xff, 0xc0, 0x00, 0x11, 0x08, 0x00, 0xf0, 0x01, - 0x40, 0x03, 0x01, 0x22, 0x00, 0x02, 0x11, 0x01, - 0x03, 0x11, 0x01, - - /* DHT */ - 0xff, 0xc4, 0x00, 0x1f, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - - /* DHT */ - 0xff, 0xc4, 0x00, 0xb5, 0x10, - - 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - /* DHT */ - 0xff, 0xc4, 0x00, 0x1f, 0x01, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - - /* DHT */ - 0xff, 0xc4, 0x00, 0xb5, 0x11, - - 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - /* SOS */ - 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, - 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00, -}; - -static void -jpeg_scale_quant_table(unsigned char *q_tab, - const unsigned char *tab, int scale) -{ - unsigned int temp; - int i; - - for (i = 0; i < 64; i++) { - temp = DIV_ROUND_CLOSEST((unsigned int)tab[i] * scale, 100); - if (temp <= 0) - temp = 1; - if (temp > 255) - temp = 255; - q_tab[i] = (unsigned char)temp; - } -} - -static void jpeg_set_quality(unsigned char *buffer, int quality) -{ - int scale; - - /* - * Non-linear scaling factor: - * [5,50] -> [1000..100], [51,100] -> [98..0] - */ - if (quality < 50) - scale = 5000 / quality; - else - scale = 200 - 2 * quality; - - jpeg_scale_quant_table(buffer + LUMA_QUANT_OFF, - luma_q_table, scale); - jpeg_scale_quant_table(buffer + CHROMA_QUANT_OFF, - chroma_q_table, scale); -} - -unsigned char * -rockchip_vpu_jpeg_get_qtable(struct rockchip_vpu_jpeg_ctx *ctx, int index) -{ - if (index == 0) - return ctx->buffer + LUMA_QUANT_OFF; - return ctx->buffer + CHROMA_QUANT_OFF; -} - -void rockchip_vpu_jpeg_header_assemble(struct rockchip_vpu_jpeg_ctx *ctx) -{ - char *buf = ctx->buffer; - - memcpy(buf, rockchip_vpu_jpeg_header, - sizeof(rockchip_vpu_jpeg_header)); - - buf[HEIGHT_OFF + 0] = ctx->height >> 8; - buf[HEIGHT_OFF + 1] = ctx->height; - buf[WIDTH_OFF + 0] = ctx->width >> 8; - buf[WIDTH_OFF + 1] = ctx->width; - - memcpy(buf + HUFF_LUMA_DC_OFF, luma_dc_table, sizeof(luma_dc_table)); - memcpy(buf + HUFF_LUMA_AC_OFF, luma_ac_table, sizeof(luma_ac_table)); - memcpy(buf + HUFF_CHROMA_DC_OFF, chroma_dc_table, - sizeof(chroma_dc_table)); - memcpy(buf + HUFF_CHROMA_AC_OFF, chroma_ac_table, - sizeof(chroma_ac_table)); - - jpeg_set_quality(buf, ctx->quality); -} - -int rockchip_vpu_jpeg_enc_init(struct rockchip_vpu_ctx *ctx) -{ - ctx->jpeg_enc.bounce_buffer.size = - ctx->dst_fmt.plane_fmt[0].sizeimage - - ctx->vpu_dst_fmt->header_size; - - ctx->jpeg_enc.bounce_buffer.cpu = - dma_alloc_attrs(ctx->dev->dev, - ctx->jpeg_enc.bounce_buffer.size, - &ctx->jpeg_enc.bounce_buffer.dma, - GFP_KERNEL, - DMA_ATTR_ALLOC_SINGLE_PAGES); - if (!ctx->jpeg_enc.bounce_buffer.cpu) - return -ENOMEM; - - return 0; -} - -void rockchip_vpu_jpeg_enc_exit(struct rockchip_vpu_ctx *ctx) -{ - dma_free_attrs(ctx->dev->dev, - ctx->jpeg_enc.bounce_buffer.size, - ctx->jpeg_enc.bounce_buffer.cpu, - ctx->jpeg_enc.bounce_buffer.dma, - DMA_ATTR_ALLOC_SINGLE_PAGES); -} diff --git a/drivers/staging/media/rockchip/vpu/rockchip_vpu_jpeg.h b/drivers/staging/media/rockchip/vpu/rockchip_vpu_jpeg.h deleted file mode 100644 index 72645d8e2ade..000000000000 --- a/drivers/staging/media/rockchip/vpu/rockchip_vpu_jpeg.h +++ /dev/null @@ -1,14 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ - -#define JPEG_HEADER_SIZE 601 - -struct rockchip_vpu_jpeg_ctx { - int width; - int height; - int quality; - unsigned char *buffer; -}; - -unsigned char * -rockchip_vpu_jpeg_get_qtable(struct rockchip_vpu_jpeg_ctx *ctx, int index); -void rockchip_vpu_jpeg_header_assemble(struct rockchip_vpu_jpeg_ctx *ctx); diff --git a/drivers/staging/media/rockchip/vpu/rockchip_vpu_mpeg2.c b/drivers/staging/media/rockchip/vpu/rockchip_vpu_mpeg2.c deleted file mode 100644 index 5a5b9ea1f6b5..000000000000 --- a/drivers/staging/media/rockchip/vpu/rockchip_vpu_mpeg2.c +++ /dev/null @@ -1,61 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Rockchip VPU codec driver - * - * Copyright (C) 2018 Rockchip Electronics Co., Ltd. - */ - -#include "rockchip_vpu.h" - -static const u8 zigzag[64] = { - 0, 1, 8, 16, 9, 2, 3, 10, - 17, 24, 32, 25, 18, 11, 4, 5, - 12, 19, 26, 33, 40, 48, 41, 34, - 27, 20, 13, 6, 7, 14, 21, 28, - 35, 42, 49, 56, 57, 50, 43, 36, - 29, 22, 15, 23, 30, 37, 44, 51, - 58, 59, 52, 45, 38, 31, 39, 46, - 53, 60, 61, 54, 47, 55, 62, 63 -}; - -void rockchip_vpu_mpeg2_dec_copy_qtable(u8 *qtable, - const struct v4l2_ctrl_mpeg2_quantization *ctrl) -{ - int i, n; - - if (!qtable || !ctrl) - return; - - for (i = 0; i < ARRAY_SIZE(zigzag); i++) { - n = zigzag[i]; - qtable[n + 0] = ctrl->intra_quantiser_matrix[i]; - qtable[n + 64] = ctrl->non_intra_quantiser_matrix[i]; - qtable[n + 128] = ctrl->chroma_intra_quantiser_matrix[i]; - qtable[n + 192] = ctrl->chroma_non_intra_quantiser_matrix[i]; - } -} - -int rockchip_vpu_mpeg2_dec_init(struct rockchip_vpu_ctx *ctx) -{ - struct rockchip_vpu_dev *vpu = ctx->dev; - - ctx->mpeg2_dec.qtable.size = ARRAY_SIZE(zigzag) * 4; - ctx->mpeg2_dec.qtable.cpu = - dma_alloc_coherent(vpu->dev, - ctx->mpeg2_dec.qtable.size, - &ctx->mpeg2_dec.qtable.dma, - GFP_KERNEL); - if (!ctx->mpeg2_dec.qtable.cpu) - return -ENOMEM; - return 0; -} - -void rockchip_vpu_mpeg2_dec_exit(struct rockchip_vpu_ctx *ctx) -{ - struct rockchip_vpu_dev *vpu = ctx->dev; - - dma_free_coherent(vpu->dev, - ctx->mpeg2_dec.qtable.size, - ctx->mpeg2_dec.qtable.cpu, - ctx->mpeg2_dec.qtable.dma); -} diff --git a/drivers/staging/media/rockchip/vpu/rockchip_vpu_v4l2.c b/drivers/staging/media/rockchip/vpu/rockchip_vpu_v4l2.c deleted file mode 100644 index 8bc709ab13be..000000000000 --- a/drivers/staging/media/rockchip/vpu/rockchip_vpu_v4l2.c +++ /dev/null @@ -1,692 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Rockchip VPU codec driver - * - * Copyright (C) 2018 Collabora, Ltd. - * Copyright (C) 2018 Rockchip Electronics Co., Ltd. - * Alpha Lin - * Jeffy Chen - * - * Copyright 2018 Google LLC. - * Tomasz Figa - * - * Based on s5p-mfc driver by Samsung Electronics Co., Ltd. - * Copyright (C) 2010-2011 Samsung Electronics Co., Ltd. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "rockchip_vpu.h" -#include "rockchip_vpu_hw.h" -#include "rockchip_vpu_v4l2.h" - -static const struct rockchip_vpu_fmt * -rockchip_vpu_get_formats(const struct rockchip_vpu_ctx *ctx, - unsigned int *num_fmts) -{ - const struct rockchip_vpu_fmt *formats; - - if (rockchip_vpu_is_encoder_ctx(ctx)) { - formats = ctx->dev->variant->enc_fmts; - *num_fmts = ctx->dev->variant->num_enc_fmts; - } else { - formats = ctx->dev->variant->dec_fmts; - *num_fmts = ctx->dev->variant->num_dec_fmts; - } - - return formats; -} - -static const struct rockchip_vpu_fmt * -rockchip_vpu_find_format(const struct rockchip_vpu_fmt *formats, - unsigned int num_fmts, u32 fourcc) -{ - unsigned int i; - - for (i = 0; i < num_fmts; i++) - if (formats[i].fourcc == fourcc) - return &formats[i]; - return NULL; -} - -static const struct rockchip_vpu_fmt * -rockchip_vpu_get_default_fmt(const struct rockchip_vpu_fmt *formats, - unsigned int num_fmts, bool bitstream) -{ - unsigned int i; - - for (i = 0; i < num_fmts; i++) { - if (bitstream == (formats[i].codec_mode != RK_VPU_MODE_NONE)) - return &formats[i]; - } - return NULL; -} - -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct rockchip_vpu_dev *vpu = video_drvdata(file); - struct video_device *vdev = video_devdata(file); - - strscpy(cap->driver, vpu->dev->driver->name, sizeof(cap->driver)); - strscpy(cap->card, vdev->name, sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform: %s", - vpu->dev->driver->name); - return 0; -} - -static int vidioc_enum_framesizes(struct file *file, void *priv, - struct v4l2_frmsizeenum *fsize) -{ - struct rockchip_vpu_ctx *ctx = fh_to_ctx(priv); - const struct rockchip_vpu_fmt *formats, *fmt; - unsigned int num_fmts; - - if (fsize->index != 0) { - vpu_debug(0, "invalid frame size index (expected 0, got %d)\n", - fsize->index); - return -EINVAL; - } - - formats = rockchip_vpu_get_formats(ctx, &num_fmts); - fmt = rockchip_vpu_find_format(formats, num_fmts, fsize->pixel_format); - if (!fmt) { - vpu_debug(0, "unsupported bitstream format (%08x)\n", - fsize->pixel_format); - return -EINVAL; - } - - /* This only makes sense for coded formats */ - if (fmt->codec_mode == RK_VPU_MODE_NONE) - return -EINVAL; - - fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; - fsize->stepwise = fmt->frmsize; - - return 0; -} - -static int vidioc_enum_fmt(struct file *file, void *priv, - struct v4l2_fmtdesc *f, bool capture) - -{ - struct rockchip_vpu_ctx *ctx = fh_to_ctx(priv); - const struct rockchip_vpu_fmt *fmt, *formats; - unsigned int num_fmts, i, j = 0; - bool skip_mode_none; - - /* - * When dealing with an encoder: - * - on the capture side we want to filter out all MODE_NONE formats. - * - on the output side we want to filter out all formats that are - * not MODE_NONE. - * When dealing with a decoder: - * - on the capture side we want to filter out all formats that are - * not MODE_NONE. - * - on the output side we want to filter out all MODE_NONE formats. - */ - skip_mode_none = capture == rockchip_vpu_is_encoder_ctx(ctx); - - formats = rockchip_vpu_get_formats(ctx, &num_fmts); - for (i = 0; i < num_fmts; i++) { - bool mode_none = formats[i].codec_mode == RK_VPU_MODE_NONE; - - if (skip_mode_none == mode_none) - continue; - if (j == f->index) { - fmt = &formats[i]; - f->pixelformat = fmt->fourcc; - return 0; - } - ++j; - } - return -EINVAL; -} - -static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - return vidioc_enum_fmt(file, priv, f, true); -} - -static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - return vidioc_enum_fmt(file, priv, f, false); -} - -static int vidioc_g_fmt_out_mplane(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; - struct rockchip_vpu_ctx *ctx = fh_to_ctx(priv); - - vpu_debug(4, "f->type = %d\n", f->type); - - *pix_mp = ctx->src_fmt; - - return 0; -} - -static int vidioc_g_fmt_cap_mplane(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; - struct rockchip_vpu_ctx *ctx = fh_to_ctx(priv); - - vpu_debug(4, "f->type = %d\n", f->type); - - *pix_mp = ctx->dst_fmt; - - return 0; -} - -static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f, - bool capture) -{ - struct rockchip_vpu_ctx *ctx = fh_to_ctx(priv); - struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; - const struct rockchip_vpu_fmt *formats, *fmt, *vpu_fmt; - unsigned int num_fmts; - bool coded; - - coded = capture == rockchip_vpu_is_encoder_ctx(ctx); - - vpu_debug(4, "trying format %c%c%c%c\n", - (pix_mp->pixelformat & 0x7f), - (pix_mp->pixelformat >> 8) & 0x7f, - (pix_mp->pixelformat >> 16) & 0x7f, - (pix_mp->pixelformat >> 24) & 0x7f); - - formats = rockchip_vpu_get_formats(ctx, &num_fmts); - fmt = rockchip_vpu_find_format(formats, num_fmts, pix_mp->pixelformat); - if (!fmt) { - fmt = rockchip_vpu_get_default_fmt(formats, num_fmts, coded); - f->fmt.pix_mp.pixelformat = fmt->fourcc; - } - - if (coded) { - pix_mp->num_planes = 1; - vpu_fmt = fmt; - } else if (rockchip_vpu_is_encoder_ctx(ctx)) { - vpu_fmt = ctx->vpu_dst_fmt; - } else { - vpu_fmt = ctx->vpu_src_fmt; - /* - * Width/height on the CAPTURE end of a decoder are ignored and - * replaced by the OUTPUT ones. - */ - pix_mp->width = ctx->src_fmt.width; - pix_mp->height = ctx->src_fmt.height; - } - - pix_mp->field = V4L2_FIELD_NONE; - - v4l2_apply_frmsize_constraints(&pix_mp->width, &pix_mp->height, - &vpu_fmt->frmsize); - - if (!coded) { - /* Fill remaining fields */ - v4l2_fill_pixfmt_mp(pix_mp, fmt->fourcc, pix_mp->width, - pix_mp->height); - } else if (!pix_mp->plane_fmt[0].sizeimage) { - /* - * For coded formats the application can specify - * sizeimage. If the application passes a zero sizeimage, - * let's default to the maximum frame size. - */ - pix_mp->plane_fmt[0].sizeimage = fmt->header_size + - pix_mp->width * pix_mp->height * fmt->max_depth; - } - - return 0; -} - -static int vidioc_try_fmt_cap_mplane(struct file *file, void *priv, - struct v4l2_format *f) -{ - return vidioc_try_fmt(file, priv, f, true); -} - -static int vidioc_try_fmt_out_mplane(struct file *file, void *priv, - struct v4l2_format *f) -{ - return vidioc_try_fmt(file, priv, f, false); -} - -static void -rockchip_vpu_reset_fmt(struct v4l2_pix_format_mplane *fmt, - const struct rockchip_vpu_fmt *vpu_fmt) -{ - memset(fmt, 0, sizeof(*fmt)); - - fmt->pixelformat = vpu_fmt->fourcc; - fmt->field = V4L2_FIELD_NONE; - fmt->colorspace = V4L2_COLORSPACE_JPEG, - fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; - fmt->quantization = V4L2_QUANTIZATION_DEFAULT; - fmt->xfer_func = V4L2_XFER_FUNC_DEFAULT; -} - -static void -rockchip_vpu_reset_encoded_fmt(struct rockchip_vpu_ctx *ctx) -{ - const struct rockchip_vpu_fmt *vpu_fmt, *formats; - struct v4l2_pix_format_mplane *fmt; - unsigned int num_fmts; - - formats = rockchip_vpu_get_formats(ctx, &num_fmts); - vpu_fmt = rockchip_vpu_get_default_fmt(formats, num_fmts, true); - - if (rockchip_vpu_is_encoder_ctx(ctx)) { - ctx->vpu_dst_fmt = vpu_fmt; - fmt = &ctx->dst_fmt; - } else { - ctx->vpu_src_fmt = vpu_fmt; - fmt = &ctx->src_fmt; - } - - rockchip_vpu_reset_fmt(fmt, vpu_fmt); - fmt->num_planes = 1; - fmt->width = vpu_fmt->frmsize.min_width; - fmt->height = vpu_fmt->frmsize.min_height; - fmt->plane_fmt[0].sizeimage = vpu_fmt->header_size + - fmt->width * fmt->height * vpu_fmt->max_depth; -} - -static void -rockchip_vpu_reset_raw_fmt(struct rockchip_vpu_ctx *ctx) -{ - const struct rockchip_vpu_fmt *raw_vpu_fmt, *formats; - struct v4l2_pix_format_mplane *raw_fmt, *encoded_fmt; - unsigned int num_fmts; - - formats = rockchip_vpu_get_formats(ctx, &num_fmts); - raw_vpu_fmt = rockchip_vpu_get_default_fmt(formats, num_fmts, false); - - if (rockchip_vpu_is_encoder_ctx(ctx)) { - ctx->vpu_src_fmt = raw_vpu_fmt; - raw_fmt = &ctx->src_fmt; - encoded_fmt = &ctx->dst_fmt; - } else { - ctx->vpu_dst_fmt = raw_vpu_fmt; - raw_fmt = &ctx->dst_fmt; - encoded_fmt = &ctx->src_fmt; - } - - rockchip_vpu_reset_fmt(raw_fmt, raw_vpu_fmt); - v4l2_fill_pixfmt_mp(raw_fmt, raw_vpu_fmt->fourcc, - encoded_fmt->width, - encoded_fmt->height); -} - -void rockchip_vpu_reset_fmts(struct rockchip_vpu_ctx *ctx) -{ - rockchip_vpu_reset_encoded_fmt(ctx); - rockchip_vpu_reset_raw_fmt(ctx); -} - -static void -rockchip_vpu_update_requires_request(struct rockchip_vpu_ctx *ctx, - u32 fourcc) -{ - switch (fourcc) { - case V4L2_PIX_FMT_JPEG: - ctx->fh.m2m_ctx->out_q_ctx.q.requires_requests = false; - break; - case V4L2_PIX_FMT_MPEG2_SLICE: - ctx->fh.m2m_ctx->out_q_ctx.q.requires_requests = true; - break; - default: - break; - } -} - -static int -vidioc_s_fmt_out_mplane(struct file *file, void *priv, struct v4l2_format *f) -{ - struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; - struct rockchip_vpu_ctx *ctx = fh_to_ctx(priv); - const struct rockchip_vpu_fmt *formats; - unsigned int num_fmts; - struct vb2_queue *vq; - int ret; - - /* Change not allowed if queue is busy. */ - vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); - if (vb2_is_busy(vq)) - return -EBUSY; - - if (!rockchip_vpu_is_encoder_ctx(ctx)) { - struct vb2_queue *peer_vq; - - /* - * Since format change on the OUTPUT queue will reset - * the CAPTURE queue, we can't allow doing so - * when the CAPTURE queue has buffers allocated. - */ - peer_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, - V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); - if (vb2_is_busy(peer_vq)) - return -EBUSY; - } - - ret = vidioc_try_fmt_out_mplane(file, priv, f); - if (ret) - return ret; - - formats = rockchip_vpu_get_formats(ctx, &num_fmts); - ctx->vpu_src_fmt = rockchip_vpu_find_format(formats, num_fmts, - pix_mp->pixelformat); - ctx->src_fmt = *pix_mp; - - /* - * Current raw format might have become invalid with newly - * selected codec, so reset it to default just to be safe and - * keep internal driver state sane. User is mandated to set - * the raw format again after we return, so we don't need - * anything smarter. - * Note that rockchip_vpu_reset_raw_fmt() also propagates size - * changes to the raw format. - */ - if (!rockchip_vpu_is_encoder_ctx(ctx)) - rockchip_vpu_reset_raw_fmt(ctx); - - /* Colorimetry information are always propagated. */ - ctx->dst_fmt.colorspace = pix_mp->colorspace; - ctx->dst_fmt.ycbcr_enc = pix_mp->ycbcr_enc; - ctx->dst_fmt.xfer_func = pix_mp->xfer_func; - ctx->dst_fmt.quantization = pix_mp->quantization; - - rockchip_vpu_update_requires_request(ctx, pix_mp->pixelformat); - - vpu_debug(0, "OUTPUT codec mode: %d\n", ctx->vpu_src_fmt->codec_mode); - vpu_debug(0, "fmt - w: %d, h: %d\n", - pix_mp->width, pix_mp->height); - return 0; -} - -static int vidioc_s_fmt_cap_mplane(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; - struct rockchip_vpu_ctx *ctx = fh_to_ctx(priv); - const struct rockchip_vpu_fmt *formats; - struct vb2_queue *vq; - unsigned int num_fmts; - int ret; - - /* Change not allowed if queue is busy. */ - vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); - if (vb2_is_busy(vq)) - return -EBUSY; - - if (rockchip_vpu_is_encoder_ctx(ctx)) { - struct vb2_queue *peer_vq; - - /* - * Since format change on the CAPTURE queue will reset - * the OUTPUT queue, we can't allow doing so - * when the OUTPUT queue has buffers allocated. - */ - peer_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, - V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); - if (vb2_is_busy(peer_vq) && - (pix_mp->pixelformat != ctx->dst_fmt.pixelformat || - pix_mp->height != ctx->dst_fmt.height || - pix_mp->width != ctx->dst_fmt.width)) - return -EBUSY; - } - - ret = vidioc_try_fmt_cap_mplane(file, priv, f); - if (ret) - return ret; - - formats = rockchip_vpu_get_formats(ctx, &num_fmts); - ctx->vpu_dst_fmt = rockchip_vpu_find_format(formats, num_fmts, - pix_mp->pixelformat); - ctx->dst_fmt = *pix_mp; - - /* - * Current raw format might have become invalid with newly - * selected codec, so reset it to default just to be safe and - * keep internal driver state sane. User is mandated to set - * the raw format again after we return, so we don't need - * anything smarter. - * Note that rockchip_vpu_reset_raw_fmt() also propagates size - * changes to the raw format. - */ - if (rockchip_vpu_is_encoder_ctx(ctx)) - rockchip_vpu_reset_raw_fmt(ctx); - - /* Colorimetry information are always propagated. */ - ctx->src_fmt.colorspace = pix_mp->colorspace; - ctx->src_fmt.ycbcr_enc = pix_mp->ycbcr_enc; - ctx->src_fmt.xfer_func = pix_mp->xfer_func; - ctx->src_fmt.quantization = pix_mp->quantization; - - vpu_debug(0, "CAPTURE codec mode: %d\n", ctx->vpu_dst_fmt->codec_mode); - vpu_debug(0, "fmt - w: %d, h: %d\n", - pix_mp->width, pix_mp->height); - - rockchip_vpu_update_requires_request(ctx, pix_mp->pixelformat); - - return 0; -} - -const struct v4l2_ioctl_ops rockchip_vpu_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_enum_framesizes = vidioc_enum_framesizes, - - .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_cap_mplane, - .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt_out_mplane, - .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt_out_mplane, - .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_cap_mplane, - .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt_out_mplane, - .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt_cap_mplane, - .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, - .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, - - .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, - .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, - .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, - .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, - .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, - .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, - .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, - - .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, - - .vidioc_streamon = v4l2_m2m_ioctl_streamon, - .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, -}; - -static int -rockchip_vpu_queue_setup(struct vb2_queue *vq, - unsigned int *num_buffers, - unsigned int *num_planes, - unsigned int sizes[], - struct device *alloc_devs[]) -{ - struct rockchip_vpu_ctx *ctx = vb2_get_drv_priv(vq); - struct v4l2_pix_format_mplane *pixfmt; - int i; - - switch (vq->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - pixfmt = &ctx->dst_fmt; - break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - pixfmt = &ctx->src_fmt; - break; - default: - vpu_err("invalid queue type: %d\n", vq->type); - return -EINVAL; - } - - if (*num_planes) { - if (*num_planes != pixfmt->num_planes) - return -EINVAL; - for (i = 0; i < pixfmt->num_planes; ++i) - if (sizes[i] < pixfmt->plane_fmt[i].sizeimage) - return -EINVAL; - return 0; - } - - *num_planes = pixfmt->num_planes; - for (i = 0; i < pixfmt->num_planes; ++i) - sizes[i] = pixfmt->plane_fmt[i].sizeimage; - return 0; -} - -static int -rockchip_vpu_buf_plane_check(struct vb2_buffer *vb, - const struct rockchip_vpu_fmt *vpu_fmt, - struct v4l2_pix_format_mplane *pixfmt) -{ - unsigned int sz; - int i; - - for (i = 0; i < pixfmt->num_planes; ++i) { - sz = pixfmt->plane_fmt[i].sizeimage; - vpu_debug(4, "plane %d size: %ld, sizeimage: %u\n", - i, vb2_plane_size(vb, i), sz); - if (vb2_plane_size(vb, i) < sz) { - vpu_err("plane %d is too small for output\n", i); - return -EINVAL; - } - } - return 0; -} - -static int rockchip_vpu_buf_prepare(struct vb2_buffer *vb) -{ - struct vb2_queue *vq = vb->vb2_queue; - struct rockchip_vpu_ctx *ctx = vb2_get_drv_priv(vq); - - if (V4L2_TYPE_IS_OUTPUT(vq->type)) - return rockchip_vpu_buf_plane_check(vb, ctx->vpu_src_fmt, - &ctx->src_fmt); - - return rockchip_vpu_buf_plane_check(vb, ctx->vpu_dst_fmt, - &ctx->dst_fmt); -} - -static void rockchip_vpu_buf_queue(struct vb2_buffer *vb) -{ - struct rockchip_vpu_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - - v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); -} - -static bool rockchip_vpu_vq_is_coded(struct vb2_queue *q) -{ - struct rockchip_vpu_ctx *ctx = vb2_get_drv_priv(q); - - return rockchip_vpu_is_encoder_ctx(ctx) != V4L2_TYPE_IS_OUTPUT(q->type); -} - -static int rockchip_vpu_start_streaming(struct vb2_queue *q, - unsigned int count) -{ - struct rockchip_vpu_ctx *ctx = vb2_get_drv_priv(q); - int ret = 0; - - if (V4L2_TYPE_IS_OUTPUT(q->type)) - ctx->sequence_out = 0; - else - ctx->sequence_cap = 0; - - if (rockchip_vpu_vq_is_coded(q)) { - enum rockchip_vpu_codec_mode codec_mode; - - if (V4L2_TYPE_IS_OUTPUT(q->type)) - codec_mode = ctx->vpu_src_fmt->codec_mode; - else - codec_mode = ctx->vpu_dst_fmt->codec_mode; - - vpu_debug(4, "Codec mode = %d\n", codec_mode); - ctx->codec_ops = &ctx->dev->variant->codec_ops[codec_mode]; - if (ctx->codec_ops && ctx->codec_ops->init) - ret = ctx->codec_ops->init(ctx); - } - - return ret; -} - -static void -rockchip_vpu_return_bufs(struct vb2_queue *q, - struct vb2_v4l2_buffer *(*buf_remove)(struct v4l2_m2m_ctx *)) -{ - struct rockchip_vpu_ctx *ctx = vb2_get_drv_priv(q); - - for (;;) { - struct vb2_v4l2_buffer *vbuf; - - vbuf = buf_remove(ctx->fh.m2m_ctx); - if (!vbuf) - break; - v4l2_ctrl_request_complete(vbuf->vb2_buf.req_obj.req, - &ctx->ctrl_handler); - v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); - } -} - -static void rockchip_vpu_stop_streaming(struct vb2_queue *q) -{ - struct rockchip_vpu_ctx *ctx = vb2_get_drv_priv(q); - - if (rockchip_vpu_vq_is_coded(q)) { - if (ctx->codec_ops && ctx->codec_ops->exit) - ctx->codec_ops->exit(ctx); - } - - /* - * The mem2mem framework calls v4l2_m2m_cancel_job before - * .stop_streaming, so there isn't any job running and - * it is safe to return all the buffers. - */ - if (V4L2_TYPE_IS_OUTPUT(q->type)) - rockchip_vpu_return_bufs(q, v4l2_m2m_src_buf_remove); - else - rockchip_vpu_return_bufs(q, v4l2_m2m_dst_buf_remove); -} - -static void rockchip_vpu_buf_request_complete(struct vb2_buffer *vb) -{ - struct rockchip_vpu_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); - - v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->ctrl_handler); -} - -static int rockchip_vpu_buf_out_validate(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - - vbuf->field = V4L2_FIELD_NONE; - return 0; -} - -const struct vb2_ops rockchip_vpu_queue_ops = { - .queue_setup = rockchip_vpu_queue_setup, - .buf_prepare = rockchip_vpu_buf_prepare, - .buf_queue = rockchip_vpu_buf_queue, - .buf_out_validate = rockchip_vpu_buf_out_validate, - .buf_request_complete = rockchip_vpu_buf_request_complete, - .start_streaming = rockchip_vpu_start_streaming, - .stop_streaming = rockchip_vpu_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, -}; diff --git a/drivers/staging/media/rockchip/vpu/rockchip_vpu_v4l2.h b/drivers/staging/media/rockchip/vpu/rockchip_vpu_v4l2.h deleted file mode 100644 index 493e8751d22d..000000000000 --- a/drivers/staging/media/rockchip/vpu/rockchip_vpu_v4l2.h +++ /dev/null @@ -1,26 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Rockchip VPU codec driver - * - * Copyright (C) 2018 Rockchip Electronics Co., Ltd. - * Alpha Lin - * Jeffy Chen - * - * Copyright 2018 Google LLC. - * Tomasz Figa - * - * Based on s5p-mfc driver by Samsung Electronics Co., Ltd. - * Copyright (C) 2011 Samsung Electronics Co., Ltd. - */ - -#ifndef ROCKCHIP_VPU_V4L2_H_ -#define ROCKCHIP_VPU_V4L2_H_ - -#include "rockchip_vpu.h" - -extern const struct v4l2_ioctl_ops rockchip_vpu_ioctl_ops; -extern const struct vb2_ops rockchip_vpu_queue_ops; - -void rockchip_vpu_reset_fmts(struct rockchip_vpu_ctx *ctx); - -#endif /* ROCKCHIP_VPU_V4L2_H_ */ -- cgit v1.2.3 From de7a0020901e4647fe3549e7f66ec6f28cae5dd7 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Fri, 7 Jun 2019 04:35:18 -0400 Subject: media: MAINTAINERS: media: Add Tomasz Figa as a videobuf2 reviewer I tend to review most of the vb2 patches anyway and we need some active reviewers, so let add me to the MAINTAINERS file as such. Signed-off-by: Tomasz Figa Acked-by: Marek Szyprowski Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) (limited to 'MAINTAINERS') diff --git a/MAINTAINERS b/MAINTAINERS index 29cca8aabf19..ad2bf808b02c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -16721,6 +16721,7 @@ VIDEOBUF2 FRAMEWORK M: Pawel Osciak M: Marek Szyprowski M: Kyungmin Park +R: Tomasz Figa L: linux-media@vger.kernel.org S: Maintained F: drivers/media/common/videobuf2/* -- cgit v1.2.3 From 0a0e265515db7619d0da9331d74245d02c741f07 Mon Sep 17 00:00:00 2001 From: Eugen Hristev Date: Wed, 12 Jun 2019 08:00:31 -0400 Subject: media: atmel: atmel-isc: split driver into driver base and isc This splits the Atmel ISC driver into a common base: atmel-isc-base.c and the driver probe/dt part , atmel-sama5d2-isc.c This is needed to keep a common ground for the sensor controller which will be reused. The atmel-isc will use the common symbols inside the atmel-isc-base Future driver will also use the same symbols and redefine different aspects, for a different version of the ISC. This is done to avoid complete code duplication by creating a totally different driver for the new variant of the ISC. Signed-off-by: Eugen Hristev Signed-off-by: Hans Verkuil [hverkuil-cisco@xs4all.nl: folded 'atmel: atmel-sama5d2-isc: fixed checkpatch warnings' into this patch] Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 4 +- drivers/media/platform/atmel/Makefile | 4 +- drivers/media/platform/atmel/atmel-isc-base.c | 2153 ++++++++++++++++++ drivers/media/platform/atmel/atmel-isc.c | 2631 ---------------------- drivers/media/platform/atmel/atmel-isc.h | 249 ++ drivers/media/platform/atmel/atmel-sama5d2-isc.c | 344 +++ 6 files changed, 2752 insertions(+), 2633 deletions(-) create mode 100644 drivers/media/platform/atmel/atmel-isc-base.c delete mode 100644 drivers/media/platform/atmel/atmel-isc.c create mode 100644 drivers/media/platform/atmel/atmel-isc.h create mode 100644 drivers/media/platform/atmel/atmel-sama5d2-isc.c (limited to 'MAINTAINERS') diff --git a/MAINTAINERS b/MAINTAINERS index ad2bf808b02c..bf32079578fb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10296,7 +10296,9 @@ MICROCHIP ISC DRIVER M: Eugen Hristev L: linux-media@vger.kernel.org S: Supported -F: drivers/media/platform/atmel/atmel-isc.c +F: drivers/media/platform/atmel/atmel-sama5d2-isc.c +F: drivers/media/platform/atmel/atmel-isc.h +F: drivers/media/platform/atmel/atmel-isc-base.c F: drivers/media/platform/atmel/atmel-isc-regs.h F: Documentation/devicetree/bindings/media/atmel-isc.txt diff --git a/drivers/media/platform/atmel/Makefile b/drivers/media/platform/atmel/Makefile index 484936604ccb..2dba38994a70 100644 --- a/drivers/media/platform/atmel/Makefile +++ b/drivers/media/platform/atmel/Makefile @@ -1,3 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_VIDEO_ATMEL_ISC) += atmel-isc.o +atmel-isc-objs = atmel-sama5d2-isc.o atmel-isc-base.o + obj-$(CONFIG_VIDEO_ATMEL_ISI) += atmel-isi.o +obj-$(CONFIG_VIDEO_ATMEL_ISC) += atmel-isc.o diff --git a/drivers/media/platform/atmel/atmel-isc-base.c b/drivers/media/platform/atmel/atmel-isc-base.c new file mode 100644 index 000000000000..edfd7e00a565 --- /dev/null +++ b/drivers/media/platform/atmel/atmel-isc-base.c @@ -0,0 +1,2153 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Microchip Image Sensor Controller (ISC) common driver base + * + * Copyright (C) 2016-2019 Microchip Technology, Inc. + * + * Author: Songjun Wu + * Author: Eugen Hristev + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "atmel-isc-regs.h" +#include "atmel-isc.h" + +unsigned int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "debug level (0-2)"); + +unsigned int sensor_preferred = 1; +module_param(sensor_preferred, uint, 0644); +MODULE_PARM_DESC(sensor_preferred, + "Sensor is preferred to output the specified format (1-on 0-off), default 1"); + +/* This is a list of the formats that the ISC can *output* */ +struct isc_format controller_formats[] = { + { + .fourcc = V4L2_PIX_FMT_ARGB444, + }, + { + .fourcc = V4L2_PIX_FMT_ARGB555, + }, + { + .fourcc = V4L2_PIX_FMT_RGB565, + }, + { + .fourcc = V4L2_PIX_FMT_ABGR32, + }, + { + .fourcc = V4L2_PIX_FMT_XBGR32, + }, + { + .fourcc = V4L2_PIX_FMT_YUV420, + }, + { + .fourcc = V4L2_PIX_FMT_YUYV, + }, + { + .fourcc = V4L2_PIX_FMT_YUV422P, + }, + { + .fourcc = V4L2_PIX_FMT_GREY, + }, +}; + +/* This is a list of formats that the ISC can receive as *input* */ +struct isc_format formats_list[] = { + { + .fourcc = V4L2_PIX_FMT_SBGGR8, + .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, + .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, + .cfa_baycfg = ISC_BAY_CFG_BGBG, + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG8, + .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8, + .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, + .cfa_baycfg = ISC_BAY_CFG_GBGB, + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG8, + .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, + .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, + .cfa_baycfg = ISC_BAY_CFG_GRGR, + }, + { + .fourcc = V4L2_PIX_FMT_SRGGB8, + .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8, + .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, + .cfa_baycfg = ISC_BAY_CFG_RGRG, + }, + { + .fourcc = V4L2_PIX_FMT_SBGGR10, + .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, + .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN, + .cfa_baycfg = ISC_BAY_CFG_RGRG, + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG10, + .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10, + .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN, + .cfa_baycfg = ISC_BAY_CFG_GBGB, + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG10, + .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, + .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN, + .cfa_baycfg = ISC_BAY_CFG_GRGR, + }, + { + .fourcc = V4L2_PIX_FMT_SRGGB10, + .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10, + .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN, + .cfa_baycfg = ISC_BAY_CFG_RGRG, + }, + { + .fourcc = V4L2_PIX_FMT_SBGGR12, + .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12, + .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE, + .cfa_baycfg = ISC_BAY_CFG_BGBG, + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG12, + .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12, + .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE, + .cfa_baycfg = ISC_BAY_CFG_GBGB, + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG12, + .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12, + .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE, + .cfa_baycfg = ISC_BAY_CFG_GRGR, + }, + { + .fourcc = V4L2_PIX_FMT_SRGGB12, + .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12, + .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE, + .cfa_baycfg = ISC_BAY_CFG_RGRG, + }, + { + .fourcc = V4L2_PIX_FMT_GREY, + .mbus_code = MEDIA_BUS_FMT_Y8_1X8, + .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, + }, + { + .fourcc = V4L2_PIX_FMT_YUYV, + .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, + .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, + }, + { + .fourcc = V4L2_PIX_FMT_RGB565, + .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE, + .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, + }, +}; + +/* Gamma table with gamma 1/2.2 */ +const u32 isc_gamma_table[GAMMA_MAX + 1][GAMMA_ENTRIES] = { + /* 0 --> gamma 1/1.8 */ + { 0x65, 0x66002F, 0x950025, 0xBB0020, 0xDB001D, 0xF8001A, + 0x1130018, 0x12B0017, 0x1420016, 0x1580014, 0x16D0013, 0x1810012, + 0x1940012, 0x1A60012, 0x1B80011, 0x1C90010, 0x1DA0010, 0x1EA000F, + 0x1FA000F, 0x209000F, 0x218000F, 0x227000E, 0x235000E, 0x243000E, + 0x251000E, 0x25F000D, 0x26C000D, 0x279000D, 0x286000D, 0x293000C, + 0x2A0000C, 0x2AC000C, 0x2B8000C, 0x2C4000C, 0x2D0000B, 0x2DC000B, + 0x2E7000B, 0x2F3000B, 0x2FE000B, 0x309000B, 0x314000B, 0x31F000A, + 0x32A000A, 0x334000B, 0x33F000A, 0x349000A, 0x354000A, 0x35E000A, + 0x368000A, 0x372000A, 0x37C000A, 0x386000A, 0x3900009, 0x399000A, + 0x3A30009, 0x3AD0009, 0x3B60009, 0x3BF000A, 0x3C90009, 0x3D20009, + 0x3DB0009, 0x3E40009, 0x3ED0009, 0x3F60009 }, + + /* 1 --> gamma 1/2 */ + { 0x7F, 0x800034, 0xB50028, 0xDE0021, 0x100001E, 0x11E001B, + 0x1390019, 0x1520017, 0x16A0015, 0x1800014, 0x1940014, 0x1A80013, + 0x1BB0012, 0x1CD0011, 0x1DF0010, 0x1EF0010, 0x200000F, 0x20F000F, + 0x21F000E, 0x22D000F, 0x23C000E, 0x24A000E, 0x258000D, 0x265000D, + 0x273000C, 0x27F000D, 0x28C000C, 0x299000C, 0x2A5000C, 0x2B1000B, + 0x2BC000C, 0x2C8000B, 0x2D3000C, 0x2DF000B, 0x2EA000A, 0x2F5000A, + 0x2FF000B, 0x30A000A, 0x314000B, 0x31F000A, 0x329000A, 0x333000A, + 0x33D0009, 0x3470009, 0x350000A, 0x35A0009, 0x363000A, 0x36D0009, + 0x3760009, 0x37F0009, 0x3880009, 0x3910009, 0x39A0009, 0x3A30009, + 0x3AC0008, 0x3B40009, 0x3BD0008, 0x3C60008, 0x3CE0008, 0x3D60009, + 0x3DF0008, 0x3E70008, 0x3EF0008, 0x3F70008 }, + + /* 2 --> gamma 1/2.2 */ + { 0x99, 0x9B0038, 0xD4002A, 0xFF0023, 0x122001F, 0x141001B, + 0x15D0019, 0x1760017, 0x18E0015, 0x1A30015, 0x1B80013, 0x1CC0012, + 0x1DE0011, 0x1F00010, 0x2010010, 0x2110010, 0x221000F, 0x230000F, + 0x23F000E, 0x24D000E, 0x25B000D, 0x269000C, 0x276000C, 0x283000C, + 0x28F000C, 0x29B000C, 0x2A7000C, 0x2B3000B, 0x2BF000B, 0x2CA000B, + 0x2D5000B, 0x2E0000A, 0x2EB000A, 0x2F5000A, 0x2FF000A, 0x30A000A, + 0x3140009, 0x31E0009, 0x327000A, 0x3310009, 0x33A0009, 0x3440009, + 0x34D0009, 0x3560009, 0x35F0009, 0x3680008, 0x3710008, 0x3790009, + 0x3820008, 0x38A0008, 0x3930008, 0x39B0008, 0x3A30008, 0x3AB0008, + 0x3B30008, 0x3BB0008, 0x3C30008, 0x3CB0007, 0x3D20008, 0x3DA0007, + 0x3E20007, 0x3E90007, 0x3F00008, 0x3F80007 }, +}; + +#define ISC_IS_FORMAT_RAW(mbus_code) \ + (((mbus_code) & 0xf000) == 0x3000) + +static inline void isc_update_awb_ctrls(struct isc_device *isc) +{ + struct isc_ctrls *ctrls = &isc->ctrls; + + regmap_write(isc->regmap, ISC_WB_O_RGR, + (ISC_WB_O_ZERO_VAL - (ctrls->offset[ISC_HIS_CFG_MODE_R])) | + ((ISC_WB_O_ZERO_VAL - ctrls->offset[ISC_HIS_CFG_MODE_GR]) << 16)); + regmap_write(isc->regmap, ISC_WB_O_BGB, + (ISC_WB_O_ZERO_VAL - (ctrls->offset[ISC_HIS_CFG_MODE_B])) | + ((ISC_WB_O_ZERO_VAL - ctrls->offset[ISC_HIS_CFG_MODE_GB]) << 16)); + regmap_write(isc->regmap, ISC_WB_G_RGR, + ctrls->gain[ISC_HIS_CFG_MODE_R] | + (ctrls->gain[ISC_HIS_CFG_MODE_GR] << 16)); + regmap_write(isc->regmap, ISC_WB_G_BGB, + ctrls->gain[ISC_HIS_CFG_MODE_B] | + (ctrls->gain[ISC_HIS_CFG_MODE_GB] << 16)); +} + +static inline void isc_reset_awb_ctrls(struct isc_device *isc) +{ + int c; + + for (c = ISC_HIS_CFG_MODE_GR; c <= ISC_HIS_CFG_MODE_B; c++) { + /* gains have a fixed point at 9 decimals */ + isc->ctrls.gain[c] = 1 << 9; + /* offsets are in 2's complements, the value + * will be substracted from ISC_WB_O_ZERO_VAL to obtain + * 2's complement of a value between 0 and + * ISC_WB_O_ZERO_VAL >> 1 + */ + isc->ctrls.offset[c] = ISC_WB_O_ZERO_VAL; + } +} + +static int isc_wait_clk_stable(struct clk_hw *hw) +{ + struct isc_clk *isc_clk = to_isc_clk(hw); + struct regmap *regmap = isc_clk->regmap; + unsigned long timeout = jiffies + usecs_to_jiffies(1000); + unsigned int status; + + while (time_before(jiffies, timeout)) { + regmap_read(regmap, ISC_CLKSR, &status); + if (!(status & ISC_CLKSR_SIP)) + return 0; + + usleep_range(10, 250); + } + + return -ETIMEDOUT; +} + +static int isc_clk_prepare(struct clk_hw *hw) +{ + struct isc_clk *isc_clk = to_isc_clk(hw); + + if (isc_clk->id == ISC_ISPCK) + pm_runtime_get_sync(isc_clk->dev); + + return isc_wait_clk_stable(hw); +} + +static void isc_clk_unprepare(struct clk_hw *hw) +{ + struct isc_clk *isc_clk = to_isc_clk(hw); + + isc_wait_clk_stable(hw); + + if (isc_clk->id == ISC_ISPCK) + pm_runtime_put_sync(isc_clk->dev); +} + +static int isc_clk_enable(struct clk_hw *hw) +{ + struct isc_clk *isc_clk = to_isc_clk(hw); + u32 id = isc_clk->id; + struct regmap *regmap = isc_clk->regmap; + unsigned long flags; + unsigned int status; + + dev_dbg(isc_clk->dev, "ISC CLK: %s, div = %d, parent id = %d\n", + __func__, isc_clk->div, isc_clk->parent_id); + + spin_lock_irqsave(&isc_clk->lock, flags); + regmap_update_bits(regmap, ISC_CLKCFG, + ISC_CLKCFG_DIV_MASK(id) | ISC_CLKCFG_SEL_MASK(id), + (isc_clk->div << ISC_CLKCFG_DIV_SHIFT(id)) | + (isc_clk->parent_id << ISC_CLKCFG_SEL_SHIFT(id))); + + regmap_write(regmap, ISC_CLKEN, ISC_CLK(id)); + spin_unlock_irqrestore(&isc_clk->lock, flags); + + regmap_read(regmap, ISC_CLKSR, &status); + if (status & ISC_CLK(id)) + return 0; + else + return -EINVAL; +} + +static void isc_clk_disable(struct clk_hw *hw) +{ + struct isc_clk *isc_clk = to_isc_clk(hw); + u32 id = isc_clk->id; + unsigned long flags; + + spin_lock_irqsave(&isc_clk->lock, flags); + regmap_write(isc_clk->regmap, ISC_CLKDIS, ISC_CLK(id)); + spin_unlock_irqrestore(&isc_clk->lock, flags); +} + +static int isc_clk_is_enabled(struct clk_hw *hw) +{ + struct isc_clk *isc_clk = to_isc_clk(hw); + u32 status; + + if (isc_clk->id == ISC_ISPCK) + pm_runtime_get_sync(isc_clk->dev); + + regmap_read(isc_clk->regmap, ISC_CLKSR, &status); + + if (isc_clk->id == ISC_ISPCK) + pm_runtime_put_sync(isc_clk->dev); + + return status & ISC_CLK(isc_clk->id) ? 1 : 0; +} + +static unsigned long +isc_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) +{ + struct isc_clk *isc_clk = to_isc_clk(hw); + + return DIV_ROUND_CLOSEST(parent_rate, isc_clk->div + 1); +} + +static int isc_clk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct isc_clk *isc_clk = to_isc_clk(hw); + long best_rate = -EINVAL; + int best_diff = -1; + unsigned int i, div; + + for (i = 0; i < clk_hw_get_num_parents(hw); i++) { + struct clk_hw *parent; + unsigned long parent_rate; + + parent = clk_hw_get_parent_by_index(hw, i); + if (!parent) + continue; + + parent_rate = clk_hw_get_rate(parent); + if (!parent_rate) + continue; + + for (div = 1; div < ISC_CLK_MAX_DIV + 2; div++) { + unsigned long rate; + int diff; + + rate = DIV_ROUND_CLOSEST(parent_rate, div); + diff = abs(req->rate - rate); + + if (best_diff < 0 || best_diff > diff) { + best_rate = rate; + best_diff = diff; + req->best_parent_rate = parent_rate; + req->best_parent_hw = parent; + } + + if (!best_diff || rate < req->rate) + break; + } + + if (!best_diff) + break; + } + + dev_dbg(isc_clk->dev, + "ISC CLK: %s, best_rate = %ld, parent clk: %s @ %ld\n", + __func__, best_rate, + __clk_get_name((req->best_parent_hw)->clk), + req->best_parent_rate); + + if (best_rate < 0) + return best_rate; + + req->rate = best_rate; + + return 0; +} + +static int isc_clk_set_parent(struct clk_hw *hw, u8 index) +{ + struct isc_clk *isc_clk = to_isc_clk(hw); + + if (index >= clk_hw_get_num_parents(hw)) + return -EINVAL; + + isc_clk->parent_id = index; + + return 0; +} + +static u8 isc_clk_get_parent(struct clk_hw *hw) +{ + struct isc_clk *isc_clk = to_isc_clk(hw); + + return isc_clk->parent_id; +} + +static int isc_clk_set_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long parent_rate) +{ + struct isc_clk *isc_clk = to_isc_clk(hw); + u32 div; + + if (!rate) + return -EINVAL; + + div = DIV_ROUND_CLOSEST(parent_rate, rate); + if (div > (ISC_CLK_MAX_DIV + 1) || !div) + return -EINVAL; + + isc_clk->div = div - 1; + + return 0; +} + +static const struct clk_ops isc_clk_ops = { + .prepare = isc_clk_prepare, + .unprepare = isc_clk_unprepare, + .enable = isc_clk_enable, + .disable = isc_clk_disable, + .is_enabled = isc_clk_is_enabled, + .recalc_rate = isc_clk_recalc_rate, + .determine_rate = isc_clk_determine_rate, + .set_parent = isc_clk_set_parent, + .get_parent = isc_clk_get_parent, + .set_rate = isc_clk_set_rate, +}; + +static int isc_clk_register(struct isc_device *isc, unsigned int id) +{ + struct regmap *regmap = isc->regmap; + struct device_node *np = isc->dev->of_node; + struct isc_clk *isc_clk; + struct clk_init_data init; + const char *clk_name = np->name; + const char *parent_names[3]; + int num_parents; + + num_parents = of_clk_get_parent_count(np); + if (num_parents < 1 || num_parents > 3) + return -EINVAL; + + if (num_parents > 2 && id == ISC_ISPCK) + num_parents = 2; + + of_clk_parent_fill(np, parent_names, num_parents); + + if (id == ISC_MCK) + of_property_read_string(np, "clock-output-names", &clk_name); + else + clk_name = "isc-ispck"; + + init.parent_names = parent_names; + init.num_parents = num_parents; + init.name = clk_name; + init.ops = &isc_clk_ops; + init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE; + + isc_clk = &isc->isc_clks[id]; + isc_clk->hw.init = &init; + isc_clk->regmap = regmap; + isc_clk->id = id; + isc_clk->dev = isc->dev; + spin_lock_init(&isc_clk->lock); + + isc_clk->clk = clk_register(isc->dev, &isc_clk->hw); + if (IS_ERR(isc_clk->clk)) { + dev_err(isc->dev, "%s: clock register fail\n", clk_name); + return PTR_ERR(isc_clk->clk); + } else if (id == ISC_MCK) + of_clk_add_provider(np, of_clk_src_simple_get, isc_clk->clk); + + return 0; +} + +int isc_clk_init(struct isc_device *isc) +{ + unsigned int i; + int ret; + + for (i = 0; i < ARRAY_SIZE(isc->isc_clks); i++) + isc->isc_clks[i].clk = ERR_PTR(-EINVAL); + + for (i = 0; i < ARRAY_SIZE(isc->isc_clks); i++) { + ret = isc_clk_register(isc, i); + if (ret) + return ret; + } + + return 0; +} + +void isc_clk_cleanup(struct isc_device *isc) +{ + unsigned int i; + + of_clk_del_provider(isc->dev->of_node); + + for (i = 0; i < ARRAY_SIZE(isc->isc_clks); i++) { + struct isc_clk *isc_clk = &isc->isc_clks[i]; + + if (!IS_ERR(isc_clk->clk)) + clk_unregister(isc_clk->clk); + } +} + +static int isc_queue_setup(struct vb2_queue *vq, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], struct device *alloc_devs[]) +{ + struct isc_device *isc = vb2_get_drv_priv(vq); + unsigned int size = isc->fmt.fmt.pix.sizeimage; + + if (*nplanes) + return sizes[0] < size ? -EINVAL : 0; + + *nplanes = 1; + sizes[0] = size; + + return 0; +} + +static int isc_buffer_prepare(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct isc_device *isc = vb2_get_drv_priv(vb->vb2_queue); + unsigned long size = isc->fmt.fmt.pix.sizeimage; + + if (vb2_plane_size(vb, 0) < size) { + v4l2_err(&isc->v4l2_dev, "buffer too small (%lu < %lu)\n", + vb2_plane_size(vb, 0), size); + return -EINVAL; + } + + vb2_set_plane_payload(vb, 0, size); + + vbuf->field = isc->fmt.fmt.pix.field; + + return 0; +} + +static void isc_start_dma(struct isc_device *isc) +{ + struct regmap *regmap = isc->regmap; + u32 sizeimage = isc->fmt.fmt.pix.sizeimage; + u32 dctrl_dview; + dma_addr_t addr0; + u32 h, w; + + h = isc->fmt.fmt.pix.height; + w = isc->fmt.fmt.pix.width; + + /* + * In case the sensor is not RAW, it will output a pixel (12-16 bits) + * with two samples on the ISC Data bus (which is 8-12) + * ISC will count each sample, so, we need to multiply these values + * by two, to get the real number of samples for the required pixels. + */ + if (!ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code)) { + h <<= 1; + w <<= 1; + } + + /* + * We limit the column/row count that the ISC will output according + * to the configured resolution that we want. + * This will avoid the situation where the sensor is misconfigured, + * sending more data, and the ISC will just take it and DMA to memory, + * causing corruption. + */ + regmap_write(regmap, ISC_PFE_CFG1, + (ISC_PFE_CFG1_COLMIN(0) & ISC_PFE_CFG1_COLMIN_MASK) | + (ISC_PFE_CFG1_COLMAX(w - 1) & ISC_PFE_CFG1_COLMAX_MASK)); + + regmap_write(regmap, ISC_PFE_CFG2, + (ISC_PFE_CFG2_ROWMIN(0) & ISC_PFE_CFG2_ROWMIN_MASK) | + (ISC_PFE_CFG2_ROWMAX(h - 1) & ISC_PFE_CFG2_ROWMAX_MASK)); + + regmap_update_bits(regmap, ISC_PFE_CFG0, + ISC_PFE_CFG0_COLEN | ISC_PFE_CFG0_ROWEN, + ISC_PFE_CFG0_COLEN | ISC_PFE_CFG0_ROWEN); + + addr0 = vb2_dma_contig_plane_dma_addr(&isc->cur_frm->vb.vb2_buf, 0); + regmap_write(regmap, ISC_DAD0, addr0); + + switch (isc->config.fourcc) { + case V4L2_PIX_FMT_YUV420: + regmap_write(regmap, ISC_DAD1, addr0 + (sizeimage * 2) / 3); + regmap_write(regmap, ISC_DAD2, addr0 + (sizeimage * 5) / 6); + break; + case V4L2_PIX_FMT_YUV422P: + regmap_write(regmap, ISC_DAD1, addr0 + sizeimage / 2); + regmap_write(regmap, ISC_DAD2, addr0 + (sizeimage * 3) / 4); + break; + default: + break; + } + + dctrl_dview = isc->config.dctrl_dview; + + regmap_write(regmap, ISC_DCTRL, dctrl_dview | ISC_DCTRL_IE_IS); + spin_lock(&isc->awb_lock); + regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_CAPTURE); + spin_unlock(&isc->awb_lock); +} + +static void isc_set_pipeline(struct isc_device *isc, u32 pipeline) +{ + struct regmap *regmap = isc->regmap; + struct isc_ctrls *ctrls = &isc->ctrls; + u32 val, bay_cfg; + const u32 *gamma; + unsigned int i; + + /* WB-->CFA-->CC-->GAM-->CSC-->CBC-->SUB422-->SUB420 */ + for (i = 0; i < ISC_PIPE_LINE_NODE_NUM; i++) { + val = pipeline & BIT(i) ? 1 : 0; + regmap_field_write(isc->pipeline[i], val); + } + + if (!pipeline) + return; + + bay_cfg = isc->config.sd_format->cfa_baycfg; + + if (ctrls->awb == ISC_WB_NONE) + isc_reset_awb_ctrls(isc); + + regmap_write(regmap, ISC_WB_CFG, bay_cfg); + isc_update_awb_ctrls(isc); + + regmap_write(regmap, ISC_CFA_CFG, bay_cfg | ISC_CFA_CFG_EITPOL); + + gamma = &isc_gamma_table[ctrls->gamma_index][0]; + regmap_bulk_write(regmap, ISC_GAM_BENTRY, gamma, GAMMA_ENTRIES); + regmap_bulk_write(regmap, ISC_GAM_GENTRY, gamma, GAMMA_ENTRIES); + regmap_bulk_write(regmap, ISC_GAM_RENTRY, gamma, GAMMA_ENTRIES); + + /* Convert RGB to YUV */ + regmap_write(regmap, ISC_CSC_YR_YG, 0x42 | (0x81 << 16)); + regmap_write(regmap, ISC_CSC_YB_OY, 0x19 | (0x10 << 16)); + regmap_write(regmap, ISC_CSC_CBR_CBG, 0xFDA | (0xFB6 << 16)); + regmap_write(regmap, ISC_CSC_CBB_OCB, 0x70 | (0x80 << 16)); + regmap_write(regmap, ISC_CSC_CRR_CRG, 0x70 | (0xFA2 << 16)); + regmap_write(regmap, ISC_CSC_CRB_OCR, 0xFEE | (0x80 << 16)); + + regmap_write(regmap, ISC_CBC_BRIGHT, ctrls->brightness); + regmap_write(regmap, ISC_CBC_CONTRAST, ctrls->contrast); +} + +static int isc_update_profile(struct isc_device *isc) +{ + struct regmap *regmap = isc->regmap; + u32 sr; + int counter = 100; + + regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_UPPRO); + + regmap_read(regmap, ISC_CTRLSR, &sr); + while ((sr & ISC_CTRL_UPPRO) && counter--) { + usleep_range(1000, 2000); + regmap_read(regmap, ISC_CTRLSR, &sr); + } + + if (counter < 0) { + v4l2_warn(&isc->v4l2_dev, "Time out to update profile\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static void isc_set_histogram(struct isc_device *isc, bool enable) +{ + struct regmap *regmap = isc->regmap; + struct isc_ctrls *ctrls = &isc->ctrls; + + if (enable) { + regmap_write(regmap, ISC_HIS_CFG, + ISC_HIS_CFG_MODE_GR | + (isc->config.sd_format->cfa_baycfg + << ISC_HIS_CFG_BAYSEL_SHIFT) | + ISC_HIS_CFG_RAR); + regmap_write(regmap, ISC_HIS_CTRL, ISC_HIS_CTRL_EN); + regmap_write(regmap, ISC_INTEN, ISC_INT_HISDONE); + ctrls->hist_id = ISC_HIS_CFG_MODE_GR; + isc_update_profile(isc); + regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_HISREQ); + + ctrls->hist_stat = HIST_ENABLED; + } else { + regmap_write(regmap, ISC_INTDIS, ISC_INT_HISDONE); + regmap_write(regmap, ISC_HIS_CTRL, ISC_HIS_CTRL_DIS); + + ctrls->hist_stat = HIST_DISABLED; + } +} + +static int isc_configure(struct isc_device *isc) +{ + struct regmap *regmap = isc->regmap; + u32 pfe_cfg0, rlp_mode, dcfg, mask, pipeline; + struct isc_subdev_entity *subdev = isc->current_subdev; + + pfe_cfg0 = isc->config.sd_format->pfe_cfg0_bps; + rlp_mode = isc->config.rlp_cfg_mode; + pipeline = isc->config.bits_pipeline; + + dcfg = isc->config.dcfg_imode | + ISC_DCFG_YMBSIZE_BEATS8 | ISC_DCFG_CMBSIZE_BEATS8; + + pfe_cfg0 |= subdev->pfe_cfg0 | ISC_PFE_CFG0_MODE_PROGRESSIVE; + mask = ISC_PFE_CFG0_BPS_MASK | ISC_PFE_CFG0_HPOL_LOW | + ISC_PFE_CFG0_VPOL_LOW | ISC_PFE_CFG0_PPOL_LOW | + ISC_PFE_CFG0_MODE_MASK | ISC_PFE_CFG0_CCIR_CRC | + ISC_PFE_CFG0_CCIR656; + + regmap_update_bits(regmap, ISC_PFE_CFG0, mask, pfe_cfg0); + + regmap_update_bits(regmap, ISC_RLP_CFG, ISC_RLP_CFG_MODE_MASK, + rlp_mode); + + regmap_write(regmap, ISC_DCFG, dcfg); + + /* Set the pipeline */ + isc_set_pipeline(isc, pipeline); + + /* + * The current implemented histogram is available for RAW R, B, GB, GR + * channels. We need to check if sensor is outputting RAW BAYER + */ + if (isc->ctrls.awb && + ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code)) + isc_set_histogram(isc, true); + else + isc_set_histogram(isc, false); + + /* Update profile */ + return isc_update_profile(isc); +} + +static int isc_start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct isc_device *isc = vb2_get_drv_priv(vq); + struct regmap *regmap = isc->regmap; + struct isc_buffer *buf; + unsigned long flags; + int ret; + + /* Enable stream on the sub device */ + ret = v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 1); + if (ret && ret != -ENOIOCTLCMD) { + v4l2_err(&isc->v4l2_dev, "stream on failed in subdev %d\n", + ret); + goto err_start_stream; + } + + pm_runtime_get_sync(isc->dev); + + ret = isc_configure(isc); + if (unlikely(ret)) + goto err_configure; + + /* Enable DMA interrupt */ + regmap_write(regmap, ISC_INTEN, ISC_INT_DDONE); + + spin_lock_irqsave(&isc->dma_queue_lock, flags); + + isc->sequence = 0; + isc->stop = false; + reinit_completion(&isc->comp); + + isc->cur_frm = list_first_entry(&isc->dma_queue, + struct isc_buffer, list); + list_del(&isc->cur_frm->list); + + isc_start_dma(isc); + + spin_unlock_irqrestore(&isc->dma_queue_lock, flags); + + /* if we streaming from RAW, we can do one-shot white balance adj */ + if (ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code)) + v4l2_ctrl_activate(isc->do_wb_ctrl, true); + + return 0; + +err_configure: + pm_runtime_put_sync(isc->dev); + + v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 0); + +err_start_stream: + spin_lock_irqsave(&isc->dma_queue_lock, flags); + list_for_each_entry(buf, &isc->dma_queue, list) + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED); + INIT_LIST_HEAD(&isc->dma_queue); + spin_unlock_irqrestore(&isc->dma_queue_lock, flags); + + return ret; +} + +static void isc_stop_streaming(struct vb2_queue *vq) +{ + struct isc_device *isc = vb2_get_drv_priv(vq); + unsigned long flags; + struct isc_buffer *buf; + int ret; + + v4l2_ctrl_activate(isc->do_wb_ctrl, false); + + isc->stop = true; + + /* Wait until the end of the current frame */ + if (isc->cur_frm && !wait_for_completion_timeout(&isc->comp, 5 * HZ)) + v4l2_err(&isc->v4l2_dev, + "Timeout waiting for end of the capture\n"); + + /* Disable DMA interrupt */ + regmap_write(isc->regmap, ISC_INTDIS, ISC_INT_DDONE); + + pm_runtime_put_sync(isc->dev); + + /* Disable stream on the sub device */ + ret = v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 0); + if (ret && ret != -ENOIOCTLCMD) + v4l2_err(&isc->v4l2_dev, "stream off failed in subdev\n"); + + /* Release all active buffers */ + spin_lock_irqsave(&isc->dma_queue_lock, flags); + if (unlikely(isc->cur_frm)) { + vb2_buffer_done(&isc->cur_frm->vb.vb2_buf, + VB2_BUF_STATE_ERROR); + isc->cur_frm = NULL; + } + list_for_each_entry(buf, &isc->dma_queue, list) + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + INIT_LIST_HEAD(&isc->dma_queue); + spin_unlock_irqrestore(&isc->dma_queue_lock, flags); +} + +static void isc_buffer_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct isc_buffer *buf = container_of(vbuf, struct isc_buffer, vb); + struct isc_device *isc = vb2_get_drv_priv(vb->vb2_queue); + unsigned long flags; + + spin_lock_irqsave(&isc->dma_queue_lock, flags); + if (!isc->cur_frm && list_empty(&isc->dma_queue) && + vb2_is_streaming(vb->vb2_queue)) { + isc->cur_frm = buf; + isc_start_dma(isc); + } else + list_add_tail(&buf->list, &isc->dma_queue); + spin_unlock_irqrestore(&isc->dma_queue_lock, flags); +} + +static struct isc_format *find_format_by_fourcc(struct isc_device *isc, + unsigned int fourcc) +{ + unsigned int num_formats = isc->num_user_formats; + struct isc_format *fmt; + unsigned int i; + + for (i = 0; i < num_formats; i++) { + fmt = isc->user_formats[i]; + if (fmt->fourcc == fourcc) + return fmt; + } + + return NULL; +} + +static const struct vb2_ops isc_vb2_ops = { + .queue_setup = isc_queue_setup, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .buf_prepare = isc_buffer_prepare, + .start_streaming = isc_start_streaming, + .stop_streaming = isc_stop_streaming, + .buf_queue = isc_buffer_queue, +}; + +static int isc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct isc_device *isc = video_drvdata(file); + + strscpy(cap->driver, ATMEL_ISC_NAME, sizeof(cap->driver)); + strscpy(cap->card, "Atmel Image Sensor Controller", sizeof(cap->card)); + snprintf(cap->bus_info, sizeof(cap->bus_info), + "platform:%s", isc->v4l2_dev.name); + + return 0; +} + +static int isc_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + u32 index = f->index; + u32 i, supported_index; + + if (index < ARRAY_SIZE(controller_formats)) { + f->pixelformat = controller_formats[index].fourcc; + return 0; + } + + index -= ARRAY_SIZE(controller_formats); + + i = 0; + supported_index = 0; + + for (i = 0; i < ARRAY_SIZE(formats_list); i++) { + if (!ISC_IS_FORMAT_RAW(formats_list[i].mbus_code) || + !formats_list[i].sd_support) + continue; + if (supported_index == index) { + f->pixelformat = formats_list[i].fourcc; + return 0; + } + supported_index++; + } + + return -EINVAL; +} + +static int isc_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *fmt) +{ + struct isc_device *isc = video_drvdata(file); + + *fmt = isc->fmt; + + return 0; +} + +/* + * Checks the current configured format, if ISC can output it, + * considering which type of format the ISC receives from the sensor + */ +static int isc_try_validate_formats(struct isc_device *isc) +{ + int ret; + bool bayer = false, yuv = false, rgb = false, grey = false; + + /* all formats supported by the RLP module are OK */ + switch (isc->try_config.fourcc) { + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SRGGB8: + case V4L2_PIX_FMT_SBGGR10: + case V4L2_PIX_FMT_SGBRG10: + case V4L2_PIX_FMT_SGRBG10: + case V4L2_PIX_FMT_SRGGB10: + case V4L2_PIX_FMT_SBGGR12: + case V4L2_PIX_FMT_SGBRG12: + case V4L2_PIX_FMT_SGRBG12: + case V4L2_PIX_FMT_SRGGB12: + ret = 0; + bayer = true; + break; + + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YUV422P: + case V4L2_PIX_FMT_YUYV: + ret = 0; + yuv = true; + break; + + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_ABGR32: + case V4L2_PIX_FMT_XBGR32: + case V4L2_PIX_FMT_ARGB444: + case V4L2_PIX_FMT_ARGB555: + ret = 0; + rgb = true; + break; + case V4L2_PIX_FMT_GREY: + ret = 0; + grey = true; + break; + default: + /* any other different formats are not supported */ + ret = -EINVAL; + } + + /* we cannot output RAW/Grey if we do not receive RAW */ + if ((bayer || grey) && + !ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) + return -EINVAL; + + v4l2_dbg(1, debug, &isc->v4l2_dev, + "Format validation, requested rgb=%u, yuv=%u, grey=%u, bayer=%u\n", + rgb, yuv, grey, bayer); + + return ret; +} + +/* + * Configures the RLP and DMA modules, depending on the output format + * configured for the ISC. + * If direct_dump == true, just dump raw data 8 bits. + */ +static int isc_try_configure_rlp_dma(struct isc_device *isc, bool direct_dump) +{ + if (direct_dump) { + isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8; + isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED8; + isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; + isc->try_config.bpp = 16; + return 0; + } + + switch (isc->try_config.fourcc) { + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SRGGB8: + isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8; + isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED8; + isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; + isc->try_config.bpp = 8; + break; + case V4L2_PIX_FMT_SBGGR10: + case V4L2_PIX_FMT_SGBRG10: + case V4L2_PIX_FMT_SGRBG10: + case V4L2_PIX_FMT_SRGGB10: + isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT10; + isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16; + isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; + isc->try_config.bpp = 16; + break; + case V4L2_PIX_FMT_SBGGR12: + case V4L2_PIX_FMT_SGBRG12: + case V4L2_PIX_FMT_SGRBG12: + case V4L2_PIX_FMT_SRGGB12: + isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT12; + isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16; + isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; + isc->try_config.bpp = 16; + break; + case V4L2_PIX_FMT_RGB565: + isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_RGB565; + isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16; + isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; + isc->try_config.bpp = 16; + break; + case V4L2_PIX_FMT_ARGB444: + isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB444; + isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16; + isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; + isc->try_config.bpp = 16; + break; + case V4L2_PIX_FMT_ARGB555: + isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB555; + isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16; + isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; + isc->try_config.bpp = 16; + break; + case V4L2_PIX_FMT_ABGR32: + case V4L2_PIX_FMT_XBGR32: + isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB32; + isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED32; + isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; + isc->try_config.bpp = 32; + break; + case V4L2_PIX_FMT_YUV420: + isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YYCC; + isc->try_config.dcfg_imode = ISC_DCFG_IMODE_YC420P; + isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PLANAR; + isc->try_config.bpp = 12; + break; + case V4L2_PIX_FMT_YUV422P: + isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YYCC; + isc->try_config.dcfg_imode = ISC_DCFG_IMODE_YC422P; + isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PLANAR; + isc->try_config.bpp = 16; + break; + case V4L2_PIX_FMT_YUYV: + isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YYCC; + isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED32; + isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; + isc->try_config.bpp = 16; + break; + case V4L2_PIX_FMT_GREY: + isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DATY8; + isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED8; + isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; + isc->try_config.bpp = 8; + break; + default: + return -EINVAL; + } + return 0; +} + +/* + * Configuring pipeline modules, depending on which format the ISC outputs + * and considering which format it has as input from the sensor. + */ +static int isc_try_configure_pipeline(struct isc_device *isc) +{ + switch (isc->try_config.fourcc) { + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_ARGB555: + case V4L2_PIX_FMT_ARGB444: + case V4L2_PIX_FMT_ABGR32: + case V4L2_PIX_FMT_XBGR32: + /* if sensor format is RAW, we convert inside ISC */ + if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) { + isc->try_config.bits_pipeline = CFA_ENABLE | + WB_ENABLE | GAM_ENABLES; + } else { + isc->try_config.bits_pipeline = 0x0; + } + break; + case V4L2_PIX_FMT_YUV420: + /* if sensor format is RAW, we convert inside ISC */ + if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) { + isc->try_config.bits_pipeline = CFA_ENABLE | + CSC_ENABLE | WB_ENABLE | GAM_ENABLES | + SUB420_ENABLE | SUB422_ENABLE | CBC_ENABLE; + } else { + isc->try_config.bits_pipeline = 0x0; + } + break; + case V4L2_PIX_FMT_YUV422P: + /* if sensor format is RAW, we convert inside ISC */ + if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) { + isc->try_config.bits_pipeline = CFA_ENABLE | + CSC_ENABLE | WB_ENABLE | GAM_ENABLES | + SUB422_ENABLE | CBC_ENABLE; + } else { + isc->try_config.bits_pipeline = 0x0; + } + break; + case V4L2_PIX_FMT_YUYV: + /* if sensor format is RAW, we convert inside ISC */ + if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) { + isc->try_config.bits_pipeline = CFA_ENABLE | + CSC_ENABLE | WB_ENABLE | GAM_ENABLES | + SUB422_ENABLE | CBC_ENABLE; + } else { + isc->try_config.bits_pipeline = 0x0; + } + break; + case V4L2_PIX_FMT_GREY: + if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) { + /* if sensor format is RAW, we convert inside ISC */ + isc->try_config.bits_pipeline = CFA_ENABLE | + CSC_ENABLE | WB_ENABLE | GAM_ENABLES | + CBC_ENABLE; + } else { + isc->try_config.bits_pipeline = 0x0; + } + break; + default: + isc->try_config.bits_pipeline = 0x0; + } + return 0; +} + +static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f, + u32 *code) +{ + int i; + struct isc_format *sd_fmt = NULL, *direct_fmt = NULL; + struct v4l2_pix_format *pixfmt = &f->fmt.pix; + struct v4l2_subdev_pad_config pad_cfg; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_TRY, + }; + u32 mbus_code; + int ret; + bool rlp_dma_direct_dump = false; + + if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + /* Step 1: find a RAW format that is supported */ + for (i = 0; i < isc->num_user_formats; i++) { + if (ISC_IS_FORMAT_RAW(isc->user_formats[i]->mbus_code)) { + sd_fmt = isc->user_formats[i]; + break; + } + } + /* Step 2: We can continue with this RAW format, or we can look + * for better: maybe sensor supports directly what we need. + */ + direct_fmt = find_format_by_fourcc(isc, pixfmt->pixelformat); + + /* Step 3: We have both. We decide given the module parameter which + * one to use. + */ + if (direct_fmt && sd_fmt && sensor_preferred) + sd_fmt = direct_fmt; + + /* Step 4: we do not have RAW but we have a direct format. Use it. */ + if (direct_fmt && !sd_fmt) + sd_fmt = direct_fmt; + + /* Step 5: if we are using a direct format, we need to package + * everything as 8 bit data and just dump it + */ + if (sd_fmt == direct_fmt) + rlp_dma_direct_dump = true; + + /* Step 6: We have no format. This can happen if the userspace + * requests some weird/invalid format. + * In this case, default to whatever we have + */ + if (!sd_fmt && !direct_fmt) { + sd_fmt = isc->user_formats[isc->num_user_formats - 1]; + v4l2_dbg(1, debug, &isc->v4l2_dev, + "Sensor not supporting %.4s, using %.4s\n", + (char *)&pixfmt->pixelformat, (char *)&sd_fmt->fourcc); + } + + if (!sd_fmt) { + ret = -EINVAL; + goto isc_try_fmt_err; + } + + /* Step 7: Print out what we decided for debugging */ + v4l2_dbg(1, debug, &isc->v4l2_dev, + "Preferring to have sensor using format %.4s\n", + (char *)&sd_fmt->fourcc); + + /* Step 8: at this moment we decided which format the subdev will use */ + isc->try_config.sd_format = sd_fmt; + + /* Limit to Atmel ISC hardware capabilities */ + if (pixfmt->width > ISC_MAX_SUPPORT_WIDTH) + pixfmt->width = ISC_MAX_SUPPORT_WIDTH; + if (pixfmt->height > ISC_MAX_SUPPORT_HEIGHT) + pixfmt->height = ISC_MAX_SUPPORT_HEIGHT; + + /* + * The mbus format is the one the subdev outputs. + * The pixels will be transferred in this format Sensor -> ISC + */ + mbus_code = sd_fmt->mbus_code; + + /* + * Validate formats. If the required format is not OK, default to raw. + */ + + isc->try_config.fourcc = pixfmt->pixelformat; + + if (isc_try_validate_formats(isc)) { + pixfmt->pixelformat = isc->try_config.fourcc = sd_fmt->fourcc; + /* Re-try to validate the new format */ + ret = isc_try_validate_formats(isc); + if (ret) + goto isc_try_fmt_err; + } + + ret = isc_try_configure_rlp_dma(isc, rlp_dma_direct_dump); + if (ret) + goto isc_try_fmt_err; + + ret = isc_try_configure_pipeline(isc); + if (ret) + goto isc_try_fmt_err; + + v4l2_fill_mbus_format(&format.format, pixfmt, mbus_code); + ret = v4l2_subdev_call(isc->current_subdev->sd, pad, set_fmt, + &pad_cfg, &format); + if (ret < 0) + goto isc_try_fmt_subdev_err; + + v4l2_fill_pix_format(pixfmt, &format.format); + + pixfmt->field = V4L2_FIELD_NONE; + pixfmt->bytesperline = (pixfmt->width * isc->try_config.bpp) >> 3; + pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height; + + if (code) + *code = mbus_code; + + return 0; + +isc_try_fmt_err: + v4l2_err(&isc->v4l2_dev, "Could not find any possible format for a working pipeline\n"); +isc_try_fmt_subdev_err: + memset(&isc->try_config, 0, sizeof(isc->try_config)); + + return ret; +} + +static int isc_set_fmt(struct isc_device *isc, struct v4l2_format *f) +{ + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + u32 mbus_code = 0; + int ret; + + ret = isc_try_fmt(isc, f, &mbus_code); + if (ret) + return ret; + + v4l2_fill_mbus_format(&format.format, &f->fmt.pix, mbus_code); + ret = v4l2_subdev_call(isc->current_subdev->sd, pad, + set_fmt, NULL, &format); + if (ret < 0) + return ret; + + isc->fmt = *f; + + if (isc->try_config.sd_format && isc->config.sd_format && + isc->try_config.sd_format != isc->config.sd_format) { + isc->ctrls.hist_stat = HIST_INIT; + isc_reset_awb_ctrls(isc); + } + /* make the try configuration active */ + isc->config = isc->try_config; + + v4l2_dbg(1, debug, &isc->v4l2_dev, "New ISC configuration in place\n"); + + return 0; +} + +static int isc_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct isc_device *isc = video_drvdata(file); + + if (vb2_is_streaming(&isc->vb2_vidq)) + return -EBUSY; + + return isc_set_fmt(isc, f); +} + +static int isc_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct isc_device *isc = video_drvdata(file); + + return isc_try_fmt(isc, f, NULL); +} + +static int isc_enum_input(struct file *file, void *priv, + struct v4l2_input *inp) +{ + if (inp->index != 0) + return -EINVAL; + + inp->type = V4L2_INPUT_TYPE_CAMERA; + inp->std = 0; + strscpy(inp->name, "Camera", sizeof(inp->name)); + + return 0; +} + +static int isc_g_input(struct file *file, void *priv, unsigned int *i) +{ + *i = 0; + + return 0; +} + +static int isc_s_input(struct file *file, void *priv, unsigned int i) +{ + if (i > 0) + return -EINVAL; + + return 0; +} + +static int isc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) +{ + struct isc_device *isc = video_drvdata(file); + + return v4l2_g_parm_cap(video_devdata(file), isc->current_subdev->sd, a); +} + +static int isc_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) +{ + struct isc_device *isc = video_drvdata(file); + + return v4l2_s_parm_cap(video_devdata(file), isc->current_subdev->sd, a); +} + +static int isc_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize) +{ + struct isc_device *isc = video_drvdata(file); + struct v4l2_subdev_frame_size_enum fse = { + .index = fsize->index, + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + int ret = -EINVAL; + int i; + + for (i = 0; i < isc->num_user_formats; i++) + if (isc->user_formats[i]->fourcc == fsize->pixel_format) + ret = 0; + + for (i = 0; i < ARRAY_SIZE(controller_formats); i++) + if (controller_formats[i].fourcc == fsize->pixel_format) + ret = 0; + + if (ret) + return ret; + + ret = v4l2_subdev_call(isc->current_subdev->sd, pad, enum_frame_size, + NULL, &fse); + if (ret) + return ret; + + fse.code = isc->config.sd_format->mbus_code; + + fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; + fsize->discrete.width = fse.max_width; + fsize->discrete.height = fse.max_height; + + return 0; +} + +static int isc_enum_frameintervals(struct file *file, void *fh, + struct v4l2_frmivalenum *fival) +{ + struct isc_device *isc = video_drvdata(file); + struct v4l2_subdev_frame_interval_enum fie = { + .index = fival->index, + .width = fival->width, + .height = fival->height, + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + int ret = -EINVAL; + int i; + + for (i = 0; i < isc->num_user_formats; i++) + if (isc->user_formats[i]->fourcc == fival->pixel_format) + ret = 0; + + for (i = 0; i < ARRAY_SIZE(controller_formats); i++) + if (controller_formats[i].fourcc == fival->pixel_format) + ret = 0; + + if (ret) + return ret; + + ret = v4l2_subdev_call(isc->current_subdev->sd, pad, + enum_frame_interval, NULL, &fie); + if (ret) + return ret; + + fie.code = isc->config.sd_format->mbus_code; + fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; + fival->discrete = fie.interval; + + return 0; +} + +static const struct v4l2_ioctl_ops isc_ioctl_ops = { + .vidioc_querycap = isc_querycap, + .vidioc_enum_fmt_vid_cap = isc_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = isc_g_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = isc_s_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = isc_try_fmt_vid_cap, + + .vidioc_enum_input = isc_enum_input, + .vidioc_g_input = isc_g_input, + .vidioc_s_input = isc_s_input, + + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + + .vidioc_g_parm = isc_g_parm, + .vidioc_s_parm = isc_s_parm, + .vidioc_enum_framesizes = isc_enum_framesizes, + .vidioc_enum_frameintervals = isc_enum_frameintervals, + + .vidioc_log_status = v4l2_ctrl_log_status, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +static int isc_open(struct file *file) +{ + struct isc_device *isc = video_drvdata(file); + struct v4l2_subdev *sd = isc->current_subdev->sd; + int ret; + + if (mutex_lock_interruptible(&isc->lock)) + return -ERESTARTSYS; + + ret = v4l2_fh_open(file); + if (ret < 0) + goto unlock; + + if (!v4l2_fh_is_singular_file(file)) + goto unlock; + + ret = v4l2_subdev_call(sd, core, s_power, 1); + if (ret < 0 && ret != -ENOIOCTLCMD) { + v4l2_fh_release(file); + goto unlock; + } + + ret = isc_set_fmt(isc, &isc->fmt); + if (ret) { + v4l2_subdev_call(sd, core, s_power, 0); + v4l2_fh_release(file); + } + +unlock: + mutex_unlock(&isc->lock); + return ret; +} + +static int isc_release(struct file *file) +{ + struct isc_device *isc = video_drvdata(file); + struct v4l2_subdev *sd = isc->current_subdev->sd; + bool fh_singular; + int ret; + + mutex_lock(&isc->lock); + + fh_singular = v4l2_fh_is_singular_file(file); + + ret = _vb2_fop_release(file, NULL); + + if (fh_singular) + v4l2_subdev_call(sd, core, s_power, 0); + + mutex_unlock(&isc->lock); + + return ret; +} + +static const struct v4l2_file_operations isc_fops = { + .owner = THIS_MODULE, + .open = isc_open, + .release = isc_release, + .unlocked_ioctl = video_ioctl2, + .read = vb2_fop_read, + .mmap = vb2_fop_mmap, + .poll = vb2_fop_poll, +}; + +irqreturn_t isc_interrupt(int irq, void *dev_id) +{ + struct isc_device *isc = (struct isc_device *)dev_id; + struct regmap *regmap = isc->regmap; + u32 isc_intsr, isc_intmask, pending; + irqreturn_t ret = IRQ_NONE; + + regmap_read(regmap, ISC_INTSR, &isc_intsr); + regmap_read(regmap, ISC_INTMASK, &isc_intmask); + + pending = isc_intsr & isc_intmask; + + if (likely(pending & ISC_INT_DDONE)) { + spin_lock(&isc->dma_queue_lock); + if (isc->cur_frm) { + struct vb2_v4l2_buffer *vbuf = &isc->cur_frm->vb; + struct vb2_buffer *vb = &vbuf->vb2_buf; + + vb->timestamp = ktime_get_ns(); + vbuf->sequence = isc->sequence++; + vb2_buffer_done(vb, VB2_BUF_STATE_DONE); + isc->cur_frm = NULL; + } + + if (!list_empty(&isc->dma_queue) && !isc->stop) { + isc->cur_frm = list_first_entry(&isc->dma_queue, + struct isc_buffer, list); + list_del(&isc->cur_frm->list); + + isc_start_dma(isc); + } + + if (isc->stop) + complete(&isc->comp); + + ret = IRQ_HANDLED; + spin_unlock(&isc->dma_queue_lock); + } + + if (pending & ISC_INT_HISDONE) { + schedule_work(&isc->awb_work); + ret = IRQ_HANDLED; + } + + return ret; +} + +static void isc_hist_count(struct isc_device *isc, u32 *min, u32 *max) +{ + struct regmap *regmap = isc->regmap; + struct isc_ctrls *ctrls = &isc->ctrls; + u32 *hist_count = &ctrls->hist_count[ctrls->hist_id]; + u32 *hist_entry = &ctrls->hist_entry[0]; + u32 i; + + *min = 0; + *max = HIST_ENTRIES; + + regmap_bulk_read(regmap, ISC_HIS_ENTRY, hist_entry, HIST_ENTRIES); + + *hist_count = 0; + /* + * we deliberately ignore the end of the histogram, + * the most white pixels + */ + for (i = 1; i < HIST_ENTRIES; i++) { + if (*hist_entry && !*min) + *min = i; + if (*hist_entry) + *max = i; + *hist_count += i * (*hist_entry++); + } + + if (!*min) + *min = 1; +} + +static void isc_wb_update(struct isc_ctrls *ctrls) +{ + u32 *hist_count = &ctrls->hist_count[0]; + u32 c, offset[4]; + u64 avg = 0; + /* We compute two gains, stretch gain and grey world gain */ + u32 s_gain[4], gw_gain[4]; + + /* + * According to Grey World, we need to set gains for R/B to normalize + * them towards the green channel. + * Thus we want to keep Green as fixed and adjust only Red/Blue + * Compute the average of the both green channels first + */ + avg = (u64)hist_count[ISC_HIS_CFG_MODE_GR] + + (u64)hist_count[ISC_HIS_CFG_MODE_GB]; + avg >>= 1; + + /* Green histogram is null, nothing to do */ + if (!avg) + return; + + for (c = ISC_HIS_CFG_MODE_GR; c <= ISC_HIS_CFG_MODE_B; c++) { + /* + * the color offset is the minimum value of the histogram. + * we stretch this color to the full range by substracting + * this value from the color component. + */ + offset[c] = ctrls->hist_minmax[c][HIST_MIN_INDEX]; + /* + * The offset is always at least 1. If the offset is 1, we do + * not need to adjust it, so our result must be zero. + * the offset is computed in a histogram on 9 bits (0..512) + * but the offset in register is based on + * 12 bits pipeline (0..4096). + * we need to shift with the 3 bits that the histogram is + * ignoring + */ + ctrls->offset[c] = (offset[c] - 1) << 3; + + /* the offset is then taken and converted to 2's complements */ + if (!ctrls->offset[c]) + ctrls->offset[c] = ISC_WB_O_ZERO_VAL; + + /* + * the stretch gain is the total number of histogram bins + * divided by the actual range of color component (Max - Min) + * If we compute gain like this, the actual color component + * will be stretched to the full histogram. + * We need to shift 9 bits for precision, we have 9 bits for + * decimals + */ + s_gain[c] = (HIST_ENTRIES << 9) / + (ctrls->hist_minmax[c][HIST_MAX_INDEX] - + ctrls->hist_minmax[c][HIST_MIN_INDEX] + 1); + + /* + * Now we have to compute the gain w.r.t. the average. + * Add/lose gain to the component towards the average. + * If it happens that the component is zero, use the + * fixed point value : 1.0 gain. + */ + if (hist_count[c]) + gw_gain[c] = div_u64(avg << 9, hist_count[c]); + else + gw_gain[c] = 1 << 9; + + /* multiply both gains and adjust for decimals */ + ctrls->gain[c] = s_gain[c] * gw_gain[c]; + ctrls->gain[c] >>= 9; + } +} + +static void isc_awb_work(struct work_struct *w) +{ + struct isc_device *isc = + container_of(w, struct isc_device, awb_work); + struct regmap *regmap = isc->regmap; + struct isc_ctrls *ctrls = &isc->ctrls; + u32 hist_id = ctrls->hist_id; + u32 baysel; + unsigned long flags; + u32 min, max; + + /* streaming is not active anymore */ + if (isc->stop) + return; + + if (ctrls->hist_stat != HIST_ENABLED) + return; + + isc_hist_count(isc, &min, &max); + ctrls->hist_minmax[hist_id][HIST_MIN_INDEX] = min; + ctrls->hist_minmax[hist_id][HIST_MAX_INDEX] = max; + + if (hist_id != ISC_HIS_CFG_MODE_B) { + hist_id++; + } else { + isc_wb_update(ctrls); + hist_id = ISC_HIS_CFG_MODE_GR; + } + + ctrls->hist_id = hist_id; + baysel = isc->config.sd_format->cfa_baycfg << ISC_HIS_CFG_BAYSEL_SHIFT; + + /* if no more auto white balance, reset controls. */ + if (ctrls->awb == ISC_WB_NONE) + isc_reset_awb_ctrls(isc); + + pm_runtime_get_sync(isc->dev); + + /* + * only update if we have all the required histograms and controls + * if awb has been disabled, we need to reset registers as well. + */ + if (hist_id == ISC_HIS_CFG_MODE_GR || ctrls->awb == ISC_WB_NONE) { + /* + * It may happen that DMA Done IRQ will trigger while we are + * updating white balance registers here. + * In that case, only parts of the controls have been updated. + * We can avoid that by locking the section. + */ + spin_lock_irqsave(&isc->awb_lock, flags); + isc_update_awb_ctrls(isc); + spin_unlock_irqrestore(&isc->awb_lock, flags); + + /* + * if we are doing just the one time white balance adjustment, + * we are basically done. + */ + if (ctrls->awb == ISC_WB_ONETIME) { + v4l2_info(&isc->v4l2_dev, + "Completed one time white-balance adjustment.\n"); + ctrls->awb = ISC_WB_NONE; + } + } + regmap_write(regmap, ISC_HIS_CFG, hist_id | baysel | ISC_HIS_CFG_RAR); + isc_update_profile(isc); + /* if awb has been disabled, we don't need to start another histogram */ + if (ctrls->awb) + regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_HISREQ); + + pm_runtime_put_sync(isc->dev); +} + +static int isc_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct isc_device *isc = container_of(ctrl->handler, + struct isc_device, ctrls.handler); + struct isc_ctrls *ctrls = &isc->ctrls; + + if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE) + return 0; + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + ctrls->brightness = ctrl->val & ISC_CBC_BRIGHT_MASK; + break; + case V4L2_CID_CONTRAST: + ctrls->contrast = ctrl->val & ISC_CBC_CONTRAST_MASK; + break; + case V4L2_CID_GAMMA: + ctrls->gamma_index = ctrl->val; + break; + case V4L2_CID_AUTO_WHITE_BALANCE: + if (ctrl->val == 1) + ctrls->awb = ISC_WB_AUTO; + else + ctrls->awb = ISC_WB_NONE; + + /* we did not configure ISC yet */ + if (!isc->config.sd_format) + break; + + if (ctrls->hist_stat != HIST_ENABLED) + isc_reset_awb_ctrls(isc); + + if (isc->ctrls.awb == ISC_WB_AUTO && + vb2_is_streaming(&isc->vb2_vidq) && + ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code)) + isc_set_histogram(isc, true); + + break; + case V4L2_CID_DO_WHITE_BALANCE: + /* if AWB is enabled, do nothing */ + if (ctrls->awb == ISC_WB_AUTO) + return 0; + + ctrls->awb = ISC_WB_ONETIME; + isc_set_histogram(isc, true); + v4l2_dbg(1, debug, &isc->v4l2_dev, + "One time white-balance started.\n"); + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct v4l2_ctrl_ops isc_ctrl_ops = { + .s_ctrl = isc_s_ctrl, +}; + +static int isc_ctrl_init(struct isc_device *isc) +{ + const struct v4l2_ctrl_ops *ops = &isc_ctrl_ops; + struct isc_ctrls *ctrls = &isc->ctrls; + struct v4l2_ctrl_handler *hdl = &ctrls->handler; + int ret; + + ctrls->hist_stat = HIST_INIT; + isc_reset_awb_ctrls(isc); + + ret = v4l2_ctrl_handler_init(hdl, 5); + if (ret < 0) + return ret; + + ctrls->brightness = 0; + ctrls->contrast = 256; + + v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, -1024, 1023, 1, 0); + v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -2048, 2047, 1, 256); + v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAMMA, 0, GAMMA_MAX, 1, 2); + v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1); + + /* do_white_balance is a button, so min,max,step,default are ignored */ + isc->do_wb_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_DO_WHITE_BALANCE, + 0, 0, 0, 0); + + v4l2_ctrl_activate(isc->do_wb_ctrl, false); + + v4l2_ctrl_handler_setup(hdl); + + return 0; +} + +static int isc_async_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *subdev, + struct v4l2_async_subdev *asd) +{ + struct isc_device *isc = container_of(notifier->v4l2_dev, + struct isc_device, v4l2_dev); + struct isc_subdev_entity *subdev_entity = + container_of(notifier, struct isc_subdev_entity, notifier); + + if (video_is_registered(&isc->video_dev)) { + v4l2_err(&isc->v4l2_dev, "only supports one sub-device.\n"); + return -EBUSY; + } + + subdev_entity->sd = subdev; + + return 0; +} + +static void isc_async_unbind(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *subdev, + struct v4l2_async_subdev *asd) +{ + struct isc_device *isc = container_of(notifier->v4l2_dev, + struct isc_device, v4l2_dev); + cancel_work_sync(&isc->awb_work); + video_unregister_device(&isc->video_dev); + v4l2_ctrl_handler_free(&isc->ctrls.handler); +} + +static struct isc_format *find_format_by_code(unsigned int code, int *index) +{ + struct isc_format *fmt = &formats_list[0]; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(formats_list); i++) { + if (fmt->mbus_code == code) { + *index = i; + return fmt; + } + + fmt++; + } + + return NULL; +} + +static int isc_formats_init(struct isc_device *isc) +{ + struct isc_format *fmt; + struct v4l2_subdev *subdev = isc->current_subdev->sd; + unsigned int num_fmts, i, j; + u32 list_size = ARRAY_SIZE(formats_list); + struct v4l2_subdev_mbus_code_enum mbus_code = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + + num_fmts = 0; + while (!v4l2_subdev_call(subdev, pad, enum_mbus_code, + NULL, &mbus_code)) { + mbus_code.index++; + + fmt = find_format_by_code(mbus_code.code, &i); + if (!fmt) { + v4l2_warn(&isc->v4l2_dev, "Mbus code %x not supported\n", + mbus_code.code); + continue; + } + + fmt->sd_support = true; + num_fmts++; + } + + if (!num_fmts) + return -ENXIO; + + isc->num_user_formats = num_fmts; + isc->user_formats = devm_kcalloc(isc->dev, + num_fmts, sizeof(*isc->user_formats), + GFP_KERNEL); + if (!isc->user_formats) + return -ENOMEM; + + fmt = &formats_list[0]; + for (i = 0, j = 0; i < list_size; i++) { + if (fmt->sd_support) + isc->user_formats[j++] = fmt; + fmt++; + } + + return 0; +} + +static int isc_set_default_fmt(struct isc_device *isc) +{ + struct v4l2_format f = { + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + .fmt.pix = { + .width = VGA_WIDTH, + .height = VGA_HEIGHT, + .field = V4L2_FIELD_NONE, + .pixelformat = isc->user_formats[0]->fourcc, + }, + }; + int ret; + + ret = isc_try_fmt(isc, &f, NULL); + if (ret) + return ret; + + isc->fmt = f; + return 0; +} + +static int isc_async_complete(struct v4l2_async_notifier *notifier) +{ + struct isc_device *isc = container_of(notifier->v4l2_dev, + struct isc_device, v4l2_dev); + struct video_device *vdev = &isc->video_dev; + struct vb2_queue *q = &isc->vb2_vidq; + int ret; + + INIT_WORK(&isc->awb_work, isc_awb_work); + + ret = v4l2_device_register_subdev_nodes(&isc->v4l2_dev); + if (ret < 0) { + v4l2_err(&isc->v4l2_dev, "Failed to register subdev nodes\n"); + return ret; + } + + isc->current_subdev = container_of(notifier, + struct isc_subdev_entity, notifier); + mutex_init(&isc->lock); + init_completion(&isc->comp); + + /* Initialize videobuf2 queue */ + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ; + q->drv_priv = isc; + q->buf_struct_size = sizeof(struct isc_buffer); + q->ops = &isc_vb2_ops; + q->mem_ops = &vb2_dma_contig_memops; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->lock = &isc->lock; + q->min_buffers_needed = 1; + q->dev = isc->dev; + + ret = vb2_queue_init(q); + if (ret < 0) { + v4l2_err(&isc->v4l2_dev, + "vb2_queue_init() failed: %d\n", ret); + return ret; + } + + /* Init video dma queues */ + INIT_LIST_HEAD(&isc->dma_queue); + spin_lock_init(&isc->dma_queue_lock); + spin_lock_init(&isc->awb_lock); + + ret = isc_formats_init(isc); + if (ret < 0) { + v4l2_err(&isc->v4l2_dev, + "Init format failed: %d\n", ret); + return ret; + } + + ret = isc_set_default_fmt(isc); + if (ret) { + v4l2_err(&isc->v4l2_dev, "Could not set default format\n"); + return ret; + } + + ret = isc_ctrl_init(isc); + if (ret) { + v4l2_err(&isc->v4l2_dev, "Init isc ctrols failed: %d\n", ret); + return ret; + } + + /* Register video device */ + strscpy(vdev->name, ATMEL_ISC_NAME, sizeof(vdev->name)); + vdev->release = video_device_release_empty; + vdev->fops = &isc_fops; + vdev->ioctl_ops = &isc_ioctl_ops; + vdev->v4l2_dev = &isc->v4l2_dev; + vdev->vfl_dir = VFL_DIR_RX; + vdev->queue = q; + vdev->lock = &isc->lock; + vdev->ctrl_handler = &isc->ctrls.handler; + vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE; + video_set_drvdata(vdev, isc); + + ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); + if (ret < 0) { + v4l2_err(&isc->v4l2_dev, + "video_register_device failed: %d\n", ret); + return ret; + } + + return 0; +} + +const struct v4l2_async_notifier_operations isc_async_ops = { + .bound = isc_async_bound, + .unbind = isc_async_unbind, + .complete = isc_async_complete, +}; + +void isc_subdev_cleanup(struct isc_device *isc) +{ + struct isc_subdev_entity *subdev_entity; + + list_for_each_entry(subdev_entity, &isc->subdev_entities, list) { + v4l2_async_notifier_unregister(&subdev_entity->notifier); + v4l2_async_notifier_cleanup(&subdev_entity->notifier); + } + + INIT_LIST_HEAD(&isc->subdev_entities); +} + +int isc_pipeline_init(struct isc_device *isc) +{ + struct device *dev = isc->dev; + struct regmap *regmap = isc->regmap; + struct regmap_field *regs; + unsigned int i; + + /* WB-->CFA-->CC-->GAM-->CSC-->CBC-->SUB422-->SUB420 */ + const struct reg_field regfields[ISC_PIPE_LINE_NODE_NUM] = { + REG_FIELD(ISC_WB_CTRL, 0, 0), + REG_FIELD(ISC_CFA_CTRL, 0, 0), + REG_FIELD(ISC_CC_CTRL, 0, 0), + REG_FIELD(ISC_GAM_CTRL, 0, 0), + REG_FIELD(ISC_GAM_CTRL, 1, 1), + REG_FIELD(ISC_GAM_CTRL, 2, 2), + REG_FIELD(ISC_GAM_CTRL, 3, 3), + REG_FIELD(ISC_CSC_CTRL, 0, 0), + REG_FIELD(ISC_CBC_CTRL, 0, 0), + REG_FIELD(ISC_SUB422_CTRL, 0, 0), + REG_FIELD(ISC_SUB420_CTRL, 0, 0), + }; + + for (i = 0; i < ISC_PIPE_LINE_NODE_NUM; i++) { + regs = devm_regmap_field_alloc(dev, regmap, regfields[i]); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + isc->pipeline[i] = regs; + } + + return 0; +} + +/* regmap configuration */ +#define ATMEL_ISC_REG_MAX 0xbfc +const struct regmap_config isc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = ATMEL_ISC_REG_MAX, +}; + diff --git a/drivers/media/platform/atmel/atmel-isc.c b/drivers/media/platform/atmel/atmel-isc.c deleted file mode 100644 index 6f80980214ac..000000000000 --- a/drivers/media/platform/atmel/atmel-isc.c +++ /dev/null @@ -1,2631 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Atmel Image Sensor Controller (ISC) driver - * - * Copyright (C) 2016 Atmel - * - * Author: Songjun Wu - * - * Sensor-->PFE-->WB-->CFA-->CC-->GAM-->CSC-->CBC-->SUB-->RLP-->DMA - * - * ISC video pipeline integrates the following submodules: - * PFE: Parallel Front End to sample the camera sensor input stream - * WB: Programmable white balance in the Bayer domain - * CFA: Color filter array interpolation module - * CC: Programmable color correction - * GAM: Gamma correction - * CSC: Programmable color space conversion - * CBC: Contrast and Brightness control - * SUB: This module performs YCbCr444 to YCbCr420 chrominance subsampling - * RLP: This module performs rounding, range limiting - * and packing of the incoming data - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "atmel-isc-regs.h" - -#define ATMEL_ISC_NAME "atmel_isc" - -#define ISC_MAX_SUPPORT_WIDTH 2592 -#define ISC_MAX_SUPPORT_HEIGHT 1944 - -#define ISC_CLK_MAX_DIV 255 - -enum isc_clk_id { - ISC_ISPCK = 0, - ISC_MCK = 1, -}; - -struct isc_clk { - struct clk_hw hw; - struct clk *clk; - struct regmap *regmap; - spinlock_t lock; - u8 id; - u8 parent_id; - u32 div; - struct device *dev; -}; - -#define to_isc_clk(hw) container_of(hw, struct isc_clk, hw) - -struct isc_buffer { - struct vb2_v4l2_buffer vb; - struct list_head list; -}; - -struct isc_subdev_entity { - struct v4l2_subdev *sd; - struct v4l2_async_subdev *asd; - struct v4l2_async_notifier notifier; - - u32 pfe_cfg0; - - struct list_head list; -}; - -/* - * struct isc_format - ISC media bus format information - This structure represents the interface between the ISC - and the sensor. It's the input format received by - the ISC. - * @fourcc: Fourcc code for this format - * @mbus_code: V4L2 media bus format code. - * @cfa_baycfg: If this format is RAW BAYER, indicate the type of bayer. - this is either BGBG, RGRG, etc. - * @pfe_cfg0_bps: Number of hardware data lines connected to the ISC - */ - -struct isc_format { - u32 fourcc; - u32 mbus_code; - u32 cfa_baycfg; - - bool sd_support; - u32 pfe_cfg0_bps; -}; - -/* Pipeline bitmap */ -#define WB_ENABLE BIT(0) -#define CFA_ENABLE BIT(1) -#define CC_ENABLE BIT(2) -#define GAM_ENABLE BIT(3) -#define GAM_BENABLE BIT(4) -#define GAM_GENABLE BIT(5) -#define GAM_RENABLE BIT(6) -#define CSC_ENABLE BIT(7) -#define CBC_ENABLE BIT(8) -#define SUB422_ENABLE BIT(9) -#define SUB420_ENABLE BIT(10) - -#define GAM_ENABLES (GAM_RENABLE | GAM_GENABLE | GAM_BENABLE | GAM_ENABLE) - -/* - * struct fmt_config - ISC format configuration and internal pipeline - This structure represents the internal configuration - of the ISC. - It also holds the format that ISC will present to v4l2. - * @sd_format: Pointer to an isc_format struct that holds the sensor - configuration. - * @fourcc: Fourcc code for this format. - * @bpp: Bytes per pixel in the current format. - * @rlp_cfg_mode: Configuration of the RLP (rounding, limiting packaging) - * @dcfg_imode: Configuration of the input of the DMA module - * @dctrl_dview: Configuration of the output of the DMA module - * @bits_pipeline: Configuration of the pipeline, which modules are enabled - */ -struct fmt_config { - struct isc_format *sd_format; - - u32 fourcc; - u8 bpp; - - u32 rlp_cfg_mode; - u32 dcfg_imode; - u32 dctrl_dview; - - u32 bits_pipeline; -}; - -#define HIST_ENTRIES 512 -#define HIST_BAYER (ISC_HIS_CFG_MODE_B + 1) - -enum{ - HIST_INIT = 0, - HIST_ENABLED, - HIST_DISABLED, -}; - -struct isc_ctrls { - struct v4l2_ctrl_handler handler; - - u32 brightness; - u32 contrast; - u8 gamma_index; -#define ISC_WB_NONE 0 -#define ISC_WB_AUTO 1 -#define ISC_WB_ONETIME 2 - u8 awb; - - /* one for each component : GR, R, GB, B */ - u32 gain[HIST_BAYER]; - u32 offset[HIST_BAYER]; - - u32 hist_entry[HIST_ENTRIES]; - u32 hist_count[HIST_BAYER]; - u8 hist_id; - u8 hist_stat; -#define HIST_MIN_INDEX 0 -#define HIST_MAX_INDEX 1 - u32 hist_minmax[HIST_BAYER][2]; -}; - -#define ISC_PIPE_LINE_NODE_NUM 11 - -struct isc_device { - struct regmap *regmap; - struct clk *hclock; - struct clk *ispck; - struct isc_clk isc_clks[2]; - - struct device *dev; - struct v4l2_device v4l2_dev; - struct video_device video_dev; - - struct vb2_queue vb2_vidq; - spinlock_t dma_queue_lock; - struct list_head dma_queue; - struct isc_buffer *cur_frm; - unsigned int sequence; - bool stop; - struct completion comp; - - struct v4l2_format fmt; - struct isc_format **user_formats; - unsigned int num_user_formats; - - struct fmt_config config; - struct fmt_config try_config; - - struct isc_ctrls ctrls; - struct v4l2_ctrl *do_wb_ctrl; - struct work_struct awb_work; - - struct mutex lock; - spinlock_t awb_lock; - - struct regmap_field *pipeline[ISC_PIPE_LINE_NODE_NUM]; - - struct isc_subdev_entity *current_subdev; - struct list_head subdev_entities; -}; - -/* This is a list of the formats that the ISC can *output* */ -static struct isc_format controller_formats[] = { - { - .fourcc = V4L2_PIX_FMT_ARGB444, - }, - { - .fourcc = V4L2_PIX_FMT_ARGB555, - }, - { - .fourcc = V4L2_PIX_FMT_RGB565, - }, - { - .fourcc = V4L2_PIX_FMT_ABGR32, - }, - { - .fourcc = V4L2_PIX_FMT_XBGR32, - }, - { - .fourcc = V4L2_PIX_FMT_YUV420, - }, - { - .fourcc = V4L2_PIX_FMT_YUYV, - }, - { - .fourcc = V4L2_PIX_FMT_YUV422P, - }, - { - .fourcc = V4L2_PIX_FMT_GREY, - }, -}; - -/* This is a list of formats that the ISC can receive as *input* */ -static struct isc_format formats_list[] = { - { - .fourcc = V4L2_PIX_FMT_SBGGR8, - .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, - .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, - .cfa_baycfg = ISC_BAY_CFG_BGBG, - }, - { - .fourcc = V4L2_PIX_FMT_SGBRG8, - .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8, - .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, - .cfa_baycfg = ISC_BAY_CFG_GBGB, - }, - { - .fourcc = V4L2_PIX_FMT_SGRBG8, - .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, - .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, - .cfa_baycfg = ISC_BAY_CFG_GRGR, - }, - { - .fourcc = V4L2_PIX_FMT_SRGGB8, - .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8, - .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, - .cfa_baycfg = ISC_BAY_CFG_RGRG, - }, - { - .fourcc = V4L2_PIX_FMT_SBGGR10, - .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, - .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN, - .cfa_baycfg = ISC_BAY_CFG_RGRG, - }, - { - .fourcc = V4L2_PIX_FMT_SGBRG10, - .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10, - .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN, - .cfa_baycfg = ISC_BAY_CFG_GBGB, - }, - { - .fourcc = V4L2_PIX_FMT_SGRBG10, - .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, - .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN, - .cfa_baycfg = ISC_BAY_CFG_GRGR, - }, - { - .fourcc = V4L2_PIX_FMT_SRGGB10, - .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10, - .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN, - .cfa_baycfg = ISC_BAY_CFG_RGRG, - }, - { - .fourcc = V4L2_PIX_FMT_SBGGR12, - .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12, - .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE, - .cfa_baycfg = ISC_BAY_CFG_BGBG, - }, - { - .fourcc = V4L2_PIX_FMT_SGBRG12, - .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12, - .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE, - .cfa_baycfg = ISC_BAY_CFG_GBGB, - }, - { - .fourcc = V4L2_PIX_FMT_SGRBG12, - .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12, - .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE, - .cfa_baycfg = ISC_BAY_CFG_GRGR, - }, - { - .fourcc = V4L2_PIX_FMT_SRGGB12, - .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12, - .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE, - .cfa_baycfg = ISC_BAY_CFG_RGRG, - }, - { - .fourcc = V4L2_PIX_FMT_GREY, - .mbus_code = MEDIA_BUS_FMT_Y8_1X8, - .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, - }, - { - .fourcc = V4L2_PIX_FMT_YUYV, - .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, - .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, - }, - { - .fourcc = V4L2_PIX_FMT_RGB565, - .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE, - .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, - }, -}; - -#define GAMMA_MAX 2 -#define GAMMA_ENTRIES 64 - -/* Gamma table with gamma 1/2.2 */ -static const u32 isc_gamma_table[GAMMA_MAX + 1][GAMMA_ENTRIES] = { - /* 0 --> gamma 1/1.8 */ - { 0x65, 0x66002F, 0x950025, 0xBB0020, 0xDB001D, 0xF8001A, - 0x1130018, 0x12B0017, 0x1420016, 0x1580014, 0x16D0013, 0x1810012, - 0x1940012, 0x1A60012, 0x1B80011, 0x1C90010, 0x1DA0010, 0x1EA000F, - 0x1FA000F, 0x209000F, 0x218000F, 0x227000E, 0x235000E, 0x243000E, - 0x251000E, 0x25F000D, 0x26C000D, 0x279000D, 0x286000D, 0x293000C, - 0x2A0000C, 0x2AC000C, 0x2B8000C, 0x2C4000C, 0x2D0000B, 0x2DC000B, - 0x2E7000B, 0x2F3000B, 0x2FE000B, 0x309000B, 0x314000B, 0x31F000A, - 0x32A000A, 0x334000B, 0x33F000A, 0x349000A, 0x354000A, 0x35E000A, - 0x368000A, 0x372000A, 0x37C000A, 0x386000A, 0x3900009, 0x399000A, - 0x3A30009, 0x3AD0009, 0x3B60009, 0x3BF000A, 0x3C90009, 0x3D20009, - 0x3DB0009, 0x3E40009, 0x3ED0009, 0x3F60009 }, - - /* 1 --> gamma 1/2 */ - { 0x7F, 0x800034, 0xB50028, 0xDE0021, 0x100001E, 0x11E001B, - 0x1390019, 0x1520017, 0x16A0015, 0x1800014, 0x1940014, 0x1A80013, - 0x1BB0012, 0x1CD0011, 0x1DF0010, 0x1EF0010, 0x200000F, 0x20F000F, - 0x21F000E, 0x22D000F, 0x23C000E, 0x24A000E, 0x258000D, 0x265000D, - 0x273000C, 0x27F000D, 0x28C000C, 0x299000C, 0x2A5000C, 0x2B1000B, - 0x2BC000C, 0x2C8000B, 0x2D3000C, 0x2DF000B, 0x2EA000A, 0x2F5000A, - 0x2FF000B, 0x30A000A, 0x314000B, 0x31F000A, 0x329000A, 0x333000A, - 0x33D0009, 0x3470009, 0x350000A, 0x35A0009, 0x363000A, 0x36D0009, - 0x3760009, 0x37F0009, 0x3880009, 0x3910009, 0x39A0009, 0x3A30009, - 0x3AC0008, 0x3B40009, 0x3BD0008, 0x3C60008, 0x3CE0008, 0x3D60009, - 0x3DF0008, 0x3E70008, 0x3EF0008, 0x3F70008 }, - - /* 2 --> gamma 1/2.2 */ - { 0x99, 0x9B0038, 0xD4002A, 0xFF0023, 0x122001F, 0x141001B, - 0x15D0019, 0x1760017, 0x18E0015, 0x1A30015, 0x1B80013, 0x1CC0012, - 0x1DE0011, 0x1F00010, 0x2010010, 0x2110010, 0x221000F, 0x230000F, - 0x23F000E, 0x24D000E, 0x25B000D, 0x269000C, 0x276000C, 0x283000C, - 0x28F000C, 0x29B000C, 0x2A7000C, 0x2B3000B, 0x2BF000B, 0x2CA000B, - 0x2D5000B, 0x2E0000A, 0x2EB000A, 0x2F5000A, 0x2FF000A, 0x30A000A, - 0x3140009, 0x31E0009, 0x327000A, 0x3310009, 0x33A0009, 0x3440009, - 0x34D0009, 0x3560009, 0x35F0009, 0x3680008, 0x3710008, 0x3790009, - 0x3820008, 0x38A0008, 0x3930008, 0x39B0008, 0x3A30008, 0x3AB0008, - 0x3B30008, 0x3BB0008, 0x3C30008, 0x3CB0007, 0x3D20008, 0x3DA0007, - 0x3E20007, 0x3E90007, 0x3F00008, 0x3F80007 }, -}; - -#define ISC_IS_FORMAT_RAW(mbus_code) \ - (((mbus_code) & 0xf000) == 0x3000) - -static unsigned int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "debug level (0-2)"); - -static unsigned int sensor_preferred = 1; -module_param(sensor_preferred, uint, 0644); -MODULE_PARM_DESC(sensor_preferred, - "Sensor is preferred to output the specified format (1-on 0-off), default 1"); - -static inline void isc_update_awb_ctrls(struct isc_device *isc) -{ - struct isc_ctrls *ctrls = &isc->ctrls; - - regmap_write(isc->regmap, ISC_WB_O_RGR, - (ISC_WB_O_ZERO_VAL - (ctrls->offset[ISC_HIS_CFG_MODE_R])) | - ((ISC_WB_O_ZERO_VAL - ctrls->offset[ISC_HIS_CFG_MODE_GR]) << 16)); - regmap_write(isc->regmap, ISC_WB_O_BGB, - (ISC_WB_O_ZERO_VAL - (ctrls->offset[ISC_HIS_CFG_MODE_B])) | - ((ISC_WB_O_ZERO_VAL - ctrls->offset[ISC_HIS_CFG_MODE_GB]) << 16)); - regmap_write(isc->regmap, ISC_WB_G_RGR, - ctrls->gain[ISC_HIS_CFG_MODE_R] | - (ctrls->gain[ISC_HIS_CFG_MODE_GR] << 16)); - regmap_write(isc->regmap, ISC_WB_G_BGB, - ctrls->gain[ISC_HIS_CFG_MODE_B] | - (ctrls->gain[ISC_HIS_CFG_MODE_GB] << 16)); -} - -static inline void isc_reset_awb_ctrls(struct isc_device *isc) -{ - int c; - - for (c = ISC_HIS_CFG_MODE_GR; c <= ISC_HIS_CFG_MODE_B; c++) { - /* gains have a fixed point at 9 decimals */ - isc->ctrls.gain[c] = 1 << 9; - /* offsets are in 2's complements, the value - * will be substracted from ISC_WB_O_ZERO_VAL to obtain - * 2's complement of a value between 0 and - * ISC_WB_O_ZERO_VAL >> 1 - */ - isc->ctrls.offset[c] = ISC_WB_O_ZERO_VAL; - } -} - -static int isc_wait_clk_stable(struct clk_hw *hw) -{ - struct isc_clk *isc_clk = to_isc_clk(hw); - struct regmap *regmap = isc_clk->regmap; - unsigned long timeout = jiffies + usecs_to_jiffies(1000); - unsigned int status; - - while (time_before(jiffies, timeout)) { - regmap_read(regmap, ISC_CLKSR, &status); - if (!(status & ISC_CLKSR_SIP)) - return 0; - - usleep_range(10, 250); - } - - return -ETIMEDOUT; -} - -static int isc_clk_prepare(struct clk_hw *hw) -{ - struct isc_clk *isc_clk = to_isc_clk(hw); - - if (isc_clk->id == ISC_ISPCK) - pm_runtime_get_sync(isc_clk->dev); - - return isc_wait_clk_stable(hw); -} - -static void isc_clk_unprepare(struct clk_hw *hw) -{ - struct isc_clk *isc_clk = to_isc_clk(hw); - - isc_wait_clk_stable(hw); - - if (isc_clk->id == ISC_ISPCK) - pm_runtime_put_sync(isc_clk->dev); -} - -static int isc_clk_enable(struct clk_hw *hw) -{ - struct isc_clk *isc_clk = to_isc_clk(hw); - u32 id = isc_clk->id; - struct regmap *regmap = isc_clk->regmap; - unsigned long flags; - unsigned int status; - - dev_dbg(isc_clk->dev, "ISC CLK: %s, div = %d, parent id = %d\n", - __func__, isc_clk->div, isc_clk->parent_id); - - spin_lock_irqsave(&isc_clk->lock, flags); - regmap_update_bits(regmap, ISC_CLKCFG, - ISC_CLKCFG_DIV_MASK(id) | ISC_CLKCFG_SEL_MASK(id), - (isc_clk->div << ISC_CLKCFG_DIV_SHIFT(id)) | - (isc_clk->parent_id << ISC_CLKCFG_SEL_SHIFT(id))); - - regmap_write(regmap, ISC_CLKEN, ISC_CLK(id)); - spin_unlock_irqrestore(&isc_clk->lock, flags); - - regmap_read(regmap, ISC_CLKSR, &status); - if (status & ISC_CLK(id)) - return 0; - else - return -EINVAL; -} - -static void isc_clk_disable(struct clk_hw *hw) -{ - struct isc_clk *isc_clk = to_isc_clk(hw); - u32 id = isc_clk->id; - unsigned long flags; - - spin_lock_irqsave(&isc_clk->lock, flags); - regmap_write(isc_clk->regmap, ISC_CLKDIS, ISC_CLK(id)); - spin_unlock_irqrestore(&isc_clk->lock, flags); -} - -static int isc_clk_is_enabled(struct clk_hw *hw) -{ - struct isc_clk *isc_clk = to_isc_clk(hw); - u32 status; - - if (isc_clk->id == ISC_ISPCK) - pm_runtime_get_sync(isc_clk->dev); - - regmap_read(isc_clk->regmap, ISC_CLKSR, &status); - - if (isc_clk->id == ISC_ISPCK) - pm_runtime_put_sync(isc_clk->dev); - - return status & ISC_CLK(isc_clk->id) ? 1 : 0; -} - -static unsigned long -isc_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) -{ - struct isc_clk *isc_clk = to_isc_clk(hw); - - return DIV_ROUND_CLOSEST(parent_rate, isc_clk->div + 1); -} - -static int isc_clk_determine_rate(struct clk_hw *hw, - struct clk_rate_request *req) -{ - struct isc_clk *isc_clk = to_isc_clk(hw); - long best_rate = -EINVAL; - int best_diff = -1; - unsigned int i, div; - - for (i = 0; i < clk_hw_get_num_parents(hw); i++) { - struct clk_hw *parent; - unsigned long parent_rate; - - parent = clk_hw_get_parent_by_index(hw, i); - if (!parent) - continue; - - parent_rate = clk_hw_get_rate(parent); - if (!parent_rate) - continue; - - for (div = 1; div < ISC_CLK_MAX_DIV + 2; div++) { - unsigned long rate; - int diff; - - rate = DIV_ROUND_CLOSEST(parent_rate, div); - diff = abs(req->rate - rate); - - if (best_diff < 0 || best_diff > diff) { - best_rate = rate; - best_diff = diff; - req->best_parent_rate = parent_rate; - req->best_parent_hw = parent; - } - - if (!best_diff || rate < req->rate) - break; - } - - if (!best_diff) - break; - } - - dev_dbg(isc_clk->dev, - "ISC CLK: %s, best_rate = %ld, parent clk: %s @ %ld\n", - __func__, best_rate, - __clk_get_name((req->best_parent_hw)->clk), - req->best_parent_rate); - - if (best_rate < 0) - return best_rate; - - req->rate = best_rate; - - return 0; -} - -static int isc_clk_set_parent(struct clk_hw *hw, u8 index) -{ - struct isc_clk *isc_clk = to_isc_clk(hw); - - if (index >= clk_hw_get_num_parents(hw)) - return -EINVAL; - - isc_clk->parent_id = index; - - return 0; -} - -static u8 isc_clk_get_parent(struct clk_hw *hw) -{ - struct isc_clk *isc_clk = to_isc_clk(hw); - - return isc_clk->parent_id; -} - -static int isc_clk_set_rate(struct clk_hw *hw, - unsigned long rate, - unsigned long parent_rate) -{ - struct isc_clk *isc_clk = to_isc_clk(hw); - u32 div; - - if (!rate) - return -EINVAL; - - div = DIV_ROUND_CLOSEST(parent_rate, rate); - if (div > (ISC_CLK_MAX_DIV + 1) || !div) - return -EINVAL; - - isc_clk->div = div - 1; - - return 0; -} - -static const struct clk_ops isc_clk_ops = { - .prepare = isc_clk_prepare, - .unprepare = isc_clk_unprepare, - .enable = isc_clk_enable, - .disable = isc_clk_disable, - .is_enabled = isc_clk_is_enabled, - .recalc_rate = isc_clk_recalc_rate, - .determine_rate = isc_clk_determine_rate, - .set_parent = isc_clk_set_parent, - .get_parent = isc_clk_get_parent, - .set_rate = isc_clk_set_rate, -}; - -static int isc_clk_register(struct isc_device *isc, unsigned int id) -{ - struct regmap *regmap = isc->regmap; - struct device_node *np = isc->dev->of_node; - struct isc_clk *isc_clk; - struct clk_init_data init; - const char *clk_name = np->name; - const char *parent_names[3]; - int num_parents; - - num_parents = of_clk_get_parent_count(np); - if (num_parents < 1 || num_parents > 3) - return -EINVAL; - - if (num_parents > 2 && id == ISC_ISPCK) - num_parents = 2; - - of_clk_parent_fill(np, parent_names, num_parents); - - if (id == ISC_MCK) - of_property_read_string(np, "clock-output-names", &clk_name); - else - clk_name = "isc-ispck"; - - init.parent_names = parent_names; - init.num_parents = num_parents; - init.name = clk_name; - init.ops = &isc_clk_ops; - init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE; - - isc_clk = &isc->isc_clks[id]; - isc_clk->hw.init = &init; - isc_clk->regmap = regmap; - isc_clk->id = id; - isc_clk->dev = isc->dev; - spin_lock_init(&isc_clk->lock); - - isc_clk->clk = clk_register(isc->dev, &isc_clk->hw); - if (IS_ERR(isc_clk->clk)) { - dev_err(isc->dev, "%s: clock register fail\n", clk_name); - return PTR_ERR(isc_clk->clk); - } else if (id == ISC_MCK) - of_clk_add_provider(np, of_clk_src_simple_get, isc_clk->clk); - - return 0; -} - -static int isc_clk_init(struct isc_device *isc) -{ - unsigned int i; - int ret; - - for (i = 0; i < ARRAY_SIZE(isc->isc_clks); i++) - isc->isc_clks[i].clk = ERR_PTR(-EINVAL); - - for (i = 0; i < ARRAY_SIZE(isc->isc_clks); i++) { - ret = isc_clk_register(isc, i); - if (ret) - return ret; - } - - return 0; -} - -static void isc_clk_cleanup(struct isc_device *isc) -{ - unsigned int i; - - of_clk_del_provider(isc->dev->of_node); - - for (i = 0; i < ARRAY_SIZE(isc->isc_clks); i++) { - struct isc_clk *isc_clk = &isc->isc_clks[i]; - - if (!IS_ERR(isc_clk->clk)) - clk_unregister(isc_clk->clk); - } -} - -static int isc_queue_setup(struct vb2_queue *vq, - unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], struct device *alloc_devs[]) -{ - struct isc_device *isc = vb2_get_drv_priv(vq); - unsigned int size = isc->fmt.fmt.pix.sizeimage; - - if (*nplanes) - return sizes[0] < size ? -EINVAL : 0; - - *nplanes = 1; - sizes[0] = size; - - return 0; -} - -static int isc_buffer_prepare(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct isc_device *isc = vb2_get_drv_priv(vb->vb2_queue); - unsigned long size = isc->fmt.fmt.pix.sizeimage; - - if (vb2_plane_size(vb, 0) < size) { - v4l2_err(&isc->v4l2_dev, "buffer too small (%lu < %lu)\n", - vb2_plane_size(vb, 0), size); - return -EINVAL; - } - - vb2_set_plane_payload(vb, 0, size); - - vbuf->field = isc->fmt.fmt.pix.field; - - return 0; -} - -static void isc_start_dma(struct isc_device *isc) -{ - struct regmap *regmap = isc->regmap; - u32 sizeimage = isc->fmt.fmt.pix.sizeimage; - u32 dctrl_dview; - dma_addr_t addr0; - u32 h, w; - - h = isc->fmt.fmt.pix.height; - w = isc->fmt.fmt.pix.width; - - /* - * In case the sensor is not RAW, it will output a pixel (12-16 bits) - * with two samples on the ISC Data bus (which is 8-12) - * ISC will count each sample, so, we need to multiply these values - * by two, to get the real number of samples for the required pixels. - */ - if (!ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code)) { - h <<= 1; - w <<= 1; - } - - /* - * We limit the column/row count that the ISC will output according - * to the configured resolution that we want. - * This will avoid the situation where the sensor is misconfigured, - * sending more data, and the ISC will just take it and DMA to memory, - * causing corruption. - */ - regmap_write(regmap, ISC_PFE_CFG1, - (ISC_PFE_CFG1_COLMIN(0) & ISC_PFE_CFG1_COLMIN_MASK) | - (ISC_PFE_CFG1_COLMAX(w - 1) & ISC_PFE_CFG1_COLMAX_MASK)); - - regmap_write(regmap, ISC_PFE_CFG2, - (ISC_PFE_CFG2_ROWMIN(0) & ISC_PFE_CFG2_ROWMIN_MASK) | - (ISC_PFE_CFG2_ROWMAX(h - 1) & ISC_PFE_CFG2_ROWMAX_MASK)); - - regmap_update_bits(regmap, ISC_PFE_CFG0, - ISC_PFE_CFG0_COLEN | ISC_PFE_CFG0_ROWEN, - ISC_PFE_CFG0_COLEN | ISC_PFE_CFG0_ROWEN); - - addr0 = vb2_dma_contig_plane_dma_addr(&isc->cur_frm->vb.vb2_buf, 0); - regmap_write(regmap, ISC_DAD0, addr0); - - switch (isc->config.fourcc) { - case V4L2_PIX_FMT_YUV420: - regmap_write(regmap, ISC_DAD1, addr0 + (sizeimage * 2) / 3); - regmap_write(regmap, ISC_DAD2, addr0 + (sizeimage * 5) / 6); - break; - case V4L2_PIX_FMT_YUV422P: - regmap_write(regmap, ISC_DAD1, addr0 + sizeimage / 2); - regmap_write(regmap, ISC_DAD2, addr0 + (sizeimage * 3) / 4); - break; - default: - break; - } - - dctrl_dview = isc->config.dctrl_dview; - - regmap_write(regmap, ISC_DCTRL, dctrl_dview | ISC_DCTRL_IE_IS); - spin_lock(&isc->awb_lock); - regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_CAPTURE); - spin_unlock(&isc->awb_lock); -} - -static void isc_set_pipeline(struct isc_device *isc, u32 pipeline) -{ - struct regmap *regmap = isc->regmap; - struct isc_ctrls *ctrls = &isc->ctrls; - u32 val, bay_cfg; - const u32 *gamma; - unsigned int i; - - /* WB-->CFA-->CC-->GAM-->CSC-->CBC-->SUB422-->SUB420 */ - for (i = 0; i < ISC_PIPE_LINE_NODE_NUM; i++) { - val = pipeline & BIT(i) ? 1 : 0; - regmap_field_write(isc->pipeline[i], val); - } - - if (!pipeline) - return; - - bay_cfg = isc->config.sd_format->cfa_baycfg; - - if (ctrls->awb == ISC_WB_NONE) - isc_reset_awb_ctrls(isc); - - regmap_write(regmap, ISC_WB_CFG, bay_cfg); - isc_update_awb_ctrls(isc); - - regmap_write(regmap, ISC_CFA_CFG, bay_cfg | ISC_CFA_CFG_EITPOL); - - gamma = &isc_gamma_table[ctrls->gamma_index][0]; - regmap_bulk_write(regmap, ISC_GAM_BENTRY, gamma, GAMMA_ENTRIES); - regmap_bulk_write(regmap, ISC_GAM_GENTRY, gamma, GAMMA_ENTRIES); - regmap_bulk_write(regmap, ISC_GAM_RENTRY, gamma, GAMMA_ENTRIES); - - /* Convert RGB to YUV */ - regmap_write(regmap, ISC_CSC_YR_YG, 0x42 | (0x81 << 16)); - regmap_write(regmap, ISC_CSC_YB_OY, 0x19 | (0x10 << 16)); - regmap_write(regmap, ISC_CSC_CBR_CBG, 0xFDA | (0xFB6 << 16)); - regmap_write(regmap, ISC_CSC_CBB_OCB, 0x70 | (0x80 << 16)); - regmap_write(regmap, ISC_CSC_CRR_CRG, 0x70 | (0xFA2 << 16)); - regmap_write(regmap, ISC_CSC_CRB_OCR, 0xFEE | (0x80 << 16)); - - regmap_write(regmap, ISC_CBC_BRIGHT, ctrls->brightness); - regmap_write(regmap, ISC_CBC_CONTRAST, ctrls->contrast); -} - -static int isc_update_profile(struct isc_device *isc) -{ - struct regmap *regmap = isc->regmap; - u32 sr; - int counter = 100; - - regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_UPPRO); - - regmap_read(regmap, ISC_CTRLSR, &sr); - while ((sr & ISC_CTRL_UPPRO) && counter--) { - usleep_range(1000, 2000); - regmap_read(regmap, ISC_CTRLSR, &sr); - } - - if (counter < 0) { - v4l2_warn(&isc->v4l2_dev, "Time out to update profile\n"); - return -ETIMEDOUT; - } - - return 0; -} - -static void isc_set_histogram(struct isc_device *isc, bool enable) -{ - struct regmap *regmap = isc->regmap; - struct isc_ctrls *ctrls = &isc->ctrls; - - if (enable) { - regmap_write(regmap, ISC_HIS_CFG, - ISC_HIS_CFG_MODE_GR | - (isc->config.sd_format->cfa_baycfg - << ISC_HIS_CFG_BAYSEL_SHIFT) | - ISC_HIS_CFG_RAR); - regmap_write(regmap, ISC_HIS_CTRL, ISC_HIS_CTRL_EN); - regmap_write(regmap, ISC_INTEN, ISC_INT_HISDONE); - ctrls->hist_id = ISC_HIS_CFG_MODE_GR; - isc_update_profile(isc); - regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_HISREQ); - - ctrls->hist_stat = HIST_ENABLED; - } else { - regmap_write(regmap, ISC_INTDIS, ISC_INT_HISDONE); - regmap_write(regmap, ISC_HIS_CTRL, ISC_HIS_CTRL_DIS); - - ctrls->hist_stat = HIST_DISABLED; - } -} - -static int isc_configure(struct isc_device *isc) -{ - struct regmap *regmap = isc->regmap; - u32 pfe_cfg0, rlp_mode, dcfg, mask, pipeline; - struct isc_subdev_entity *subdev = isc->current_subdev; - - pfe_cfg0 = isc->config.sd_format->pfe_cfg0_bps; - rlp_mode = isc->config.rlp_cfg_mode; - pipeline = isc->config.bits_pipeline; - - dcfg = isc->config.dcfg_imode | - ISC_DCFG_YMBSIZE_BEATS8 | ISC_DCFG_CMBSIZE_BEATS8; - - pfe_cfg0 |= subdev->pfe_cfg0 | ISC_PFE_CFG0_MODE_PROGRESSIVE; - mask = ISC_PFE_CFG0_BPS_MASK | ISC_PFE_CFG0_HPOL_LOW | - ISC_PFE_CFG0_VPOL_LOW | ISC_PFE_CFG0_PPOL_LOW | - ISC_PFE_CFG0_MODE_MASK | ISC_PFE_CFG0_CCIR_CRC | - ISC_PFE_CFG0_CCIR656; - - regmap_update_bits(regmap, ISC_PFE_CFG0, mask, pfe_cfg0); - - regmap_update_bits(regmap, ISC_RLP_CFG, ISC_RLP_CFG_MODE_MASK, - rlp_mode); - - regmap_write(regmap, ISC_DCFG, dcfg); - - /* Set the pipeline */ - isc_set_pipeline(isc, pipeline); - - /* - * The current implemented histogram is available for RAW R, B, GB, GR - * channels. We need to check if sensor is outputting RAW BAYER - */ - if (isc->ctrls.awb && - ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code)) - isc_set_histogram(isc, true); - else - isc_set_histogram(isc, false); - - /* Update profile */ - return isc_update_profile(isc); -} - -static int isc_start_streaming(struct vb2_queue *vq, unsigned int count) -{ - struct isc_device *isc = vb2_get_drv_priv(vq); - struct regmap *regmap = isc->regmap; - struct isc_buffer *buf; - unsigned long flags; - int ret; - - /* Enable stream on the sub device */ - ret = v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 1); - if (ret && ret != -ENOIOCTLCMD) { - v4l2_err(&isc->v4l2_dev, "stream on failed in subdev %d\n", - ret); - goto err_start_stream; - } - - pm_runtime_get_sync(isc->dev); - - ret = isc_configure(isc); - if (unlikely(ret)) - goto err_configure; - - /* Enable DMA interrupt */ - regmap_write(regmap, ISC_INTEN, ISC_INT_DDONE); - - spin_lock_irqsave(&isc->dma_queue_lock, flags); - - isc->sequence = 0; - isc->stop = false; - reinit_completion(&isc->comp); - - isc->cur_frm = list_first_entry(&isc->dma_queue, - struct isc_buffer, list); - list_del(&isc->cur_frm->list); - - isc_start_dma(isc); - - spin_unlock_irqrestore(&isc->dma_queue_lock, flags); - - /* if we streaming from RAW, we can do one-shot white balance adj */ - if (ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code)) - v4l2_ctrl_activate(isc->do_wb_ctrl, true); - - return 0; - -err_configure: - pm_runtime_put_sync(isc->dev); - - v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 0); - -err_start_stream: - spin_lock_irqsave(&isc->dma_queue_lock, flags); - list_for_each_entry(buf, &isc->dma_queue, list) - vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED); - INIT_LIST_HEAD(&isc->dma_queue); - spin_unlock_irqrestore(&isc->dma_queue_lock, flags); - - return ret; -} - -static void isc_stop_streaming(struct vb2_queue *vq) -{ - struct isc_device *isc = vb2_get_drv_priv(vq); - unsigned long flags; - struct isc_buffer *buf; - int ret; - - v4l2_ctrl_activate(isc->do_wb_ctrl, false); - - isc->stop = true; - - /* Wait until the end of the current frame */ - if (isc->cur_frm && !wait_for_completion_timeout(&isc->comp, 5 * HZ)) - v4l2_err(&isc->v4l2_dev, - "Timeout waiting for end of the capture\n"); - - /* Disable DMA interrupt */ - regmap_write(isc->regmap, ISC_INTDIS, ISC_INT_DDONE); - - pm_runtime_put_sync(isc->dev); - - /* Disable stream on the sub device */ - ret = v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 0); - if (ret && ret != -ENOIOCTLCMD) - v4l2_err(&isc->v4l2_dev, "stream off failed in subdev\n"); - - /* Release all active buffers */ - spin_lock_irqsave(&isc->dma_queue_lock, flags); - if (unlikely(isc->cur_frm)) { - vb2_buffer_done(&isc->cur_frm->vb.vb2_buf, - VB2_BUF_STATE_ERROR); - isc->cur_frm = NULL; - } - list_for_each_entry(buf, &isc->dma_queue, list) - vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); - INIT_LIST_HEAD(&isc->dma_queue); - spin_unlock_irqrestore(&isc->dma_queue_lock, flags); -} - -static void isc_buffer_queue(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct isc_buffer *buf = container_of(vbuf, struct isc_buffer, vb); - struct isc_device *isc = vb2_get_drv_priv(vb->vb2_queue); - unsigned long flags; - - spin_lock_irqsave(&isc->dma_queue_lock, flags); - if (!isc->cur_frm && list_empty(&isc->dma_queue) && - vb2_is_streaming(vb->vb2_queue)) { - isc->cur_frm = buf; - isc_start_dma(isc); - } else - list_add_tail(&buf->list, &isc->dma_queue); - spin_unlock_irqrestore(&isc->dma_queue_lock, flags); -} - -static struct isc_format *find_format_by_fourcc(struct isc_device *isc, - unsigned int fourcc) -{ - unsigned int num_formats = isc->num_user_formats; - struct isc_format *fmt; - unsigned int i; - - for (i = 0; i < num_formats; i++) { - fmt = isc->user_formats[i]; - if (fmt->fourcc == fourcc) - return fmt; - } - - return NULL; -} - -static const struct vb2_ops isc_vb2_ops = { - .queue_setup = isc_queue_setup, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, - .buf_prepare = isc_buffer_prepare, - .start_streaming = isc_start_streaming, - .stop_streaming = isc_stop_streaming, - .buf_queue = isc_buffer_queue, -}; - -static int isc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct isc_device *isc = video_drvdata(file); - - strscpy(cap->driver, ATMEL_ISC_NAME, sizeof(cap->driver)); - strscpy(cap->card, "Atmel Image Sensor Controller", sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), - "platform:%s", isc->v4l2_dev.name); - - return 0; -} - -static int isc_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - u32 index = f->index; - u32 i, supported_index; - - if (index < ARRAY_SIZE(controller_formats)) { - f->pixelformat = controller_formats[index].fourcc; - return 0; - } - - index -= ARRAY_SIZE(controller_formats); - - i = 0; - supported_index = 0; - - for (i = 0; i < ARRAY_SIZE(formats_list); i++) { - if (!ISC_IS_FORMAT_RAW(formats_list[i].mbus_code) || - !formats_list[i].sd_support) - continue; - if (supported_index == index) { - f->pixelformat = formats_list[i].fourcc; - return 0; - } - supported_index++; - } - - return -EINVAL; -} - -static int isc_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *fmt) -{ - struct isc_device *isc = video_drvdata(file); - - *fmt = isc->fmt; - - return 0; -} - -/* - * Checks the current configured format, if ISC can output it, - * considering which type of format the ISC receives from the sensor - */ -static int isc_try_validate_formats(struct isc_device *isc) -{ - int ret; - bool bayer = false, yuv = false, rgb = false, grey = false; - - /* all formats supported by the RLP module are OK */ - switch (isc->try_config.fourcc) { - case V4L2_PIX_FMT_SBGGR8: - case V4L2_PIX_FMT_SGBRG8: - case V4L2_PIX_FMT_SGRBG8: - case V4L2_PIX_FMT_SRGGB8: - case V4L2_PIX_FMT_SBGGR10: - case V4L2_PIX_FMT_SGBRG10: - case V4L2_PIX_FMT_SGRBG10: - case V4L2_PIX_FMT_SRGGB10: - case V4L2_PIX_FMT_SBGGR12: - case V4L2_PIX_FMT_SGBRG12: - case V4L2_PIX_FMT_SGRBG12: - case V4L2_PIX_FMT_SRGGB12: - ret = 0; - bayer = true; - break; - - case V4L2_PIX_FMT_YUV420: - case V4L2_PIX_FMT_YUV422P: - case V4L2_PIX_FMT_YUYV: - ret = 0; - yuv = true; - break; - - case V4L2_PIX_FMT_RGB565: - case V4L2_PIX_FMT_ABGR32: - case V4L2_PIX_FMT_XBGR32: - case V4L2_PIX_FMT_ARGB444: - case V4L2_PIX_FMT_ARGB555: - ret = 0; - rgb = true; - break; - case V4L2_PIX_FMT_GREY: - ret = 0; - grey = true; - break; - default: - /* any other different formats are not supported */ - ret = -EINVAL; - } - - /* we cannot output RAW/Grey if we do not receive RAW */ - if ((bayer || grey) && - !ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) - return -EINVAL; - - v4l2_dbg(1, debug, &isc->v4l2_dev, - "Format validation, requested rgb=%u, yuv=%u, grey=%u, bayer=%u\n", - rgb, yuv, grey, bayer); - - return ret; -} - -/* - * Configures the RLP and DMA modules, depending on the output format - * configured for the ISC. - * If direct_dump == true, just dump raw data 8 bits. - */ -static int isc_try_configure_rlp_dma(struct isc_device *isc, bool direct_dump) -{ - if (direct_dump) { - isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8; - isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED8; - isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; - isc->try_config.bpp = 16; - return 0; - } - - switch (isc->try_config.fourcc) { - case V4L2_PIX_FMT_SBGGR8: - case V4L2_PIX_FMT_SGBRG8: - case V4L2_PIX_FMT_SGRBG8: - case V4L2_PIX_FMT_SRGGB8: - isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8; - isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED8; - isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; - isc->try_config.bpp = 8; - break; - case V4L2_PIX_FMT_SBGGR10: - case V4L2_PIX_FMT_SGBRG10: - case V4L2_PIX_FMT_SGRBG10: - case V4L2_PIX_FMT_SRGGB10: - isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT10; - isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16; - isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; - isc->try_config.bpp = 16; - break; - case V4L2_PIX_FMT_SBGGR12: - case V4L2_PIX_FMT_SGBRG12: - case V4L2_PIX_FMT_SGRBG12: - case V4L2_PIX_FMT_SRGGB12: - isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT12; - isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16; - isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; - isc->try_config.bpp = 16; - break; - case V4L2_PIX_FMT_RGB565: - isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_RGB565; - isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16; - isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; - isc->try_config.bpp = 16; - break; - case V4L2_PIX_FMT_ARGB444: - isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB444; - isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16; - isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; - isc->try_config.bpp = 16; - break; - case V4L2_PIX_FMT_ARGB555: - isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB555; - isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16; - isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; - isc->try_config.bpp = 16; - break; - case V4L2_PIX_FMT_ABGR32: - case V4L2_PIX_FMT_XBGR32: - isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB32; - isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED32; - isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; - isc->try_config.bpp = 32; - break; - case V4L2_PIX_FMT_YUV420: - isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YYCC; - isc->try_config.dcfg_imode = ISC_DCFG_IMODE_YC420P; - isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PLANAR; - isc->try_config.bpp = 12; - break; - case V4L2_PIX_FMT_YUV422P: - isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YYCC; - isc->try_config.dcfg_imode = ISC_DCFG_IMODE_YC422P; - isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PLANAR; - isc->try_config.bpp = 16; - break; - case V4L2_PIX_FMT_YUYV: - isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YYCC; - isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED32; - isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; - isc->try_config.bpp = 16; - break; - case V4L2_PIX_FMT_GREY: - isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DATY8; - isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED8; - isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; - isc->try_config.bpp = 8; - break; - default: - return -EINVAL; - } - return 0; -} - -/* - * Configuring pipeline modules, depending on which format the ISC outputs - * and considering which format it has as input from the sensor. - */ -static int isc_try_configure_pipeline(struct isc_device *isc) -{ - switch (isc->try_config.fourcc) { - case V4L2_PIX_FMT_RGB565: - case V4L2_PIX_FMT_ARGB555: - case V4L2_PIX_FMT_ARGB444: - case V4L2_PIX_FMT_ABGR32: - case V4L2_PIX_FMT_XBGR32: - /* if sensor format is RAW, we convert inside ISC */ - if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) { - isc->try_config.bits_pipeline = CFA_ENABLE | - WB_ENABLE | GAM_ENABLES; - } else { - isc->try_config.bits_pipeline = 0x0; - } - break; - case V4L2_PIX_FMT_YUV420: - /* if sensor format is RAW, we convert inside ISC */ - if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) { - isc->try_config.bits_pipeline = CFA_ENABLE | - CSC_ENABLE | WB_ENABLE | GAM_ENABLES | - SUB420_ENABLE | SUB422_ENABLE | CBC_ENABLE; - } else { - isc->try_config.bits_pipeline = 0x0; - } - break; - case V4L2_PIX_FMT_YUV422P: - /* if sensor format is RAW, we convert inside ISC */ - if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) { - isc->try_config.bits_pipeline = CFA_ENABLE | - CSC_ENABLE | WB_ENABLE | GAM_ENABLES | - SUB422_ENABLE | CBC_ENABLE; - } else { - isc->try_config.bits_pipeline = 0x0; - } - break; - case V4L2_PIX_FMT_YUYV: - /* if sensor format is RAW, we convert inside ISC */ - if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) { - isc->try_config.bits_pipeline = CFA_ENABLE | - CSC_ENABLE | WB_ENABLE | GAM_ENABLES | - SUB422_ENABLE | CBC_ENABLE; - } else { - isc->try_config.bits_pipeline = 0x0; - } - break; - case V4L2_PIX_FMT_GREY: - if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) { - /* if sensor format is RAW, we convert inside ISC */ - isc->try_config.bits_pipeline = CFA_ENABLE | - CSC_ENABLE | WB_ENABLE | GAM_ENABLES | - CBC_ENABLE; - } else { - isc->try_config.bits_pipeline = 0x0; - } - break; - default: - isc->try_config.bits_pipeline = 0x0; - } - return 0; -} - -static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f, - u32 *code) -{ - int i; - struct isc_format *sd_fmt = NULL, *direct_fmt = NULL; - struct v4l2_pix_format *pixfmt = &f->fmt.pix; - struct v4l2_subdev_pad_config pad_cfg; - struct v4l2_subdev_format format = { - .which = V4L2_SUBDEV_FORMAT_TRY, - }; - u32 mbus_code; - int ret; - bool rlp_dma_direct_dump = false; - - if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - /* Step 1: find a RAW format that is supported */ - for (i = 0; i < isc->num_user_formats; i++) { - if (ISC_IS_FORMAT_RAW(isc->user_formats[i]->mbus_code)) { - sd_fmt = isc->user_formats[i]; - break; - } - } - /* Step 2: We can continue with this RAW format, or we can look - * for better: maybe sensor supports directly what we need. - */ - direct_fmt = find_format_by_fourcc(isc, pixfmt->pixelformat); - - /* Step 3: We have both. We decide given the module parameter which - * one to use. - */ - if (direct_fmt && sd_fmt && sensor_preferred) - sd_fmt = direct_fmt; - - /* Step 4: we do not have RAW but we have a direct format. Use it. */ - if (direct_fmt && !sd_fmt) - sd_fmt = direct_fmt; - - /* Step 5: if we are using a direct format, we need to package - * everything as 8 bit data and just dump it - */ - if (sd_fmt == direct_fmt) - rlp_dma_direct_dump = true; - - /* Step 6: We have no format. This can happen if the userspace - * requests some weird/invalid format. - * In this case, default to whatever we have - */ - if (!sd_fmt && !direct_fmt) { - sd_fmt = isc->user_formats[isc->num_user_formats - 1]; - v4l2_dbg(1, debug, &isc->v4l2_dev, - "Sensor not supporting %.4s, using %.4s\n", - (char *)&pixfmt->pixelformat, (char *)&sd_fmt->fourcc); - } - - if (!sd_fmt) { - ret = -EINVAL; - goto isc_try_fmt_err; - } - - /* Step 7: Print out what we decided for debugging */ - v4l2_dbg(1, debug, &isc->v4l2_dev, - "Preferring to have sensor using format %.4s\n", - (char *)&sd_fmt->fourcc); - - /* Step 8: at this moment we decided which format the subdev will use */ - isc->try_config.sd_format = sd_fmt; - - /* Limit to Atmel ISC hardware capabilities */ - if (pixfmt->width > ISC_MAX_SUPPORT_WIDTH) - pixfmt->width = ISC_MAX_SUPPORT_WIDTH; - if (pixfmt->height > ISC_MAX_SUPPORT_HEIGHT) - pixfmt->height = ISC_MAX_SUPPORT_HEIGHT; - - /* - * The mbus format is the one the subdev outputs. - * The pixels will be transferred in this format Sensor -> ISC - */ - mbus_code = sd_fmt->mbus_code; - - /* - * Validate formats. If the required format is not OK, default to raw. - */ - - isc->try_config.fourcc = pixfmt->pixelformat; - - if (isc_try_validate_formats(isc)) { - pixfmt->pixelformat = isc->try_config.fourcc = sd_fmt->fourcc; - /* Re-try to validate the new format */ - ret = isc_try_validate_formats(isc); - if (ret) - goto isc_try_fmt_err; - } - - ret = isc_try_configure_rlp_dma(isc, rlp_dma_direct_dump); - if (ret) - goto isc_try_fmt_err; - - ret = isc_try_configure_pipeline(isc); - if (ret) - goto isc_try_fmt_err; - - v4l2_fill_mbus_format(&format.format, pixfmt, mbus_code); - ret = v4l2_subdev_call(isc->current_subdev->sd, pad, set_fmt, - &pad_cfg, &format); - if (ret < 0) - goto isc_try_fmt_subdev_err; - - v4l2_fill_pix_format(pixfmt, &format.format); - - pixfmt->field = V4L2_FIELD_NONE; - pixfmt->bytesperline = (pixfmt->width * isc->try_config.bpp) >> 3; - pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height; - - if (code) - *code = mbus_code; - - return 0; - -isc_try_fmt_err: - v4l2_err(&isc->v4l2_dev, "Could not find any possible format for a working pipeline\n"); -isc_try_fmt_subdev_err: - memset(&isc->try_config, 0, sizeof(isc->try_config)); - - return ret; -} - -static int isc_set_fmt(struct isc_device *isc, struct v4l2_format *f) -{ - struct v4l2_subdev_format format = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - }; - u32 mbus_code = 0; - int ret; - - ret = isc_try_fmt(isc, f, &mbus_code); - if (ret) - return ret; - - v4l2_fill_mbus_format(&format.format, &f->fmt.pix, mbus_code); - ret = v4l2_subdev_call(isc->current_subdev->sd, pad, - set_fmt, NULL, &format); - if (ret < 0) - return ret; - - isc->fmt = *f; - - if (isc->try_config.sd_format && isc->config.sd_format && - isc->try_config.sd_format != isc->config.sd_format) { - isc->ctrls.hist_stat = HIST_INIT; - isc_reset_awb_ctrls(isc); - } - /* make the try configuration active */ - isc->config = isc->try_config; - - v4l2_dbg(1, debug, &isc->v4l2_dev, "New ISC configuration in place\n"); - - return 0; -} - -static int isc_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct isc_device *isc = video_drvdata(file); - - if (vb2_is_streaming(&isc->vb2_vidq)) - return -EBUSY; - - return isc_set_fmt(isc, f); -} - -static int isc_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct isc_device *isc = video_drvdata(file); - - return isc_try_fmt(isc, f, NULL); -} - -static int isc_enum_input(struct file *file, void *priv, - struct v4l2_input *inp) -{ - if (inp->index != 0) - return -EINVAL; - - inp->type = V4L2_INPUT_TYPE_CAMERA; - inp->std = 0; - strscpy(inp->name, "Camera", sizeof(inp->name)); - - return 0; -} - -static int isc_g_input(struct file *file, void *priv, unsigned int *i) -{ - *i = 0; - - return 0; -} - -static int isc_s_input(struct file *file, void *priv, unsigned int i) -{ - if (i > 0) - return -EINVAL; - - return 0; -} - -static int isc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) -{ - struct isc_device *isc = video_drvdata(file); - - return v4l2_g_parm_cap(video_devdata(file), isc->current_subdev->sd, a); -} - -static int isc_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) -{ - struct isc_device *isc = video_drvdata(file); - - return v4l2_s_parm_cap(video_devdata(file), isc->current_subdev->sd, a); -} - -static int isc_enum_framesizes(struct file *file, void *fh, - struct v4l2_frmsizeenum *fsize) -{ - struct isc_device *isc = video_drvdata(file); - struct v4l2_subdev_frame_size_enum fse = { - .index = fsize->index, - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - }; - int ret = -EINVAL; - int i; - - for (i = 0; i < isc->num_user_formats; i++) - if (isc->user_formats[i]->fourcc == fsize->pixel_format) - ret = 0; - - for (i = 0; i < ARRAY_SIZE(controller_formats); i++) - if (controller_formats[i].fourcc == fsize->pixel_format) - ret = 0; - - if (ret) - return ret; - - ret = v4l2_subdev_call(isc->current_subdev->sd, pad, enum_frame_size, - NULL, &fse); - if (ret) - return ret; - - fse.code = isc->config.sd_format->mbus_code; - - fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; - fsize->discrete.width = fse.max_width; - fsize->discrete.height = fse.max_height; - - return 0; -} - -static int isc_enum_frameintervals(struct file *file, void *fh, - struct v4l2_frmivalenum *fival) -{ - struct isc_device *isc = video_drvdata(file); - struct v4l2_subdev_frame_interval_enum fie = { - .index = fival->index, - .width = fival->width, - .height = fival->height, - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - }; - int ret = -EINVAL; - int i; - - for (i = 0; i < isc->num_user_formats; i++) - if (isc->user_formats[i]->fourcc == fival->pixel_format) - ret = 0; - - for (i = 0; i < ARRAY_SIZE(controller_formats); i++) - if (controller_formats[i].fourcc == fival->pixel_format) - ret = 0; - - if (ret) - return ret; - - ret = v4l2_subdev_call(isc->current_subdev->sd, pad, - enum_frame_interval, NULL, &fie); - if (ret) - return ret; - - fie.code = isc->config.sd_format->mbus_code; - fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; - fival->discrete = fie.interval; - - return 0; -} - -static const struct v4l2_ioctl_ops isc_ioctl_ops = { - .vidioc_querycap = isc_querycap, - .vidioc_enum_fmt_vid_cap = isc_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = isc_g_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = isc_s_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = isc_try_fmt_vid_cap, - - .vidioc_enum_input = isc_enum_input, - .vidioc_g_input = isc_g_input, - .vidioc_s_input = isc_s_input, - - .vidioc_reqbufs = vb2_ioctl_reqbufs, - .vidioc_querybuf = vb2_ioctl_querybuf, - .vidioc_qbuf = vb2_ioctl_qbuf, - .vidioc_expbuf = vb2_ioctl_expbuf, - .vidioc_dqbuf = vb2_ioctl_dqbuf, - .vidioc_create_bufs = vb2_ioctl_create_bufs, - .vidioc_prepare_buf = vb2_ioctl_prepare_buf, - .vidioc_streamon = vb2_ioctl_streamon, - .vidioc_streamoff = vb2_ioctl_streamoff, - - .vidioc_g_parm = isc_g_parm, - .vidioc_s_parm = isc_s_parm, - .vidioc_enum_framesizes = isc_enum_framesizes, - .vidioc_enum_frameintervals = isc_enum_frameintervals, - - .vidioc_log_status = v4l2_ctrl_log_status, - .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, -}; - -static int isc_open(struct file *file) -{ - struct isc_device *isc = video_drvdata(file); - struct v4l2_subdev *sd = isc->current_subdev->sd; - int ret; - - if (mutex_lock_interruptible(&isc->lock)) - return -ERESTARTSYS; - - ret = v4l2_fh_open(file); - if (ret < 0) - goto unlock; - - if (!v4l2_fh_is_singular_file(file)) - goto unlock; - - ret = v4l2_subdev_call(sd, core, s_power, 1); - if (ret < 0 && ret != -ENOIOCTLCMD) { - v4l2_fh_release(file); - goto unlock; - } - - ret = isc_set_fmt(isc, &isc->fmt); - if (ret) { - v4l2_subdev_call(sd, core, s_power, 0); - v4l2_fh_release(file); - } - -unlock: - mutex_unlock(&isc->lock); - return ret; -} - -static int isc_release(struct file *file) -{ - struct isc_device *isc = video_drvdata(file); - struct v4l2_subdev *sd = isc->current_subdev->sd; - bool fh_singular; - int ret; - - mutex_lock(&isc->lock); - - fh_singular = v4l2_fh_is_singular_file(file); - - ret = _vb2_fop_release(file, NULL); - - if (fh_singular) - v4l2_subdev_call(sd, core, s_power, 0); - - mutex_unlock(&isc->lock); - - return ret; -} - -static const struct v4l2_file_operations isc_fops = { - .owner = THIS_MODULE, - .open = isc_open, - .release = isc_release, - .unlocked_ioctl = video_ioctl2, - .read = vb2_fop_read, - .mmap = vb2_fop_mmap, - .poll = vb2_fop_poll, -}; - -static irqreturn_t isc_interrupt(int irq, void *dev_id) -{ - struct isc_device *isc = (struct isc_device *)dev_id; - struct regmap *regmap = isc->regmap; - u32 isc_intsr, isc_intmask, pending; - irqreturn_t ret = IRQ_NONE; - - regmap_read(regmap, ISC_INTSR, &isc_intsr); - regmap_read(regmap, ISC_INTMASK, &isc_intmask); - - pending = isc_intsr & isc_intmask; - - if (likely(pending & ISC_INT_DDONE)) { - spin_lock(&isc->dma_queue_lock); - if (isc->cur_frm) { - struct vb2_v4l2_buffer *vbuf = &isc->cur_frm->vb; - struct vb2_buffer *vb = &vbuf->vb2_buf; - - vb->timestamp = ktime_get_ns(); - vbuf->sequence = isc->sequence++; - vb2_buffer_done(vb, VB2_BUF_STATE_DONE); - isc->cur_frm = NULL; - } - - if (!list_empty(&isc->dma_queue) && !isc->stop) { - isc->cur_frm = list_first_entry(&isc->dma_queue, - struct isc_buffer, list); - list_del(&isc->cur_frm->list); - - isc_start_dma(isc); - } - - if (isc->stop) - complete(&isc->comp); - - ret = IRQ_HANDLED; - spin_unlock(&isc->dma_queue_lock); - } - - if (pending & ISC_INT_HISDONE) { - schedule_work(&isc->awb_work); - ret = IRQ_HANDLED; - } - - return ret; -} - -static void isc_hist_count(struct isc_device *isc, u32 *min, u32 *max) -{ - struct regmap *regmap = isc->regmap; - struct isc_ctrls *ctrls = &isc->ctrls; - u32 *hist_count = &ctrls->hist_count[ctrls->hist_id]; - u32 *hist_entry = &ctrls->hist_entry[0]; - u32 i; - - *min = 0; - *max = HIST_ENTRIES; - - regmap_bulk_read(regmap, ISC_HIS_ENTRY, hist_entry, HIST_ENTRIES); - - *hist_count = 0; - /* - * we deliberately ignore the end of the histogram, - * the most white pixels - */ - for (i = 1; i < HIST_ENTRIES; i++) { - if (*hist_entry && !*min) - *min = i; - if (*hist_entry) - *max = i; - *hist_count += i * (*hist_entry++); - } - - if (!*min) - *min = 1; -} - -static void isc_wb_update(struct isc_ctrls *ctrls) -{ - u32 *hist_count = &ctrls->hist_count[0]; - u32 c, offset[4]; - u64 avg = 0; - /* We compute two gains, stretch gain and grey world gain */ - u32 s_gain[4], gw_gain[4]; - - /* - * According to Grey World, we need to set gains for R/B to normalize - * them towards the green channel. - * Thus we want to keep Green as fixed and adjust only Red/Blue - * Compute the average of the both green channels first - */ - avg = (u64)hist_count[ISC_HIS_CFG_MODE_GR] + - (u64)hist_count[ISC_HIS_CFG_MODE_GB]; - avg >>= 1; - - /* Green histogram is null, nothing to do */ - if (!avg) - return; - - for (c = ISC_HIS_CFG_MODE_GR; c <= ISC_HIS_CFG_MODE_B; c++) { - /* - * the color offset is the minimum value of the histogram. - * we stretch this color to the full range by substracting - * this value from the color component. - */ - offset[c] = ctrls->hist_minmax[c][HIST_MIN_INDEX]; - /* - * The offset is always at least 1. If the offset is 1, we do - * not need to adjust it, so our result must be zero. - * the offset is computed in a histogram on 9 bits (0..512) - * but the offset in register is based on - * 12 bits pipeline (0..4096). - * we need to shift with the 3 bits that the histogram is - * ignoring - */ - ctrls->offset[c] = (offset[c] - 1) << 3; - - /* the offset is then taken and converted to 2's complements */ - if (!ctrls->offset[c]) - ctrls->offset[c] = ISC_WB_O_ZERO_VAL; - - /* - * the stretch gain is the total number of histogram bins - * divided by the actual range of color component (Max - Min) - * If we compute gain like this, the actual color component - * will be stretched to the full histogram. - * We need to shift 9 bits for precision, we have 9 bits for - * decimals - */ - s_gain[c] = (HIST_ENTRIES << 9) / - (ctrls->hist_minmax[c][HIST_MAX_INDEX] - - ctrls->hist_minmax[c][HIST_MIN_INDEX] + 1); - - /* - * Now we have to compute the gain w.r.t. the average. - * Add/lose gain to the component towards the average. - * If it happens that the component is zero, use the - * fixed point value : 1.0 gain. - */ - if (hist_count[c]) - gw_gain[c] = div_u64(avg << 9, hist_count[c]); - else - gw_gain[c] = 1 << 9; - - /* multiply both gains and adjust for decimals */ - ctrls->gain[c] = s_gain[c] * gw_gain[c]; - ctrls->gain[c] >>= 9; - } -} - -static void isc_awb_work(struct work_struct *w) -{ - struct isc_device *isc = - container_of(w, struct isc_device, awb_work); - struct regmap *regmap = isc->regmap; - struct isc_ctrls *ctrls = &isc->ctrls; - u32 hist_id = ctrls->hist_id; - u32 baysel; - unsigned long flags; - u32 min, max; - - /* streaming is not active anymore */ - if (isc->stop) - return; - - if (ctrls->hist_stat != HIST_ENABLED) - return; - - isc_hist_count(isc, &min, &max); - ctrls->hist_minmax[hist_id][HIST_MIN_INDEX] = min; - ctrls->hist_minmax[hist_id][HIST_MAX_INDEX] = max; - - if (hist_id != ISC_HIS_CFG_MODE_B) { - hist_id++; - } else { - isc_wb_update(ctrls); - hist_id = ISC_HIS_CFG_MODE_GR; - } - - ctrls->hist_id = hist_id; - baysel = isc->config.sd_format->cfa_baycfg << ISC_HIS_CFG_BAYSEL_SHIFT; - - /* if no more auto white balance, reset controls. */ - if (ctrls->awb == ISC_WB_NONE) - isc_reset_awb_ctrls(isc); - - pm_runtime_get_sync(isc->dev); - - /* - * only update if we have all the required histograms and controls - * if awb has been disabled, we need to reset registers as well. - */ - if (hist_id == ISC_HIS_CFG_MODE_GR || ctrls->awb == ISC_WB_NONE) { - /* - * It may happen that DMA Done IRQ will trigger while we are - * updating white balance registers here. - * In that case, only parts of the controls have been updated. - * We can avoid that by locking the section. - */ - spin_lock_irqsave(&isc->awb_lock, flags); - isc_update_awb_ctrls(isc); - spin_unlock_irqrestore(&isc->awb_lock, flags); - - /* - * if we are doing just the one time white balance adjustment, - * we are basically done. - */ - if (ctrls->awb == ISC_WB_ONETIME) { - v4l2_info(&isc->v4l2_dev, - "Completed one time white-balance adjustment.\n"); - ctrls->awb = ISC_WB_NONE; - } - } - regmap_write(regmap, ISC_HIS_CFG, hist_id | baysel | ISC_HIS_CFG_RAR); - isc_update_profile(isc); - /* if awb has been disabled, we don't need to start another histogram */ - if (ctrls->awb) - regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_HISREQ); - - pm_runtime_put_sync(isc->dev); -} - -static int isc_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct isc_device *isc = container_of(ctrl->handler, - struct isc_device, ctrls.handler); - struct isc_ctrls *ctrls = &isc->ctrls; - - if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE) - return 0; - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - ctrls->brightness = ctrl->val & ISC_CBC_BRIGHT_MASK; - break; - case V4L2_CID_CONTRAST: - ctrls->contrast = ctrl->val & ISC_CBC_CONTRAST_MASK; - break; - case V4L2_CID_GAMMA: - ctrls->gamma_index = ctrl->val; - break; - case V4L2_CID_AUTO_WHITE_BALANCE: - if (ctrl->val == 1) - ctrls->awb = ISC_WB_AUTO; - else - ctrls->awb = ISC_WB_NONE; - - /* we did not configure ISC yet */ - if (!isc->config.sd_format) - break; - - if (ctrls->hist_stat != HIST_ENABLED) - isc_reset_awb_ctrls(isc); - - if (isc->ctrls.awb == ISC_WB_AUTO && - vb2_is_streaming(&isc->vb2_vidq) && - ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code)) - isc_set_histogram(isc, true); - - break; - case V4L2_CID_DO_WHITE_BALANCE: - /* if AWB is enabled, do nothing */ - if (ctrls->awb == ISC_WB_AUTO) - return 0; - - ctrls->awb = ISC_WB_ONETIME; - isc_set_histogram(isc, true); - v4l2_dbg(1, debug, &isc->v4l2_dev, - "One time white-balance started.\n"); - break; - default: - return -EINVAL; - } - - return 0; -} - -static const struct v4l2_ctrl_ops isc_ctrl_ops = { - .s_ctrl = isc_s_ctrl, -}; - -static int isc_ctrl_init(struct isc_device *isc) -{ - const struct v4l2_ctrl_ops *ops = &isc_ctrl_ops; - struct isc_ctrls *ctrls = &isc->ctrls; - struct v4l2_ctrl_handler *hdl = &ctrls->handler; - int ret; - - ctrls->hist_stat = HIST_INIT; - isc_reset_awb_ctrls(isc); - - ret = v4l2_ctrl_handler_init(hdl, 5); - if (ret < 0) - return ret; - - ctrls->brightness = 0; - ctrls->contrast = 256; - - v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, -1024, 1023, 1, 0); - v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -2048, 2047, 1, 256); - v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAMMA, 0, GAMMA_MAX, 1, 2); - v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1); - - /* do_white_balance is a button, so min,max,step,default are ignored */ - isc->do_wb_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_DO_WHITE_BALANCE, - 0, 0, 0, 0); - - v4l2_ctrl_activate(isc->do_wb_ctrl, false); - - v4l2_ctrl_handler_setup(hdl); - - return 0; -} - -static int isc_async_bound(struct v4l2_async_notifier *notifier, - struct v4l2_subdev *subdev, - struct v4l2_async_subdev *asd) -{ - struct isc_device *isc = container_of(notifier->v4l2_dev, - struct isc_device, v4l2_dev); - struct isc_subdev_entity *subdev_entity = - container_of(notifier, struct isc_subdev_entity, notifier); - - if (video_is_registered(&isc->video_dev)) { - v4l2_err(&isc->v4l2_dev, "only supports one sub-device.\n"); - return -EBUSY; - } - - subdev_entity->sd = subdev; - - return 0; -} - -static void isc_async_unbind(struct v4l2_async_notifier *notifier, - struct v4l2_subdev *subdev, - struct v4l2_async_subdev *asd) -{ - struct isc_device *isc = container_of(notifier->v4l2_dev, - struct isc_device, v4l2_dev); - cancel_work_sync(&isc->awb_work); - video_unregister_device(&isc->video_dev); - v4l2_ctrl_handler_free(&isc->ctrls.handler); -} - -static struct isc_format *find_format_by_code(unsigned int code, int *index) -{ - struct isc_format *fmt = &formats_list[0]; - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(formats_list); i++) { - if (fmt->mbus_code == code) { - *index = i; - return fmt; - } - - fmt++; - } - - return NULL; -} - -static int isc_formats_init(struct isc_device *isc) -{ - struct isc_format *fmt; - struct v4l2_subdev *subdev = isc->current_subdev->sd; - unsigned int num_fmts, i, j; - u32 list_size = ARRAY_SIZE(formats_list); - struct v4l2_subdev_mbus_code_enum mbus_code = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - }; - - num_fmts = 0; - while (!v4l2_subdev_call(subdev, pad, enum_mbus_code, - NULL, &mbus_code)) { - mbus_code.index++; - - fmt = find_format_by_code(mbus_code.code, &i); - if (!fmt) { - v4l2_warn(&isc->v4l2_dev, "Mbus code %x not supported\n", - mbus_code.code); - continue; - } - - fmt->sd_support = true; - num_fmts++; - } - - if (!num_fmts) - return -ENXIO; - - isc->num_user_formats = num_fmts; - isc->user_formats = devm_kcalloc(isc->dev, - num_fmts, sizeof(*isc->user_formats), - GFP_KERNEL); - if (!isc->user_formats) - return -ENOMEM; - - fmt = &formats_list[0]; - for (i = 0, j = 0; i < list_size; i++) { - if (fmt->sd_support) - isc->user_formats[j++] = fmt; - fmt++; - } - - return 0; -} - -static int isc_set_default_fmt(struct isc_device *isc) -{ - struct v4l2_format f = { - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, - .fmt.pix = { - .width = VGA_WIDTH, - .height = VGA_HEIGHT, - .field = V4L2_FIELD_NONE, - .pixelformat = isc->user_formats[0]->fourcc, - }, - }; - int ret; - - ret = isc_try_fmt(isc, &f, NULL); - if (ret) - return ret; - - isc->fmt = f; - return 0; -} - -static int isc_async_complete(struct v4l2_async_notifier *notifier) -{ - struct isc_device *isc = container_of(notifier->v4l2_dev, - struct isc_device, v4l2_dev); - struct video_device *vdev = &isc->video_dev; - struct vb2_queue *q = &isc->vb2_vidq; - int ret; - - INIT_WORK(&isc->awb_work, isc_awb_work); - - ret = v4l2_device_register_subdev_nodes(&isc->v4l2_dev); - if (ret < 0) { - v4l2_err(&isc->v4l2_dev, "Failed to register subdev nodes\n"); - return ret; - } - - isc->current_subdev = container_of(notifier, - struct isc_subdev_entity, notifier); - mutex_init(&isc->lock); - init_completion(&isc->comp); - - /* Initialize videobuf2 queue */ - q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ; - q->drv_priv = isc; - q->buf_struct_size = sizeof(struct isc_buffer); - q->ops = &isc_vb2_ops; - q->mem_ops = &vb2_dma_contig_memops; - q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - q->lock = &isc->lock; - q->min_buffers_needed = 1; - q->dev = isc->dev; - - ret = vb2_queue_init(q); - if (ret < 0) { - v4l2_err(&isc->v4l2_dev, - "vb2_queue_init() failed: %d\n", ret); - return ret; - } - - /* Init video dma queues */ - INIT_LIST_HEAD(&isc->dma_queue); - spin_lock_init(&isc->dma_queue_lock); - spin_lock_init(&isc->awb_lock); - - ret = isc_formats_init(isc); - if (ret < 0) { - v4l2_err(&isc->v4l2_dev, - "Init format failed: %d\n", ret); - return ret; - } - - ret = isc_set_default_fmt(isc); - if (ret) { - v4l2_err(&isc->v4l2_dev, "Could not set default format\n"); - return ret; - } - - ret = isc_ctrl_init(isc); - if (ret) { - v4l2_err(&isc->v4l2_dev, "Init isc ctrols failed: %d\n", ret); - return ret; - } - - /* Register video device */ - strscpy(vdev->name, ATMEL_ISC_NAME, sizeof(vdev->name)); - vdev->release = video_device_release_empty; - vdev->fops = &isc_fops; - vdev->ioctl_ops = &isc_ioctl_ops; - vdev->v4l2_dev = &isc->v4l2_dev; - vdev->vfl_dir = VFL_DIR_RX; - vdev->queue = q; - vdev->lock = &isc->lock; - vdev->ctrl_handler = &isc->ctrls.handler; - vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE; - video_set_drvdata(vdev, isc); - - ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); - if (ret < 0) { - v4l2_err(&isc->v4l2_dev, - "video_register_device failed: %d\n", ret); - return ret; - } - - return 0; -} - -static const struct v4l2_async_notifier_operations isc_async_ops = { - .bound = isc_async_bound, - .unbind = isc_async_unbind, - .complete = isc_async_complete, -}; - -static void isc_subdev_cleanup(struct isc_device *isc) -{ - struct isc_subdev_entity *subdev_entity; - - list_for_each_entry(subdev_entity, &isc->subdev_entities, list) { - v4l2_async_notifier_unregister(&subdev_entity->notifier); - v4l2_async_notifier_cleanup(&subdev_entity->notifier); - } - - INIT_LIST_HEAD(&isc->subdev_entities); -} - -static int isc_pipeline_init(struct isc_device *isc) -{ - struct device *dev = isc->dev; - struct regmap *regmap = isc->regmap; - struct regmap_field *regs; - unsigned int i; - - /* WB-->CFA-->CC-->GAM-->CSC-->CBC-->SUB422-->SUB420 */ - const struct reg_field regfields[ISC_PIPE_LINE_NODE_NUM] = { - REG_FIELD(ISC_WB_CTRL, 0, 0), - REG_FIELD(ISC_CFA_CTRL, 0, 0), - REG_FIELD(ISC_CC_CTRL, 0, 0), - REG_FIELD(ISC_GAM_CTRL, 0, 0), - REG_FIELD(ISC_GAM_CTRL, 1, 1), - REG_FIELD(ISC_GAM_CTRL, 2, 2), - REG_FIELD(ISC_GAM_CTRL, 3, 3), - REG_FIELD(ISC_CSC_CTRL, 0, 0), - REG_FIELD(ISC_CBC_CTRL, 0, 0), - REG_FIELD(ISC_SUB422_CTRL, 0, 0), - REG_FIELD(ISC_SUB420_CTRL, 0, 0), - }; - - for (i = 0; i < ISC_PIPE_LINE_NODE_NUM; i++) { - regs = devm_regmap_field_alloc(dev, regmap, regfields[i]); - if (IS_ERR(regs)) - return PTR_ERR(regs); - - isc->pipeline[i] = regs; - } - - return 0; -} - -static int isc_parse_dt(struct device *dev, struct isc_device *isc) -{ - struct device_node *np = dev->of_node; - struct device_node *epn = NULL, *rem; - struct isc_subdev_entity *subdev_entity; - unsigned int flags; - int ret; - - INIT_LIST_HEAD(&isc->subdev_entities); - - while (1) { - struct v4l2_fwnode_endpoint v4l2_epn = { .bus_type = 0 }; - - epn = of_graph_get_next_endpoint(np, epn); - if (!epn) - return 0; - - rem = of_graph_get_remote_port_parent(epn); - if (!rem) { - dev_notice(dev, "Remote device at %pOF not found\n", - epn); - continue; - } - - ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(epn), - &v4l2_epn); - if (ret) { - of_node_put(rem); - ret = -EINVAL; - dev_err(dev, "Could not parse the endpoint\n"); - break; - } - - subdev_entity = devm_kzalloc(dev, - sizeof(*subdev_entity), GFP_KERNEL); - if (!subdev_entity) { - of_node_put(rem); - ret = -ENOMEM; - break; - } - - /* asd will be freed by the subsystem once it's added to the - * notifier list - */ - subdev_entity->asd = kzalloc(sizeof(*subdev_entity->asd), - GFP_KERNEL); - if (!subdev_entity->asd) { - of_node_put(rem); - ret = -ENOMEM; - break; - } - - flags = v4l2_epn.bus.parallel.flags; - - if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) - subdev_entity->pfe_cfg0 = ISC_PFE_CFG0_HPOL_LOW; - - if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) - subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_VPOL_LOW; - - if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) - subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_PPOL_LOW; - - if (v4l2_epn.bus_type == V4L2_MBUS_BT656) - subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_CCIR_CRC | - ISC_PFE_CFG0_CCIR656; - - subdev_entity->asd->match_type = V4L2_ASYNC_MATCH_FWNODE; - subdev_entity->asd->match.fwnode = - of_fwnode_handle(rem); - list_add_tail(&subdev_entity->list, &isc->subdev_entities); - } - - of_node_put(epn); - return ret; -} - -/* regmap configuration */ -#define ATMEL_ISC_REG_MAX 0xbfc -static const struct regmap_config isc_regmap_config = { - .reg_bits = 32, - .reg_stride = 4, - .val_bits = 32, - .max_register = ATMEL_ISC_REG_MAX, -}; - -static int atmel_isc_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct isc_device *isc; - struct resource *res; - void __iomem *io_base; - struct isc_subdev_entity *subdev_entity; - int irq; - int ret; - - isc = devm_kzalloc(dev, sizeof(*isc), GFP_KERNEL); - if (!isc) - return -ENOMEM; - - platform_set_drvdata(pdev, isc); - isc->dev = dev; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - io_base = devm_ioremap_resource(dev, res); - if (IS_ERR(io_base)) - return PTR_ERR(io_base); - - isc->regmap = devm_regmap_init_mmio(dev, io_base, &isc_regmap_config); - if (IS_ERR(isc->regmap)) { - ret = PTR_ERR(isc->regmap); - dev_err(dev, "failed to init register map: %d\n", ret); - return ret; - } - - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - ret = irq; - dev_err(dev, "failed to get irq: %d\n", ret); - return ret; - } - - ret = devm_request_irq(dev, irq, isc_interrupt, 0, - ATMEL_ISC_NAME, isc); - if (ret < 0) { - dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n", - irq, ret); - return ret; - } - - ret = isc_pipeline_init(isc); - if (ret) - return ret; - - isc->hclock = devm_clk_get(dev, "hclock"); - if (IS_ERR(isc->hclock)) { - ret = PTR_ERR(isc->hclock); - dev_err(dev, "failed to get hclock: %d\n", ret); - return ret; - } - - ret = clk_prepare_enable(isc->hclock); - if (ret) { - dev_err(dev, "failed to enable hclock: %d\n", ret); - return ret; - } - - ret = isc_clk_init(isc); - if (ret) { - dev_err(dev, "failed to init isc clock: %d\n", ret); - goto unprepare_hclk; - } - - isc->ispck = isc->isc_clks[ISC_ISPCK].clk; - - ret = clk_prepare_enable(isc->ispck); - if (ret) { - dev_err(dev, "failed to enable ispck: %d\n", ret); - goto unprepare_hclk; - } - - /* ispck should be greater or equal to hclock */ - ret = clk_set_rate(isc->ispck, clk_get_rate(isc->hclock)); - if (ret) { - dev_err(dev, "failed to set ispck rate: %d\n", ret); - goto unprepare_clk; - } - - ret = v4l2_device_register(dev, &isc->v4l2_dev); - if (ret) { - dev_err(dev, "unable to register v4l2 device.\n"); - goto unprepare_clk; - } - - ret = isc_parse_dt(dev, isc); - if (ret) { - dev_err(dev, "fail to parse device tree\n"); - goto unregister_v4l2_device; - } - - if (list_empty(&isc->subdev_entities)) { - dev_err(dev, "no subdev found\n"); - ret = -ENODEV; - goto unregister_v4l2_device; - } - - list_for_each_entry(subdev_entity, &isc->subdev_entities, list) { - v4l2_async_notifier_init(&subdev_entity->notifier); - - ret = v4l2_async_notifier_add_subdev(&subdev_entity->notifier, - subdev_entity->asd); - if (ret) { - fwnode_handle_put(subdev_entity->asd->match.fwnode); - kfree(subdev_entity->asd); - goto cleanup_subdev; - } - - subdev_entity->notifier.ops = &isc_async_ops; - - ret = v4l2_async_notifier_register(&isc->v4l2_dev, - &subdev_entity->notifier); - if (ret) { - dev_err(dev, "fail to register async notifier\n"); - goto cleanup_subdev; - } - - if (video_is_registered(&isc->video_dev)) - break; - } - - pm_runtime_set_active(dev); - pm_runtime_enable(dev); - pm_request_idle(dev); - - return 0; - -cleanup_subdev: - isc_subdev_cleanup(isc); - -unregister_v4l2_device: - v4l2_device_unregister(&isc->v4l2_dev); - -unprepare_clk: - clk_disable_unprepare(isc->ispck); -unprepare_hclk: - clk_disable_unprepare(isc->hclock); - - isc_clk_cleanup(isc); - - return ret; -} - -static int atmel_isc_remove(struct platform_device *pdev) -{ - struct isc_device *isc = platform_get_drvdata(pdev); - - pm_runtime_disable(&pdev->dev); - clk_disable_unprepare(isc->ispck); - clk_disable_unprepare(isc->hclock); - - isc_subdev_cleanup(isc); - - v4l2_device_unregister(&isc->v4l2_dev); - - isc_clk_cleanup(isc); - - return 0; -} - -static int __maybe_unused isc_runtime_suspend(struct device *dev) -{ - struct isc_device *isc = dev_get_drvdata(dev); - - clk_disable_unprepare(isc->ispck); - clk_disable_unprepare(isc->hclock); - - return 0; -} - -static int __maybe_unused isc_runtime_resume(struct device *dev) -{ - struct isc_device *isc = dev_get_drvdata(dev); - int ret; - - ret = clk_prepare_enable(isc->hclock); - if (ret) - return ret; - - return clk_prepare_enable(isc->ispck); -} - -static const struct dev_pm_ops atmel_isc_dev_pm_ops = { - SET_RUNTIME_PM_OPS(isc_runtime_suspend, isc_runtime_resume, NULL) -}; - -static const struct of_device_id atmel_isc_of_match[] = { - { .compatible = "atmel,sama5d2-isc" }, - { } -}; -MODULE_DEVICE_TABLE(of, atmel_isc_of_match); - -static struct platform_driver atmel_isc_driver = { - .probe = atmel_isc_probe, - .remove = atmel_isc_remove, - .driver = { - .name = ATMEL_ISC_NAME, - .pm = &atmel_isc_dev_pm_ops, - .of_match_table = of_match_ptr(atmel_isc_of_match), - }, -}; - -module_platform_driver(atmel_isc_driver); - -MODULE_AUTHOR("Songjun Wu "); -MODULE_DESCRIPTION("The V4L2 driver for Atmel-ISC"); -MODULE_LICENSE("GPL v2"); -MODULE_SUPPORTED_DEVICE("video"); diff --git a/drivers/media/platform/atmel/atmel-isc.h b/drivers/media/platform/atmel/atmel-isc.h new file mode 100644 index 000000000000..5be5b093aefb --- /dev/null +++ b/drivers/media/platform/atmel/atmel-isc.h @@ -0,0 +1,249 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Microchip Image Sensor Controller (ISC) driver header file + * + * Copyright (C) 2016-2019 Microchip Technology, Inc. + * + * Author: Songjun Wu + * Author: Eugen Hristev + * + */ +#ifndef _ATMEL_ISC_H_ + +#define ISC_MAX_SUPPORT_WIDTH 2592 +#define ISC_MAX_SUPPORT_HEIGHT 1944 + +#define ISC_CLK_MAX_DIV 255 + +enum isc_clk_id { + ISC_ISPCK = 0, + ISC_MCK = 1, +}; + +struct isc_clk { + struct clk_hw hw; + struct clk *clk; + struct regmap *regmap; + spinlock_t lock; /* serialize access to clock registers */ + u8 id; + u8 parent_id; + u32 div; + struct device *dev; +}; + +#define to_isc_clk(v) container_of(v, struct isc_clk, hw) + +struct isc_buffer { + struct vb2_v4l2_buffer vb; + struct list_head list; +}; + +struct isc_subdev_entity { + struct v4l2_subdev *sd; + struct v4l2_async_subdev *asd; + struct v4l2_async_notifier notifier; + + u32 pfe_cfg0; + + struct list_head list; +}; + +/* + * struct isc_format - ISC media bus format information + This structure represents the interface between the ISC + and the sensor. It's the input format received by + the ISC. + * @fourcc: Fourcc code for this format + * @mbus_code: V4L2 media bus format code. + * @cfa_baycfg: If this format is RAW BAYER, indicate the type of bayer. + this is either BGBG, RGRG, etc. + * @pfe_cfg0_bps: Number of hardware data lines connected to the ISC + */ + +struct isc_format { + u32 fourcc; + u32 mbus_code; + u32 cfa_baycfg; + + bool sd_support; + u32 pfe_cfg0_bps; +}; + +/* Pipeline bitmap */ +#define WB_ENABLE BIT(0) +#define CFA_ENABLE BIT(1) +#define CC_ENABLE BIT(2) +#define GAM_ENABLE BIT(3) +#define GAM_BENABLE BIT(4) +#define GAM_GENABLE BIT(5) +#define GAM_RENABLE BIT(6) +#define CSC_ENABLE BIT(7) +#define CBC_ENABLE BIT(8) +#define SUB422_ENABLE BIT(9) +#define SUB420_ENABLE BIT(10) + +#define GAM_ENABLES (GAM_RENABLE | GAM_GENABLE | GAM_BENABLE | GAM_ENABLE) + +/* + * struct fmt_config - ISC format configuration and internal pipeline + This structure represents the internal configuration + of the ISC. + It also holds the format that ISC will present to v4l2. + * @sd_format: Pointer to an isc_format struct that holds the sensor + configuration. + * @fourcc: Fourcc code for this format. + * @bpp: Bytes per pixel in the current format. + * @rlp_cfg_mode: Configuration of the RLP (rounding, limiting packaging) + * @dcfg_imode: Configuration of the input of the DMA module + * @dctrl_dview: Configuration of the output of the DMA module + * @bits_pipeline: Configuration of the pipeline, which modules are enabled + */ +struct fmt_config { + struct isc_format *sd_format; + + u32 fourcc; + u8 bpp; + + u32 rlp_cfg_mode; + u32 dcfg_imode; + u32 dctrl_dview; + + u32 bits_pipeline; +}; + +#define HIST_ENTRIES 512 +#define HIST_BAYER (ISC_HIS_CFG_MODE_B + 1) + +enum{ + HIST_INIT = 0, + HIST_ENABLED, + HIST_DISABLED, +}; + +struct isc_ctrls { + struct v4l2_ctrl_handler handler; + + u32 brightness; + u32 contrast; + u8 gamma_index; +#define ISC_WB_NONE 0 +#define ISC_WB_AUTO 1 +#define ISC_WB_ONETIME 2 + u8 awb; + + /* one for each component : GR, R, GB, B */ + u32 gain[HIST_BAYER]; + u32 offset[HIST_BAYER]; + + u32 hist_entry[HIST_ENTRIES]; + u32 hist_count[HIST_BAYER]; + u8 hist_id; + u8 hist_stat; +#define HIST_MIN_INDEX 0 +#define HIST_MAX_INDEX 1 + u32 hist_minmax[HIST_BAYER][2]; +}; + +#define ISC_PIPE_LINE_NODE_NUM 11 + +/* + * struct isc_device - ISC device driver data/config struct + * @regmap: Register map + * @hclock: Hclock clock input (refer datasheet) + * @ispck: iscpck clock (refer datasheet) + * @isc_clks: ISC clocks + * + * @dev: Registered device driver + * @v4l2_dev: v4l2 registered device + * @video_dev: registered video device + * + * @vb2_vidq: video buffer 2 video queue + * @dma_queue_lock: lock to serialize the dma buffer queue + * @dma_queue: the queue for dma buffers + * @cur_frm: current isc frame/buffer + * @sequence: current frame number + * @stop: true if isc is not streaming, false if streaming + * @comp: completion reference that signals frame completion + * + * @fmt: current v42l format + * @user_formats: list of formats that are supported and agreed with sd + * @num_user_formats: how many formats are in user_formats + * + * @config: current ISC format configuration + * @try_config: the current ISC try format , not yet activated + * + * @ctrls: holds information about ISC controls + * @do_wb_ctrl: control regarding the DO_WHITE_BALANCE button + * @awb_work: workqueue reference for autowhitebalance histogram + * analysis + * + * @lock: lock for serializing userspace file operations + * with ISC operations + * @awb_lock: lock for serializing awb work queue operations + * with DMA/buffer operations + * + * @pipeline: configuration of the ISC pipeline + * + * @current_subdev: current subdevice: the sensor + * @subdev_entities: list of subdevice entitites + */ +struct isc_device { + struct regmap *regmap; + struct clk *hclock; + struct clk *ispck; + struct isc_clk isc_clks[2]; + + struct device *dev; + struct v4l2_device v4l2_dev; + struct video_device video_dev; + + struct vb2_queue vb2_vidq; + spinlock_t dma_queue_lock; /* serialize access to dma queue */ + struct list_head dma_queue; + struct isc_buffer *cur_frm; + unsigned int sequence; + bool stop; + struct completion comp; + + struct v4l2_format fmt; + struct isc_format **user_formats; + unsigned int num_user_formats; + + struct fmt_config config; + struct fmt_config try_config; + + struct isc_ctrls ctrls; + struct v4l2_ctrl *do_wb_ctrl; + struct work_struct awb_work; + + struct mutex lock; /* serialize access to file operations */ + spinlock_t awb_lock; /* serialize access to DMA buffers from awb work queue */ + + struct regmap_field *pipeline[ISC_PIPE_LINE_NODE_NUM]; + + struct isc_subdev_entity *current_subdev; + struct list_head subdev_entities; +}; + +#define GAMMA_MAX 2 +#define GAMMA_ENTRIES 64 + +#define ATMEL_ISC_NAME "atmel-isc" + +/* module parameters */ +extern unsigned int debug; +extern unsigned int sensor_preferred; + +extern struct isc_format formats_list[]; +extern struct isc_format controller_formats[]; +extern const u32 isc_gamma_table[GAMMA_MAX + 1][GAMMA_ENTRIES]; +extern const struct regmap_config isc_regmap_config; +extern const struct v4l2_async_notifier_operations isc_async_ops; + +irqreturn_t isc_interrupt(int irq, void *dev_id); +int isc_pipeline_init(struct isc_device *isc); +int isc_clk_init(struct isc_device *isc); +void isc_subdev_cleanup(struct isc_device *isc); +void isc_clk_cleanup(struct isc_device *isc); + +#endif diff --git a/drivers/media/platform/atmel/atmel-sama5d2-isc.c b/drivers/media/platform/atmel/atmel-sama5d2-isc.c new file mode 100644 index 000000000000..127e79c8f84a --- /dev/null +++ b/drivers/media/platform/atmel/atmel-sama5d2-isc.c @@ -0,0 +1,344 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Microchip Image Sensor Controller (ISC) driver + * + * Copyright (C) 2016-2019 Microchip Technology, Inc. + * + * Author: Songjun Wu + * Author: Eugen Hristev + * + * + * Sensor-->PFE-->WB-->CFA-->CC-->GAM-->CSC-->CBC-->SUB-->RLP-->DMA + * + * ISC video pipeline integrates the following submodules: + * PFE: Parallel Front End to sample the camera sensor input stream + * WB: Programmable white balance in the Bayer domain + * CFA: Color filter array interpolation module + * CC: Programmable color correction + * GAM: Gamma correction + * CSC: Programmable color space conversion + * CBC: Contrast and Brightness control + * SUB: This module performs YCbCr444 to YCbCr420 chrominance subsampling + * RLP: This module performs rounding, range limiting + * and packing of the incoming data + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "atmel-isc-regs.h" +#include "atmel-isc.h" + +#define ISC_MAX_SUPPORT_WIDTH 2592 +#define ISC_MAX_SUPPORT_HEIGHT 1944 + +#define ISC_CLK_MAX_DIV 255 + +static int isc_parse_dt(struct device *dev, struct isc_device *isc) +{ + struct device_node *np = dev->of_node; + struct device_node *epn = NULL, *rem; + struct isc_subdev_entity *subdev_entity; + unsigned int flags; + int ret; + + INIT_LIST_HEAD(&isc->subdev_entities); + + while (1) { + struct v4l2_fwnode_endpoint v4l2_epn = { .bus_type = 0 }; + + epn = of_graph_get_next_endpoint(np, epn); + if (!epn) + return 0; + + rem = of_graph_get_remote_port_parent(epn); + if (!rem) { + dev_notice(dev, "Remote device at %pOF not found\n", + epn); + continue; + } + + ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(epn), + &v4l2_epn); + if (ret) { + of_node_put(rem); + ret = -EINVAL; + dev_err(dev, "Could not parse the endpoint\n"); + break; + } + + subdev_entity = devm_kzalloc(dev, sizeof(*subdev_entity), + GFP_KERNEL); + if (!subdev_entity) { + of_node_put(rem); + ret = -ENOMEM; + break; + } + + /* asd will be freed by the subsystem once it's added to the + * notifier list + */ + subdev_entity->asd = kzalloc(sizeof(*subdev_entity->asd), + GFP_KERNEL); + if (!subdev_entity->asd) { + of_node_put(rem); + ret = -ENOMEM; + break; + } + + flags = v4l2_epn.bus.parallel.flags; + + if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) + subdev_entity->pfe_cfg0 = ISC_PFE_CFG0_HPOL_LOW; + + if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) + subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_VPOL_LOW; + + if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) + subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_PPOL_LOW; + + if (v4l2_epn.bus_type == V4L2_MBUS_BT656) + subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_CCIR_CRC | + ISC_PFE_CFG0_CCIR656; + + subdev_entity->asd->match_type = V4L2_ASYNC_MATCH_FWNODE; + subdev_entity->asd->match.fwnode = + of_fwnode_handle(rem); + list_add_tail(&subdev_entity->list, &isc->subdev_entities); + } + + of_node_put(epn); + return ret; +} + +static int atmel_isc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct isc_device *isc; + struct resource *res; + void __iomem *io_base; + struct isc_subdev_entity *subdev_entity; + int irq; + int ret; + + isc = devm_kzalloc(dev, sizeof(*isc), GFP_KERNEL); + if (!isc) + return -ENOMEM; + + platform_set_drvdata(pdev, isc); + isc->dev = dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + io_base = devm_ioremap_resource(dev, res); + if (IS_ERR(io_base)) + return PTR_ERR(io_base); + + isc->regmap = devm_regmap_init_mmio(dev, io_base, &isc_regmap_config); + if (IS_ERR(isc->regmap)) { + ret = PTR_ERR(isc->regmap); + dev_err(dev, "failed to init register map: %d\n", ret); + return ret; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + ret = irq; + dev_err(dev, "failed to get irq: %d\n", ret); + return ret; + } + + ret = devm_request_irq(dev, irq, isc_interrupt, 0, + ATMEL_ISC_NAME, isc); + if (ret < 0) { + dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n", + irq, ret); + return ret; + } + + ret = isc_pipeline_init(isc); + if (ret) + return ret; + + isc->hclock = devm_clk_get(dev, "hclock"); + if (IS_ERR(isc->hclock)) { + ret = PTR_ERR(isc->hclock); + dev_err(dev, "failed to get hclock: %d\n", ret); + return ret; + } + + ret = clk_prepare_enable(isc->hclock); + if (ret) { + dev_err(dev, "failed to enable hclock: %d\n", ret); + return ret; + } + + ret = isc_clk_init(isc); + if (ret) { + dev_err(dev, "failed to init isc clock: %d\n", ret); + goto unprepare_hclk; + } + + isc->ispck = isc->isc_clks[ISC_ISPCK].clk; + + ret = clk_prepare_enable(isc->ispck); + if (ret) { + dev_err(dev, "failed to enable ispck: %d\n", ret); + goto unprepare_hclk; + } + + /* ispck should be greater or equal to hclock */ + ret = clk_set_rate(isc->ispck, clk_get_rate(isc->hclock)); + if (ret) { + dev_err(dev, "failed to set ispck rate: %d\n", ret); + goto unprepare_clk; + } + + ret = v4l2_device_register(dev, &isc->v4l2_dev); + if (ret) { + dev_err(dev, "unable to register v4l2 device.\n"); + goto unprepare_clk; + } + + ret = isc_parse_dt(dev, isc); + if (ret) { + dev_err(dev, "fail to parse device tree\n"); + goto unregister_v4l2_device; + } + + if (list_empty(&isc->subdev_entities)) { + dev_err(dev, "no subdev found\n"); + ret = -ENODEV; + goto unregister_v4l2_device; + } + + list_for_each_entry(subdev_entity, &isc->subdev_entities, list) { + v4l2_async_notifier_init(&subdev_entity->notifier); + + ret = v4l2_async_notifier_add_subdev(&subdev_entity->notifier, + subdev_entity->asd); + if (ret) { + fwnode_handle_put(subdev_entity->asd->match.fwnode); + kfree(subdev_entity->asd); + goto cleanup_subdev; + } + + subdev_entity->notifier.ops = &isc_async_ops; + + ret = v4l2_async_notifier_register(&isc->v4l2_dev, + &subdev_entity->notifier); + if (ret) { + dev_err(dev, "fail to register async notifier\n"); + goto cleanup_subdev; + } + + if (video_is_registered(&isc->video_dev)) + break; + } + + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + pm_request_idle(dev); + + return 0; + +cleanup_subdev: + isc_subdev_cleanup(isc); + +unregister_v4l2_device: + v4l2_device_unregister(&isc->v4l2_dev); + +unprepare_clk: + clk_disable_unprepare(isc->ispck); +unprepare_hclk: + clk_disable_unprepare(isc->hclock); + + isc_clk_cleanup(isc); + + return ret; +} + +static int atmel_isc_remove(struct platform_device *pdev) +{ + struct isc_device *isc = platform_get_drvdata(pdev); + + pm_runtime_disable(&pdev->dev); + clk_disable_unprepare(isc->ispck); + clk_disable_unprepare(isc->hclock); + + isc_subdev_cleanup(isc); + + v4l2_device_unregister(&isc->v4l2_dev); + + isc_clk_cleanup(isc); + + return 0; +} + +static int __maybe_unused isc_runtime_suspend(struct device *dev) +{ + struct isc_device *isc = dev_get_drvdata(dev); + + clk_disable_unprepare(isc->ispck); + clk_disable_unprepare(isc->hclock); + + return 0; +} + +static int __maybe_unused isc_runtime_resume(struct device *dev) +{ + struct isc_device *isc = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(isc->hclock); + if (ret) + return ret; + + return clk_prepare_enable(isc->ispck); +} + +static const struct dev_pm_ops atmel_isc_dev_pm_ops = { + SET_RUNTIME_PM_OPS(isc_runtime_suspend, isc_runtime_resume, NULL) +}; + +static const struct of_device_id atmel_isc_of_match[] = { + { .compatible = "atmel,sama5d2-isc" }, + { } +}; +MODULE_DEVICE_TABLE(of, atmel_isc_of_match); + +static struct platform_driver atmel_isc_driver = { + .probe = atmel_isc_probe, + .remove = atmel_isc_remove, + .driver = { + .name = ATMEL_ISC_NAME, + .pm = &atmel_isc_dev_pm_ops, + .of_match_table = of_match_ptr(atmel_isc_of_match), + }, +}; + +module_platform_driver(atmel_isc_driver); + +MODULE_AUTHOR("Songjun Wu"); +MODULE_DESCRIPTION("The V4L2 driver for Atmel-ISC"); +MODULE_LICENSE("GPL v2"); +MODULE_SUPPORTED_DEVICE("video"); -- cgit v1.2.3 From fc47bf1147ecf55fe51181723dd52cbad53dd02b Mon Sep 17 00:00:00 2001 From: Maxime Jourdan Date: Thu, 13 Jun 2019 05:51:02 -0400 Subject: media: MAINTAINERS: fix linux-media mailing list for meson drivers Both MESON AO CEC and MESON VIDEO DECODER point to the wrong linux-media mailing list. Update it to linux-media@vger.kernel.org. Signed-off-by: Maxime Jourdan Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'MAINTAINERS') diff --git a/MAINTAINERS b/MAINTAINERS index bf32079578fb..065b4016e888 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10219,7 +10219,7 @@ F: drivers/watchdog/menz69_wdt.c MESON AO CEC DRIVER FOR AMLOGIC SOCS M: Neil Armstrong -L: linux-media@lists.freedesktop.org +L: linux-media@vger.kernel.org L: linux-amlogic@lists.infradead.org W: http://linux-meson.com/ S: Supported @@ -10237,7 +10237,7 @@ F: Documentation/devicetree/bindings/mtd/amlogic,meson-nand.txt MESON VIDEO DECODER DRIVER FOR AMLOGIC SOCS M: Maxime Jourdan -L: linux-media@lists.freedesktop.org +L: linux-media@vger.kernel.org L: linux-amlogic@lists.infradead.org S: Supported F: drivers/staging/media/meson/vdec/ -- cgit v1.2.3 From 86d617d6c79d79288ca608b6fb0a2467b0e8ddbb Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 20 Jun 2019 10:17:53 -0400 Subject: media: MAINTAINERS: Add maintainers for Media Controller When Media Controller was merged to mainline long, long time ago, no-one bothered to think what its MAINTAINERS entry should be. Now that Media Controller is moved into its own directory, address this at the same time. So tell people to mail patches to myself and Laurent Pinchart. Note that the patches are still merged through the Media tree, just like any other driver or framework bits that have separate "mail patches to" entries different from the main drivers/media one. Signed-off-by: Sakari Ailus Signed-off-by: Laurent Pinchart Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'MAINTAINERS') diff --git a/MAINTAINERS b/MAINTAINERS index 065b4016e888..866969b36a13 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9643,6 +9643,17 @@ L: linux-iio@vger.kernel.org S: Maintained F: drivers/iio/dac/cio-dac.c +MEDIA CONTROLLER FRAMEWORK +M: Sakari Ailus +M: Laurent Pinchart +L: linux-media@vger.kernel.org +W: https://www.linuxtv.org +T: git git://linuxtv.org/media_tree.git +S: Supported +F: drivers/media/mc/ +F: include/media/media-*.h +F: include/uapi/linux/media.h + MEDIA DRIVERS FOR ASCOT2E M: Sergey Kozlov M: Abylay Ospan -- cgit v1.2.3