diff --git a/Documentation/devicetree/bindings/media/raspberrypi,hevc-dec.yaml b/Documentation/devicetree/bindings/media/raspberrypi,hevc-dec.yaml new file mode 100644 index 00000000000000..b86534f2689f0e --- /dev/null +++ b/Documentation/devicetree/bindings/media/raspberrypi,hevc-dec.yaml @@ -0,0 +1,70 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/raspberrypi,hevc-dec.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Raspberry Pi HEVC Decoder + +maintainers: + - John Cox + - Dom Cobley + - Dave Stevenson + - Raspberry Pi internal review list + +description: + The Raspberry Pi HEVC decoder is a hardware video decode accelerator block + found in the BCM2711 and BCM2712 processors used on Raspberry Pi 4 and 5 + boards respectively. + +properties: + compatible: + items: + - enum: + - brcm,bcm2711-hevc-dec + - brcm,bcm2712-hevc-dec + - const: raspberrypi,hevc-dec + + reg: + items: + - description: The HEVC main register region + - description: The Interrupt control register region + + reg-names: + items: + - const: hevc + - const: intc + + interrupts: + maxItems: 1 + + clocks: + items: + - description: The HEVC block clock + +required: + - compatible + - reg + - reg-names + - interrupts + - clocks + +additionalProperties: false + +examples: + - | + #include + + video-codec@7eb10000 { + compatible = "brcm,bcm2711-hevc-dec", "raspberrypi,hevc-dec"; + reg = <0x7eb00000 0x10000>, /* HEVC */ + <0x7eb10000 0x1000>; /* INTC */ + reg-names = "hevc", + "intc"; + + interrupts = ; + + clocks = <&clk 0>; + }; + +... diff --git a/Documentation/userspace-api/media/v4l/pixfmt-nv12-col128.rst b/Documentation/userspace-api/media/v4l/pixfmt-nv12-col128.rst deleted file mode 100644 index 196ca33a5dff85..00000000000000 --- a/Documentation/userspace-api/media/v4l/pixfmt-nv12-col128.rst +++ /dev/null @@ -1,215 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _V4L2_PIX_FMT_NV12_COL128: -.. _V4L2_PIX_FMT_NV12_10_COL128: - -******************************************************************************** -V4L2_PIX_FMT_NV12_COL128, V4L2_PIX_FMT_NV12_10_COL128 -******************************************************************************** - - -V4L2_PIX_FMT_NV21_COL128 -Formats with ½ horizontal and vertical chroma resolution. This format -has two planes - one for luminance and one for chrominance. Chroma -samples are interleaved. The difference to ``V4L2_PIX_FMT_NV12`` is the -memory layout. The image is split into columns of 128 bytes wide rather than -being in raster order. - -V4L2_PIX_FMT_NV12_10_COL128 -Follows the same pattern as ``V4L2_PIX_FMT_NV21_COL128`` with 128 byte, but is -a 10bit format with 3 10-bit samples being packed into 4 bytes. Each 128 byte -wide column therefore contains 96 samples. - - -Description -=========== - -This is the two-plane versions of the YUV 4:2:0 format where data is -grouped into 128 byte wide columns. The three components are separated into -two sub-images or planes. The Y plane has one byte per pixel and pixels -are grouped into 128 byte wide columns. The CbCr plane has the same width, -in bytes, as the Y plane (and the image), but is half as tall in pixels. -The chroma plane is also in 128 byte columns, reflecting 64 Cb and 64 Cr -samples. - -The chroma samples for a column follow the luma samples. If there is any -paddding, then that will be reflected via the selection API. -The luma height must be a multiple of 2 lines. - -The normal bytesperline is effectively fixed at 128. However the format -requires knowledge of the stride between columns, therefore the bytesperline -value has been repurposed to denote the number of 128 byte long lines between -the start of each column. - -**Byte Order.** - - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - :widths: 12 12 12 12 12 4 12 12 12 12 - - * - start + 0: - - Y'\ :sub:`0,0` - - Y'\ :sub:`0,1` - - Y'\ :sub:`0,2` - - Y'\ :sub:`0,3` - - ... - - Y'\ :sub:`0,124` - - Y'\ :sub:`0,125` - - Y'\ :sub:`0,126` - - Y'\ :sub:`0,127` - * - start + 128: - - Y'\ :sub:`1,0` - - Y'\ :sub:`1,1` - - Y'\ :sub:`1,2` - - Y'\ :sub:`1,3` - - ... - - Y'\ :sub:`1,124` - - Y'\ :sub:`1,125` - - Y'\ :sub:`1,126` - - Y'\ :sub:`1,127` - * - start + 256: - - Y'\ :sub:`2,0` - - Y'\ :sub:`2,1` - - Y'\ :sub:`2,2` - - Y'\ :sub:`2,3` - - ... - - Y'\ :sub:`2,124` - - Y'\ :sub:`2,125` - - Y'\ :sub:`2,126` - - Y'\ :sub:`2,127` - * - ... - - ... - - ... - - ... - - ... - - ... - - ... - - ... - * - start + ((height-1) * 128): - - Y'\ :sub:`height-1,0` - - Y'\ :sub:`height-1,1` - - Y'\ :sub:`height-1,2` - - Y'\ :sub:`height-1,3` - - ... - - Y'\ :sub:`height-1,124` - - Y'\ :sub:`height-1,125` - - Y'\ :sub:`height-1,126` - - Y'\ :sub:`height-1,127` - * - start + ((height) * 128): - - Cb\ :sub:`0,0` - - Cr\ :sub:`0,0` - - Cb\ :sub:`0,1` - - Cr\ :sub:`0,1` - - ... - - Cb\ :sub:`0,62` - - Cr\ :sub:`0,62` - - Cb\ :sub:`0,63` - - Cr\ :sub:`0,63` - * - start + ((height+1) * 128): - - Cb\ :sub:`1,0` - - Cr\ :sub:`1,0` - - Cb\ :sub:`1,1` - - Cr\ :sub:`1,1` - - ... - - Cb\ :sub:`1,62` - - Cr\ :sub:`1,62` - - Cb\ :sub:`1,63` - - Cr\ :sub:`1,63` - * - ... - - ... - - ... - - ... - - ... - - ... - - ... - - ... - * - start + ((height+(height/2)-1) * 128): - - Cb\ :sub:`(height/2)-1,0` - - Cr\ :sub:`(height/2)-1,0` - - Cb\ :sub:`(height/2)-1,1` - - Cr\ :sub:`(height/2)-1,1` - - ... - - Cb\ :sub:`(height/2)-1,62` - - Cr\ :sub:`(height/2)-1,62` - - Cb\ :sub:`(height/2)-1,63` - - Cr\ :sub:`(height/2)-1,63` - * - start + (bytesperline * 128): - - Y'\ :sub:`0,128` - - Y'\ :sub:`0,129` - - Y'\ :sub:`0,130` - - Y'\ :sub:`0,131` - - ... - - Y'\ :sub:`0,252` - - Y'\ :sub:`0,253` - - Y'\ :sub:`0,254` - - Y'\ :sub:`0,255` - * - ... - - ... - - ... - - ... - - ... - - ... - - ... - - ... - -V4L2_PIX_FMT_NV12_10_COL128 uses the same 128 byte column structure, but -encodes 10-bit YUV. -3 10-bit values are packed into 4 bytes as bits 9:0, 19:10, and 29:20, with -bits 30 & 31 unused. For the luma plane, bits 9:0 are Y0, 19:10 are Y1, and -29:20 are Y2. For the chroma plane the samples always come in pairs of Cr -and Cb, so it needs to be considered 6 values packed in 8 bytes. - -Bit-packed representation. - -.. raw:: latex - - \small - -.. tabularcolumns:: |p{1.2cm}||p{1.2cm}||p{1.2cm}||p{1.2cm}|p{3.2cm}|p{3.2cm}| - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - :widths: 8 8 8 8 - - * - Y'\ :sub:`00[7:0]` - - Y'\ :sub:`01[5:0] (bits 7--2)` Y'\ :sub:`00[9:8]`\ (bits 1--0) - - Y'\ :sub:`02[3:0] (bits 7--4)` Y'\ :sub:`01[9:6]`\ (bits 3--0) - - unused (bits 7--6)` Y'\ :sub:`02[9:4]`\ (bits 5--0) - -.. raw:: latex - - \small - -.. tabularcolumns:: |p{1.2cm}||p{1.2cm}||p{1.2cm}||p{1.2cm}|p{3.2cm}|p{3.2cm}| - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - :widths: 12 12 12 12 12 12 12 12 - - * - Cb\ :sub:`00[7:0]` - - Cr\ :sub:`00[5:0]`\ (bits 7--2) Cb\ :sub:`00[9:8]`\ (bits 1--0) - - Cb\ :sub:`01[3:0]`\ (bits 7--4) Cr\ :sub:`00[9:6]`\ (bits 3--0) - - unused (bits 7--6) Cb\ :sub:`02[9:4]`\ (bits 5--0) - - Cr\ :sub:`01[7:0]` - - Cb\ :sub:`02[5:0]`\ (bits 7--2) Cr\ :sub:`01[9:8]`\ (bits 1--0) - - Cr\ :sub:`02[3:0]`\ (bits 7--4) Cb\ :sub:`02[9:6]`\ (bits 3--0) - - unused (bits 7--6) Cr\ :sub:`02[9:4]`\ (bits 5--0) - -.. raw:: latex - - \normalsize - - - - diff --git a/Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst b/Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst index 7f92b071e6ed08..b5b590f234b003 100644 --- a/Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst +++ b/Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst @@ -827,17 +827,47 @@ Data in the 12 high bits, zeros in the 4 low bits, arranged in little endian ord - Cb\ :sub:`11` - Cr\ :sub:`11` +V4L2_PIX_FMT_NV12MT_COL128 and V4L2_PIX_FMT_NV12MT_10_COL128 +------------------------------------------------------------ -V4L2_PIX_FMT_NV12_COL128 ------------------------- +``V4L2_PIX_FMT_NV12MT_COL128`` is a tiled version of +``V4L2_PIX_FMT_NV12M`` where the two planes are split into 128 byte wide columns +of Y or interleaved CbCr. -``V4L2_PIX_FMT_NV12_COL128`` is the tiled version of -``V4L2_PIX_FMT_NV12`` with the image broken down into 128 pixel wide columns of -Y followed by the associated combined CbCr plane. -The normal bytesperline is effectively fixed at 128. However the format -requires knowledge of the stride between columns, therefore the bytesperline -value has been repurposed to denote the number of 128 byte long lines between -the start of each column. +V4L2_PIX_FMT_NV12MT_10_COL128 expands that as a 10 bit format where 3 10 bit +values are packed into a 32bit word. A 128 byte wide column therefore holds 96 +samples (either Y or interleaved CrCb). That effectively makes it 6 values in a +64 bit word for the CbCr plane, as the values always go in pairs. + +Bit-packed representation. + +.. tabularcolumns:: |p{1.2cm}||p{1.2cm}||p{1.2cm}||p{1.2cm}|p{3.2cm}|p{3.2cm}| + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + :widths: 8 8 8 8 + + * - Y'\ :sub:`00[7:0]` + - Y'\ :sub:`01[5:0] (bits 7--2)` Y'\ :sub:`00[9:8]`\ (bits 1--0) + - Y'\ :sub:`02[3:0] (bits 7--4)` Y'\ :sub:`01[9:6]`\ (bits 3--0) + - unused (bits 7--6)` Y'\ :sub:`02[9:4]`\ (bits 5--0) + +.. tabularcolumns:: |p{1.2cm}||p{1.2cm}||p{1.2cm}||p{1.2cm}|p{3.2cm}|p{3.2cm}| + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + :widths: 12 12 12 12 12 12 12 12 + + * - Cb\ :sub:`00[7:0]` + - Cr\ :sub:`00[5:0]`\ (bits 7--2) Cb\ :sub:`00[9:8]`\ (bits 1--0) + - Cb\ :sub:`01[3:0]`\ (bits 7--4) Cr\ :sub:`00[9:6]`\ (bits 3--0) + - unused (bits 7--6) Cb\ :sub:`02[9:4]`\ (bits 5--0) + - Cr\ :sub:`01[7:0]` + - Cb\ :sub:`02[5:0]`\ (bits 7--2) Cr\ :sub:`01[9:8]`\ (bits 1--0) + - Cr\ :sub:`02[3:0]`\ (bits 7--4) Cb\ :sub:`02[9:6]`\ (bits 3--0) + - unused (bits 7--6) Cr\ :sub:`02[9:4]`\ (bits 5--0) Fully Planar YUV Formats diff --git a/Documentation/userspace-api/media/v4l/yuv-formats.rst b/Documentation/userspace-api/media/v4l/yuv-formats.rst index 458e07782c8d80..24b34cdfa6fea6 100644 --- a/Documentation/userspace-api/media/v4l/yuv-formats.rst +++ b/Documentation/userspace-api/media/v4l/yuv-formats.rst @@ -270,23 +270,4 @@ image. pixfmt-y8i pixfmt-y12i pixfmt-uv8 - pixfmt-yuyv - pixfmt-uyvy - pixfmt-yvyu - pixfmt-vyuy - pixfmt-y41p - pixfmt-yuv420 - pixfmt-yuv420m - pixfmt-yuv422m - pixfmt-yuv444m - pixfmt-yuv410 - pixfmt-yuv422p - pixfmt-yuv411p - pixfmt-nv12 - pixfmt-nv12m - pixfmt-nv12mt - pixfmt-nv12-col128 - pixfmt-nv16 - pixfmt-nv16m - pixfmt-nv24 pixfmt-m420 diff --git a/MAINTAINERS b/MAINTAINERS index 0ca82e50fe372a..859779bc375d0b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -19357,6 +19357,16 @@ S: Maintained F: Documentation/devicetree/bindings/spi/raspberrypi,rp2040-gpio-bridge.yaml F: drivers/spi/spi-rp2040-gpio-bridge.c +RASPBERRY PI HEVC DECODER +M: John Cox +M: Dom Cobley +M: Dave Stevenson +M: Raspberry Pi Internal Kernel List +L: linux-media@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/media/raspberrypi,rpi_hevc_dec.yaml +F: drivers/media/platform/raspberrypi/hevc_dec + RASPBERRY PI PISP BACK END M: Jacopo Mondi L: Raspberry Pi Kernel Maintenance diff --git a/arch/arm/boot/dts/broadcom/bcm2711-rpi-ds.dtsi b/arch/arm/boot/dts/broadcom/bcm2711-rpi-ds.dtsi index fd70dea32e3a54..eb3e4cbf2bedc6 100644 --- a/arch/arm/boot/dts/broadcom/bcm2711-rpi-ds.dtsi +++ b/arch/arm/boot/dts/broadcom/bcm2711-rpi-ds.dtsi @@ -147,18 +147,11 @@ interrupts = ; power-domains = <&power RPI_POWER_DOMAIN_USB>; }; +}; - codec@7eb10000 { - compatible = "raspberrypi,rpivid-vid-decoder"; - reg = <0x0 0x7eb10000 0x0 0x1000>, /* INTC */ - <0x0 0x7eb00000 0x0 0x10000>; /* HEVC */ - reg-names = "intc", - "hevc"; - interrupts = ; - - clocks = <&firmware_clocks 11>; - clock-names = "hevc"; - }; +&hevc_dec { + reg = <0x0 0x7eb00000 0x0 0x10000>, /* HEVC */ + <0x0 0x7eb10000 0x0 0x1000>; /* INTC */ }; &pcie0 { diff --git a/arch/arm/boot/dts/broadcom/bcm2711-rpi.dtsi b/arch/arm/boot/dts/broadcom/bcm2711-rpi.dtsi index da5f54e7dd2447..0eaf232d4861d0 100644 --- a/arch/arm/boot/dts/broadcom/bcm2711-rpi.dtsi +++ b/arch/arm/boot/dts/broadcom/bcm2711-rpi.dtsi @@ -113,3 +113,7 @@ &vchiq { interrupts = ; }; + +&hevc_dec { + clocks = <&firmware_clocks 11>; +}; diff --git a/arch/arm/boot/dts/broadcom/bcm2711.dtsi b/arch/arm/boot/dts/broadcom/bcm2711.dtsi index 21c628c55b5808..bb137d8da1a821 100644 --- a/arch/arm/boot/dts/broadcom/bcm2711.dtsi +++ b/arch/arm/boot/dts/broadcom/bcm2711.dtsi @@ -612,6 +612,15 @@ resets = <&pm BCM2835_RESET_V3D>; interrupts = ; }; + + hevc_dec: codec@7eb10000 { + compatible = "brcm,bcm2711-hevc-dec", "raspberrypi,hevc-dec"; + reg = <0x0 0x7eb00000 0x10000>, /* HEVC */ + <0x0 0x7eb10000 0x1000>; /* INTC */ + reg-names = "hevc", + "intc"; + interrupts = ; + }; }; }; diff --git a/arch/arm/configs/bcm2711_defconfig b/arch/arm/configs/bcm2711_defconfig index 9bbb8f8ebeda81..e7608e37ea6f7b 100644 --- a/arch/arm/configs/bcm2711_defconfig +++ b/arch/arm/configs/bcm2711_defconfig @@ -959,6 +959,7 @@ CONFIG_V4L_PLATFORM_DRIVERS=y CONFIG_VIDEO_MUX=m CONFIG_VIDEO_BCM2835_UNICAM_LEGACY=m CONFIG_VIDEO_BCM2835_UNICAM=m +CONFIG_VIDEO_RPI_HEVC_DEC=m CONFIG_VIDEO_ARDUCAM_64MP=m CONFIG_VIDEO_ARDUCAM_PIVARIETY=m CONFIG_VIDEO_IMX219=m @@ -1403,7 +1404,6 @@ CONFIG_STAGING=y CONFIG_R8712U=m CONFIG_VT6656=m CONFIG_STAGING_MEDIA=y -CONFIG_VIDEO_RPIVID=m CONFIG_STAGING_MEDIA_DEPRECATED=y CONFIG_FB_TFT=m CONFIG_FB_TFT_AGM1264K_FL=m diff --git a/arch/arm64/boot/dts/broadcom/bcm2712-ds.dtsi b/arch/arm64/boot/dts/broadcom/bcm2712-ds.dtsi index e797fa76ad6ea8..159bb9aa79f6bf 100644 --- a/arch/arm64/boot/dts/broadcom/bcm2712-ds.dtsi +++ b/arch/arm64/boot/dts/broadcom/bcm2712-ds.dtsi @@ -552,8 +552,8 @@ status = "disabled"; }; - rpivid: codec@800000 { - compatible = "raspberrypi,rpivid-vid-decoder"; + hevc_dec: codec@800000 { + compatible = "brcm,bcm2712-hevc-dec", "raspberrypi,hevc-dec"; reg = <0x10 0x00800000 0x0 0x10000>, /* HEVC */ <0x10 0x00840000 0x0 0x1000>; /* INTC */ reg-names = "hevc", @@ -564,7 +564,6 @@ clocks = <&firmware_clocks 11>; clock-names = "hevc"; iommus = <&iommu2>; - status = "disabled"; }; pisp_be: pisp_be@880000 { diff --git a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts index 5181fcad52224a..22896ca859f684 100644 --- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts +++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts @@ -445,10 +445,6 @@ dpi_16bit_gpio2: &rp1_dpi_16bit_gpio2 { }; }; }; -&rpivid { - status = "okay"; -}; - &pinctrl { spi10_gpio2: spi10_gpio2 { function = "vc_spi0"; diff --git a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi index 42f5c012b1ccbc..d8302ff6d91cdd 100644 --- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi +++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi @@ -426,10 +426,6 @@ dpi_16bit_gpio2: &rp1_dpi_16bit_gpio2 { }; }; }; -&rpivid { - status = "okay"; -}; - &pinctrl { spi10_gpio2: spi10_gpio2 { function = "vc_spi0"; diff --git a/arch/arm64/configs/bcm2711_defconfig b/arch/arm64/configs/bcm2711_defconfig index 974e7028bd7f37..f1dc4940d2d039 100644 --- a/arch/arm64/configs/bcm2711_defconfig +++ b/arch/arm64/configs/bcm2711_defconfig @@ -1001,6 +1001,7 @@ CONFIG_V4L_PLATFORM_DRIVERS=y CONFIG_VIDEO_MUX=m CONFIG_VIDEO_BCM2835_UNICAM_LEGACY=m CONFIG_VIDEO_BCM2835_UNICAM=m +CONFIG_VIDEO_RPI_HEVC_DEC=m CONFIG_VIDEO_RASPBERRYPI_PISP_BE=m CONFIG_VIDEO_RP1_CFE=m CONFIG_V4L_TEST_DRIVERS=y diff --git a/arch/arm64/configs/bcm2712_defconfig b/arch/arm64/configs/bcm2712_defconfig index 94cbd28ff74c54..e7ff90ca01e5aa 100644 --- a/arch/arm64/configs/bcm2712_defconfig +++ b/arch/arm64/configs/bcm2712_defconfig @@ -1003,6 +1003,7 @@ CONFIG_V4L_PLATFORM_DRIVERS=y CONFIG_VIDEO_MUX=m CONFIG_VIDEO_BCM2835_UNICAM_LEGACY=m CONFIG_VIDEO_BCM2835_UNICAM=m +CONFIG_VIDEO_RPI_HEVC_DEC=m CONFIG_VIDEO_RASPBERRYPI_PISP_BE=m CONFIG_VIDEO_RP1_CFE=m CONFIG_V4L_TEST_DRIVERS=y @@ -1465,7 +1466,6 @@ CONFIG_STAGING=y CONFIG_R8712U=m CONFIG_VT6656=m CONFIG_STAGING_MEDIA=y -CONFIG_VIDEO_RPIVID=m CONFIG_STAGING_MEDIA_DEPRECATED=y CONFIG_FB_TFT=m CONFIG_FB_TFT_AGM1264K_FL=m diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index f9c24baf18e5e2..0562f2995a9af0 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -199,7 +199,8 @@ static int framebuffer_check(struct drm_device *dev, if ((uint64_t) height * r->pitches[i] + r->offsets[i] > UINT_MAX) return -ERANGE; - if (block_size && r->pitches[i] < min_pitch) { + if (r->modifier[i] == DRM_FORMAT_MOD_LINEAR && block_size && + r->pitches[i] < min_pitch) { drm_dbg_kms(dev, "bad pitch %u for plane %d\n", r->pitches[i], i); return -EINVAL; } diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c index 3258dbec9bddee..73680550bcef74 100644 --- a/drivers/gpu/drm/vc4/vc4_hvs.c +++ b/drivers/gpu/drm/vc4/vc4_hvs.c @@ -281,8 +281,8 @@ static int vc4_hvs_debugfs_dlist(struct seq_file *m, void *data) static int vc6_hvs_debugfs_dlist(struct seq_file *m, void *data) { - struct drm_info_node *node = m->private; - struct drm_device *dev = node->minor->dev; + struct drm_debugfs_entry *entry = m->private; + struct drm_device *dev = entry->dev; struct vc4_dev *vc4 = to_vc4_dev(dev); struct vc4_hvs *hvs = vc4->hvs; struct drm_printer p = drm_seq_file_printer(m); diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index 5ce0598c92117a..8e994a3221047c 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -843,7 +843,14 @@ static size_t vc6_upm_size(const struct drm_plane_state *state, { const struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); unsigned int stride = state->fb->pitches[plane]; + u64 base_format_mod = fourcc_mod_broadcom_mod(state->fb->modifier); + if (base_format_mod == DRM_FORMAT_MOD_BROADCOM_SAND128) { + if (state->fb->format->format == DRM_FORMAT_P030) + stride = (ALIGN(state->fb->width, 96) * 4) / 3; + else + stride = ALIGN(state->fb->width, 128); + } /* * TODO: This only works for raster formats, and is sub-optimal * for buffers with a stride aligned on 32 bytes. @@ -1293,7 +1300,7 @@ static int vc4_plane_mode_set(struct drm_plane *plane, u32 v_subsample = fb->format->vsub; bool mix_plane_alpha; bool covers_screen; - u32 scl0, scl1, pitch0; + u32 scl0, scl1, pitch[2]; u32 tiling, src_x, src_y; u32 width, height; u32 hvs_format = format->hvs; @@ -1347,7 +1354,7 @@ static int vc4_plane_mode_set(struct drm_plane *plane, switch (base_format_mod) { case DRM_FORMAT_MOD_LINEAR: tiling = SCALER_CTL0_TILING_LINEAR; - pitch0 = VC4_SET_FIELD(fb->pitches[0], SCALER_SRC_PITCH); + pitch[0] = VC4_SET_FIELD(fb->pitches[0], SCALER_SRC_PITCH); /* Adjust the base pointer to the first pixel to be scanned * out. @@ -1399,23 +1406,23 @@ static int vc4_plane_mode_set(struct drm_plane *plane, */ if (rotation & DRM_MODE_REFLECT_Y) { y_off = tile_h_mask - y_off; - pitch0 = SCALER_PITCH0_TILE_LINE_DIR; + pitch[0] = SCALER_PITCH0_TILE_LINE_DIR; } else { - pitch0 = 0; + pitch[0] = 0; } tiling = SCALER_CTL0_TILING_256B_OR_T; - pitch0 |= (VC4_SET_FIELD(x_off, SCALER_PITCH0_SINK_PIX) | - VC4_SET_FIELD(y_off, SCALER_PITCH0_TILE_Y_OFFSET) | - VC4_SET_FIELD(tiles_l, SCALER_PITCH0_TILE_WIDTH_L) | - VC4_SET_FIELD(tiles_r, SCALER_PITCH0_TILE_WIDTH_R)); + pitch[0] |= (VC4_SET_FIELD(x_off, SCALER_PITCH0_SINK_PIX) | + VC4_SET_FIELD(y_off, SCALER_PITCH0_TILE_Y_OFFSET) | + VC4_SET_FIELD(tiles_l, SCALER_PITCH0_TILE_WIDTH_L) | + VC4_SET_FIELD(tiles_r, SCALER_PITCH0_TILE_WIDTH_R)); offsets[0] += tiles_t * (tiles_w << tile_size_shift); offsets[0] += subtile_y << 8; offsets[0] += utile_y << 4; /* Rows of tiles alternate left-to-right and right-to-left. */ if (tiles_t & 1) { - pitch0 |= SCALER_PITCH0_TILE_INITIAL_LINE_DIR; + pitch[0] |= SCALER_PITCH0_TILE_INITIAL_LINE_DIR; offsets[0] += (tiles_w - tiles_l) << tile_size_shift; offsets[0] -= (1 + !tile_y) << 10; } else { @@ -1430,6 +1437,7 @@ static int vc4_plane_mode_set(struct drm_plane *plane, case DRM_FORMAT_MOD_BROADCOM_SAND128: case DRM_FORMAT_MOD_BROADCOM_SAND256: { uint32_t param = fourcc_mod_broadcom_param(fb->modifier); + unsigned int tile_width = 0; if (param > SCALER_TILE_HEIGHT_MASK) { DRM_DEBUG_KMS("SAND height too large (%d)\n", @@ -1440,18 +1448,22 @@ static int vc4_plane_mode_set(struct drm_plane *plane, if (fb->format->format == DRM_FORMAT_P030) { hvs_format = HVS_PIXEL_FORMAT_YCBCR_10BIT; tiling = SCALER_CTL0_TILING_128B; + tile_width = 128; } else { hvs_format = HVS_PIXEL_FORMAT_H264; switch (base_format_mod) { case DRM_FORMAT_MOD_BROADCOM_SAND64: tiling = SCALER_CTL0_TILING_64B; + tile_width = 64; break; case DRM_FORMAT_MOD_BROADCOM_SAND128: tiling = SCALER_CTL0_TILING_128B; + tile_width = 128; break; case DRM_FORMAT_MOD_BROADCOM_SAND256: tiling = SCALER_CTL0_TILING_256B_OR_T; + tile_width = 256; break; default: return -EINVAL; @@ -1469,7 +1481,16 @@ static int vc4_plane_mode_set(struct drm_plane *plane, * should be 6. */ for (i = 0; i < num_planes; i++) { - u32 tile_w, tile, x_off, pix_per_tile; + u32 tile, x_off, pix_per_tile; + + switch (param) { + case 0: + pitch[i] = fb->pitches[i]; + break; + default: + pitch[i] = VC4_SET_FIELD(param, SCALER_TILE_HEIGHT); + break; + } if (fb->format->format == DRM_FORMAT_P030) { /* @@ -1485,23 +1506,9 @@ static int vc4_plane_mode_set(struct drm_plane *plane, u32 last_bits = remaining_pixels % 12; x_off = aligned * 16 + last_bits; - tile_w = 128; pix_per_tile = 96; } else { - switch (base_format_mod) { - case DRM_FORMAT_MOD_BROADCOM_SAND64: - tile_w = 64; - break; - case DRM_FORMAT_MOD_BROADCOM_SAND128: - tile_w = 128; - break; - case DRM_FORMAT_MOD_BROADCOM_SAND256: - tile_w = 256; - break; - default: - return -EINVAL; - } - pix_per_tile = tile_w / fb->format->cpp[0]; + pix_per_tile = tile_width / fb->format->cpp[0]; x_off = (src_x % pix_per_tile) / (i ? h_subsample : 1) * fb->format->cpp[i]; @@ -1509,12 +1516,10 @@ static int vc4_plane_mode_set(struct drm_plane *plane, tile = src_x / pix_per_tile; - offsets[i] += param * tile_w * tile; - offsets[i] += src_y / (i ? v_subsample : 1) * tile_w; + offsets[i] += pitch[i] * tile; + offsets[i] += src_y / (i ? v_subsample : 1) * tile_width; offsets[i] += x_off & ~(i ? 1 : 0); } - - pitch0 = VC4_SET_FIELD(param, SCALER_TILE_HEIGHT); break; } @@ -1669,7 +1674,7 @@ static int vc4_plane_mode_set(struct drm_plane *plane, vc4_dlist_write(vc4_state, 0xc0c0c0c0); /* Pitch word 0 */ - vc4_dlist_write(vc4_state, pitch0); + vc4_dlist_write(vc4_state, pitch[0]); /* Pitch word 1/2 */ for (i = 1; i < num_planes; i++) { @@ -1679,7 +1684,7 @@ static int vc4_plane_mode_set(struct drm_plane *plane, VC4_SET_FIELD(fb->pitches[i], SCALER_SRC_PITCH)); } else { - vc4_dlist_write(vc4_state, pitch0); + vc4_dlist_write(vc4_state, pitch[1]); } } @@ -1834,7 +1839,7 @@ static int vc6_plane_mode_set(struct drm_plane *plane, u32 v_subsample = fb->format->vsub; bool mix_plane_alpha; bool covers_screen; - u32 scl0, scl1, pitch0; + u32 scl0, scl1, pitch[2]; u32 tiling, src_x, src_y; u32 width, height; u32 hvs_format = format->hvs; @@ -1904,6 +1909,7 @@ static int vc6_plane_mode_set(struct drm_plane *plane, case DRM_FORMAT_MOD_BROADCOM_SAND128: case DRM_FORMAT_MOD_BROADCOM_SAND256: { uint32_t param = fourcc_mod_broadcom_param(fb->modifier); + unsigned int tile_width = 0; u32 components_per_word; u32 starting_offset; u32 fetch_count; @@ -1917,21 +1923,29 @@ static int vc6_plane_mode_set(struct drm_plane *plane, if (fb->format->format == DRM_FORMAT_P030) { hvs_format = HVS_PIXEL_FORMAT_YCBCR_10BIT; tiling = SCALER6_CTL0_ADDR_MODE_128B; + tile_width = 128; } else { hvs_format = HVS_PIXEL_FORMAT_YCBCR_YUV420_2PLANE; switch (base_format_mod) { case DRM_FORMAT_MOD_BROADCOM_SAND128: tiling = SCALER6_CTL0_ADDR_MODE_128B; + tile_width = 128; break; case DRM_FORMAT_MOD_BROADCOM_SAND256: tiling = SCALER6_CTL0_ADDR_MODE_256B; + tile_width = 256; break; default: return -EINVAL; } } + components_per_word = fb->format->format == DRM_FORMAT_P030 ? 24 : 32; + starting_offset = src_x % components_per_word; + fetch_count = (width + starting_offset + components_per_word - 1) / + components_per_word; + /* Adjust the base pointer to the first pixel to be scanned * out. * @@ -1943,7 +1957,16 @@ static int vc6_plane_mode_set(struct drm_plane *plane, * should be 6. */ for (i = 0; i < num_planes; i++) { - u32 tile_w, tile, x_off, pix_per_tile; + u32 tile, x_off, pix_per_tile; + + switch (param) { + case 0: + pitch[i] = fb->pitches[i]; + break; + default: + pitch[i] = VC4_SET_FIELD(param, SCALER_TILE_HEIGHT); + break; + } if (fb->format->format == DRM_FORMAT_P030) { /* @@ -1959,20 +1982,9 @@ static int vc6_plane_mode_set(struct drm_plane *plane, u32 last_bits = remaining_pixels % 12; x_off = aligned * 16 + last_bits; - tile_w = 128; pix_per_tile = 96; } else { - switch (base_format_mod) { - case DRM_FORMAT_MOD_BROADCOM_SAND128: - tile_w = 128; - break; - case DRM_FORMAT_MOD_BROADCOM_SAND256: - tile_w = 256; - break; - default: - return -EINVAL; - } - pix_per_tile = tile_w / fb->format->cpp[0]; + pix_per_tile = tile_width / fb->format->cpp[0]; x_off = (src_x % pix_per_tile) / (i ? h_subsample : 1) * fb->format->cpp[i]; @@ -1980,18 +1992,18 @@ static int vc6_plane_mode_set(struct drm_plane *plane, tile = src_x / pix_per_tile; - offsets[i] += param * tile_w * tile; - offsets[i] += src_y / (i ? v_subsample : 1) * tile_w; + offsets[i] += pitch[i] * tile; + offsets[i] += src_y / (i ? v_subsample : 1) * tile_width; offsets[i] += x_off & ~(i ? 1 : 0); - } - components_per_word = fb->format->format == DRM_FORMAT_P030 ? 24 : 32; - starting_offset = src_x % components_per_word; - fetch_count = (width + starting_offset + components_per_word - 1) / - components_per_word; + /* + * Finished using the pitch as a pitch, so pack it as the + * register value. + */ + pitch[i] = VC4_SET_FIELD(pitch[i], SCALER6_PTR2_PITCH) | + VC4_SET_FIELD(fetch_count - 1, SCALER6_PTR2_FETCH_COUNT); + } - pitch0 = VC4_SET_FIELD(param, SCALER6_PTR2_PITCH) | - VC4_SET_FIELD(fetch_count - 1, SCALER6_PTR2_FETCH_COUNT); break; } @@ -2104,7 +2116,7 @@ static int vc6_plane_mode_set(struct drm_plane *plane, VC4_SET_FIELD(fb->pitches[i], SCALER6_PTR2_PITCH)); } else { - vc4_dlist_write(vc4_state, pitch0); + vc4_dlist_write(vc4_state, pitch[i]); } } @@ -2613,9 +2625,9 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev, unsigned i; static const uint64_t modifiers[] = { DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED, - DRM_FORMAT_MOD_BROADCOM_SAND128, - DRM_FORMAT_MOD_BROADCOM_SAND64, - DRM_FORMAT_MOD_BROADCOM_SAND256, + DRM_FORMAT_MOD_BROADCOM_SAND128_COL_HEIGHT(0), + DRM_FORMAT_MOD_BROADCOM_SAND64_COL_HEIGHT(0), + DRM_FORMAT_MOD_BROADCOM_SAND256_COL_HEIGHT(0), DRM_FORMAT_MOD_LINEAR, DRM_FORMAT_MOD_INVALID }; diff --git a/drivers/media/mc/mc-device.c b/drivers/media/mc/mc-device.c index c0dd4ae5722725..5a458160200afb 100644 --- a/drivers/media/mc/mc-device.c +++ b/drivers/media/mc/mc-device.c @@ -679,6 +679,23 @@ void media_device_unregister_entity(struct media_entity *entity) } EXPORT_SYMBOL_GPL(media_device_unregister_entity); +#ifdef CONFIG_DEBUG_FS +/* + * Log the state of media requests. + * Very useful for debugging. + */ +static int media_device_requests(struct seq_file *file, void *priv) +{ + struct media_device *dev = dev_get_drvdata(file->private); + + seq_printf(file, "number of requests: %d\n", + atomic_read(&dev->num_requests)); + seq_printf(file, "number of request objects: %d\n", + atomic_read(&dev->num_request_objects)); + return 0; +} +#endif + void media_device_init(struct media_device *mdev) { INIT_LIST_HEAD(&mdev->entities); @@ -697,6 +714,9 @@ void media_device_init(struct media_device *mdev) media_set_bus_info(mdev->bus_info, sizeof(mdev->bus_info), mdev->dev); + atomic_set(&mdev->num_requests, 0); + atomic_set(&mdev->num_request_objects, 0); + dev_dbg(mdev->dev, "Media device initialized\n"); } EXPORT_SYMBOL_GPL(media_device_init); @@ -748,6 +768,15 @@ int __must_check __media_device_register(struct media_device *mdev, dev_dbg(mdev->dev, "Media device registered\n"); +#ifdef CONFIG_DEBUG_FS + if (!media_debugfs_root) + media_debugfs_root = debugfs_create_dir("media", NULL); + mdev->media_dir = debugfs_create_dir(dev_name(&devnode->dev), + media_debugfs_root); + debugfs_create_devm_seqfile(&devnode->dev, "requests", + mdev->media_dir, media_device_requests); +#endif + return 0; } EXPORT_SYMBOL_GPL(__media_device_register); @@ -824,6 +853,7 @@ void media_device_unregister(struct media_device *mdev) dev_dbg(mdev->dev, "Media device unregistered\n"); + debugfs_remove_recursive(mdev->media_dir); device_remove_file(&mdev->devnode->dev, &dev_attr_model); media_devnode_unregister(mdev->devnode); /* devnode free is handled in media_devnode_*() */ diff --git a/drivers/media/mc/mc-devnode.c b/drivers/media/mc/mc-devnode.c index 56444edaf13651..d0a8bcc11dd635 100644 --- a/drivers/media/mc/mc-devnode.c +++ b/drivers/media/mc/mc-devnode.c @@ -45,6 +45,9 @@ static dev_t media_dev_t; static DEFINE_MUTEX(media_devnode_lock); static DECLARE_BITMAP(media_devnode_nums, MEDIA_NUM_DEVICES); +/* debugfs */ +struct dentry *media_debugfs_root; + /* Called when the last user of the media device exits. */ static void media_devnode_release(struct device *cd) { @@ -236,6 +239,7 @@ int __must_check media_devnode_register(struct media_device *mdev, if (devnode->parent) devnode->dev.parent = devnode->parent; dev_set_name(&devnode->dev, "media%d", devnode->minor); + dev_set_drvdata(&devnode->dev, mdev); device_initialize(&devnode->dev); /* Part 2: Initialize the character device */ @@ -313,6 +317,7 @@ static int __init media_devnode_init(void) static void __exit media_devnode_exit(void) { + debugfs_remove_recursive(media_debugfs_root); bus_unregister(&media_bus_type); unregister_chrdev_region(media_dev_t, MEDIA_NUM_DEVICES); } diff --git a/drivers/media/mc/mc-request.c b/drivers/media/mc/mc-request.c index b222f994760d40..d7cf2fe1436cab 100644 --- a/drivers/media/mc/mc-request.c +++ b/drivers/media/mc/mc-request.c @@ -54,6 +54,7 @@ static void media_request_clean(struct media_request *req) req->access_count = 0; WARN_ON(req->num_incomplete_objects); req->num_incomplete_objects = 0; + req->manual_completion = false; wake_up_interruptible_all(&req->poll_wait); } @@ -74,6 +75,7 @@ static void media_request_release(struct kref *kref) mdev->ops->req_free(req); else kfree(req); + atomic_dec(&mdev->num_requests); } void media_request_put(struct media_request *req) @@ -319,6 +321,7 @@ int media_request_alloc(struct media_device *mdev, int *alloc_fd) req->mdev = mdev; req->state = MEDIA_REQUEST_STATE_IDLE; req->num_incomplete_objects = 0; + req->manual_completion = false; kref_init(&req->kref); INIT_LIST_HEAD(&req->objects); spin_lock_init(&req->lock); @@ -330,6 +333,7 @@ int media_request_alloc(struct media_device *mdev, int *alloc_fd) snprintf(req->debug_str, sizeof(req->debug_str), "%u:%d", atomic_inc_return(&mdev->request_id), fd); + atomic_inc(&mdev->num_requests); dev_dbg(mdev->dev, "request: allocated %s\n", req->debug_str); fd_install(fd, filp); @@ -353,10 +357,12 @@ static void media_request_object_release(struct kref *kref) struct media_request_object *obj = container_of(kref, struct media_request_object, kref); struct media_request *req = obj->req; + struct media_device *mdev = obj->mdev; if (WARN_ON(req)) media_request_object_unbind(obj); obj->ops->release(obj); + atomic_dec(&mdev->num_request_objects); } struct media_request_object * @@ -421,6 +427,7 @@ int media_request_object_bind(struct media_request *req, obj->req = req; obj->ops = ops; obj->priv = priv; + obj->mdev = req->mdev; if (is_buffer) list_add_tail(&obj->list, &req->objects); @@ -428,6 +435,7 @@ int media_request_object_bind(struct media_request *req, list_add(&obj->list, &req->objects); req->num_incomplete_objects++; ret = 0; + atomic_inc(&obj->mdev->num_request_objects); unlock: spin_unlock_irqrestore(&req->lock, flags); @@ -465,7 +473,7 @@ void media_request_object_unbind(struct media_request_object *obj) req->num_incomplete_objects--; if (req->state == MEDIA_REQUEST_STATE_QUEUED && - !req->num_incomplete_objects) { + !req->num_incomplete_objects && !req->manual_completion) { req->state = MEDIA_REQUEST_STATE_COMPLETE; completed = true; wake_up_interruptible_all(&req->poll_wait); @@ -494,7 +502,7 @@ void media_request_object_complete(struct media_request_object *obj) WARN_ON(req->state != MEDIA_REQUEST_STATE_QUEUED)) goto unlock; - if (!--req->num_incomplete_objects) { + if (!--req->num_incomplete_objects && !req->manual_completion) { req->state = MEDIA_REQUEST_STATE_COMPLETE; wake_up_interruptible_all(&req->poll_wait); completed = true; @@ -506,30 +514,27 @@ void media_request_object_complete(struct media_request_object *obj) } EXPORT_SYMBOL_GPL(media_request_object_complete); -void media_request_pin(struct media_request *req) -{ - unsigned long flags; - - spin_lock_irqsave(&req->lock, flags); - if (WARN_ON(req->state != MEDIA_REQUEST_STATE_QUEUED)) - goto unlock; - req->num_incomplete_objects++; -unlock: - spin_unlock_irqrestore(&req->lock, flags); -} -EXPORT_SYMBOL_GPL(media_request_pin); - -void media_request_unpin(struct media_request *req) +void media_request_manual_complete(struct media_request *req) { unsigned long flags; bool completed = false; + if (WARN_ON(!req)) + return; + if (WARN_ON(!req->manual_completion)) + return; + spin_lock_irqsave(&req->lock, flags); - if (WARN_ON(!req->num_incomplete_objects) || - WARN_ON(req->state != MEDIA_REQUEST_STATE_QUEUED)) + if (WARN_ON(req->state != MEDIA_REQUEST_STATE_QUEUED)) goto unlock; - if (!--req->num_incomplete_objects) { + req->manual_completion = false; + /* + * It is expected that all other objects in this request are + * completed when this function is called. WARN if that is + * not the case. + */ + if (!WARN_ON(req->num_incomplete_objects)) { req->state = MEDIA_REQUEST_STATE_COMPLETE; wake_up_interruptible_all(&req->poll_wait); completed = true; @@ -539,4 +544,4 @@ void media_request_unpin(struct media_request *req) if (completed) media_request_put(req); } -EXPORT_SYMBOL_GPL(media_request_unpin); +EXPORT_SYMBOL_GPL(media_request_manual_complete); diff --git a/drivers/media/platform/raspberrypi/Kconfig b/drivers/media/platform/raspberrypi/Kconfig index a1850c559dbbcc..c90fd591d7234b 100644 --- a/drivers/media/platform/raspberrypi/Kconfig +++ b/drivers/media/platform/raspberrypi/Kconfig @@ -2,5 +2,6 @@ comment "Raspberry Pi media platform drivers" +source "drivers/media/platform/raspberrypi/hevc_dec/Kconfig" source "drivers/media/platform/raspberrypi/pisp_be/Kconfig" source "drivers/media/platform/raspberrypi/rp1_cfe/Kconfig" diff --git a/drivers/media/platform/raspberrypi/Makefile b/drivers/media/platform/raspberrypi/Makefile index 4ce6c998927c17..b7fe9aa25c10bb 100644 --- a/drivers/media/platform/raspberrypi/Makefile +++ b/drivers/media/platform/raspberrypi/Makefile @@ -1,4 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 +obj-y += hevc_dec/ obj-y += pisp_be/ obj-y += rp1_cfe/ diff --git a/drivers/staging/media/rpivid/Kconfig b/drivers/media/platform/raspberrypi/hevc_dec/Kconfig similarity index 59% rename from drivers/staging/media/rpivid/Kconfig rename to drivers/media/platform/raspberrypi/hevc_dec/Kconfig index f9a8a4491301f2..ae1fd079e5c91d 100644 --- a/drivers/staging/media/rpivid/Kconfig +++ b/drivers/media/platform/raspberrypi/hevc_dec/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 -config VIDEO_RPIVID - tristate "Rpi H265 driver" +config VIDEO_RPI_HEVC_DEC + tristate "Rasperry Pi HEVC decoder" depends on VIDEO_DEV && VIDEO_DEV depends on OF select MEDIA_CONTROLLER @@ -9,8 +9,9 @@ config VIDEO_RPIVID select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV help - Support for the Rpi H265 h/w decoder. + Support for the Raspberry Pi HEVC / H265 H/W decoder as a stateless + V4L2 decoder device. To compile this driver as a module, choose M here: the module - will be called rpivid-hevc. + will be called rpi-hevc-dec. diff --git a/drivers/media/platform/raspberrypi/hevc_dec/Makefile b/drivers/media/platform/raspberrypi/hevc_dec/Makefile new file mode 100644 index 00000000000000..b6506bf2e00d15 --- /dev/null +++ b/drivers/media/platform/raspberrypi/hevc_dec/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_VIDEO_RPI_HEVC_DEC) += rpi-hevc-dec.o + +rpi-hevc-dec-y = hevc_d.o hevc_d_video.o hevc_d_hw.o\ + hevc_d_h265.o diff --git a/drivers/staging/media/rpivid/rpivid.c b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d.c similarity index 67% rename from drivers/staging/media/rpivid/rpivid.c rename to drivers/media/platform/raspberrypi/hevc_dec/hevc_d.c index c68a94c8d002df..dee978882f82f9 100644 --- a/drivers/staging/media/rpivid/rpivid.c +++ b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d.c @@ -2,7 +2,7 @@ /* * Raspberry Pi HEVC driver * - * Copyright (C) 2020 Raspberry Pi (Trading) Ltd + * Copyright (C) 2024 Raspberry Pi Ltd * * Based on the Cedrus VPU driver, that is: * @@ -20,10 +20,10 @@ #include #include -#include "rpivid.h" -#include "rpivid_video.h" -#include "rpivid_hw.h" -#include "rpivid_dec.h" +#include "hevc_d.h" +#include "hevc_d_h265.h" +#include "hevc_d_video.h" +#include "hevc_d_hw.h" /* * Default /dev/videoN node number. @@ -34,34 +34,30 @@ static int video_nr = 19; module_param(video_nr, int, 0644); MODULE_PARM_DESC(video_nr, "decoder video device number"); -static const struct rpivid_control rpivid_ctrls[] = { +static const struct hevc_d_control hevc_d_ctrls[] = { { .cfg = { .id = V4L2_CID_STATELESS_HEVC_SPS, - .ops = &rpivid_hevc_sps_ctrl_ops, + .ops = &hevc_d_hevc_sps_ctrl_ops, }, .required = false, - }, - { + }, { .cfg = { .id = V4L2_CID_STATELESS_HEVC_PPS, - .ops = &rpivid_hevc_pps_ctrl_ops, + .ops = &hevc_d_hevc_pps_ctrl_ops, }, .required = false, - }, - { + }, { .cfg = { .id = V4L2_CID_STATELESS_HEVC_SCALING_MATRIX, }, .required = false, - }, - { + }, { .cfg = { .id = V4L2_CID_STATELESS_HEVC_DECODE_PARAMS, }, .required = true, - }, - { + }, { .cfg = { .name = "Slice param array", .id = V4L2_CID_STATELESS_HEVC_SLICE_PARAMS, @@ -70,17 +66,15 @@ static const struct rpivid_control rpivid_ctrls[] = { .dims = { 0x1000 }, }, .required = true, - }, - { + }, { .cfg = { .id = V4L2_CID_STATELESS_HEVC_DECODE_MODE, - .min = V4L2_STATELESS_HEVC_DECODE_MODE_SLICE_BASED, - .max = V4L2_STATELESS_HEVC_DECODE_MODE_SLICE_BASED, - .def = V4L2_STATELESS_HEVC_DECODE_MODE_SLICE_BASED, + .min = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED, + .max = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED, + .def = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED, }, .required = false, - }, - { + }, { .cfg = { .id = V4L2_CID_STATELESS_HEVC_START_CODE, .min = V4L2_STATELESS_HEVC_START_CODE_NONE, @@ -91,53 +85,50 @@ static const struct rpivid_control rpivid_ctrls[] = { }, }; -#define rpivid_ctrls_COUNT ARRAY_SIZE(rpivid_ctrls) +#define HEVC_D_CTRLS_COUNT ARRAY_SIZE(hevc_d_ctrls) -struct v4l2_ctrl *rpivid_find_ctrl(struct rpivid_ctx *ctx, u32 id) +struct v4l2_ctrl *hevc_d_find_ctrl(struct hevc_d_ctx *ctx, u32 id) { unsigned int i; - for (i = 0; ctx->ctrls[i]; i++) + for (i = 0; i < HEVC_D_CTRLS_COUNT; i++) if (ctx->ctrls[i]->id == id) return ctx->ctrls[i]; return NULL; } -void *rpivid_find_control_data(struct rpivid_ctx *ctx, u32 id) +void *hevc_d_find_control_data(struct hevc_d_ctx *ctx, u32 id) { - struct v4l2_ctrl *const ctrl = rpivid_find_ctrl(ctx, id); + struct v4l2_ctrl *const ctrl = hevc_d_find_ctrl(ctx, id); return !ctrl ? NULL : ctrl->p_cur.p; } -static int rpivid_init_ctrls(struct rpivid_dev *dev, struct rpivid_ctx *ctx) +static int hevc_d_init_ctrls(struct hevc_d_dev *dev, struct hevc_d_ctx *ctx) { struct v4l2_ctrl_handler *hdl = &ctx->hdl; struct v4l2_ctrl *ctrl; - unsigned int ctrl_size; unsigned int i; - v4l2_ctrl_handler_init(hdl, rpivid_ctrls_COUNT); + v4l2_ctrl_handler_init(hdl, HEVC_D_CTRLS_COUNT); if (hdl->error) { v4l2_err(&dev->v4l2_dev, "Failed to initialize control handler\n"); return hdl->error; } - ctrl_size = sizeof(ctrl) * rpivid_ctrls_COUNT + 1; - - ctx->ctrls = kzalloc(ctrl_size, GFP_KERNEL); + ctx->ctrls = kzalloc(HEVC_D_CTRLS_COUNT * sizeof(ctrl), GFP_KERNEL); if (!ctx->ctrls) return -ENOMEM; - for (i = 0; i < rpivid_ctrls_COUNT; i++) { - ctrl = v4l2_ctrl_new_custom(hdl, &rpivid_ctrls[i].cfg, + for (i = 0; i < HEVC_D_CTRLS_COUNT; i++) { + ctrl = v4l2_ctrl_new_custom(hdl, &hevc_d_ctrls[i].cfg, ctx); if (hdl->error) { v4l2_err(&dev->v4l2_dev, "Failed to create new custom control id=%#x\n", - rpivid_ctrls[i].cfg.id); + hevc_d_ctrls[i].cfg.id); v4l2_ctrl_handler_free(hdl); kfree(ctx->ctrls); @@ -153,11 +144,11 @@ static int rpivid_init_ctrls(struct rpivid_dev *dev, struct rpivid_ctx *ctx) return 0; } -static int rpivid_request_validate(struct media_request *req) +static int hevc_d_request_validate(struct media_request *req) { struct media_request_object *obj; struct v4l2_ctrl_handler *parent_hdl, *hdl; - struct rpivid_ctx *ctx = NULL; + struct hevc_d_ctx *ctx = NULL; struct v4l2_ctrl *ctrl_test; unsigned int count; unsigned int i; @@ -195,16 +186,17 @@ static int rpivid_request_validate(struct media_request *req) return -ENOENT; } - for (i = 0; i < rpivid_ctrls_COUNT; i++) { - if (!rpivid_ctrls[i].required) + for (i = 0; i < HEVC_D_CTRLS_COUNT; i++) { + if (!hevc_d_ctrls[i].required) continue; ctrl_test = v4l2_ctrl_request_hdl_ctrl_find(hdl, - rpivid_ctrls[i].cfg.id); + hevc_d_ctrls[i].cfg.id); if (!ctrl_test) { v4l2_info(&ctx->dev->v4l2_dev, - "Missing required codec control\n"); + "Missing required codec control %d: id=%#x\n", + i, hevc_d_ctrls[i].cfg.id); v4l2_ctrl_request_hdl_put(hdl); return -ENOENT; } @@ -215,10 +207,10 @@ static int rpivid_request_validate(struct media_request *req) return vb2_request_validate(req); } -static int rpivid_open(struct file *file) +static int hevc_d_open(struct file *file) { - struct rpivid_dev *dev = video_drvdata(file); - struct rpivid_ctx *ctx = NULL; + struct hevc_d_dev *dev = video_drvdata(file); + struct hevc_d_ctx *ctx = NULL; int ret; if (mutex_lock_interruptible(&dev->dev_mutex)) @@ -237,12 +229,12 @@ static int rpivid_open(struct file *file) file->private_data = &ctx->fh; ctx->dev = dev; - ret = rpivid_init_ctrls(dev, ctx); + ret = hevc_d_init_ctrls(dev, ctx); if (ret) goto err_free; ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, - &rpivid_queue_init); + &hevc_d_queue_init); if (IS_ERR(ctx->fh.m2m_ctx)) { ret = PTR_ERR(ctx->fh.m2m_ctx); goto err_ctrls; @@ -251,7 +243,7 @@ static int rpivid_open(struct file *file) /* The only bit of format info that we can guess now is H265 src * Everything else we need more info for */ - rpivid_prepare_src_format(&ctx->src_fmt); + hevc_d_prepare_src_format(&ctx->src_fmt); v4l2_fh_add(&ctx->fh); @@ -261,6 +253,7 @@ static int rpivid_open(struct file *file) err_ctrls: v4l2_ctrl_handler_free(&ctx->hdl); + kfree(ctx->ctrls); err_free: mutex_destroy(&ctx->ctx_mutex); kfree(ctx); @@ -270,11 +263,11 @@ static int rpivid_open(struct file *file) return ret; } -static int rpivid_release(struct file *file) +static int hevc_d_release(struct file *file) { - struct rpivid_dev *dev = video_drvdata(file); - struct rpivid_ctx *ctx = container_of(file->private_data, - struct rpivid_ctx, fh); + struct hevc_d_dev *dev = video_drvdata(file); + struct hevc_d_ctx *ctx = container_of(file->private_data, + struct hevc_d_ctx, fh); mutex_lock(&dev->dev_mutex); @@ -294,37 +287,43 @@ static int rpivid_release(struct file *file) return 0; } -static const struct v4l2_file_operations rpivid_fops = { +static void hevc_d_media_req_queue(struct media_request *req) +{ + media_request_mark_manual_completion(req); + v4l2_m2m_request_queue(req); +} + +static const struct v4l2_file_operations hevc_d_fops = { .owner = THIS_MODULE, - .open = rpivid_open, - .release = rpivid_release, + .open = hevc_d_open, + .release = hevc_d_release, .poll = v4l2_m2m_fop_poll, .unlocked_ioctl = video_ioctl2, .mmap = v4l2_m2m_fop_mmap, }; -static const struct video_device rpivid_video_device = { - .name = RPIVID_NAME, +static const struct video_device hevc_d_video_device = { + .name = HEVC_D_NAME, .vfl_dir = VFL_DIR_M2M, - .fops = &rpivid_fops, - .ioctl_ops = &rpivid_ioctl_ops, + .fops = &hevc_d_fops, + .ioctl_ops = &hevc_d_ioctl_ops, .minor = -1, .release = video_device_release_empty, .device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING, }; -static const struct v4l2_m2m_ops rpivid_m2m_ops = { - .device_run = rpivid_device_run, +static const struct v4l2_m2m_ops hevc_d_m2m_ops = { + .device_run = hevc_d_device_run, }; -static const struct media_device_ops rpivid_m2m_media_ops = { - .req_validate = rpivid_request_validate, - .req_queue = v4l2_m2m_request_queue, +static const struct media_device_ops hevc_d_m2m_media_ops = { + .req_validate = hevc_d_request_validate, + .req_queue = hevc_d_media_req_queue, }; -static int rpivid_probe(struct platform_device *pdev) +static int hevc_d_probe(struct platform_device *pdev) { - struct rpivid_dev *dev; + struct hevc_d_dev *dev; struct video_device *vfd; int ret; @@ -332,19 +331,17 @@ static int rpivid_probe(struct platform_device *pdev) if (!dev) return -ENOMEM; - dev->vfd = rpivid_video_device; + dev->vfd = hevc_d_video_device; dev->dev = &pdev->dev; dev->pdev = pdev; ret = 0; - ret = rpivid_hw_probe(dev); + ret = hevc_d_hw_probe(dev); if (ret) { - dev_err(&pdev->dev, "Failed to probe hardware\n"); + dev_err(&pdev->dev, "Failed to probe hardware - %d\n", ret); return ret; } - dev->dec_ops = &rpivid_dec_ops_h265; - mutex_init(&dev->dev_mutex); ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); @@ -357,7 +354,7 @@ static int rpivid_probe(struct platform_device *pdev) vfd->lock = &dev->dev_mutex; vfd->v4l2_dev = &dev->v4l2_dev; - snprintf(vfd->name, sizeof(vfd->name), "%s", rpivid_video_device.name); + snprintf(vfd->name, sizeof(vfd->name), "%s", hevc_d_video_device.name); video_set_drvdata(vfd, dev); ret = dma_set_mask_and_coherent(dev->dev, DMA_BIT_MASK(36)); @@ -367,7 +364,7 @@ static int rpivid_probe(struct platform_device *pdev) goto err_v4l2; } - dev->m2m_dev = v4l2_m2m_init(&rpivid_m2m_ops); + dev->m2m_dev = v4l2_m2m_init(&hevc_d_m2m_ops); if (IS_ERR(dev->m2m_dev)) { v4l2_err(&dev->v4l2_dev, "Failed to initialize V4L2 M2M device\n"); @@ -377,12 +374,12 @@ static int rpivid_probe(struct platform_device *pdev) } dev->mdev.dev = &pdev->dev; - strscpy(dev->mdev.model, RPIVID_NAME, sizeof(dev->mdev.model)); - strscpy(dev->mdev.bus_info, "platform:" RPIVID_NAME, + strscpy(dev->mdev.model, HEVC_D_NAME, sizeof(dev->mdev.model)); + strscpy(dev->mdev.bus_info, "platform:" HEVC_D_NAME, sizeof(dev->mdev.bus_info)); media_device_init(&dev->mdev); - dev->mdev.ops = &rpivid_m2m_media_ops; + dev->mdev.ops = &hevc_d_m2m_media_ops; dev->v4l2_dev.mdev = &dev->mdev; ret = video_register_device(vfd, VFL_TYPE_VIDEO, video_nr); @@ -424,9 +421,9 @@ static int rpivid_probe(struct platform_device *pdev) return ret; } -static void rpivid_remove(struct platform_device *pdev) +static void hevc_d_remove(struct platform_device *pdev) { - struct rpivid_dev *dev = platform_get_drvdata(pdev); + struct hevc_d_dev *dev = platform_get_drvdata(pdev); if (media_devnode_is_registered(dev->mdev.devnode)) { media_device_unregister(&dev->mdev); @@ -438,27 +435,25 @@ static void rpivid_remove(struct platform_device *pdev) video_unregister_device(&dev->vfd); v4l2_device_unregister(&dev->v4l2_dev); - rpivid_hw_remove(dev); + hevc_d_hw_remove(dev); } -static const struct of_device_id rpivid_dt_match[] = { - { - .compatible = "raspberrypi,rpivid-vid-decoder", - }, +static const struct of_device_id hevc_d_dt_match[] = { + { .compatible = "raspberrypi,hevc-dec", }, { /* sentinel */ } }; -MODULE_DEVICE_TABLE(of, rpivid_dt_match); +MODULE_DEVICE_TABLE(of, hevc_d_dt_match); -static struct platform_driver rpivid_driver = { - .probe = rpivid_probe, - .remove = rpivid_remove, +static struct platform_driver hevc_d_driver = { + .probe = hevc_d_probe, + .remove = hevc_d_remove, .driver = { - .name = RPIVID_NAME, - .of_match_table = of_match_ptr(rpivid_dt_match), + .name = HEVC_D_NAME, + .of_match_table = of_match_ptr(hevc_d_dt_match), }, }; -module_platform_driver(rpivid_driver); +module_platform_driver(hevc_d_driver); -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("John Cox "); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("John Cox "); MODULE_DESCRIPTION("Raspberry Pi HEVC V4L2 driver"); diff --git a/drivers/media/platform/raspberrypi/hevc_dec/hevc_d.h b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d.h new file mode 100644 index 00000000000000..37c2d1612d2a4b --- /dev/null +++ b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d.h @@ -0,0 +1,189 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Raspberry Pi HEVC driver + * + * Copyright (C) 2024 Raspberry Pi Ltd + * + * Based on the Cedrus VPU driver, that is: + * + * Copyright (C) 2016 Florent Revest + * Copyright (C) 2018 Paul Kocialkowski + * Copyright (C) 2018 Bootlin + */ + +#ifndef _HEVC_D_H_ +#define _HEVC_D_H_ + +#include +#include +#include +#include +#include +#include +#include + +#define HEVC_D_DEC_ENV_COUNT 6 +#define HEVC_D_P1BUF_COUNT 3 +#define HEVC_D_P2BUF_COUNT 3 + +#define HEVC_D_NAME "rpi-hevc-dec" + +#define HEVC_D_CAPABILITY_UNTILED BIT(0) +#define HEVC_D_CAPABILITY_H265_DEC BIT(1) + +#define HEVC_D_QUIRK_NO_DMA_OFFSET BIT(0) + +enum hevc_d_irq_status { + HEVC_D_IRQ_NONE, + HEVC_D_IRQ_ERROR, + HEVC_D_IRQ_OK, +}; + +struct hevc_d_control { + struct v4l2_ctrl_config cfg; + unsigned char required:1; +}; + +struct hevc_d_h265_run { + u32 slice_ents; + const struct v4l2_ctrl_hevc_sps *sps; + const struct v4l2_ctrl_hevc_pps *pps; + const struct v4l2_ctrl_hevc_decode_params *dec; + const struct v4l2_ctrl_hevc_slice_params *slice_params; + const struct v4l2_ctrl_hevc_scaling_matrix *scaling_matrix; +}; + +struct hevc_d_run { + struct vb2_v4l2_buffer *src; + struct vb2_v4l2_buffer *dst; + + struct hevc_d_h265_run h265; +}; + +struct hevc_d_buffer { + struct v4l2_m2m_buffer m2m_buf; +}; + +struct hevc_d_dec_state; +struct hevc_d_dec_env; + +struct hevc_d_gptr { + size_t size; + __u8 *ptr; + dma_addr_t addr; + unsigned long attrs; +}; + +struct hevc_d_dev; +typedef void (*hevc_d_irq_callback)(struct hevc_d_dev *dev, void *ctx); + +struct hevc_d_q_aux; +#define HEVC_D_AUX_ENT_COUNT VB2_MAX_FRAME + +struct hevc_d_ctx { + struct v4l2_fh fh; + struct hevc_d_dev *dev; + + struct v4l2_pix_format_mplane src_fmt; + struct v4l2_pix_format_mplane dst_fmt; + int dst_fmt_set; + + int src_stream_on; + int dst_stream_on; + + /* + * fatal_err is set if an error has occurred s.t. decode cannot + * continue (such as running out of CMA) + */ + int fatal_err; + + /* Lock for queue operations */ + struct mutex ctx_mutex; + + struct v4l2_ctrl_handler hdl; + struct v4l2_ctrl **ctrls; + + /* + * state contains stuff that is only needed in phase0 + * it could be held in dec_env but that would be wasteful + */ + struct hevc_d_dec_state *state; + struct hevc_d_dec_env *dec0; + + /* Spinlock protecting dec_free */ + spinlock_t dec_lock; + struct hevc_d_dec_env *dec_free; + + struct hevc_d_dec_env *dec_pool; + + unsigned int p1idx; + atomic_t p1out; + + unsigned int p2idx; + struct hevc_d_gptr pu_bufs[HEVC_D_P2BUF_COUNT]; + struct hevc_d_gptr coeff_bufs[HEVC_D_P2BUF_COUNT]; + + /* Spinlock protecting aux_free */ + spinlock_t aux_lock; + struct hevc_d_q_aux *aux_free; + + struct hevc_d_q_aux *aux_ents[HEVC_D_AUX_ENT_COUNT]; + + unsigned int colmv_stride; + unsigned int colmv_picsize; +}; + +struct hevc_d_variant { + unsigned int capabilities; + unsigned int quirks; + unsigned int mod_rate; +}; + +struct hevc_d_hw_irq_ent; + +#define HEVC_D_ICTL_ENABLE_UNLIMITED (-1) + +struct hevc_d_hw_irq_ctrl { + /* Spinlock protecting claim and tail */ + spinlock_t lock; + struct hevc_d_hw_irq_ent *claim; + struct hevc_d_hw_irq_ent *tail; + + /* Ent for pending irq - also prevents sched */ + struct hevc_d_hw_irq_ent *irq; + /* Non-zero => do not start a new job - outer layer sched pending */ + int no_sched; + /* Enable count. -1 always OK, 0 do not sched, +ve shed & count down */ + int enable; + /* Thread CB requested */ + bool thread_reqed; +}; + +struct hevc_d_dev { + struct v4l2_device v4l2_dev; + struct video_device vfd; + struct media_device mdev; + struct media_pad pad[2]; + struct platform_device *pdev; + struct device *dev; + struct v4l2_m2m_dev *m2m_dev; + + /* Device file mutex */ + struct mutex dev_mutex; + + void __iomem *base_irq; + void __iomem *base_h265; + + struct clk *clock; + unsigned long max_clock_rate; + + int cache_align; + + struct hevc_d_hw_irq_ctrl ic_active1; + struct hevc_d_hw_irq_ctrl ic_active2; +}; + +struct v4l2_ctrl *hevc_d_find_ctrl(struct hevc_d_ctx *ctx, u32 id); +void *hevc_d_find_control_data(struct hevc_d_ctx *ctx, u32 id); + +#endif diff --git a/drivers/staging/media/rpivid/rpivid_h265.c b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_h265.c similarity index 67% rename from drivers/staging/media/rpivid/rpivid_h265.c rename to drivers/media/platform/raspberrypi/hevc_dec/hevc_d_h265.c index 566f65caf2a92d..6c9a9d6db15a54 100644 --- a/drivers/staging/media/rpivid/rpivid_h265.c +++ b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_h265.c @@ -2,7 +2,7 @@ /* * Raspberry Pi HEVC driver * - * Copyright (C) 2020 Raspberry Pi (Trading) Ltd + * Copyright (C) 2020 Raspberry Pi Ltd * * Based on the Cedrus VPU driver, that is: * @@ -16,34 +16,10 @@ #include -#include "rpivid.h" -#include "rpivid_hw.h" -#include "rpivid_video.h" - -#define DEBUG_TRACE_P1_CMD 0 -#define DEBUG_TRACE_EXECUTION 0 - -#define USE_REQUEST_PIN 1 - -#if DEBUG_TRACE_EXECUTION -#define xtrace_in(dev_, de_)\ - v4l2_info(&(dev_)->v4l2_dev, "%s[%d]: in\n", __func__,\ - (de_) == NULL ? -1 : (de_)->decode_order) -#define xtrace_ok(dev_, de_)\ - v4l2_info(&(dev_)->v4l2_dev, "%s[%d]: ok\n", __func__,\ - (de_) == NULL ? -1 : (de_)->decode_order) -#define xtrace_fin(dev_, de_)\ - v4l2_info(&(dev_)->v4l2_dev, "%s[%d]: finish\n", __func__,\ - (de_) == NULL ? -1 : (de_)->decode_order) -#define xtrace_fail(dev_, de_)\ - v4l2_info(&(dev_)->v4l2_dev, "%s[%d]: FAIL\n", __func__,\ - (de_) == NULL ? -1 : (de_)->decode_order) -#else -#define xtrace_in(dev_, de_) -#define xtrace_ok(dev_, de_) -#define xtrace_fin(dev_, de_) -#define xtrace_fail(dev_, de_) -#endif +#include "hevc_d.h" +#include "hevc_d_h265.h" +#include "hevc_d_hw.h" +#include "hevc_d_video.h" enum hevc_slice_type { HEVC_SLICE_B = 0, @@ -53,7 +29,7 @@ enum hevc_slice_type { enum hevc_layer { L0 = 0, L1 = 1 }; -static int gptr_alloc(struct rpivid_dev *const dev, struct rpivid_gptr *gptr, +static int gptr_alloc(struct hevc_d_dev *const dev, struct hevc_d_gptr *gptr, size_t size, unsigned long attrs) { gptr->size = size; @@ -64,8 +40,8 @@ static int gptr_alloc(struct rpivid_dev *const dev, struct rpivid_gptr *gptr, return !gptr->ptr ? -ENOMEM : 0; } -static void gptr_free(struct rpivid_dev *const dev, - struct rpivid_gptr *const gptr) +static void gptr_free(struct hevc_d_dev *const dev, + struct hevc_d_gptr *const gptr) { if (gptr->ptr) dma_free_attrs(dev->dev, gptr->size, gptr->ptr, gptr->addr, @@ -83,8 +59,8 @@ static void gptr_free(struct rpivid_dev *const dev, * On error then check gptr->ptr to determine if anything is currently * allocated. */ -static int gptr_realloc_new(struct rpivid_dev * const dev, - struct rpivid_gptr * const gptr, size_t size) +static int gptr_realloc_new(struct hevc_d_dev * const dev, + struct hevc_d_gptr * const gptr, size_t size) { const size_t old_size = gptr->size; @@ -118,7 +94,7 @@ static int gptr_realloc_new(struct rpivid_dev * const dev, static size_t next_size(const size_t x) { - return rpivid_round_up_size(x + 1); + return hevc_d_round_up_size(x + 1); } #define NUM_SCALING_FACTORS 4064 /* Not a typo = 0xbe0 + 0x400 */ @@ -130,36 +106,30 @@ static size_t next_size(const size_t x) #define HEVC_MAX_REFS V4L2_HEVC_DPB_ENTRIES_NUM_MAX -////////////////////////////////////////////////////////////////////////////// - struct rpi_cmd { u32 addr; u32 data; } __packed; -struct rpivid_q_aux { +struct hevc_d_q_aux { unsigned int refcount; unsigned int q_index; - struct rpivid_q_aux *next; - struct rpivid_gptr col; + struct hevc_d_q_aux *next; + struct hevc_d_gptr col; }; -////////////////////////////////////////////////////////////////////////////// - -enum rpivid_decode_state { - RPIVID_DECODE_SLICE_START, - RPIVID_DECODE_SLICE_CONTINUE, - RPIVID_DECODE_ERROR_CONTINUE, - RPIVID_DECODE_ERROR_DONE, - RPIVID_DECODE_PHASE1, - RPIVID_DECODE_END, +enum hevc_d_decode_state { + HEVC_D_DECODE_SLICE_START, + HEVC_D_DECODE_ERROR_DONE, + HEVC_D_DECODE_PHASE1, + HEVC_D_DECODE_END, }; -struct rpivid_dec_env { - struct rpivid_ctx *ctx; - struct rpivid_dec_env *next; +struct hevc_d_dec_env { + struct hevc_d_ctx *ctx; + struct hevc_d_dec_env *next; - enum rpivid_decode_state state; + enum hevc_d_decode_state state; unsigned int decode_order; int p1_status; /* P1 status - what to realloc */ @@ -187,14 +157,15 @@ struct rpivid_dec_env { u32 rpi_framesize; u32 rpi_currpoc; - struct vb2_v4l2_buffer *frame_buf; // Detached dest buffer - struct vb2_v4l2_buffer *src_buf; // Detached src buffer - unsigned int frame_c_offset; - unsigned int frame_stride; - dma_addr_t frame_addr; - dma_addr_t ref_addrs[16]; - struct rpivid_q_aux *frame_aux; - struct rpivid_q_aux *col_aux; + struct vb2_v4l2_buffer *frame_buf; + struct vb2_v4l2_buffer *src_buf; + dma_addr_t frame_luma_addr; + unsigned int luma_stride; + dma_addr_t frame_chroma_addr; + unsigned int chroma_stride; + dma_addr_t ref_addrs[16][2]; + struct hevc_d_q_aux *frame_aux; + struct hevc_d_q_aux *col_aux; dma_addr_t cmd_addr; size_t cmd_size; @@ -204,28 +175,19 @@ struct rpivid_dec_env { u32 pu_stride; u32 coeff_stride; - struct rpivid_gptr *bit_copy_gptr; - size_t bit_copy_len; - #define SLICE_MSGS_MAX (2 * HEVC_MAX_REFS * 8 + 3) u16 slice_msgs[SLICE_MSGS_MAX]; u8 scaling_factors[NUM_SCALING_FACTORS]; -#if USE_REQUEST_PIN struct media_request *req_pin; -#else - struct media_request_object *req_obj; -#endif - struct rpivid_hw_irq_ent irq_ent; + struct hevc_d_hw_irq_ent irq_ent; }; -#define member_size(type, member) sizeof(((type *)0)->member) - -struct rpivid_dec_state { +struct hevc_d_dec_state { struct v4l2_ctrl_hevc_sps sps; struct v4l2_ctrl_hevc_pps pps; - // Helper vars & tables derived from sps/pps + /* Helper vars & tables derived from sps/pps */ unsigned int log2_ctb_size; /* log2 width of a CTB */ unsigned int ctb_width; /* Width in CTBs */ unsigned int ctb_height; /* Height in CTBs */ @@ -238,19 +200,17 @@ struct rpivid_dec_state { int *ctb_addr_rs_to_ts; int *ctb_addr_ts_to_rs; - // Aux starage for DPB - // Hold refs - struct rpivid_q_aux *ref_aux[HEVC_MAX_REFS]; - struct rpivid_q_aux *frame_aux; + /* Aux starage for DPB */ + struct hevc_d_q_aux *ref_aux[HEVC_MAX_REFS]; + struct hevc_d_q_aux *frame_aux; - // Slice vars + /* Slice vars */ unsigned int slice_idx; bool slice_temporal_mvp; /* Slice flag but constant for frame */ bool use_aux; bool mk_aux; - // Temp vars per run - don't actually need to persist - u8 *src_buf; + /* Temp vars per run - don't actually need to persist */ dma_addr_t src_addr; const struct v4l2_ctrl_hevc_slice_params *sh; const struct v4l2_ctrl_hevc_decode_params *dec; @@ -266,30 +226,13 @@ struct rpivid_dec_state { unsigned int prev_ctb_y; }; -#if !USE_REQUEST_PIN -static void dst_req_obj_release(struct media_request_object *object) -{ - kfree(object); -} - -static const struct media_request_object_ops dst_req_obj_ops = { - .release = dst_req_obj_release, -}; -#endif - static inline int clip_int(const int x, const int lo, const int hi) { return x < lo ? lo : x > hi ? hi : x; } -////////////////////////////////////////////////////////////////////////////// -// Phase 1 command and bit FIFOs - -#if DEBUG_TRACE_P1_CMD -static int p1_z; -#endif - -static int cmds_check_space(struct rpivid_dec_env *const de, unsigned int n) +/* Phase 1 command and bit FIFOs */ +static int cmds_check_space(struct hevc_d_dec_env *const de, unsigned int n) { struct rpi_cmd *a; unsigned int newmax; @@ -322,7 +265,7 @@ static int cmds_check_space(struct rpivid_dec_env *const de, unsigned int n) } // ???? u16 addr - put in u32 -static void p1_apb_write(struct rpivid_dec_env *const de, const u16 addr, +static void p1_apb_write(struct hevc_d_dec_env *const de, const u16 addr, const u32 data) { if (de->cmd_len >= de->cmd_max) { @@ -334,12 +277,6 @@ static void p1_apb_write(struct rpivid_dec_env *const de, const u16 addr, de->cmd_fifo[de->cmd_len].addr = addr; de->cmd_fifo[de->cmd_len].data = data; -#if DEBUG_TRACE_P1_CMD - if (++p1_z < 256) { - v4l2_info(&de->ctx->dev->v4l2_dev, "[%02x] %x %x\n", - de->cmd_len, addr, data); - } -#endif de->cmd_len++; } @@ -348,36 +285,37 @@ static int ctb_to_tile(unsigned int ctb, unsigned int *bd, int num) int i; for (i = 1; ctb >= bd[i]; i++) - ; // bd[] has num+1 elements; bd[0]=0; + ; /* bd[] has num+1 elements; bd[0]=0; */ + return i - 1; } -static unsigned int ctb_to_tile_x(const struct rpivid_dec_state *const s, +static unsigned int ctb_to_tile_x(const struct hevc_d_dec_state *const s, const unsigned int ctb_x) { return ctb_to_tile(ctb_x, s->col_bd, s->tile_width); } -static unsigned int ctb_to_tile_y(const struct rpivid_dec_state *const s, +static unsigned int ctb_to_tile_y(const struct hevc_d_dec_state *const s, const unsigned int ctb_y) { return ctb_to_tile(ctb_y, s->row_bd, s->tile_height); } -static void aux_q_free(struct rpivid_ctx *const ctx, - struct rpivid_q_aux *const aq) +static void aux_q_free(struct hevc_d_ctx *const ctx, + struct hevc_d_q_aux *const aq) { - struct rpivid_dev *const dev = ctx->dev; + struct hevc_d_dev *const dev = ctx->dev; gptr_free(dev, &aq->col); kfree(aq); } -static struct rpivid_q_aux *aux_q_alloc(struct rpivid_ctx *const ctx, +static struct hevc_d_q_aux *aux_q_alloc(struct hevc_d_ctx *const ctx, const unsigned int q_index) { - struct rpivid_dev *const dev = ctx->dev; - struct rpivid_q_aux *const aq = kzalloc(sizeof(*aq), GFP_KERNEL); + struct hevc_d_dev *const dev = ctx->dev; + struct hevc_d_q_aux *const aq = kzalloc(sizeof(*aq), GFP_KERNEL); if (!aq) return NULL; @@ -400,10 +338,10 @@ static struct rpivid_q_aux *aux_q_alloc(struct rpivid_ctx *const ctx, return NULL; } -static struct rpivid_q_aux *aux_q_new(struct rpivid_ctx *const ctx, +static struct hevc_d_q_aux *aux_q_new(struct hevc_d_ctx *const ctx, const unsigned int q_index) { - struct rpivid_q_aux *aq; + struct hevc_d_q_aux *aq; unsigned long lockflags; spin_lock_irqsave(&ctx->aux_lock, lockflags); @@ -411,14 +349,18 @@ static struct rpivid_q_aux *aux_q_new(struct rpivid_ctx *const ctx, * If we already have this allocated to a slot then use that * and assume that it will all work itself out in the pipeline */ - if ((aq = ctx->aux_ents[q_index]) != NULL) { + aq = ctx->aux_ents[q_index]; + if (aq) { ++aq->refcount; - } else if ((aq = ctx->aux_free) != NULL) { - ctx->aux_free = aq->next; - aq->next = NULL; - aq->refcount = 1; - aq->q_index = q_index; - ctx->aux_ents[q_index] = aq; + } else { + aq = ctx->aux_free; + if (aq) { + ctx->aux_free = aq->next; + aq->next = NULL; + aq->refcount = 1; + aq->q_index = q_index; + ctx->aux_ents[q_index] = aq; + } } spin_unlock_irqrestore(&ctx->aux_lock, lockflags); @@ -428,39 +370,38 @@ static struct rpivid_q_aux *aux_q_new(struct rpivid_ctx *const ctx, return aq; } -static struct rpivid_q_aux *aux_q_ref_idx(struct rpivid_ctx *const ctx, +static struct hevc_d_q_aux *aux_q_ref_idx(struct hevc_d_ctx *const ctx, const int q_index) { unsigned long lockflags; - struct rpivid_q_aux *aq; + struct hevc_d_q_aux *aq; spin_lock_irqsave(&ctx->aux_lock, lockflags); - if ((aq = ctx->aux_ents[q_index]) != NULL) + aq = ctx->aux_ents[q_index]; + if (aq) ++aq->refcount; spin_unlock_irqrestore(&ctx->aux_lock, lockflags); return aq; } -static struct rpivid_q_aux *aux_q_ref(struct rpivid_ctx *const ctx, - struct rpivid_q_aux *const aq) +static struct hevc_d_q_aux *aux_q_ref(struct hevc_d_ctx *const ctx, + struct hevc_d_q_aux *const aq) { - if (aq) { - unsigned long lockflags; + unsigned long lockflags; + if (aq) { spin_lock_irqsave(&ctx->aux_lock, lockflags); - ++aq->refcount; - spin_unlock_irqrestore(&ctx->aux_lock, lockflags); } return aq; } -static void aux_q_release(struct rpivid_ctx *const ctx, - struct rpivid_q_aux **const paq) +static void aux_q_release(struct hevc_d_ctx *const ctx, + struct hevc_d_q_aux **const paq) { - struct rpivid_q_aux *const aq = *paq; + struct hevc_d_q_aux *const aq = *paq; unsigned long lockflags; if (!aq) @@ -478,15 +419,15 @@ static void aux_q_release(struct rpivid_ctx *const ctx, spin_unlock_irqrestore(&ctx->aux_lock, lockflags); } -static void aux_q_init(struct rpivid_ctx *const ctx) +static void aux_q_init(struct hevc_d_ctx *const ctx) { spin_lock_init(&ctx->aux_lock); ctx->aux_free = NULL; } -static void aux_q_uninit(struct rpivid_ctx *const ctx) +static void aux_q_uninit(struct hevc_d_ctx *const ctx) { - struct rpivid_q_aux *aq; + struct hevc_d_q_aux *aq; ctx->colmv_picsize = 0; ctx->colmv_stride = 0; @@ -496,8 +437,6 @@ static void aux_q_uninit(struct rpivid_ctx *const ctx) } } -////////////////////////////////////////////////////////////////////////////// - /* * Initialisation process for context variables (CABAC init) * see H.265 9.3.2.2 @@ -558,18 +497,18 @@ static const u8 prob_init[3][156] = { }; #define CMDS_WRITE_PROB ((RPI_PROB_ARRAY_SIZE / 4) + 1) -static void write_prob(struct rpivid_dec_env *const de, - const struct rpivid_dec_state *const s) -{ - u8 dst[RPI_PROB_ARRAY_SIZE]; +static void write_prob(struct hevc_d_dec_env *const de, + const struct hevc_d_dec_state *const s) +{ const unsigned int init_type = ((s->sh->flags & V4L2_HEVC_SLICE_PARAMS_FLAG_CABAC_INIT) != 0 && s->sh->slice_type != HEVC_SLICE_I) ? s->sh->slice_type + 1 : 2 - s->sh->slice_type; - const u8 *p = prob_init[init_type]; const int q = clip_int(s->slice_qp, 0, 51); + const u8 *p = prob_init[init_type]; + u8 dst[RPI_PROB_ARRAY_SIZE]; unsigned int i; for (i = 0; i < RPI_PROB_VALS; i++) { @@ -602,10 +541,10 @@ static void write_prob(struct rpivid_dec_env *const de, } #define CMDS_WRITE_SCALING_FACTORS NUM_SCALING_FACTORS -static void write_scaling_factors(struct rpivid_dec_env *const de) +static void write_scaling_factors(struct hevc_d_dec_env *const de) { - int i; const u8 *p = (u8 *)de->scaling_factors; + int i; for (i = 0; i < NUM_SCALING_FACTORS; i += 4, p += 4) p1_apb_write(de, 0x2000 + i, @@ -618,9 +557,10 @@ static inline __u32 dma_to_axi_addr(dma_addr_t a) } #define CMDS_WRITE_BITSTREAM 4 -static int write_bitstream(struct rpivid_dec_env *const de, - const struct rpivid_dec_state *const s) +static int write_bitstream(struct hevc_d_dec_env *const de, + const struct hevc_d_dec_state *const s) { + // FIXME!!!! // Note that FFmpeg V4L2 does not remove emulation prevention bytes, // so this is matched in the configuration here. // Whether that is the correct behaviour or not is not clear in the @@ -628,23 +568,8 @@ static int write_bitstream(struct rpivid_dec_env *const de, const int rpi_use_emu = 1; unsigned int offset = s->sh->data_byte_offset; const unsigned int len = (s->sh->bit_size + 7) / 8 - offset; - dma_addr_t addr; + dma_addr_t addr = s->src_addr + offset; - if (s->src_addr != 0) { - addr = s->src_addr + offset; - } else { - if (len + de->bit_copy_len > de->bit_copy_gptr->size) { - v4l2_warn(&de->ctx->dev->v4l2_dev, - "Bit copy buffer overflow: size=%zu, offset=%zu, len=%u\n", - de->bit_copy_gptr->size, - de->bit_copy_len, len); - return -ENOMEM; - } - memcpy(de->bit_copy_gptr->ptr + de->bit_copy_len, - s->src_buf + offset, len); - addr = de->bit_copy_gptr->addr + de->bit_copy_len; - de->bit_copy_len += (len + 63) & ~63; - } offset = addr & 63; p1_apb_write(de, RPI_BFBASE, dma_to_axi_addr(addr)); @@ -654,13 +579,11 @@ static int write_bitstream(struct rpivid_dec_env *const de, return 0; } -////////////////////////////////////////////////////////////////////////////// - /* * The slice constant part of the slice register - width and height need to * be ORed in later as they are per-tile / WPP-row */ -static u32 slice_reg_const(const struct rpivid_dec_state *const s) +static u32 slice_reg_const(const struct hevc_d_dec_state *const s) { u32 x = (s->max_num_merge_cand << 0) | (s->nb_refs[L0] << 4) | @@ -678,11 +601,10 @@ static u32 slice_reg_const(const struct rpivid_dec_state *const s) return x; } -////////////////////////////////////////////////////////////////////////////// - #define CMDS_NEW_SLICE_SEGMENT (4 + CMDS_WRITE_SCALING_FACTORS) -static void new_slice_segment(struct rpivid_dec_env *const de, - const struct rpivid_dec_state *const s) + +static void new_slice_segment(struct hevc_d_dec_env *const de, + const struct hevc_d_dec_state *const s) { const struct v4l2_ctrl_hevc_sps *const sps = &s->sps; const struct v4l2_ctrl_hevc_pps *const pps = &s->pps; @@ -757,16 +679,15 @@ static void new_slice_segment(struct rpivid_dec_env *const de, p1_apb_write(de, RPI_SLICESTART, de->reg_slicestart); } -////////////////////////////////////////////////////////////////////////////// -// Slice messages +/* Slice messages */ -static void msg_slice(struct rpivid_dec_env *const de, const u16 msg) +static void msg_slice(struct hevc_d_dec_env *const de, const u16 msg) { de->slice_msgs[de->num_slice_msgs++] = msg; } #define CMDS_PROGRAM_SLICECMDS (1 + SLICE_MSGS_MAX) -static void program_slicecmds(struct rpivid_dec_env *const de, +static void program_slicecmds(struct hevc_d_dec_env *const de, const int sliceid) { int i; @@ -777,8 +698,7 @@ static void program_slicecmds(struct rpivid_dec_env *const de, p1_apb_write(de, 0x4000 + 4 * i, de->slice_msgs[i] & 0xffff); } -// NoBackwardPredictionFlag 8.3.5 -// Simply checks POCs +/* NoBackwardPredictionFlag 8.3.5 - Simply checks POCs */ static int has_backward(const struct v4l2_hevc_dpb_entry *const dpb, const __u8 *const idx, const unsigned int n, const s32 cur_poc) @@ -792,8 +712,8 @@ static int has_backward(const struct v4l2_hevc_dpb_entry *const dpb, return 1; } -static void pre_slice_decode(struct rpivid_dec_env *const de, - const struct rpivid_dec_state *const s) +static void pre_slice_decode(struct hevc_d_dec_env *const de, + const struct hevc_d_dec_state *const s) { const struct v4l2_ctrl_hevc_slice_params *const sh = s->sh; const struct v4l2_ctrl_hevc_decode_params *const dec = s->dec; @@ -821,7 +741,7 @@ static void pre_slice_decode(struct rpivid_dec_env *const de, cmd_slice |= collocated_from_l0_flag << 14; if (sh->slice_type == HEVC_SLICE_P || sh->slice_type == HEVC_SLICE_B) { - // Flag to say all reference pictures are from the past + /* Flag to say all reference pictures are from the past */ const int no_backward_pred_flag = has_backward(dec->dpb, sh->ref_idx_l0, s->nb_refs[L0], sh->slice_pic_order_cnt) && @@ -834,13 +754,9 @@ static void pre_slice_decode(struct rpivid_dec_env *const de, const __u8 *const rpl = collocated_from_l0_flag ? sh->ref_idx_l0 : sh->ref_idx_l1; de->dpbno_col = rpl[sh->collocated_ref_idx]; - //v4l2_info(&de->ctx->dev->v4l2_dev, - // "L0=%d col_ref_idx=%d, - // dpb_no=%d\n", collocated_from_l0_flag, - // sh->collocated_ref_idx, de->dpbno_col); } - // Write reference picture descriptions + /* Write reference picture descriptions */ weighted_pred_flag = sh->slice_type == HEVC_SLICE_P ? !!(s->pps.flags & V4L2_HEVC_PPS_FLAG_WEIGHTED_PRED) : @@ -848,8 +764,6 @@ static void pre_slice_decode(struct rpivid_dec_env *const de, for (idx = 0; idx < s->nb_refs[L0]; ++idx) { unsigned int dpb_no = sh->ref_idx_l0[idx]; - //v4l2_info(&de->ctx->dev->v4l2_dev, - // "L0[%d]=dpb[%d]\n", idx, dpb_no); msg_slice(de, dpb_no | @@ -895,8 +809,7 @@ static void pre_slice_decode(struct rpivid_dec_env *const de, for (idx = 0; idx < s->nb_refs[L1]; ++idx) { unsigned int dpb_no = sh->ref_idx_l1[idx]; - //v4l2_info(&de->ctx->dev->v4l2_dev, - // "L1[%d]=dpb[%d]\n", idx, dpb_no); + msg_slice(de, dpb_no | ((dec->dpb[dpb_no].flags & @@ -954,12 +867,12 @@ static void pre_slice_decode(struct rpivid_dec_env *const de, 1 << 10 : 0)); msg_slice(de, ((sh->slice_cr_qp_offset & 31) << 5) + - (sh->slice_cb_qp_offset & 31)); // CMD_QPOFF + (sh->slice_cb_qp_offset & 31)); /* CMD_QPOFF */ } #define CMDS_WRITE_SLICE 1 -static void write_slice(struct rpivid_dec_env *const de, - const struct rpivid_dec_state *const s, +static void write_slice(struct hevc_d_dec_env *const de, + const struct hevc_d_dec_state *const s, const u32 slice_const, const unsigned int ctb_col, const unsigned int ctb_row) @@ -984,8 +897,9 @@ static void write_slice(struct rpivid_dec_env *const de, * use any state data that may change from slice to slice (e.g. qp) */ #define CMDS_NEW_ENTRY_POINT (6 + CMDS_WRITE_SLICE) -static void new_entry_point(struct rpivid_dec_env *const de, - const struct rpivid_dec_state *const s, + +static void new_entry_point(struct hevc_d_dec_env *const de, + const struct hevc_d_dec_state *const s, const bool do_bte, const bool reset_qp_y, const u32 pause_mode, @@ -1031,11 +945,10 @@ static void new_entry_point(struct rpivid_dec_env *const de, de->entry_slice = slice_const; } -////////////////////////////////////////////////////////////////////////////// -// Wavefront mode +/* Wavefront mode */ #define CMDS_WPP_PAUSE 4 -static void wpp_pause(struct rpivid_dec_env *const de, int ctb_row) +static void wpp_pause(struct hevc_d_dec_env *const de, int ctb_row) { p1_apb_write(de, RPI_STATUS, (ctb_row << 18) | 0x25); p1_apb_write(de, RPI_TRANSFER, PROB_BACKUP); @@ -1046,8 +959,8 @@ static void wpp_pause(struct rpivid_dec_env *const de, int ctb_row) } #define CMDS_WPP_ENTRY_FILL_1 (CMDS_WPP_PAUSE + 2 + CMDS_NEW_ENTRY_POINT) -static int wpp_entry_fill(struct rpivid_dec_env *const de, - const struct rpivid_dec_state *const s, +static int wpp_entry_fill(struct hevc_d_dec_env *const de, + const struct hevc_d_dec_state *const s, const unsigned int last_y) { int rv; @@ -1078,8 +991,8 @@ static int wpp_entry_fill(struct rpivid_dec_env *const de, return 0; } -static int wpp_end_previous_slice(struct rpivid_dec_env *const de, - const struct rpivid_dec_state *const s) +static int wpp_end_previous_slice(struct hevc_d_dec_env *const de, + const struct hevc_d_dec_state *const s) { int rv; @@ -1103,11 +1016,12 @@ static int wpp_end_previous_slice(struct rpivid_dec_env *const de, return 0; } -/* Only main profile supported so WPP => !Tiles which makes some of the +/* + * Only main profile supported so WPP => !Tiles which makes some of the * next chunk code simpler */ -static int wpp_decode_slice(struct rpivid_dec_env *const de, - const struct rpivid_dec_state *const s, +static int wpp_decode_slice(struct hevc_d_dec_env *const de, + const struct hevc_d_dec_state *const s, bool last_slice) { bool reset_qp_y = true; @@ -1166,12 +1080,11 @@ static int wpp_decode_slice(struct rpivid_dec_env *const de, return 0; } -////////////////////////////////////////////////////////////////////////////// -// Tiles mode +/* Tiles mode */ -// Guarantees 1 cmd entry free on exit -static int tile_entry_fill(struct rpivid_dec_env *const de, - const struct rpivid_dec_state *const s, +/* Guarantees 1 cmd entry free on exit */ +static int tile_entry_fill(struct hevc_d_dec_env *const de, + const struct hevc_d_dec_state *const s, const unsigned int last_tile_x, const unsigned int last_tile_y) { @@ -1184,7 +1097,7 @@ static int tile_entry_fill(struct rpivid_dec_env *const de, const unsigned int last_x = s->col_bd[t_x + 1] - 1; const unsigned int last_y = s->row_bd[t_y + 1] - 1; - // One more than needed here + /* One more than needed here */ rv = cmds_check_space(de, CMDS_NEW_ENTRY_POINT + 3); if (rv) return rv; @@ -1206,11 +1119,9 @@ static int tile_entry_fill(struct rpivid_dec_env *const de, return 0; } -/* - * Write STATUS register with expected end CTU address of previous slice - */ -static int end_previous_slice(struct rpivid_dec_env *const de, - const struct rpivid_dec_state *const s) +/* Write STATUS register with expected end CTU address of previous slice */ +static int end_previous_slice(struct hevc_d_dec_env *const de, + const struct hevc_d_dec_state *const s) { int rv; @@ -1225,8 +1136,8 @@ static int end_previous_slice(struct rpivid_dec_env *const de, return 0; } -static int decode_slice(struct rpivid_dec_env *const de, - const struct rpivid_dec_state *const s, +static int decode_slice(struct hevc_d_dec_env *const de, + const struct hevc_d_dec_state *const s, bool last_slice) { bool reset_qp_y; @@ -1286,8 +1197,7 @@ static int decode_slice(struct rpivid_dec_env *const de, return 0; } -////////////////////////////////////////////////////////////////////////////// -// Scaling factors +/* Scaling factors */ static void expand_scaling_list(const unsigned int size_id, u8 *const dst0, @@ -1334,25 +1244,26 @@ static void expand_scaling_list(const unsigned int size_id, } } -static void populate_scaling_factors(const struct rpivid_run *const run, - struct rpivid_dec_env *const de, - const struct rpivid_dec_state *const s) +static void populate_scaling_factors(const struct hevc_d_run *const run, + struct hevc_d_dec_env *const de, + const struct hevc_d_dec_state *const s) { const struct v4l2_ctrl_hevc_scaling_matrix *const sl = run->h265.scaling_matrix; - // Array of constants for scaling factors + /* Array of constants for scaling factors */ static const u32 scaling_factor_offsets[4][6] = { - // MID0 MID1 MID2 MID3 MID4 MID5 - // SID0 (4x4) + /* + * MID0 MID1 MID2 MID3 MID4 MID5 + */ + /* SID0 (4x4) */ { 0x0000, 0x0010, 0x0020, 0x0030, 0x0040, 0x0050 }, - // SID1 (8x8) + /* SID1 (8x8) */ { 0x0060, 0x00A0, 0x00E0, 0x0120, 0x0160, 0x01A0 }, - // SID2 (16x16) + /* SID2 (16x16) */ { 0x01E0, 0x02E0, 0x03E0, 0x04E0, 0x05E0, 0x06E0 }, - // SID3 (32x32) + /* SID3 (32x32) */ { 0x07E0, 0x0BE0, 0x0000, 0x0000, 0x0000, 0x0000 } }; - unsigned int mid; for (mid = 0; mid < 6; mid++) @@ -1375,7 +1286,7 @@ static void populate_scaling_factors(const struct rpivid_run *const run, sl->scaling_list_dc_coef_32x32[mid]); } -static void free_ps_info(struct rpivid_dec_state *const s) +static void free_ps_info(struct hevc_d_dec_state *const s) { kfree(s->ctb_addr_rs_to_ts); s->ctb_addr_rs_to_ts = NULL; @@ -1388,19 +1299,19 @@ static void free_ps_info(struct rpivid_dec_state *const s) s->row_bd = NULL; } -static unsigned int tile_width(const struct rpivid_dec_state *const s, +static unsigned int tile_width(const struct hevc_d_dec_state *const s, const unsigned int t_x) { return s->col_bd[t_x + 1] - s->col_bd[t_x]; } -static unsigned int tile_height(const struct rpivid_dec_state *const s, +static unsigned int tile_height(const struct hevc_d_dec_state *const s, const unsigned int t_y) { return s->row_bd[t_y + 1] - s->row_bd[t_y]; } -static void fill_rs_to_ts(struct rpivid_dec_state *const s) +static void fill_rs_to_ts(struct hevc_d_dec_state *const s) { unsigned int ts = 0; unsigned int t_y; @@ -1432,13 +1343,13 @@ static void fill_rs_to_ts(struct rpivid_dec_state *const s) } } -static int updated_ps(struct rpivid_dec_state *const s) +static int updated_ps(struct hevc_d_dec_state *const s) { unsigned int i; free_ps_info(s); - // Inferred parameters + /* Inferred parameters */ s->log2_ctb_size = s->sps.log2_min_luma_coding_block_size_minus3 + 3 + s->sps.log2_diff_max_min_luma_coding_block_size; @@ -1450,8 +1361,6 @@ static int updated_ps(struct rpivid_dec_state *const s) s->log2_ctb_size; s->ctb_size = s->ctb_width * s->ctb_height; - // Inferred parameters - s->ctb_addr_rs_to_ts = kmalloc_array(s->ctb_size, sizeof(*s->ctb_addr_rs_to_ts), GFP_KERNEL); @@ -1471,12 +1380,12 @@ static int updated_ps(struct rpivid_dec_state *const s) s->tile_height = s->pps.num_tile_rows_minus1 + 1; } - s->col_bd = kmalloc((s->tile_width + 1) * sizeof(*s->col_bd), - GFP_KERNEL); + s->col_bd = kmalloc_array((s->tile_width + 1), sizeof(*s->col_bd), + GFP_KERNEL); if (!s->col_bd) goto fail; - s->row_bd = kmalloc((s->tile_height + 1) * sizeof(*s->row_bd), - GFP_KERNEL); + s->row_bd = kmalloc_array((s->tile_height + 1), sizeof(*s->row_bd), + GFP_KERNEL); if (!s->row_bd) goto fail; @@ -1502,9 +1411,9 @@ static int updated_ps(struct rpivid_dec_state *const s) return -ENOMEM; } -static int write_cmd_buffer(struct rpivid_dev *const dev, - struct rpivid_dec_env *const de, - const struct rpivid_dec_state *const s) +static int write_cmd_buffer(struct hevc_d_dev *const dev, + struct hevc_d_dec_env *const de, + const struct hevc_d_dec_state *const s) { const size_t cmd_size = ALIGN(de->cmd_len * sizeof(de->cmd_fifo[0]), dev->cache_align); @@ -1520,18 +1429,17 @@ static int write_cmd_buffer(struct rpivid_dev *const dev, return 0; } -static void setup_colmv(struct rpivid_ctx *const ctx, struct rpivid_run *run, - struct rpivid_dec_state *const s) +static void setup_colmv(struct hevc_d_ctx *const ctx, struct hevc_d_run *run, + struct hevc_d_dec_state *const s) { ctx->colmv_stride = ALIGN(s->sps.pic_width_in_luma_samples, 64); ctx->colmv_picsize = ctx->colmv_stride * (ALIGN(s->sps.pic_height_in_luma_samples, 64) >> 4); } -// Can be called from irq context -static struct rpivid_dec_env *dec_env_new(struct rpivid_ctx *const ctx) +static struct hevc_d_dec_env *dec_env_new(struct hevc_d_ctx *const ctx) { - struct rpivid_dec_env *de; + struct hevc_d_dec_env *de; unsigned long lock_flags; spin_lock_irqsave(&ctx->dec_lock, lock_flags); @@ -1540,17 +1448,17 @@ static struct rpivid_dec_env *dec_env_new(struct rpivid_ctx *const ctx) if (de) { ctx->dec_free = de->next; de->next = NULL; - de->state = RPIVID_DECODE_SLICE_START; + de->state = HEVC_D_DECODE_SLICE_START; } spin_unlock_irqrestore(&ctx->dec_lock, lock_flags); return de; } -// Can be called from irq context -static void dec_env_delete(struct rpivid_dec_env *const de) +/* Can be called from irq context */ +static void dec_env_delete(struct hevc_d_dec_env *const de) { - struct rpivid_ctx * const ctx = de->ctx; + struct hevc_d_ctx * const ctx = de->ctx; unsigned long lock_flags; if (de->cmd_size) { @@ -1564,20 +1472,20 @@ static void dec_env_delete(struct rpivid_dec_env *const de) spin_lock_irqsave(&ctx->dec_lock, lock_flags); - de->state = RPIVID_DECODE_END; + de->state = HEVC_D_DECODE_END; de->next = ctx->dec_free; ctx->dec_free = de; spin_unlock_irqrestore(&ctx->dec_lock, lock_flags); } -static void dec_env_uninit(struct rpivid_ctx *const ctx) +static void dec_env_uninit(struct hevc_d_ctx *const ctx) { unsigned int i; if (ctx->dec_pool) { - for (i = 0; i != RPIVID_DEC_ENV_COUNT; ++i) { - struct rpivid_dec_env *const de = ctx->dec_pool + i; + for (i = 0; i != HEVC_D_DEC_ENV_COUNT; ++i) { + struct hevc_d_dec_env *const de = ctx->dec_pool + i; kfree(de->cmd_fifo); } @@ -1589,29 +1497,26 @@ static void dec_env_uninit(struct rpivid_ctx *const ctx) ctx->dec_free = NULL; } -static int dec_env_init(struct rpivid_ctx *const ctx) +static int dec_env_init(struct hevc_d_ctx *const ctx) { unsigned int i; - ctx->dec_pool = kzalloc(sizeof(*ctx->dec_pool) * RPIVID_DEC_ENV_COUNT, + ctx->dec_pool = kzalloc(sizeof(*ctx->dec_pool) * HEVC_D_DEC_ENV_COUNT, GFP_KERNEL); if (!ctx->dec_pool) return -1; spin_lock_init(&ctx->dec_lock); - // Build free chain ctx->dec_free = ctx->dec_pool; - for (i = 0; i != RPIVID_DEC_ENV_COUNT - 1; ++i) + for (i = 0; i != HEVC_D_DEC_ENV_COUNT - 1; ++i) ctx->dec_pool[i].next = ctx->dec_pool + i + 1; - // Fill in other bits - for (i = 0; i != RPIVID_DEC_ENV_COUNT; ++i) { - struct rpivid_dec_env *const de = ctx->dec_pool + i; + for (i = 0; i != HEVC_D_DEC_ENV_COUNT; ++i) { + struct hevc_d_dec_env *const de = ctx->dec_pool + i; de->ctx = ctx; de->decode_order = i; -// de->cmd_max = 1024; de->cmd_max = 8096; de->cmd_fifo = kmalloc_array(de->cmd_max, sizeof(struct rpi_cmd), @@ -1627,26 +1532,25 @@ static int dec_env_init(struct rpivid_ctx *const ctx) return -1; } -// Assume that we get exactly the same DPB for every slice -// it makes no real sense otherwise +/* + * Assume that we get exactly the same DPB for every slice it makes no real + * sense otherwise. + */ #if V4L2_HEVC_DPB_ENTRIES_NUM_MAX > 16 #error HEVC_DPB_ENTRIES > h/w slots #endif -static u32 mk_config2(const struct rpivid_dec_state *const s) +static u32 mk_config2(const struct hevc_d_dec_state *const s) { const struct v4l2_ctrl_hevc_sps *const sps = &s->sps; const struct v4l2_ctrl_hevc_pps *const pps = &s->pps; u32 c; - // BitDepthY - c = (sps->bit_depth_luma_minus8 + 8) << 0; - // BitDepthC - c |= (sps->bit_depth_chroma_minus8 + 8) << 4; - // BitDepthY - if (sps->bit_depth_luma_minus8) + + c = (sps->bit_depth_luma_minus8 + 8) << 0; /* BitDepthY */ + c |= (sps->bit_depth_chroma_minus8 + 8) << 4; /* BitDepthC */ + if (sps->bit_depth_luma_minus8) /* BitDepthY */ c |= BIT(8); - // BitDepthC - if (sps->bit_depth_chroma_minus8) + if (sps->bit_depth_chroma_minus8) /* BitDepthC */ c |= BIT(9); c |= s->log2_ctb_size << 10; if (pps->flags & V4L2_HEVC_PPS_FLAG_CONSTRAINED_INTRA_PRED) @@ -1673,9 +1577,9 @@ static inline bool is_ref_unit_type(const unsigned int nal_unit_type) return (nal_unit_type & ~0xe) != 0; } -static void rpivid_h265_setup(struct rpivid_ctx *ctx, struct rpivid_run *run) +void hevc_d_h265_setup(struct hevc_d_ctx *ctx, struct hevc_d_run *run) { - struct rpivid_dev *const dev = ctx->dev; + struct hevc_d_dev *const dev = ctx->dev; const struct v4l2_ctrl_hevc_decode_params *const dec = run->h265.dec; /* sh0 used where slice header contents should be constant over all @@ -1683,232 +1587,218 @@ static void rpivid_h265_setup(struct rpivid_ctx *ctx, struct rpivid_run *run) */ const struct v4l2_ctrl_hevc_slice_params *const sh0 = run->h265.slice_params; - struct rpivid_q_aux *dpb_q_aux[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; - struct rpivid_dec_state *const s = ctx->state; + struct hevc_d_q_aux *dpb_q_aux[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; + struct hevc_d_dec_state *const s = ctx->state; struct vb2_queue *vq; - struct rpivid_dec_env *de = ctx->dec0; + struct hevc_d_dec_env *de = ctx->dec0; unsigned int prev_rs; unsigned int i; int rv; bool slice_temporal_mvp; - bool frame_end; + unsigned int ctb_size_y; + bool sps_changed = false; - xtrace_in(dev, de); - s->sh = NULL; // Avoid use until in the slice loop - - frame_end = - ((run->src->flags & V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF) == 0); + s->sh = NULL; /* Avoid use until in the slice loop */ slice_temporal_mvp = (sh0->flags & V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_TEMPORAL_MVP_ENABLED); - if (de && de->state != RPIVID_DECODE_END) { - switch (de->state) { - case RPIVID_DECODE_SLICE_CONTINUE: - // Expected state - break; - default: - v4l2_err(&dev->v4l2_dev, "%s: Unexpected state: %d\n", - __func__, de->state); - fallthrough; - case RPIVID_DECODE_ERROR_CONTINUE: - // Uncleared error - fail now - goto fail; - } + if (de) { + v4l2_warn(&dev->v4l2_dev, "Decode env set unexpectedly"); + goto fail; + } - if (s->slice_temporal_mvp != slice_temporal_mvp) { - v4l2_warn(&dev->v4l2_dev, - "Slice Temporal MVP non-constant\n"); - goto fail; - } - } else { - /* Frame start */ - unsigned int ctb_size_y; - bool sps_changed = false; + /* Frame start */ + + if (!is_sps_set(run->h265.sps)) { + v4l2_warn(&dev->v4l2_dev, "SPS never set\n"); + goto fail; + } + /* Can't check for PPS easily as all 0's looks valid */ + + if (memcmp(&s->sps, run->h265.sps, sizeof(s->sps)) != 0) { + /* SPS changed */ + memcpy(&s->sps, run->h265.sps, sizeof(s->sps)); + sps_changed = true; + } + if (sps_changed || + memcmp(&s->pps, run->h265.pps, sizeof(s->pps)) != 0) { + /* SPS changed */ + memcpy(&s->pps, run->h265.pps, sizeof(s->pps)); - if (!is_sps_set(run->h265.sps)) { - v4l2_warn(&dev->v4l2_dev, "SPS never set\n"); + /* Recalc stuff as required */ + rv = updated_ps(s); + if (rv) goto fail; - } - // Can't check for PPS easily as all 0's looks valid to me + } - if (memcmp(&s->sps, run->h265.sps, sizeof(s->sps)) != 0) { - /* SPS changed */ - v4l2_info(&dev->v4l2_dev, "SPS changed\n"); - memcpy(&s->sps, run->h265.sps, sizeof(s->sps)); - sps_changed = true; - } - if (sps_changed || - memcmp(&s->pps, run->h265.pps, sizeof(s->pps)) != 0) { - /* SPS changed */ - v4l2_info(&dev->v4l2_dev, "PPS changed\n"); - memcpy(&s->pps, run->h265.pps, sizeof(s->pps)); - - /* Recalc stuff as required */ - rv = updated_ps(s); - if (rv) - goto fail; - } + de = dec_env_new(ctx); + if (!de) { + v4l2_err(&dev->v4l2_dev, "Failed to find free decode env\n"); + goto fail; + } + ctx->dec0 = de; + + ctb_size_y = + 1U << (s->sps.log2_min_luma_coding_block_size_minus3 + + 3 + s->sps.log2_diff_max_min_luma_coding_block_size); + + de->pic_width_in_ctbs_y = + (s->sps.pic_width_in_luma_samples + ctb_size_y - 1) / + ctb_size_y; /* 7-15 */ + de->pic_height_in_ctbs_y = + (s->sps.pic_height_in_luma_samples + ctb_size_y - 1) / + ctb_size_y; /* 7-17 */ + de->cmd_len = 0; + de->dpbno_col = ~0U; + + switch (ctx->dst_fmt.pixelformat) { + case V4L2_PIX_FMT_NV12MT_COL128: + case V4L2_PIX_FMT_NV12MT_10_COL128: + de->luma_stride = ctx->dst_fmt.height * 128; + de->frame_luma_addr = + vb2_dma_contig_plane_dma_addr(&run->dst->vb2_buf, 0); + de->chroma_stride = de->luma_stride / 2; + de->frame_chroma_addr = + vb2_dma_contig_plane_dma_addr(&run->dst->vb2_buf, 1); + break; + case V4L2_PIX_FMT_NV12_COL128: + case V4L2_PIX_FMT_NV12_10_COL128: + de->luma_stride = ctx->dst_fmt.plane_fmt[0].bytesperline * 128; + de->frame_luma_addr = + vb2_dma_contig_plane_dma_addr(&run->dst->vb2_buf, 0); + de->chroma_stride = de->luma_stride; + de->frame_chroma_addr = de->frame_luma_addr + + (ctx->dst_fmt.height * 128); + break; + } - de = dec_env_new(ctx); - if (!de) { + de->frame_aux = NULL; + + if (s->sps.bit_depth_luma_minus8 != + s->sps.bit_depth_chroma_minus8) { + v4l2_warn(&dev->v4l2_dev, + "Chroma depth (%d) != Luma depth (%d)\n", + s->sps.bit_depth_chroma_minus8 + 8, + s->sps.bit_depth_luma_minus8 + 8); + goto fail; + } + if (s->sps.bit_depth_luma_minus8 == 0) { + if (ctx->dst_fmt.pixelformat != V4L2_PIX_FMT_NV12MT_COL128 && + ctx->dst_fmt.pixelformat != V4L2_PIX_FMT_NV12_COL128) { v4l2_err(&dev->v4l2_dev, - "Failed to find free decode env\n"); + "Pixel format %#x != NV12MT_COL128 for 8-bit output", + ctx->dst_fmt.pixelformat); goto fail; } - ctx->dec0 = de; - - ctb_size_y = - 1U << (s->sps.log2_min_luma_coding_block_size_minus3 + - 3 + - s->sps.log2_diff_max_min_luma_coding_block_size); - - de->pic_width_in_ctbs_y = - (s->sps.pic_width_in_luma_samples + ctb_size_y - 1) / - ctb_size_y; // 7-15 - de->pic_height_in_ctbs_y = - (s->sps.pic_height_in_luma_samples + ctb_size_y - 1) / - ctb_size_y; // 7-17 - de->cmd_len = 0; - de->dpbno_col = ~0U; - - de->bit_copy_gptr = ctx->bitbufs + ctx->p1idx; - de->bit_copy_len = 0; - - de->frame_c_offset = ctx->dst_fmt.height * 128; - de->frame_stride = ctx->dst_fmt.plane_fmt[0].bytesperline * 128; - de->frame_addr = - vb2_dma_contig_plane_dma_addr(&run->dst->vb2_buf, 0); - de->frame_aux = NULL; - - if (s->sps.bit_depth_luma_minus8 != - s->sps.bit_depth_chroma_minus8) { - v4l2_warn(&dev->v4l2_dev, - "Chroma depth (%d) != Luma depth (%d)\n", - s->sps.bit_depth_chroma_minus8 + 8, - s->sps.bit_depth_luma_minus8 + 8); + } else if (s->sps.bit_depth_luma_minus8 == 2) { + if (ctx->dst_fmt.pixelformat != V4L2_PIX_FMT_NV12MT_10_COL128 && + ctx->dst_fmt.pixelformat != V4L2_PIX_FMT_NV12_10_COL128) { + v4l2_err(&dev->v4l2_dev, + "Pixel format %#x != NV12MT_10_COL128 for 10-bit output", + ctx->dst_fmt.pixelformat); goto fail; } - if (s->sps.bit_depth_luma_minus8 == 0) { - if (ctx->dst_fmt.pixelformat != - V4L2_PIX_FMT_NV12_COL128) { - v4l2_err(&dev->v4l2_dev, - "Pixel format %#x != NV12_COL128 for 8-bit output", - ctx->dst_fmt.pixelformat); - goto fail; - } - } else if (s->sps.bit_depth_luma_minus8 == 2) { - if (ctx->dst_fmt.pixelformat != - V4L2_PIX_FMT_NV12_10_COL128) { - v4l2_err(&dev->v4l2_dev, - "Pixel format %#x != NV12_10_COL128 for 10-bit output", - ctx->dst_fmt.pixelformat); - goto fail; - } - } else { + } else { + v4l2_warn(&dev->v4l2_dev, "Luma depth (%d) unsupported\n", + s->sps.bit_depth_luma_minus8 + 8); + goto fail; + } + switch (ctx->dst_fmt.pixelformat) { + case V4L2_PIX_FMT_NV12MT_COL128: + case V4L2_PIX_FMT_NV12MT_10_COL128: + if (run->dst->vb2_buf.num_planes != 2) { + v4l2_warn(&dev->v4l2_dev, "Capture planes (%d) != 2\n", + run->dst->vb2_buf.num_planes); + goto fail; + } + if (run->dst->planes[0].length < ctx->dst_fmt.plane_fmt[0].sizeimage || + run->dst->planes[1].length < ctx->dst_fmt.plane_fmt[1].sizeimage) { v4l2_warn(&dev->v4l2_dev, - "Luma depth (%d) unsupported\n", - s->sps.bit_depth_luma_minus8 + 8); + "Capture planes length (%d/%d) < sizeimage (%d/%d)\n", + run->dst->planes[0].length, + run->dst->planes[1].length, + ctx->dst_fmt.plane_fmt[0].sizeimage, + ctx->dst_fmt.plane_fmt[1].sizeimage); goto fail; } + break; + case V4L2_PIX_FMT_NV12_COL128: + case V4L2_PIX_FMT_NV12_10_COL128: if (run->dst->vb2_buf.num_planes != 1) { v4l2_warn(&dev->v4l2_dev, "Capture planes (%d) != 1\n", run->dst->vb2_buf.num_planes); goto fail; } - if (run->dst->planes[0].length < - ctx->dst_fmt.plane_fmt[0].sizeimage) { + if (run->dst->planes[0].length < ctx->dst_fmt.plane_fmt[0].sizeimage) { v4l2_warn(&dev->v4l2_dev, - "Capture plane[0] length (%d) < sizeimage (%d)\n", + "Capture planes length (%d) < sizeimage (%d)\n", run->dst->planes[0].length, ctx->dst_fmt.plane_fmt[0].sizeimage); goto fail; } + break; + } - // Fill in ref planes with our address s.t. if we mess - // up refs somehow then we still have a valid address - // entry - for (i = 0; i != 16; ++i) - de->ref_addrs[i] = de->frame_addr; - - /* - * Stash initial temporal_mvp flag - * This must be the same for all pic slices (7.4.7.1) - */ - s->slice_temporal_mvp = slice_temporal_mvp; + /* + * Fill in ref planes with our address s.t. if we mess up refs + * somehow then we still have a valid address entry + */ + for (i = 0; i != 16; ++i) { + de->ref_addrs[i][0] = de->frame_luma_addr; + de->ref_addrs[i][1] = de->frame_chroma_addr; + } - /* - * Need Aux ents for all (ref) DPB ents if temporal MV could - * be enabled for any pic - */ - s->use_aux = ((s->sps.flags & - V4L2_HEVC_SPS_FLAG_SPS_TEMPORAL_MVP_ENABLED) != 0); - s->mk_aux = s->use_aux && - (s->sps.sps_max_sub_layers_minus1 >= sh0->nuh_temporal_id_plus1 || - is_ref_unit_type(sh0->nal_unit_type)); - - // Phase 2 reg pre-calc - de->rpi_config2 = mk_config2(s); - de->rpi_framesize = (s->sps.pic_height_in_luma_samples << 16) | - s->sps.pic_width_in_luma_samples; - de->rpi_currpoc = sh0->slice_pic_order_cnt; - - if (s->sps.flags & - V4L2_HEVC_SPS_FLAG_SPS_TEMPORAL_MVP_ENABLED) { - setup_colmv(ctx, run, s); - } + /* + * Stash initial temporal_mvp flag + * This must be the same for all pic slices (7.4.7.1) + */ + s->slice_temporal_mvp = slice_temporal_mvp; - s->slice_idx = 0; + /* + * Need Aux ents for all (ref) DPB ents if temporal MV could + * be enabled for any pic + */ + s->use_aux = ((s->sps.flags & + V4L2_HEVC_SPS_FLAG_SPS_TEMPORAL_MVP_ENABLED) != 0); + s->mk_aux = s->use_aux && + (s->sps.sps_max_sub_layers_minus1 >= sh0->nuh_temporal_id_plus1 || + is_ref_unit_type(sh0->nal_unit_type)); + + /* Phase 2 reg pre-calc */ + de->rpi_config2 = mk_config2(s); + de->rpi_framesize = (s->sps.pic_height_in_luma_samples << 16) | + s->sps.pic_width_in_luma_samples; + de->rpi_currpoc = sh0->slice_pic_order_cnt; + + if (s->sps.flags & + V4L2_HEVC_SPS_FLAG_SPS_TEMPORAL_MVP_ENABLED) { + setup_colmv(ctx, run, s); + } - if (sh0->slice_segment_addr != 0) { - v4l2_warn(&dev->v4l2_dev, - "New frame but segment_addr=%d\n", - sh0->slice_segment_addr); - goto fail; - } + s->slice_idx = 0; - /* Allocate a bitbuf if we need one - don't need one if single - * slice as we can use the src buf directly - */ - if (!frame_end && !de->bit_copy_gptr->ptr) { - size_t bits_alloc; - bits_alloc = rpivid_bit_buf_size(s->sps.pic_width_in_luma_samples, - s->sps.pic_height_in_luma_samples, - s->sps.bit_depth_luma_minus8); - - if (gptr_alloc(dev, de->bit_copy_gptr, - bits_alloc, - DMA_ATTR_FORCE_CONTIGUOUS) != 0) { - v4l2_err(&dev->v4l2_dev, - "Unable to alloc buf (%zu) for bit copy\n", - bits_alloc); - goto fail; - } - v4l2_info(&dev->v4l2_dev, - "Alloc buf (%zu) for bit copy OK\n", - bits_alloc); - } + if (sh0->slice_segment_addr != 0) { + v4l2_warn(&dev->v4l2_dev, + "New frame but segment_addr=%d\n", + sh0->slice_segment_addr); + goto fail; } - // Either map src buffer or use directly + /* Either map src buffer or use directly */ s->src_addr = 0; - s->src_buf = NULL; - - if (frame_end) - s->src_addr = vb2_dma_contig_plane_dma_addr(&run->src->vb2_buf, - 0); - if (!s->src_addr) - s->src_buf = vb2_plane_vaddr(&run->src->vb2_buf, 0); - if (!s->src_addr && !s->src_buf) { + + s->src_addr = vb2_dma_contig_plane_dma_addr(&run->src->vb2_buf, 0); + if (!s->src_addr) { v4l2_err(&dev->v4l2_dev, "Failed to map src buffer\n"); goto fail; } - // Pre calc a few things + /* Pre calc parameters */ s->dec = dec; for (i = 0; i != run->h265.slice_ents; ++i) { const struct v4l2_ctrl_hevc_slice_params *const sh = sh0 + i; - const bool last_slice = frame_end && i + 1 == run->h265.slice_ents; + const bool last_slice = i + 1 == run->h265.slice_ents; s->sh = sh; @@ -1962,19 +1852,16 @@ static void rpivid_h265_setup(struct rpivid_ctx *ctx, struct rpivid_run *run) ++s->slice_idx; } - if (!frame_end) { - xtrace_ok(dev, de); - return; - } - - // Frame end + /* Frame end */ memset(dpb_q_aux, 0, sizeof(*dpb_q_aux) * V4L2_HEVC_DPB_ENTRIES_NUM_MAX); - // Locate ref frames - // At least in the current implementation this is constant across all - // slices. If this changes we will need idx mapping code. - // Uses sh so here rather than trigger + /* + * Locate ref frames + * At least in the current implementation this is constant across all + * slices. If this changes we will need idx mapping code. + * Uses sh so here rather than trigger + */ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); @@ -1984,12 +1871,12 @@ static void rpivid_h265_setup(struct rpivid_ctx *ctx, struct rpivid_run *run) goto fail; } - // v4l2_info(&dev->v4l2_dev, "rpivid_h265_end of frame\n"); if (write_cmd_buffer(dev, de, s)) goto fail; for (i = 0; i < dec->num_active_dpb_entries; ++i) { struct vb2_buffer *buf = vb2_find_buffer(vq, dec->dpb[i].timestamp); + if (!buf) { v4l2_warn(&dev->v4l2_dev, "Missing DPB ent %d, timestamp=%lld\n", @@ -1999,6 +1886,7 @@ static void rpivid_h265_setup(struct rpivid_ctx *ctx, struct rpivid_run *run) if (s->use_aux) { int buffer_index = buf->index; + dpb_q_aux[i] = aux_q_ref_idx(ctx, buffer_index); if (!dpb_q_aux[i]) v4l2_warn(&dev->v4l2_dev, @@ -2007,17 +1895,24 @@ static void rpivid_h265_setup(struct rpivid_ctx *ctx, struct rpivid_run *run) buffer_index); } - de->ref_addrs[i] = + de->ref_addrs[i][0] = vb2_dma_contig_plane_dma_addr(buf, 0); + if (ctx->dst_fmt.pixelformat == V4L2_PIX_FMT_NV12MT_COL128 || + ctx->dst_fmt.pixelformat == V4L2_PIX_FMT_NV12MT_10_COL128) + de->ref_addrs[i][1] = + vb2_dma_contig_plane_dma_addr(buf, 1); + else + de->ref_addrs[i][1] = de->ref_addrs[i][0] + + (ctx->dst_fmt.height * 128); } - // Move DPB from temp + /* Move DPB from temp */ for (i = 0; i != V4L2_HEVC_DPB_ENTRIES_NUM_MAX; ++i) { aux_q_release(ctx, &s->ref_aux[i]); s->ref_aux[i] = dpb_q_aux[i]; } - // Unref the old frame aux too - it is either in the DPB or not - // now + + /* Unref the old frame aux too - it is either in the DPB or not now */ aux_q_release(ctx, &s->frame_aux); if (s->mk_aux) { @@ -2039,61 +1934,60 @@ static void rpivid_h265_setup(struct rpivid_ctx *ctx, struct rpivid_run *run) de->dpbno_col, dec->num_active_dpb_entries); } else { - // Standard requires that the col pic is - // constant for the duration of the pic - // (text of collocated_ref_idx in H265-2 2018 - // 7.4.7.1) + /* Standard requires that the col pic is constant for + * the duration of the pic (text of collocated_ref_idx + * in H265-2 2018 7.4.7.1) + */ - // Spot the collocated ref in passing + /* Spot the collocated ref in passing */ de->col_aux = aux_q_ref(ctx, dpb_q_aux[de->dpbno_col]); if (!de->col_aux) { v4l2_warn(&dev->v4l2_dev, "Missing DPB ent for col\n"); - // Probably need to abort if this fails - // as P2 may explode on bad data + /* Need to abort if this fails as P2 may + * explode on bad data + */ goto fail; } } } - de->state = RPIVID_DECODE_PHASE1; - xtrace_ok(dev, de); + de->state = HEVC_D_DECODE_PHASE1; return; fail: if (de) // Actual error reporting happens in Trigger - de->state = frame_end ? RPIVID_DECODE_ERROR_DONE : - RPIVID_DECODE_ERROR_CONTINUE; - xtrace_fail(dev, de); + de->state = HEVC_D_DECODE_ERROR_DONE; } -////////////////////////////////////////////////////////////////////////////// -// Handle PU and COEFF stream overflow - -// Returns: -// -1 Phase 1 decode error -// 0 OK -// >0 Out of space (bitmask) +/* Handle PU and COEFF stream overflow + * + * Returns: + * -1 Phase 1 decode error + * 0 OK + * >0 Out of space (bitmask) + */ #define STATUS_COEFF_EXHAUSTED 8 #define STATUS_PU_EXHAUSTED 16 -static int check_status(const struct rpivid_dev *const dev) +static int check_status(const struct hevc_d_dev *const dev) { const u32 cfstatus = apb_read(dev, RPI_CFSTATUS); const u32 cfnum = apb_read(dev, RPI_CFNUM); u32 status = apb_read(dev, RPI_STATUS); - // Handle PU and COEFF stream overflow - - // this is the definition of successful completion of phase 1 - // it assures that status register is zero and all blocks in each tile - // have completed + /* + * Handle PU and COEFF stream overflow + * This is the definition of successful completion of phase 1. + * It assures that status register is zero and all blocks in each tile + * have completed + */ if (cfstatus == cfnum) - return 0; //No error + return 0; status &= (STATUS_PU_EXHAUSTED | STATUS_COEFF_EXHAUSTED); if (status) @@ -2102,97 +1996,72 @@ static int check_status(const struct rpivid_dev *const dev) return -1; } -static void phase2_cb(struct rpivid_dev *const dev, void *v) +static void phase2_cb(struct hevc_d_dev *const dev, void *v) { - struct rpivid_dec_env *const de = v; - - xtrace_in(dev, de); + struct hevc_d_dec_env *const de = v; /* Done with buffers - allow new P1 */ - rpivid_hw_irq_active1_enable_claim(dev, 1); + hevc_d_hw_irq_active1_enable_claim(dev, 1); v4l2_m2m_buf_done(de->frame_buf, VB2_BUF_STATE_DONE); de->frame_buf = NULL; -#if USE_REQUEST_PIN - media_request_unpin(de->req_pin); + media_request_manual_complete(de->req_pin); de->req_pin = NULL; -#else - media_request_object_complete(de->req_obj); - de->req_obj = NULL; -#endif - xtrace_ok(dev, de); dec_env_delete(de); } -static void phase2_claimed(struct rpivid_dev *const dev, void *v) +static void phase2_claimed(struct hevc_d_dev *const dev, void *v) { - struct rpivid_dec_env *const de = v; + struct hevc_d_dec_env *const de = v; unsigned int i; - xtrace_in(dev, de); - apb_write_vc_addr(dev, RPI_PURBASE, de->pu_base_vc); apb_write_vc_len(dev, RPI_PURSTRIDE, de->pu_stride); apb_write_vc_addr(dev, RPI_COEFFRBASE, de->coeff_base_vc); apb_write_vc_len(dev, RPI_COEFFRSTRIDE, de->coeff_stride); - apb_write_vc_addr(dev, RPI_OUTYBASE, de->frame_addr); - apb_write_vc_addr(dev, RPI_OUTCBASE, - de->frame_addr + de->frame_c_offset); - apb_write_vc_len(dev, RPI_OUTYSTRIDE, de->frame_stride); - apb_write_vc_len(dev, RPI_OUTCSTRIDE, de->frame_stride); - - // v4l2_info(&dev->v4l2_dev, "Frame: Y=%llx, C=%llx, Stride=%x\n", - // de->frame_addr, de->frame_addr + de->frame_c_offset, - // de->frame_stride); + apb_write_vc_addr(dev, RPI_OUTYBASE, de->frame_luma_addr); + apb_write_vc_addr(dev, RPI_OUTCBASE, de->frame_chroma_addr); + apb_write_vc_len(dev, RPI_OUTYSTRIDE, de->luma_stride); + apb_write_vc_len(dev, RPI_OUTCSTRIDE, de->chroma_stride); for (i = 0; i < 16; i++) { // Strides are in fact unused but fill in anyway - apb_write_vc_addr(dev, 0x9000 + 16 * i, de->ref_addrs[i]); - apb_write_vc_len(dev, 0x9004 + 16 * i, de->frame_stride); - apb_write_vc_addr(dev, 0x9008 + 16 * i, - de->ref_addrs[i] + de->frame_c_offset); - apb_write_vc_len(dev, 0x900C + 16 * i, de->frame_stride); + apb_write_vc_addr(dev, 0x9000 + 16 * i, de->ref_addrs[i][0]); + apb_write_vc_len(dev, 0x9004 + 16 * i, de->luma_stride); + apb_write_vc_addr(dev, 0x9008 + 16 * i, de->ref_addrs[i][1]); + apb_write_vc_len(dev, 0x900C + 16 * i, de->chroma_stride); } apb_write(dev, RPI_CONFIG2, de->rpi_config2); apb_write(dev, RPI_FRAMESIZE, de->rpi_framesize); apb_write(dev, RPI_CURRPOC, de->rpi_currpoc); - // v4l2_info(&dev->v4l2_dev, "Config2=%#x, FrameSize=%#x, POC=%#x\n", - // de->rpi_config2, de->rpi_framesize, de->rpi_currpoc); - // collocated reads/writes + /* collocated reads/writes */ apb_write_vc_len(dev, RPI_COLSTRIDE, - de->ctx->colmv_stride); // Read vals + de->ctx->colmv_stride); apb_write_vc_len(dev, RPI_MVSTRIDE, - de->ctx->colmv_stride); // Write vals + de->ctx->colmv_stride); apb_write_vc_addr(dev, RPI_MVBASE, !de->frame_aux ? 0 : de->frame_aux->col.addr); apb_write_vc_addr(dev, RPI_COLBASE, !de->col_aux ? 0 : de->col_aux->col.addr); - //v4l2_info(&dev->v4l2_dev, - // "Mv=%llx, Col=%llx, Stride=%x, Buf=%llx->%llx\n", - // de->rpi_mvbase, de->rpi_colbase, de->ctx->colmv_stride, - // de->ctx->colmvbuf.addr, de->ctx->colmvbuf.addr + - // de->ctx->colmvbuf.size); - - rpivid_hw_irq_active2_irq(dev, &de->irq_ent, phase2_cb, de); + hevc_d_hw_irq_active2_irq(dev, &de->irq_ent, phase2_cb, de); apb_write_final(dev, RPI_NUMROWS, de->pic_height_in_ctbs_y); - - xtrace_ok(dev, de); } -static void phase1_claimed(struct rpivid_dev *const dev, void *v); +static void phase1_claimed(struct hevc_d_dev *const dev, void *v); -// release any and all objects associated with de -// and reenable phase 1 if required -static void phase1_err_fin(struct rpivid_dev *const dev, - struct rpivid_ctx *const ctx, - struct rpivid_dec_env *const de) +/* release any and all objects associated with de and reenable phase 1 if + * required + */// 1 if required +static void phase1_err_fin(struct hevc_d_dev *const dev, + struct hevc_d_ctx *const ctx, + struct hevc_d_dec_env *const de) { /* Return all detached buffers */ if (de->src_buf) @@ -2201,35 +2070,28 @@ static void phase1_err_fin(struct rpivid_dev *const dev, if (de->frame_buf) v4l2_m2m_buf_done(de->frame_buf, VB2_BUF_STATE_ERROR); de->frame_buf = NULL; -#if USE_REQUEST_PIN + if (de->req_pin) - media_request_unpin(de->req_pin); + media_request_manual_complete(de->req_pin); de->req_pin = NULL; -#else - if (de->req_obj) - media_request_object_complete(de->req_obj); - de->req_obj = NULL; -#endif dec_env_delete(de); /* Reenable phase 0 if we were blocking */ - if (atomic_add_return(-1, &ctx->p1out) >= RPIVID_P1BUF_COUNT - 1) + if (atomic_add_return(-1, &ctx->p1out) >= HEVC_D_P1BUF_COUNT - 1) v4l2_m2m_job_finish(dev->m2m_dev, ctx->fh.m2m_ctx); /* Done with P1-P2 buffers - allow new P1 */ - rpivid_hw_irq_active1_enable_claim(dev, 1); + hevc_d_hw_irq_active1_enable_claim(dev, 1); } -static void phase1_thread(struct rpivid_dev *const dev, void *v) +static void phase1_thread(struct hevc_d_dev *const dev, void *v) { - struct rpivid_dec_env *const de = v; - struct rpivid_ctx *const ctx = de->ctx; + struct hevc_d_dec_env *const de = v; + struct hevc_d_ctx *const ctx = de->ctx; - struct rpivid_gptr *const pu_gptr = ctx->pu_bufs + ctx->p2idx; - struct rpivid_gptr *const coeff_gptr = ctx->coeff_bufs + ctx->p2idx; - - xtrace_in(dev, de); + struct hevc_d_gptr *const pu_gptr = ctx->pu_bufs + ctx->p2idx; + struct hevc_d_gptr *const coeff_gptr = ctx->coeff_bufs + ctx->p2idx; if (de->p1_status & STATUS_PU_EXHAUSTED) { if (gptr_realloc_new(dev, pu_gptr, next_size(pu_gptr->size))) { @@ -2255,7 +2117,6 @@ static void phase1_thread(struct rpivid_dev *const dev, void *v) } phase1_claimed(dev, de); - xtrace_ok(dev, de); return; fail: @@ -2265,17 +2126,14 @@ static void phase1_thread(struct rpivid_dev *const dev, void *v) __func__); ctx->fatal_err = 1; } - xtrace_fail(dev, de); phase1_err_fin(dev, ctx, de); } /* Always called in irq context (this is good) */ -static void phase1_cb(struct rpivid_dev *const dev, void *v) +static void phase1_cb(struct hevc_d_dev *const dev, void *v) { - struct rpivid_dec_env *const de = v; - struct rpivid_ctx *const ctx = de->ctx; - - xtrace_in(dev, de); + struct hevc_d_dec_env *const de = v; + struct hevc_d_ctx *const ctx = de->ctx; de->p1_status = check_status(dev); @@ -2287,7 +2145,7 @@ static void phase1_cb(struct rpivid_dev *const dev, void *v) goto fail; /* Need to realloc - push onto a thread rather than IRQ */ - rpivid_hw_irq_active1_thread(dev, &de->irq_ent, + hevc_d_hw_irq_active1_thread(dev, &de->irq_ent, phase1_thread, de); return; } @@ -2297,35 +2155,29 @@ static void phase1_cb(struct rpivid_dev *const dev, void *v) /* All phase1 error paths done - it is safe to inc p2idx */ ctx->p2idx = - (ctx->p2idx + 1 >= RPIVID_P2BUF_COUNT) ? 0 : ctx->p2idx + 1; + (ctx->p2idx + 1 >= HEVC_D_P2BUF_COUNT) ? 0 : ctx->p2idx + 1; /* Renable the next setup if we were blocking */ - if (atomic_add_return(-1, &ctx->p1out) >= RPIVID_P1BUF_COUNT - 1) { - xtrace_fin(dev, de); + if (atomic_add_return(-1, &ctx->p1out) >= HEVC_D_P1BUF_COUNT - 1) v4l2_m2m_job_finish(dev->m2m_dev, ctx->fh.m2m_ctx); - } - rpivid_hw_irq_active2_claim(dev, &de->irq_ent, phase2_claimed, de); + hevc_d_hw_irq_active2_claim(dev, &de->irq_ent, phase2_claimed, de); - xtrace_ok(dev, de); return; fail: - xtrace_fail(dev, de); phase1_err_fin(dev, ctx, de); } -static void phase1_claimed(struct rpivid_dev *const dev, void *v) +static void phase1_claimed(struct hevc_d_dev *const dev, void *v) { - struct rpivid_dec_env *const de = v; - struct rpivid_ctx *const ctx = de->ctx; + struct hevc_d_dec_env *const de = v; + struct hevc_d_ctx *const ctx = de->ctx; - const struct rpivid_gptr * const pu_gptr = ctx->pu_bufs + ctx->p2idx; - const struct rpivid_gptr * const coeff_gptr = ctx->coeff_bufs + + const struct hevc_d_gptr * const pu_gptr = ctx->pu_bufs + ctx->p2idx; + const struct hevc_d_gptr * const coeff_gptr = ctx->coeff_bufs + ctx->p2idx; - xtrace_in(dev, de); - if (ctx->fatal_err) goto fail; @@ -2346,27 +2198,25 @@ static void phase1_claimed(struct rpivid_dev *const dev, void *v) apb_write_vc_addr(dev, RPI_COEFFWBASE, de->coeff_base_vc); apb_write_vc_len(dev, RPI_COEFFWSTRIDE, de->coeff_stride); - // Trigger command FIFO + /* Trigger command FIFO */ apb_write(dev, RPI_CFNUM, de->cmd_len); - // Claim irq - rpivid_hw_irq_active1_irq(dev, &de->irq_ent, phase1_cb, de); + /* Claim irq */ + hevc_d_hw_irq_active1_irq(dev, &de->irq_ent, phase1_cb, de); - // And start the h/w + /* Start the h/w */ apb_write_vc_addr_final(dev, RPI_CFBASE, de->cmd_addr); - xtrace_ok(dev, de); return; fail: - xtrace_fail(dev, de); phase1_err_fin(dev, ctx, de); } -static void dec_state_delete(struct rpivid_ctx *const ctx) +static void dec_state_delete(struct hevc_d_ctx *const ctx) { unsigned int i; - struct rpivid_dec_state *const s = ctx->state; + struct hevc_d_dec_state *const s = ctx->state; if (!s) return; @@ -2384,10 +2234,10 @@ static void dec_state_delete(struct rpivid_ctx *const ctx) struct irq_sync { atomic_t done; wait_queue_head_t wq; - struct rpivid_hw_irq_ent irq_ent; + struct hevc_d_hw_irq_ent irq_ent; }; -static void phase2_sync_claimed(struct rpivid_dev *const dev, void *v) +static void phase2_sync_claimed(struct hevc_d_dev *const dev, void *v) { struct irq_sync *const sync = v; @@ -2395,12 +2245,12 @@ static void phase2_sync_claimed(struct rpivid_dev *const dev, void *v) wake_up(&sync->wq); } -static void phase1_sync_claimed(struct rpivid_dev *const dev, void *v) +static void phase1_sync_claimed(struct hevc_d_dev *const dev, void *v) { struct irq_sync *const sync = v; - rpivid_hw_irq_active1_enable_claim(dev, 1); - rpivid_hw_irq_active2_claim(dev, &sync->irq_ent, phase2_sync_claimed, sync); + hevc_d_hw_irq_active1_enable_claim(dev, 1); + hevc_d_hw_irq_active2_claim(dev, &sync->irq_ent, phase2_sync_claimed, sync); } /* Sync with IRQ operations @@ -2411,49 +2261,47 @@ static void phase1_sync_claimed(struct rpivid_dev *const dev, void *v) * phase1 has counted enables so must reenable once claimed * phase2 has unlimited enables */ -static void irq_sync(struct rpivid_dev *const dev) +static void irq_sync(struct hevc_d_dev *const dev) { struct irq_sync sync; atomic_set(&sync.done, 0); init_waitqueue_head(&sync.wq); - rpivid_hw_irq_active1_claim(dev, &sync.irq_ent, phase1_sync_claimed, &sync); + hevc_d_hw_irq_active1_claim(dev, &sync.irq_ent, phase1_sync_claimed, &sync); wait_event(sync.wq, atomic_read(&sync.done)); } -static void h265_ctx_uninit(struct rpivid_dev *const dev, struct rpivid_ctx *ctx) +static void h265_ctx_uninit(struct hevc_d_dev *const dev, struct hevc_d_ctx *ctx) { unsigned int i; dec_env_uninit(ctx); dec_state_delete(ctx); - // dec_env & state must be killed before this to release the buffer to - // the free pool + /* + * dec_env & state must be killed before this to release the buffer to + * the free pool + */ aux_q_uninit(ctx); - for (i = 0; i != ARRAY_SIZE(ctx->bitbufs); ++i) - gptr_free(dev, ctx->bitbufs + i); for (i = 0; i != ARRAY_SIZE(ctx->pu_bufs); ++i) gptr_free(dev, ctx->pu_bufs + i); for (i = 0; i != ARRAY_SIZE(ctx->coeff_bufs); ++i) gptr_free(dev, ctx->coeff_bufs + i); } -static void rpivid_h265_stop(struct rpivid_ctx *ctx) +void hevc_d_h265_stop(struct hevc_d_ctx *ctx) { - struct rpivid_dev *const dev = ctx->dev; - - v4l2_info(&dev->v4l2_dev, "%s\n", __func__); + struct hevc_d_dev *const dev = ctx->dev; irq_sync(dev); h265_ctx_uninit(dev, ctx); } -static int rpivid_h265_start(struct rpivid_ctx *ctx) +int hevc_d_h265_start(struct hevc_d_ctx *ctx) { - struct rpivid_dev *const dev = ctx->dev; + struct hevc_d_dev *const dev = ctx->dev; unsigned int i; unsigned int w = ctx->dst_fmt.width; @@ -2462,12 +2310,7 @@ static int rpivid_h265_start(struct rpivid_ctx *ctx) size_t pu_alloc; size_t coeff_alloc; -#if DEBUG_TRACE_P1_CMD - p1_z = 0; -#endif - - // Generate a sanitised WxH for memory alloc - // Assume HD if unset + /* Generate a sanitised WxH for memory alloc. Assume HD if unset */ if (w == 0) w = 1920; if (w > 4096) @@ -2478,9 +2321,6 @@ static int rpivid_h265_start(struct rpivid_ctx *ctx) h = 4096; wxh = w * h; - v4l2_info(&dev->v4l2_dev, "%s: (%dx%d)\n", __func__, - ctx->dst_fmt.width, ctx->dst_fmt.height); - ctx->fatal_err = 0; ctx->dec0 = NULL; ctx->state = kzalloc(sizeof(*ctx->state), GFP_KERNEL); @@ -2494,12 +2334,10 @@ static int rpivid_h265_start(struct rpivid_ctx *ctx) goto fail; } - // Finger in the air PU & Coeff alloc - // Will be realloced if too small - coeff_alloc = rpivid_round_up_size(wxh); - pu_alloc = rpivid_round_up_size(wxh / 4); + coeff_alloc = hevc_d_round_up_size(wxh); + pu_alloc = hevc_d_round_up_size(wxh / 4); for (i = 0; i != ARRAY_SIZE(ctx->pu_bufs); ++i) { - // Don't actually need a kernel mapping here + /* Don't actually need a kernel mapping here */ if (gptr_alloc(dev, ctx->pu_bufs + i, pu_alloc, DMA_ATTR_NO_KERNEL_MAPPING)) { v4l2_err(&dev->v4l2_dev, @@ -2524,103 +2362,60 @@ static int rpivid_h265_start(struct rpivid_ctx *ctx) return -ENOMEM; } -static void rpivid_h265_trigger(struct rpivid_ctx *ctx) +void hevc_d_h265_trigger(struct hevc_d_ctx *ctx) { - struct rpivid_dev *const dev = ctx->dev; - struct rpivid_dec_env *const de = ctx->dec0; + struct hevc_d_dev *const dev = ctx->dev; + struct hevc_d_dec_env *const de = ctx->dec0; + struct vb2_v4l2_buffer *src_buf; + struct media_request *req; - xtrace_in(dev, de); - - switch (!de ? RPIVID_DECODE_ERROR_CONTINUE : de->state) { - case RPIVID_DECODE_SLICE_START: - de->state = RPIVID_DECODE_SLICE_CONTINUE; - fallthrough; - case RPIVID_DECODE_SLICE_CONTINUE: - v4l2_m2m_buf_done_and_job_finish(dev->m2m_dev, ctx->fh.m2m_ctx, - VB2_BUF_STATE_DONE); - xtrace_ok(dev, de); - break; + src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + req = src_buf->vb2_buf.req_obj.req; + switch (!de ? HEVC_D_DECODE_ERROR_DONE : de->state) { default: v4l2_err(&dev->v4l2_dev, "%s: Unexpected state: %d\n", __func__, de->state); fallthrough; - case RPIVID_DECODE_ERROR_DONE: + case HEVC_D_DECODE_ERROR_DONE: ctx->dec0 = NULL; dec_env_delete(de); - fallthrough; - case RPIVID_DECODE_ERROR_CONTINUE: - xtrace_fin(dev, de); v4l2_m2m_buf_done_and_job_finish(dev->m2m_dev, ctx->fh.m2m_ctx, VB2_BUF_STATE_ERROR); + media_request_manual_complete(req); break; - case RPIVID_DECODE_PHASE1: + case HEVC_D_DECODE_PHASE1: ctx->dec0 = NULL; -#if !USE_REQUEST_PIN - /* Alloc a new request object - needs to be alloced dynamically - * as the media request will release it some random time after - * it is completed - */ - de->req_obj = kmalloc(sizeof(*de->req_obj), GFP_KERNEL); - if (!de->req_obj) { - xtrace_fail(dev, de); - dec_env_delete(de); - v4l2_m2m_buf_done_and_job_finish(dev->m2m_dev, - ctx->fh.m2m_ctx, - VB2_BUF_STATE_ERROR); - break; - } - media_request_object_init(de->req_obj); -#warning probably needs to _get the req obj too -#endif - ctx->p1idx = (ctx->p1idx + 1 >= RPIVID_P1BUF_COUNT) ? + ctx->p1idx = (ctx->p1idx + 1 >= HEVC_D_P1BUF_COUNT) ? 0 : ctx->p1idx + 1; /* We know we have src & dst so no need to test */ de->src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); de->frame_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); - -#if USE_REQUEST_PIN - de->req_pin = de->src_buf->vb2_buf.req_obj.req; - media_request_pin(de->req_pin); -#else - media_request_object_bind(de->src_buf->vb2_buf.req_obj.req, - &dst_req_obj_ops, de, false, - de->req_obj); -#endif + de->req_pin = req; /* We could get rid of the src buffer here if we've already * copied it, but we don't copy the last buffer unless it - * didn't return a contig dma addr and that shouldn't happen + * didn't return a contig dma addr, and that shouldn't happen */ /* Enable the next setup if our Q isn't too big */ - if (atomic_add_return(1, &ctx->p1out) < RPIVID_P1BUF_COUNT) { - xtrace_fin(dev, de); + if (atomic_add_return(1, &ctx->p1out) < HEVC_D_P1BUF_COUNT) v4l2_m2m_job_finish(dev->m2m_dev, ctx->fh.m2m_ctx); - } - rpivid_hw_irq_active1_claim(dev, &de->irq_ent, phase1_claimed, + hevc_d_hw_irq_active1_claim(dev, &de->irq_ent, phase1_claimed, de); - xtrace_ok(dev, de); break; } } -const struct rpivid_dec_ops rpivid_dec_ops_h265 = { - .setup = rpivid_h265_setup, - .start = rpivid_h265_start, - .stop = rpivid_h265_stop, - .trigger = rpivid_h265_trigger, -}; - static int try_ctrl_sps(struct v4l2_ctrl *ctrl) { const struct v4l2_ctrl_hevc_sps *const sps = ctrl->p_new.p_hevc_sps; - struct rpivid_ctx *const ctx = ctrl->priv; - struct rpivid_dev *const dev = ctx->dev; + struct hevc_d_ctx *const ctx = ctrl->priv; + struct hevc_d_dev *const dev = ctx->dev; if (sps->chroma_format_idc != 1) { v4l2_warn(&dev->v4l2_dev, @@ -2660,8 +2455,10 @@ static int try_ctrl_sps(struct v4l2_ctrl *ctrl) return 0; if ((sps->bit_depth_luma_minus8 == 0 && + ctx->dst_fmt.pixelformat != V4L2_PIX_FMT_NV12MT_COL128 && ctx->dst_fmt.pixelformat != V4L2_PIX_FMT_NV12_COL128) || (sps->bit_depth_luma_minus8 == 2 && + ctx->dst_fmt.pixelformat != V4L2_PIX_FMT_NV12MT_10_COL128 && ctx->dst_fmt.pixelformat != V4L2_PIX_FMT_NV12_10_COL128)) { v4l2_warn(&dev->v4l2_dev, "SPS luma depth %d does not match capture format\n", @@ -2683,15 +2480,15 @@ static int try_ctrl_sps(struct v4l2_ctrl *ctrl) return 0; } -const struct v4l2_ctrl_ops rpivid_hevc_sps_ctrl_ops = { +const struct v4l2_ctrl_ops hevc_d_hevc_sps_ctrl_ops = { .try_ctrl = try_ctrl_sps, }; static int try_ctrl_pps(struct v4l2_ctrl *ctrl) { const struct v4l2_ctrl_hevc_pps *const pps = ctrl->p_new.p_hevc_pps; - struct rpivid_ctx *const ctx = ctrl->priv; - struct rpivid_dev *const dev = ctx->dev; + struct hevc_d_ctx *const ctx = ctrl->priv; + struct hevc_d_dev *const dev = ctx->dev; if ((pps->flags & V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED) && @@ -2706,7 +2503,83 @@ static int try_ctrl_pps(struct v4l2_ctrl *ctrl) return 0; } -const struct v4l2_ctrl_ops rpivid_hevc_pps_ctrl_ops = { +const struct v4l2_ctrl_ops hevc_d_hevc_pps_ctrl_ops = { .try_ctrl = try_ctrl_pps, }; +void hevc_d_device_run(void *priv) +{ + struct hevc_d_ctx *const ctx = priv; + struct hevc_d_dev *const dev = ctx->dev; + struct hevc_d_run run = {}; + struct media_request *src_req; + + run.src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + run.dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + + if (!run.src || !run.dst) { + v4l2_err(&dev->v4l2_dev, "%s: Missing buffer: src=%p, dst=%p\n", + __func__, run.src, run.dst); + goto fail; + } + + /* Apply request(s) controls */ + src_req = run.src->vb2_buf.req_obj.req; + if (!src_req) { + v4l2_err(&dev->v4l2_dev, "%s: Missing request\n", __func__); + goto fail; + } + + v4l2_ctrl_request_setup(src_req, &ctx->hdl); + + switch (ctx->src_fmt.pixelformat) { + case V4L2_PIX_FMT_HEVC_SLICE: + { + const struct v4l2_ctrl *ctrl; + + run.h265.sps = + hevc_d_find_control_data(ctx, + V4L2_CID_STATELESS_HEVC_SPS); + run.h265.pps = + hevc_d_find_control_data(ctx, + V4L2_CID_STATELESS_HEVC_PPS); + run.h265.dec = + hevc_d_find_control_data(ctx, + V4L2_CID_STATELESS_HEVC_DECODE_PARAMS); + + ctrl = hevc_d_find_ctrl(ctx, + V4L2_CID_STATELESS_HEVC_SLICE_PARAMS); + if (!ctrl || !ctrl->elems) { + v4l2_err(&dev->v4l2_dev, "%s: Missing slice params\n", + __func__); + goto fail; + } + run.h265.slice_ents = ctrl->elems; + run.h265.slice_params = ctrl->p_cur.p; + + run.h265.scaling_matrix = + hevc_d_find_control_data(ctx, + V4L2_CID_STATELESS_HEVC_SCALING_MATRIX); + break; + } + + default: + break; + } + + v4l2_m2m_buf_copy_metadata(run.src, run.dst, true); + + hevc_d_h265_setup(ctx, &run); + + /* Complete request(s) controls */ + v4l2_ctrl_request_complete(src_req, &ctx->hdl); + + hevc_d_h265_trigger(ctx); + return; + +fail: + /* We really shouldn't get here but tidy up what we can */ + v4l2_m2m_buf_done_and_job_finish(dev->m2m_dev, ctx->fh.m2m_ctx, + VB2_BUF_STATE_ERROR); + media_request_manual_complete(src_req); +} diff --git a/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_h265.h b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_h265.h new file mode 100644 index 00000000000000..775fe7de5dd6ef --- /dev/null +++ b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_h265.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Raspberry Pi HEVC driver + * + * Copyright (C) 2024 Raspberry Pi Ltd + * + */ + +#ifndef _HEVC_D_H265_H_ +#define _HEVC_D_H265_H_ +#include "hevc_d.h" + +extern const struct v4l2_ctrl_ops hevc_d_hevc_sps_ctrl_ops; +extern const struct v4l2_ctrl_ops hevc_d_hevc_pps_ctrl_ops; + +void hevc_d_h265_setup(struct hevc_d_ctx *ctx, struct hevc_d_run *run); +int hevc_d_h265_start(struct hevc_d_ctx *ctx); +void hevc_d_h265_stop(struct hevc_d_ctx *ctx); +void hevc_d_h265_trigger(struct hevc_d_ctx *ctx); + +void hevc_d_device_run(void *priv); + +#endif diff --git a/drivers/staging/media/rpivid/rpivid_hw.c b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_hw.c similarity index 60% rename from drivers/staging/media/rpivid/rpivid_hw.c rename to drivers/media/platform/raspberrypi/hevc_dec/hevc_d_hw.c index 1026fa6b8b04f4..5030a69093018f 100644 --- a/drivers/staging/media/rpivid/rpivid_hw.c +++ b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_hw.c @@ -2,7 +2,7 @@ /* * Raspberry Pi HEVC driver * - * Copyright (C) 2020 Raspberry Pi (Trading) Ltd + * Copyright (C) 2024 Raspberry Pi Ltd * * Based on the Cedrus VPU driver, that is: * @@ -27,12 +27,12 @@ #include -#include "rpivid.h" -#include "rpivid_hw.h" +#include "hevc_d.h" +#include "hevc_d_hw.h" -static void pre_irq(struct rpivid_dev *dev, struct rpivid_hw_irq_ent *ient, - rpivid_irq_callback cb, void *v, - struct rpivid_hw_irq_ctrl *ictl) +static void pre_irq(struct hevc_d_dev *dev, struct hevc_d_hw_irq_ent *ient, + hevc_d_irq_callback cb, void *v, + struct hevc_d_hw_irq_ctrl *ictl) { unsigned long flags; @@ -51,13 +51,13 @@ static void pre_irq(struct rpivid_dev *dev, struct rpivid_hw_irq_ent *ient, } /* Should be called from inside ictl->lock */ -static inline bool sched_enabled(const struct rpivid_hw_irq_ctrl * const ictl) +static inline bool sched_enabled(const struct hevc_d_hw_irq_ctrl * const ictl) { return ictl->no_sched <= 0 && ictl->enable; } /* Should be called from inside ictl->lock & after checking sched_enabled() */ -static inline void set_claimed(struct rpivid_hw_irq_ctrl * const ictl) +static inline void set_claimed(struct hevc_d_hw_irq_ctrl * const ictl) { if (ictl->enable > 0) --ictl->enable; @@ -65,9 +65,9 @@ static inline void set_claimed(struct rpivid_hw_irq_ctrl * const ictl) } /* Should be called from inside ictl->lock */ -static struct rpivid_hw_irq_ent *get_sched(struct rpivid_hw_irq_ctrl * const ictl) +static struct hevc_d_hw_irq_ent *get_sched(struct hevc_d_hw_irq_ctrl * const ictl) { - struct rpivid_hw_irq_ent *ient; + struct hevc_d_hw_irq_ent *ient; if (!sched_enabled(ictl)) return NULL; @@ -82,9 +82,9 @@ static struct rpivid_hw_irq_ent *get_sched(struct rpivid_hw_irq_ctrl * const ict } /* Run a callback & check to see if there is anything else to run */ -static void sched_cb(struct rpivid_dev * const dev, - struct rpivid_hw_irq_ctrl * const ictl, - struct rpivid_hw_irq_ent *ient) +static void sched_cb(struct hevc_d_dev * const dev, + struct hevc_d_hw_irq_ctrl * const ictl, + struct hevc_d_hw_irq_ent *ient) { while (ient) { unsigned long flags; @@ -93,7 +93,8 @@ static void sched_cb(struct rpivid_dev * const dev, spin_lock_irqsave(&ictl->lock, flags); - /* Always dec no_sched after cb exec - must have been set + /* + * Always dec no_sched after cb exec - must have been set * on entry to cb */ --ictl->no_sched; @@ -104,10 +105,10 @@ static void sched_cb(struct rpivid_dev * const dev, } /* Should only ever be called from its own IRQ cb so no lock required */ -static void pre_thread(struct rpivid_dev *dev, - struct rpivid_hw_irq_ent *ient, - rpivid_irq_callback cb, void *v, - struct rpivid_hw_irq_ctrl *ictl) +static void pre_thread(struct hevc_d_dev *dev, + struct hevc_d_hw_irq_ent *ient, + hevc_d_irq_callback cb, void *v, + struct hevc_d_hw_irq_ctrl *ictl) { ient->cb = cb; ient->v = v; @@ -116,11 +117,11 @@ static void pre_thread(struct rpivid_dev *dev, ictl->no_sched++; /* This is unwound in do_thread */ } -// Called in irq context -static void do_irq(struct rpivid_dev * const dev, - struct rpivid_hw_irq_ctrl * const ictl) +/* Called in irq context */ +static void do_irq(struct hevc_d_dev * const dev, + struct hevc_d_hw_irq_ctrl * const ictl) { - struct rpivid_hw_irq_ent *ient; + struct hevc_d_hw_irq_ent *ient; unsigned long flags; spin_lock_irqsave(&ictl->lock, flags); @@ -131,10 +132,10 @@ static void do_irq(struct rpivid_dev * const dev, sched_cb(dev, ictl, ient); } -static void do_claim(struct rpivid_dev * const dev, - struct rpivid_hw_irq_ent *ient, - const rpivid_irq_callback cb, void * const v, - struct rpivid_hw_irq_ctrl * const ictl) +static void do_claim(struct hevc_d_dev * const dev, + struct hevc_d_hw_irq_ent *ient, + const hevc_d_irq_callback cb, void * const v, + struct hevc_d_hw_irq_ctrl * const ictl) { unsigned long flags; @@ -145,18 +146,20 @@ static void do_claim(struct rpivid_dev * const dev, spin_lock_irqsave(&ictl->lock, flags); if (ictl->claim) { - // If we have a Q then add to end + /* If we have a Q then add to end */ ictl->tail->next = ient; ictl->tail = ient; ient = NULL; } else if (!sched_enabled(ictl)) { - // Empty Q but other activity in progress so Q + /* Empty Q but other activity in progress so Q */ ictl->claim = ient; ictl->tail = ient; ient = NULL; } else { - // Nothing else going on - schedule immediately and - // prevent anything else scheduling claims + /* + * Nothing else going on - schedule immediately and + * prevent anything else scheduling claims + */ set_claimed(ictl); } @@ -172,12 +175,12 @@ static void do_claim(struct rpivid_dev * const dev, * otherwise add n enables * The enable count is automatically decremented every time a claim is run */ -static void do_enable_claim(struct rpivid_dev * const dev, +static void do_enable_claim(struct hevc_d_dev * const dev, int n, - struct rpivid_hw_irq_ctrl * const ictl) + struct hevc_d_hw_irq_ctrl * const ictl) { unsigned long flags; - struct rpivid_hw_irq_ent *ient; + struct hevc_d_hw_irq_ent *ient; spin_lock_irqsave(&ictl->lock, flags); ictl->enable = n < 0 ? -1 : ictl->enable <= 0 ? n : ictl->enable + n; @@ -187,7 +190,7 @@ static void do_enable_claim(struct rpivid_dev * const dev, sched_cb(dev, ictl, ient); } -static void ictl_init(struct rpivid_hw_irq_ctrl * const ictl, int enables) +static void ictl_init(struct hevc_d_hw_irq_ctrl * const ictl, int enables) { spin_lock_init(&ictl->lock); ictl->claim = NULL; @@ -198,15 +201,14 @@ static void ictl_init(struct rpivid_hw_irq_ctrl * const ictl, int enables) ictl->thread_reqed = false; } -static void ictl_uninit(struct rpivid_hw_irq_ctrl * const ictl) +static void ictl_uninit(struct hevc_d_hw_irq_ctrl * const ictl) { - // Nothing to do + /* Nothing to do */ } -#if !OPT_DEBUG_POLL_IRQ -static irqreturn_t rpivid_irq_irq(int irq, void *data) +static irqreturn_t hevc_d_irq_irq(int irq, void *data) { - struct rpivid_dev * const dev = data; + struct hevc_d_dev * const dev = data; __u32 ictrl; ictrl = irq_read(dev, ARG_IC_ICTRL); @@ -215,11 +217,13 @@ static irqreturn_t rpivid_irq_irq(int irq, void *data) return IRQ_NONE; } - // Cancel any/all irqs + /* Cancel any/all irqs */ irq_write(dev, ARG_IC_ICTRL, ictrl & ~ARG_IC_ICTRL_SET_ZERO_MASK); - // Service Active2 before Active1 so Phase 1 can transition to Phase 2 - // without delay + /* + * Service Active2 before Active1 so Phase 1 can transition to Phase 2 + * without delay + */ if (ictrl & ARG_IC_ICTRL_ACTIVE2_INT_SET) do_irq(dev, &dev->ic_active2); if (ictrl & ARG_IC_ICTRL_ACTIVE1_INT_SET) @@ -229,11 +233,11 @@ static irqreturn_t rpivid_irq_irq(int irq, void *data) IRQ_WAKE_THREAD : IRQ_HANDLED; } -static void do_thread(struct rpivid_dev * const dev, - struct rpivid_hw_irq_ctrl *const ictl) +static void do_thread(struct hevc_d_dev * const dev, + struct hevc_d_hw_irq_ctrl *const ictl) { unsigned long flags; - struct rpivid_hw_irq_ent *ient = NULL; + struct hevc_d_hw_irq_ent *ient = NULL; spin_lock_irqsave(&ictl->lock, flags); @@ -248,90 +252,81 @@ static void do_thread(struct rpivid_dev * const dev, sched_cb(dev, ictl, ient); } -static irqreturn_t rpivid_irq_thread(int irq, void *data) +static irqreturn_t hevc_d_irq_thread(int irq, void *data) { - struct rpivid_dev * const dev = data; + struct hevc_d_dev * const dev = data; do_thread(dev, &dev->ic_active1); do_thread(dev, &dev->ic_active2); return IRQ_HANDLED; } -#endif -/* May only be called from Active1 CB +/* + * May only be called from Active1 CB * IRQs should not be expected until execution continues in the cb */ -void rpivid_hw_irq_active1_thread(struct rpivid_dev *dev, - struct rpivid_hw_irq_ent *ient, - rpivid_irq_callback thread_cb, void *ctx) +void hevc_d_hw_irq_active1_thread(struct hevc_d_dev *dev, + struct hevc_d_hw_irq_ent *ient, + hevc_d_irq_callback thread_cb, void *ctx) { pre_thread(dev, ient, thread_cb, ctx, &dev->ic_active1); } -void rpivid_hw_irq_active1_enable_claim(struct rpivid_dev *dev, +void hevc_d_hw_irq_active1_enable_claim(struct hevc_d_dev *dev, int n) { do_enable_claim(dev, n, &dev->ic_active1); } -void rpivid_hw_irq_active1_claim(struct rpivid_dev *dev, - struct rpivid_hw_irq_ent *ient, - rpivid_irq_callback ready_cb, void *ctx) +void hevc_d_hw_irq_active1_claim(struct hevc_d_dev *dev, + struct hevc_d_hw_irq_ent *ient, + hevc_d_irq_callback ready_cb, void *ctx) { do_claim(dev, ient, ready_cb, ctx, &dev->ic_active1); } -void rpivid_hw_irq_active1_irq(struct rpivid_dev *dev, - struct rpivid_hw_irq_ent *ient, - rpivid_irq_callback irq_cb, void *ctx) +void hevc_d_hw_irq_active1_irq(struct hevc_d_dev *dev, + struct hevc_d_hw_irq_ent *ient, + hevc_d_irq_callback irq_cb, void *ctx) { pre_irq(dev, ient, irq_cb, ctx, &dev->ic_active1); } -void rpivid_hw_irq_active2_claim(struct rpivid_dev *dev, - struct rpivid_hw_irq_ent *ient, - rpivid_irq_callback ready_cb, void *ctx) +void hevc_d_hw_irq_active2_claim(struct hevc_d_dev *dev, + struct hevc_d_hw_irq_ent *ient, + hevc_d_irq_callback ready_cb, void *ctx) { do_claim(dev, ient, ready_cb, ctx, &dev->ic_active2); } -void rpivid_hw_irq_active2_irq(struct rpivid_dev *dev, - struct rpivid_hw_irq_ent *ient, - rpivid_irq_callback irq_cb, void *ctx) +void hevc_d_hw_irq_active2_irq(struct hevc_d_dev *dev, + struct hevc_d_hw_irq_ent *ient, + hevc_d_irq_callback irq_cb, void *ctx) { pre_irq(dev, ient, irq_cb, ctx, &dev->ic_active2); } -int rpivid_hw_probe(struct rpivid_dev *dev) +int hevc_d_hw_probe(struct hevc_d_dev *dev) { struct rpi_firmware *firmware; struct device_node *node; - struct resource *res; __u32 irq_stat; int irq_dec; int ret = 0; - ictl_init(&dev->ic_active1, RPIVID_P2BUF_COUNT); - ictl_init(&dev->ic_active2, RPIVID_ICTL_ENABLE_UNLIMITED); - - res = platform_get_resource_byname(dev->pdev, IORESOURCE_MEM, "intc"); - if (!res) - return -ENODEV; + ictl_init(&dev->ic_active1, HEVC_D_P2BUF_COUNT); + ictl_init(&dev->ic_active2, HEVC_D_ICTL_ENABLE_UNLIMITED); - dev->base_irq = devm_ioremap(dev->dev, res->start, resource_size(res)); + dev->base_irq = devm_platform_ioremap_resource_byname(dev->pdev, "intc"); if (IS_ERR(dev->base_irq)) return PTR_ERR(dev->base_irq); - res = platform_get_resource_byname(dev->pdev, IORESOURCE_MEM, "hevc"); - if (!res) - return -ENODEV; - - dev->base_h265 = devm_ioremap(dev->dev, res->start, resource_size(res)); + dev->base_h265 = devm_platform_ioremap_resource_byname(dev->pdev, "hevc"); if (IS_ERR(dev->base_h265)) return PTR_ERR(dev->base_h265); - dev->clock = devm_clk_get(&dev->pdev->dev, "hevc"); + dev->clock = devm_clk_get(&dev->pdev->dev, NULL); if (IS_ERR(dev->clock)) return PTR_ERR(dev->clock); @@ -350,33 +345,31 @@ int rpivid_hw_probe(struct rpivid_dev *dev) dev->cache_align = dma_get_cache_alignment(); - // Disable IRQs & reset anything pending + /* Disable IRQs & reset anything pending */ irq_write(dev, 0, ARG_IC_ICTRL_ACTIVE1_EN_SET | ARG_IC_ICTRL_ACTIVE2_EN_SET); irq_stat = irq_read(dev, 0); irq_write(dev, 0, irq_stat); -#if !OPT_DEBUG_POLL_IRQ irq_dec = platform_get_irq(dev->pdev, 0); if (irq_dec <= 0) return irq_dec; ret = devm_request_threaded_irq(dev->dev, irq_dec, - rpivid_irq_irq, - rpivid_irq_thread, + hevc_d_irq_irq, + hevc_d_irq_thread, 0, dev_name(dev->dev), dev); - if (ret) { + if (ret) dev_err(dev->dev, "Failed to request IRQ - %d\n", ret); - return ret; - } -#endif return ret; } -void rpivid_hw_remove(struct rpivid_dev *dev) +void hevc_d_hw_remove(struct hevc_d_dev *dev) { - // IRQ auto freed on unload so no need to do it here - // ioremap auto freed on unload + /* + * IRQ auto freed on unload so no need to do it here + * ioremap auto freed on unload + */ ictl_uninit(&dev->ic_active1); ictl_uninit(&dev->ic_active2); } diff --git a/drivers/staging/media/rpivid/rpivid_hw.h b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_hw.h similarity index 83% rename from drivers/staging/media/rpivid/rpivid_hw.h rename to drivers/media/platform/raspberrypi/hevc_dec/hevc_d_hw.h index ec73a2332b73f0..8d91931aadf207 100644 --- a/drivers/staging/media/rpivid/rpivid_hw.h +++ b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_hw.h @@ -2,7 +2,7 @@ /* * Raspberry Pi HEVC driver * - * Copyright (C) 2020 Raspberry Pi (Trading) Ltd + * Copyright (C) 2024 Raspberry Pi Ltd * * Based on the Cedrus VPU driver, that is: * @@ -11,12 +11,12 @@ * Copyright (C) 2018 Bootlin */ -#ifndef _RPIVID_HW_H_ -#define _RPIVID_HW_H_ +#ifndef _HEVC_D_HW_H_ +#define _HEVC_D_HW_H_ -struct rpivid_hw_irq_ent { - struct rpivid_hw_irq_ent *next; - rpivid_irq_callback cb; +struct hevc_d_hw_irq_ent { + struct hevc_d_hw_irq_ent *next; + hevc_d_irq_callback cb; void *v; }; @@ -77,52 +77,52 @@ struct rpivid_hw_irq_ent { * Write a general register value * Order is unimportant */ -static inline void apb_write(const struct rpivid_dev * const dev, +static inline void apb_write(const struct hevc_d_dev * const dev, const unsigned int offset, const u32 val) { writel_relaxed(val, dev->base_h265 + offset); } /* Write the final register value that actually starts the phase */ -static inline void apb_write_final(const struct rpivid_dev * const dev, +static inline void apb_write_final(const struct hevc_d_dev * const dev, const unsigned int offset, const u32 val) { writel(val, dev->base_h265 + offset); } -static inline u32 apb_read(const struct rpivid_dev * const dev, +static inline u32 apb_read(const struct hevc_d_dev * const dev, const unsigned int offset) { return readl(dev->base_h265 + offset); } -static inline void irq_write(const struct rpivid_dev * const dev, +static inline void irq_write(const struct hevc_d_dev * const dev, const unsigned int offset, const u32 val) { writel(val, dev->base_irq + offset); } -static inline u32 irq_read(const struct rpivid_dev * const dev, +static inline u32 irq_read(const struct hevc_d_dev * const dev, const unsigned int offset) { return readl(dev->base_irq + offset); } -static inline void apb_write_vc_addr(const struct rpivid_dev * const dev, +static inline void apb_write_vc_addr(const struct hevc_d_dev * const dev, const unsigned int offset, const dma_addr_t a) { apb_write(dev, offset, (u32)(a >> 6)); } -static inline void apb_write_vc_addr_final(const struct rpivid_dev * const dev, +static inline void apb_write_vc_addr_final(const struct hevc_d_dev * const dev, const unsigned int offset, const dma_addr_t a) { apb_write_final(dev, offset, (u32)(a >> 6)); } -static inline void apb_write_vc_len(const struct rpivid_dev * const dev, +static inline void apb_write_vc_len(const struct hevc_d_dev * const dev, const unsigned int offset, const unsigned int x) { @@ -273,31 +273,31 @@ static inline void apb_write_vc_len(const struct rpivid_dev * const dev, ARG_IC_ICTRL_ACTIVE2_INT_SET) /* Regulate claim Q */ -void rpivid_hw_irq_active1_enable_claim(struct rpivid_dev *dev, +void hevc_d_hw_irq_active1_enable_claim(struct hevc_d_dev *dev, int n); /* Auto release once all CBs called */ -void rpivid_hw_irq_active1_claim(struct rpivid_dev *dev, - struct rpivid_hw_irq_ent *ient, - rpivid_irq_callback ready_cb, void *ctx); +void hevc_d_hw_irq_active1_claim(struct hevc_d_dev *dev, + struct hevc_d_hw_irq_ent *ient, + hevc_d_irq_callback ready_cb, void *ctx); /* May only be called in claim cb */ -void rpivid_hw_irq_active1_irq(struct rpivid_dev *dev, - struct rpivid_hw_irq_ent *ient, - rpivid_irq_callback irq_cb, void *ctx); +void hevc_d_hw_irq_active1_irq(struct hevc_d_dev *dev, + struct hevc_d_hw_irq_ent *ient, + hevc_d_irq_callback irq_cb, void *ctx); /* May only be called in irq cb */ -void rpivid_hw_irq_active1_thread(struct rpivid_dev *dev, - struct rpivid_hw_irq_ent *ient, - rpivid_irq_callback thread_cb, void *ctx); +void hevc_d_hw_irq_active1_thread(struct hevc_d_dev *dev, + struct hevc_d_hw_irq_ent *ient, + hevc_d_irq_callback thread_cb, void *ctx); /* Auto release once all CBs called */ -void rpivid_hw_irq_active2_claim(struct rpivid_dev *dev, - struct rpivid_hw_irq_ent *ient, - rpivid_irq_callback ready_cb, void *ctx); +void hevc_d_hw_irq_active2_claim(struct hevc_d_dev *dev, + struct hevc_d_hw_irq_ent *ient, + hevc_d_irq_callback ready_cb, void *ctx); /* May only be called in claim cb */ -void rpivid_hw_irq_active2_irq(struct rpivid_dev *dev, - struct rpivid_hw_irq_ent *ient, - rpivid_irq_callback irq_cb, void *ctx); +void hevc_d_hw_irq_active2_irq(struct hevc_d_dev *dev, + struct hevc_d_hw_irq_ent *ient, + hevc_d_irq_callback irq_cb, void *ctx); -int rpivid_hw_probe(struct rpivid_dev *dev); -void rpivid_hw_remove(struct rpivid_dev *dev); +int hevc_d_hw_probe(struct hevc_d_dev *dev); +void hevc_d_hw_remove(struct hevc_d_dev *dev); #endif diff --git a/drivers/staging/media/rpivid/rpivid_video.c b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_video.c similarity index 55% rename from drivers/staging/media/rpivid/rpivid_video.c rename to drivers/media/platform/raspberrypi/hevc_dec/hevc_d_video.c index 55e31eda8120d9..274af191d9e65e 100644 --- a/drivers/staging/media/rpivid/rpivid_video.c +++ b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_video.c @@ -2,7 +2,7 @@ /* * Raspberry Pi HEVC driver * - * Copyright (C) 2020 Raspberry Pi (Trading) Ltd + * Copyright (C) 2024 Raspberry Pi Ltd * * Based on the Cedrus VPU driver, that is: * @@ -17,24 +17,24 @@ #include #include -#include "rpivid.h" -#include "rpivid_hw.h" -#include "rpivid_video.h" -#include "rpivid_dec.h" +#include "hevc_d.h" +#include "hevc_d_h265.h" +#include "hevc_d_hw.h" +#include "hevc_d_video.h" -#define RPIVID_DECODE_SRC BIT(0) -#define RPIVID_DECODE_DST BIT(1) +#define HEVC_D_DECODE_SRC BIT(0) +#define HEVC_D_DECODE_DST BIT(1) -#define RPIVID_MIN_WIDTH 16U -#define RPIVID_MIN_HEIGHT 16U -#define RPIVID_DEFAULT_WIDTH 1920U -#define RPIVID_DEFAULT_HEIGHT 1088U -#define RPIVID_MAX_WIDTH 4096U -#define RPIVID_MAX_HEIGHT 4096U +#define HEVC_D_MIN_WIDTH 16U +#define HEVC_D_MIN_HEIGHT 16U +#define HEVC_D_DEFAULT_WIDTH 1920U +#define HEVC_D_DEFAULT_HEIGHT 1088U +#define HEVC_D_MAX_WIDTH 4096U +#define HEVC_D_MAX_HEIGHT 4096U -static inline struct rpivid_ctx *rpivid_file2ctx(struct file *file) +static inline struct hevc_d_ctx *hevc_d_file2ctx(struct file *file) { - return container_of(file->private_data, struct rpivid_ctx, fh); + return container_of(file->private_data, struct hevc_d_ctx, fh); } /* constrain x to y,y*2 */ @@ -45,7 +45,7 @@ static inline unsigned int constrain2x(unsigned int x, unsigned int y) (x > y * 2) ? y : x; } -size_t rpivid_round_up_size(const size_t x) +size_t hevc_d_round_up_size(const size_t x) { /* Admit no size < 256 */ const unsigned int n = x < 256 ? 8 : ilog2(x); @@ -53,7 +53,7 @@ size_t rpivid_round_up_size(const size_t x) return x >= (3 << n) ? 4 << n : (3 << n); } -size_t rpivid_bit_buf_size(unsigned int w, unsigned int h, unsigned int bits_minus8) +size_t hevc_d_bit_buf_size(unsigned int w, unsigned int h, unsigned int bits_minus8) { const size_t wxh = w * h; size_t bits_alloc; @@ -69,10 +69,10 @@ size_t rpivid_bit_buf_size(unsigned int w, unsigned int h, unsigned int bits_min wxh * 3 / 8; /* Allow for bit depth */ bits_alloc += (bits_alloc * bits_minus8) / 8; - return rpivid_round_up_size(bits_alloc); + return hevc_d_round_up_size(bits_alloc); } -void rpivid_prepare_src_format(struct v4l2_pix_format_mplane *pix_fmt) +void hevc_d_prepare_src_format(struct v4l2_pix_format_mplane *pix_fmt) { size_t size; u32 w; @@ -81,18 +81,18 @@ void rpivid_prepare_src_format(struct v4l2_pix_format_mplane *pix_fmt) w = pix_fmt->width; h = pix_fmt->height; if (!w || !h) { - w = RPIVID_DEFAULT_WIDTH; - h = RPIVID_DEFAULT_HEIGHT; + w = HEVC_D_DEFAULT_WIDTH; + h = HEVC_D_DEFAULT_HEIGHT; } - if (w > RPIVID_MAX_WIDTH) - w = RPIVID_MAX_WIDTH; - if (h > RPIVID_MAX_HEIGHT) - h = RPIVID_MAX_HEIGHT; + if (w > HEVC_D_MAX_WIDTH) + w = HEVC_D_MAX_WIDTH; + if (h > HEVC_D_MAX_HEIGHT) + h = HEVC_D_MAX_HEIGHT; if (!pix_fmt->plane_fmt[0].sizeimage || pix_fmt->plane_fmt[0].sizeimage > SZ_32M) { /* Unspecified or way too big - pick max for size */ - size = rpivid_bit_buf_size(w, h, 2); + size = hevc_d_bit_buf_size(w, h, 2); } /* Set a minimum */ size = max_t(u32, SZ_4K, pix_fmt->plane_fmt[0].sizeimage); @@ -108,7 +108,7 @@ void rpivid_prepare_src_format(struct v4l2_pix_format_mplane *pix_fmt) } /* Take any pix_format and make it valid */ -static void rpivid_prepare_dst_format(struct v4l2_pix_format_mplane *pix_fmt) +static void hevc_d_prepare_dst_format(struct v4l2_pix_format_mplane *pix_fmt) { unsigned int width = pix_fmt->width; unsigned int height = pix_fmt->height; @@ -116,35 +116,51 @@ static void rpivid_prepare_dst_format(struct v4l2_pix_format_mplane *pix_fmt) unsigned int bytesperline = pix_fmt->plane_fmt[0].bytesperline; if (!width) - width = RPIVID_DEFAULT_WIDTH; - if (width > RPIVID_MAX_WIDTH) - width = RPIVID_MAX_WIDTH; + width = HEVC_D_DEFAULT_WIDTH; + if (width > HEVC_D_MAX_WIDTH) + width = HEVC_D_MAX_WIDTH; if (!height) - height = RPIVID_DEFAULT_HEIGHT; - if (height > RPIVID_MAX_HEIGHT) - height = RPIVID_MAX_HEIGHT; + height = HEVC_D_DEFAULT_HEIGHT; + if (height > HEVC_D_MAX_HEIGHT) + height = HEVC_D_MAX_HEIGHT; /* For column formats set bytesperline to column height (stride2) */ switch (pix_fmt->pixelformat) { default: - pix_fmt->pixelformat = V4L2_PIX_FMT_NV12_COL128; + pix_fmt->pixelformat = V4L2_PIX_FMT_NV12MT_COL128; fallthrough; + case V4L2_PIX_FMT_NV12MT_COL128: + /* Width rounds up to columns */ + width = ALIGN(width, 128); + height = ALIGN(height, 8); + + /* column height is sizeimage / bytesperline */ + bytesperline = width; + sizeimage = bytesperline * height; + break; + + case V4L2_PIX_FMT_NV12MT_10_COL128: + /* width in pixels (3 pels = 4 bytes) rounded to 128 byte + * columns + */ + width = ALIGN(((width + 2) / 3), 32) * 3; + height = ALIGN(height, 8); + + /* column height is sizeimage / bytesperline */ + bytesperline = width * 4 / 3; + sizeimage = bytesperline * height; + break; + case V4L2_PIX_FMT_NV12_COL128: /* Width rounds up to columns */ width = ALIGN(width, 128); + height = ALIGN(height, 8); - /* 16 aligned height - not sure we even need that */ - height = ALIGN(height, 16); /* column height * Accept suggested shape if at least min & < 2 * min */ bytesperline = constrain2x(bytesperline, height * 3 / 2); - - /* image size - * Again allow plausible variation in case added padding is - * required - */ - sizeimage = constrain2x(sizeimage, bytesperline * width); + sizeimage = bytesperline * width; break; case V4L2_PIX_FMT_NV12_10_COL128: @@ -152,21 +168,13 @@ static void rpivid_prepare_dst_format(struct v4l2_pix_format_mplane *pix_fmt) * columns */ width = ALIGN(((width + 2) / 3), 32) * 3; - - /* 16-aligned height. */ - height = ALIGN(height, 16); + height = ALIGN(height, 8); /* column height * Accept suggested shape if at least min & < 2 * min */ bytesperline = constrain2x(bytesperline, height * 3 / 2); - - /* image size - * Again allow plausible variation in case added padding is - * required - */ - sizeimage = constrain2x(sizeimage, - bytesperline * width * 4 / 3); + sizeimage = bytesperline * width * 4 / 3; break; } @@ -174,28 +182,43 @@ static void rpivid_prepare_dst_format(struct v4l2_pix_format_mplane *pix_fmt) pix_fmt->height = height; pix_fmt->field = V4L2_FIELD_NONE; - pix_fmt->plane_fmt[0].bytesperline = bytesperline; - pix_fmt->plane_fmt[0].sizeimage = sizeimage; - pix_fmt->num_planes = 1; + switch (pix_fmt->pixelformat) { + default: + case V4L2_PIX_FMT_NV12MT_COL128: + case V4L2_PIX_FMT_NV12MT_10_COL128: + pix_fmt->plane_fmt[0].bytesperline = bytesperline; + pix_fmt->plane_fmt[0].sizeimage = sizeimage; + pix_fmt->plane_fmt[1].bytesperline = bytesperline; + pix_fmt->plane_fmt[1].sizeimage = sizeimage / 2; + pix_fmt->num_planes = 2; + break; + case V4L2_PIX_FMT_NV12_COL128: + case V4L2_PIX_FMT_NV12_10_COL128: + pix_fmt->plane_fmt[0].bytesperline = bytesperline; + pix_fmt->plane_fmt[0].sizeimage = sizeimage; + pix_fmt->num_planes = 1; + break; + } } -static int rpivid_querycap(struct file *file, void *priv, +static int hevc_d_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - strscpy(cap->driver, RPIVID_NAME, sizeof(cap->driver)); - strscpy(cap->card, RPIVID_NAME, sizeof(cap->card)); + strscpy(cap->driver, HEVC_D_NAME, sizeof(cap->driver)); + strscpy(cap->card, HEVC_D_NAME, sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), - "platform:%s", RPIVID_NAME); + "platform:%s", HEVC_D_NAME); return 0; } -static int rpivid_enum_fmt_vid_out(struct file *file, void *priv, +static int hevc_d_enum_fmt_vid_out(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - // Input formats - - // H.265 Slice only currently + /* + * Input formats + * H.265 Slice only + */ if (f->index == 0) { f->pixelformat = V4L2_PIX_FMT_HEVC_SLICE; return 0; @@ -204,7 +227,7 @@ static int rpivid_enum_fmt_vid_out(struct file *file, void *priv, return -EINVAL; } -static int rpivid_hevc_validate_sps(const struct v4l2_ctrl_hevc_sps * const sps) +static int hevc_d_hevc_validate_sps(const struct v4l2_ctrl_hevc_sps * const sps) { const unsigned int ctb_log2_size_y = sps->log2_min_luma_coding_block_size_minus3 + 3 + @@ -260,29 +283,51 @@ static int rpivid_hevc_validate_sps(const struct v4l2_ctrl_hevc_sps * const sps) static u32 pixelformat_from_sps(const struct v4l2_ctrl_hevc_sps * const sps, const int index) { + static const u32 all_formats[] = { + //V4L2_PIX_FMT_NV12MT_COL128, + //V4L2_PIX_FMT_NV12MT_10_COL128, + V4L2_PIX_FMT_NV12_COL128, + V4L2_PIX_FMT_NV12_10_COL128, + }; u32 pf = 0; - if (!is_sps_set(sps) || !rpivid_hevc_validate_sps(sps)) { + if (!is_sps_set(sps) || !hevc_d_hevc_validate_sps(sps)) { /* Treat this as an error? For now return both */ - if (index == 0) - pf = V4L2_PIX_FMT_NV12_COL128; - else if (index == 1) - pf = V4L2_PIX_FMT_NV12_10_COL128; - } else if (index == 0) { - if (sps->bit_depth_luma_minus8 == 0) - pf = V4L2_PIX_FMT_NV12_COL128; - else if (sps->bit_depth_luma_minus8 == 2) - pf = V4L2_PIX_FMT_NV12_10_COL128; + + if (index < ARRAY_SIZE(all_formats)) + pf = all_formats[index]; + } else { + if (index == 0) { +/* if (sps->bit_depth_luma_minus8 == 0) + pf = V4L2_PIX_FMT_NV12MT_COL128; + else if (sps->bit_depth_luma_minus8 == 2) + pf = V4L2_PIX_FMT_NV12MT_10_COL128; + } else if (index == 1) { + */ + if (sps->bit_depth_luma_minus8 == 0) + pf = V4L2_PIX_FMT_NV12_COL128; + else if (sps->bit_depth_luma_minus8 == 2) + pf = V4L2_PIX_FMT_NV12_10_COL128; + } } return pf; } +static void copy_color(struct v4l2_pix_format_mplane *d, + const struct v4l2_pix_format_mplane *s) +{ + d->colorspace = s->colorspace; + d->xfer_func = s->xfer_func; + d->ycbcr_enc = s->ycbcr_enc; + d->quantization = s->quantization; +} + static struct v4l2_pix_format_mplane -rpivid_hevc_default_dst_fmt(struct rpivid_ctx * const ctx) +hevc_d_hevc_default_dst_fmt(struct hevc_d_ctx * const ctx) { const struct v4l2_ctrl_hevc_sps * const sps = - rpivid_find_control_data(ctx, V4L2_CID_STATELESS_HEVC_SPS); + hevc_d_find_control_data(ctx, V4L2_CID_STATELESS_HEVC_SPS); struct v4l2_pix_format_mplane pix_fmt; memset(&pix_fmt, 0, sizeof(pix_fmt)); @@ -292,25 +337,27 @@ rpivid_hevc_default_dst_fmt(struct rpivid_ctx * const ctx) pix_fmt.pixelformat = pixelformat_from_sps(sps, 0); } - rpivid_prepare_dst_format(&pix_fmt); + hevc_d_prepare_dst_format(&pix_fmt); + copy_color(&pix_fmt, &ctx->src_fmt); + return pix_fmt; } -static u32 rpivid_hevc_get_dst_pixelformat(struct rpivid_ctx * const ctx, +static u32 hevc_d_hevc_get_dst_pixelformat(struct hevc_d_ctx * const ctx, const int index) { const struct v4l2_ctrl_hevc_sps * const sps = - rpivid_find_control_data(ctx, V4L2_CID_STATELESS_HEVC_SPS); + hevc_d_find_control_data(ctx, V4L2_CID_STATELESS_HEVC_SPS); return pixelformat_from_sps(sps, index); } -static int rpivid_enum_fmt_vid_cap(struct file *file, void *priv, +static int hevc_d_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - struct rpivid_ctx * const ctx = rpivid_file2ctx(file); + struct hevc_d_ctx * const ctx = hevc_d_file2ctx(file); - const u32 pf = rpivid_hevc_get_dst_pixelformat(ctx, f->index); + const u32 pf = hevc_d_hevc_get_dst_pixelformat(ctx, f->index); if (pf == 0) return -EINVAL; @@ -323,46 +370,37 @@ static int rpivid_enum_fmt_vid_cap(struct file *file, void *priv, * get dst format - sets it to default if otherwise unset * returns a pointer to the struct as a convienience */ -static struct v4l2_pix_format_mplane *get_dst_fmt(struct rpivid_ctx *const ctx) +static struct v4l2_pix_format_mplane *get_dst_fmt(struct hevc_d_ctx *const ctx) { if (!ctx->dst_fmt_set) - ctx->dst_fmt = rpivid_hevc_default_dst_fmt(ctx); + ctx->dst_fmt = hevc_d_hevc_default_dst_fmt(ctx); return &ctx->dst_fmt; } -static int rpivid_g_fmt_vid_cap(struct file *file, void *priv, +static int hevc_d_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct rpivid_ctx *ctx = rpivid_file2ctx(file); + struct hevc_d_ctx *ctx = hevc_d_file2ctx(file); f->fmt.pix_mp = *get_dst_fmt(ctx); return 0; } -static int rpivid_g_fmt_vid_out(struct file *file, void *priv, +static int hevc_d_g_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f) { - struct rpivid_ctx *ctx = rpivid_file2ctx(file); + struct hevc_d_ctx *ctx = hevc_d_file2ctx(file); f->fmt.pix_mp = ctx->src_fmt; return 0; } -static inline void copy_color(struct v4l2_pix_format_mplane *d, - const struct v4l2_pix_format_mplane *s) -{ - d->colorspace = s->colorspace; - d->xfer_func = s->xfer_func; - d->ycbcr_enc = s->ycbcr_enc; - d->quantization = s->quantization; -} - -static int rpivid_try_fmt_vid_cap(struct file *file, void *priv, +static int hevc_d_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct rpivid_ctx *ctx = rpivid_file2ctx(file); + struct hevc_d_ctx *ctx = hevc_d_file2ctx(file); const struct v4l2_ctrl_hevc_sps * const sps = - rpivid_find_control_data(ctx, V4L2_CID_STATELESS_HEVC_SPS); + hevc_d_find_control_data(ctx, V4L2_CID_STATELESS_HEVC_SPS); u32 pixelformat; int i; @@ -371,27 +409,29 @@ static int rpivid_try_fmt_vid_cap(struct file *file, void *priv, break; } - // We don't have any way of finding out colourspace so believe - // anything we are told - take anything set in src as a default + /* + * We don't have any way of finding out colourspace so believe + * anything we are told - take anything set in src as a default + */ if (f->fmt.pix_mp.colorspace == V4L2_COLORSPACE_DEFAULT) copy_color(&f->fmt.pix_mp, &ctx->src_fmt); f->fmt.pix_mp.pixelformat = pixelformat; - rpivid_prepare_dst_format(&f->fmt.pix_mp); + hevc_d_prepare_dst_format(&f->fmt.pix_mp); return 0; } -static int rpivid_try_fmt_vid_out(struct file *file, void *priv, +static int hevc_d_try_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f) { - rpivid_prepare_src_format(&f->fmt.pix_mp); + hevc_d_prepare_src_format(&f->fmt.pix_mp); return 0; } -static int rpivid_s_fmt_vid_cap(struct file *file, void *priv, +static int hevc_d_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct rpivid_ctx *ctx = rpivid_file2ctx(file); + struct hevc_d_ctx *ctx = hevc_d_file2ctx(file); struct vb2_queue *vq; int ret; @@ -399,7 +439,7 @@ static int rpivid_s_fmt_vid_cap(struct file *file, void *priv, if (vb2_is_busy(vq)) return -EBUSY; - ret = rpivid_try_fmt_vid_cap(file, priv, f); + ret = hevc_d_try_fmt_vid_cap(file, priv, f); if (ret) return ret; @@ -409,10 +449,10 @@ static int rpivid_s_fmt_vid_cap(struct file *file, void *priv, return 0; } -static int rpivid_s_fmt_vid_out(struct file *file, void *priv, +static int hevc_d_s_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f) { - struct rpivid_ctx *ctx = rpivid_file2ctx(file); + struct hevc_d_ctx *ctx = hevc_d_file2ctx(file); struct vb2_queue *vq; int ret; @@ -420,33 +460,30 @@ static int rpivid_s_fmt_vid_out(struct file *file, void *priv, if (vb2_is_busy(vq)) return -EBUSY; - ret = rpivid_try_fmt_vid_out(file, priv, f); + ret = hevc_d_try_fmt_vid_out(file, priv, f); if (ret) return ret; ctx->src_fmt = f->fmt.pix_mp; - ctx->dst_fmt_set = 0; // Setting src invalidates dst - - vq->subsystem_flags |= - VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF; + ctx->dst_fmt_set = 0; /* Setting src invalidates dst */ /* Propagate colorspace information to capture. */ copy_color(&ctx->dst_fmt, &f->fmt.pix_mp); return 0; } -const struct v4l2_ioctl_ops rpivid_ioctl_ops = { - .vidioc_querycap = rpivid_querycap, +const struct v4l2_ioctl_ops hevc_d_ioctl_ops = { + .vidioc_querycap = hevc_d_querycap, - .vidioc_enum_fmt_vid_cap = rpivid_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap_mplane = rpivid_g_fmt_vid_cap, - .vidioc_try_fmt_vid_cap_mplane = rpivid_try_fmt_vid_cap, - .vidioc_s_fmt_vid_cap_mplane = rpivid_s_fmt_vid_cap, + .vidioc_enum_fmt_vid_cap = hevc_d_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap_mplane = hevc_d_g_fmt_vid_cap, + .vidioc_try_fmt_vid_cap_mplane = hevc_d_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap_mplane = hevc_d_s_fmt_vid_cap, - .vidioc_enum_fmt_vid_out = rpivid_enum_fmt_vid_out, - .vidioc_g_fmt_vid_out_mplane = rpivid_g_fmt_vid_out, - .vidioc_try_fmt_vid_out_mplane = rpivid_try_fmt_vid_out, - .vidioc_s_fmt_vid_out_mplane = rpivid_s_fmt_vid_out, + .vidioc_enum_fmt_vid_out = hevc_d_enum_fmt_vid_out, + .vidioc_g_fmt_vid_out_mplane = hevc_d_g_fmt_vid_out, + .vidioc_try_fmt_vid_out_mplane = hevc_d_try_fmt_vid_out, + .vidioc_s_fmt_vid_out_mplane = hevc_d_s_fmt_vid_out, .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, @@ -466,32 +503,54 @@ const struct v4l2_ioctl_ops rpivid_ioctl_ops = { .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; -static int rpivid_queue_setup(struct vb2_queue *vq, unsigned int *nbufs, +static int hevc_d_queue_setup(struct vb2_queue *vq, unsigned int *nbufs, unsigned int *nplanes, unsigned int sizes[], struct device *alloc_devs[]) { - struct rpivid_ctx *ctx = vb2_get_drv_priv(vq); + struct hevc_d_ctx *ctx = vb2_get_drv_priv(vq); struct v4l2_pix_format_mplane *pix_fmt; + int expected_nplanes; - if (V4L2_TYPE_IS_OUTPUT(vq->type)) + if (V4L2_TYPE_IS_OUTPUT(vq->type)) { pix_fmt = &ctx->src_fmt; - else + expected_nplanes = 1; + } else { pix_fmt = get_dst_fmt(ctx); + expected_nplanes = 2; + } if (*nplanes) { - if (sizes[0] < pix_fmt->plane_fmt[0].sizeimage) - return -EINVAL; + if (pix_fmt->pixelformat == V4L2_PIX_FMT_NV12MT_COL128 || + pix_fmt->pixelformat == V4L2_PIX_FMT_NV12MT_10_COL128) { + if (*nplanes != expected_nplanes || + sizes[0] < pix_fmt->plane_fmt[0].sizeimage || + sizes[1] < pix_fmt->plane_fmt[1].sizeimage) + return -EINVAL; + } else { + if (sizes[0] < pix_fmt->plane_fmt[0].sizeimage) + return -EINVAL; + } } else { sizes[0] = pix_fmt->plane_fmt[0].sizeimage; - *nplanes = 1; + if (V4L2_TYPE_IS_OUTPUT(vq->type)) { + *nplanes = 1; + } else { + if (pix_fmt->pixelformat == V4L2_PIX_FMT_NV12MT_COL128 || + pix_fmt->pixelformat == V4L2_PIX_FMT_NV12MT_10_COL128) { + sizes[1] = pix_fmt->plane_fmt[1].sizeimage; + *nplanes = 2; + } else { + *nplanes = 1; + } + } } return 0; } -static void rpivid_queue_cleanup(struct vb2_queue *vq, u32 state) +static void hevc_d_queue_cleanup(struct vb2_queue *vq, u32 state) { - struct rpivid_ctx *ctx = vb2_get_drv_priv(vq); + struct hevc_d_ctx *ctx = vb2_get_drv_priv(vq); struct vb2_v4l2_buffer *vbuf; for (;;) { @@ -509,7 +568,7 @@ static void rpivid_queue_cleanup(struct vb2_queue *vq, u32 state) } } -static int rpivid_buf_out_validate(struct vb2_buffer *vb) +static int hevc_d_buf_out_validate(struct vb2_buffer *vb) { struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); @@ -517,10 +576,10 @@ static int rpivid_buf_out_validate(struct vb2_buffer *vb) return 0; } -static int rpivid_buf_prepare(struct vb2_buffer *vb) +static int hevc_d_buf_prepare(struct vb2_buffer *vb) { struct vb2_queue *vq = vb->vb2_queue; - struct rpivid_ctx *ctx = vb2_get_drv_priv(vq); + struct hevc_d_ctx *ctx = vb2_get_drv_priv(vq); struct v4l2_pix_format_mplane *pix_fmt; if (V4L2_TYPE_IS_OUTPUT(vq->type)) @@ -528,16 +587,18 @@ static int rpivid_buf_prepare(struct vb2_buffer *vb) else pix_fmt = &ctx->dst_fmt; - if (vb2_plane_size(vb, 0) < pix_fmt->plane_fmt[0].sizeimage) + if (vb2_plane_size(vb, 0) < pix_fmt->plane_fmt[0].sizeimage || + vb2_plane_size(vb, 1) < pix_fmt->plane_fmt[1].sizeimage) return -EINVAL; vb2_set_plane_payload(vb, 0, pix_fmt->plane_fmt[0].sizeimage); + vb2_set_plane_payload(vb, 1, pix_fmt->plane_fmt[1].sizeimage); return 0; } /* Only stops the clock if streaom off on both output & capture */ -static void stop_clock(struct rpivid_dev *dev, struct rpivid_ctx *ctx) +static void stop_clock(struct hevc_d_dev *dev, struct hevc_d_ctx *ctx) { if (ctx->src_stream_on || ctx->dst_stream_on) @@ -548,7 +609,7 @@ static void stop_clock(struct rpivid_dev *dev, struct rpivid_ctx *ctx) } /* Always starts the clock if it isn't already on this ctx */ -static int start_clock(struct rpivid_dev *dev, struct rpivid_ctx *ctx) +static int start_clock(struct hevc_d_dev *dev, struct hevc_d_ctx *ctx) { int rv; @@ -567,10 +628,10 @@ static int start_clock(struct rpivid_dev *dev, struct rpivid_ctx *ctx) return 0; } -static int rpivid_start_streaming(struct vb2_queue *vq, unsigned int count) +static int hevc_d_start_streaming(struct vb2_queue *vq, unsigned int count) { - struct rpivid_ctx *ctx = vb2_get_drv_priv(vq); - struct rpivid_dev *dev = ctx->dev; + struct hevc_d_ctx *ctx = vb2_get_drv_priv(vq); + struct hevc_d_dev *dev = ctx->dev; int ret = 0; if (!V4L2_TYPE_IS_OUTPUT(vq->type)) { @@ -590,8 +651,7 @@ static int rpivid_start_streaming(struct vb2_queue *vq, unsigned int count) if (ret) goto fail_cleanup; - if (dev->dec_ops->start) - ret = dev->dec_ops->start(ctx); + ret = hevc_d_h265_start(ctx); if (ret) goto fail_stop_clock; @@ -603,68 +663,67 @@ static int rpivid_start_streaming(struct vb2_queue *vq, unsigned int count) stop_clock(dev, ctx); fail_cleanup: v4l2_err(&dev->v4l2_dev, "%s: qtype=%d: FAIL\n", __func__, vq->type); - rpivid_queue_cleanup(vq, VB2_BUF_STATE_QUEUED); + hevc_d_queue_cleanup(vq, VB2_BUF_STATE_QUEUED); return ret; } -static void rpivid_stop_streaming(struct vb2_queue *vq) +static void hevc_d_stop_streaming(struct vb2_queue *vq) { - struct rpivid_ctx *ctx = vb2_get_drv_priv(vq); - struct rpivid_dev *dev = ctx->dev; + struct hevc_d_ctx *ctx = vb2_get_drv_priv(vq); + struct hevc_d_dev *dev = ctx->dev; if (V4L2_TYPE_IS_OUTPUT(vq->type)) { ctx->src_stream_on = 0; - if (dev->dec_ops->stop) - dev->dec_ops->stop(ctx); + hevc_d_h265_stop(ctx); } else { ctx->dst_stream_on = 0; } - rpivid_queue_cleanup(vq, VB2_BUF_STATE_ERROR); + hevc_d_queue_cleanup(vq, VB2_BUF_STATE_ERROR); vb2_wait_for_all_buffers(vq); stop_clock(dev, ctx); } -static void rpivid_buf_queue(struct vb2_buffer *vb) +static void hevc_d_buf_queue(struct vb2_buffer *vb) { struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct rpivid_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct hevc_d_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); } -static void rpivid_buf_request_complete(struct vb2_buffer *vb) +static void hevc_d_buf_request_complete(struct vb2_buffer *vb) { - struct rpivid_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct hevc_d_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->hdl); } -static struct vb2_ops rpivid_qops = { - .queue_setup = rpivid_queue_setup, - .buf_prepare = rpivid_buf_prepare, - .buf_queue = rpivid_buf_queue, - .buf_out_validate = rpivid_buf_out_validate, - .buf_request_complete = rpivid_buf_request_complete, - .start_streaming = rpivid_start_streaming, - .stop_streaming = rpivid_stop_streaming, +static const struct vb2_ops hevc_d_qops = { + .queue_setup = hevc_d_queue_setup, + .buf_prepare = hevc_d_buf_prepare, + .buf_queue = hevc_d_buf_queue, + .buf_out_validate = hevc_d_buf_out_validate, + .buf_request_complete = hevc_d_buf_request_complete, + .start_streaming = hevc_d_start_streaming, + .stop_streaming = hevc_d_stop_streaming, .wait_prepare = vb2_ops_wait_prepare, .wait_finish = vb2_ops_wait_finish, }; -int rpivid_queue_init(void *priv, struct vb2_queue *src_vq, +int hevc_d_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) { - struct rpivid_ctx *ctx = priv; + struct hevc_d_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->buf_struct_size = sizeof(struct rpivid_buffer); - src_vq->ops = &rpivid_qops; + src_vq->buf_struct_size = sizeof(struct hevc_d_buffer); + src_vq->ops = &hevc_d_qops; src_vq->mem_ops = &vb2_dma_contig_memops; src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; src_vq->lock = &ctx->ctx_mutex; @@ -679,9 +738,9 @@ int rpivid_queue_init(void *priv, struct vb2_queue *src_vq, dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; dst_vq->drv_priv = ctx; - dst_vq->buf_struct_size = sizeof(struct rpivid_buffer); + dst_vq->buf_struct_size = sizeof(struct hevc_d_buffer); dst_vq->min_queued_buffers = 1; - dst_vq->ops = &rpivid_qops; + dst_vq->ops = &hevc_d_qops; dst_vq->mem_ops = &vb2_dma_contig_memops; dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; dst_vq->lock = &ctx->ctx_mutex; diff --git a/drivers/staging/media/rpivid/rpivid_video.h b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_video.h similarity index 53% rename from drivers/staging/media/rpivid/rpivid_video.h rename to drivers/media/platform/raspberrypi/hevc_dec/hevc_d_video.h index 9db3a1968682f1..3ea193423194da 100644 --- a/drivers/staging/media/rpivid/rpivid_video.h +++ b/drivers/media/platform/raspberrypi/hevc_dec/hevc_d_video.h @@ -2,7 +2,7 @@ /* * Raspberry Pi HEVC driver * - * Copyright (C) 2020 Raspberry Pi (Trading) Ltd + * Copyright (C) 2024 Raspberry Pi Ltd * * Based on the Cedrus VPU driver, that is: * @@ -11,10 +11,10 @@ * Copyright (C) 2018 Bootlin */ -#ifndef _RPIVID_VIDEO_H_ -#define _RPIVID_VIDEO_H_ +#ifndef _HEVC_D_VIDEO_H_ +#define _HEVC_D_VIDEO_H_ -struct rpivid_format { +struct hevc_d_format { u32 pixelformat; u32 directions; unsigned int capabilities; @@ -22,17 +22,17 @@ struct rpivid_format { static inline int is_sps_set(const struct v4l2_ctrl_hevc_sps * const sps) { - return sps && sps->pic_width_in_luma_samples != 0; + return sps && sps->pic_width_in_luma_samples; } -extern const struct v4l2_ioctl_ops rpivid_ioctl_ops; +extern const struct v4l2_ioctl_ops hevc_d_ioctl_ops; -int rpivid_queue_init(void *priv, struct vb2_queue *src_vq, +int hevc_d_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq); -size_t rpivid_bit_buf_size(unsigned int w, unsigned int h, unsigned int bits_minus8); -size_t rpivid_round_up_size(const size_t x); +size_t hevc_d_bit_buf_size(unsigned int w, unsigned int h, unsigned int bits_minus8); +size_t hevc_d_round_up_size(const size_t x); -void rpivid_prepare_src_format(struct v4l2_pix_format_mplane *pix_fmt); +void hevc_d_prepare_src_format(struct v4l2_pix_format_mplane *pix_fmt); #endif diff --git a/drivers/media/test-drivers/vicodec/vicodec-core.c b/drivers/media/test-drivers/vicodec/vicodec-core.c index 846e90c062910e..2870fa3b529cfd 100644 --- a/drivers/media/test-drivers/vicodec/vicodec-core.c +++ b/drivers/media/test-drivers/vicodec/vicodec-core.c @@ -446,8 +446,10 @@ static void device_run(void *priv) ctx->comp_magic_cnt = 0; ctx->comp_has_frame = false; spin_unlock(ctx->lock); - if (ctx->is_stateless && src_req) + if (ctx->is_stateless && src_req) { v4l2_ctrl_request_complete(src_req, &ctx->hdl); + media_request_manual_complete(src_req); + } if (ctx->is_enc) v4l2_m2m_job_finish(dev->stateful_enc.m2m_dev, ctx->fh.m2m_ctx); @@ -1523,8 +1525,12 @@ static void vicodec_return_bufs(struct vb2_queue *q, u32 state) vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); if (vbuf == NULL) return; - v4l2_ctrl_request_complete(vbuf->vb2_buf.req_obj.req, - &ctx->hdl); + if (ctx->is_stateless && V4L2_TYPE_IS_OUTPUT(q->type)) { + struct media_request *req = vbuf->vb2_buf.req_obj.req; + + v4l2_ctrl_request_complete(req, &ctx->hdl); + media_request_manual_complete(req); + } spin_lock(ctx->lock); v4l2_m2m_buf_done(vbuf, state); spin_unlock(ctx->lock); @@ -1677,6 +1683,7 @@ static void vicodec_buf_request_complete(struct vb2_buffer *vb) struct vicodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->hdl); + media_request_manual_complete(vb->req_obj.req); } @@ -2001,6 +2008,12 @@ static int vicodec_request_validate(struct media_request *req) return vb2_request_validate(req); } +static void vicodec_request_queue(struct media_request *req) +{ + media_request_mark_manual_completion(req); + v4l2_m2m_request_queue(req); +} + static const struct v4l2_file_operations vicodec_fops = { .owner = THIS_MODULE, .open = vicodec_open, @@ -2021,7 +2034,7 @@ static const struct video_device vicodec_videodev = { static const struct media_device_ops vicodec_m2m_media_ops = { .req_validate = vicodec_request_validate, - .req_queue = v4l2_m2m_request_queue, + .req_queue = vicodec_request_queue, }; static const struct v4l2_m2m_ops m2m_ops = { diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index d132f73111f69b..1f4b79c02ce021 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1369,6 +1369,8 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_PIX_FMT_NV12_4L4: descr = "Y/UV 4:2:0 (4x4 Linear)"; break; case V4L2_PIX_FMT_NV12_16L16: descr = "Y/UV 4:2:0 (16x16 Linear)"; break; case V4L2_PIX_FMT_NV12_32L32: descr = "Y/UV 4:2:0 (32x32 Linear)"; break; + case V4L2_PIX_FMT_NV12_COL128: descr = "Y/CbCr 4:2:0 (128b cols)"; break; + case V4L2_PIX_FMT_NV12_10_COL128: descr = "10-bit Y/CbCr 4:2:0 (128b cols)"; break; case V4L2_PIX_FMT_NV15_4L4: descr = "10-bit Y/UV 4:2:0 (4x4 Linear)"; break; case V4L2_PIX_FMT_P010_4L4: descr = "10-bit Y/UV 4:2:0 (4x4 Linear)"; break; case V4L2_PIX_FMT_NV12M: descr = "Y/UV 4:2:0 (N-C)"; break; @@ -1376,10 +1378,10 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_PIX_FMT_NV16M: descr = "Y/UV 4:2:2 (N-C)"; break; case V4L2_PIX_FMT_NV61M: descr = "Y/VU 4:2:2 (N-C)"; break; case V4L2_PIX_FMT_NV12MT: descr = "Y/UV 4:2:0 (64x32 MB, N-C)"; break; + case V4L2_PIX_FMT_NV12MT_COL128: descr = "Y/CbCr 4:2:0 (128b cols)"; break; case V4L2_PIX_FMT_NV12MT_16X16: descr = "Y/UV 4:2:0 (16x16 MB, N-C)"; break; + case V4L2_PIX_FMT_NV12MT_10_COL128: descr = "10-bit Y/CbCr 4:2:0 (128b cols)"; break; case V4L2_PIX_FMT_P012M: descr = "12-bit Y/UV 4:2:0 (N-C)"; break; - case V4L2_PIX_FMT_NV12_COL128: descr = "Y/CbCr 4:2:0 (128b cols)"; break; - case V4L2_PIX_FMT_NV12_10_COL128: descr = "10-bit Y/CbCr 4:2:0 (128b cols)"; break; case V4L2_PIX_FMT_YUV420M: descr = "Planar YUV 4:2:0 (N-C)"; break; case V4L2_PIX_FMT_YVU420M: descr = "Planar YVU 4:2:0 (N-C)"; break; case V4L2_PIX_FMT_YUV422M: descr = "Planar YUV 4:2:2 (N-C)"; break; diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c index 8db37425b96f35..eb22d6172462da 100644 --- a/drivers/media/v4l2-core/v4l2-mem2mem.c +++ b/drivers/media/v4l2-core/v4l2-mem2mem.c @@ -495,6 +495,8 @@ void v4l2_m2m_job_finish(struct v4l2_m2m_dev *m2m_dev, * holding capture buffers. Those should use * v4l2_m2m_buf_done_and_job_finish() instead. */ + WARN_ON(m2m_ctx->out_q_ctx.q.subsystem_flags & + VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF); spin_lock_irqsave(&m2m_dev->job_spinlock, flags); schedule_next = _v4l2_m2m_job_finish(m2m_dev, m2m_ctx); spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags); diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig index 76d1aaf0c6b03c..554c2e475ce3bf 100644 --- a/drivers/staging/media/Kconfig +++ b/drivers/staging/media/Kconfig @@ -36,8 +36,6 @@ source "drivers/staging/media/omap4iss/Kconfig" source "drivers/staging/media/rkvdec/Kconfig" -source "drivers/staging/media/rpivid/Kconfig" - source "drivers/staging/media/starfive/Kconfig" source "drivers/staging/media/sunxi/Kconfig" diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile index 2eef2e38fc8ad7..dcaeeca0ee6d72 100644 --- a/drivers/staging/media/Makefile +++ b/drivers/staging/media/Makefile @@ -6,7 +6,6 @@ obj-$(CONFIG_VIDEO_MAX96712) += max96712/ obj-$(CONFIG_VIDEO_MESON_VDEC) += meson/vdec/ obj-$(CONFIG_VIDEO_OMAP4) += omap4iss/ obj-$(CONFIG_VIDEO_ROCKCHIP_VDEC) += rkvdec/ -obj-$(CONFIG_VIDEO_RPIVID) += rpivid/ obj-$(CONFIG_VIDEO_STARFIVE_CAMSS) += starfive/ obj-$(CONFIG_VIDEO_SUNXI) += sunxi/ obj-$(CONFIG_VIDEO_TEGRA) += tegra-video/ diff --git a/drivers/staging/media/rpivid/Makefile b/drivers/staging/media/rpivid/Makefile deleted file mode 100644 index 990257052b0726..00000000000000 --- a/drivers/staging/media/rpivid/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_VIDEO_RPIVID) += rpivid-hevc.o - -rpivid-hevc-y = rpivid.o rpivid_video.o rpivid_dec.o \ - rpivid_hw.o rpivid_h265.o diff --git a/drivers/staging/media/rpivid/rpivid.h b/drivers/staging/media/rpivid/rpivid.h deleted file mode 100644 index 9d6c2adb331b5b..00000000000000 --- a/drivers/staging/media/rpivid/rpivid.h +++ /dev/null @@ -1,203 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Raspberry Pi HEVC driver - * - * Copyright (C) 2020 Raspberry Pi (Trading) Ltd - * - * Based on the Cedrus VPU driver, that is: - * - * Copyright (C) 2016 Florent Revest - * Copyright (C) 2018 Paul Kocialkowski - * Copyright (C) 2018 Bootlin - */ - -#ifndef _RPIVID_H_ -#define _RPIVID_H_ - -#include -#include -#include -#include -#include -#include -#include - -#define OPT_DEBUG_POLL_IRQ 0 - -#define RPIVID_DEC_ENV_COUNT 6 -#define RPIVID_P1BUF_COUNT 3 -#define RPIVID_P2BUF_COUNT 3 - -#define RPIVID_NAME "rpivid" - -#define RPIVID_CAPABILITY_UNTILED BIT(0) -#define RPIVID_CAPABILITY_H265_DEC BIT(1) - -#define RPIVID_QUIRK_NO_DMA_OFFSET BIT(0) - -enum rpivid_irq_status { - RPIVID_IRQ_NONE, - RPIVID_IRQ_ERROR, - RPIVID_IRQ_OK, -}; - -struct rpivid_control { - struct v4l2_ctrl_config cfg; - unsigned char required:1; -}; - -struct rpivid_h265_run { - u32 slice_ents; - const struct v4l2_ctrl_hevc_sps *sps; - const struct v4l2_ctrl_hevc_pps *pps; - const struct v4l2_ctrl_hevc_decode_params *dec; - const struct v4l2_ctrl_hevc_slice_params *slice_params; - const struct v4l2_ctrl_hevc_scaling_matrix *scaling_matrix; -}; - -struct rpivid_run { - struct vb2_v4l2_buffer *src; - struct vb2_v4l2_buffer *dst; - - struct rpivid_h265_run h265; -}; - -struct rpivid_buffer { - struct v4l2_m2m_buffer m2m_buf; -}; - -struct rpivid_dec_state; -struct rpivid_dec_env; - -struct rpivid_gptr { - size_t size; - __u8 *ptr; - dma_addr_t addr; - unsigned long attrs; -}; - -struct rpivid_dev; -typedef void (*rpivid_irq_callback)(struct rpivid_dev *dev, void *ctx); - -struct rpivid_q_aux; -#define RPIVID_AUX_ENT_COUNT VB2_MAX_FRAME - -struct rpivid_ctx { - struct v4l2_fh fh; - struct rpivid_dev *dev; - - struct v4l2_pix_format_mplane src_fmt; - struct v4l2_pix_format_mplane dst_fmt; - int dst_fmt_set; - - int src_stream_on; - int dst_stream_on; - - // fatal_err is set if an error has occurred s.t. decode cannot - // continue (such as running out of CMA) - int fatal_err; - - /* Lock for queue operations */ - struct mutex ctx_mutex; - - struct v4l2_ctrl_handler hdl; - struct v4l2_ctrl **ctrls; - - /* Decode state - stateless decoder my *** */ - /* state contains stuff that is only needed in phase0 - * it could be held in dec_env but that would be wasteful - */ - struct rpivid_dec_state *state; - struct rpivid_dec_env *dec0; - - /* Spinlock protecting dec_free */ - spinlock_t dec_lock; - struct rpivid_dec_env *dec_free; - - struct rpivid_dec_env *dec_pool; - - unsigned int p1idx; - atomic_t p1out; - struct rpivid_gptr bitbufs[RPIVID_P1BUF_COUNT]; - - /* *** Should be in dev *** */ - unsigned int p2idx; - struct rpivid_gptr pu_bufs[RPIVID_P2BUF_COUNT]; - struct rpivid_gptr coeff_bufs[RPIVID_P2BUF_COUNT]; - - /* Spinlock protecting aux_free */ - spinlock_t aux_lock; - struct rpivid_q_aux *aux_free; - - struct rpivid_q_aux *aux_ents[RPIVID_AUX_ENT_COUNT]; - - unsigned int colmv_stride; - unsigned int colmv_picsize; -}; - -struct rpivid_dec_ops { - void (*setup)(struct rpivid_ctx *ctx, struct rpivid_run *run); - int (*start)(struct rpivid_ctx *ctx); - void (*stop)(struct rpivid_ctx *ctx); - void (*trigger)(struct rpivid_ctx *ctx); -}; - -struct rpivid_variant { - unsigned int capabilities; - unsigned int quirks; - unsigned int mod_rate; -}; - -struct rpivid_hw_irq_ent; - -#define RPIVID_ICTL_ENABLE_UNLIMITED (-1) - -struct rpivid_hw_irq_ctrl { - /* Spinlock protecting claim and tail */ - spinlock_t lock; - struct rpivid_hw_irq_ent *claim; - struct rpivid_hw_irq_ent *tail; - - /* Ent for pending irq - also prevents sched */ - struct rpivid_hw_irq_ent *irq; - /* Non-zero => do not start a new job - outer layer sched pending */ - int no_sched; - /* Enable count. -1 always OK, 0 do not sched, +ve shed & count down */ - int enable; - /* Thread CB requested */ - bool thread_reqed; -}; - -struct rpivid_dev { - struct v4l2_device v4l2_dev; - struct video_device vfd; - struct media_device mdev; - struct media_pad pad[2]; - struct platform_device *pdev; - struct device *dev; - struct v4l2_m2m_dev *m2m_dev; - const struct rpivid_dec_ops *dec_ops; - - /* Device file mutex */ - struct mutex dev_mutex; - - void __iomem *base_irq; - void __iomem *base_h265; - - struct clk *clock; - unsigned long max_clock_rate; - - int cache_align; - - struct rpivid_hw_irq_ctrl ic_active1; - struct rpivid_hw_irq_ctrl ic_active2; -}; - -extern const struct rpivid_dec_ops rpivid_dec_ops_h265; -extern const struct v4l2_ctrl_ops rpivid_hevc_sps_ctrl_ops; -extern const struct v4l2_ctrl_ops rpivid_hevc_pps_ctrl_ops; - -struct v4l2_ctrl *rpivid_find_ctrl(struct rpivid_ctx *ctx, u32 id); -void *rpivid_find_control_data(struct rpivid_ctx *ctx, u32 id); - -#endif diff --git a/drivers/staging/media/rpivid/rpivid_dec.c b/drivers/staging/media/rpivid/rpivid_dec.c deleted file mode 100644 index e51408dabbdb99..00000000000000 --- a/drivers/staging/media/rpivid/rpivid_dec.c +++ /dev/null @@ -1,96 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Raspberry Pi HEVC driver - * - * Copyright (C) 2020 Raspberry Pi (Trading) Ltd - * - * Based on the Cedrus VPU driver, that is: - * - * Copyright (C) 2016 Florent Revest - * Copyright (C) 2018 Paul Kocialkowski - * Copyright (C) 2018 Bootlin - */ - -#include -#include -#include -#include - -#include "rpivid.h" -#include "rpivid_dec.h" - -void rpivid_device_run(void *priv) -{ - struct rpivid_ctx *const ctx = priv; - struct rpivid_dev *const dev = ctx->dev; - struct rpivid_run run = {}; - struct media_request *src_req; - - run.src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); - run.dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); - - if (!run.src || !run.dst) { - v4l2_err(&dev->v4l2_dev, "%s: Missing buffer: src=%p, dst=%p\n", - __func__, run.src, run.dst); - goto fail; - } - - /* Apply request(s) controls */ - src_req = run.src->vb2_buf.req_obj.req; - if (!src_req) { - v4l2_err(&dev->v4l2_dev, "%s: Missing request\n", __func__); - goto fail; - } - - v4l2_ctrl_request_setup(src_req, &ctx->hdl); - - switch (ctx->src_fmt.pixelformat) { - case V4L2_PIX_FMT_HEVC_SLICE: - { - const struct v4l2_ctrl *ctrl; - - run.h265.sps = - rpivid_find_control_data(ctx, - V4L2_CID_STATELESS_HEVC_SPS); - run.h265.pps = - rpivid_find_control_data(ctx, - V4L2_CID_STATELESS_HEVC_PPS); - run.h265.dec = - rpivid_find_control_data(ctx, - V4L2_CID_STATELESS_HEVC_DECODE_PARAMS); - - ctrl = rpivid_find_ctrl(ctx, - V4L2_CID_STATELESS_HEVC_SLICE_PARAMS); - if (!ctrl || !ctrl->elems) { - v4l2_err(&dev->v4l2_dev, "%s: Missing slice params\n", - __func__); - goto fail; - } - run.h265.slice_ents = ctrl->elems; - run.h265.slice_params = ctrl->p_cur.p; - - run.h265.scaling_matrix = - rpivid_find_control_data(ctx, - V4L2_CID_STATELESS_HEVC_SCALING_MATRIX); - break; - } - - default: - break; - } - - v4l2_m2m_buf_copy_metadata(run.src, run.dst, true); - - dev->dec_ops->setup(ctx, &run); - - /* Complete request(s) controls */ - v4l2_ctrl_request_complete(src_req, &ctx->hdl); - - dev->dec_ops->trigger(ctx); - return; - -fail: - /* We really shouldn't get here but tidy up what we can */ - v4l2_m2m_buf_done_and_job_finish(dev->m2m_dev, ctx->fh.m2m_ctx, - VB2_BUF_STATE_ERROR); -} diff --git a/drivers/staging/media/rpivid/rpivid_dec.h b/drivers/staging/media/rpivid/rpivid_dec.h deleted file mode 100644 index 8f15bb6406abc6..00000000000000 --- a/drivers/staging/media/rpivid/rpivid_dec.h +++ /dev/null @@ -1,19 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Raspberry Pi HEVC driver - * - * Copyright (C) 2020 Raspberry Pi (Trading) Ltd - * - * Based on the Cedrus VPU driver, that is: - * - * Copyright (C) 2016 Florent Revest - * Copyright (C) 2018 Paul Kocialkowski - * Copyright (C) 2018 Bootlin - */ - -#ifndef _RPIVID_DEC_H_ -#define _RPIVID_DEC_H_ - -void rpivid_device_run(void *priv); - -#endif diff --git a/include/media/media-device.h b/include/media/media-device.h index 53d2a16a70b0d9..749c327e3c582c 100644 --- a/include/media/media-device.h +++ b/include/media/media-device.h @@ -11,6 +11,7 @@ #ifndef _MEDIA_DEVICE_H #define _MEDIA_DEVICE_H +#include #include #include #include @@ -106,6 +107,9 @@ struct media_device_ops { * @ops: Operation handler callbacks * @req_queue_mutex: Serialise the MEDIA_REQUEST_IOC_QUEUE ioctl w.r.t. * other operations that stop or start streaming. + * @num_requests: number of associated requests + * @num_request_objects: number of associated request objects + * @media_dir: DebugFS media directory * @request_id: Used to generate unique request IDs * * This structure represents an abstract high-level media device. It allows easy @@ -179,6 +183,11 @@ struct media_device { const struct media_device_ops *ops; struct mutex req_queue_mutex; + atomic_t num_requests; + atomic_t num_request_objects; + + /* debugfs */ + struct dentry *media_dir; atomic_t request_id; }; diff --git a/include/media/media-devnode.h b/include/media/media-devnode.h index d27c1c646c2805..dbcabeffcb572a 100644 --- a/include/media/media-devnode.h +++ b/include/media/media-devnode.h @@ -20,9 +20,13 @@ #include #include #include +#include struct media_device; +/* debugfs top-level media directory */ +extern struct dentry *media_debugfs_root; + /* * Flag to mark the media_devnode struct as registered. Drivers must not touch * this flag directly, it will be set and cleared by media_devnode_register and diff --git a/include/media/media-request.h b/include/media/media-request.h index 0de5c2c9418839..db0d9edfb38f13 100644 --- a/include/media/media-request.h +++ b/include/media/media-request.h @@ -56,6 +56,10 @@ struct media_request_object; * @access_count: count the number of request accesses that are in progress * @objects: List of @struct media_request_object request objects * @num_incomplete_objects: The number of incomplete objects in the request + * @manual_completion: if true, then the request won't be marked as completed + * when @num_incomplete_objects reaches 0. Call media_request_manual_complete() + * to set this field to false and complete the request + * if @num_incomplete_objects == 0. * @poll_wait: Wait queue for poll * @lock: Serializes access to this struct */ @@ -68,6 +72,7 @@ struct media_request { unsigned int access_count; struct list_head objects; unsigned int num_incomplete_objects; + bool manual_completion; wait_queue_head_t poll_wait; spinlock_t lock; }; @@ -189,10 +194,6 @@ static inline void media_request_get(struct media_request *req) */ void media_request_put(struct media_request *req); -void media_request_pin(struct media_request *req); - -void media_request_unpin(struct media_request *req); - /** * media_request_get_by_fd - Get a media request by fd * @@ -222,21 +223,42 @@ media_request_get_by_fd(struct media_device *mdev, int request_fd); int media_request_alloc(struct media_device *mdev, int *alloc_fd); -#else - -static inline void media_request_get(struct media_request *req) +/** + * media_request_mark_manual_completion - Set manual_completion to true + * + * @req: The request + * + * Mark that the request has to be manually completed by calling + * media_request_manual_complete(). + * + * This function should be called in the req_queue callback. + */ +static inline void +media_request_mark_manual_completion(struct media_request *req) { + req->manual_completion = true; } -static inline void media_request_put(struct media_request *req) -{ -} +/** + * media_request_manual_complete - Set manual_completion to false + * + * @req: The request + * + * Set @manual_completion to false, and if @num_incomplete_objects + * is 0, then mark the request as completed. + * + * If there are still incomplete objects in the request, then + * WARN for that since that suggests a driver error. + */ +void media_request_manual_complete(struct media_request *req); -static inline void media_request_pin(struct media_request *req) +#else + +static inline void media_request_get(struct media_request *req) { } -static inline void media_request_unpin(struct media_request *req) +static inline void media_request_put(struct media_request *req) { } @@ -268,6 +290,7 @@ struct media_request_object_ops { * struct media_request_object - An opaque object that belongs to a media * request * + * @mdev: Media device this object belongs to * @ops: object's operations * @priv: object's priv pointer * @req: the request this object belongs to (can be NULL) @@ -279,6 +302,7 @@ struct media_request_object_ops { * another struct that contains the actual data for this request object. */ struct media_request_object { + struct media_device *mdev; const struct media_request_object_ops *ops; void *priv; struct media_request *req; @@ -348,7 +372,7 @@ void media_request_object_init(struct media_request_object *obj); * @req: The media request * @ops: The object ops for this object * @priv: A driver-specific priv pointer associated with this object - * @is_buffer: Set to true if the object a buffer object. + * @is_buffer: Set to true if the object is a buffer object. * @obj: The object * * Bind this object to the request and set the ops and priv values of diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 3a8e4bc19b3d80..ef1fdf384848df 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -686,12 +686,20 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_P010_4L4 v4l2_fourcc('T', '0', '1', '0') /* 12 Y/CbCr 4:2:0 10-bit 4x4 macroblocks */ #define V4L2_PIX_FMT_NV12_8L128 v4l2_fourcc('A', 'T', '1', '2') /* Y/CbCr 4:2:0 8x128 tiles */ #define V4L2_PIX_FMT_NV12_10BE_8L128 v4l2_fourcc_be('A', 'X', '1', '2') /* Y/CbCr 4:2:0 10-bit 8x128 tiles */ +#define V4L2_PIX_FMT_NV12_COL128 v4l2_fourcc('N', 'C', '1', '2') /* 12 Y/CbCr 4:2:0 128 pixel wide column */ +#define V4L2_PIX_FMT_NV12_10_COL128 v4l2_fourcc('N', 'C', '3', '0') + /* Y/CbCr 4:2:0 10bpc, 3x10 packed as 4 bytes in + * a 128 bytes / 96 pixel wide column */ /* Tiled YUV formats, non contiguous planes */ #define V4L2_PIX_FMT_NV12MT v4l2_fourcc('T', 'M', '1', '2') /* 12 Y/CbCr 4:2:0 64x32 tiles */ #define V4L2_PIX_FMT_NV12MT_16X16 v4l2_fourcc('V', 'M', '1', '2') /* 12 Y/CbCr 4:2:0 16x16 tiles */ #define V4L2_PIX_FMT_NV12M_8L128 v4l2_fourcc('N', 'A', '1', '2') /* Y/CbCr 4:2:0 8x128 tiles */ #define V4L2_PIX_FMT_NV12M_10BE_8L128 v4l2_fourcc_be('N', 'T', '1', '2') /* Y/CbCr 4:2:0 10-bit 8x128 tiles */ +#define V4L2_PIX_FMT_NV12MT_COL128 v4l2_fourcc('N', 'c', '1', '2') /* 12 Y/CbCr 4:2:0 128 pixel wide column */ +#define V4L2_PIX_FMT_NV12MT_10_COL128 v4l2_fourcc('N', 'c', '3', '0') + /* Y/CbCr 4:2:0 10bpc, 3x10 packed as 4 bytes in a 128 bytes / 96 pixel wide column */ + /* Bayer formats - see http://www.siliconimaging.com/RGB%20Bayer.htm */ #define V4L2_PIX_FMT_SBGGR8 v4l2_fourcc('B', 'A', '8', '1') /* 8 BGBG.. GRGR.. */ @@ -815,10 +823,6 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_QC10C v4l2_fourcc('Q', '1', '0', 'C') /* Qualcomm 10-bit compressed */ #define V4L2_PIX_FMT_AJPG v4l2_fourcc('A', 'J', 'P', 'G') /* Aspeed JPEG */ #define V4L2_PIX_FMT_HEXTILE v4l2_fourcc('H', 'X', 'T', 'L') /* Hextile compressed */ -#define V4L2_PIX_FMT_NV12_COL128 v4l2_fourcc('N', 'C', '1', '2') /* 12 Y/CbCr 4:2:0 128 pixel wide column */ -#define V4L2_PIX_FMT_NV12_10_COL128 v4l2_fourcc('N', 'C', '3', '0') - /* Y/CbCr 4:2:0 10bpc, 3x10 packed as 4 bytes in - * a 128 bytes / 96 pixel wide column */ /* 10bit raw packed, 32 bytes for every 25 pixels, last LSB 6 bits unused */ #define V4L2_PIX_FMT_IPU3_SBGGR10 v4l2_fourcc('i', 'p', '3', 'b') /* IPU3 packed 10-bit BGGR bayer */