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:
commit
5d435a3f7b
@ -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>;
|
||||
};
|
@ -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>;
|
||||
};
|
@ -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>;
|
||||
};
|
@ -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
|
||||
|
||||
|
@ -57,6 +57,7 @@ properties:
|
||||
enum:
|
||||
- mediatek,mt8192-vcodec-dec
|
||||
- mediatek,mt8186-vcodec-dec
|
||||
- mediatek,mt8188-vcodec-dec
|
||||
- mediatek,mt8195-vcodec-dec
|
||||
|
||||
reg:
|
||||
|
69
Documentation/devicetree/bindings/media/nxp,dw100.yaml
Normal file
69
Documentation/devicetree/bindings/media/nxp,dw100.yaml
Normal 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>;
|
||||
};
|
@ -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
|
||||
|
@ -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>;
|
||||
};
|
@ -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>;
|
||||
};
|
@ -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
|
||||
|
84
Documentation/userspace-api/media/drivers/dw100.rst
Normal file
84
Documentation/userspace-api/media/drivers/dw100.rst
Normal 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
|
@ -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
|
||||
|
@ -1,9 +0,0 @@
|
||||
.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
|
||||
|
||||
.. _async:
|
||||
|
||||
****************
|
||||
Asynchronous I/O
|
||||
****************
|
||||
|
||||
This method is not defined yet.
|
@ -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
|
||||
|
@ -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.
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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}|
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
||||
|
24
MAINTAINERS
24
MAINTAINERS
@ -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>
|
||||
|
@ -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);
|
||||
|
@ -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"
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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]
|
||||
*/
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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>
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -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/
|
||||
|
@ -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) {
|
||||
|
@ -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 */
|
||||
|
@ -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 },
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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;
|
||||
|
@ -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",
|
@ -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! */
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
60
drivers/media/pci/zoran/zoran_device.h
Normal file
60
drivers/media/pci/zoran/zoran_device.h
Normal 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__ */
|
@ -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;
|
@ -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)
|
||||
{
|
@ -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)
|
||||
{
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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);
|
@ -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"
|
||||
|
||||
|
@ -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/
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -119,7 +119,6 @@ struct vpu_mbox {
|
||||
enum vpu_core_state {
|
||||
VPU_CORE_DEINIT = 0,
|
||||
VPU_CORE_ACTIVE,
|
||||
VPU_CORE_SNAPSHOT,
|
||||
VPU_CORE_HANG
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -854,7 +854,7 @@ fail:
|
||||
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;
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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"
|
||||
|
@ -3,3 +3,4 @@ obj-y += jpeg/
|
||||
obj-y += mdp/
|
||||
obj-y += vcodec/
|
||||
obj-y += vpu/
|
||||
obj-y += mdp3/
|
||||
|
@ -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);
|
||||
|
||||
|
21
drivers/media/platform/mediatek/mdp3/Kconfig
Normal file
21
drivers/media/platform/mediatek/mdp3/Kconfig
Normal 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.
|
6
drivers/media/platform/mediatek/mdp3/Makefile
Normal file
6
drivers/media/platform/mediatek/mdp3/Makefile
Normal 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
|
19
drivers/media/platform/mediatek/mdp3/mdp_reg_ccorr.h
Normal file
19
drivers/media/platform/mediatek/mdp3/mdp_reg_ccorr.h
Normal 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__
|
65
drivers/media/platform/mediatek/mdp3/mdp_reg_rdma.h
Normal file
65
drivers/media/platform/mediatek/mdp3/mdp_reg_rdma.h
Normal 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__
|
39
drivers/media/platform/mediatek/mdp3/mdp_reg_rsz.h
Normal file
39
drivers/media/platform/mediatek/mdp3/mdp_reg_rsz.h
Normal 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__
|
47
drivers/media/platform/mediatek/mdp3/mdp_reg_wdma.h
Normal file
47
drivers/media/platform/mediatek/mdp3/mdp_reg_wdma.h
Normal 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__
|
55
drivers/media/platform/mediatek/mdp3/mdp_reg_wrot.h
Normal file
55
drivers/media/platform/mediatek/mdp3/mdp_reg_wrot.h
Normal 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__
|
290
drivers/media/platform/mediatek/mdp3/mtk-img-ipi.h
Normal file
290
drivers/media/platform/mediatek/mdp3/mtk-img-ipi.h
Normal 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__ */
|
466
drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c
Normal file
466
drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c
Normal 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);
|
43
drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.h
Normal file
43
drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.h
Normal 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__ */
|
1033
drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c
Normal file
1033
drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c
Normal file
File diff suppressed because it is too large
Load Diff
186
drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.h
Normal file
186
drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.h
Normal 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__ */
|
357
drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c
Normal file
357
drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c
Normal 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");
|
94
drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.h
Normal file
94
drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.h
Normal 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__ */
|
724
drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c
Normal file
724
drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c
Normal 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(¶m.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(¶m.outputs[0], frame, &dst_vb->vb2_buf);
|
||||
|
||||
ret = mdp_vpu_process(&ctx->vpu, ¶m);
|
||||
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 = ¶m;
|
||||
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);
|
||||
}
|
48
drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.h
Normal file
48
drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.h
Normal 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__ */
|
735
drivers/media/platform/mediatek/mdp3/mtk-mdp3-regs.c
Normal file
735
drivers/media/platform/mediatek/mdp3/mtk-mdp3-regs.c
Normal 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 = ¶m->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) ? ¶m->limit->out_limit :
|
||||
¶m->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(¶m->list);
|
||||
param->limit = &mdp_def_limit;
|
||||
param->type = MDP_STREAM_TYPE_BITBLT;
|
||||
|
||||
frame = ¶m->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 = ¶m->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
Loading…
Reference in New Issue
Block a user