media updates for v6.1-rc1

-----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEE+QmuaPwR3wnBdVwACF8+vY7k4RUFAmM9SW4ACgkQCF8+vY7k
 4RUFXQ//TDretp4pLjgZRYmNedC3g0yoUObSTQSCasaqcqS7GF4SwNDzkt83m4mm
 dDkgeMM3OXi7MQMPjnXt3jDxSvNrrwqG4CRjEj+Faw2NzEsv85badD+j+ZoqaSsw
 SPUy3Ep7XEeinzU27nVMeKhOZ1LNvoI45BSKenl9iLvLsRP5I5ON5J1qlEy7HFvG
 5X62isRAZ/IW0wcvYgxZfA8x9QuRrpbCr3bdIonmrBeZLslaFDFPoRP9lBkamf3a
 nfp9KfC/4ULuAU4hjTY8Oij7GGvLKtUIwEUpou4fdgbDaq96cTkd/KwVxr7Ah4lL
 ZHtRj0I4GMITmdnfFd6vRfpeK8uzLxj2BssxiuKDcnraHvFxMAmIZSTKHPmTrSPS
 2+JZf8dVCpU9Xx8EXWR55Z8G6GTnVPeWk1X5TtKcmgXqyCB996xzI1nZ3LRtcpHk
 W53NhjtDwX2BqQ51CT576TnW0zN58ZfyhkTHHl2aUnmjd89OgfZzhUS9eAtfA5WO
 vmpQQqARc4v8+NL4uibyrBbjbrPkWFSMzP2Ed3yTfU2Wd8zjwqE9v3KTMb6Lrlhb
 4WJ5SuTHjVDI+TUFy8UvJRiqzyBer+mpDZubBnGp/Z3JE+Eh8mg3oLmfElLwtl2t
 Vdm8uymOivY3JdZ17Bi33cXrAa9TEkm25LGXWGGfE3oofSHlJwg=
 =MHQ/
 -----END PGP SIGNATURE-----

Merge tag 'media/v6.1-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media

Pull media updates from Mauro Carvalho Chehab:

 - New driver for Mediatek MDP V3

 - New driver for NXP i.MX DW100 dewarper

 - Zoran driver got promoted from staging

 - Hantro and related drivers got promoted from staging

 - Several VB1 drivers got moved to staging/deprecated (cpia2, fsl-viu,
   meye, saa7146, av7110, stkwebcam, tm6000, vpfe_capture, davinci,
   zr364xx)

 - Usual set of driver fixes, improvements and cleanups

* tag 'media/v6.1-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (107 commits)
  media: destage Hantro VPU driver
  media: platform: mtk-mdp3: add MediaTek MDP3 driver
  media: dt-binding: mediatek: add bindings for MediaTek CCORR and WDMA
  media: dt-binding: mediatek: add bindings for MediaTek MDP3 components
  media: xilinx: vipp: Fix refcount leak in xvip_graph_dma_init
  media: xilinx: video: Add 1X12 greyscale format
  media: xilinx: csi2rxss: Add 1X12 greyscale format
  media: staging: media: imx: imx7-media-csi: Increase video mem limit
  media: uvcvideo: Limit power line control for Sonix Technology
  media: uvcvideo: Use entity get_cur in uvc_ctrl_set
  media: uvcvideo: Fix typo 'the the' in comment
  media: uvcvideo: Use indexed loops in uvc_ctrl_init_ctrl()
  media: uvcvideo: Fix memory leak in uvc_gpio_parse
  media: renesas: vsp1: Add support for RZ/G2L VSPD
  media: renesas: vsp1: Add VSP1_HAS_NON_ZERO_LBA feature bit
  media: renesas: vsp1: Add support for VSP software version
  media: renesas: vsp1: Add support to deassert/assert reset line
  media: dt-bindings: media: renesas,vsp1: Document RZ/G2L VSPD bindings
  media: meson: vdec: add missing clk_disable_unprepare on error in vdec_hevc_start()
  media: amphion: fix a bug that vpu core may not resume after suspend
  ...
This commit is contained in:
Linus Torvalds 2022-10-07 11:04:35 -07:00
commit 5d435a3f7b
380 changed files with 9472 additions and 1463 deletions

View file

@ -0,0 +1,95 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/media/mediatek,mdp3-rdma.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: MediaTek Read Direct Memory Access
maintainers:
- Matthias Brugger <matthias.bgg@gmail.com>
- Moudy Ho <moudy.ho@mediatek.com>
description: |
MediaTek Read Direct Memory Access(RDMA) component used to do read DMA.
It contains one line buffer to store the sufficient pixel data, and
must be siblings to the central MMSYS_CONFIG node.
For a description of the MMSYS_CONFIG binding, see
Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.yaml
for details.
properties:
compatible:
items:
- const: mediatek,mt8183-mdp3-rdma
reg:
maxItems: 1
mediatek,gce-client-reg:
$ref: '/schemas/types.yaml#/definitions/phandle-array'
items:
items:
- description: phandle of GCE
- description: GCE subsys id
- description: register offset
- description: register size
description: The register of client driver can be configured by gce with
4 arguments defined in this property. Each GCE subsys id is mapping to
a client defined in the header include/dt-bindings/gce/<chip>-gce.h.
mediatek,gce-events:
description:
The event id which is mapping to the specific hardware event signal
to gce. The event id is defined in the gce header
include/dt-bindings/gce/<chip>-gce.h of each chips.
$ref: /schemas/types.yaml#/definitions/uint32-array
power-domains:
maxItems: 1
clocks:
items:
- description: RDMA clock
- description: RSZ clock
iommus:
maxItems: 1
mboxes:
items:
- description: used for 1st data pipe from RDMA
- description: used for 2nd data pipe from RDMA
required:
- compatible
- reg
- mediatek,gce-client-reg
- mediatek,gce-events
- power-domains
- clocks
- iommus
- mboxes
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/mt8183-clk.h>
#include <dt-bindings/gce/mt8183-gce.h>
#include <dt-bindings/power/mt8183-power.h>
#include <dt-bindings/memory/mt8183-larb-port.h>
mdp3_rdma0: mdp3-rdma0@14001000 {
compatible = "mediatek,mt8183-mdp3-rdma";
reg = <0x14001000 0x1000>;
mediatek,gce-client-reg = <&gce SUBSYS_1400XXXX 0x1000 0x1000>;
mediatek,gce-events = <CMDQ_EVENT_MDP_RDMA0_SOF>,
<CMDQ_EVENT_MDP_RDMA0_EOF>;
power-domains = <&spm MT8183_POWER_DOMAIN_DISP>;
clocks = <&mmsys CLK_MM_MDP_RDMA0>,
<&mmsys CLK_MM_MDP_RSZ1>;
iommus = <&iommu>;
mboxes = <&gce 20 CMDQ_THR_PRIO_LOWEST>,
<&gce 21 CMDQ_THR_PRIO_LOWEST>;
};

View file

@ -0,0 +1,77 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/media/mediatek,mdp3-rsz.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: MediaTek Resizer
maintainers:
- Matthias Brugger <matthias.bgg@gmail.com>
- Moudy Ho <moudy.ho@mediatek.com>
description: |
One of Media Data Path 3 (MDP3) components used to do frame resizing.
properties:
compatible:
items:
- enum:
- mediatek,mt8183-mdp3-rsz
reg:
maxItems: 1
mediatek,gce-client-reg:
$ref: /schemas/types.yaml#/definitions/phandle-array
items:
items:
- description: phandle of GCE
- description: GCE subsys id
- description: register offset
- description: register size
description: The register of client driver can be configured by gce with
4 arguments defined in this property. Each GCE subsys id is mapping to
a client defined in the header include/dt-bindings/gce/<chip>-gce.h.
mediatek,gce-events:
description:
The event id which is mapping to the specific hardware event signal
to gce. The event id is defined in the gce header
include/dt-bindings/gce/<chip>-gce.h of each chips.
$ref: /schemas/types.yaml#/definitions/uint32-array
clocks:
minItems: 1
required:
- compatible
- reg
- mediatek,gce-client-reg
- mediatek,gce-events
- clocks
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/mt8183-clk.h>
#include <dt-bindings/gce/mt8183-gce.h>
mdp3_rsz0: mdp3-rsz0@14003000 {
compatible = "mediatek,mt8183-mdp3-rsz";
reg = <0x14003000 0x1000>;
mediatek,gce-client-reg = <&gce SUBSYS_1400XXXX 0x3000 0x1000>;
mediatek,gce-events = <CMDQ_EVENT_MDP_RSZ0_SOF>,
<CMDQ_EVENT_MDP_RSZ0_EOF>;
clocks = <&mmsys CLK_MM_MDP_RSZ0>;
};
mdp3_rsz1: mdp3-rsz1@14004000 {
compatible = "mediatek,mt8183-mdp3-rsz";
reg = <0x14004000 0x1000>;
mediatek,gce-client-reg = <&gce SUBSYS_1400XXXX 0x4000 0x1000>;
mediatek,gce-events = <CMDQ_EVENT_MDP_RSZ1_SOF>,
<CMDQ_EVENT_MDP_RSZ1_EOF>;
clocks = <&mmsys CLK_MM_MDP_RSZ1>;
};

View file

@ -0,0 +1,80 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/media/mediatek,mdp3-wrot.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: MediaTek Write DMA with Rotation
maintainers:
- Matthias Brugger <matthias.bgg@gmail.com>
- Moudy Ho <moudy.ho@mediatek.com>
description: |
One of Media Data Path 3 (MDP3) components used to write DMA with frame rotation.
properties:
compatible:
items:
- enum:
- mediatek,mt8183-mdp3-wrot
reg:
maxItems: 1
mediatek,gce-client-reg:
$ref: /schemas/types.yaml#/definitions/phandle-array
items:
items:
- description: phandle of GCE
- description: GCE subsys id
- description: register offset
- description: register size
description: The register of client driver can be configured by gce with
4 arguments defined in this property. Each GCE subsys id is mapping to
a client defined in the header include/dt-bindings/gce/<chip>-gce.h.
mediatek,gce-events:
description:
The event id which is mapping to the specific hardware event signal
to gce. The event id is defined in the gce header
include/dt-bindings/gce/<chip>-gce.h of each chips.
$ref: /schemas/types.yaml#/definitions/uint32-array
power-domains:
maxItems: 1
clocks:
minItems: 1
iommus:
maxItems: 1
required:
- compatible
- reg
- mediatek,gce-client-reg
- mediatek,gce-events
- power-domains
- clocks
- iommus
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/mt8183-clk.h>
#include <dt-bindings/gce/mt8183-gce.h>
#include <dt-bindings/power/mt8183-power.h>
#include <dt-bindings/memory/mt8183-larb-port.h>
mdp3_wrot0: mdp3-wrot0@14005000 {
compatible = "mediatek,mt8183-mdp3-wrot";
reg = <0x14005000 0x1000>;
mediatek,gce-client-reg = <&gce SUBSYS_1400XXXX 0x5000 0x1000>;
mediatek,gce-events = <CMDQ_EVENT_MDP_WROT0_SOF>,
<CMDQ_EVENT_MDP_WROT0_EOF>;
power-domains = <&spm MT8183_POWER_DOMAIN_DISP>;
clocks = <&mmsys CLK_MM_MDP_WROT0>;
iommus = <&iommu>;
};

View file

@ -20,6 +20,7 @@ properties:
- mediatek,mt8173-vcodec-enc-vp8
- mediatek,mt8173-vcodec-enc
- mediatek,mt8183-vcodec-enc
- mediatek,mt8188-vcodec-enc
- mediatek,mt8192-vcodec-enc
- mediatek,mt8195-vcodec-enc

View file

@ -57,6 +57,7 @@ properties:
enum:
- mediatek,mt8192-vcodec-dec
- mediatek,mt8186-vcodec-dec
- mediatek,mt8188-vcodec-dec
- mediatek,mt8195-vcodec-dec
reg:

View file

@ -0,0 +1,69 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/media/nxp,dw100.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: NXP i.MX8MP DW100 Dewarper core
maintainers:
- Xavier Roumegue <xavier.roumegue@oss.nxp.com>
description: |-
The Dewarp Engine provides high-performance dewarp processing for the
correction of the distortion that is introduced in images produced by fisheye
and wide angle lenses. It is implemented with a line/tile-cache based
architecture. With configurable address mapping look up tables and per tile
processing, it successfully generates a corrected output image.
The engine can be used to perform scaling, cropping and pixel format
conversion.
properties:
compatible:
enum:
- nxp,imx8mp-dw100
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
items:
- description: The AXI clock
- description: The AHB clock
clock-names:
items:
- const: axi
- const: ahb
power-domains:
maxItems: 1
required:
- compatible
- reg
- interrupts
- clocks
- clock-names
- power-domains
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/imx8mp-clock.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/power/imx8mp-power.h>
dewarp: dwe@32e30000 {
compatible = "nxp,imx8mp-dw100";
reg = <0x32e30000 0x10000>;
interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk IMX8MP_CLK_MEDIA_AXI_ROOT>,
<&clk IMX8MP_CLK_MEDIA_APB_ROOT>;
clock-names = "axi", "ahb";
power-domains = <&media_blk_ctrl IMX8MP_MEDIABLK_PD_DWE>;
};

View file

@ -17,6 +17,7 @@ description:
properties:
compatible:
enum:
- renesas,r9a07g044-vsp2 # RZ/G2L
- renesas,vsp1 # R-Car Gen2 and RZ/G1
- renesas,vsp2 # R-Car Gen3 and RZ/G2
@ -26,8 +27,8 @@ properties:
interrupts:
maxItems: 1
clocks:
maxItems: 1
clocks: true
clock-names: true
power-domains:
maxItems: 1
@ -50,17 +51,43 @@ required:
additionalProperties: false
if:
properties:
compatible:
items:
- const: renesas,vsp1
then:
properties:
renesas,fcp: false
else:
required:
- renesas,fcp
allOf:
- if:
properties:
compatible:
contains:
const: renesas,vsp1
then:
properties:
renesas,fcp: false
else:
required:
- renesas,fcp
- if:
properties:
compatible:
contains:
const: renesas,r9a07g044-vsp2
then:
properties:
clocks:
items:
- description: Main clock
- description: Register access clock
- description: Video clock
clock-names:
items:
- const: aclk
- const: pclk
- const: vclk
required:
- clock-names
else:
properties:
clocks:
maxItems: 1
clock-names: false
examples:
# R8A7790 (R-Car H2) VSP1-S

View file

@ -0,0 +1,68 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/soc/mediatek/mediatek,ccorr.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: MediaTek color correction
maintainers:
- Matthias Brugger <matthias.bgg@gmail.com>
- Moudy Ho <moudy.ho@mediatek.com>
description: |
MediaTek color correction with 3X3 matrix.
properties:
compatible:
items:
- enum:
- mediatek,mt8183-mdp3-ccorr
reg:
maxItems: 1
mediatek,gce-client-reg:
$ref: /schemas/types.yaml#/definitions/phandle-array
items:
items:
- description: phandle of GCE
- description: GCE subsys id
- description: register offset
- description: register size
description: The register of client driver can be configured by gce with
4 arguments defined in this property. Each GCE subsys id is mapping to
a client defined in the header include/dt-bindings/gce/<chip>-gce.h.
mediatek,gce-events:
description:
The event id which is mapping to the specific hardware event signal
to gce. The event id is defined in the gce header
include/dt-bindings/gce/<chip>-gce.h of each chips.
$ref: /schemas/types.yaml#/definitions/uint32-array
clocks:
minItems: 1
required:
- compatible
- reg
- mediatek,gce-client-reg
- mediatek,gce-events
- clocks
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/mt8183-clk.h>
#include <dt-bindings/gce/mt8183-gce.h>
mdp3_ccorr: mdp3-ccorr@1401c000 {
compatible = "mediatek,mt8183-mdp3-ccorr";
reg = <0x1401c000 0x1000>;
mediatek,gce-client-reg = <&gce SUBSYS_1401XXXX 0xc000 0x1000>;
mediatek,gce-events = <CMDQ_EVENT_MDP_CCORR_SOF>,
<CMDQ_EVENT_MDP_CCORR_EOF>;
clocks = <&mmsys CLK_MM_MDP_CCORR>;
};

View file

@ -0,0 +1,81 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/soc/mediatek/mediatek,wdma.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: MediaTek Write Direct Memory Access
maintainers:
- Matthias Brugger <matthias.bgg@gmail.com>
- Moudy Ho <moudy.ho@mediatek.com>
description: |
MediaTek Write Direct Memory Access(WDMA) component used to write
the data into DMA.
properties:
compatible:
items:
- enum:
- mediatek,mt8183-mdp3-wdma
reg:
maxItems: 1
mediatek,gce-client-reg:
$ref: /schemas/types.yaml#/definitions/phandle-array
items:
items:
- description: phandle of GCE
- description: GCE subsys id
- description: register offset
- description: register size
description: The register of client driver can be configured by gce with
4 arguments defined in this property. Each GCE subsys id is mapping to
a client defined in the header include/dt-bindings/gce/<chip>-gce.h.
mediatek,gce-events:
description:
The event id which is mapping to the specific hardware event signal
to gce. The event id is defined in the gce header
include/dt-bindings/gce/<chip>-gce.h of each chips.
$ref: /schemas/types.yaml#/definitions/uint32-array
power-domains:
maxItems: 1
clocks:
minItems: 1
iommus:
maxItems: 1
required:
- compatible
- reg
- mediatek,gce-client-reg
- mediatek,gce-events
- power-domains
- clocks
- iommus
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/mt8183-clk.h>
#include <dt-bindings/gce/mt8183-gce.h>
#include <dt-bindings/power/mt8183-power.h>
#include <dt-bindings/memory/mt8183-larb-port.h>
mdp3_wdma: mdp3-wdma@14006000 {
compatible = "mediatek,mt8183-mdp3-wdma";
reg = <0x14006000 0x1000>;
mediatek,gce-client-reg = <&gce SUBSYS_1400XXXX 0x6000 0x1000>;
mediatek,gce-events = <CMDQ_EVENT_MDP_WDMA0_SOF>,
<CMDQ_EVENT_MDP_WDMA0_EOF>;
power-domains = <&spm MT8183_POWER_DOMAIN_DISP>;
clocks = <&mmsys CLK_MM_MDP_WDMA0>;
iommus = <&iommu>;
};

View file

@ -19,7 +19,7 @@ Global video workflow
a) QCI stopped
Initially, the QCI interface is stopped.
When a buffer is queued (pxa_videobuf_ops->buf_queue), the QCI starts.
When a buffer is queued, start_streaming is called and the QCI starts.
b) QCI started
More buffers can be queued while the QCI is started without halting the

View file

@ -0,0 +1,84 @@
.. SPDX-License-Identifier: GPL-2.0
DW100 dewarp driver
===================
The Vivante DW100 Dewarp Processor IP core found on i.MX8MP SoC applies a
programmable geometrical transformation on the input image to correct distortion
introduced by lenses.
The transformation function is exposed by the hardware as a grid map with 16x16
pixel macroblocks indexed using X, Y vertex coordinates.
::
Image width
<--------------------------------------->
^ .-------.-------.-------.-------.-------.
| | 16x16 | | | | |
I | | pixel | | | | |
m | | block | | | | |
a | .-------.-------.-------.-------.-------.
g | | | | | | |
e | | | | | | |
| | | | | | |
h | .-------.-------.-------.-------.-------.
e | | | | | | |
i | | | | | | |
g | | | | | | |
h | .-------.-------.-------.-------.-------.
t | | | | | | |
| | | | | | |
| | | | | | |
v '-------'-------'-------'-------'-------'
Grid of Image Blocks for Dewarping Map
Each x, y coordinate register uses 16 bits to record the coordinate address in
an unsigned 12.4 fixed point format (UQ12.4).
::
.----------------------.--------..----------------------.--------.
| 31~20 | 19~16 || 15~4 | 3~0 |
| (integer) | (frac) || (integer) | (frac) |
'----------------------'--------''----------------------'--------'
<-------------------------------><------------------------------->
Y coordinate X coordinate
Remap Register Layout
The dewarping map is set from applications using the
V4L2_CID_DW100_DEWARPING_16x16_VERTEX_MAP control. The control contains
an array of u32 values storing (x, y) destination coordinates for each
vertex of the grid. The x coordinate is stored in the 16 LSBs and the y
coordinate in the 16 MSBs.
The number of elements in the array must match the image size:
.. code-block:: C
elems = (DIV_ROUND_UP(width, 16) + 1) * (DIV_ROUND_UP(height, 16) + 1);
If the control has not been set by the application, the driver uses an identity
map.
More details on the DW100 hardware operations can be found in
*chapter 13.15 DeWarp* of IMX8MP_ reference manual.
The Vivante DW100 m2m driver implements the following driver-specific control:
``V4L2_CID_DW100_DEWARPING_16x16_VERTEX_MAP (__u32 array)``
Specifies to DW100 driver its dewarping map (aka LUT) blob as described in
*chapter 13.15.2.3 Dewarping Remap* of IMX8MP_ reference manual as an U32
dynamic array. The image is divided into many small 16x16 blocks. If the
width/height of the image is not divisible by 16, the size of the
rightmost/bottommost block is the remainder. The dewarping map only saves
the vertex coordinates of the block. The dewarping grid map is comprised of
vertex coordinates for x and y. Each x, y coordinate register uses 16 bits
(UQ12.4) to record the coordinate address, with the Y coordinate in the
upper bits and X in the lower bits. The driver modifies the dimensions of
this control when the sink format is changed, to reflect the new input
resolution.
.. _IMX8MP: https://www.nxp.com/webapp/Download?colCode=IMX8MPRM

View file

@ -33,6 +33,7 @@ For more details see the file COPYING in the source distribution of Linux.
ccs
cx2341x-uapi
dw100
imx-uapi
max2175
meye-uapi

View file

@ -1,9 +0,0 @@
.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
.. _async:
****************
Asynchronous I/O
****************
This method is not defined yet.

View file

@ -41,7 +41,7 @@ Devices supporting the raw VBI capturing or output API set the
in the ``capabilities`` field of struct
:c:type:`v4l2_capability` returned by the
:ref:`VIDIOC_QUERYCAP` ioctl. At least one of the
read/write, streaming or asynchronous I/O methods must be supported. VBI
read/write or streaming I/O methods must be supported. VBI
devices may or may not have a tuner or modulator.
Supplemental Functions

View file

@ -34,7 +34,7 @@ Devices supporting the SDR transmitter interface set the
device has an Digital to Analog Converter (DAC), which is a mandatory
element for the SDR transmitter.
At least one of the read/write, streaming or asynchronous I/O methods
At least one of the read/write or streaming I/O methods
must be supported.

View file

@ -36,7 +36,7 @@ Devices supporting the sliced VBI capturing or output API set the
respectively, in the ``capabilities`` field of struct
:c:type:`v4l2_capability` returned by the
:ref:`VIDIOC_QUERYCAP` ioctl. At least one of the
read/write, streaming or asynchronous :ref:`I/O methods <io>` must be
read/write or streaming :ref:`I/O methods <io>` must be
supported. Sliced VBI devices may have a tuner or modulator.
Supplemental Functions

View file

@ -316,7 +316,7 @@ This unnamed version was finally merged into Linux 2.5.46.
There are new fields to identify the driver, a new RDS device
function ``V4L2_CAP_RDS_CAPTURE``, the ``V4L2_CAP_AUDIO`` flag
indicates if the device has any audio connectors, another I/O
capability ``V4L2_CAP_ASYNCIO`` can be flagged. In response to these
capability V4L2_CAP_ASYNCIO can be flagged. In response to these
changes the ``type`` field became a bit set and was merged into the
``flags`` field. ``V4L2_FLAG_TUNER`` was renamed to
``V4L2_CAP_TUNER``, ``V4L2_CAP_VIDEO_OVERLAY`` replaced

View file

@ -17,8 +17,7 @@ read or write will fail at any time.
Other methods must be negotiated. To select the streaming I/O method
with memory mapped or user buffers applications call the
:ref:`VIDIOC_REQBUFS` ioctl. The asynchronous I/O
method is not defined yet.
:ref:`VIDIOC_REQBUFS` ioctl.
Video overlay can be considered another I/O method, although the
application does not directly receive the image data. It is selected by
@ -46,6 +45,5 @@ The following sections describe the various I/O methods in more detail.
mmap
userp
dmabuf
async
buffer
field-order

View file

@ -332,6 +332,11 @@ call.
- 0x0004
- This control event was triggered because the minimum, maximum,
step or the default value of the control changed.
* - ``V4L2_EVENT_CTRL_CH_DIMENSIONS``
- 0x0008
- This control event was triggered because the dimensions of the
control changed. Note that the number of dimensions remains the
same.
.. tabularcolumns:: |p{6.6cm}|p{2.2cm}|p{8.5cm}|

View file

@ -244,9 +244,6 @@ specification the ioctl returns an ``EINVAL`` error code.
- 0x01000000
- The device supports the :c:func:`read()` and/or
:c:func:`write()` I/O methods.
* - ``V4L2_CAP_ASYNCIO``
- 0x02000000
- The device supports the :ref:`asynchronous <async>` I/O methods.
* - ``V4L2_CAP_STREAMING``
- 0x04000000
- The device supports the :ref:`streaming <mmap>` I/O method.

View file

@ -514,6 +514,7 @@ replace define V4L2_EVENT_PRIVATE_START event-type
replace define V4L2_EVENT_CTRL_CH_VALUE ctrl-changes-flags
replace define V4L2_EVENT_CTRL_CH_FLAGS ctrl-changes-flags
replace define V4L2_EVENT_CTRL_CH_RANGE ctrl-changes-flags
replace define V4L2_EVENT_CTRL_CH_DIMENSIONS ctrl-changes-flags
replace define V4L2_EVENT_SRC_CH_RESOLUTION src-changes-flags

View file

@ -8936,7 +8936,7 @@ S: Maintained
F: Documentation/devicetree/bindings/media/nxp,imx8mq-vpu.yaml
F: Documentation/devicetree/bindings/media/rockchip,rk3568-vepu.yaml
F: Documentation/devicetree/bindings/media/rockchip-vpu.yaml
F: drivers/staging/media/hantro/
F: drivers/media/platform/verisilicon/
HARD DRIVE ACTIVE PROTECTION SYSTEM (HDAPS) DRIVER
M: Frank Seidel <frank@f-seidel.de>
@ -13823,7 +13823,7 @@ MOTION EYE VAIO PICTUREBOOK CAMERA DRIVER
S: Orphan
W: http://popies.net/meye/
F: Documentation/userspace-api/media/drivers/meye*
F: drivers/media/pci/meye/
F: drivers/staging/media/deprecated/meye/
F: include/uapi/linux/meye.h
MOTORCOMM PHY DRIVER
@ -14749,6 +14749,15 @@ S: Orphan
F: Documentation/devicetree/bindings/net/nfc/nxp,nci.yaml
F: drivers/nfc/nxp-nci
NXP i.MX 8MP DW100 V4L2 DRIVER
M: Xavier Roumegue <xavier.roumegue@oss.nxp.com>
L: linux-media@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/media/nxp,dw100.yaml
F: Documentation/userspace-api/media/drivers/dw100.rst
F: drivers/media/platform/nxp/dw100/
F: include/uapi/linux/dw100.h
NXP i.MX 8QXP/8QM JPEG V4L2 DRIVER
M: Mirela Rabulea <mirela.rabulea@nxp.com>
R: NXP Linux Team <linux-imx@nxp.com>
@ -18004,8 +18013,7 @@ M: Hans Verkuil <hverkuil@xs4all.nl>
L: linux-media@vger.kernel.org
S: Maintained
T: git git://linuxtv.org/media_tree.git
F: drivers/media/common/saa7146/
F: drivers/media/pci/saa7146/
F: drivers/staging/media/deprecated/saa7146/
F: include/media/drv-intf/saa7146*
SAFESETID SECURITY MODULE
@ -20428,6 +20436,7 @@ W: https://linuxtv.org
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/mhadli/v4l-dvb-davinci_devices.git
F: drivers/media/platform/ti/davinci/
F: drivers/staging/media/deprecated/vpfe_capture/
F: include/media/davinci/
TI ENHANCED QUADRATURE ENCODER PULSE (eQEP) DRIVER
@ -20568,7 +20577,7 @@ S: Odd fixes
W: https://linuxtv.org
T: git git://linuxtv.org/media_tree.git
F: Documentation/admin-guide/media/tm6000*
F: drivers/media/usb/tm6000/
F: drivers/staging/media/deprecated/tm6000/
TMIO/SDHI MMC DRIVER
M: Wolfram Sang <wsa+renesas@sang-engineering.com>
@ -20668,9 +20677,10 @@ F: include/linux/toshiba.h
F: include/uapi/linux/toshiba.h
TOSHIBA TC358743 DRIVER
M: Mats Randgaard <matrandg@cisco.com>
M: Hans Verkuil <hverkuil-cisco@xs4all.nl>
L: linux-media@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/media/i2c/tc358743.txt
F: drivers/media/i2c/tc358743*
F: include/media/i2c/tc358743.h
@ -21326,7 +21336,7 @@ S: Maintained
W: http://royale.zerezo.com/zr364xx/
T: git git://linuxtv.org/media_tree.git
F: Documentation/admin-guide/media/zr364xx*
F: drivers/media/usb/zr364xx/
F: drivers/staging/media/deprecated/zr364xx/
USER-MODE LINUX (UML)
M: Richard Weinberger <richard@nod.at>

View file

@ -256,8 +256,8 @@ static void stih_rx_done(struct stih_cec *cec, u32 status)
if (!msg.len)
return;
if (msg.len > 16)
msg.len = 16;
if (msg.len > CEC_MAX_MSG_SIZE)
msg.len = CEC_MAX_MSG_SIZE;
for (i = 0; i < msg.len; i++)
msg.msg[i] = readl(cec->regs + CEC_RX_DATA_BASE + i);

View file

@ -22,7 +22,6 @@ config VIDEO_TVEEPROM
depends on I2C
source "drivers/media/common/b2c2/Kconfig"
source "drivers/media/common/saa7146/Kconfig"
source "drivers/media/common/siano/Kconfig"
source "drivers/media/common/v4l2-tpg/Kconfig"
source "drivers/media/common/videobuf2/Kconfig"

View file

@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-y += b2c2/ saa7146/ siano/ v4l2-tpg/ videobuf2/
obj-y += b2c2/ siano/ v4l2-tpg/ videobuf2/
# Please keep it alphabetically sorted by Kconfig name
# (e. g. LC_ALL=C sort Makefile)

View file

@ -398,7 +398,7 @@ static void init_buffer_cache_hints(struct vb2_queue *q, struct vb2_buffer *vb)
}
/*
* __vb2_queue_alloc() - allocate videobuf buffer structures and (for MMAP type)
* __vb2_queue_alloc() - allocate vb2 buffer structures and (for MMAP type)
* video buffer memory for all buffers/planes on the queue and initializes the
* queue
*
@ -417,7 +417,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
VB2_MAX_FRAME - q->num_buffers);
for (buffer = 0; buffer < num_buffers; ++buffer) {
/* Allocate videobuf buffer structures */
/* Allocate vb2 buffer structures */
vb = kzalloc(q->buf_struct_size, GFP_KERNEL);
if (!vb) {
dprintk(q, 1, "memory alloc for buffer struct failed\n");
@ -599,7 +599,7 @@ static int __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
}
#endif
/* Free videobuf buffers */
/* Free vb2 buffers */
for (buffer = q->num_buffers - buffers; buffer < q->num_buffers;
++buffer) {
kfree(q->bufs[buffer]);
@ -1949,7 +1949,7 @@ int vb2_core_dqbuf(struct vb2_queue *q, unsigned int *pindex, void *pb,
if (pb)
call_void_bufop(q, fill_user_buffer, vb, pb);
/* Remove from videobuf queue */
/* Remove from vb2 queue */
list_del(&vb->queued_entry);
q->queued_count--;
@ -1978,7 +1978,7 @@ EXPORT_SYMBOL_GPL(vb2_core_dqbuf);
* __vb2_queue_cancel() - cancel and stop (pause) streaming
*
* Removes all queued buffers from driver's queue and all buffers queued by
* userspace from videobuf's queue. Returns to state after reqbufs.
* userspace from vb2's queue. Returns to state after reqbufs.
*/
static void __vb2_queue_cancel(struct vb2_queue *q)
{
@ -2016,7 +2016,7 @@ static void __vb2_queue_cancel(struct vb2_queue *q)
q->uses_qbuf = 0;
/*
* Remove all buffers from videobuf's list...
* Remove all buffers from vb2's list...
*/
INIT_LIST_HEAD(&q->queued_list);
/*
@ -2139,7 +2139,7 @@ int vb2_core_streamoff(struct vb2_queue *q, unsigned int type)
/*
* Cancel will pause streaming and remove all buffers from the driver
* and videobuf, effectively returning control over them to userspace.
* and vb2, effectively returning control over them to userspace.
*
* Note that we do this even if q->streaming == 0: if you prepare or
* queue buffers, and then call streamoff without ever having called

View file

@ -3,8 +3,8 @@
*
* some helper function for simple DVB cards which simply DMA the
* complete transport stream and let the computer sort everything else
* (i.e. we are using the software demux, ...). Also uses the
* video-buf to manage DMA buffers.
* (i.e. we are using the software demux, ...). Also uses vb2
* to manage DMA buffers.
*
* (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SUSE Labs]
*/

View file

@ -268,7 +268,7 @@ static int vb2_fill_vb2_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b
/*
* Single-planar buffers do not use planes array,
* so fill in relevant v4l2_buffer struct fields instead.
* In videobuf we use our internal V4l2_planes struct for
* In vb2 we use our internal V4l2_planes struct for
* single-planar buffers as well, for simplicity.
*
* If bytesused == 0 for the output buffer, then fall back
@ -625,19 +625,6 @@ static const struct vb2_buf_ops v4l2_buf_ops = {
.copy_timestamp = __copy_timestamp,
};
int vb2_find_timestamp(const struct vb2_queue *q, u64 timestamp,
unsigned int start_idx)
{
unsigned int i;
for (i = start_idx; i < q->num_buffers; i++)
if (q->bufs[i]->copied_timestamp &&
q->bufs[i]->timestamp == timestamp)
return i;
return -1;
}
EXPORT_SYMBOL_GPL(vb2_find_timestamp);
struct vb2_buffer *vb2_find_buffer(struct vb2_queue *q, u64 timestamp)
{
unsigned int i;
@ -652,7 +639,7 @@ EXPORT_SYMBOL_GPL(vb2_find_buffer);
/*
* vb2_querybuf() - query video buffer information
* @q: videobuf queue
* @q: vb2 queue
* @b: buffer struct passed from userspace to vidioc_querybuf handler
* in driver
*

View file

@ -3212,7 +3212,7 @@ static int dib8000_tune(struct dvb_frontend *fe)
case CT_DEMOD_STEP_6: /* (36) if there is an input (diversity) */
if ((state->fe[1] != NULL) && (state->output_mode != OUTMODE_DIVERSITY)) {
/* if there is a diversity fe in input and this fe is has not already failed : wait here until this this fe has succedeed or failed */
/* if there is a diversity fe in input and this fe is has not already failed : wait here until this fe has succeeded or failed */
if (dib8000_get_status(state->fe[1]) <= FE_STATUS_STD_SUCCESS) /* Something is locked on the input fe */
*tune_state = CT_DEMOD_STEP_8; /* go for mpeg */
else if (dib8000_get_status(state->fe[1]) >= FE_STATUS_TUNE_TIME_TOO_SHORT) { /* fe in input failed also, break the current one */

View file

@ -3516,7 +3516,7 @@ static int set_dvbt_standard(struct drxk_state *state,
status = write16(state, IQM_AF_CLP_LEN__A, 0);
if (status < 0)
goto error;
/* window size for for sense pre-SAW detection */
/* window size for sense pre-SAW detection */
status = write16(state, IQM_AF_SNS_LEN__A, 0);
if (status < 0)
goto error;

View file

@ -245,7 +245,7 @@ static void rtl2832_sdr_urb_complete(struct urb *urb)
if (unlikely(fbuf == NULL)) {
dev->vb_full++;
dev_notice_ratelimited(&pdev->dev,
"videobuf is full, %d packets dropped\n",
"video buffer is full, %d packets dropped\n",
dev->vb_full);
goto skip;
}

View file

@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
TDA10021/TDA10023 - Single Chip Cable Channel Receiver driver module
used on the the Siemens DVB-C cards
used on the Siemens DVB-C cards
Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
Copyright (C) 2004 Markus Schulz <msc@antzsystem.de>

View file

@ -1118,7 +1118,7 @@ struct dvb_frontend *tda10048_attach(const struct tda10048_config *config,
state->pll_pfactor = 0;
}
/* Establish any defaults the the user didn't pass */
/* Establish any defaults the user didn't pass */
tda10048_establish_defaults(&state->frontend);
/* Set the xtal and freq defaults */

View file

@ -943,8 +943,8 @@ static int adv7511_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
v4l2_dbg(1, debug, sd, "%s: cec msg len %d\n", __func__,
msg.len);
if (msg.len > 16)
msg.len = 16;
if (msg.len > CEC_MAX_MSG_SIZE)
msg.len = CEC_MAX_MSG_SIZE;
if (msg.len) {
u8 i;

View file

@ -2047,8 +2047,8 @@ static void adv76xx_cec_isr(struct v4l2_subdev *sd, bool *handled)
struct cec_msg msg;
msg.len = cec_read(sd, 0x25) & 0x1f;
if (msg.len > 16)
msg.len = 16;
if (msg.len > CEC_MAX_MSG_SIZE)
msg.len = CEC_MAX_MSG_SIZE;
if (msg.len) {
u8 i;

View file

@ -2215,8 +2215,8 @@ static void adv7842_cec_isr(struct v4l2_subdev *sd, bool *handled)
struct cec_msg msg;
msg.len = cec_read(sd, 0x25) & 0x1f;
if (msg.len > 16)
msg.len = 16;
if (msg.len > CEC_MAX_MSG_SIZE)
msg.len = CEC_MAX_MSG_SIZE;
if (msg.len) {
u8 i;

View file

@ -196,7 +196,7 @@ static u32 clock_divider_to_resolution(u16 divider)
{
/*
* Resolution is the duration of 1 tick of the readable portion of
* of the pulse width counter as read from the FIFO. The two lsb's are
* the pulse width counter as read from the FIFO. The two lsb's are
* not readable, hence the << 2. This function returns ns.
*/
return DIV_ROUND_CLOSEST((1 << 2) * ((u32) divider + 1) * 1000,

View file

@ -964,6 +964,8 @@ static void tc358743_cec_handler(struct v4l2_subdev *sd, u16 intstatus,
v = i2c_rd32(sd, CECRCTR);
msg.len = v & 0x1f;
if (msg.len > CEC_MAX_MSG_SIZE)
msg.len = CEC_MAX_MSG_SIZE;
for (i = 0; i < msg.len; i++) {
v = i2c_rd32(sd, CECRBUF1 + i * 4);
msg.msg[i] = v & 0xff;

View file

@ -13,12 +13,12 @@ if MEDIA_PCI_SUPPORT
if MEDIA_CAMERA_SUPPORT
comment "Media capture support"
source "drivers/media/pci/meye/Kconfig"
source "drivers/media/pci/solo6x10/Kconfig"
source "drivers/media/pci/sta2x11/Kconfig"
source "drivers/media/pci/tw5864/Kconfig"
source "drivers/media/pci/tw68/Kconfig"
source "drivers/media/pci/tw686x/Kconfig"
source "drivers/media/pci/zoran/Kconfig"
endif
@ -27,7 +27,6 @@ if MEDIA_ANALOG_TV_SUPPORT
source "drivers/media/pci/dt3155/Kconfig"
source "drivers/media/pci/ivtv/Kconfig"
source "drivers/media/pci/saa7146/Kconfig"
endif
@ -58,7 +57,6 @@ source "drivers/media/pci/pluto2/Kconfig"
source "drivers/media/pci/pt1/Kconfig"
source "drivers/media/pci/pt3/Kconfig"
source "drivers/media/pci/smipcie/Kconfig"
source "drivers/media/pci/ttpci/Kconfig"
endif

View file

@ -5,8 +5,7 @@
# Please keep it alphabetically sorted by directory
# (e. g. LC_ALL=C sort Makefile)
obj-y += ttpci/ \
b2c2/ \
obj-y += b2c2/ \
pluto2/ \
dm1105/ \
pt1/ \
@ -14,7 +13,6 @@ obj-y += ttpci/ \
mantis/ \
ngene/ \
ddbridge/ \
saa7146/ \
smipcie/ \
netup_unidvb/ \
intel/
@ -32,10 +30,10 @@ obj-$(CONFIG_VIDEO_CX25821) += cx25821/
obj-$(CONFIG_VIDEO_CX88) += cx88/
obj-$(CONFIG_VIDEO_DT3155) += dt3155/
obj-$(CONFIG_VIDEO_IVTV) += ivtv/
obj-$(CONFIG_VIDEO_MEYE) += meye/
obj-$(CONFIG_VIDEO_SAA7134) += saa7134/
obj-$(CONFIG_VIDEO_SAA7164) += saa7164/
obj-$(CONFIG_VIDEO_SOLO6X10) += solo6x10/
obj-$(CONFIG_VIDEO_TW5864) += tw5864/
obj-$(CONFIG_VIDEO_TW686X) += tw686x/
obj-$(CONFIG_VIDEO_TW68) += tw68/
obj-$(CONFIG_VIDEO_ZORAN) += zoran/

View file

@ -50,7 +50,7 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq)
*
* Many thanks to Jeff Campbell and Mike Bradley for their extensive
* investigation, experimentation, testing, and suggested solutions of
* of audio/video sync problems with SVideo and CVBS captures.
* audio/video sync problems with SVideo and CVBS captures.
*/
if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {

View file

@ -248,7 +248,7 @@ void cx18_init_power(struct cx18 *cx, int lowpwr)
*
* Many thanks to Jeff Campbell and Mike Bradley for their extensive
* investigation, experimentation, testing, and suggested solutions of
* of audio/video sync problems with SVideo and CVBS captures.
* audio/video sync problems with SVideo and CVBS captures.
*/
/* the fast clock is at 200/245 MHz */

View file

@ -2086,6 +2086,9 @@ static struct {
/* 0x1419 is the PCI ID for the IOMMU found on 15h (Models 10h-1fh) family
*/
{ PCI_VENDOR_ID_AMD, 0x1419 },
/* 0x1631 is the PCI ID for the IOMMU found on Renoir/Cezanne
*/
{ PCI_VENDOR_ID_AMD, 0x1631 },
/* 0x5a23 is the PCI ID for the IOMMU found on RD890S/RD990
*/
{ PCI_VENDOR_ID_ATI, 0x5a23 },

View file

@ -235,7 +235,7 @@ static u32 clock_divider_to_resolution(u16 divider)
{
/*
* Resolution is the duration of 1 tick of the readable portion of
* of the pulse width counter as read from the FIFO. The two lsb's are
* the pulse width counter as read from the FIFO. The two lsb's are
* not readable, hence the << 2. This function returns ns.
*/
return DIV_ROUND_CLOSEST((1 << 2) * ((u32) divider + 1) * 1000,

View file

@ -24,7 +24,7 @@
/*
* We calculate the baseband frequencies of the carrier and the pilot tones
* based on the the sampling rate of the audio rds fifo.
* based on the sampling rate of the audio rds fifo.
*/
#define FREQ_A2_CARRIER baseband_freq(54687.5, 2689.36, 0.0)

View file

@ -144,11 +144,10 @@ static int buffer_prepare(struct vb2_buffer *vb)
return -EINVAL;
vb2_set_plane_payload(vb, 0, size);
cx88_risc_buffer(dev->pci, &buf->risc, sgt->sgl,
0, VBI_LINE_LENGTH * lines,
VBI_LINE_LENGTH, 0,
lines);
return 0;
return cx88_risc_buffer(dev->pci, &buf->risc, sgt->sgl,
0, VBI_LINE_LENGTH * lines,
VBI_LINE_LENGTH, 0,
lines);
}
static void buffer_finish(struct vb2_buffer *vb)

View file

@ -431,6 +431,7 @@ static int queue_setup(struct vb2_queue *q,
static int buffer_prepare(struct vb2_buffer *vb)
{
int ret;
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
struct cx8800_dev *dev = vb->vb2_queue->drv_priv;
struct cx88_core *core = dev->core;
@ -445,35 +446,35 @@ static int buffer_prepare(struct vb2_buffer *vb)
switch (core->field) {
case V4L2_FIELD_TOP:
cx88_risc_buffer(dev->pci, &buf->risc,
sgt->sgl, 0, UNSET,
buf->bpl, 0, core->height);
ret = cx88_risc_buffer(dev->pci, &buf->risc,
sgt->sgl, 0, UNSET,
buf->bpl, 0, core->height);
break;
case V4L2_FIELD_BOTTOM:
cx88_risc_buffer(dev->pci, &buf->risc,
sgt->sgl, UNSET, 0,
buf->bpl, 0, core->height);
ret = cx88_risc_buffer(dev->pci, &buf->risc,
sgt->sgl, UNSET, 0,
buf->bpl, 0, core->height);
break;
case V4L2_FIELD_SEQ_TB:
cx88_risc_buffer(dev->pci, &buf->risc,
sgt->sgl,
0, buf->bpl * (core->height >> 1),
buf->bpl, 0,
core->height >> 1);
ret = cx88_risc_buffer(dev->pci, &buf->risc,
sgt->sgl,
0, buf->bpl * (core->height >> 1),
buf->bpl, 0,
core->height >> 1);
break;
case V4L2_FIELD_SEQ_BT:
cx88_risc_buffer(dev->pci, &buf->risc,
sgt->sgl,
buf->bpl * (core->height >> 1), 0,
buf->bpl, 0,
core->height >> 1);
ret = cx88_risc_buffer(dev->pci, &buf->risc,
sgt->sgl,
buf->bpl * (core->height >> 1), 0,
buf->bpl, 0,
core->height >> 1);
break;
case V4L2_FIELD_INTERLACED:
default:
cx88_risc_buffer(dev->pci, &buf->risc,
sgt->sgl, 0, buf->bpl,
buf->bpl, buf->bpl,
core->height >> 1);
ret = cx88_risc_buffer(dev->pci, &buf->risc,
sgt->sgl, 0, buf->bpl,
buf->bpl, buf->bpl,
core->height >> 1);
break;
}
dprintk(2,
@ -481,7 +482,7 @@ static int buffer_prepare(struct vb2_buffer *vb)
buf, buf->vb.vb2_buf.index, __func__,
core->width, core->height, dev->fmt->depth, dev->fmt->fourcc,
(unsigned long)buf->risc.dma);
return 0;
return ret;
}
static void buffer_finish(struct vb2_buffer *vb)

View file

@ -538,7 +538,7 @@ static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *f)
reg_2964 = (reg_2964 << 16) + reg_2964 + (reg_2964 * 46 / 94);
/* Okay, we've wasted time working out the correct value,
but if we use it, it fouls the the window alignment.
but if we use it, it fouls the window alignment.
Fudge it to what we want... */
reg_2964 = 0x00010001 + ((reg_2964 & 0x0000FFFF) - (reg_2964 >> 16));
reg_2968 = 0x00010001 + ((reg_2968 & 0x0000FFFF) - (reg_2968 >> 16));

View file

@ -596,43 +596,6 @@ struct mychip {
int capture_source[MIXER_ADDR_LAST + 1][2];
};
#ifdef NGENE_V4L
struct ngene_overlay {
int tvnorm;
struct v4l2_rect w;
enum v4l2_field field;
struct v4l2_clip *clips;
int nclips;
int setup_ok;
};
struct ngene_tvnorm {
int v4l2_id;
char *name;
u16 swidth, sheight; /* scaled standard width, height */
int tuner_norm;
int soundstd;
};
struct ngene_vopen {
struct ngene_channel *ch;
enum v4l2_priority prio;
int width;
int height;
int depth;
struct videobuf_queue vbuf_q;
struct videobuf_queue vbi;
int fourcc;
int picxcount;
int resources;
enum v4l2_buf_type type;
const struct ngene_format *fmt;
const struct ngene_format *ovfmt;
struct ngene_overlay ov;
};
#endif
struct ngene_channel {
struct device device;
struct i2c_adapter i2c_adapter;
@ -709,18 +672,6 @@ struct ngene_channel {
int tvnorm_num;
int tvnorm;
#ifdef NGENE_V4L
int videousers;
struct v4l2_prio_state prio;
struct ngene_vopen init;
int resources;
struct v4l2_framebuffer fbuf;
struct ngene_buffer *screen; /* overlay */
struct list_head capture; /* video capture queue */
spinlock_t s_lock;
struct semaphore reslock;
#endif
int running;
int tsin_offset;
@ -863,35 +814,6 @@ struct ngene_info {
int (*switch_ctrl)(struct ngene_channel *, int, int);
};
#ifdef NGENE_V4L
struct ngene_format {
char *name;
int fourcc; /* video4linux 2 */
int btformat; /* BT848_COLOR_FMT_* */
int format;
int btswap; /* BT848_COLOR_CTL_* */
int depth; /* bit/pixel */
int flags;
int hshift, vshift; /* for planar modes */
int palette;
};
#define RESOURCE_OVERLAY 1
#define RESOURCE_VIDEO 2
#define RESOURCE_VBI 4
struct ngene_buffer {
/* common v4l buffer stuff -- must be first */
struct videobuf_buffer vb;
/* ngene specific */
const struct ngene_format *fmt;
int tvnorm;
int btformat;
int btswap;
};
#endif
/* Provided by ngene-core.c */
int ngene_probe(struct pci_dev *pci_dev, const struct pci_device_id *id);

View file

@ -626,7 +626,7 @@ static irqreturn_t saa7164_irq(int irq, void *dev_id)
portf = &dev->ports[SAA7164_PORT_VBI2];
/* Check that the hardware is accessible. If the status bytes are
* 0xFF then the device is not accessible, the the IRQ belongs
* 0xFF then the device is not accessible, the IRQ belongs
* to another driver.
* 4 x u32 interrupt registers.
*/

View file

@ -1020,7 +1020,7 @@ static int solo_g_parm(struct file *file, void *priv,
cp->timeperframe.numerator = solo_enc->interval;
cp->timeperframe.denominator = solo_enc->solo_dev->fps;
cp->capturemode = 0;
/* XXX: Shouldn't we be able to get/set this from videobuf? */
/* XXX: Shouldn't we be able to get/set this from vb2? */
cp->readbuffers = 2;
return 0;

View file

@ -92,9 +92,8 @@ struct videocodec *videocodec_attach(struct videocodec_master *master)
h->attached += 1;
return codec;
} else {
kfree(codec);
}
kfree(codec);
}
h = h->next;
}
@ -255,8 +254,8 @@ int videocodec_debugfs_show(struct seq_file *m)
struct codec_list *h = codeclist_top;
struct attached_list *a;
seq_printf(m, "<S>lave or attached <M>aster name type flags magic ");
seq_printf(m, "(connected as)\n");
seq_puts(m, "<S>lave or attached <M>aster name type flags magic ");
seq_puts(m, "(connected as)\n");
while (h) {
seq_printf(m, "S %32s %04x %08lx %08lx (TEMPLATE)\n",

View file

@ -12,109 +12,109 @@
/* general description */
/* =================== */
/* Should ease the (re-)usage of drivers supporting cards with (different)
video codecs. The codecs register to this module their functionality,
and the processors (masters) can attach to them if they fit.
The codecs are typically have a "strong" binding to their master - so I
don't think it makes sense to have a full blown interfacing as with e.g.
i2c. If you have an other opinion, let's discuss & implement it :-)))
Usage:
The slave has just to setup the videocodec structure and use two functions:
videocodec_register(codecdata);
videocodec_unregister(codecdata);
The best is just calling them at module (de-)initialisation.
The master sets up the structure videocodec_master and calls:
codecdata=videocodec_attach(master_codecdata);
videocodec_detach(codecdata);
The slave is called during attach/detach via functions setup previously
during register. At that time, the master_data pointer is set up
and the slave can access any io registers of the master device (in the case
the slave is bound to it). Otherwise it doesn't need this functions and
therfor they may not be initialized.
The other functions are just for convenience, as they are for sure used by
most/all of the codecs. The last ones may be omitted, too.
See the structure declaration below for more information and which data has
to be set up for the master and the slave.
----------------------------------------------------------------------------
The master should have "knowledge" of the slave and vice versa. So the data
structures sent to/from slave via set_data/get_data set_image/get_image are
device dependent and vary between MJPEG/MPEG/WAVELET/... devices. (!!!!)
----------------------------------------------------------------------------
*/
/*
* Should ease the (re-)usage of drivers supporting cards with (different)
* video codecs. The codecs register to this module their functionality,
* and the processors (masters) can attach to them if they fit.
*
* The codecs are typically have a "strong" binding to their master - so I
* don't think it makes sense to have a full blown interfacing as with e.g.
* i2c. If you have an other opinion, let's discuss & implement it :-)))
*
* Usage:
*
* The slave has just to setup the videocodec structure and use two functions:
* videocodec_register(codecdata);
* videocodec_unregister(codecdata);
* The best is just calling them at module (de-)initialisation.
*
* The master sets up the structure videocodec_master and calls:
* codecdata=videocodec_attach(master_codecdata);
* videocodec_detach(codecdata);
*
* The slave is called during attach/detach via functions setup previously
* during register. At that time, the master_data pointer is set up
* and the slave can access any io registers of the master device (in the case
* the slave is bound to it). Otherwise it doesn't need this functions and
* therefor they may not be initialized.
*
* The other functions are just for convenience, as they are for sure used by
* most/all of the codecs. The last ones may be omitted, too.
*
* See the structure declaration below for more information and which data has
* to be set up for the master and the slave.
*
* ----------------------------------------------------------------------------
* The master should have "knowledge" of the slave and vice versa. So the data
* structures sent to/from slave via set_data/get_data set_image/get_image are
* device dependent and vary between MJPEG/MPEG/WAVELET/... devices. (!!!!)
* ----------------------------------------------------------------------------
*/
/* ========================================== */
/* description of the videocodec_io structure */
/* ========================================== */
/*
==== master setup ====
name -> name of the device structure for reference and debugging
master_data -> data ref. for the master (e.g. the zr36055,57,67)
readreg -> ref. to read-fn from register (setup by master, used by slave)
writereg -> ref. to write-fn to register (setup by master, used by slave)
this two functions do the lowlevel I/O job
* ==== master setup ====
* name -> name of the device structure for reference and debugging
* master_data -> data ref. for the master (e.g. the zr36055,57,67)
* readreg -> ref. to read-fn from register (setup by master, used by slave)
* writereg -> ref. to write-fn to register (setup by master, used by slave)
* this two functions do the lowlevel I/O job
*
* ==== slave functionality setup ====
* slave_data -> data ref. for the slave (e.g. the zr36050,60)
* check -> fn-ref. checks availability of an device, returns -EIO on failure or
* the type on success
* this makes espcecially sense if a driver module supports more than
* one codec which may be quite similar to access, nevertheless it
* is good for a first functionality check
*
* -- main functions you always need for compression/decompression --
*
* set_mode -> this fn-ref. resets the entire codec, and sets up the mode
* with the last defined norm/size (or device default if not
* available) - it returns 0 if the mode is possible
* set_size -> this fn-ref. sets the norm and image size for
* compression/decompression (returns 0 on success)
* the norm param is defined in videodev2.h (V4L2_STD_*)
*
* additional setup may be available, too - but the codec should work with
* some default values even without this
*
* set_data -> sets device-specific data (tables, quality etc.)
* get_data -> query device-specific data (tables, quality etc.)
*
* if the device delivers interrupts, they may be setup/handled here
* setup_interrupt -> codec irq setup (not needed for 36050/60)
* handle_interrupt -> codec irq handling (not needed for 36050/60)
==== slave functionality setup ====
slave_data -> data ref. for the slave (e.g. the zr36050,60)
check -> fn-ref. checks availability of an device, returns -EIO on failure or
the type on success
this makes espcecially sense if a driver module supports more than
one codec which may be quite similar to access, nevertheless it
is good for a first functionality check
-- main functions you always need for compression/decompression --
set_mode -> this fn-ref. resets the entire codec, and sets up the mode
with the last defined norm/size (or device default if not
available) - it returns 0 if the mode is possible
set_size -> this fn-ref. sets the norm and image size for
compression/decompression (returns 0 on success)
the norm param is defined in videodev2.h (V4L2_STD_*)
additional setup may be available, too - but the codec should work with
some default values even without this
set_data -> sets device-specific data (tables, quality etc.)
get_data -> query device-specific data (tables, quality etc.)
if the device delivers interrupts, they may be setup/handled here
setup_interrupt -> codec irq setup (not needed for 36050/60)
handle_interrupt -> codec irq handling (not needed for 36050/60)
if the device delivers pictures, they may be handled here
put_image -> puts image data to the codec (not needed for 36050/60)
get_image -> gets image data from the codec (not needed for 36050/60)
the calls include frame numbers and flags (even/odd/...)
if needed and a flag which allows blocking until its ready
*/
* if the device delivers pictures, they may be handled here
* put_image -> puts image data to the codec (not needed for 36050/60)
* get_image -> gets image data from the codec (not needed for 36050/60)
* the calls include frame numbers and flags (even/odd/...)
* if needed and a flag which allows blocking until its ready
*/
/* ============== */
/* user interface */
/* ============== */
/*
Currently there is only a information display planned, as the layer
is not visible for the user space at all.
Information is available via procfs. The current entry is "/proc/videocodecs"
but it makes sense to "hide" it in the /proc/video tree of v4l(2) --TODO--.
A example for such an output is:
<S>lave or attached <M>aster name type flags magic (connected as)
S zr36050 0002 0000d001 00000000 (TEMPLATE)
M zr36055[0] 0001 0000c001 00000000 (zr36050[0])
M zr36055[1] 0001 0000c001 00000000 (zr36050[1])
*/
* Currently there is only a information display planned, as the layer
* is not visible for the user space at all.
*
* Information is available via procfs. The current entry is "/proc/videocodecs"
* but it makes sense to "hide" it in the /proc/video tree of v4l(2) --TODO--.
*
* A example for such an output is:
*
* <S>lave or attached <M>aster name type flags magic (connected as)
* S zr36050 0002 0000d001 00000000 (TEMPLATE)
* M zr36055[0] 0001 0000c001 00000000 (zr36050[0])
* M zr36055[1] 0001 0000c001 00000000 (zr36050[1])
*/
/* =============================================== */
/* special defines for the videocodec_io structure */
@ -293,15 +293,15 @@ struct videocodec_master {
// * master structure needs to be kmalloc'ed before calling attach
// and free'd after calling detach
// * returns pointer on success, NULL on failure
extern struct videocodec *videocodec_attach(struct videocodec_master *);
struct videocodec *videocodec_attach(struct videocodec_master *master);
// * 0 on success, <0 (errno) on failure
extern int videocodec_detach(struct videocodec *);
int videocodec_detach(struct videocodec *codec);
/* register and unregister commands for the slaves */
// * 0 on success, <0 (errno) on failure
extern int videocodec_register(const struct videocodec *);
int videocodec_register(const struct videocodec *codec);
// * 0 on success, <0 (errno) on failure
extern int videocodec_unregister(const struct videocodec *);
int videocodec_unregister(const struct videocodec *codec);
/* the other calls are directly done via the videocodec structure! */

View file

@ -140,11 +140,16 @@ struct zoran_v4l_settings {
/* jpg-capture/-playback settings */
struct zoran_jpg_settings {
int decimation; /* this bit is used to set everything to default */
int hor_dcm, ver_dcm, tmp_dcm; /* capture decimation settings (tmp_dcm=1 means both fields) */
int field_per_buff, odd_even; /* field-settings (odd_even=1 (+tmp_dcm=1) means top-field-first) */
int img_x, img_y, img_width, img_height; /* crop settings (subframe capture) */
struct v4l2_jpegcompression jpg_comp; /* JPEG-specific capture settings */
/* this bit is used to set everything to default */
int decimation;
/* capture decimation settings (tmp_dcm=1 means both fields) */
int hor_dcm, ver_dcm, tmp_dcm;
/* field-settings (odd_even=1 (+tmp_dcm=1) means top-field-first) */
int field_per_buff, odd_even;
/* crop settings (subframe capture) */
int img_x, img_y, img_width, img_height;
/* JPEG-specific capture settings */
struct v4l2_jpegcompression jpg_comp;
};
struct zoran;
@ -248,7 +253,8 @@ struct zoran {
unsigned long vbseq;
/* zr36057's code buffer table */
__le32 *stat_com; /* stat_com[i] is indexed by dma_head/tail & BUZ_MASK_STAT_COM */
/* stat_com[i] is indexed by dma_head/tail & BUZ_MASK_STAT_COM */
__le32 *stat_com;
/* Additional stuff for testing */
unsigned int ghost_int;
@ -292,14 +298,16 @@ static inline struct zoran *to_zoran(struct v4l2_device *v4l2_dev)
return container_of(v4l2_dev, struct zoran, v4l2_dev);
}
/* There was something called _ALPHA_BUZ that used the PCI address instead of
* the kernel iomapped address for btread/btwrite. */
/*
* There was something called _ALPHA_BUZ that used the PCI address instead of
* the kernel iomapped address for btread/btwrite.
*/
#define btwrite(dat, adr) writel((dat), zr->zr36057_mem + (adr))
#define btread(adr) readl(zr->zr36057_mem + (adr))
#define btand(dat, adr) btwrite((dat) & btread(adr), adr)
#define btor(dat, adr) btwrite((dat) | btread(adr), adr)
#define btaor(dat, mask, adr) btwrite((dat) | ((mask) & btread(adr)), adr)
#define btand(dat, adr) btwrite((dat) & btread(adr), (adr))
#define btor(dat, adr) btwrite((dat) | btread(adr), (adr))
#define btaor(dat, mask, adr) btwrite((dat) | ((mask) & btread(adr)), (adr))
#endif

View file

@ -172,8 +172,6 @@ void zr36016_write(struct videocodec *codec, u16 reg, u32 val)
static void dc10_init(struct zoran *zr)
{
pci_dbg(zr->pci_dev, "%s\n", __func__);
/* Pixel clock selection */
GPIO(zr, 4, 0);
GPIO(zr, 5, 1);
@ -183,13 +181,10 @@ static void dc10_init(struct zoran *zr)
static void dc10plus_init(struct zoran *zr)
{
pci_dbg(zr->pci_dev, "%s\n", __func__);
}
static void buz_init(struct zoran *zr)
{
pci_dbg(zr->pci_dev, "%s\n", __func__);
/* some stuff from Iomega */
pci_write_config_dword(zr->pci_dev, 0xfc, 0x90680f15);
pci_write_config_dword(zr->pci_dev, 0x0c, 0x00012020);
@ -198,8 +193,6 @@ static void buz_init(struct zoran *zr)
static void lml33_init(struct zoran *zr)
{
pci_dbg(zr->pci_dev, "%s\n", __func__);
GPIO(zr, 2, 1); // Set Composite input/output
}
@ -334,10 +327,6 @@ static void videocodec_exit(struct zoran *zr)
codec_exit(zr, zr->card.video_vfe);
}
// struct tvnorm {
// u16 wt, wa, h_start, h_sync_start, ht, ha, v_start;
// };
static const struct tvnorm f50sqpixel = { 944, 768, 83, 880, 625, 576, 16 };
static const struct tvnorm f60sqpixel = { 780, 640, 51, 716, 525, 480, 12 };
static const struct tvnorm f50ccir601 = { 864, 720, 75, 804, 625, 576, 18 };
@ -619,7 +608,10 @@ static struct card_info zoran_cards[NUM_CARDS] = {
}, {
.type = AVS6EYES,
.name = "6-Eyes",
/* AverMedia chose not to brand the 6-Eyes. Thus it can't be autodetected, and requires card=x. */
/*
* AverMedia chose not to brand the 6-Eyes. Thus it can't be
* autodetected, and requires card=x.
*/
.i2c_decoder = "ks0127",
.addrs_decoder = ks0127_addrs,
.i2c_encoder = "bt866",
@ -764,7 +756,9 @@ int zoran_check_jpg_settings(struct zoran *zr,
case 4:
if (zr->card.type == DC10_NEW) {
pci_dbg(zr->pci_dev, "%s - HDec by 4 is not supported on the DC10\n", __func__);
pci_dbg(zr->pci_dev,
"%s - HDec by 4 is not supported on the DC10\n",
__func__);
err0++;
break;
}
@ -882,12 +876,7 @@ static int zoran_init_video_device(struct zoran *zr, struct video_device *video_
video_dev->device_caps = V4L2_CAP_STREAMING | dir;
strscpy(video_dev->name, ZR_DEVNAME(zr), sizeof(video_dev->name));
/*
* It's not a mem2mem device, but you can both capture and output from one and the same
* device. This should really be split up into two device nodes, but that's a job for
* another day.
*/
video_dev->vfl_dir = VFL_DIR_M2M;
video_dev->vfl_dir = VFL_DIR_RX;
zoran_queue_init(zr, &zr->vq, V4L2_BUF_TYPE_VIDEO_CAPTURE);
err = video_register_device(video_dev, VFL_TYPE_VIDEO, video_nr[zr->id]);
@ -1019,7 +1008,9 @@ static int zr36057_init(struct zoran *zr)
zr->timing = zr->card.tvn[ZR_NORM_SECAM];
}
if (!zr->timing) {
pci_warn(zr->pci_dev, "%s - default TV standard not supported by hardware. PAL will be used.\n", __func__);
pci_warn(zr->pci_dev,
"%s - default TV standard not supported by hardware. PAL will be used.\n",
__func__);
zr->norm = V4L2_STD_PAL;
zr->timing = zr->card.tvn[ZR_NORM_PAL];
}
@ -1038,9 +1029,9 @@ static int zr36057_init(struct zoran *zr)
zr->stat_com = dma_alloc_coherent(&zr->pci_dev->dev,
BUZ_NUM_STAT_COM * sizeof(u32),
&zr->p_sc, GFP_KERNEL);
if (!zr->stat_com) {
if (!zr->stat_com)
return -ENOMEM;
}
for (j = 0; j < BUZ_NUM_STAT_COM; j++)
zr->stat_com[j] = cpu_to_le32(1); /* mark as unavailable to zr36057 */
@ -1066,9 +1057,11 @@ static int zr36057_init(struct zoran *zr)
return 0;
exit_statcomb:
dma_free_coherent(&zr->pci_dev->dev, BUZ_NUM_STAT_COM * sizeof(u32) * 2, zr->stat_comb, zr->p_scb);
dma_free_coherent(&zr->pci_dev->dev, BUZ_NUM_STAT_COM * sizeof(u32) * 2,
zr->stat_comb, zr->p_scb);
exit_statcom:
dma_free_coherent(&zr->pci_dev->dev, BUZ_NUM_STAT_COM * sizeof(u32), zr->stat_com, zr->p_sc);
dma_free_coherent(&zr->pci_dev->dev, BUZ_NUM_STAT_COM * sizeof(u32),
zr->stat_com, zr->p_sc);
return err;
}
@ -1099,8 +1092,10 @@ static void zoran_remove(struct pci_dev *pdev)
btwrite(0, ZR36057_SPGPPCR);
pci_free_irq(zr->pci_dev, 0, zr);
/* unmap and free memory */
dma_free_coherent(&zr->pci_dev->dev, BUZ_NUM_STAT_COM * sizeof(u32), zr->stat_com, zr->p_sc);
dma_free_coherent(&zr->pci_dev->dev, BUZ_NUM_STAT_COM * sizeof(u32) * 2, zr->stat_comb, zr->p_scb);
dma_free_coherent(&zr->pci_dev->dev, BUZ_NUM_STAT_COM * sizeof(u32),
zr->stat_com, zr->p_sc);
dma_free_coherent(&zr->pci_dev->dev, BUZ_NUM_STAT_COM * sizeof(u32) * 2,
zr->stat_comb, zr->p_scb);
pci_release_regions(pdev);
pci_disable_device(zr->pci_dev);
zoran_exit_video_devices(zr);
@ -1299,7 +1294,8 @@ static int zoran_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_err(pdev, "Unknown card, try specifying card=X module parameter\n");
goto zr_unreg;
}
pci_info(zr->pci_dev, "%s() - card %s detected\n", __func__, zoran_cards[card_num].name);
pci_info(zr->pci_dev, "%s() - card %s detected\n", __func__,
zoran_cards[card_num].name);
} else {
card_num = card[nr];
if (card_num >= NUM_CARDS || card_num < 0) {
@ -1324,7 +1320,8 @@ static int zoran_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (err)
goto zr_unreg;
zr->zr36057_mem = devm_ioremap(&pdev->dev, pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
zr->zr36057_mem = devm_ioremap(&pdev->dev, pci_resource_start(pdev, 0),
pci_resource_len(pdev, 0));
if (!zr->zr36057_mem) {
pci_err(pdev, "%s() - ioremap failed\n", __func__);
goto zr_pci_release;
@ -1348,7 +1345,8 @@ static int zoran_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
&latency);
need_latency = zr->revision > 1 ? 32 : 48;
if (latency != need_latency) {
pci_info(zr->pci_dev, "Changing PCI latency from %d to %d\n", latency, need_latency);
pci_info(zr->pci_dev, "Changing PCI latency from %d to %d\n",
latency, need_latency);
pci_write_config_byte(zr->pci_dev, PCI_LATENCY_TIMER, need_latency);
}

View file

@ -19,11 +19,10 @@ extern int zr36067_debug;
extern const struct video_device zoran_template;
extern int zoran_check_jpg_settings(struct zoran *zr,
struct zoran_jpg_settings *settings,
int try);
extern void zoran_open_init_params(struct zoran *zr);
extern void zoran_vdev_release(struct video_device *vdev);
int zoran_check_jpg_settings(struct zoran *zr,
struct zoran_jpg_settings *settings, int try);
void zoran_open_init_params(struct zoran *zr);
void zoran_vdev_release(struct video_device *vdev);
void zr36016_write(struct videocodec *codec, u16 reg, u32 val);

View file

@ -50,7 +50,6 @@ static bool lml33dpath; /* default = 0
module_param(lml33dpath, bool, 0644);
MODULE_PARM_DESC(lml33dpath, "Use digital path capture mode (on LML33 cards)");
int zr_set_buf(struct zoran *zr);
/*
* initialize video front end
*/
@ -108,7 +107,6 @@ int post_office_wait(struct zoran *zr)
{
u32 por;
// while (((por = btread(ZR36057_POR)) & (ZR36057_POR_PO_PEN | ZR36057_POR_PO_TIME)) == ZR36057_POR_PO_PEN) {
while ((por = btread(ZR36057_POR)) & ZR36057_POR_PO_PEN) {
/* wait for something to happen */
/* TODO add timeout */
@ -155,10 +153,12 @@ void jpeg_codec_sleep(struct zoran *zr, int sleep)
{
GPIO(zr, zr->card.gpio[ZR_GPIO_JPEG_SLEEP], !sleep);
if (!sleep) {
pci_dbg(zr->pci_dev, "%s() - wake GPIO=0x%08x\n", __func__, btread(ZR36057_GPPGCR1));
udelay(500);
pci_dbg(zr->pci_dev, "%s() - wake GPIO=0x%08x\n",
__func__, btread(ZR36057_GPPGCR1));
usleep_range(500, 1000);
} else {
pci_dbg(zr->pci_dev, "%s() - sleep GPIO=0x%08x\n", __func__, btread(ZR36057_GPPGCR1));
pci_dbg(zr->pci_dev, "%s() - sleep GPIO=0x%08x\n",
__func__, btread(ZR36057_GPPGCR1));
udelay(2);
}
}
@ -284,7 +284,8 @@ static void zr36057_set_vfe(struct zoran *zr, int video_width, int video_height,
vcrop1 = (tvn->ha / 2 - he) / 2;
vcrop2 = tvn->ha / 2 - he - vcrop1;
v_start = tvn->v_start;
v_end = v_start + tvn->ha / 2; // - 1; FIXME SnapShot times out with -1 in 768*576 on the DC10 - LP
// FIXME SnapShot times out with -1 in 768*576 on the DC10 - LP
v_end = v_start + tvn->ha / 2; // - 1;
v_start += vcrop1;
v_end -= vcrop2;
reg = ((v_start & ZR36057_VFEVCR_VMASK) << ZR36057_VFEVCR_V_START)
@ -298,10 +299,12 @@ static void zr36057_set_vfe(struct zoran *zr, int video_width, int video_height,
reg |= (hor_dcm << ZR36057_VFESPFR_HOR_DCM);
reg |= (ver_dcm << ZR36057_VFESPFR_VER_DCM);
reg |= (disp_mode << ZR36057_VFESPFR_DISP_MODE);
/* RJ: I don't know, why the following has to be the opposite
/*
* RJ: I don't know, why the following has to be the opposite
* of the corresponding ZR36060 setting, but only this way
* we get the correct colors when uncompressing to the screen */
//reg |= ZR36057_VFESPFR_VCLK_POL; /**/
* we get the correct colors when uncompressing to the screen
*/
//reg |= ZR36057_VFESPFR_VCLK_POL;
/* RJ: Don't know if that is needed for NTSC also */
if (!(zr->norm & V4L2_STD_NTSC))
reg |= ZR36057_VFESPFR_EXT_FL; // NEEDED!!!!!!! Wolfgang
@ -342,7 +345,7 @@ void zr36057_set_memgrab(struct zoran *zr, int mode)
* will be stuck at 1 until capturing is turned back on.
*/
if (btread(ZR36057_VSSFGR) & ZR36057_VSSFGR_SNAP_SHOT)
pci_warn(zr->pci_dev, "zr36057_set_memgrab(1) with SnapShot on!?\n");
pci_warn(zr->pci_dev, "%s(1) with SnapShot on!?\n", __func__);
/* switch on VSync interrupts */
btwrite(IRQ_MASK, ZR36057_ISR); // Clear Interrupts
@ -595,11 +598,9 @@ void jpeg_start(struct zoran *zr)
/* enable the Go generation */
btor(ZR36057_JMC_GO_EN, ZR36057_JMC);
udelay(30);
usleep_range(30, 100);
set_frame(zr, 1); // /FRAME
pci_dbg(zr->pci_dev, "jpeg_start\n");
}
void zr36057_enable_jpg(struct zoran *zr, enum zoran_codec_mode mode)
@ -803,8 +804,10 @@ static void zoran_reap_stat_com(struct zoran *zr)
unsigned int size = 0;
u32 fcnt;
/* In motion decompress we don't have a hardware frame counter,
* we just count the interrupts here */
/*
* In motion decompress we don't have a hardware frame counter,
* we just count the interrupts here
*/
if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS)
zr->jpg_seq_num++;
@ -938,9 +941,9 @@ void zoran_init_hardware(struct zoran *zr)
void zr36057_restart(struct zoran *zr)
{
btwrite(0, ZR36057_SPGPPCR);
udelay(1000);
usleep_range(1000, 2000);
btor(ZR36057_SPGPPCR_SOFT_RESET, ZR36057_SPGPPCR);
udelay(1000);
usleep_range(1000, 2000);
/* assert P_Reset */
btwrite(0, ZR36057_JPC);

View file

@ -0,0 +1,60 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Zoran zr36057/zr36067 PCI controller driver, for the
* Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux
* Media Labs LML33/LML33R10.
*
* This part handles card-specific data and detection
*
* Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
*/
#ifndef __ZORAN_DEVICE_H__
#define __ZORAN_DEVICE_H__
/* general purpose I/O */
void GPIO(struct zoran *zr, int bit, unsigned int value);
/* codec (or actually: guest bus) access */
int post_office_wait(struct zoran *zr);
int post_office_write(struct zoran *zr, unsigned int guest, unsigned int reg,
unsigned int value);
int post_office_read(struct zoran *zr, unsigned int guest, unsigned int reg);
void jpeg_codec_sleep(struct zoran *zr, int sleep);
int jpeg_codec_reset(struct zoran *zr);
/* zr360x7 access to raw capture */
void zr36057_overlay(struct zoran *zr, int on);
void write_overlay_mask(struct zoran_fh *fh, struct v4l2_clip *vp, int count);
void zr36057_set_memgrab(struct zoran *zr, int mode);
int wait_grab_pending(struct zoran *zr);
/* interrupts */
void print_interrupts(struct zoran *zr);
void clear_interrupt_counters(struct zoran *zr);
irqreturn_t zoran_irq(int irq, void *dev_id);
/* JPEG codec access */
void jpeg_start(struct zoran *zr);
void zr36057_enable_jpg(struct zoran *zr, enum zoran_codec_mode mode);
void zoran_feed_stat_com(struct zoran *zr);
/* general */
void zoran_set_pci_master(struct zoran *zr, int set_master);
void zoran_init_hardware(struct zoran *zr);
void zr36057_restart(struct zoran *zr);
extern const struct zoran_format zoran_formats[];
extern int v4l_bufsize;
extern int jpg_bufsize;
extern int pass_through;
/* i2c */
#define decoder_call(zr, o, f, args...) \
v4l2_subdev_call((zr)->decoder, o, f, ##args)
#define encoder_call(zr, o, f, args...) \
v4l2_subdev_call((zr)->encoder, o, f, ##args)
#endif /* __ZORAN_DEVICE_H__ */

View file

@ -203,7 +203,6 @@ static int zoran_v4l_set_format(struct zoran *zr, int width, int height,
static int zoran_set_norm(struct zoran *zr, v4l2_std_id norm)
{
if (!(norm & zr->card.norms)) {
pci_dbg(zr->pci_dev, "%s - unsupported norm %llx\n", __func__, norm);
return -EINVAL;
@ -287,17 +286,6 @@ static int zoran_enum_fmt_vid_cap(struct file *file, void *__fh,
return zoran_enum_fmt(zr, f, ZORAN_FORMAT_CAPTURE);
}
#if 0
/* TODO: output does not work yet */
static int zoran_enum_fmt_vid_out(struct file *file, void *__fh,
struct v4l2_fmtdesc *f)
{
struct zoran *zr = video_drvdata(file);
return zoran_enum_fmt(zr, f, ZORAN_FORMAT_PLAYBACK);
}
#endif
static int zoran_g_fmt_vid_out(struct file *file, void *__fh,
struct v4l2_format *fmt)
{
@ -430,8 +418,10 @@ static int zoran_try_fmt_vid_cap(struct file *file, void *__fh,
fmt->fmt.pix.field = V4L2_FIELD_TOP;
bpp = DIV_ROUND_UP(zoran_formats[i].depth, 8);
v4l_bound_align_image(&fmt->fmt.pix.width, BUZ_MIN_WIDTH, BUZ_MAX_WIDTH, bpp == 2 ? 1 : 2,
&fmt->fmt.pix.height, BUZ_MIN_HEIGHT, BUZ_MAX_HEIGHT, 0, 0);
v4l_bound_align_image(&fmt->fmt.pix.width, BUZ_MIN_WIDTH, BUZ_MAX_WIDTH,
bpp == 2 ? 1 : 2,
&fmt->fmt.pix.height, BUZ_MIN_HEIGHT, BUZ_MAX_HEIGHT,
0, 0);
fmt->fmt.pix.bytesperline = fmt->fmt.pix.width * bpp;
fmt->fmt.pix.sizeimage = fmt->fmt.pix.bytesperline * fmt->fmt.pix.height;
return 0;
@ -627,38 +617,6 @@ static int zoran_s_input(struct file *file, void *__fh, unsigned int input)
return res;
}
#if 0
/* TODO: output does not work yet */
static int zoran_enum_output(struct file *file, void *__fh,
struct v4l2_output *outp)
{
if (outp->index != 0)
return -EINVAL;
outp->index = 0;
outp->type = V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY;
outp->std = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM;
outp->capabilities = V4L2_OUT_CAP_STD;
strscpy(outp->name, "Autodetect", sizeof(outp->name));
return 0;
}
static int zoran_g_output(struct file *file, void *__fh, unsigned int *output)
{
*output = 0;
return 0;
}
static int zoran_s_output(struct file *file, void *__fh, unsigned int output)
{
if (output != 0)
return -EINVAL;
return 0;
}
#endif
/* cropping (sub-frame capture) */
static int zoran_g_selection(struct file *file, void *__fh, struct v4l2_selection *sel)
{
@ -746,9 +704,6 @@ static const struct v4l2_ioctl_ops zoran_ioctl_ops = {
.vidioc_enum_input = zoran_enum_input,
.vidioc_g_input = zoran_g_input,
.vidioc_s_input = zoran_s_input,
/* .vidioc_enum_output = zoran_enum_output,
.vidioc_g_output = zoran_g_output,
.vidioc_s_output = zoran_s_output,*/
.vidioc_g_std = zoran_g_std,
.vidioc_s_std = zoran_s_std,
.vidioc_create_bufs = vb2_ioctl_create_bufs,
@ -760,13 +715,9 @@ static const struct v4l2_ioctl_ops zoran_ioctl_ops = {
.vidioc_streamon = vb2_ioctl_streamon,
.vidioc_streamoff = vb2_ioctl_streamoff,
.vidioc_enum_fmt_vid_cap = zoran_enum_fmt_vid_cap,
/* .vidioc_enum_fmt_vid_out = zoran_enum_fmt_vid_out,*/
.vidioc_g_fmt_vid_cap = zoran_g_fmt_vid_cap,
/* .vidioc_g_fmt_vid_out = zoran_g_fmt_vid_out,*/
.vidioc_s_fmt_vid_cap = zoran_s_fmt_vid_cap,
/* .vidioc_s_fmt_vid_out = zoran_s_fmt_vid_out,*/
.vidioc_try_fmt_vid_cap = zoran_try_fmt_vid_cap,
/* .vidioc_try_fmt_vid_out = zoran_try_fmt_vid_out,*/
.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
@ -1013,7 +964,7 @@ int zoran_queue_init(struct zoran *zr, struct vb2_queue *vq, int dir)
vq->dev = &zr->pci_dev->dev;
vq->type = dir;
vq->io_modes = VB2_DMABUF | VB2_MMAP | VB2_READ | VB2_WRITE;
vq->io_modes = VB2_DMABUF | VB2_MMAP;
vq->drv_priv = zr;
vq->buf_struct_size = sizeof(struct zr_buffer);
vq->ops = &zr_video_qops;

View file

@ -15,18 +15,19 @@
/* codec io API */
#include "videocodec.h"
/* it doesn't make sense to have more than 20 or so,
just to prevent some unwanted loops */
/*
* it doesn't make sense to have more than 20 or so,
* just to prevent some unwanted loops
*/
#define MAX_CODECS 20
/* amount of chips attached via this driver */
static int zr36016_codecs;
/* =========================================================================
Local hardware I/O functions:
read/write via codec layer (registers are located in the master device)
========================================================================= */
/*
* Local hardware I/O functions: read/write via codec layer
* (registers are located in the master device)
*/
/* read and write functions */
static u8 zr36016_read(struct zr36016 *ptr, u16 reg)
@ -58,9 +59,12 @@ static void zr36016_write(struct zr36016 *ptr, u16 reg, u8 value)
zrdev_err(zr, "%s: invalid I/O setup, nothing written!\n", ptr->name);
}
/* indirect read and write functions */
/* the 016 supports auto-addr-increment, but
* writing it all time cost not much and is safer... */
/*
* indirect read and write functions
*
* the 016 supports auto-addr-increment, but
* writing it all time cost not much and is safer...
*/
static u8 zr36016_readi(struct zr36016 *ptr, u16 reg)
{
u8 value = 0;
@ -68,8 +72,8 @@ static u8 zr36016_readi(struct zr36016 *ptr, u16 reg)
/* just in case something is wrong... */
if ((ptr->codec->master_data->writereg) && (ptr->codec->master_data->readreg)) {
ptr->codec->master_data->writereg(ptr->codec, ZR016_IADDR, reg & 0x0F); // ADDR
value = (ptr->codec->master_data->readreg(ptr->codec, ZR016_IDATA)) & 0xFF; // DATA
ptr->codec->master_data->writereg(ptr->codec, ZR016_IADDR, reg & 0x0F);
value = (ptr->codec->master_data->readreg(ptr->codec, ZR016_IDATA)) & 0xFF;
} else {
zrdev_err(zr, "%s: invalid I/O setup, nothing read (i)!\n", ptr->name);
}
@ -88,18 +92,14 @@ static void zr36016_writei(struct zr36016 *ptr, u16 reg, u8 value)
/* just in case something is wrong... */
if (ptr->codec->master_data->writereg) {
ptr->codec->master_data->writereg(ptr->codec, ZR016_IADDR, reg & 0x0F); // ADDR
ptr->codec->master_data->writereg(ptr->codec, ZR016_IDATA, value & 0x0FF); // DATA
ptr->codec->master_data->writereg(ptr->codec, ZR016_IADDR, reg & 0x0F);
ptr->codec->master_data->writereg(ptr->codec, ZR016_IDATA, value & 0x0FF);
} else {
zrdev_err(zr, "%s: invalid I/O setup, nothing written (i)!\n", ptr->name);
}
}
/* =========================================================================
Local helper function:
version read
========================================================================= */
/* Local helper function: version read */
/* version kept in datastructure */
static u8 zr36016_read_version(struct zr36016 *ptr)
@ -108,11 +108,10 @@ static u8 zr36016_read_version(struct zr36016 *ptr)
return ptr->version;
}
/* =========================================================================
Local helper function:
basic test of "connectivity", writes/reads to/from PAX-Lo register
========================================================================= */
/*
* Local helper function: basic test of "connectivity", writes/reads
* to/from PAX-Lo register
*/
static int zr36016_basic_test(struct zr36016 *ptr)
{
@ -150,36 +149,7 @@ static int zr36016_basic_test(struct zr36016 *ptr)
return 0; /* looks good! */
}
/* =========================================================================
Local helper function:
simple loop for pushing the init datasets - NO USE --
========================================================================= */
#if 0
static int zr36016_pushit(struct zr36016 *ptr,
u16 startreg,
u16 len,
const char *data)
{
struct zoran *zr = videocodec_to_zoran(ptr->codec);
int i = 0;
zrdev_dbg(zr, "%s: write data block to 0x%04x (len=%d)\n",
ptr->name, startreg, len);
while (i < len) {
zr36016_writei(ptr, startreg++, data[i++]);
}
return i;
}
#endif
/* =========================================================================
Basic datasets & init:
//TODO//
========================================================================= */
/* Basic datasets & init */
static void zr36016_init(struct zr36016 *ptr)
{
@ -213,14 +183,16 @@ static void zr36016_init(struct zr36016 *ptr)
zr36016_write(ptr, ZR016_GOSTOP, 1);
}
/* =========================================================================
CODEC API FUNCTIONS
/*
* CODEC API FUNCTIONS
*
* These functions are accessed by the master via the API structure
*/
this functions are accessed by the master via the API structure
========================================================================= */
/* set compression/expansion mode and launches codec -
this should be the last call from the master before starting processing */
/*
* set compression/expansion mode and launches codec -
* this should be the last call from the master before starting processing
*/
static int zr36016_set_mode(struct videocodec *codec, int mode)
{
struct zr36016 *ptr = (struct zr36016 *)codec->data;
@ -249,22 +221,28 @@ static int zr36016_set_video(struct videocodec *codec, const struct tvnorm *norm
cap->x, cap->y, cap->width, cap->height,
cap->decimation);
/* if () return -EINVAL;
/*
* if () return -EINVAL;
* trust the master driver that it knows what it does - so
* we allow invalid startx/y for now ... */
* we allow invalid startx/y for now ...
*/
ptr->width = cap->width;
ptr->height = cap->height;
/* (Ronald) This is ugly. zoran_device.c, line 387
/*
* (Ronald) This is ugly. zoran_device.c, line 387
* already mentions what happens if h_start is even
* (blue faces, etc., cr/cb inversed). There's probably
* some good reason why h_start is 0 instead of 1, so I'm
* leaving it to this for now, but really... This can be
* done a lot simpler */
* done a lot simpler
*/
ptr->xoff = (norm->h_start ? norm->h_start : 1) + cap->x;
/* Something to note here (I don't understand it), setting
/*
* Something to note here (I don't understand it), setting
* v_start too high will cause the codec to 'not work'. I
* really don't get it. values of 16 (v_start) already break
* it here. Just '0' seems to work. More testing needed! */
* it here. Just '0' seems to work. More testing needed!
*/
ptr->yoff = norm->v_start + cap->y;
/* (Ronald) dzjeeh, can't this thing do hor_decimation = 4? */
ptr->xdec = ((cap->decimation & 0xff) == 1) ? 0 : 1;
@ -319,11 +297,11 @@ static int zr36016_control(struct videocodec *codec, int type, int size, void *d
return size;
}
/* =========================================================================
Exit and unregister function:
Deinitializes Zoran's JPEG processor
========================================================================= */
/*
* Exit and unregister function:
*
* Deinitializes Zoran's JPEG processor
*/
static int zr36016_unset(struct videocodec *codec)
{
@ -344,14 +322,14 @@ static int zr36016_unset(struct videocodec *codec)
return -EFAULT;
}
/* =========================================================================
Setup and registry function:
Initializes Zoran's JPEG processor
Also sets pixel size, average code size, mode (compr./decompr.)
(the given size is determined by the processor with the video interface)
========================================================================= */
/*
* Setup and registry function:
*
* Initializes Zoran's JPEG processor
*
* Also sets pixel size, average code size, mode (compr./decompr.)
* (the given size is determined by the processor with the video interface)
*/
static int zr36016_setup(struct videocodec *codec)
{
@ -410,9 +388,7 @@ static const struct videocodec zr36016_codec = {
/* others are not used */
};
/* =========================================================================
HOOK IN DRIVER AS KERNEL MODULE
========================================================================= */
/* HOOK IN DRIVER AS KERNEL MODULE */
int zr36016_init_module(void)
{

View file

@ -22,18 +22,20 @@
/* codec io API */
#include "videocodec.h"
/* it doesn't make sense to have more than 20 or so,
just to prevent some unwanted loops */
/*
* it doesn't make sense to have more than 20 or so,
* just to prevent some unwanted loops
*/
#define MAX_CODECS 20
/* amount of chips attached via this driver */
static int zr36050_codecs;
/* =========================================================================
Local hardware I/O functions:
read/write via codec layer (registers are located in the master device)
========================================================================= */
/*
* Local hardware I/O functions:
*
* read/write via codec layer (registers are located in the master device)
*/
/* read and write functions */
static u8 zr36050_read(struct zr36050 *ptr, u16 reg)
@ -66,12 +68,6 @@ static void zr36050_write(struct zr36050 *ptr, u16 reg, u8 value)
ptr->name);
}
/* =========================================================================
Local helper function:
status read
========================================================================= */
/* status is kept in datastructure */
static u8 zr36050_read_status1(struct zr36050 *ptr)
{
@ -81,12 +77,6 @@ static u8 zr36050_read_status1(struct zr36050 *ptr)
return ptr->status1;
}
/* =========================================================================
Local helper function:
scale factor read
========================================================================= */
/* scale factor is kept in datastructure */
static u16 zr36050_read_scalefactor(struct zr36050 *ptr)
{
@ -98,11 +88,11 @@ static u16 zr36050_read_scalefactor(struct zr36050 *ptr)
return ptr->scalefact;
}
/* =========================================================================
Local helper function:
wait if codec is ready to proceed (end of processing) or time is over
========================================================================= */
/*
* Local helper function:
*
* wait if codec is ready to proceed (end of processing) or time is over
*/
static void zr36050_wait_end(struct zr36050 *ptr)
{
@ -120,11 +110,10 @@ static void zr36050_wait_end(struct zr36050 *ptr)
}
}
/* =========================================================================
Local helper function:
basic test of "connectivity", writes/reads to/from memory the SOF marker
========================================================================= */
/*
* Local helper function: basic test of "connectivity", writes/reads
* to/from memory the SOF marker
*/
static int zr36050_basic_test(struct zr36050 *ptr)
{
@ -160,11 +149,7 @@ static int zr36050_basic_test(struct zr36050 *ptr)
return 0; /* looks good! */
}
/* =========================================================================
Local helper function:
simple loop for pushing the init datasets
========================================================================= */
/* Local helper function: simple loop for pushing the init datasets */
static int zr36050_pushit(struct zr36050 *ptr, u16 startreg, u16 len, const char *data)
{
@ -179,16 +164,16 @@ static int zr36050_pushit(struct zr36050 *ptr, u16 startreg, u16 len, const char
return i;
}
/* =========================================================================
Basic datasets:
jpeg baseline setup data (you find it on lots places in internet, or just
extract it from any regular .jpg image...)
Could be variable, but until it's not needed it they are just fixed to save
memory. Otherwise expand zr36050 structure with arrays, push the values to
it and initialize from there, as e.g. the linux zr36057/60 driver does it.
========================================================================= */
/*
* Basic datasets:
*
* jpeg baseline setup data (you find it on lots places in internet, or just
* extract it from any regular .jpg image...)
*
* Could be variable, but until it's not needed it they are just fixed to save
* memory. Otherwise expand zr36050 structure with arrays, push the values to
* it and initialize from there, as e.g. the linux zr36057/60 driver does it.
*/
static const char zr36050_dqt[0x86] = {
0xff, 0xdb, //Marker: DQT
@ -281,18 +266,19 @@ static const char zr36050_ta[8] = { 0, 1, 1, 0, 0, 0, 0, 0 }; //table idx's AC
static const char zr36050_decimation_h[8] = { 2, 1, 1, 0, 0, 0, 0, 0 };
static const char zr36050_decimation_v[8] = { 1, 1, 1, 0, 0, 0, 0, 0 };
/* =========================================================================
Local helper functions:
calculation and setup of parameter-dependent JPEG baseline segments
(needed for compression only)
========================================================================= */
/*
* Local helper functions:
*
* calculation and setup of parameter-dependent JPEG baseline segments
* (needed for compression only)
*/
/* ------------------------------------------------------------------------- */
/* SOF (start of frame) segment depends on width, height and sampling ratio
of each color component */
/*
* SOF (start of frame) segment depends on width, height and sampling ratio
* of each color component
*/
static int zr36050_set_sof(struct zr36050 *ptr)
{
struct zoran *zr = videocodec_to_zoran(ptr->codec);
@ -313,7 +299,8 @@ static int zr36050_set_sof(struct zr36050 *ptr)
sof_data[9] = NO_OF_COMPONENTS;
for (i = 0; i < NO_OF_COMPONENTS; i++) {
sof_data[10 + (i * 3)] = i; // index identifier
sof_data[11 + (i * 3)] = (ptr->h_samp_ratio[i] << 4) | (ptr->v_samp_ratio[i]); // sampling ratios
sof_data[11 + (i * 3)] = (ptr->h_samp_ratio[i] << 4) |
(ptr->v_samp_ratio[i]); // sampling ratios
sof_data[12 + (i * 3)] = zr36050_tq[i]; // Q table selection
}
return zr36050_pushit(ptr, ZR050_SOF_IDX,
@ -322,8 +309,10 @@ static int zr36050_set_sof(struct zr36050 *ptr)
/* ------------------------------------------------------------------------- */
/* SOS (start of scan) segment depends on the used scan components
of each color component */
/*
* SOS (start of scan) segment depends on the used scan components
* of each color component
*/
static int zr36050_set_sos(struct zr36050 *ptr)
{
@ -368,14 +357,14 @@ static int zr36050_set_dri(struct zr36050 *ptr)
return zr36050_pushit(ptr, ZR050_DRI_IDX, 6, dri_data);
}
/* =========================================================================
Setup function:
Setup compression/decompression of Zoran's JPEG processor
( see also zoran 36050 manual )
... sorry for the spaghetti code ...
========================================================================= */
/*
* Setup function:
*
* Setup compression/decompression of Zoran's JPEG processor
* ( see also zoran 36050 manual )
*
* ... sorry for the spaghetti code ...
*/
static void zr36050_init(struct zr36050 *ptr)
{
int sum = 0;
@ -411,8 +400,10 @@ static void zr36050_init(struct zr36050 *ptr)
sum += zr36050_set_sos(ptr);
sum += zr36050_set_dri(ptr);
/* setup the fixed jpeg tables - maybe variable, though -
* (see table init section above) */
/*
* setup the fixed jpeg tables - maybe variable, though -
* (see table init section above)
*/
zrdev_dbg(zr, "%s: write DQT, DHT, APP\n", ptr->name);
sum += zr36050_pushit(ptr, ZR050_DQT_IDX,
sizeof(zr36050_dqt), zr36050_dqt);
@ -522,14 +513,16 @@ static void zr36050_init(struct zr36050 *ptr)
zr36050_read(ptr, 0);
}
/* =========================================================================
CODEC API FUNCTIONS
/*
* CODEC API FUNCTIONS
*
* this functions are accessed by the master via the API structure
*/
this functions are accessed by the master via the API structure
========================================================================= */
/* set compression/expansion mode and launches codec -
this should be the last call from the master before starting processing */
/*
* set compression/expansion mode and launches codec -
* this should be the last call from the master before starting processing
*/
static int zr36050_set_mode(struct videocodec *codec, int mode)
{
struct zr36050 *ptr = (struct zr36050 *)codec->data;
@ -558,9 +551,10 @@ static int zr36050_set_video(struct videocodec *codec, const struct tvnorm *norm
ptr->name, norm->h_start, norm->v_start,
cap->x, cap->y, cap->width, cap->height,
cap->decimation, cap->quality);
/* if () return -EINVAL;
/*
* trust the master driver that it knows what it does - so
* we allow invalid startx/y and norm for now ... */
* we allow invalid startx/y and norm for now ...
*/
ptr->width = cap->width / (cap->decimation & 0xff);
ptr->height = cap->height / ((cap->decimation >> 8) & 0xff);
@ -579,8 +573,10 @@ static int zr36050_set_video(struct videocodec *codec, const struct tvnorm *norm
ptr->real_code_vol = size >> 3; /* in bytes */
/* Set max_block_vol here (previously in zr36050_init, moved
* here for consistency with zr36060 code */
/*
* Set max_block_vol here (previously in zr36050_init, moved
* here for consistency with zr36060 code
*/
zr36050_write(ptr, ZR050_MBCV, ptr->max_block_vol);
return 0;
@ -637,8 +633,6 @@ static int zr36050_control(struct videocodec *codec, int type, int size, void *d
if (size != sizeof(int))
return -EFAULT;
ptr->total_code_vol = *ival;
/* (Kieran Morrissey)
* code copied from zr36060.c to ensure proper bitrate */
ptr->real_code_vol = (ptr->total_code_vol * 6) >> 3;
break;
@ -701,11 +695,7 @@ static int zr36050_control(struct videocodec *codec, int type, int size, void *d
return size;
}
/* =========================================================================
Exit and unregister function:
Deinitializes Zoran's JPEG processor
========================================================================= */
/* Exit and unregister function: Deinitializes Zoran's JPEG processor */
static int zr36050_unset(struct videocodec *codec)
{
@ -727,14 +717,14 @@ static int zr36050_unset(struct videocodec *codec)
return -EFAULT;
}
/* =========================================================================
Setup and registry function:
Initializes Zoran's JPEG processor
Also sets pixel size, average code size, mode (compr./decompr.)
(the given size is determined by the processor with the video interface)
========================================================================= */
/*
* Setup and registry function:
*
* Initializes Zoran's JPEG processor
*
* Also sets pixel size, average code size, mode (compr./decompr.)
* (the given size is determined by the processor with the video interface)
*/
static int zr36050_setup(struct videocodec *codec)
{
@ -771,8 +761,8 @@ static int zr36050_setup(struct videocodec *codec)
memcpy(ptr->h_samp_ratio, zr36050_decimation_h, 8);
memcpy(ptr->v_samp_ratio, zr36050_decimation_v, 8);
ptr->bitrate_ctrl = 0; /* 0 or 1 - fixed file size flag
* (what is the difference?) */
/* 0 or 1 - fixed file size flag (what is the difference?) */
ptr->bitrate_ctrl = 0;
ptr->mode = CODEC_DO_COMPRESSION;
ptr->width = 384;
ptr->height = 288;
@ -809,9 +799,7 @@ static const struct videocodec zr36050_codec = {
// others are not used
};
/* =========================================================================
HOOK IN DRIVER AS KERNEL MODULE
========================================================================= */
/* HOOK IN DRIVER AS KERNEL MODULE */
int zr36050_init_module(void)
{

View file

@ -11,117 +11,117 @@
/* Zoran ZR36057 registers */
#define ZR36057_VFEHCR 0x000 /* Video Front End, Horizontal Configuration Register */
#define ZR36057_VFEHCR_HS_POL BIT(30)
#define ZR36057_VFEHCR_H_START 10
#define ZR36057_VFEHCR_HS_POL BIT(30)
#define ZR36057_VFEHCR_H_START 10
#define ZR36057_VFEHCR_H_END 0
#define ZR36057_VFEHCR_HMASK 0x3ff
#define ZR36057_VFEVCR 0x004 /* Video Front End, Vertical Configuration Register */
#define ZR36057_VFEVCR_VS_POL BIT(30)
#define ZR36057_VFEVCR_V_START 10
#define ZR36057_VFEVCR_VS_POL BIT(30)
#define ZR36057_VFEVCR_V_START 10
#define ZR36057_VFEVCR_V_END 0
#define ZR36057_VFEVCR_VMASK 0x3ff
#define ZR36057_VFESPFR 0x008 /* Video Front End, Scaler and Pixel Format Register */
#define ZR36057_VFESPFR_EXT_FL BIT(26)
#define ZR36057_VFESPFR_TOP_FIELD BIT(25)
#define ZR36057_VFESPFR_VCLK_POL BIT(24)
#define ZR36057_VFESPFR_H_FILTER 21
#define ZR36057_VFESPFR_HOR_DCM 14
#define ZR36057_VFESPFR_VER_DCM 8
#define ZR36057_VFESPFR_DISP_MODE 6
#define ZR36057_VFESPFR_EXT_FL BIT(26)
#define ZR36057_VFESPFR_TOP_FIELD BIT(25)
#define ZR36057_VFESPFR_VCLK_POL BIT(24)
#define ZR36057_VFESPFR_H_FILTER 21
#define ZR36057_VFESPFR_HOR_DCM 14
#define ZR36057_VFESPFR_VER_DCM 8
#define ZR36057_VFESPFR_DISP_MODE 6
#define ZR36057_VFESPFR_YUV422 (0 << 3)
#define ZR36057_VFESPFR_RGB888 (1 << 3)
#define ZR36057_VFESPFR_RGB565 (2 << 3)
#define ZR36057_VFESPFR_RGB555 (3 << 3)
#define ZR36057_VFESPFR_ERR_DIF (1 << 2)
#define ZR36057_VFESPFR_PACK24 (1 << 1)
#define ZR36057_VFESPFR_LITTLE_ENDIAN (1 << 0)
#define ZR36057_VFESPFR_ERR_DIF BIT(2)
#define ZR36057_VFESPFR_PACK24 BIT(1)
#define ZR36057_VFESPFR_LITTLE_ENDIAN BIT(0)
#define ZR36057_VDTR 0x00c /* Video Display "Top" Register */
#define ZR36057_VDBR 0x010 /* Video Display "Bottom" Register */
#define ZR36057_VSSFGR 0x014 /* Video Stride, Status, and Frame Grab Register */
#define ZR36057_VSSFGR_DISP_STRIDE 16
#define ZR36057_VSSFGR_VID_OVF BIT(8)
#define ZR36057_VSSFGR_SNAP_SHOT BIT(1)
#define ZR36057_VSSFGR_FRAME_GRAB BIT(0)
#define ZR36057_VSSFGR_DISP_STRIDE 16
#define ZR36057_VSSFGR_VID_OVF BIT(8)
#define ZR36057_VSSFGR_SNAP_SHOT BIT(1)
#define ZR36057_VSSFGR_FRAME_GRAB BIT(0)
#define ZR36057_VDCR 0x018 /* Video Display Configuration Register */
#define ZR36057_VDCR_VID_EN BIT(31)
#define ZR36057_VDCR_MIN_PIX 24
#define ZR36057_VDCR_TRITON BIT(24)
#define ZR36057_VDCR_VID_WIN_HT 12
#define ZR36057_VDCR_VID_WIN_WID 0
#define ZR36057_VDCR_VID_EN BIT(31)
#define ZR36057_VDCR_MIN_PIX 24
#define ZR36057_VDCR_TRITON BIT(24)
#define ZR36057_VDCR_VID_WIN_HT 12
#define ZR36057_VDCR_VID_WIN_WID 0
#define ZR36057_MMTR 0x01c /* Masking Map "Top" Register */
#define ZR36057_MMBR 0x020 /* Masking Map "Bottom" Register */
#define ZR36057_OCR 0x024 /* Overlay Control Register */
#define ZR36057_OCR_OVL_ENABLE BIT(15)
#define ZR36057_OCR_MASK_STRIDE 0
#define ZR36057_OCR_OVL_ENABLE BIT(15)
#define ZR36057_OCR_MASK_STRIDE 0
#define ZR36057_SPGPPCR 0x028 /* System, PCI, and General Purpose Pins Control Register */
#define ZR36057_SPGPPCR_SOFT_RESET BIT(24)
#define ZR36057_SPGPPCR_SOFT_RESET BIT(24)
#define ZR36057_GPPGCR1 0x02c /* General Purpose Pins and GuestBus Control Register (1) */
#define ZR36057_MCSAR 0x030 /* MPEG Code Source Address Register */
#define ZR36057_MCTCR 0x034 /* MPEG Code Transfer Control Register */
#define ZR36057_MCTCR_COD_TIME BIT(30)
#define ZR36057_MCTCR_C_EMPTY BIT(29)
#define ZR36057_MCTCR_C_FLUSH BIT(28)
#define ZR36057_MCTCR_COD_TIME BIT(30)
#define ZR36057_MCTCR_C_EMPTY BIT(29)
#define ZR36057_MCTCR_C_FLUSH BIT(28)
#define ZR36057_MCTCR_COD_GUEST_ID 20
#define ZR36057_MCTCR_COD_GUEST_REG 16
#define ZR36057_MCMPR 0x038 /* MPEG Code Memory Pointer Register */
#define ZR36057_ISR 0x03c /* Interrupt Status Register */
#define ZR36057_ISR_GIRQ1 BIT(30)
#define ZR36057_ISR_GIRQ0 BIT(29)
#define ZR36057_ISR_COD_REP_IRQ BIT(28)
#define ZR36057_ISR_JPEG_REP_IRQ BIT(27)
#define ZR36057_ISR_GIRQ1 BIT(30)
#define ZR36057_ISR_GIRQ0 BIT(29)
#define ZR36057_ISR_COD_REP_IRQ BIT(28)
#define ZR36057_ISR_JPEG_REP_IRQ BIT(27)
#define ZR36057_ICR 0x040 /* Interrupt Control Register */
#define ZR36057_ICR_GIRQ1 BIT(30)
#define ZR36057_ICR_GIRQ0 BIT(29)
#define ZR36057_ICR_COD_REP_IRQ BIT(28)
#define ZR36057_ICR_JPEG_REP_IRQ BIT(27)
#define ZR36057_ICR_INT_PIN_EN BIT(24)
#define ZR36057_ICR_GIRQ1 BIT(30)
#define ZR36057_ICR_GIRQ0 BIT(29)
#define ZR36057_ICR_COD_REP_IRQ BIT(28)
#define ZR36057_ICR_JPEG_REP_IRQ BIT(27)
#define ZR36057_ICR_INT_PIN_EN BIT(24)
#define ZR36057_I2CBR 0x044 /* I2C Bus Register */
#define ZR36057_I2CBR_SDA BIT(1)
#define ZR36057_I2CBR_SCL BIT(0)
#define ZR36057_I2CBR_SDA BIT(1)
#define ZR36057_I2CBR_SCL BIT(0)
#define ZR36057_JMC 0x100 /* JPEG Mode and Control */
#define ZR36057_JMC_JPG BIT(31)
#define ZR36057_JMC_JPG_EXP_MODE (0 << 29)
#define ZR36057_JMC_JPG_CMP_MODE BIT(29)
#define ZR36057_JMC_MJPG_EXP_MODE (2 << 29)
#define ZR36057_JMC_MJPG_CMP_MODE (3 << 29)
#define ZR36057_JMC_RTBUSY_FB BIT(6)
#define ZR36057_JMC_GO_EN BIT(5)
#define ZR36057_JMC_SYNC_MSTR BIT(4)
#define ZR36057_JMC_FLD_PER_BUFF BIT(3)
#define ZR36057_JMC_VFIFO_FB BIT(2)
#define ZR36057_JMC_CFIFO_FB BIT(1)
#define ZR36057_JMC_STLL_LIT_ENDIAN BIT(0)
#define ZR36057_JMC_JPG BIT(31)
#define ZR36057_JMC_JPG_EXP_MODE (0 << 29)
#define ZR36057_JMC_JPG_CMP_MODE BIT(29)
#define ZR36057_JMC_MJPG_EXP_MODE (2 << 29)
#define ZR36057_JMC_MJPG_CMP_MODE (3 << 29)
#define ZR36057_JMC_RTBUSY_FB BIT(6)
#define ZR36057_JMC_GO_EN BIT(5)
#define ZR36057_JMC_SYNC_MSTR BIT(4)
#define ZR36057_JMC_FLD_PER_BUFF BIT(3)
#define ZR36057_JMC_VFIFO_FB BIT(2)
#define ZR36057_JMC_CFIFO_FB BIT(1)
#define ZR36057_JMC_STLL_LIT_ENDIAN BIT(0)
#define ZR36057_JPC 0x104 /* JPEG Process Control */
#define ZR36057_JPC_P_RESET BIT(7)
#define ZR36057_JPC_COD_TRNS_EN BIT(5)
#define ZR36057_JPC_ACTIVE BIT(0)
#define ZR36057_JPC_P_RESET BIT(7)
#define ZR36057_JPC_COD_TRNS_EN BIT(5)
#define ZR36057_JPC_ACTIVE BIT(0)
#define ZR36057_VSP 0x108 /* Vertical Sync Parameters */
#define ZR36057_VSP_VSYNC_SIZE 16
#define ZR36057_VSP_FRM_TOT 0
#define ZR36057_VSP_VSYNC_SIZE 16
#define ZR36057_VSP_FRM_TOT 0
#define ZR36057_HSP 0x10c /* Horizontal Sync Parameters */
#define ZR36057_HSP_HSYNC_START 16
#define ZR36057_HSP_LINE_TOT 0
#define ZR36057_HSP_HSYNC_START 16
#define ZR36057_HSP_LINE_TOT 0
#define ZR36057_FHAP 0x110 /* Field Horizontal Active Portion */
#define ZR36057_FHAP_NAX 16
@ -132,22 +132,22 @@
#define ZR36057_FVAP_PAY 0
#define ZR36057_FPP 0x118 /* Field Process Parameters */
#define ZR36057_FPP_ODD_EVEN BIT(0)
#define ZR36057_FPP_ODD_EVEN BIT(0)
#define ZR36057_JCBA 0x11c /* JPEG Code Base Address */
#define ZR36057_JCFT 0x120 /* JPEG Code FIFO Threshold */
#define ZR36057_JCGI 0x124 /* JPEG Codec Guest ID */
#define ZR36057_JCGI_JPE_GUEST_ID 4
#define ZR36057_JCGI_JPE_GUEST_REG 0
#define ZR36057_JCGI_JPE_GUEST_ID 4
#define ZR36057_JCGI_JPE_GUEST_REG 0
#define ZR36057_GCR2 0x12c /* GuestBus Control Register (2) */
#define ZR36057_POR 0x200 /* Post Office Register */
#define ZR36057_POR_PO_PEN BIT(25)
#define ZR36057_POR_PO_TIME BIT(24)
#define ZR36057_POR_PO_DIR BIT(23)
#define ZR36057_POR_PO_PEN BIT(25)
#define ZR36057_POR_PO_TIME BIT(24)
#define ZR36057_POR_PO_DIR BIT(23)
#define ZR36057_STR 0x300 /* "Still" Transfer Register */

View file

@ -243,7 +243,10 @@ static const char zr36060_ta[8] = { 0, 1, 1, 0, 0, 0, 0, 0 }; //table idx's AC
static const char zr36060_decimation_h[8] = { 2, 1, 1, 0, 0, 0, 0, 0 };
static const char zr36060_decimation_v[8] = { 1, 1, 1, 0, 0, 0, 0, 0 };
/* SOF (start of frame) segment depends on width, height and sampling ratio of each color component */
/*
* SOF (start of frame) segment depends on width, height and sampling ratio
* of each color component
*/
static int zr36060_set_sof(struct zr36060 *ptr)
{
struct zoran *zr = videocodec_to_zoran(ptr->codec);
@ -555,8 +558,6 @@ static int zr36060_set_video(struct videocodec *codec, const struct tvnorm *norm
reg = 6 - 1; /* VsyncSize */
zr36060_write(ptr, ZR060_SGR_VSYNC, reg);
//reg = 30 - 1; /* HsyncSize */
///*CP*/ reg = (zr->params.norm == 1 ? 57 : 68);
reg = 68;
zr36060_write(ptr, ZR060_SGR_HSYNC, reg);

View file

@ -124,78 +124,78 @@ struct zr36060 {
/* ZR36060 LOAD register bits */
#define ZR060_LOAD_LOAD BIT(7)
#define ZR060_LOAD_SYNC_RST BIT(0)
#define ZR060_LOAD_LOAD BIT(7)
#define ZR060_LOAD_SYNC_RST BIT(0)
/* ZR36060 Code FIFO Status register bits */
#define ZR060_CFSR_BUSY BIT(7)
#define ZR060_CFSR_C_BUSY BIT(2)
#define ZR060_CFSR_BUSY BIT(7)
#define ZR060_CFSR_C_BUSY BIT(2)
#define ZR060_CFSR_CFIFO (3 << 0)
/* ZR36060 Code Interface register */
#define ZR060_CIR_CODE16 BIT(7)
#define ZR060_CIR_ENDIAN BIT(6)
#define ZR060_CIR_CFIS BIT(2)
#define ZR060_CIR_CODE_MSTR BIT(0)
#define ZR060_CIR_CODE16 BIT(7)
#define ZR060_CIR_ENDIAN BIT(6)
#define ZR060_CIR_CFIS BIT(2)
#define ZR060_CIR_CODE_MSTR BIT(0)
/* ZR36060 Codec Mode register */
#define ZR060_CMR_COMP BIT(7)
#define ZR060_CMR_ATP BIT(6)
#define ZR060_CMR_PASS2 BIT(5)
#define ZR060_CMR_TLM BIT(4)
#define ZR060_CMR_BRB BIT(2)
#define ZR060_CMR_FSF BIT(1)
#define ZR060_CMR_COMP BIT(7)
#define ZR060_CMR_ATP BIT(6)
#define ZR060_CMR_PASS2 BIT(5)
#define ZR060_CMR_TLM BIT(4)
#define ZR060_CMR_BRB BIT(2)
#define ZR060_CMR_FSF BIT(1)
/* ZR36060 Markers Enable register */
#define ZR060_MER_APP BIT(7)
#define ZR060_MER_COM BIT(6)
#define ZR060_MER_DRI BIT(5)
#define ZR060_MER_DQT BIT(4)
#define ZR060_MER_DHT BIT(3)
#define ZR060_MER_APP BIT(7)
#define ZR060_MER_COM BIT(6)
#define ZR060_MER_DRI BIT(5)
#define ZR060_MER_DQT BIT(4)
#define ZR060_MER_DHT BIT(3)
/* ZR36060 Interrupt Mask register */
#define ZR060_IMR_EOAV BIT(3)
#define ZR060_IMR_EOI BIT(2)
#define ZR060_IMR_END BIT(1)
#define ZR060_IMR_DATA_ERR BIT(0)
#define ZR060_IMR_EOAV BIT(3)
#define ZR060_IMR_EOI BIT(2)
#define ZR060_IMR_END BIT(1)
#define ZR060_IMR_DATA_ERR BIT(0)
/* ZR36060 Interrupt Status register */
#define ZR060_ISR_PRO_CNT (3 << 6)
#define ZR060_ISR_EOAV BIT(3)
#define ZR060_ISR_EOI BIT(2)
#define ZR060_ISR_END BIT(1)
#define ZR060_ISR_DATA_ERR BIT(0)
#define ZR060_ISR_EOAV BIT(3)
#define ZR060_ISR_EOI BIT(2)
#define ZR060_ISR_END BIT(1)
#define ZR060_ISR_DATA_ERR BIT(0)
/* ZR36060 Video Control register */
#define ZR060_VCR_VIDEO8 BIT(7)
#define ZR060_VCR_RANGE BIT(6)
#define ZR060_VCR_FI_DET BIT(3)
#define ZR060_VCR_FI_VEDGE BIT(2)
#define ZR060_VCR_FI_EXT BIT(1)
#define ZR060_VCR_SYNC_MSTR BIT(0)
#define ZR060_VCR_VIDEO8 BIT(7)
#define ZR060_VCR_RANGE BIT(6)
#define ZR060_VCR_FI_DET BIT(3)
#define ZR060_VCR_FI_VEDGE BIT(2)
#define ZR060_VCR_FI_EXT BIT(1)
#define ZR060_VCR_SYNC_MSTR BIT(0)
/* ZR36060 Video Polarity register */
#define ZR060_VPR_VCLK_POL BIT(7)
#define ZR060_VPR_P_VAL_POL BIT(6)
#define ZR060_VPR_POE_POL BIT(5)
#define ZR060_VPR_S_IMG_POL BIT(4)
#define ZR060_VPR_BL_POL BIT(3)
#define ZR060_VPR_FI_POL BIT(2)
#define ZR060_VPR_HS_POL BIT(1)
#define ZR060_VPR_VS_POL BIT(0)
#define ZR060_VPR_VCLK_POL BIT(7)
#define ZR060_VPR_P_VAL_POL BIT(6)
#define ZR060_VPR_POE_POL BIT(5)
#define ZR060_VPR_S_IMG_POL BIT(4)
#define ZR060_VPR_BL_POL BIT(3)
#define ZR060_VPR_FI_POL BIT(2)
#define ZR060_VPR_HS_POL BIT(1)
#define ZR060_VPR_VS_POL BIT(0)
/* ZR36060 Scaling register */
#define ZR060_SR_V_SCALE BIT(2)
#define ZR060_SR_H_SCALE2 BIT(0)
#define ZR060_SR_V_SCALE BIT(2)
#define ZR060_SR_H_SCALE2 BIT(0)
#define ZR060_SR_H_SCALE4 (2 << 0)
int zr36060_init_module(void);

View file

@ -81,6 +81,7 @@ source "drivers/media/platform/samsung/Kconfig"
source "drivers/media/platform/st/Kconfig"
source "drivers/media/platform/sunxi/Kconfig"
source "drivers/media/platform/ti/Kconfig"
source "drivers/media/platform/verisilicon/Kconfig"
source "drivers/media/platform/via/Kconfig"
source "drivers/media/platform/xilinx/Kconfig"

View file

@ -24,6 +24,7 @@ obj-y += samsung/
obj-y += st/
obj-y += sunxi/
obj-y += ti/
obj-y += verisilicon/
obj-y += via/
obj-y += xilinx/

View file

@ -1030,7 +1030,6 @@ static int ge2d_remove(struct platform_device *pdev)
video_unregister_device(ge2d->vfd);
v4l2_m2m_release(ge2d->m2m_dev);
video_device_release(ge2d->vfd);
v4l2_device_unregister(&ge2d->v4l2_dev);
clk_disable_unprepare(ge2d->clk);

View file

@ -808,14 +808,6 @@ static void vdec_init_fmt(struct vpu_inst *inst)
inst->cap_format.field = V4L2_FIELD_NONE;
else
inst->cap_format.field = V4L2_FIELD_SEQ_TB;
if (vdec->codec_info.color_primaries == V4L2_COLORSPACE_DEFAULT)
vdec->codec_info.color_primaries = V4L2_COLORSPACE_REC709;
if (vdec->codec_info.transfer_chars == V4L2_XFER_FUNC_DEFAULT)
vdec->codec_info.transfer_chars = V4L2_XFER_FUNC_709;
if (vdec->codec_info.matrix_coeffs == V4L2_YCBCR_ENC_DEFAULT)
vdec->codec_info.matrix_coeffs = V4L2_YCBCR_ENC_709;
if (vdec->codec_info.full_range == V4L2_QUANTIZATION_DEFAULT)
vdec->codec_info.full_range = V4L2_QUANTIZATION_LIM_RANGE;
}
static void vdec_init_crop(struct vpu_inst *inst)
@ -1555,6 +1547,14 @@ static int vdec_get_debug_info(struct vpu_inst *inst, char *str, u32 size, u32 i
vdec->codec_info.frame_rate.numerator,
vdec->codec_info.frame_rate.denominator);
break;
case 9:
num = scnprintf(str, size, "colorspace: %d, %d, %d, %d (%d)\n",
vdec->codec_info.color_primaries,
vdec->codec_info.transfer_chars,
vdec->codec_info.matrix_coeffs,
vdec->codec_info.full_range,
vdec->codec_info.vui_present);
break;
default:
break;
}

View file

@ -644,7 +644,7 @@ static int venc_ctrl_init(struct vpu_inst *inst)
BITRATE_DEFAULT_PEAK);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_GOP_SIZE, 0, (1 << 16) - 1, 1, 30);
V4L2_CID_MPEG_VIDEO_GOP_SIZE, 1, 8000, 1, 30);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_B_FRAMES, 0, 4, 1, 0);

View file

@ -119,7 +119,6 @@ struct vpu_mbox {
enum vpu_core_state {
VPU_CORE_DEINIT = 0,
VPU_CORE_ACTIVE,
VPU_CORE_SNAPSHOT,
VPU_CORE_HANG
};

View file

@ -89,7 +89,7 @@ static int vpu_core_boot_done(struct vpu_core *core)
core->supported_instance_count = min(core->supported_instance_count, count);
}
core->fw_version = fw_version;
core->state = VPU_CORE_ACTIVE;
vpu_core_set_state(core, VPU_CORE_ACTIVE);
return 0;
}
@ -172,10 +172,26 @@ int vpu_alloc_dma(struct vpu_core *core, struct vpu_buffer *buf)
return __vpu_alloc_dma(core->dev, buf);
}
static void vpu_core_check_hang(struct vpu_core *core)
void vpu_core_set_state(struct vpu_core *core, enum vpu_core_state state)
{
if (core->hang_mask)
core->state = VPU_CORE_HANG;
if (state != core->state)
vpu_trace(core->dev, "vpu core state change from %d to %d\n", core->state, state);
core->state = state;
if (core->state == VPU_CORE_DEINIT)
core->hang_mask = 0;
}
static void vpu_core_update_state(struct vpu_core *core)
{
if (!vpu_iface_get_power_state(core)) {
if (core->request_count)
vpu_core_set_state(core, VPU_CORE_HANG);
else
vpu_core_set_state(core, VPU_CORE_DEINIT);
} else if (core->state == VPU_CORE_ACTIVE && core->hang_mask) {
vpu_core_set_state(core, VPU_CORE_HANG);
}
}
static struct vpu_core *vpu_core_find_proper_by_type(struct vpu_dev *vpu, u32 type)
@ -188,11 +204,13 @@ static struct vpu_core *vpu_core_find_proper_by_type(struct vpu_dev *vpu, u32 ty
dev_dbg(c->dev, "instance_mask = 0x%lx, state = %d\n", c->instance_mask, c->state);
if (c->type != type)
continue;
mutex_lock(&c->lock);
vpu_core_update_state(c);
mutex_unlock(&c->lock);
if (c->state == VPU_CORE_DEINIT) {
core = c;
break;
}
vpu_core_check_hang(c);
if (c->state != VPU_CORE_ACTIVE)
continue;
if (c->request_count < request_count) {
@ -409,6 +427,12 @@ int vpu_inst_register(struct vpu_inst *inst)
}
mutex_lock(&core->lock);
if (core->state != VPU_CORE_ACTIVE) {
dev_err(core->dev, "vpu core is not active, state = %d\n", core->state);
ret = -EINVAL;
goto exit;
}
if (inst->id >= 0 && inst->id < core->supported_instance_count)
goto exit;
@ -450,7 +474,7 @@ int vpu_inst_unregister(struct vpu_inst *inst)
vpu_core_release_instance(core, inst->id);
inst->id = VPU_INST_NULL_ID;
}
vpu_core_check_hang(core);
vpu_core_update_state(core);
if (core->state == VPU_CORE_HANG && !core->instance_mask) {
int err;
@ -459,7 +483,7 @@ int vpu_inst_unregister(struct vpu_inst *inst)
err = vpu_core_sw_reset(core);
mutex_lock(&core->lock);
if (!err) {
core->state = VPU_CORE_ACTIVE;
vpu_core_set_state(core, VPU_CORE_ACTIVE);
core->hang_mask = 0;
}
}
@ -609,7 +633,7 @@ static int vpu_core_probe(struct platform_device *pdev)
mutex_init(&core->cmd_lock);
init_completion(&core->cmp);
init_waitqueue_head(&core->ack_wq);
core->state = VPU_CORE_DEINIT;
vpu_core_set_state(core, VPU_CORE_DEINIT);
core->res = of_device_get_match_data(dev);
if (!core->res)
@ -758,33 +782,18 @@ static int __maybe_unused vpu_core_resume(struct device *dev)
mutex_lock(&core->lock);
pm_runtime_resume_and_get(dev);
vpu_core_get_vpu(core);
if (core->state != VPU_CORE_SNAPSHOT)
goto exit;
if (!vpu_iface_get_power_state(core)) {
if (!list_empty(&core->instances)) {
if (core->request_count) {
if (!vpu_iface_get_power_state(core))
ret = vpu_core_boot(core, false);
if (ret) {
dev_err(core->dev, "%s boot fail\n", __func__);
core->state = VPU_CORE_DEINIT;
goto exit;
}
} else {
core->state = VPU_CORE_DEINIT;
}
} else {
if (!list_empty(&core->instances)) {
else
ret = vpu_core_sw_reset(core);
if (ret) {
dev_err(core->dev, "%s sw_reset fail\n", __func__);
core->state = VPU_CORE_HANG;
goto exit;
}
if (ret) {
dev_err(core->dev, "resume fail\n");
vpu_core_set_state(core, VPU_CORE_HANG);
}
core->state = VPU_CORE_ACTIVE;
}
exit:
vpu_core_update_state(core);
pm_runtime_put_sync(dev);
mutex_unlock(&core->lock);
@ -798,18 +807,11 @@ static int __maybe_unused vpu_core_suspend(struct device *dev)
int ret = 0;
mutex_lock(&core->lock);
if (core->state == VPU_CORE_ACTIVE) {
if (!list_empty(&core->instances)) {
ret = vpu_core_snapshot(core);
if (ret) {
mutex_unlock(&core->lock);
return ret;
}
}
core->state = VPU_CORE_SNAPSHOT;
}
if (core->request_count)
ret = vpu_core_snapshot(core);
mutex_unlock(&core->lock);
if (ret)
return ret;
vpu_core_cancel_work(core);

View file

@ -11,5 +11,6 @@ u32 csr_readl(struct vpu_core *core, u32 reg);
int vpu_alloc_dma(struct vpu_core *core, struct vpu_buffer *buf);
void vpu_free_dma(struct vpu_buffer *buf);
struct vpu_inst *vpu_core_find_instance(struct vpu_core *core, u32 index);
void vpu_core_set_state(struct vpu_core *core, enum vpu_core_state state);
#endif

View file

@ -15,6 +15,7 @@
#include <linux/debugfs.h>
#include "vpu.h"
#include "vpu_defs.h"
#include "vpu_core.h"
#include "vpu_helpers.h"
#include "vpu_cmds.h"
#include "vpu_rpc.h"
@ -233,6 +234,10 @@ static int vpu_dbg_core(struct seq_file *s, void *data)
if (seq_write(s, str, num))
return 0;
num = scnprintf(str, sizeof(str), "power %s\n",
vpu_iface_get_power_state(core) ? "on" : "off");
if (seq_write(s, str, num))
return 0;
num = scnprintf(str, sizeof(str), "state = %d\n", core->state);
if (seq_write(s, str, num))
return 0;
@ -346,10 +351,10 @@ static ssize_t vpu_dbg_core_write(struct file *file,
pm_runtime_resume_and_get(core->dev);
mutex_lock(&core->lock);
if (core->state != VPU_CORE_DEINIT && !core->instance_mask) {
if (vpu_iface_get_power_state(core) && !core->request_count) {
dev_info(core->dev, "reset\n");
if (!vpu_core_sw_reset(core)) {
core->state = VPU_CORE_ACTIVE;
vpu_core_set_state(core, VPU_CORE_ACTIVE);
core->hang_mask = 0;
}
}

View file

@ -1293,7 +1293,7 @@ static int vpu_malone_insert_scode_vc1_g_pic(struct malone_scode_t *scode)
vbuf = to_vb2_v4l2_buffer(scode->vb);
data = vb2_plane_vaddr(scode->vb, 0);
if (vbuf->sequence == 0 || vpu_vb_is_codecconfig(vbuf))
if (scode->inst->total_input_count == 0 || vpu_vb_is_codecconfig(vbuf))
return 0;
if (MALONE_VC1_CONTAIN_NAL(*data))
return 0;

View file

@ -854,7 +854,7 @@ static int pxa_init_dma_channel(struct pxa_camera_dev *pcdev,
return -ENOMEM;
}
static void pxa_videobuf_set_actdma(struct pxa_camera_dev *pcdev,
static void pxa_video_buf_set_actdma(struct pxa_camera_dev *pcdev,
struct pxa_buffer *buf)
{
buf->active_dma = DMA_Y;
@ -973,7 +973,7 @@ static void pxa_camera_wakeup(struct pxa_camera_dev *pcdev,
* stopped. This means the tailed buffer would never be transferred by DMA.
* This function restarts the capture for this corner case, where :
* - DADR() == DADDR_STOP
* - a videobuffer is queued on the pcdev->capture list
* - a video buffer is queued on the pcdev->capture list
*
* Please check the "DMA hot chaining timeslice issue" in
* Documentation/driver-api/media/drivers/pxa_camera.rst
@ -1163,7 +1163,7 @@ static void pxa_camera_eof(struct tasklet_struct *t)
pcdev->active = list_first_entry(&pcdev->capture,
struct pxa_buffer, queue);
buf = pcdev->active;
pxa_videobuf_set_actdma(pcdev, buf);
pxa_video_buf_set_actdma(pcdev, buf);
pxa_dma_start_channels(pcdev);
}
@ -1416,7 +1416,7 @@ static int pxac_vb2_prepare(struct vb2_buffer *vb)
* the actual buffer is yours
*/
buf->inwork = 0;
pxa_videobuf_set_actdma(pcdev, buf);
pxa_video_buf_set_actdma(pcdev, buf);
return ret;
}

View file

@ -32,7 +32,7 @@
#if !defined(MCAM_MODE_VMALLOC) && !defined(MCAM_MODE_DMA_CONTIG) && \
!defined(MCAM_MODE_DMA_SG)
#error One of the videobuf buffer modes must be selected in the config
#error One of the vb2 buffer modes must be selected in the config
#endif

View file

@ -6,3 +6,4 @@ source "drivers/media/platform/mediatek/jpeg/Kconfig"
source "drivers/media/platform/mediatek/mdp/Kconfig"
source "drivers/media/platform/mediatek/vcodec/Kconfig"
source "drivers/media/platform/mediatek/vpu/Kconfig"
source "drivers/media/platform/mediatek/mdp3/Kconfig"

View file

@ -3,3 +3,4 @@ obj-y += jpeg/
obj-y += mdp/
obj-y += vcodec/
obj-y += vpu/
obj-y += mdp3/

View file

@ -1414,7 +1414,6 @@ static int mtk_jpeg_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
video_unregister_device(jpeg->vdev);
video_device_release(jpeg->vdev);
v4l2_m2m_release(jpeg->m2m_dev);
v4l2_device_unregister(&jpeg->v4l2_dev);

View file

@ -0,0 +1,21 @@
# SPDX-License-Identifier: GPL-2.0-only
config VIDEO_MEDIATEK_MDP3
tristate "MediaTek MDP v3 driver"
depends on MTK_IOMMU || COMPILE_TEST
depends on VIDEO_DEV
depends on ARCH_MEDIATEK || COMPILE_TEST
depends on HAS_DMA
depends on REMOTEPROC
select VIDEOBUF2_DMA_CONTIG
select V4L2_MEM2MEM_DEV
select MTK_MMSYS
select VIDEO_MEDIATEK_VPU
select MTK_CMDQ
select MTK_SCP
default n
help
It is a v4l2 driver and present in MediaTek MT8183 SoC.
The driver supports scaling and color space conversion.
To compile this driver as a module, choose M here: the
module will be called mtk-mdp3.

View file

@ -0,0 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
mtk-mdp3-y += mtk-mdp3-core.o mtk-mdp3-vpu.o mtk-mdp3-regs.o
mtk-mdp3-y += mtk-mdp3-m2m.o
mtk-mdp3-y += mtk-mdp3-comp.o mtk-mdp3-cmdq.o
obj-$(CONFIG_VIDEO_MEDIATEK_MDP3) += mtk-mdp3.o

View file

@ -0,0 +1,19 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2022 MediaTek Inc.
* Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
*/
#ifndef __MDP_REG_CCORR_H__
#define __MDP_REG_CCORR_H__
#define MDP_CCORR_EN 0x000
#define MDP_CCORR_CFG 0x020
#define MDP_CCORR_SIZE 0x030
/* MASK */
#define MDP_CCORR_EN_MASK 0x00000001
#define MDP_CCORR_CFG_MASK 0x70001317
#define MDP_CCORR_SIZE_MASK 0x1fff1fff
#endif // __MDP_REG_CCORR_H__

View file

@ -0,0 +1,65 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2022 MediaTek Inc.
* Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
*/
#ifndef __MDP_REG_RDMA_H__
#define __MDP_REG_RDMA_H__
#define MDP_RDMA_EN 0x000
#define MDP_RDMA_RESET 0x008
#define MDP_RDMA_CON 0x020
#define MDP_RDMA_GMCIF_CON 0x028
#define MDP_RDMA_SRC_CON 0x030
#define MDP_RDMA_MF_BKGD_SIZE_IN_BYTE 0x060
#define MDP_RDMA_MF_BKGD_SIZE_IN_PXL 0x068
#define MDP_RDMA_MF_SRC_SIZE 0x070
#define MDP_RDMA_MF_CLIP_SIZE 0x078
#define MDP_RDMA_MF_OFFSET_1 0x080
#define MDP_RDMA_SF_BKGD_SIZE_IN_BYTE 0x090
#define MDP_RDMA_SRC_END_0 0x100
#define MDP_RDMA_SRC_END_1 0x108
#define MDP_RDMA_SRC_END_2 0x110
#define MDP_RDMA_SRC_OFFSET_0 0x118
#define MDP_RDMA_SRC_OFFSET_1 0x120
#define MDP_RDMA_SRC_OFFSET_2 0x128
#define MDP_RDMA_SRC_OFFSET_0_P 0x148
#define MDP_RDMA_TRANSFORM_0 0x200
#define MDP_RDMA_RESV_DUMMY_0 0x2a0
#define MDP_RDMA_MON_STA_1 0x408
#define MDP_RDMA_SRC_BASE_0 0xf00
#define MDP_RDMA_SRC_BASE_1 0xf08
#define MDP_RDMA_SRC_BASE_2 0xf10
#define MDP_RDMA_UFO_DEC_LENGTH_BASE_Y 0xf20
#define MDP_RDMA_UFO_DEC_LENGTH_BASE_C 0xf28
/* MASK */
#define MDP_RDMA_EN_MASK 0x00000001
#define MDP_RDMA_RESET_MASK 0x00000001
#define MDP_RDMA_CON_MASK 0x00001110
#define MDP_RDMA_GMCIF_CON_MASK 0xfffb3771
#define MDP_RDMA_SRC_CON_MASK 0xf3ffffff
#define MDP_RDMA_MF_BKGD_SIZE_IN_BYTE_MASK 0x001fffff
#define MDP_RDMA_MF_BKGD_SIZE_IN_PXL_MASK 0x001fffff
#define MDP_RDMA_MF_SRC_SIZE_MASK 0x1fff1fff
#define MDP_RDMA_MF_CLIP_SIZE_MASK 0x1fff1fff
#define MDP_RDMA_MF_OFFSET_1_MASK 0x003f001f
#define MDP_RDMA_SF_BKGD_SIZE_IN_BYTE_MASK 0x001fffff
#define MDP_RDMA_SRC_END_0_MASK 0xffffffff
#define MDP_RDMA_SRC_END_1_MASK 0xffffffff
#define MDP_RDMA_SRC_END_2_MASK 0xffffffff
#define MDP_RDMA_SRC_OFFSET_0_MASK 0xffffffff
#define MDP_RDMA_SRC_OFFSET_1_MASK 0xffffffff
#define MDP_RDMA_SRC_OFFSET_2_MASK 0xffffffff
#define MDP_RDMA_SRC_OFFSET_0_P_MASK 0xffffffff
#define MDP_RDMA_TRANSFORM_0_MASK 0xff110777
#define MDP_RDMA_RESV_DUMMY_0_MASK 0xffffffff
#define MDP_RDMA_MON_STA_1_MASK 0xffffffff
#define MDP_RDMA_SRC_BASE_0_MASK 0xffffffff
#define MDP_RDMA_SRC_BASE_1_MASK 0xffffffff
#define MDP_RDMA_SRC_BASE_2_MASK 0xffffffff
#define MDP_RDMA_UFO_DEC_LENGTH_BASE_Y_MASK 0xffffffff
#define MDP_RDMA_UFO_DEC_LENGTH_BASE_C_MASK 0xffffffff
#endif // __MDP_REG_RDMA_H__

View file

@ -0,0 +1,39 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2022 MediaTek Inc.
* Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
*/
#ifndef __MDP_REG_RSZ_H__
#define __MDP_REG_RSZ_H__
#define PRZ_ENABLE 0x000
#define PRZ_CONTROL_1 0x004
#define PRZ_CONTROL_2 0x008
#define PRZ_INPUT_IMAGE 0x010
#define PRZ_OUTPUT_IMAGE 0x014
#define PRZ_HORIZONTAL_COEFF_STEP 0x018
#define PRZ_VERTICAL_COEFF_STEP 0x01c
#define PRZ_LUMA_HORIZONTAL_INTEGER_OFFSET 0x020
#define PRZ_LUMA_HORIZONTAL_SUBPIXEL_OFFSET 0x024
#define PRZ_LUMA_VERTICAL_INTEGER_OFFSET 0x028
#define PRZ_LUMA_VERTICAL_SUBPIXEL_OFFSET 0x02c
#define PRZ_CHROMA_HORIZONTAL_INTEGER_OFFSET 0x030
#define PRZ_CHROMA_HORIZONTAL_SUBPIXEL_OFFSET 0x034
/* MASK */
#define PRZ_ENABLE_MASK 0x00010001
#define PRZ_CONTROL_1_MASK 0xfffffff3
#define PRZ_CONTROL_2_MASK 0x0ffffaff
#define PRZ_INPUT_IMAGE_MASK 0xffffffff
#define PRZ_OUTPUT_IMAGE_MASK 0xffffffff
#define PRZ_HORIZONTAL_COEFF_STEP_MASK 0x007fffff
#define PRZ_VERTICAL_COEFF_STEP_MASK 0x007fffff
#define PRZ_LUMA_HORIZONTAL_INTEGER_OFFSET_MASK 0x0000ffff
#define PRZ_LUMA_HORIZONTAL_SUBPIXEL_OFFSET_MASK 0x001fffff
#define PRZ_LUMA_VERTICAL_INTEGER_OFFSET_MASK 0x0000ffff
#define PRZ_LUMA_VERTICAL_SUBPIXEL_OFFSET_MASK 0x001fffff
#define PRZ_CHROMA_HORIZONTAL_INTEGER_OFFSET_MASK 0x0000ffff
#define PRZ_CHROMA_HORIZONTAL_SUBPIXEL_OFFSET_MASK 0x001fffff
#endif // __MDP_REG_RSZ_H__

View file

@ -0,0 +1,47 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2022 MediaTek Inc.
* Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
*/
#ifndef __MDP_REG_WDMA_H__
#define __MDP_REG_WDMA_H__
#define WDMA_EN 0x008
#define WDMA_RST 0x00c
#define WDMA_CFG 0x014
#define WDMA_SRC_SIZE 0x018
#define WDMA_CLIP_SIZE 0x01c
#define WDMA_CLIP_COORD 0x020
#define WDMA_DST_W_IN_BYTE 0x028
#define WDMA_ALPHA 0x02c
#define WDMA_BUF_CON2 0x03c
#define WDMA_DST_UV_PITCH 0x078
#define WDMA_DST_ADDR_OFFSET 0x080
#define WDMA_DST_U_ADDR_OFFSET 0x084
#define WDMA_DST_V_ADDR_OFFSET 0x088
#define WDMA_FLOW_CTRL_DBG 0x0a0
#define WDMA_DST_ADDR 0xf00
#define WDMA_DST_U_ADDR 0xf04
#define WDMA_DST_V_ADDR 0xf08
/* MASK */
#define WDMA_EN_MASK 0x00000001
#define WDMA_RST_MASK 0x00000001
#define WDMA_CFG_MASK 0xff03bff0
#define WDMA_SRC_SIZE_MASK 0x3fff3fff
#define WDMA_CLIP_SIZE_MASK 0x3fff3fff
#define WDMA_CLIP_COORD_MASK 0x3fff3fff
#define WDMA_DST_W_IN_BYTE_MASK 0x0000ffff
#define WDMA_ALPHA_MASK 0x800000ff
#define WDMA_BUF_CON2_MASK 0xffffffff
#define WDMA_DST_UV_PITCH_MASK 0x0000ffff
#define WDMA_DST_ADDR_OFFSET_MASK 0x0fffffff
#define WDMA_DST_U_ADDR_OFFSET_MASK 0x0fffffff
#define WDMA_DST_V_ADDR_OFFSET_MASK 0x0fffffff
#define WDMA_FLOW_CTRL_DBG_MASK 0x0000f3ff
#define WDMA_DST_ADDR_MASK 0xffffffff
#define WDMA_DST_U_ADDR_MASK 0xffffffff
#define WDMA_DST_V_ADDR_MASK 0xffffffff
#endif // __MDP_REG_WDMA_H__

View file

@ -0,0 +1,55 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2022 MediaTek Inc.
* Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
*/
#ifndef __MDP_REG_WROT_H__
#define __MDP_REG_WROT_H__
#define VIDO_CTRL 0x000
#define VIDO_MAIN_BUF_SIZE 0x008
#define VIDO_SOFT_RST 0x010
#define VIDO_SOFT_RST_STAT 0x014
#define VIDO_CROP_OFST 0x020
#define VIDO_TAR_SIZE 0x024
#define VIDO_OFST_ADDR 0x02c
#define VIDO_STRIDE 0x030
#define VIDO_OFST_ADDR_C 0x038
#define VIDO_STRIDE_C 0x03c
#define VIDO_DITHER 0x054
#define VIDO_STRIDE_V 0x06c
#define VIDO_OFST_ADDR_V 0x068
#define VIDO_RSV_1 0x070
#define VIDO_IN_SIZE 0x078
#define VIDO_ROT_EN 0x07c
#define VIDO_FIFO_TEST 0x080
#define VIDO_MAT_CTRL 0x084
#define VIDO_BASE_ADDR 0xf00
#define VIDO_BASE_ADDR_C 0xf04
#define VIDO_BASE_ADDR_V 0xf08
/* MASK */
#define VIDO_CTRL_MASK 0xf530711f
#define VIDO_MAIN_BUF_SIZE_MASK 0x1fff7f77
#define VIDO_SOFT_RST_MASK 0x00000001
#define VIDO_SOFT_RST_STAT_MASK 0x00000001
#define VIDO_TAR_SIZE_MASK 0x1fff1fff
#define VIDO_CROP_OFST_MASK 0x1fff1fff
#define VIDO_OFST_ADDR_MASK 0x0fffffff
#define VIDO_STRIDE_MASK 0x0000ffff
#define VIDO_OFST_ADDR_C_MASK 0x0fffffff
#define VIDO_STRIDE_C_MASK 0x0000ffff
#define VIDO_DITHER_MASK 0xff000001
#define VIDO_STRIDE_V_MASK 0x0000ffff
#define VIDO_OFST_ADDR_V_MASK 0x0fffffff
#define VIDO_RSV_1_MASK 0xffffffff
#define VIDO_IN_SIZE_MASK 0x1fff1fff
#define VIDO_ROT_EN_MASK 0x00000001
#define VIDO_FIFO_TEST_MASK 0x00000fff
#define VIDO_MAT_CTRL_MASK 0x000000f3
#define VIDO_BASE_ADDR_MASK 0xffffffff
#define VIDO_BASE_ADDR_C_MASK 0xffffffff
#define VIDO_BASE_ADDR_V_MASK 0xffffffff
#endif // __MDP_REG_WROT_H__

View file

@ -0,0 +1,290 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2022 MediaTek Inc.
* Author: Holmes Chiou <holmes.chiou@mediatek.com>
* Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
*/
#ifndef __MTK_IMG_IPI_H__
#define __MTK_IMG_IPI_H__
#include <linux/types.h>
/*
* ISP-MDP generic input information
* MD5 of the target SCP blob:
* 6da52bdcf4bf76a0983b313e1d4745d6
*/
#define IMG_MAX_HW_INPUTS 3
#define IMG_MAX_HW_OUTPUTS 4
#define IMG_MAX_PLANES 3
#define IMG_IPI_INIT 1
#define IMG_IPI_DEINIT 2
#define IMG_IPI_FRAME 3
#define IMG_IPI_DEBUG 4
struct img_timeval {
u32 tv_sec;
u32 tv_usec;
} __packed;
struct img_addr {
u64 va; /* Used for Linux OS access */
u32 pa; /* Used for CM4 access */
u32 iova; /* Used for IOMMU HW access */
} __packed;
struct tuning_addr {
u64 present;
u32 pa; /* Used for CM4 access */
u32 iova; /* Used for IOMMU HW access */
} __packed;
struct img_sw_addr {
u64 va; /* Used for APMCU access */
u32 pa; /* Used for CM4 access */
} __packed;
struct img_plane_format {
u32 size;
u16 stride;
} __packed;
struct img_pix_format {
u16 width;
u16 height;
u32 colorformat; /* enum mdp_color */
u16 ycbcr_prof; /* enum mdp_ycbcr_profile */
struct img_plane_format plane_fmt[IMG_MAX_PLANES];
} __packed;
struct img_image_buffer {
struct img_pix_format format;
u32 iova[IMG_MAX_PLANES];
/* enum mdp_buffer_usage, FD or advanced ISP usages */
u32 usage;
} __packed;
#define IMG_SUBPIXEL_SHIFT 20
struct img_crop {
s16 left;
s16 top;
u16 width;
u16 height;
u32 left_subpix;
u32 top_subpix;
u32 width_subpix;
u32 height_subpix;
} __packed;
#define IMG_CTRL_FLAG_HFLIP BIT(0)
#define IMG_CTRL_FLAG_DITHER BIT(1)
#define IMG_CTRL_FLAG_SHARPNESS BIT(4)
#define IMG_CTRL_FLAG_HDR BIT(5)
#define IMG_CTRL_FLAG_DRE BIT(6)
struct img_input {
struct img_image_buffer buffer;
u16 flags; /* HDR, DRE, dither */
} __packed;
struct img_output {
struct img_image_buffer buffer;
struct img_crop crop;
s16 rotation;
u16 flags; /* H-flip, sharpness, dither */
} __packed;
struct img_ipi_frameparam {
u32 index;
u32 frame_no;
struct img_timeval timestamp;
u8 type; /* enum mdp_stream_type */
u8 state;
u8 num_inputs;
u8 num_outputs;
u64 drv_data;
struct img_input inputs[IMG_MAX_HW_INPUTS];
struct img_output outputs[IMG_MAX_HW_OUTPUTS];
struct tuning_addr tuning_data;
struct img_addr subfrm_data;
struct img_sw_addr config_data;
struct img_sw_addr self_data;
} __packed;
struct img_sw_buffer {
u64 handle; /* Used for APMCU access */
u32 scp_addr; /* Used for CM4 access */
} __packed;
struct img_ipi_param {
u8 usage;
struct img_sw_buffer frm_param;
} __packed;
struct img_frameparam {
struct list_head list_entry;
struct img_ipi_frameparam frameparam;
};
/* ISP-MDP generic output information */
struct img_comp_frame {
u32 output_disable:1;
u32 bypass:1;
u16 in_width;
u16 in_height;
u16 out_width;
u16 out_height;
struct img_crop crop;
u16 in_total_width;
u16 out_total_width;
} __packed;
struct img_region {
s16 left;
s16 right;
s16 top;
s16 bottom;
} __packed;
struct img_offset {
s16 left;
s16 top;
u32 left_subpix;
u32 top_subpix;
} __packed;
struct img_comp_subfrm {
u32 tile_disable:1;
struct img_region in;
struct img_region out;
struct img_offset luma;
struct img_offset chroma;
s16 out_vertical; /* Output vertical index */
s16 out_horizontal; /* Output horizontal index */
} __packed;
#define IMG_MAX_SUBFRAMES 14
struct mdp_rdma_subfrm {
u32 offset[IMG_MAX_PLANES];
u32 offset_0_p;
u32 src;
u32 clip;
u32 clip_ofst;
} __packed;
struct mdp_rdma_data {
u32 src_ctrl;
u32 control;
u32 iova[IMG_MAX_PLANES];
u32 iova_end[IMG_MAX_PLANES];
u32 mf_bkgd;
u32 mf_bkgd_in_pxl;
u32 sf_bkgd;
u32 ufo_dec_y;
u32 ufo_dec_c;
u32 transform;
struct mdp_rdma_subfrm subfrms[IMG_MAX_SUBFRAMES];
} __packed;
struct mdp_rsz_subfrm {
u32 control2;
u32 src;
u32 clip;
} __packed;
struct mdp_rsz_data {
u32 coeff_step_x;
u32 coeff_step_y;
u32 control1;
u32 control2;
struct mdp_rsz_subfrm subfrms[IMG_MAX_SUBFRAMES];
} __packed;
struct mdp_wrot_subfrm {
u32 offset[IMG_MAX_PLANES];
u32 src;
u32 clip;
u32 clip_ofst;
u32 main_buf;
} __packed;
struct mdp_wrot_data {
u32 iova[IMG_MAX_PLANES];
u32 control;
u32 stride[IMG_MAX_PLANES];
u32 mat_ctrl;
u32 fifo_test;
u32 filter;
struct mdp_wrot_subfrm subfrms[IMG_MAX_SUBFRAMES];
} __packed;
struct mdp_wdma_subfrm {
u32 offset[IMG_MAX_PLANES];
u32 src;
u32 clip;
u32 clip_ofst;
} __packed;
struct mdp_wdma_data {
u32 wdma_cfg;
u32 iova[IMG_MAX_PLANES];
u32 w_in_byte;
u32 uv_stride;
struct mdp_wdma_subfrm subfrms[IMG_MAX_SUBFRAMES];
} __packed;
struct isp_data {
u64 dl_flags; /* 1 << (enum mdp_comp_type) */
u32 smxi_iova[4];
u32 cq_idx;
u32 cq_iova;
u32 tpipe_iova[IMG_MAX_SUBFRAMES];
} __packed;
struct img_compparam {
u16 type; /* enum mdp_comp_type */
u16 id; /* enum mtk_mdp_comp_id */
u32 input;
u32 outputs[IMG_MAX_HW_OUTPUTS];
u32 num_outputs;
struct img_comp_frame frame;
struct img_comp_subfrm subfrms[IMG_MAX_SUBFRAMES];
u32 num_subfrms;
union {
struct mdp_rdma_data rdma;
struct mdp_rsz_data rsz;
struct mdp_wrot_data wrot;
struct mdp_wdma_data wdma;
struct isp_data isp;
};
} __packed;
#define IMG_MAX_COMPONENTS 20
struct img_mux {
u32 reg;
u32 value;
u32 subsys_id;
};
struct img_mmsys_ctrl {
struct img_mux sets[IMG_MAX_COMPONENTS * 2];
u32 num_sets;
};
struct img_config {
struct img_compparam components[IMG_MAX_COMPONENTS];
u32 num_components;
struct img_mmsys_ctrl ctrls[IMG_MAX_SUBFRAMES];
u32 num_subfrms;
} __packed;
#endif /* __MTK_IMG_IPI_H__ */

View file

@ -0,0 +1,466 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2022 MediaTek Inc.
* Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
*/
#include <linux/mailbox_controller.h>
#include <linux/platform_device.h>
#include "mtk-mdp3-cmdq.h"
#include "mtk-mdp3-comp.h"
#include "mtk-mdp3-core.h"
#include "mtk-mdp3-m2m.h"
#define MDP_PATH_MAX_COMPS IMG_MAX_COMPONENTS
struct mdp_path {
struct mdp_dev *mdp_dev;
struct mdp_comp_ctx comps[MDP_PATH_MAX_COMPS];
u32 num_comps;
const struct img_config *config;
const struct img_ipi_frameparam *param;
const struct v4l2_rect *composes[IMG_MAX_HW_OUTPUTS];
struct v4l2_rect bounds[IMG_MAX_HW_OUTPUTS];
};
#define has_op(ctx, op) \
((ctx)->comp->ops && (ctx)->comp->ops->op)
#define call_op(ctx, op, ...) \
(has_op(ctx, op) ? (ctx)->comp->ops->op(ctx, ##__VA_ARGS__) : 0)
static bool is_output_disabled(const struct img_compparam *param, u32 count)
{
return (count < param->num_subfrms) ?
(param->frame.output_disable ||
param->subfrms[count].tile_disable) :
true;
}
static int mdp_path_subfrm_require(const struct mdp_path *path,
struct mdp_cmdq_cmd *cmd,
s32 *mutex_id, u32 count)
{
const struct img_config *config = path->config;
const struct mdp_comp_ctx *ctx;
const struct mtk_mdp_driver_data *data = path->mdp_dev->mdp_data;
struct device *dev = &path->mdp_dev->pdev->dev;
struct mtk_mutex **mutex = path->mdp_dev->mdp_mutex;
int id, index;
/* Decide which mutex to use based on the current pipeline */
switch (path->comps[0].comp->id) {
case MDP_COMP_RDMA0:
*mutex_id = MDP_PIPE_RDMA0;
break;
case MDP_COMP_ISP_IMGI:
*mutex_id = MDP_PIPE_IMGI;
break;
case MDP_COMP_WPEI:
*mutex_id = MDP_PIPE_WPEI;
break;
case MDP_COMP_WPEI2:
*mutex_id = MDP_PIPE_WPEI2;
break;
default:
dev_err(dev, "Unknown pipeline and no mutex is assigned");
return -EINVAL;
}
/* Set mutex mod */
for (index = 0; index < config->num_components; index++) {
ctx = &path->comps[index];
if (is_output_disabled(ctx->param, count))
continue;
id = ctx->comp->id;
mtk_mutex_write_mod(mutex[*mutex_id],
data->mdp_mutex_table_idx[id], false);
}
mtk_mutex_write_sof(mutex[*mutex_id],
MUTEX_SOF_IDX_SINGLE_MODE);
return 0;
}
static int mdp_path_subfrm_run(const struct mdp_path *path,
struct mdp_cmdq_cmd *cmd,
s32 *mutex_id, u32 count)
{
const struct img_config *config = path->config;
const struct mdp_comp_ctx *ctx;
struct device *dev = &path->mdp_dev->pdev->dev;
struct mtk_mutex **mutex = path->mdp_dev->mdp_mutex;
int index;
s32 event;
if (-1 == *mutex_id) {
dev_err(dev, "Incorrect mutex id");
return -EINVAL;
}
/* Wait WROT SRAM shared to DISP RDMA */
/* Clear SOF event for each engine */
for (index = 0; index < config->num_components; index++) {
ctx = &path->comps[index];
if (is_output_disabled(ctx->param, count))
continue;
event = ctx->comp->gce_event[MDP_GCE_EVENT_SOF];
if (event != MDP_GCE_NO_EVENT)
MM_REG_CLEAR(cmd, event);
}
/* Enable the mutex */
mtk_mutex_enable_by_cmdq(mutex[*mutex_id], (void *)&cmd->pkt);
/* Wait SOF events and clear mutex modules (optional) */
for (index = 0; index < config->num_components; index++) {
ctx = &path->comps[index];
if (is_output_disabled(ctx->param, count))
continue;
event = ctx->comp->gce_event[MDP_GCE_EVENT_SOF];
if (event != MDP_GCE_NO_EVENT)
MM_REG_WAIT(cmd, event);
}
return 0;
}
static int mdp_path_ctx_init(struct mdp_dev *mdp, struct mdp_path *path)
{
const struct img_config *config = path->config;
int index, ret;
if (config->num_components < 1)
return -EINVAL;
for (index = 0; index < config->num_components; index++) {
ret = mdp_comp_ctx_config(mdp, &path->comps[index],
&config->components[index],
path->param);
if (ret)
return ret;
}
return 0;
}
static int mdp_path_config_subfrm(struct mdp_cmdq_cmd *cmd,
struct mdp_path *path, u32 count)
{
const struct img_config *config = path->config;
const struct img_mmsys_ctrl *ctrl = &config->ctrls[count];
const struct img_mux *set;
struct mdp_comp_ctx *ctx;
s32 mutex_id;
int index, ret;
/* Acquire components */
ret = mdp_path_subfrm_require(path, cmd, &mutex_id, count);
if (ret)
return ret;
/* Enable mux settings */
for (index = 0; index < ctrl->num_sets; index++) {
set = &ctrl->sets[index];
cmdq_pkt_write_mask(&cmd->pkt, set->subsys_id, set->reg,
set->value, 0xFFFFFFFF);
}
/* Config sub-frame information */
for (index = (config->num_components - 1); index >= 0; index--) {
ctx = &path->comps[index];
if (is_output_disabled(ctx->param, count))
continue;
ret = call_op(ctx, config_subfrm, cmd, count);
if (ret)
return ret;
}
/* Run components */
ret = mdp_path_subfrm_run(path, cmd, &mutex_id, count);
if (ret)
return ret;
/* Wait components done */
for (index = 0; index < config->num_components; index++) {
ctx = &path->comps[index];
if (is_output_disabled(ctx->param, count))
continue;
ret = call_op(ctx, wait_comp_event, cmd);
if (ret)
return ret;
}
/* Advance to the next sub-frame */
for (index = 0; index < config->num_components; index++) {
ctx = &path->comps[index];
ret = call_op(ctx, advance_subfrm, cmd, count);
if (ret)
return ret;
}
/* Disable mux settings */
for (index = 0; index < ctrl->num_sets; index++) {
set = &ctrl->sets[index];
cmdq_pkt_write_mask(&cmd->pkt, set->subsys_id, set->reg,
0, 0xFFFFFFFF);
}
return 0;
}
static int mdp_path_config(struct mdp_dev *mdp, struct mdp_cmdq_cmd *cmd,
struct mdp_path *path)
{
const struct img_config *config = path->config;
struct mdp_comp_ctx *ctx;
int index, count, ret;
/* Config path frame */
/* Reset components */
for (index = 0; index < config->num_components; index++) {
ctx = &path->comps[index];
ret = call_op(ctx, init_comp, cmd);
if (ret)
return ret;
}
/* Config frame mode */
for (index = 0; index < config->num_components; index++) {
const struct v4l2_rect *compose =
path->composes[ctx->param->outputs[0]];
ctx = &path->comps[index];
ret = call_op(ctx, config_frame, cmd, compose);
if (ret)
return ret;
}
/* Config path sub-frames */
for (count = 0; count < config->num_subfrms; count++) {
ret = mdp_path_config_subfrm(cmd, path, count);
if (ret)
return ret;
}
/* Post processing information */
for (index = 0; index < config->num_components; index++) {
ctx = &path->comps[index];
ret = call_op(ctx, post_process, cmd);
if (ret)
return ret;
}
return 0;
}
static int mdp_cmdq_pkt_create(struct cmdq_client *client, struct cmdq_pkt *pkt,
size_t size)
{
struct device *dev;
dma_addr_t dma_addr;
pkt->va_base = kzalloc(size, GFP_KERNEL);
if (!pkt->va_base) {
kfree(pkt);
return -ENOMEM;
}
pkt->buf_size = size;
pkt->cl = (void *)client;
dev = client->chan->mbox->dev;
dma_addr = dma_map_single(dev, pkt->va_base, pkt->buf_size,
DMA_TO_DEVICE);
if (dma_mapping_error(dev, dma_addr)) {
dev_err(dev, "dma map failed, size=%u\n", (u32)(u64)size);
kfree(pkt->va_base);
return -ENOMEM;
}
pkt->pa_base = dma_addr;
return 0;
}
static void mdp_cmdq_pkt_destroy(struct cmdq_pkt *pkt)
{
struct cmdq_client *client = (struct cmdq_client *)pkt->cl;
dma_unmap_single(client->chan->mbox->dev, pkt->pa_base, pkt->buf_size,
DMA_TO_DEVICE);
kfree(pkt->va_base);
pkt->va_base = NULL;
}
static void mdp_auto_release_work(struct work_struct *work)
{
struct mdp_cmdq_cmd *cmd;
struct mdp_dev *mdp;
cmd = container_of(work, struct mdp_cmdq_cmd, auto_release_work);
mdp = cmd->mdp;
mtk_mutex_unprepare(mdp->mdp_mutex[MDP_PIPE_RDMA0]);
mdp_comp_clocks_off(&mdp->pdev->dev, cmd->comps,
cmd->num_comps);
atomic_dec(&mdp->job_count);
wake_up(&mdp->callback_wq);
mdp_cmdq_pkt_destroy(&cmd->pkt);
kfree(cmd->comps);
cmd->comps = NULL;
kfree(cmd);
cmd = NULL;
}
static void mdp_handle_cmdq_callback(struct mbox_client *cl, void *mssg)
{
struct mdp_cmdq_cmd *cmd;
struct cmdq_cb_data *data;
struct mdp_dev *mdp;
struct device *dev;
if (!mssg) {
pr_info("%s:no callback data\n", __func__);
return;
}
data = (struct cmdq_cb_data *)mssg;
cmd = container_of(data->pkt, struct mdp_cmdq_cmd, pkt);
mdp = cmd->mdp;
dev = &mdp->pdev->dev;
if (cmd->mdp_ctx)
mdp_m2m_job_finish(cmd->mdp_ctx);
if (cmd->user_cmdq_cb) {
struct cmdq_cb_data user_cb_data;
user_cb_data.sta = data->sta;
user_cb_data.pkt = data->pkt;
cmd->user_cmdq_cb(user_cb_data);
}
INIT_WORK(&cmd->auto_release_work, mdp_auto_release_work);
if (!queue_work(mdp->clock_wq, &cmd->auto_release_work)) {
dev_err(dev, "%s:queue_work fail!\n", __func__);
mtk_mutex_unprepare(mdp->mdp_mutex[MDP_PIPE_RDMA0]);
mdp_comp_clocks_off(&mdp->pdev->dev, cmd->comps,
cmd->num_comps);
atomic_dec(&mdp->job_count);
wake_up(&mdp->callback_wq);
mdp_cmdq_pkt_destroy(&cmd->pkt);
kfree(cmd->comps);
cmd->comps = NULL;
kfree(cmd);
cmd = NULL;
}
}
int mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param)
{
struct mdp_path *path = NULL;
struct mdp_cmdq_cmd *cmd = NULL;
struct mdp_comp *comps = NULL;
struct device *dev = &mdp->pdev->dev;
int i, ret;
atomic_inc(&mdp->job_count);
if (atomic_read(&mdp->suspended)) {
atomic_dec(&mdp->job_count);
return -ECANCELED;
}
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
ret = -ENOMEM;
goto err_cmdq_data;
}
if (mdp_cmdq_pkt_create(mdp->cmdq_clt, &cmd->pkt, SZ_16K)) {
ret = -ENOMEM;
goto err_cmdq_data;
}
comps = kcalloc(param->config->num_components, sizeof(*comps),
GFP_KERNEL);
if (!comps) {
ret = -ENOMEM;
goto err_cmdq_data;
}
path = kzalloc(sizeof(*path), GFP_KERNEL);
if (!path) {
ret = -ENOMEM;
goto err_cmdq_data;
}
path->mdp_dev = mdp;
path->config = param->config;
path->param = param->param;
for (i = 0; i < param->param->num_outputs; i++) {
path->bounds[i].left = 0;
path->bounds[i].top = 0;
path->bounds[i].width =
param->param->outputs[i].buffer.format.width;
path->bounds[i].height =
param->param->outputs[i].buffer.format.height;
path->composes[i] = param->composes[i] ?
param->composes[i] : &path->bounds[i];
}
ret = mdp_path_ctx_init(mdp, path);
if (ret) {
dev_err(dev, "mdp_path_ctx_init error\n");
goto err_cmdq_data;
}
mtk_mutex_prepare(mdp->mdp_mutex[MDP_PIPE_RDMA0]);
ret = mdp_path_config(mdp, cmd, path);
if (ret) {
dev_err(dev, "mdp_path_config error\n");
goto err_cmdq_data;
}
cmdq_pkt_finalize(&cmd->pkt);
for (i = 0; i < param->config->num_components; i++)
memcpy(&comps[i], path->comps[i].comp,
sizeof(struct mdp_comp));
mdp->cmdq_clt->client.rx_callback = mdp_handle_cmdq_callback;
cmd->mdp = mdp;
cmd->user_cmdq_cb = param->cmdq_cb;
cmd->user_cb_data = param->cb_data;
cmd->comps = comps;
cmd->num_comps = param->config->num_components;
cmd->mdp_ctx = param->mdp_ctx;
ret = mdp_comp_clocks_on(&mdp->pdev->dev, cmd->comps, cmd->num_comps);
if (ret) {
dev_err(dev, "comp %d failed to enable clock!\n", ret);
goto err_clock_off;
}
dma_sync_single_for_device(mdp->cmdq_clt->chan->mbox->dev,
cmd->pkt.pa_base, cmd->pkt.cmd_buf_size,
DMA_TO_DEVICE);
ret = mbox_send_message(mdp->cmdq_clt->chan, &cmd->pkt);
if (ret < 0) {
dev_err(dev, "mbox send message fail %d!\n", ret);
goto err_clock_off;
}
mbox_client_txdone(mdp->cmdq_clt->chan, 0);
kfree(path);
return 0;
err_clock_off:
mtk_mutex_unprepare(mdp->mdp_mutex[MDP_PIPE_RDMA0]);
mdp_comp_clocks_off(&mdp->pdev->dev, cmd->comps,
cmd->num_comps);
err_cmdq_data:
kfree(path);
atomic_dec(&mdp->job_count);
wake_up(&mdp->callback_wq);
if (cmd->pkt.buf_size > 0)
mdp_cmdq_pkt_destroy(&cmd->pkt);
kfree(comps);
kfree(cmd);
return ret;
}
EXPORT_SYMBOL_GPL(mdp_cmdq_send);

View file

@ -0,0 +1,43 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2022 MediaTek Inc.
* Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
*/
#ifndef __MTK_MDP3_CMDQ_H__
#define __MTK_MDP3_CMDQ_H__
#include <linux/platform_device.h>
#include <linux/videodev2.h>
#include <linux/soc/mediatek/mtk-cmdq.h>
#include "mtk-img-ipi.h"
struct platform_device *mdp_get_plat_device(struct platform_device *pdev);
struct mdp_cmdq_param {
struct img_config *config;
struct img_ipi_frameparam *param;
const struct v4l2_rect *composes[IMG_MAX_HW_OUTPUTS];
void (*cmdq_cb)(struct cmdq_cb_data data);
void *cb_data;
void *mdp_ctx;
};
struct mdp_cmdq_cmd {
struct work_struct auto_release_work;
struct cmdq_pkt pkt;
s32 *event;
struct mdp_dev *mdp;
void (*user_cmdq_cb)(struct cmdq_cb_data data);
void *user_cb_data;
struct mdp_comp *comps;
void *mdp_ctx;
u8 num_comps;
};
struct mdp_dev;
int mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param);
#endif /* __MTK_MDP3_CMDQ_H__ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,186 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2022 MediaTek Inc.
* Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
*/
#ifndef __MTK_MDP3_COMP_H__
#define __MTK_MDP3_COMP_H__
#include "mtk-mdp3-cmdq.h"
#define MM_REG_WRITE_MASK(cmd, id, base, ofst, val, mask, ...) \
cmdq_pkt_write_mask(&((cmd)->pkt), id, \
(base) + (ofst), (val), (mask), ##__VA_ARGS__)
#define MM_REG_WRITE(cmd, id, base, ofst, val, mask, ...) \
do { \
typeof(mask) (m) = (mask); \
MM_REG_WRITE_MASK(cmd, id, base, ofst, val, \
(((m) & (ofst##_MASK)) == (ofst##_MASK)) ? \
(0xffffffff) : (m), ##__VA_ARGS__); \
} while (0)
#define MM_REG_WAIT(cmd, evt) \
do { \
typeof(cmd) (c) = (cmd); \
typeof(evt) (e) = (evt); \
cmdq_pkt_wfe(&((c)->pkt), (e), true); \
} while (0)
#define MM_REG_WAIT_NO_CLEAR(cmd, evt) \
do { \
typeof(cmd) (c) = (cmd); \
typeof(evt) (e) = (evt); \
cmdq_pkt_wfe(&((c)->pkt), (e), false); \
} while (0)
#define MM_REG_CLEAR(cmd, evt) \
do { \
typeof(cmd) (c) = (cmd); \
typeof(evt) (e) = (evt); \
cmdq_pkt_clear_event(&((c)->pkt), (e)); \
} while (0)
#define MM_REG_SET_EVENT(cmd, evt) \
do { \
typeof(cmd) (c) = (cmd); \
typeof(evt) (e) = (evt); \
cmdq_pkt_set_event(&((c)->pkt), (e)); \
} while (0)
#define MM_REG_POLL_MASK(cmd, id, base, ofst, val, _mask, ...) \
do { \
typeof(_mask) (_m) = (_mask); \
cmdq_pkt_poll_mask(&((cmd)->pkt), id, \
(base) + (ofst), (val), (_m), ##__VA_ARGS__); \
} while (0)
#define MM_REG_POLL(cmd, id, base, ofst, val, mask, ...) \
do { \
typeof(mask) (m) = (mask); \
MM_REG_POLL_MASK((cmd), id, base, ofst, val, \
(((m) & (ofst##_MASK)) == (ofst##_MASK)) ? \
(0xffffffff) : (m), ##__VA_ARGS__); \
} while (0)
enum mtk_mdp_comp_id {
MDP_COMP_NONE = -1, /* Invalid engine */
/* ISP */
MDP_COMP_WPEI = 0,
MDP_COMP_WPEO, /* 1 */
MDP_COMP_WPEI2, /* 2 */
MDP_COMP_WPEO2, /* 3 */
MDP_COMP_ISP_IMGI, /* 4 */
MDP_COMP_ISP_IMGO, /* 5 */
MDP_COMP_ISP_IMG2O, /* 6 */
/* IPU */
MDP_COMP_IPUI, /* 7 */
MDP_COMP_IPUO, /* 8 */
/* MDP */
MDP_COMP_CAMIN, /* 9 */
MDP_COMP_CAMIN2, /* 10 */
MDP_COMP_RDMA0, /* 11 */
MDP_COMP_AAL0, /* 12 */
MDP_COMP_CCORR0, /* 13 */
MDP_COMP_RSZ0, /* 14 */
MDP_COMP_RSZ1, /* 15 */
MDP_COMP_TDSHP0, /* 16 */
MDP_COMP_COLOR0, /* 17 */
MDP_COMP_PATH0_SOUT, /* 18 */
MDP_COMP_PATH1_SOUT, /* 19 */
MDP_COMP_WROT0, /* 20 */
MDP_COMP_WDMA, /* 21 */
/* Dummy Engine */
MDP_COMP_RDMA1, /* 22 */
MDP_COMP_RSZ2, /* 23 */
MDP_COMP_TDSHP1, /* 24 */
MDP_COMP_WROT1, /* 25 */
MDP_MAX_COMP_COUNT /* ALWAYS keep at the end */
};
enum mdp_comp_type {
MDP_COMP_TYPE_INVALID = 0,
MDP_COMP_TYPE_RDMA,
MDP_COMP_TYPE_RSZ,
MDP_COMP_TYPE_WROT,
MDP_COMP_TYPE_WDMA,
MDP_COMP_TYPE_PATH,
MDP_COMP_TYPE_TDSHP,
MDP_COMP_TYPE_COLOR,
MDP_COMP_TYPE_DRE,
MDP_COMP_TYPE_CCORR,
MDP_COMP_TYPE_HDR,
MDP_COMP_TYPE_IMGI,
MDP_COMP_TYPE_WPEI,
MDP_COMP_TYPE_EXTO, /* External path */
MDP_COMP_TYPE_DL_PATH, /* Direct-link path */
MDP_COMP_TYPE_COUNT /* ALWAYS keep at the end */
};
#define MDP_GCE_NO_EVENT (-1)
enum {
MDP_GCE_EVENT_SOF = 0,
MDP_GCE_EVENT_EOF = 1,
MDP_GCE_EVENT_MAX,
};
struct mdp_comp_ops;
struct mdp_comp {
struct mdp_dev *mdp_dev;
void __iomem *regs;
phys_addr_t reg_base;
u8 subsys_id;
struct clk *clks[6];
struct device *comp_dev;
enum mdp_comp_type type;
enum mtk_mdp_comp_id id;
u32 alias_id;
s32 gce_event[MDP_GCE_EVENT_MAX];
const struct mdp_comp_ops *ops;
};
struct mdp_comp_ctx {
struct mdp_comp *comp;
const struct img_compparam *param;
const struct img_input *input;
const struct img_output *outputs[IMG_MAX_HW_OUTPUTS];
};
struct mdp_comp_ops {
s64 (*get_comp_flag)(const struct mdp_comp_ctx *ctx);
int (*init_comp)(struct mdp_comp_ctx *ctx, struct mdp_cmdq_cmd *cmd);
int (*config_frame)(struct mdp_comp_ctx *ctx, struct mdp_cmdq_cmd *cmd,
const struct v4l2_rect *compose);
int (*config_subfrm)(struct mdp_comp_ctx *ctx,
struct mdp_cmdq_cmd *cmd, u32 index);
int (*wait_comp_event)(struct mdp_comp_ctx *ctx,
struct mdp_cmdq_cmd *cmd);
int (*advance_subfrm)(struct mdp_comp_ctx *ctx,
struct mdp_cmdq_cmd *cmd, u32 index);
int (*post_process)(struct mdp_comp_ctx *ctx, struct mdp_cmdq_cmd *cmd);
};
struct mdp_dev;
int mdp_comp_config(struct mdp_dev *mdp);
void mdp_comp_destroy(struct mdp_dev *mdp);
int mdp_comp_clock_on(struct device *dev, struct mdp_comp *comp);
void mdp_comp_clock_off(struct device *dev, struct mdp_comp *comp);
int mdp_comp_clocks_on(struct device *dev, struct mdp_comp *comps, int num);
void mdp_comp_clocks_off(struct device *dev, struct mdp_comp *comps, int num);
int mdp_comp_ctx_config(struct mdp_dev *mdp, struct mdp_comp_ctx *ctx,
const struct img_compparam *param,
const struct img_ipi_frameparam *frame);
#endif /* __MTK_MDP3_COMP_H__ */

View file

@ -0,0 +1,357 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2022 MediaTek Inc.
* Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
*/
#include <linux/clk.h>
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/remoteproc.h>
#include <linux/remoteproc/mtk_scp.h>
#include <media/videobuf2-dma-contig.h>
#include "mtk-mdp3-core.h"
#include "mtk-mdp3-m2m.h"
static const struct mdp_platform_config mt8183_plat_cfg = {
.rdma_support_10bit = true,
.rdma_rsz1_sram_sharing = true,
.rdma_upsample_repeat_only = true,
.rsz_disable_dcm_small_sample = false,
.wrot_filter_constraint = false,
};
static const struct of_device_id mt8183_mdp_probe_infra[MDP_INFRA_MAX] = {
[MDP_INFRA_MMSYS] = { .compatible = "mediatek,mt8183-mmsys" },
[MDP_INFRA_MUTEX] = { .compatible = "mediatek,mt8183-disp-mutex" },
[MDP_INFRA_SCP] = { .compatible = "mediatek,mt8183-scp" }
};
static const u32 mt8183_mutex_idx[MDP_MAX_COMP_COUNT] = {
[MDP_COMP_RDMA0] = MUTEX_MOD_IDX_MDP_RDMA0,
[MDP_COMP_RSZ0] = MUTEX_MOD_IDX_MDP_RSZ0,
[MDP_COMP_RSZ1] = MUTEX_MOD_IDX_MDP_RSZ1,
[MDP_COMP_TDSHP0] = MUTEX_MOD_IDX_MDP_TDSHP0,
[MDP_COMP_WROT0] = MUTEX_MOD_IDX_MDP_WROT0,
[MDP_COMP_WDMA] = MUTEX_MOD_IDX_MDP_WDMA,
[MDP_COMP_AAL0] = MUTEX_MOD_IDX_MDP_AAL0,
[MDP_COMP_CCORR0] = MUTEX_MOD_IDX_MDP_CCORR0,
};
static const struct mtk_mdp_driver_data mt8183_mdp_driver_data = {
.mdp_probe_infra = mt8183_mdp_probe_infra,
.mdp_cfg = &mt8183_plat_cfg,
.mdp_mutex_table_idx = mt8183_mutex_idx,
};
static const struct of_device_id mdp_of_ids[] = {
{ .compatible = "mediatek,mt8183-mdp3-rdma",
.data = &mt8183_mdp_driver_data,
},
{},
};
MODULE_DEVICE_TABLE(of, mdp_of_ids);
static struct platform_device *__get_pdev_by_id(struct platform_device *pdev,
enum mdp_infra_id id)
{
struct device_node *node;
struct platform_device *mdp_pdev = NULL;
const struct mtk_mdp_driver_data *mdp_data;
const char *compat;
if (!pdev)
return NULL;
if (id < MDP_INFRA_MMSYS || id >= MDP_INFRA_MAX) {
dev_err(&pdev->dev, "Illegal infra id %d\n", id);
return NULL;
}
mdp_data = of_device_get_match_data(&pdev->dev);
if (!mdp_data) {
dev_err(&pdev->dev, "have no driver data to find node\n");
return NULL;
}
compat = mdp_data->mdp_probe_infra[id].compatible;
node = of_find_compatible_node(NULL, NULL, compat);
if (WARN_ON(!node)) {
dev_err(&pdev->dev, "find node from id %d failed\n", id);
return NULL;
}
mdp_pdev = of_find_device_by_node(node);
of_node_put(node);
if (WARN_ON(!mdp_pdev)) {
dev_err(&pdev->dev, "find pdev from id %d failed\n", id);
return NULL;
}
return mdp_pdev;
}
struct platform_device *mdp_get_plat_device(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *mdp_node;
struct platform_device *mdp_pdev;
mdp_node = of_parse_phandle(dev->of_node, MDP_PHANDLE_NAME, 0);
if (!mdp_node) {
dev_err(dev, "can't get node %s\n", MDP_PHANDLE_NAME);
return NULL;
}
mdp_pdev = of_find_device_by_node(mdp_node);
of_node_put(mdp_node);
return mdp_pdev;
}
EXPORT_SYMBOL_GPL(mdp_get_plat_device);
int mdp_vpu_get_locked(struct mdp_dev *mdp)
{
int ret = 0;
if (mdp->vpu_count++ == 0) {
ret = rproc_boot(mdp->rproc_handle);
if (ret) {
dev_err(&mdp->pdev->dev,
"vpu_load_firmware failed %d\n", ret);
goto err_load_vpu;
}
ret = mdp_vpu_register(mdp);
if (ret) {
dev_err(&mdp->pdev->dev,
"mdp_vpu register failed %d\n", ret);
goto err_reg_vpu;
}
ret = mdp_vpu_dev_init(&mdp->vpu, mdp->scp, &mdp->vpu_lock);
if (ret) {
dev_err(&mdp->pdev->dev,
"mdp_vpu device init failed %d\n", ret);
goto err_init_vpu;
}
}
return 0;
err_init_vpu:
mdp_vpu_unregister(mdp);
err_reg_vpu:
err_load_vpu:
mdp->vpu_count--;
return ret;
}
void mdp_vpu_put_locked(struct mdp_dev *mdp)
{
if (--mdp->vpu_count == 0) {
mdp_vpu_dev_deinit(&mdp->vpu);
mdp_vpu_unregister(mdp);
}
}
void mdp_video_device_release(struct video_device *vdev)
{
struct mdp_dev *mdp = (struct mdp_dev *)video_get_drvdata(vdev);
int i;
scp_put(mdp->scp);
destroy_workqueue(mdp->job_wq);
destroy_workqueue(mdp->clock_wq);
pm_runtime_disable(&mdp->pdev->dev);
vb2_dma_contig_clear_max_seg_size(&mdp->pdev->dev);
mdp_comp_destroy(mdp);
for (i = 0; i < MDP_PIPE_MAX; i++)
mtk_mutex_put(mdp->mdp_mutex[i]);
mdp_vpu_shared_mem_free(&mdp->vpu);
v4l2_m2m_release(mdp->m2m_dev);
kfree(mdp);
}
static int mdp_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct mdp_dev *mdp;
struct platform_device *mm_pdev;
int ret, i;
mdp = kzalloc(sizeof(*mdp), GFP_KERNEL);
if (!mdp) {
ret = -ENOMEM;
goto err_return;
}
mdp->pdev = pdev;
mdp->mdp_data = of_device_get_match_data(&pdev->dev);
mm_pdev = __get_pdev_by_id(pdev, MDP_INFRA_MMSYS);
if (!mm_pdev) {
ret = -ENODEV;
goto err_return;
}
mdp->mdp_mmsys = &mm_pdev->dev;
mm_pdev = __get_pdev_by_id(pdev, MDP_INFRA_MUTEX);
if (WARN_ON(!mm_pdev)) {
ret = -ENODEV;
goto err_return;
}
for (i = 0; i < MDP_PIPE_MAX; i++) {
mdp->mdp_mutex[i] = mtk_mutex_get(&mm_pdev->dev);
if (!mdp->mdp_mutex[i]) {
ret = -ENODEV;
goto err_return;
}
}
ret = mdp_comp_config(mdp);
if (ret) {
dev_err(dev, "Failed to config mdp components\n");
goto err_return;
}
mdp->job_wq = alloc_workqueue(MDP_MODULE_NAME, WQ_FREEZABLE, 0);
if (!mdp->job_wq) {
dev_err(dev, "Unable to create job workqueue\n");
ret = -ENOMEM;
goto err_deinit_comp;
}
mdp->clock_wq = alloc_workqueue(MDP_MODULE_NAME "-clock", WQ_FREEZABLE,
0);
if (!mdp->clock_wq) {
dev_err(dev, "Unable to create clock workqueue\n");
ret = -ENOMEM;
goto err_destroy_job_wq;
}
mm_pdev = __get_pdev_by_id(pdev, MDP_INFRA_SCP);
if (WARN_ON(!mm_pdev)) {
dev_err(&pdev->dev, "Could not get scp device\n");
ret = -ENODEV;
goto err_destroy_clock_wq;
}
mdp->scp = platform_get_drvdata(mm_pdev);
mdp->rproc_handle = scp_get_rproc(mdp->scp);
dev_dbg(&pdev->dev, "MDP rproc_handle: %pK", mdp->rproc_handle);
mutex_init(&mdp->vpu_lock);
mutex_init(&mdp->m2m_lock);
mdp->cmdq_clt = cmdq_mbox_create(dev, 0);
if (IS_ERR(mdp->cmdq_clt)) {
ret = PTR_ERR(mdp->cmdq_clt);
goto err_put_scp;
}
init_waitqueue_head(&mdp->callback_wq);
ida_init(&mdp->mdp_ida);
platform_set_drvdata(pdev, mdp);
vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32));
ret = v4l2_device_register(dev, &mdp->v4l2_dev);
if (ret) {
dev_err(dev, "Failed to register v4l2 device\n");
ret = -EINVAL;
goto err_mbox_destroy;
}
ret = mdp_m2m_device_register(mdp);
if (ret) {
v4l2_err(&mdp->v4l2_dev, "Failed to register m2m device\n");
goto err_unregister_device;
}
dev_dbg(dev, "mdp-%d registered successfully\n", pdev->id);
return 0;
err_unregister_device:
v4l2_device_unregister(&mdp->v4l2_dev);
err_mbox_destroy:
cmdq_mbox_destroy(mdp->cmdq_clt);
err_put_scp:
scp_put(mdp->scp);
err_destroy_clock_wq:
destroy_workqueue(mdp->clock_wq);
err_destroy_job_wq:
destroy_workqueue(mdp->job_wq);
err_deinit_comp:
mdp_comp_destroy(mdp);
err_return:
for (i = 0; i < MDP_PIPE_MAX; i++)
mtk_mutex_put(mdp->mdp_mutex[i]);
kfree(mdp);
dev_dbg(dev, "Errno %d\n", ret);
return ret;
}
static int mdp_remove(struct platform_device *pdev)
{
struct mdp_dev *mdp = platform_get_drvdata(pdev);
v4l2_device_unregister(&mdp->v4l2_dev);
dev_dbg(&pdev->dev, "%s driver unloaded\n", pdev->name);
return 0;
}
static int __maybe_unused mdp_suspend(struct device *dev)
{
struct mdp_dev *mdp = dev_get_drvdata(dev);
int ret;
atomic_set(&mdp->suspended, 1);
if (atomic_read(&mdp->job_count)) {
ret = wait_event_timeout(mdp->callback_wq,
!atomic_read(&mdp->job_count),
2 * HZ);
if (ret == 0) {
dev_err(dev,
"%s:flushed cmdq task incomplete, count=%d\n",
__func__, atomic_read(&mdp->job_count));
return -EBUSY;
}
}
return 0;
}
static int __maybe_unused mdp_resume(struct device *dev)
{
struct mdp_dev *mdp = dev_get_drvdata(dev);
atomic_set(&mdp->suspended, 0);
return 0;
}
static const struct dev_pm_ops mdp_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(mdp_suspend, mdp_resume)
};
static struct platform_driver mdp_driver = {
.probe = mdp_probe,
.remove = mdp_remove,
.driver = {
.name = MDP_MODULE_NAME,
.pm = &mdp_pm_ops,
.of_match_table = of_match_ptr(mdp_of_ids),
},
};
module_platform_driver(mdp_driver);
MODULE_AUTHOR("Ping-Hsun Wu <ping-hsun.wu@mediatek.com>");
MODULE_DESCRIPTION("MediaTek image processor 3 driver");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,94 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2022 MediaTek Inc.
* Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
*/
#ifndef __MTK_MDP3_CORE_H__
#define __MTK_MDP3_CORE_H__
#include <media/v4l2-device.h>
#include <media/v4l2-mem2mem.h>
#include <linux/soc/mediatek/mtk-mmsys.h>
#include <linux/soc/mediatek/mtk-mutex.h>
#include "mtk-mdp3-comp.h"
#include "mtk-mdp3-vpu.h"
#define MDP_MODULE_NAME "mtk-mdp3"
#define MDP_DEVICE_NAME "MediaTek MDP3"
#define MDP_PHANDLE_NAME "mediatek,mdp3"
enum mdp_infra_id {
MDP_INFRA_MMSYS,
MDP_INFRA_MUTEX,
MDP_INFRA_SCP,
MDP_INFRA_MAX
};
enum mdp_buffer_usage {
MDP_BUFFER_USAGE_HW_READ,
MDP_BUFFER_USAGE_MDP,
MDP_BUFFER_USAGE_MDP2,
MDP_BUFFER_USAGE_ISP,
MDP_BUFFER_USAGE_WPE,
};
struct mdp_platform_config {
bool rdma_support_10bit;
bool rdma_rsz1_sram_sharing;
bool rdma_upsample_repeat_only;
bool rsz_disable_dcm_small_sample;
bool wrot_filter_constraint;
};
/* indicate which mutex is used by each pipepline */
enum mdp_pipe_id {
MDP_PIPE_RDMA0,
MDP_PIPE_IMGI,
MDP_PIPE_WPEI,
MDP_PIPE_WPEI2,
MDP_PIPE_MAX
};
struct mtk_mdp_driver_data {
const struct of_device_id *mdp_probe_infra;
const struct mdp_platform_config *mdp_cfg;
const u32 *mdp_mutex_table_idx;
};
struct mdp_dev {
struct platform_device *pdev;
struct device *mdp_mmsys;
struct mtk_mutex *mdp_mutex[MDP_PIPE_MAX];
struct mdp_comp *comp[MDP_MAX_COMP_COUNT];
const struct mtk_mdp_driver_data *mdp_data;
struct workqueue_struct *job_wq;
struct workqueue_struct *clock_wq;
struct mdp_vpu_dev vpu;
struct mtk_scp *scp;
struct rproc *rproc_handle;
/* synchronization protect for accessing vpu working buffer info */
struct mutex vpu_lock;
s32 vpu_count;
u32 id_count;
struct ida mdp_ida;
struct cmdq_client *cmdq_clt;
wait_queue_head_t callback_wq;
struct v4l2_device v4l2_dev;
struct video_device *m2m_vdev;
struct v4l2_m2m_dev *m2m_dev;
/* synchronization protect for m2m device operation */
struct mutex m2m_lock;
atomic_t suspended;
atomic_t job_count;
};
int mdp_vpu_get_locked(struct mdp_dev *mdp);
void mdp_vpu_put_locked(struct mdp_dev *mdp);
int mdp_vpu_register(struct mdp_dev *mdp);
void mdp_vpu_unregister(struct mdp_dev *mdp);
void mdp_video_device_release(struct video_device *vdev);
#endif /* __MTK_MDP3_CORE_H__ */

View file

@ -0,0 +1,724 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2022 MediaTek Inc.
* Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
*/
#include <linux/platform_device.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-event.h>
#include <media/videobuf2-dma-contig.h>
#include "mtk-mdp3-m2m.h"
static inline struct mdp_m2m_ctx *fh_to_ctx(struct v4l2_fh *fh)
{
return container_of(fh, struct mdp_m2m_ctx, fh);
}
static inline struct mdp_m2m_ctx *ctrl_to_ctx(struct v4l2_ctrl *ctrl)
{
return container_of(ctrl->handler, struct mdp_m2m_ctx, ctrl_handler);
}
static inline struct mdp_frame *ctx_get_frame(struct mdp_m2m_ctx *ctx,
enum v4l2_buf_type type)
{
if (V4L2_TYPE_IS_OUTPUT(type))
return &ctx->curr_param.output;
else
return &ctx->curr_param.captures[0];
}
static inline void mdp_m2m_ctx_set_state(struct mdp_m2m_ctx *ctx, u32 state)
{
atomic_or(state, &ctx->curr_param.state);
}
static inline bool mdp_m2m_ctx_is_state_set(struct mdp_m2m_ctx *ctx, u32 mask)
{
return ((atomic_read(&ctx->curr_param.state) & mask) == mask);
}
static void mdp_m2m_process_done(void *priv, int vb_state)
{
struct mdp_m2m_ctx *ctx = priv;
struct vb2_v4l2_buffer *src_vbuf, *dst_vbuf;
src_vbuf = (struct vb2_v4l2_buffer *)
v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
dst_vbuf = (struct vb2_v4l2_buffer *)
v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
ctx->curr_param.frame_no = ctx->frame_count[MDP_M2M_SRC];
src_vbuf->sequence = ctx->frame_count[MDP_M2M_SRC]++;
dst_vbuf->sequence = ctx->frame_count[MDP_M2M_DST]++;
v4l2_m2m_buf_copy_metadata(src_vbuf, dst_vbuf, true);
v4l2_m2m_buf_done(src_vbuf, vb_state);
v4l2_m2m_buf_done(dst_vbuf, vb_state);
v4l2_m2m_job_finish(ctx->mdp_dev->m2m_dev, ctx->m2m_ctx);
}
static void mdp_m2m_device_run(void *priv)
{
struct mdp_m2m_ctx *ctx = priv;
struct mdp_frame *frame;
struct vb2_v4l2_buffer *src_vb, *dst_vb;
struct img_ipi_frameparam param = {};
struct mdp_cmdq_param task = {};
enum vb2_buffer_state vb_state = VB2_BUF_STATE_ERROR;
int ret;
if (mdp_m2m_ctx_is_state_set(ctx, MDP_M2M_CTX_ERROR)) {
dev_err(&ctx->mdp_dev->pdev->dev,
"mdp_m2m_ctx is in error state\n");
goto worker_end;
}
param.frame_no = ctx->curr_param.frame_no;
param.type = ctx->curr_param.type;
param.num_inputs = 1;
param.num_outputs = 1;
frame = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
src_vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
mdp_set_src_config(&param.inputs[0], frame, &src_vb->vb2_buf);
frame = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
dst_vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
mdp_set_dst_config(&param.outputs[0], frame, &dst_vb->vb2_buf);
ret = mdp_vpu_process(&ctx->vpu, &param);
if (ret) {
dev_err(&ctx->mdp_dev->pdev->dev,
"VPU MDP process failed: %d\n", ret);
goto worker_end;
}
task.config = ctx->vpu.config;
task.param = &param;
task.composes[0] = &frame->compose;
task.cmdq_cb = NULL;
task.cb_data = NULL;
task.mdp_ctx = ctx;
ret = mdp_cmdq_send(ctx->mdp_dev, &task);
if (ret) {
dev_err(&ctx->mdp_dev->pdev->dev,
"CMDQ sendtask failed: %d\n", ret);
goto worker_end;
}
return;
worker_end:
mdp_m2m_process_done(ctx, vb_state);
}
static int mdp_m2m_start_streaming(struct vb2_queue *q, unsigned int count)
{
struct mdp_m2m_ctx *ctx = vb2_get_drv_priv(q);
struct mdp_frame *capture;
struct vb2_queue *vq;
int ret;
bool out_streaming, cap_streaming;
if (V4L2_TYPE_IS_OUTPUT(q->type))
ctx->frame_count[MDP_M2M_SRC] = 0;
if (V4L2_TYPE_IS_CAPTURE(q->type))
ctx->frame_count[MDP_M2M_DST] = 0;
capture = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
vq = v4l2_m2m_get_src_vq(ctx->m2m_ctx);
out_streaming = vb2_is_streaming(vq);
vq = v4l2_m2m_get_dst_vq(ctx->m2m_ctx);
cap_streaming = vb2_is_streaming(vq);
/* Check to see if scaling ratio is within supported range */
if ((V4L2_TYPE_IS_OUTPUT(q->type) && cap_streaming) ||
(V4L2_TYPE_IS_CAPTURE(q->type) && out_streaming)) {
ret = mdp_check_scaling_ratio(&capture->crop.c,
&capture->compose,
capture->rotation,
ctx->curr_param.limit);
if (ret) {
dev_err(&ctx->mdp_dev->pdev->dev,
"Out of scaling range\n");
return ret;
}
}
if (!mdp_m2m_ctx_is_state_set(ctx, MDP_VPU_INIT)) {
ret = mdp_vpu_get_locked(ctx->mdp_dev);
if (ret)
return ret;
ret = mdp_vpu_ctx_init(&ctx->vpu, &ctx->mdp_dev->vpu,
MDP_DEV_M2M);
if (ret) {
dev_err(&ctx->mdp_dev->pdev->dev,
"VPU init failed %d\n", ret);
return -EINVAL;
}
mdp_m2m_ctx_set_state(ctx, MDP_VPU_INIT);
}
return 0;
}
static struct vb2_v4l2_buffer *mdp_m2m_buf_remove(struct mdp_m2m_ctx *ctx,
unsigned int type)
{
if (V4L2_TYPE_IS_OUTPUT(type))
return (struct vb2_v4l2_buffer *)
v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
else
return (struct vb2_v4l2_buffer *)
v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
}
static void mdp_m2m_stop_streaming(struct vb2_queue *q)
{
struct mdp_m2m_ctx *ctx = vb2_get_drv_priv(q);
struct vb2_v4l2_buffer *vb;
vb = mdp_m2m_buf_remove(ctx, q->type);
while (vb) {
v4l2_m2m_buf_done(vb, VB2_BUF_STATE_ERROR);
vb = mdp_m2m_buf_remove(ctx, q->type);
}
}
static int mdp_m2m_queue_setup(struct vb2_queue *q,
unsigned int *num_buffers,
unsigned int *num_planes, unsigned int sizes[],
struct device *alloc_devs[])
{
struct mdp_m2m_ctx *ctx = vb2_get_drv_priv(q);
struct v4l2_pix_format_mplane *pix_mp;
u32 i;
pix_mp = &ctx_get_frame(ctx, q->type)->format.fmt.pix_mp;
/* from VIDIOC_CREATE_BUFS */
if (*num_planes) {
if (*num_planes != pix_mp->num_planes)
return -EINVAL;
for (i = 0; i < pix_mp->num_planes; ++i)
if (sizes[i] < pix_mp->plane_fmt[i].sizeimage)
return -EINVAL;
} else {/* from VIDIOC_REQBUFS */
*num_planes = pix_mp->num_planes;
for (i = 0; i < pix_mp->num_planes; ++i)
sizes[i] = pix_mp->plane_fmt[i].sizeimage;
}
return 0;
}
static int mdp_m2m_buf_prepare(struct vb2_buffer *vb)
{
struct mdp_m2m_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
struct v4l2_pix_format_mplane *pix_mp;
struct vb2_v4l2_buffer *v4l2_buf = to_vb2_v4l2_buffer(vb);
u32 i;
v4l2_buf->field = V4L2_FIELD_NONE;
if (V4L2_TYPE_IS_CAPTURE(vb->type)) {
pix_mp = &ctx_get_frame(ctx, vb->type)->format.fmt.pix_mp;
for (i = 0; i < pix_mp->num_planes; ++i) {
vb2_set_plane_payload(vb, i,
pix_mp->plane_fmt[i].sizeimage);
}
}
return 0;
}
static int mdp_m2m_buf_out_validate(struct vb2_buffer *vb)
{
struct vb2_v4l2_buffer *v4l2_buf = to_vb2_v4l2_buffer(vb);
v4l2_buf->field = V4L2_FIELD_NONE;
return 0;
}
static void mdp_m2m_buf_queue(struct vb2_buffer *vb)
{
struct mdp_m2m_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
struct vb2_v4l2_buffer *v4l2_buf = to_vb2_v4l2_buffer(vb);
v4l2_buf->field = V4L2_FIELD_NONE;
v4l2_m2m_buf_queue(ctx->m2m_ctx, to_vb2_v4l2_buffer(vb));
}
static const struct vb2_ops mdp_m2m_qops = {
.queue_setup = mdp_m2m_queue_setup,
.wait_prepare = vb2_ops_wait_prepare,
.wait_finish = vb2_ops_wait_finish,
.buf_prepare = mdp_m2m_buf_prepare,
.start_streaming = mdp_m2m_start_streaming,
.stop_streaming = mdp_m2m_stop_streaming,
.buf_queue = mdp_m2m_buf_queue,
.buf_out_validate = mdp_m2m_buf_out_validate,
};
static int mdp_m2m_querycap(struct file *file, void *fh,
struct v4l2_capability *cap)
{
strscpy(cap->driver, MDP_MODULE_NAME, sizeof(cap->driver));
strscpy(cap->card, MDP_DEVICE_NAME, sizeof(cap->card));
return 0;
}
static int mdp_m2m_enum_fmt_mplane(struct file *file, void *fh,
struct v4l2_fmtdesc *f)
{
return mdp_enum_fmt_mplane(f);
}
static int mdp_m2m_g_fmt_mplane(struct file *file, void *fh,
struct v4l2_format *f)
{
struct mdp_m2m_ctx *ctx = fh_to_ctx(fh);
struct mdp_frame *frame;
struct v4l2_pix_format_mplane *pix_mp;
frame = ctx_get_frame(ctx, f->type);
*f = frame->format;
pix_mp = &f->fmt.pix_mp;
pix_mp->colorspace = ctx->curr_param.colorspace;
pix_mp->xfer_func = ctx->curr_param.xfer_func;
pix_mp->ycbcr_enc = ctx->curr_param.ycbcr_enc;
pix_mp->quantization = ctx->curr_param.quant;
return 0;
}
static int mdp_m2m_s_fmt_mplane(struct file *file, void *fh,
struct v4l2_format *f)
{
struct mdp_m2m_ctx *ctx = fh_to_ctx(fh);
struct mdp_frame *frame = ctx_get_frame(ctx, f->type);
struct mdp_frame *capture;
const struct mdp_format *fmt;
struct vb2_queue *vq;
fmt = mdp_try_fmt_mplane(f, &ctx->curr_param, ctx->id);
if (!fmt)
return -EINVAL;
vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
if (vb2_is_busy(vq))
return -EBUSY;
frame->format = *f;
frame->mdp_fmt = fmt;
frame->ycbcr_prof = mdp_map_ycbcr_prof_mplane(f, fmt->mdp_color);
frame->usage = V4L2_TYPE_IS_OUTPUT(f->type) ?
MDP_BUFFER_USAGE_HW_READ : MDP_BUFFER_USAGE_MDP;
capture = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
if (V4L2_TYPE_IS_OUTPUT(f->type)) {
capture->crop.c.left = 0;
capture->crop.c.top = 0;
capture->crop.c.width = f->fmt.pix_mp.width;
capture->crop.c.height = f->fmt.pix_mp.height;
ctx->curr_param.colorspace = f->fmt.pix_mp.colorspace;
ctx->curr_param.ycbcr_enc = f->fmt.pix_mp.ycbcr_enc;
ctx->curr_param.quant = f->fmt.pix_mp.quantization;
ctx->curr_param.xfer_func = f->fmt.pix_mp.xfer_func;
} else {
capture->compose.left = 0;
capture->compose.top = 0;
capture->compose.width = f->fmt.pix_mp.width;
capture->compose.height = f->fmt.pix_mp.height;
}
return 0;
}
static int mdp_m2m_try_fmt_mplane(struct file *file, void *fh,
struct v4l2_format *f)
{
struct mdp_m2m_ctx *ctx = fh_to_ctx(fh);
if (!mdp_try_fmt_mplane(f, &ctx->curr_param, ctx->id))
return -EINVAL;
return 0;
}
static int mdp_m2m_g_selection(struct file *file, void *fh,
struct v4l2_selection *s)
{
struct mdp_m2m_ctx *ctx = fh_to_ctx(fh);
struct mdp_frame *frame;
bool valid = false;
if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
valid = mdp_target_is_crop(s->target);
else if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
valid = mdp_target_is_compose(s->target);
if (!valid)
return -EINVAL;
switch (s->target) {
case V4L2_SEL_TGT_CROP:
if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
return -EINVAL;
frame = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
s->r = frame->crop.c;
return 0;
case V4L2_SEL_TGT_COMPOSE:
if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
frame = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
s->r = frame->compose;
return 0;
case V4L2_SEL_TGT_CROP_DEFAULT:
case V4L2_SEL_TGT_CROP_BOUNDS:
if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
return -EINVAL;
frame = ctx_get_frame(ctx, s->type);
s->r.left = 0;
s->r.top = 0;
s->r.width = frame->format.fmt.pix_mp.width;
s->r.height = frame->format.fmt.pix_mp.height;
return 0;
case V4L2_SEL_TGT_COMPOSE_DEFAULT:
case V4L2_SEL_TGT_COMPOSE_BOUNDS:
if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
frame = ctx_get_frame(ctx, s->type);
s->r.left = 0;
s->r.top = 0;
s->r.width = frame->format.fmt.pix_mp.width;
s->r.height = frame->format.fmt.pix_mp.height;
return 0;
}
return -EINVAL;
}
static int mdp_m2m_s_selection(struct file *file, void *fh,
struct v4l2_selection *s)
{
struct mdp_m2m_ctx *ctx = fh_to_ctx(fh);
struct mdp_frame *frame = ctx_get_frame(ctx, s->type);
struct mdp_frame *capture;
struct v4l2_rect r;
struct device *dev = &ctx->mdp_dev->pdev->dev;
bool valid = false;
int ret;
if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
valid = (s->target == V4L2_SEL_TGT_CROP);
else if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
valid = (s->target == V4L2_SEL_TGT_COMPOSE);
if (!valid) {
dev_dbg(dev, "[%s:%d] invalid type:%u target:%u", __func__,
ctx->id, s->type, s->target);
return -EINVAL;
}
ret = mdp_try_crop(ctx, &r, s, frame);
if (ret)
return ret;
capture = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
if (mdp_target_is_crop(s->target))
capture->crop.c = r;
else
capture->compose = r;
s->r = r;
return 0;
}
static const struct v4l2_ioctl_ops mdp_m2m_ioctl_ops = {
.vidioc_querycap = mdp_m2m_querycap,
.vidioc_enum_fmt_vid_cap = mdp_m2m_enum_fmt_mplane,
.vidioc_enum_fmt_vid_out = mdp_m2m_enum_fmt_mplane,
.vidioc_g_fmt_vid_cap_mplane = mdp_m2m_g_fmt_mplane,
.vidioc_g_fmt_vid_out_mplane = mdp_m2m_g_fmt_mplane,
.vidioc_s_fmt_vid_cap_mplane = mdp_m2m_s_fmt_mplane,
.vidioc_s_fmt_vid_out_mplane = mdp_m2m_s_fmt_mplane,
.vidioc_try_fmt_vid_cap_mplane = mdp_m2m_try_fmt_mplane,
.vidioc_try_fmt_vid_out_mplane = mdp_m2m_try_fmt_mplane,
.vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
.vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
.vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
.vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
.vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
.vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
.vidioc_streamon = v4l2_m2m_ioctl_streamon,
.vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
.vidioc_g_selection = mdp_m2m_g_selection,
.vidioc_s_selection = mdp_m2m_s_selection,
.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
static int mdp_m2m_queue_init(void *priv,
struct vb2_queue *src_vq,
struct vb2_queue *dst_vq)
{
struct mdp_m2m_ctx *ctx = priv;
int ret;
src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
src_vq->ops = &mdp_m2m_qops;
src_vq->mem_ops = &vb2_dma_contig_memops;
src_vq->drv_priv = ctx;
src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
src_vq->dev = &ctx->mdp_dev->pdev->dev;
src_vq->lock = &ctx->ctx_lock;
ret = vb2_queue_init(src_vq);
if (ret)
return ret;
dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
dst_vq->ops = &mdp_m2m_qops;
dst_vq->mem_ops = &vb2_dma_contig_memops;
dst_vq->drv_priv = ctx;
dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
dst_vq->dev = &ctx->mdp_dev->pdev->dev;
dst_vq->lock = &ctx->ctx_lock;
return vb2_queue_init(dst_vq);
}
static int mdp_m2m_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct mdp_m2m_ctx *ctx = ctrl_to_ctx(ctrl);
struct mdp_frame *capture;
capture = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
switch (ctrl->id) {
case V4L2_CID_HFLIP:
capture->hflip = ctrl->val;
break;
case V4L2_CID_VFLIP:
capture->vflip = ctrl->val;
break;
case V4L2_CID_ROTATE:
capture->rotation = ctrl->val;
break;
}
return 0;
}
static const struct v4l2_ctrl_ops mdp_m2m_ctrl_ops = {
.s_ctrl = mdp_m2m_s_ctrl,
};
static int mdp_m2m_ctrls_create(struct mdp_m2m_ctx *ctx)
{
v4l2_ctrl_handler_init(&ctx->ctrl_handler, MDP_MAX_CTRLS);
ctx->ctrls.hflip = v4l2_ctrl_new_std(&ctx->ctrl_handler,
&mdp_m2m_ctrl_ops, V4L2_CID_HFLIP,
0, 1, 1, 0);
ctx->ctrls.vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler,
&mdp_m2m_ctrl_ops, V4L2_CID_VFLIP,
0, 1, 1, 0);
ctx->ctrls.rotate = v4l2_ctrl_new_std(&ctx->ctrl_handler,
&mdp_m2m_ctrl_ops,
V4L2_CID_ROTATE, 0, 270, 90, 0);
if (ctx->ctrl_handler.error) {
int err = ctx->ctrl_handler.error;
v4l2_ctrl_handler_free(&ctx->ctrl_handler);
dev_err(&ctx->mdp_dev->pdev->dev,
"Failed to register controls\n");
return err;
}
return 0;
}
static int mdp_m2m_open(struct file *file)
{
struct video_device *vdev = video_devdata(file);
struct mdp_dev *mdp = video_get_drvdata(vdev);
struct mdp_m2m_ctx *ctx;
struct device *dev = &mdp->pdev->dev;
int ret;
struct v4l2_format default_format = {};
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
if (mutex_lock_interruptible(&mdp->m2m_lock)) {
ret = -ERESTARTSYS;
goto err_free_ctx;
}
ctx->id = ida_alloc(&mdp->mdp_ida, GFP_KERNEL);
ctx->mdp_dev = mdp;
v4l2_fh_init(&ctx->fh, vdev);
file->private_data = &ctx->fh;
ret = mdp_m2m_ctrls_create(ctx);
if (ret)
goto err_exit_fh;
/* Use separate control handler per file handle */
ctx->fh.ctrl_handler = &ctx->ctrl_handler;
v4l2_fh_add(&ctx->fh);
mutex_init(&ctx->ctx_lock);
ctx->m2m_ctx = v4l2_m2m_ctx_init(mdp->m2m_dev, ctx, mdp_m2m_queue_init);
if (IS_ERR(ctx->m2m_ctx)) {
dev_err(dev, "Failed to initialize m2m context\n");
ret = PTR_ERR(ctx->m2m_ctx);
goto err_release_handler;
}
ctx->fh.m2m_ctx = ctx->m2m_ctx;
ctx->curr_param.ctx = ctx;
ret = mdp_frameparam_init(&ctx->curr_param);
if (ret) {
dev_err(dev, "Failed to initialize mdp parameter\n");
goto err_release_m2m_ctx;
}
mutex_unlock(&mdp->m2m_lock);
/* Default format */
default_format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
default_format.fmt.pix_mp.width = 32;
default_format.fmt.pix_mp.height = 32;
default_format.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_YUV420M;
mdp_m2m_s_fmt_mplane(file, &ctx->fh, &default_format);
default_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
mdp_m2m_s_fmt_mplane(file, &ctx->fh, &default_format);
dev_dbg(dev, "%s:[%d]", __func__, ctx->id);
return 0;
err_release_m2m_ctx:
v4l2_m2m_ctx_release(ctx->m2m_ctx);
err_release_handler:
v4l2_ctrl_handler_free(&ctx->ctrl_handler);
v4l2_fh_del(&ctx->fh);
err_exit_fh:
v4l2_fh_exit(&ctx->fh);
mutex_unlock(&mdp->m2m_lock);
err_free_ctx:
kfree(ctx);
return ret;
}
static int mdp_m2m_release(struct file *file)
{
struct mdp_m2m_ctx *ctx = fh_to_ctx(file->private_data);
struct mdp_dev *mdp = video_drvdata(file);
struct device *dev = &mdp->pdev->dev;
mutex_lock(&mdp->m2m_lock);
v4l2_m2m_ctx_release(ctx->m2m_ctx);
if (mdp_m2m_ctx_is_state_set(ctx, MDP_VPU_INIT)) {
mdp_vpu_ctx_deinit(&ctx->vpu);
mdp_vpu_put_locked(mdp);
}
v4l2_ctrl_handler_free(&ctx->ctrl_handler);
v4l2_fh_del(&ctx->fh);
v4l2_fh_exit(&ctx->fh);
ida_free(&mdp->mdp_ida, ctx->id);
mutex_unlock(&mdp->m2m_lock);
dev_dbg(dev, "%s:[%d]", __func__, ctx->id);
kfree(ctx);
return 0;
}
static const struct v4l2_file_operations mdp_m2m_fops = {
.owner = THIS_MODULE,
.poll = v4l2_m2m_fop_poll,
.unlocked_ioctl = video_ioctl2,
.mmap = v4l2_m2m_fop_mmap,
.open = mdp_m2m_open,
.release = mdp_m2m_release,
};
static const struct v4l2_m2m_ops mdp_m2m_ops = {
.device_run = mdp_m2m_device_run,
};
int mdp_m2m_device_register(struct mdp_dev *mdp)
{
struct device *dev = &mdp->pdev->dev;
int ret = 0;
mdp->m2m_vdev = video_device_alloc();
if (!mdp->m2m_vdev) {
dev_err(dev, "Failed to allocate video device\n");
ret = -ENOMEM;
goto err_video_alloc;
}
mdp->m2m_vdev->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE |
V4L2_CAP_STREAMING;
mdp->m2m_vdev->fops = &mdp_m2m_fops;
mdp->m2m_vdev->ioctl_ops = &mdp_m2m_ioctl_ops;
mdp->m2m_vdev->release = mdp_video_device_release;
mdp->m2m_vdev->lock = &mdp->m2m_lock;
mdp->m2m_vdev->vfl_dir = VFL_DIR_M2M;
mdp->m2m_vdev->v4l2_dev = &mdp->v4l2_dev;
snprintf(mdp->m2m_vdev->name, sizeof(mdp->m2m_vdev->name), "%s:m2m",
MDP_MODULE_NAME);
video_set_drvdata(mdp->m2m_vdev, mdp);
mdp->m2m_dev = v4l2_m2m_init(&mdp_m2m_ops);
if (IS_ERR(mdp->m2m_dev)) {
dev_err(dev, "Failed to initialize v4l2-m2m device\n");
ret = PTR_ERR(mdp->m2m_dev);
goto err_m2m_init;
}
ret = video_register_device(mdp->m2m_vdev, VFL_TYPE_VIDEO, -1);
if (ret) {
dev_err(dev, "Failed to register video device\n");
goto err_video_register;
}
v4l2_info(&mdp->v4l2_dev, "Driver registered as /dev/video%d",
mdp->m2m_vdev->num);
return 0;
err_video_register:
v4l2_m2m_release(mdp->m2m_dev);
err_m2m_init:
video_device_release(mdp->m2m_vdev);
err_video_alloc:
return ret;
}
void mdp_m2m_device_unregister(struct mdp_dev *mdp)
{
video_unregister_device(mdp->m2m_vdev);
}
void mdp_m2m_job_finish(struct mdp_m2m_ctx *ctx)
{
enum vb2_buffer_state vb_state = VB2_BUF_STATE_DONE;
mdp_m2m_process_done(ctx, vb_state);
}

View file

@ -0,0 +1,48 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2022 MediaTek Inc.
* Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
*/
#ifndef __MTK_MDP3_M2M_H__
#define __MTK_MDP3_M2M_H__
#include <media/v4l2-ctrls.h>
#include "mtk-mdp3-core.h"
#include "mtk-mdp3-vpu.h"
#include "mtk-mdp3-regs.h"
#define MDP_MAX_CTRLS 10
enum {
MDP_M2M_SRC = 0,
MDP_M2M_DST = 1,
MDP_M2M_MAX,
};
struct mdp_m2m_ctrls {
struct v4l2_ctrl *hflip;
struct v4l2_ctrl *vflip;
struct v4l2_ctrl *rotate;
};
struct mdp_m2m_ctx {
u32 id;
struct mdp_dev *mdp_dev;
struct v4l2_fh fh;
struct v4l2_ctrl_handler ctrl_handler;
struct mdp_m2m_ctrls ctrls;
struct v4l2_m2m_ctx *m2m_ctx;
struct mdp_vpu_ctx vpu;
u32 frame_count[MDP_M2M_MAX];
struct mdp_frameparam curr_param;
/* synchronization protect for mdp m2m context */
struct mutex ctx_lock;
};
int mdp_m2m_device_register(struct mdp_dev *mdp);
void mdp_m2m_device_unregister(struct mdp_dev *mdp);
void mdp_m2m_job_finish(struct mdp_m2m_ctx *ctx);
#endif /* __MTK_MDP3_M2M_H__ */

View file

@ -0,0 +1,735 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2022 MediaTek Inc.
* Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
*/
#include <media/v4l2-common.h>
#include <media/videobuf2-v4l2.h>
#include <media/videobuf2-dma-contig.h>
#include "mtk-mdp3-core.h"
#include "mtk-mdp3-regs.h"
#include "mtk-mdp3-m2m.h"
/*
* All 10-bit related formats are not added in the basic format list,
* please add the corresponding format settings before use.
*/
static const struct mdp_format mdp_formats[] = {
{
.pixelformat = V4L2_PIX_FMT_GREY,
.mdp_color = MDP_COLOR_GREY,
.depth = { 8 },
.row_depth = { 8 },
.num_planes = 1,
.flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
}, {
.pixelformat = V4L2_PIX_FMT_RGB565X,
.mdp_color = MDP_COLOR_BGR565,
.depth = { 16 },
.row_depth = { 16 },
.num_planes = 1,
.flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
}, {
.pixelformat = V4L2_PIX_FMT_RGB565,
.mdp_color = MDP_COLOR_RGB565,
.depth = { 16 },
.row_depth = { 16 },
.num_planes = 1,
.flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
}, {
.pixelformat = V4L2_PIX_FMT_RGB24,
.mdp_color = MDP_COLOR_RGB888,
.depth = { 24 },
.row_depth = { 24 },
.num_planes = 1,
.flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
}, {
.pixelformat = V4L2_PIX_FMT_BGR24,
.mdp_color = MDP_COLOR_BGR888,
.depth = { 24 },
.row_depth = { 24 },
.num_planes = 1,
.flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
}, {
.pixelformat = V4L2_PIX_FMT_ABGR32,
.mdp_color = MDP_COLOR_BGRA8888,
.depth = { 32 },
.row_depth = { 32 },
.num_planes = 1,
.flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
}, {
.pixelformat = V4L2_PIX_FMT_ARGB32,
.mdp_color = MDP_COLOR_ARGB8888,
.depth = { 32 },
.row_depth = { 32 },
.num_planes = 1,
.flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
}, {
.pixelformat = V4L2_PIX_FMT_UYVY,
.mdp_color = MDP_COLOR_UYVY,
.depth = { 16 },
.row_depth = { 16 },
.num_planes = 1,
.walign = 1,
.flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
}, {
.pixelformat = V4L2_PIX_FMT_VYUY,
.mdp_color = MDP_COLOR_VYUY,
.depth = { 16 },
.row_depth = { 16 },
.num_planes = 1,
.walign = 1,
.flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
}, {
.pixelformat = V4L2_PIX_FMT_YUYV,
.mdp_color = MDP_COLOR_YUYV,
.depth = { 16 },
.row_depth = { 16 },
.num_planes = 1,
.walign = 1,
.flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
}, {
.pixelformat = V4L2_PIX_FMT_YVYU,
.mdp_color = MDP_COLOR_YVYU,
.depth = { 16 },
.row_depth = { 16 },
.num_planes = 1,
.walign = 1,
.flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
}, {
.pixelformat = V4L2_PIX_FMT_YUV420,
.mdp_color = MDP_COLOR_I420,
.depth = { 12 },
.row_depth = { 8 },
.num_planes = 1,
.walign = 1,
.halign = 1,
.flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
}, {
.pixelformat = V4L2_PIX_FMT_YVU420,
.mdp_color = MDP_COLOR_YV12,
.depth = { 12 },
.row_depth = { 8 },
.num_planes = 1,
.walign = 1,
.halign = 1,
.flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
}, {
.pixelformat = V4L2_PIX_FMT_NV12,
.mdp_color = MDP_COLOR_NV12,
.depth = { 12 },
.row_depth = { 8 },
.num_planes = 1,
.walign = 1,
.halign = 1,
.flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
}, {
.pixelformat = V4L2_PIX_FMT_NV21,
.mdp_color = MDP_COLOR_NV21,
.depth = { 12 },
.row_depth = { 8 },
.num_planes = 1,
.walign = 1,
.halign = 1,
.flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
}, {
.pixelformat = V4L2_PIX_FMT_NV16,
.mdp_color = MDP_COLOR_NV16,
.depth = { 16 },
.row_depth = { 8 },
.num_planes = 1,
.walign = 1,
.flags = MDP_FMT_FLAG_OUTPUT,
}, {
.pixelformat = V4L2_PIX_FMT_NV61,
.mdp_color = MDP_COLOR_NV61,
.depth = { 16 },
.row_depth = { 8 },
.num_planes = 1,
.walign = 1,
.flags = MDP_FMT_FLAG_OUTPUT,
}, {
.pixelformat = V4L2_PIX_FMT_NV24,
.mdp_color = MDP_COLOR_NV24,
.depth = { 24 },
.row_depth = { 8 },
.num_planes = 1,
.flags = MDP_FMT_FLAG_OUTPUT,
}, {
.pixelformat = V4L2_PIX_FMT_NV42,
.mdp_color = MDP_COLOR_NV42,
.depth = { 24 },
.row_depth = { 8 },
.num_planes = 1,
.flags = MDP_FMT_FLAG_OUTPUT,
}, {
.pixelformat = V4L2_PIX_FMT_MT21C,
.mdp_color = MDP_COLOR_420_BLK_UFO,
.depth = { 8, 4 },
.row_depth = { 8, 8 },
.num_planes = 2,
.walign = 4,
.halign = 5,
.flags = MDP_FMT_FLAG_OUTPUT,
}, {
.pixelformat = V4L2_PIX_FMT_MM21,
.mdp_color = MDP_COLOR_420_BLK,
.depth = { 8, 4 },
.row_depth = { 8, 8 },
.num_planes = 2,
.walign = 4,
.halign = 5,
.flags = MDP_FMT_FLAG_OUTPUT,
}, {
.pixelformat = V4L2_PIX_FMT_NV12M,
.mdp_color = MDP_COLOR_NV12,
.depth = { 8, 4 },
.row_depth = { 8, 8 },
.num_planes = 2,
.walign = 1,
.halign = 1,
.flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
}, {
.pixelformat = V4L2_PIX_FMT_NV21M,
.mdp_color = MDP_COLOR_NV21,
.depth = { 8, 4 },
.row_depth = { 8, 8 },
.num_planes = 2,
.walign = 1,
.halign = 1,
.flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
}, {
.pixelformat = V4L2_PIX_FMT_NV16M,
.mdp_color = MDP_COLOR_NV16,
.depth = { 8, 8 },
.row_depth = { 8, 8 },
.num_planes = 2,
.walign = 1,
.flags = MDP_FMT_FLAG_OUTPUT,
}, {
.pixelformat = V4L2_PIX_FMT_NV61M,
.mdp_color = MDP_COLOR_NV61,
.depth = { 8, 8 },
.row_depth = { 8, 8 },
.num_planes = 2,
.walign = 1,
.flags = MDP_FMT_FLAG_OUTPUT,
}, {
.pixelformat = V4L2_PIX_FMT_YUV420M,
.mdp_color = MDP_COLOR_I420,
.depth = { 8, 2, 2 },
.row_depth = { 8, 4, 4 },
.num_planes = 3,
.walign = 1,
.halign = 1,
.flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
}, {
.pixelformat = V4L2_PIX_FMT_YVU420M,
.mdp_color = MDP_COLOR_YV12,
.depth = { 8, 2, 2 },
.row_depth = { 8, 4, 4 },
.num_planes = 3,
.walign = 1,
.halign = 1,
.flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE,
}
};
static const struct mdp_limit mdp_def_limit = {
.out_limit = {
.wmin = 16,
.hmin = 16,
.wmax = 8176,
.hmax = 8176,
},
.cap_limit = {
.wmin = 2,
.hmin = 2,
.wmax = 8176,
.hmax = 8176,
},
.h_scale_up_max = 32,
.v_scale_up_max = 32,
.h_scale_down_max = 20,
.v_scale_down_max = 128,
};
static const struct mdp_format *mdp_find_fmt(u32 pixelformat, u32 type)
{
u32 i, flag;
flag = V4L2_TYPE_IS_OUTPUT(type) ? MDP_FMT_FLAG_OUTPUT :
MDP_FMT_FLAG_CAPTURE;
for (i = 0; i < ARRAY_SIZE(mdp_formats); ++i) {
if (!(mdp_formats[i].flags & flag))
continue;
if (mdp_formats[i].pixelformat == pixelformat)
return &mdp_formats[i];
}
return NULL;
}
static const struct mdp_format *mdp_find_fmt_by_index(u32 index, u32 type)
{
u32 i, flag, num = 0;
flag = V4L2_TYPE_IS_OUTPUT(type) ? MDP_FMT_FLAG_OUTPUT :
MDP_FMT_FLAG_CAPTURE;
for (i = 0; i < ARRAY_SIZE(mdp_formats); ++i) {
if (!(mdp_formats[i].flags & flag))
continue;
if (index == num)
return &mdp_formats[i];
num++;
}
return NULL;
}
enum mdp_ycbcr_profile mdp_map_ycbcr_prof_mplane(struct v4l2_format *f,
u32 mdp_color)
{
struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
if (MDP_COLOR_IS_RGB(mdp_color))
return MDP_YCBCR_PROFILE_FULL_BT601;
switch (pix_mp->colorspace) {
case V4L2_COLORSPACE_JPEG:
return MDP_YCBCR_PROFILE_JPEG;
case V4L2_COLORSPACE_REC709:
case V4L2_COLORSPACE_DCI_P3:
if (pix_mp->quantization == V4L2_QUANTIZATION_FULL_RANGE)
return MDP_YCBCR_PROFILE_FULL_BT709;
return MDP_YCBCR_PROFILE_BT709;
case V4L2_COLORSPACE_BT2020:
if (pix_mp->quantization == V4L2_QUANTIZATION_FULL_RANGE)
return MDP_YCBCR_PROFILE_FULL_BT2020;
return MDP_YCBCR_PROFILE_BT2020;
default:
if (pix_mp->quantization == V4L2_QUANTIZATION_FULL_RANGE)
return MDP_YCBCR_PROFILE_FULL_BT601;
return MDP_YCBCR_PROFILE_BT601;
}
}
static void mdp_bound_align_image(u32 *w, u32 *h,
struct v4l2_frmsize_stepwise *s,
unsigned int salign)
{
unsigned int org_w, org_h;
org_w = *w;
org_h = *h;
v4l_bound_align_image(w, s->min_width, s->max_width, s->step_width,
h, s->min_height, s->max_height, s->step_height,
salign);
s->min_width = org_w;
s->min_height = org_h;
v4l2_apply_frmsize_constraints(w, h, s);
}
static int mdp_clamp_align(s32 *x, int min, int max, unsigned int align)
{
unsigned int mask;
if (min < 0 || max < 0)
return -ERANGE;
/* Bits that must be zero to be aligned */
mask = ~((1 << align) - 1);
min = 0 ? 0 : ((min + ~mask) & mask);
max = max & mask;
if ((unsigned int)min > (unsigned int)max)
return -ERANGE;
/* Clamp to aligned min and max */
*x = clamp(*x, min, max);
/* Round to nearest aligned value */
if (align)
*x = (*x + (1 << (align - 1))) & mask;
return 0;
}
int mdp_enum_fmt_mplane(struct v4l2_fmtdesc *f)
{
const struct mdp_format *fmt;
fmt = mdp_find_fmt_by_index(f->index, f->type);
if (!fmt)
return -EINVAL;
f->pixelformat = fmt->pixelformat;
return 0;
}
const struct mdp_format *mdp_try_fmt_mplane(struct v4l2_format *f,
struct mdp_frameparam *param,
u32 ctx_id)
{
struct device *dev = &param->ctx->mdp_dev->pdev->dev;
struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
const struct mdp_format *fmt;
const struct mdp_pix_limit *pix_limit;
struct v4l2_frmsize_stepwise s;
u32 org_w, org_h;
unsigned int i;
fmt = mdp_find_fmt(pix_mp->pixelformat, f->type);
if (!fmt) {
fmt = mdp_find_fmt_by_index(0, f->type);
if (!fmt) {
dev_dbg(dev, "%d: pixelformat %c%c%c%c invalid", ctx_id,
(pix_mp->pixelformat & 0xff),
(pix_mp->pixelformat >> 8) & 0xff,
(pix_mp->pixelformat >> 16) & 0xff,
(pix_mp->pixelformat >> 24) & 0xff);
return NULL;
}
}
pix_mp->field = V4L2_FIELD_NONE;
pix_mp->flags = 0;
pix_mp->pixelformat = fmt->pixelformat;
if (V4L2_TYPE_IS_CAPTURE(f->type)) {
pix_mp->colorspace = param->colorspace;
pix_mp->xfer_func = param->xfer_func;
pix_mp->ycbcr_enc = param->ycbcr_enc;
pix_mp->quantization = param->quant;
}
pix_limit = V4L2_TYPE_IS_OUTPUT(f->type) ? &param->limit->out_limit :
&param->limit->cap_limit;
s.min_width = pix_limit->wmin;
s.max_width = pix_limit->wmax;
s.step_width = fmt->walign;
s.min_height = pix_limit->hmin;
s.max_height = pix_limit->hmax;
s.step_height = fmt->halign;
org_w = pix_mp->width;
org_h = pix_mp->height;
mdp_bound_align_image(&pix_mp->width, &pix_mp->height, &s, fmt->salign);
if (org_w != pix_mp->width || org_h != pix_mp->height)
dev_dbg(dev, "%d: size change: %ux%u to %ux%u", ctx_id,
org_w, org_h, pix_mp->width, pix_mp->height);
if (pix_mp->num_planes && pix_mp->num_planes != fmt->num_planes)
dev_dbg(dev, "%d num of planes change: %u to %u", ctx_id,
pix_mp->num_planes, fmt->num_planes);
pix_mp->num_planes = fmt->num_planes;
for (i = 0; i < pix_mp->num_planes; ++i) {
u32 min_bpl = (pix_mp->width * fmt->row_depth[i]) >> 3;
u32 max_bpl = (pix_limit->wmax * fmt->row_depth[i]) >> 3;
u32 bpl = pix_mp->plane_fmt[i].bytesperline;
u32 min_si, max_si;
u32 si = pix_mp->plane_fmt[i].sizeimage;
bpl = clamp(bpl, min_bpl, max_bpl);
pix_mp->plane_fmt[i].bytesperline = bpl;
min_si = (bpl * pix_mp->height * fmt->depth[i]) /
fmt->row_depth[i];
max_si = (bpl * s.max_height * fmt->depth[i]) /
fmt->row_depth[i];
si = clamp(si, min_si, max_si);
pix_mp->plane_fmt[i].sizeimage = si;
dev_dbg(dev, "%d: p%u, bpl:%u [%u, %u], sizeimage:%u [%u, %u]",
ctx_id, i, bpl, min_bpl, max_bpl, si, min_si, max_si);
}
return fmt;
}
static int mdp_clamp_start(s32 *x, int min, int max, unsigned int align,
u32 flags)
{
if (flags & V4L2_SEL_FLAG_GE)
max = *x;
if (flags & V4L2_SEL_FLAG_LE)
min = *x;
return mdp_clamp_align(x, min, max, align);
}
static int mdp_clamp_end(s32 *x, int min, int max, unsigned int align,
u32 flags)
{
if (flags & V4L2_SEL_FLAG_GE)
min = *x;
if (flags & V4L2_SEL_FLAG_LE)
max = *x;
return mdp_clamp_align(x, min, max, align);
}
int mdp_try_crop(struct mdp_m2m_ctx *ctx, struct v4l2_rect *r,
const struct v4l2_selection *s, struct mdp_frame *frame)
{
struct device *dev = &ctx->mdp_dev->pdev->dev;
s32 left, top, right, bottom;
u32 framew, frameh, walign, halign;
int ret;
dev_dbg(dev, "%d target:%d, set:(%d,%d) %ux%u", ctx->id,
s->target, s->r.left, s->r.top, s->r.width, s->r.height);
left = s->r.left;
top = s->r.top;
right = s->r.left + s->r.width;
bottom = s->r.top + s->r.height;
framew = frame->format.fmt.pix_mp.width;
frameh = frame->format.fmt.pix_mp.height;
if (mdp_target_is_crop(s->target)) {
walign = 1;
halign = 1;
} else {
walign = frame->mdp_fmt->walign;
halign = frame->mdp_fmt->halign;
}
dev_dbg(dev, "%d align:%u,%u, bound:%ux%u", ctx->id,
walign, halign, framew, frameh);
ret = mdp_clamp_start(&left, 0, right, walign, s->flags);
if (ret)
return ret;
ret = mdp_clamp_start(&top, 0, bottom, halign, s->flags);
if (ret)
return ret;
ret = mdp_clamp_end(&right, left, framew, walign, s->flags);
if (ret)
return ret;
ret = mdp_clamp_end(&bottom, top, frameh, halign, s->flags);
if (ret)
return ret;
r->left = left;
r->top = top;
r->width = right - left;
r->height = bottom - top;
dev_dbg(dev, "%d crop:(%d,%d) %ux%u", ctx->id,
r->left, r->top, r->width, r->height);
return 0;
}
int mdp_check_scaling_ratio(const struct v4l2_rect *crop,
const struct v4l2_rect *compose, s32 rotation,
const struct mdp_limit *limit)
{
u32 crop_w, crop_h, comp_w, comp_h;
crop_w = crop->width;
crop_h = crop->height;
if (90 == rotation || 270 == rotation) {
comp_w = compose->height;
comp_h = compose->width;
} else {
comp_w = compose->width;
comp_h = compose->height;
}
if ((crop_w / comp_w) > limit->h_scale_down_max ||
(crop_h / comp_h) > limit->v_scale_down_max ||
(comp_w / crop_w) > limit->h_scale_up_max ||
(comp_h / crop_h) > limit->v_scale_up_max)
return -ERANGE;
return 0;
}
/* Stride that is accepted by MDP HW */
static u32 mdp_fmt_get_stride(const struct mdp_format *fmt,
u32 bytesperline, unsigned int plane)
{
enum mdp_color c = fmt->mdp_color;
u32 stride;
stride = (bytesperline * MDP_COLOR_BITS_PER_PIXEL(c))
/ fmt->row_depth[0];
if (plane == 0)
return stride;
if (plane < MDP_COLOR_GET_PLANE_COUNT(c)) {
if (MDP_COLOR_IS_BLOCK_MODE(c))
stride = stride / 2;
return stride;
}
return 0;
}
/* Stride that is accepted by MDP HW of format with contiguous planes */
static u32 mdp_fmt_get_stride_contig(const struct mdp_format *fmt,
u32 pix_stride, unsigned int plane)
{
enum mdp_color c = fmt->mdp_color;
u32 stride = pix_stride;
if (plane == 0)
return stride;
if (plane < MDP_COLOR_GET_PLANE_COUNT(c)) {
stride = stride >> MDP_COLOR_GET_H_SUBSAMPLE(c);
if (MDP_COLOR_IS_UV_COPLANE(c) && !MDP_COLOR_IS_BLOCK_MODE(c))
stride = stride * 2;
return stride;
}
return 0;
}
/* Plane size that is accepted by MDP HW */
static u32 mdp_fmt_get_plane_size(const struct mdp_format *fmt,
u32 stride, u32 height, unsigned int plane)
{
enum mdp_color c = fmt->mdp_color;
u32 bytesperline;
bytesperline = (stride * fmt->row_depth[0])
/ MDP_COLOR_BITS_PER_PIXEL(c);
if (plane == 0)
return bytesperline * height;
if (plane < MDP_COLOR_GET_PLANE_COUNT(c)) {
height = height >> MDP_COLOR_GET_V_SUBSAMPLE(c);
if (MDP_COLOR_IS_BLOCK_MODE(c))
bytesperline = bytesperline * 2;
return bytesperline * height;
}
return 0;
}
static void mdp_prepare_buffer(struct img_image_buffer *b,
struct mdp_frame *frame, struct vb2_buffer *vb)
{
struct v4l2_pix_format_mplane *pix_mp = &frame->format.fmt.pix_mp;
unsigned int i;
b->format.colorformat = frame->mdp_fmt->mdp_color;
b->format.ycbcr_prof = frame->ycbcr_prof;
for (i = 0; i < pix_mp->num_planes; ++i) {
u32 stride = mdp_fmt_get_stride(frame->mdp_fmt,
pix_mp->plane_fmt[i].bytesperline, i);
b->format.plane_fmt[i].stride = stride;
b->format.plane_fmt[i].size =
mdp_fmt_get_plane_size(frame->mdp_fmt, stride,
pix_mp->height, i);
b->iova[i] = vb2_dma_contig_plane_dma_addr(vb, i);
}
for (; i < MDP_COLOR_GET_PLANE_COUNT(b->format.colorformat); ++i) {
u32 stride = mdp_fmt_get_stride_contig(frame->mdp_fmt,
b->format.plane_fmt[0].stride, i);
b->format.plane_fmt[i].stride = stride;
b->format.plane_fmt[i].size =
mdp_fmt_get_plane_size(frame->mdp_fmt, stride,
pix_mp->height, i);
b->iova[i] = b->iova[i - 1] + b->format.plane_fmt[i - 1].size;
}
b->usage = frame->usage;
}
void mdp_set_src_config(struct img_input *in,
struct mdp_frame *frame, struct vb2_buffer *vb)
{
in->buffer.format.width = frame->format.fmt.pix_mp.width;
in->buffer.format.height = frame->format.fmt.pix_mp.height;
mdp_prepare_buffer(&in->buffer, frame, vb);
}
static u32 mdp_to_fixed(u32 *r, struct v4l2_fract *f)
{
u32 q;
if (f->denominator == 0) {
*r = 0;
return 0;
}
q = f->numerator / f->denominator;
*r = div_u64(((u64)f->numerator - q * f->denominator) <<
IMG_SUBPIXEL_SHIFT, f->denominator);
return q;
}
static void mdp_set_src_crop(struct img_crop *c, struct mdp_crop *crop)
{
c->left = crop->c.left
+ mdp_to_fixed(&c->left_subpix, &crop->left_subpix);
c->top = crop->c.top
+ mdp_to_fixed(&c->top_subpix, &crop->top_subpix);
c->width = crop->c.width
+ mdp_to_fixed(&c->width_subpix, &crop->width_subpix);
c->height = crop->c.height
+ mdp_to_fixed(&c->height_subpix, &crop->height_subpix);
}
static void mdp_set_orientation(struct img_output *out,
s32 rotation, bool hflip, bool vflip)
{
u8 flip = 0;
if (hflip)
flip ^= 1;
if (vflip) {
/*
* A vertical flip is equivalent to
* a 180-degree rotation with a horizontal flip
*/
rotation += 180;
flip ^= 1;
}
out->rotation = rotation % 360;
if (flip != 0)
out->flags |= IMG_CTRL_FLAG_HFLIP;
else
out->flags &= ~IMG_CTRL_FLAG_HFLIP;
}
void mdp_set_dst_config(struct img_output *out,
struct mdp_frame *frame, struct vb2_buffer *vb)
{
out->buffer.format.width = frame->compose.width;
out->buffer.format.height = frame->compose.height;
mdp_prepare_buffer(&out->buffer, frame, vb);
mdp_set_src_crop(&out->crop, &frame->crop);
mdp_set_orientation(out, frame->rotation, frame->hflip, frame->vflip);
}
int mdp_frameparam_init(struct mdp_frameparam *param)
{
struct mdp_frame *frame;
if (!param)
return -EINVAL;
INIT_LIST_HEAD(&param->list);
param->limit = &mdp_def_limit;
param->type = MDP_STREAM_TYPE_BITBLT;
frame = &param->output;
frame->format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
frame->mdp_fmt = mdp_try_fmt_mplane(&frame->format, param, 0);
frame->ycbcr_prof =
mdp_map_ycbcr_prof_mplane(&frame->format,
frame->mdp_fmt->mdp_color);
frame->usage = MDP_BUFFER_USAGE_HW_READ;
param->num_captures = 1;
frame = &param->captures[0];
frame->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
frame->mdp_fmt = mdp_try_fmt_mplane(&frame->format, param, 0);
frame->ycbcr_prof =
mdp_map_ycbcr_prof_mplane(&frame->format,
frame->mdp_fmt->mdp_color);
frame->usage = MDP_BUFFER_USAGE_MDP;
frame->crop.c.width = param->output.format.fmt.pix_mp.width;
frame->crop.c.height = param->output.format.fmt.pix_mp.height;
frame->compose.width = frame->format.fmt.pix_mp.width;
frame->compose.height = frame->format.fmt.pix_mp.height;
return 0;
}

Some files were not shown because too many files have changed in this diff Show more