From: jintao xu Date: Mon, 12 Aug 2019 10:50:27 +0000 (+0800) Subject: video_composer: add multiple video layer display. [1/1] X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=00022ca8badfabadae622aed41d4d874ac9062dc;p=GitHub%2FLineageOS%2FG12%2Fandroid_kernel_amlogic_linux-4.9.git video_composer: add multiple video layer display. [1/1] PD#SWPL-5991 Problem: video_composer bringup Solution: add v4lvideo态dma to display on the video layer via video_composer Verify: on U212 Change-Id: Iec1b75cc8c9aa0475912148a0687d95250aeb8a0 Signed-off-by: jintao xu --- diff --git a/MAINTAINERS b/MAINTAINERS index 649a0c9835b3..7818286686ff 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15221,3 +15221,32 @@ AMLOGIC VPP DRIVER M: Brian Zhu F: drivers/amlogic/media/video_sink/video_hw.c +AMLOGIC T962X3 DRM DTS +M: Dezhi Kong +F: arch/arm/boot/dts/amlogic/tm2_t962x3_ab301_drm.dts +F: arch/arm/boot/dts/amlogic/tm2_t962e2_ab311_drm.dts +F: arch/arm64/boot/dts/amlogic/tm2_t962x3_ab301_drm.dts +F: arch/arm64/boot/dts/amlogic/tm2_t962e2_ab311_drm.dts +F: arch/arm64/boot/dts/amlogic/mesontm2_drm.dtsi +F: arch/arm/boot/dts/amlogic/mesontm2_drm.dtsi + +AMLOGIC VIDEO COMPOSER +M: Jintao.Xu +F: drivers/amlogic/media/video_processor/v4lvideo/Kconfig +F: drivers/amlogic/media/video_processor/v4lvideo/Makefile +F: drivers/amlogic/media/video_processor/v4lvideo/v4lvideo.c +F: drivers/amlogic/media/video_processor/v4lvideo/v4lvideo.h +F: drivers/amlogic/media/video_processor/video_composer/Kconfig +F: drivers/amlogic/media/video_processor/video_composer/Makefile +F: drivers/amlogic/media/video_processor/video_composer/vfq.h +F: drivers/amlogic/media/video_processor/video_composer/vframe_ge2d_composer.c +F: drivers/amlogic/media/video_processor/video_composer/vframe_ge2d_composer.h +F: drivers/amlogic/media/video_processor/video_composer/video_composer.c +F: drivers/amlogic/media/video_processor/video_composer/video_composer.h +F: include/linux/amlogic/media/video_processor/video_composer_ext.h +F: include/linux/amlogic/media/video_sink/v4lvideo_ext.h + +AMLOGIC VPP DRIVER +M: Brian Zhu +F: drivers/amlogic/media/video_sink/video_receiver.c +F: drivers/amlogic/media/video_sink/video_receiver.h diff --git a/arch/arm/boot/dts/amlogic/g12a_s905x2_u212.dts b/arch/arm/boot/dts/amlogic/g12a_s905x2_u212.dts index 57c9719fa7e1..c75260867556 100644 --- a/arch/arm/boot/dts/amlogic/g12a_s905x2_u212.dts +++ b/arch/arm/boot/dts/amlogic/g12a_s905x2_u212.dts @@ -108,7 +108,8 @@ * 10x4736064=45.2M(0x2e) support 12bit * 10x4074560=40M(0x28) support 10bit */ - size = <0x02800000>; + //size = <0x02800000>; + size = <0x05800000>; alignment = <0x400000>; }; /* POST PROCESS MANAGER */ @@ -121,7 +122,7 @@ compatible = "shared-dma-pool"; reusable; /* ion_codec_mm max can alloc size 80M*/ - size = <0x13400000>; + size = <0x16400000>; alignment = <0x400000>; linux,contiguous-region; }; @@ -288,9 +289,8 @@ dev_name = "ppmgr"; status = "okay"; }; - - deinterlace { - compatible = "amlogic, deinterlace"; + multi-di { + compatible = "amlogic, dim-g12a"; status = "okay"; /* 0:use reserved; 1:use cma; 2:use cma as reserved */ flag_cma = <1>; @@ -313,6 +313,30 @@ nrds-enable = <1>; pps-enable = <1>; }; + deinterlace { + compatible = "amlogic, deinterlace"; + status = "disable";//status = "okay"; + /* 0:use reserved; 1:use cma; 2:use cma as reserved */ + flag_cma = <1>; + //memory-region = <&di_reserved>; + //memory-region = <&di_cma_reserved>; + interrupts = <0 46 1 + 0 40 1>; + interrupt-names = "pre_irq", "post_irq"; + clocks = <&clkc CLKID_VPU_CLKB_TMP_COMP>, + <&clkc CLKID_VPU_CLKB_COMP>; + clock-names = "vpu_clkb_tmp_composite", + "vpu_clkb_composite"; + clock-range = <334 667>; + /* buffer-size = <3621952>;(yuv422 8bit) */ + buffer-size = <4074560>;/*yuv422 fullpack*/ + /* reserve-iomap = "true"; */ + /* if enable nr10bit, set nr10bit-support to 1 */ + post-wr-support = <1>; + nr10bit-support = <1>; + nrds-enable = <1>; + pps-enable = <1>; + }; ionvideo { compatible = "amlogic, ionvideo"; dev_name = "ionvideo"; diff --git a/arch/arm/boot/dts/amlogic/g12a_s905x2_u212_1g.dts b/arch/arm/boot/dts/amlogic/g12a_s905x2_u212_1g.dts index b5a0411437c0..5370cce19f58 100644 --- a/arch/arm/boot/dts/amlogic/g12a_s905x2_u212_1g.dts +++ b/arch/arm/boot/dts/amlogic/g12a_s905x2_u212_1g.dts @@ -119,7 +119,8 @@ * 10x4736064=45.2M(0x2e) support 12bit * 10x4074560=40M(0x28) support 10bit */ - size = <0x02800000>; + //size = <0x02800000>; + size = <0x05800000>; alignment = <0x400000>; alloc-ranges = <0x30000000 0x10000000>; }; @@ -286,9 +287,8 @@ dev_name = "ppmgr"; status = "okay"; }; - - deinterlace { - compatible = "amlogic, deinterlace"; + multi-di { + compatible = "amlogic, dim-g12a"; status = "okay"; /* 0:use reserved; 1:use cma; 2:use cma as reserved */ flag_cma = <1>; @@ -311,6 +311,30 @@ nrds-enable = <1>; pps-enable = <1>; }; + deinterlace { + compatible = "amlogic, deinterlace"; + status = "disable";//status = "okay"; + /* 0:use reserved; 1:use cma; 2:use cma as reserved */ + flag_cma = <1>; + //memory-region = <&di_reserved>; + //memory-region = <&di_cma_reserved>; + interrupts = <0 46 1 + 0 40 1>; + interrupt-names = "pre_irq", "post_irq"; + clocks = <&clkc CLKID_VPU_CLKB_TMP_COMP>, + <&clkc CLKID_VPU_CLKB_COMP>; + clock-names = "vpu_clkb_tmp_composite", + "vpu_clkb_composite"; + clock-range = <334 667>; + /* buffer-size = <3621952>;(yuv422 8bit) */ + buffer-size = <4074560>;/*yuv422 fullpack*/ + /* reserve-iomap = "true"; */ + /* if enable nr10bit, set nr10bit-support to 1 */ + post-wr-support = <1>; + nr10bit-support = <1>; + nrds-enable = <1>; + pps-enable = <1>; + }; ionvideo { compatible = "amlogic, ionvideo"; dev_name = "ionvideo"; diff --git a/arch/arm/boot/dts/amlogic/g12a_s905y2_deadpool.dts b/arch/arm/boot/dts/amlogic/g12a_s905y2_deadpool.dts index 3e41535e45d7..0e763fedaa07 100644 --- a/arch/arm/boot/dts/amlogic/g12a_s905y2_deadpool.dts +++ b/arch/arm/boot/dts/amlogic/g12a_s905y2_deadpool.dts @@ -109,7 +109,8 @@ * 10x4736064=45.2M(0x2e) support 12bit * 10x4074560=40M(0x28) support 10bit */ - size = <0x02800000>; + //size = <0x02800000>; + size = <0x05800000>; alignment = <0x400000>; }; /* POST PROCESS MANAGER */ @@ -122,7 +123,7 @@ compatible = "shared-dma-pool"; reusable; /* ion_codec_mm max can alloc size 80M*/ - size = <0x13400000>; + size = <0x16400000>; alignment = <0x400000>; linux,contiguous-region; alloc-ranges = <0x30000000 0x50000000>; @@ -234,14 +235,37 @@ dev_name = "ppmgr"; status = "okay"; }; - + multi-di { + compatible = "amlogic, dim-g12a"; + status = "okay"; + /* 0:use reserved; 1:use cma; 2:use cma as reserved */ + flag_cma = <1>; + //memory-region = <&di_reserved>; + memory-region = <&di_cma_reserved>; + interrupts = <0 46 1 + 0 40 1>; + interrupt-names = "pre_irq", "post_irq"; + clocks = <&clkc CLKID_VPU_CLKB_TMP_COMP>, + <&clkc CLKID_VPU_CLKB_COMP>; + clock-names = "vpu_clkb_tmp_composite", + "vpu_clkb_composite"; + clock-range = <334 667>; + /* buffer-size = <3621952>;(yuv422 8bit) */ + buffer-size = <4074560>;/*yuv422 fullpack*/ + /* reserve-iomap = "true"; */ + /* if enable nr10bit, set nr10bit-support to 1 */ + post-wr-support = <1>; + nr10bit-support = <1>; + nrds-enable = <1>; + pps-enable = <1>; + }; deinterlace { compatible = "amlogic, deinterlace"; status = "okay"; /* 0:use reserved; 1:use cma; 2:use cma as reserved */ flag_cma = <1>; //memory-region = <&di_reserved>; - memory-region = <&di_cma_reserved>; + //memory-region = <&di_cma_reserved>; interrupts = <0 46 1 0 40 1>; interrupt-names = "pre_irq", "post_irq"; diff --git a/arch/arm/boot/dts/amlogic/mesong12a.dtsi b/arch/arm/boot/dts/amlogic/mesong12a.dtsi index 16fb5edb84b3..c19c28262b2f 100644 --- a/arch/arm/boot/dts/amlogic/mesong12a.dtsi +++ b/arch/arm/boot/dts/amlogic/mesong12a.dtsi @@ -1301,6 +1301,12 @@ status = "okay"; }; + video_composer { + compatible = "amlogic, video_composer"; + dev_name = "video_composer"; + status = "okay"; + }; + amvenc_avc{ compatible = "amlogic, amvenc_avc"; dev_name = "amvenc_avc"; diff --git a/arch/arm/boot/dts/amlogic/mesong12a_deadpool.dtsi b/arch/arm/boot/dts/amlogic/mesong12a_deadpool.dtsi index 68eb7cc9d300..9a40a8df8cea 100644 --- a/arch/arm/boot/dts/amlogic/mesong12a_deadpool.dtsi +++ b/arch/arm/boot/dts/amlogic/mesong12a_deadpool.dtsi @@ -1128,6 +1128,12 @@ status = "okay"; }; + video_composer { + compatible = "amlogic, video_composer"; + dev_name = "video_composer"; + status = "okay"; + }; + amvenc_avc{ compatible = "amlogic, amvenc_avc"; dev_name = "amvenc_avc"; diff --git a/arch/arm/boot/dts/amlogic/mesonsm1.dtsi b/arch/arm/boot/dts/amlogic/mesonsm1.dtsi index dc0a7541bb3b..559473c4c9a6 100644 --- a/arch/arm/boot/dts/amlogic/mesonsm1.dtsi +++ b/arch/arm/boot/dts/amlogic/mesonsm1.dtsi @@ -1407,6 +1407,12 @@ status = "okay"; }; + video_composer { + compatible = "amlogic, video_composer"; + dev_name = "video_composer"; + status = "okay"; + }; + amvenc_avc{ compatible = "amlogic, amvenc_avc"; dev_name = "amvenc_avc"; diff --git a/arch/arm/boot/dts/amlogic/mesonsm1_sabrina.dtsi b/arch/arm/boot/dts/amlogic/mesonsm1_sabrina.dtsi index 7e18920a0cd5..ab697c85a055 100644 --- a/arch/arm/boot/dts/amlogic/mesonsm1_sabrina.dtsi +++ b/arch/arm/boot/dts/amlogic/mesonsm1_sabrina.dtsi @@ -1370,6 +1370,12 @@ status = "okay"; }; + video_composer { + compatible = "amlogic, video_composer"; + dev_name = "video_composer"; + status = "okay"; + }; + amvenc_avc{ compatible = "amlogic, amvenc_avc"; dev_name = "amvenc_avc"; diff --git a/arch/arm/boot/dts/amlogic/sm1_s905d3_ac200.dts b/arch/arm/boot/dts/amlogic/sm1_s905d3_ac200.dts old mode 100755 new mode 100644 index 38530a7fcd1d..8926afa68fa2 --- a/arch/arm/boot/dts/amlogic/sm1_s905d3_ac200.dts +++ b/arch/arm/boot/dts/amlogic/sm1_s905d3_ac200.dts @@ -110,7 +110,7 @@ * 10x4736064=45.2M(0x2e) support 12bit * 10x4074560=40M(0x28) support 10bit */ - size = <0x02800000>; + size = <0x05800000>; alignment = <0x400000>; }; /* POST PROCESS MANAGER */ @@ -123,7 +123,7 @@ compatible = "shared-dma-pool"; reusable; /* ion_codec_mm max can alloc size 80M*/ - size = <0x13400000>; + size = <0x16400000>; alignment = <0x400000>; linux,contiguous-region; alloc-ranges = <0x30000000 0x50000000>; @@ -277,8 +277,8 @@ status = "okay"; }; - deinterlace { - compatible = "amlogic, deinterlace"; + multi-di { + compatible = "amlogic, dim-sm1"; status = "okay"; /* 0:use reserved; 1:use cma; 2:use cma as reserved */ flag_cma = <1>; @@ -301,6 +301,32 @@ nrds-enable = <1>; pps-enable = <1>; }; + + deinterlace { + compatible = "amlogic, deinterlace"; + status = "disable";//status = "okay"; + /* 0:use reserved; 1:use cma; 2:use cma as reserved */ + flag_cma = <1>; + //memory-region = <&di_reserved>; + //memory-region = <&di_cma_reserved>; + interrupts = <0 46 1 + 0 40 1>; + interrupt-names = "pre_irq", "post_irq"; + clocks = <&clkc CLKID_VPU_CLKB_TMP_COMP>, + <&clkc CLKID_VPU_CLKB_COMP>; + clock-names = "vpu_clkb_tmp_composite", + "vpu_clkb_composite"; + clock-range = <334 667>; + /* buffer-size = <3621952>;(yuv422 8bit) */ + buffer-size = <4074560>;/*yuv422 fullpack*/ + /* reserve-iomap = "true"; */ + /* if enable nr10bit, set nr10bit-support to 1 */ + post-wr-support = <1>; + nr10bit-support = <1>; + nrds-enable = <1>; + pps-enable = <1>; + }; + ionvideo { compatible = "amlogic, ionvideo"; dev_name = "ionvideo"; diff --git a/arch/arm/boot/dts/amlogic/sm1_s905d3_ac202.dts b/arch/arm/boot/dts/amlogic/sm1_s905d3_ac202.dts index bed7b014a18a..9371f6e90fa6 100644 --- a/arch/arm/boot/dts/amlogic/sm1_s905d3_ac202.dts +++ b/arch/arm/boot/dts/amlogic/sm1_s905d3_ac202.dts @@ -110,7 +110,7 @@ * 10x4736064=45.2M(0x2e) support 12bit * 10x4074560=40M(0x28) support 10bit */ - size = <0x02800000>; + size = <0x05800000>; alignment = <0x400000>; }; /* POST PROCESS MANAGER */ @@ -123,7 +123,7 @@ compatible = "shared-dma-pool"; reusable; /* ion_codec_mm max can alloc size 80M*/ - size = <0x13400000>; + size = <0x16400000>; alignment = <0x400000>; linux,contiguous-region; alloc-ranges = <0x30000000 0x50000000>; @@ -277,8 +277,8 @@ status = "okay"; }; - deinterlace { - compatible = "amlogic, deinterlace"; + multi-di { + compatible = "amlogic, dim-sm1"; status = "okay"; /* 0:use reserved; 1:use cma; 2:use cma as reserved */ flag_cma = <1>; @@ -301,6 +301,32 @@ nrds-enable = <1>; pps-enable = <1>; }; + + deinterlace { + compatible = "amlogic, deinterlace"; + status = "disable";//status = "okay"; + /* 0:use reserved; 1:use cma; 2:use cma as reserved */ + flag_cma = <1>; + //memory-region = <&di_reserved>; + //memory-region = <&di_cma_reserved>; + interrupts = <0 46 1 + 0 40 1>; + interrupt-names = "pre_irq", "post_irq"; + clocks = <&clkc CLKID_VPU_CLKB_TMP_COMP>, + <&clkc CLKID_VPU_CLKB_COMP>; + clock-names = "vpu_clkb_tmp_composite", + "vpu_clkb_composite"; + clock-range = <334 667>; + /* buffer-size = <3621952>;(yuv422 8bit) */ + buffer-size = <4074560>;/*yuv422 fullpack*/ + /* reserve-iomap = "true"; */ + /* if enable nr10bit, set nr10bit-support to 1 */ + post-wr-support = <1>; + nr10bit-support = <1>; + nrds-enable = <1>; + pps-enable = <1>; + }; + ionvideo { compatible = "amlogic, ionvideo"; dev_name = "ionvideo"; diff --git a/arch/arm/boot/dts/amlogic/sm1_s905d3_ac202_1g.dts b/arch/arm/boot/dts/amlogic/sm1_s905d3_ac202_1g.dts index 17145c144314..000684defb87 100644 --- a/arch/arm/boot/dts/amlogic/sm1_s905d3_ac202_1g.dts +++ b/arch/arm/boot/dts/amlogic/sm1_s905d3_ac202_1g.dts @@ -110,7 +110,7 @@ * 10x4736064=45.2M(0x2e) support 12bit * 10x4074560=40M(0x28) support 10bit */ - size = <0x02800000>; + size = <0x05800000>; alignment = <0x400000>; }; /* POST PROCESS MANAGER */ @@ -277,8 +277,8 @@ status = "okay"; }; - deinterlace { - compatible = "amlogic, deinterlace"; + multi-di { + compatible = "amlogic, dim-sm1"; status = "okay"; /* 0:use reserved; 1:use cma; 2:use cma as reserved */ flag_cma = <1>; @@ -301,6 +301,32 @@ nrds-enable = <1>; pps-enable = <1>; }; + + deinterlace { + compatible = "amlogic, deinterlace"; + status = "disable";//status = "okay"; + /* 0:use reserved; 1:use cma; 2:use cma as reserved */ + flag_cma = <1>; + //memory-region = <&di_reserved>; + //memory-region = <&di_cma_reserved>; + interrupts = <0 46 1 + 0 40 1>; + interrupt-names = "pre_irq", "post_irq"; + clocks = <&clkc CLKID_VPU_CLKB_TMP_COMP>, + <&clkc CLKID_VPU_CLKB_COMP>; + clock-names = "vpu_clkb_tmp_composite", + "vpu_clkb_composite"; + clock-range = <334 667>; + /* buffer-size = <3621952>;(yuv422 8bit) */ + buffer-size = <4074560>;/*yuv422 fullpack*/ + /* reserve-iomap = "true"; */ + /* if enable nr10bit, set nr10bit-support to 1 */ + post-wr-support = <1>; + nr10bit-support = <1>; + nrds-enable = <1>; + pps-enable = <1>; + }; + ionvideo { compatible = "amlogic, ionvideo"; dev_name = "ionvideo"; diff --git a/arch/arm/boot/dts/amlogic/sm1_s905d3_sabrina.dts b/arch/arm/boot/dts/amlogic/sm1_s905d3_sabrina.dts index 47df4f98f4b9..cf1a86e8e5e8 100644 --- a/arch/arm/boot/dts/amlogic/sm1_s905d3_sabrina.dts +++ b/arch/arm/boot/dts/amlogic/sm1_s905d3_sabrina.dts @@ -109,7 +109,7 @@ * 10x4736064=45.2M(0x2e) support 12bit * 10x4074560=40M(0x28) support 10bit */ - size = <0x02800000>; + size = <0x05800000>; alignment = <0x400000>; }; /* POST PROCESS MANAGER */ @@ -122,7 +122,7 @@ compatible = "shared-dma-pool"; reusable; /* ion_codec_mm max can alloc size 80M*/ - size = <0x13400000>; + size = <0x16400000>; alignment = <0x400000>; linux,contiguous-region; alloc-ranges = <0x30000000 0x50000000>; @@ -267,8 +267,8 @@ status = "okay"; }; - deinterlace { - compatible = "amlogic, deinterlace"; + multi-di { + compatible = "amlogic, dim-sm1"; status = "okay"; /* 0:use reserved; 1:use cma; 2:use cma as reserved */ flag_cma = <1>; @@ -291,6 +291,32 @@ nrds-enable = <1>; pps-enable = <1>; }; + + deinterlace { + compatible = "amlogic, deinterlace"; + status = "disable";//status = "okay"; + /* 0:use reserved; 1:use cma; 2:use cma as reserved */ + flag_cma = <1>; + //memory-region = <&di_reserved>; + //memory-region = <&di_cma_reserved>; + interrupts = <0 46 1 + 0 40 1>; + interrupt-names = "pre_irq", "post_irq"; + clocks = <&clkc CLKID_VPU_CLKB_TMP_COMP>, + <&clkc CLKID_VPU_CLKB_COMP>; + clock-names = "vpu_clkb_tmp_composite", + "vpu_clkb_composite"; + clock-range = <334 667>; + /* buffer-size = <3621952>;(yuv422 8bit) */ + buffer-size = <4074560>;/*yuv422 fullpack*/ + /* reserve-iomap = "true"; */ + /* if enable nr10bit, set nr10bit-support to 1 */ + post-wr-support = <1>; + nr10bit-support = <1>; + nrds-enable = <1>; + pps-enable = <1>; + }; + ionvideo { compatible = "amlogic, ionvideo"; dev_name = "ionvideo"; diff --git a/arch/arm/boot/dts/amlogic/sm1_s905x3_ac213.dts b/arch/arm/boot/dts/amlogic/sm1_s905x3_ac213.dts index 8951ce524ea1..a116ead97308 100644 --- a/arch/arm/boot/dts/amlogic/sm1_s905x3_ac213.dts +++ b/arch/arm/boot/dts/amlogic/sm1_s905x3_ac213.dts @@ -110,7 +110,7 @@ * 10x4736064=45.2M(0x2e) support 12bit * 10x4074560=40M(0x28) support 10bit */ - size = <0x02800000>; + size = <0x05800000>; alignment = <0x400000>; }; /* POST PROCESS MANAGER */ @@ -123,7 +123,7 @@ compatible = "shared-dma-pool"; reusable; /* ion_codec_mm max can alloc size 80M*/ - size = <0x13400000>; + size = <0x16400000>; alignment = <0x400000>; linux,contiguous-region; alloc-ranges = <0x30000000 0x50000000>; @@ -303,8 +303,8 @@ status = "okay"; }; - deinterlace { - compatible = "amlogic, deinterlace"; + multi-di { + compatible = "amlogic, dim-sm1"; status = "okay"; /* 0:use reserved; 1:use cma; 2:use cma as reserved */ flag_cma = <1>; @@ -327,6 +327,30 @@ nrds-enable = <1>; pps-enable = <1>; }; + deinterlace { + compatible = "amlogic, deinterlace"; + status = "disable";//status = "okay"; + /* 0:use reserved; 1:use cma; 2:use cma as reserved */ + flag_cma = <1>; + //memory-region = <&di_reserved>; + //memory-region = <&di_cma_reserved>; + interrupts = <0 46 1 + 0 40 1>; + interrupt-names = "pre_irq", "post_irq"; + clocks = <&clkc CLKID_VPU_CLKB_TMP_COMP>, + <&clkc CLKID_VPU_CLKB_COMP>; + clock-names = "vpu_clkb_tmp_composite", + "vpu_clkb_composite"; + clock-range = <334 667>; + /* buffer-size = <3621952>;(yuv422 8bit) */ + buffer-size = <4074560>;/*yuv422 fullpack*/ + /* reserve-iomap = "true"; */ + /* if enable nr10bit, set nr10bit-support to 1 */ + post-wr-support = <1>; + nr10bit-support = <1>; + nrds-enable = <1>; + pps-enable = <1>; + }; ionvideo { compatible = "amlogic, ionvideo"; dev_name = "ionvideo"; diff --git a/arch/arm/boot/dts/amlogic/sm1_s905x3_ac214.dts b/arch/arm/boot/dts/amlogic/sm1_s905x3_ac214.dts index 5244fb869270..76b0d46c69f5 100644 --- a/arch/arm/boot/dts/amlogic/sm1_s905x3_ac214.dts +++ b/arch/arm/boot/dts/amlogic/sm1_s905x3_ac214.dts @@ -110,7 +110,7 @@ * 10x4736064=45.2M(0x2e) support 12bit * 10x4074560=40M(0x28) support 10bit */ - size = <0x02800000>; + size = <0x05800000>; alignment = <0x400000>; }; /* POST PROCESS MANAGER */ @@ -123,7 +123,7 @@ compatible = "shared-dma-pool"; reusable; /* ion_codec_mm max can alloc size 80M*/ - size = <0x13400000>; + size = <0x16400000>; alignment = <0x400000>; linux,contiguous-region; alloc-ranges = <0x30000000 0x50000000>; @@ -303,8 +303,8 @@ status = "okay"; }; - deinterlace { - compatible = "amlogic, deinterlace"; + multi-di { + compatible = "amlogic, dim-sm1"; status = "okay"; /* 0:use reserved; 1:use cma; 2:use cma as reserved */ flag_cma = <1>; diff --git a/arch/arm/boot/dts/amlogic/sm1_s905x3_ac214_buildroot.dts b/arch/arm/boot/dts/amlogic/sm1_s905x3_ac214_buildroot.dts index 2b1246794e9a..238f82405e8c 100644 --- a/arch/arm/boot/dts/amlogic/sm1_s905x3_ac214_buildroot.dts +++ b/arch/arm/boot/dts/amlogic/sm1_s905x3_ac214_buildroot.dts @@ -101,7 +101,7 @@ * 10x4736064=45.2M(0x2e) support 12bit * 10x4074560=40M(0x28) support 10bit */ - size = <0x02800000>; + size = <0x05800000>; alignment = <0x400000>; }; /* POST PROCESS MANAGER */ @@ -114,7 +114,7 @@ compatible = "shared-dma-pool"; reusable; /* ion_codec_mm max can alloc size 80M*/ - size = <0x13400000>; + size = <0x16400000>; alignment = <0x400000>; linux,contiguous-region; alloc-ranges = <0x30000000 0x50000000>; @@ -294,8 +294,8 @@ status = "okay"; }; - deinterlace { - compatible = "amlogic, deinterlace"; + multi-di { + compatible = "amlogic, dim-sm1"; status = "okay"; /* 0:use reserved; 1:use cma; 2:use cma as reserved */ flag_cma = <1>; @@ -318,6 +318,32 @@ nrds-enable = <1>; pps-enable = <1>; }; + + deinterlace { + compatible = "amlogic, deinterlace"; + status = "disable";//status = "okay"; + /* 0:use reserved; 1:use cma; 2:use cma as reserved */ + flag_cma = <1>; + //memory-region = <&di_reserved>; + //memory-region = <&di_cma_reserved>; + interrupts = <0 46 1 + 0 40 1>; + interrupt-names = "pre_irq", "post_irq"; + clocks = <&clkc CLKID_VPU_CLKB_TMP_COMP>, + <&clkc CLKID_VPU_CLKB_COMP>; + clock-names = "vpu_clkb_tmp_composite", + "vpu_clkb_composite"; + clock-range = <334 667>; + /* buffer-size = <3621952>;(yuv422 8bit) */ + buffer-size = <4074560>;/*yuv422 fullpack*/ + /* reserve-iomap = "true"; */ + /* if enable nr10bit, set nr10bit-support to 1 */ + post-wr-support = <1>; + nr10bit-support = <1>; + nrds-enable = <1>; + pps-enable = <1>; + }; + ionvideo { compatible = "amlogic, ionvideo"; dev_name = "ionvideo"; diff --git a/arch/arm/configs/meson64_a32_defconfig b/arch/arm/configs/meson64_a32_defconfig index 3b361e078be6..aa3bf7d344da 100644 --- a/arch/arm/configs/meson64_a32_defconfig +++ b/arch/arm/configs/meson64_a32_defconfig @@ -335,6 +335,8 @@ CONFIG_AMLOGIC_VIDEOBUF2_ION=y CONFIG_AMLOGIC_IONVIDEO=y CONFIG_AMLOGIC_PIC_DEC=y CONFIG_AMLOGIC_VIDEOSYNC=y +CONFIG_AMLOGIC_V4L_VIDEO3=y +CONFIG_AMLOGIC_VIDEO_COMPOSER=y CONFIG_AMLOGIC_MEDIA_ENHANCEMENT=y CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_VECM=y CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION=y @@ -476,7 +478,6 @@ CONFIG_SPI_SPIDEV=y CONFIG_GPIO_SYSFS=y CONFIG_GPIO_PCA953X=y CONFIG_POWER_RESET=y -CONFIG_POWER_SUPPLY=y CONFIG_THERMAL=y CONFIG_THERMAL_WRITABLE_TRIPS=y CONFIG_THERMAL_DEFAULT_GOV_POWER_ALLOCATOR=y @@ -523,9 +524,9 @@ CONFIG_AMLOGIC_SND_SOC_MESON=y CONFIG_AMLOGIC_SND_SOC_AUGE=y CONFIG_AMLOGIC_SND_SPLIT_MODE=y CONFIG_AMLOGIC_SND_SOC_COMMON=y -CONFIG_HID_SONY=y CONFIG_HIDRAW=y CONFIG_UHID=y +CONFIG_HID_SONY=y CONFIG_USB_HIDDEV=y CONFIG_USB_XHCI_HCD=y CONFIG_USB_EHCI_HCD=y diff --git a/arch/arm64/boot/dts/amlogic/g12a_s905x2_u212.dts b/arch/arm64/boot/dts/amlogic/g12a_s905x2_u212.dts index 378c1b173df6..cd2c614e321e 100644 --- a/arch/arm64/boot/dts/amlogic/g12a_s905x2_u212.dts +++ b/arch/arm64/boot/dts/amlogic/g12a_s905x2_u212.dts @@ -108,7 +108,7 @@ * 10x4736064=45.2M(0x2e) support 12bit * 10x4074560=40M(0x28) support 10bit */ - size = <0x0 0x02800000>; + size = <0x0 0x05800000>; alignment = <0x0 0x400000>; }; /* POST PROCESS MANAGER */ @@ -121,7 +121,7 @@ compatible = "shared-dma-pool"; reusable; /* ion_codec_mm max can alloc size 80M*/ - size = <0x0 0x13400000>; + size = <0x0 0x16400000>; alignment = <0x0 0x400000>; linux,contiguous-region; }; @@ -288,9 +288,8 @@ dev_name = "ppmgr"; status = "okay"; }; - - deinterlace { - compatible = "amlogic, deinterlace"; + multi-di { + compatible = "amlogic, dim-g12a"; status = "okay"; /* 0:use reserved; 1:use cma; 2:use cma as reserved */ flag_cma = <1>; @@ -313,6 +312,30 @@ nrds-enable = <1>; pps-enable = <1>; }; + deinterlace { + compatible = "amlogic, deinterlace"; + status = "disable";//status = "okay"; + /* 0:use reserved; 1:use cma; 2:use cma as reserved */ + flag_cma = <1>; + //memory-region = <&di_reserved>; + //memory-region = <&di_cma_reserved>; + interrupts = <0 46 1 + 0 40 1>; + interrupt-names = "pre_irq", "post_irq"; + clocks = <&clkc CLKID_VPU_CLKB_TMP_COMP>, + <&clkc CLKID_VPU_CLKB_COMP>; + clock-names = "vpu_clkb_tmp_composite", + "vpu_clkb_composite"; + clock-range = <334 667>; + /* buffer-size = <3621952>;(yuv422 8bit) */ + buffer-size = <4074560>;/*yuv422 fullpack*/ + /* reserve-iomap = "true"; */ + /* if enable nr10bit, set nr10bit-support to 1 */ + post-wr-support = <1>; + nr10bit-support = <1>; + nrds-enable = <1>; + pps-enable = <1>; + }; ionvideo { compatible = "amlogic, ionvideo"; dev_name = "ionvideo"; diff --git a/arch/arm64/boot/dts/amlogic/g12a_s905x2_u212_1g.dts b/arch/arm64/boot/dts/amlogic/g12a_s905x2_u212_1g.dts index d548a0e80afd..83adbbd1ffca 100644 --- a/arch/arm64/boot/dts/amlogic/g12a_s905x2_u212_1g.dts +++ b/arch/arm64/boot/dts/amlogic/g12a_s905x2_u212_1g.dts @@ -109,7 +109,7 @@ * 10x4736064=45.2M(0x2e) support 12bit * 10x4074560=40M(0x28) support 10bit */ - size = <0x0 0x02800000>; + size = <0x0 0x05800000>; alignment = <0x0 0x400000>; }; /* POST PROCESS MANAGER */ @@ -282,9 +282,8 @@ dev_name = "ppmgr"; status = "okay"; }; - - deinterlace { - compatible = "amlogic, deinterlace"; + multi-di { + compatible = "amlogic, dim-g12a"; status = "okay"; /* 0:use reserved; 1:use cma; 2:use cma as reserved */ flag_cma = <1>; @@ -307,6 +306,30 @@ nrds-enable = <1>; pps-enable = <1>; }; + deinterlace { + compatible = "amlogic, deinterlace"; + status = "disable";//status = "okay"; + /* 0:use reserved; 1:use cma; 2:use cma as reserved */ + flag_cma = <1>; + //memory-region = <&di_reserved>; + //memory-region = <&di_cma_reserved>; + interrupts = <0 46 1 + 0 40 1>; + interrupt-names = "pre_irq", "post_irq"; + clocks = <&clkc CLKID_VPU_CLKB_TMP_COMP>, + <&clkc CLKID_VPU_CLKB_COMP>; + clock-names = "vpu_clkb_tmp_composite", + "vpu_clkb_composite"; + clock-range = <334 667>; + /* buffer-size = <3621952>;(yuv422 8bit) */ + buffer-size = <4074560>;/*yuv422 fullpack*/ + /* reserve-iomap = "true"; */ + /* if enable nr10bit, set nr10bit-support to 1 */ + post-wr-support = <1>; + nr10bit-support = <1>; + nrds-enable = <1>; + pps-enable = <1>; + }; ionvideo { compatible = "amlogic, ionvideo"; dev_name = "ionvideo"; diff --git a/arch/arm64/boot/dts/amlogic/g12a_s905y2_deadpool.dts b/arch/arm64/boot/dts/amlogic/g12a_s905y2_deadpool.dts index 3b5cddf52045..d0a35f29a325 100644 --- a/arch/arm64/boot/dts/amlogic/g12a_s905y2_deadpool.dts +++ b/arch/arm64/boot/dts/amlogic/g12a_s905y2_deadpool.dts @@ -108,7 +108,7 @@ * 10x4736064=45.2M(0x2e) support 12bit * 10x4074560=40M(0x28) support 10bit */ - size = <0x0 0x02800000>; + size = <0x0 0x05800000>; alignment = <0x0 0x400000>; }; /* POST PROCESS MANAGER */ @@ -121,7 +121,7 @@ compatible = "shared-dma-pool"; reusable; /* ion_codec_mm max can alloc size 80M*/ - size = <0x0 0x13400000>; + size = <0x0 0x16400000>; alignment = <0x0 0x400000>; linux,contiguous-region; }; @@ -242,14 +242,37 @@ dev_name = "ppmgr"; status = "okay"; }; - + multi-di { + compatible = "amlogic, dim-g12a"; + status = "okay"; + /* 0:use reserved; 1:use cma; 2:use cma as reserved */ + flag_cma = <1>; + //memory-region = <&di_reserved>; + memory-region = <&di_cma_reserved>; + interrupts = <0 46 1 + 0 40 1>; + interrupt-names = "pre_irq", "post_irq"; + clocks = <&clkc CLKID_VPU_CLKB_TMP_COMP>, + <&clkc CLKID_VPU_CLKB_COMP>; + clock-names = "vpu_clkb_tmp_composite", + "vpu_clkb_composite"; + clock-range = <334 667>; + /* buffer-size = <3621952>;(yuv422 8bit) */ + buffer-size = <4074560>;/*yuv422 fullpack*/ + /* reserve-iomap = "true"; */ + /* if enable nr10bit, set nr10bit-support to 1 */ + post-wr-support = <1>; + nr10bit-support = <1>; + nrds-enable = <1>; + pps-enable = <1>; + }; deinterlace { compatible = "amlogic, deinterlace"; status = "okay"; /* 0:use reserved; 1:use cma; 2:use cma as reserved */ flag_cma = <1>; //memory-region = <&di_reserved>; - memory-region = <&di_cma_reserved>; + //memory-region = <&di_cma_reserved>; interrupts = <0 46 1 0 40 1>; interrupt-names = "pre_irq", "post_irq"; diff --git a/arch/arm64/boot/dts/amlogic/mesong12a.dtsi b/arch/arm64/boot/dts/amlogic/mesong12a.dtsi index 86ee9123f6c1..f419244e69b8 100644 --- a/arch/arm64/boot/dts/amlogic/mesong12a.dtsi +++ b/arch/arm64/boot/dts/amlogic/mesong12a.dtsi @@ -1300,6 +1300,12 @@ status = "okay"; }; + video_composer { + compatible = "amlogic, video_composer"; + dev_name = "video_composer"; + status = "okay"; + }; + amvenc_avc{ compatible = "amlogic, amvenc_avc"; dev_name = "amvenc_avc"; diff --git a/arch/arm64/boot/dts/amlogic/mesong12a_deadpool.dtsi b/arch/arm64/boot/dts/amlogic/mesong12a_deadpool.dtsi index 4048775b9b65..f4118f806426 100644 --- a/arch/arm64/boot/dts/amlogic/mesong12a_deadpool.dtsi +++ b/arch/arm64/boot/dts/amlogic/mesong12a_deadpool.dtsi @@ -1126,6 +1126,12 @@ status = "okay"; }; + video_composer { + compatible = "amlogic, video_composer"; + dev_name = "video_composer"; + status = "okay"; + }; + amvenc_avc{ compatible = "amlogic, amvenc_avc"; dev_name = "amvenc_avc"; diff --git a/arch/arm64/boot/dts/amlogic/mesonsm1.dtsi b/arch/arm64/boot/dts/amlogic/mesonsm1.dtsi index 370e214817db..8af44d5fe669 100644 --- a/arch/arm64/boot/dts/amlogic/mesonsm1.dtsi +++ b/arch/arm64/boot/dts/amlogic/mesonsm1.dtsi @@ -1406,6 +1406,12 @@ status = "okay"; }; + video_composer { + compatible = "amlogic, video_composer"; + dev_name = "video_composer"; + status = "okay"; + }; + amvenc_avc{ compatible = "amlogic, amvenc_avc"; dev_name = "amvenc_avc"; diff --git a/arch/arm64/boot/dts/amlogic/mesonsm1_sabrina.dtsi b/arch/arm64/boot/dts/amlogic/mesonsm1_sabrina.dtsi index b053d5c7c2e9..a4ae378a8e09 100644 --- a/arch/arm64/boot/dts/amlogic/mesonsm1_sabrina.dtsi +++ b/arch/arm64/boot/dts/amlogic/mesonsm1_sabrina.dtsi @@ -1369,6 +1369,12 @@ status = "okay"; }; + video_composer { + compatible = "amlogic, video_composer"; + dev_name = "video_composer"; + status = "okay"; + }; + amvenc_avc{ compatible = "amlogic, amvenc_avc"; dev_name = "amvenc_avc"; diff --git a/arch/arm64/boot/dts/amlogic/sm1_s905d3_ac200.dts b/arch/arm64/boot/dts/amlogic/sm1_s905d3_ac200.dts index 43fb18244f9d..3322c284d5db 100644 --- a/arch/arm64/boot/dts/amlogic/sm1_s905d3_ac200.dts +++ b/arch/arm64/boot/dts/amlogic/sm1_s905d3_ac200.dts @@ -109,7 +109,7 @@ * 10x4736064=45.2M(0x2e) support 12bit * 10x4074560=40M(0x28) support 10bit */ - size = <0x0 0x02800000>; + size = <0x0 0x05800000>; alignment = <0x0 0x400000>; }; /* POST PROCESS MANAGER */ @@ -122,7 +122,7 @@ compatible = "shared-dma-pool"; reusable; /* ion_codec_mm max can alloc size 80M*/ - size = <0x0 0x13400000>; + size = <0x0 0x16400000>; alignment = <0x0 0x400000>; linux,contiguous-region; }; @@ -275,8 +275,8 @@ status = "okay"; }; - deinterlace { - compatible = "amlogic, deinterlace"; + multi-di { + compatible = "amlogic, dim-sm1"; status = "okay"; /* 0:use reserved; 1:use cma; 2:use cma as reserved */ flag_cma = <1>; @@ -299,6 +299,30 @@ nrds-enable = <1>; pps-enable = <1>; }; + deinterlace { + compatible = "amlogic, deinterlace"; + status = "disable";//status = "okay"; + /* 0:use reserved; 1:use cma; 2:use cma as reserved */ + flag_cma = <1>; + //memory-region = <&di_reserved>; + //memory-region = <&di_cma_reserved>; + interrupts = <0 46 1 + 0 40 1>; + interrupt-names = "pre_irq", "post_irq"; + clocks = <&clkc CLKID_VPU_CLKB_TMP_COMP>, + <&clkc CLKID_VPU_CLKB_COMP>; + clock-names = "vpu_clkb_tmp_composite", + "vpu_clkb_composite"; + clock-range = <334 667>; + /* buffer-size = <3621952>;(yuv422 8bit) */ + buffer-size = <4074560>;/*yuv422 fullpack*/ + /* reserve-iomap = "true"; */ + /* if enable nr10bit, set nr10bit-support to 1 */ + post-wr-support = <1>; + nr10bit-support = <1>; + nrds-enable = <1>; + pps-enable = <1>; + }; ionvideo { compatible = "amlogic, ionvideo"; dev_name = "ionvideo"; diff --git a/arch/arm64/boot/dts/amlogic/sm1_s905d3_ac202.dts b/arch/arm64/boot/dts/amlogic/sm1_s905d3_ac202.dts index 91360b69faba..d1d441d69730 100644 --- a/arch/arm64/boot/dts/amlogic/sm1_s905d3_ac202.dts +++ b/arch/arm64/boot/dts/amlogic/sm1_s905d3_ac202.dts @@ -109,7 +109,7 @@ * 10x4736064=45.2M(0x2e) support 12bit * 10x4074560=40M(0x28) support 10bit */ - size = <0x0 0x02800000>; + size = <0x0 0x05800000>; alignment = <0x0 0x400000>; }; /* POST PROCESS MANAGER */ @@ -122,7 +122,7 @@ compatible = "shared-dma-pool"; reusable; /* ion_codec_mm max can alloc size 80M*/ - size = <0x0 0x13400000>; + size = <0x0 0x16400000>; alignment = <0x0 0x400000>; linux,contiguous-region; }; @@ -275,8 +275,8 @@ status = "okay"; }; - deinterlace { - compatible = "amlogic, deinterlace"; + multi-di { + compatible = "amlogic, dim-sm1"; status = "okay"; /* 0:use reserved; 1:use cma; 2:use cma as reserved */ flag_cma = <1>; @@ -299,6 +299,30 @@ nrds-enable = <1>; pps-enable = <1>; }; + deinterlace { + compatible = "amlogic, deinterlace"; + status = "disable";//status = "okay"; + /* 0:use reserved; 1:use cma; 2:use cma as reserved */ + flag_cma = <1>; + //memory-region = <&di_reserved>; + //memory-region = <&di_cma_reserved>; + interrupts = <0 46 1 + 0 40 1>; + interrupt-names = "pre_irq", "post_irq"; + clocks = <&clkc CLKID_VPU_CLKB_TMP_COMP>, + <&clkc CLKID_VPU_CLKB_COMP>; + clock-names = "vpu_clkb_tmp_composite", + "vpu_clkb_composite"; + clock-range = <334 667>; + /* buffer-size = <3621952>;(yuv422 8bit) */ + buffer-size = <4074560>;/*yuv422 fullpack*/ + /* reserve-iomap = "true"; */ + /* if enable nr10bit, set nr10bit-support to 1 */ + post-wr-support = <1>; + nr10bit-support = <1>; + nrds-enable = <1>; + pps-enable = <1>; + }; ionvideo { compatible = "amlogic, ionvideo"; dev_name = "ionvideo"; diff --git a/arch/arm64/boot/dts/amlogic/sm1_s905d3_ac202_1g.dts b/arch/arm64/boot/dts/amlogic/sm1_s905d3_ac202_1g.dts index fc6f2e3ba6cc..690ca65f5b85 100644 --- a/arch/arm64/boot/dts/amlogic/sm1_s905d3_ac202_1g.dts +++ b/arch/arm64/boot/dts/amlogic/sm1_s905d3_ac202_1g.dts @@ -109,7 +109,7 @@ * 10x4736064=45.2M(0x2e) support 12bit * 10x4074560=40M(0x28) support 10bit */ - size = <0x0 0x02800000>; + size = <0x0 0x05800000>; alignment = <0x0 0x400000>; }; /* POST PROCESS MANAGER */ @@ -275,8 +275,8 @@ status = "okay"; }; - deinterlace { - compatible = "amlogic, deinterlace"; + multi-di { + compatible = "amlogic, dim-sm1"; status = "okay"; /* 0:use reserved; 1:use cma; 2:use cma as reserved */ flag_cma = <1>; @@ -299,6 +299,30 @@ nrds-enable = <1>; pps-enable = <1>; }; + deinterlace { + compatible = "amlogic, deinterlace"; + status = "disable";//status = "okay"; + /* 0:use reserved; 1:use cma; 2:use cma as reserved */ + flag_cma = <1>; + //memory-region = <&di_reserved>; + //memory-region = <&di_cma_reserved>; + interrupts = <0 46 1 + 0 40 1>; + interrupt-names = "pre_irq", "post_irq"; + clocks = <&clkc CLKID_VPU_CLKB_TMP_COMP>, + <&clkc CLKID_VPU_CLKB_COMP>; + clock-names = "vpu_clkb_tmp_composite", + "vpu_clkb_composite"; + clock-range = <334 667>; + /* buffer-size = <3621952>;(yuv422 8bit) */ + buffer-size = <4074560>;/*yuv422 fullpack*/ + /* reserve-iomap = "true"; */ + /* if enable nr10bit, set nr10bit-support to 1 */ + post-wr-support = <1>; + nr10bit-support = <1>; + nrds-enable = <1>; + pps-enable = <1>; + }; ionvideo { compatible = "amlogic, ionvideo"; dev_name = "ionvideo"; diff --git a/arch/arm64/boot/dts/amlogic/sm1_s905d3_sabrina.dts b/arch/arm64/boot/dts/amlogic/sm1_s905d3_sabrina.dts index ff91c65330ff..e16d8631104f 100644 --- a/arch/arm64/boot/dts/amlogic/sm1_s905d3_sabrina.dts +++ b/arch/arm64/boot/dts/amlogic/sm1_s905d3_sabrina.dts @@ -108,7 +108,7 @@ * 10x4736064=45.2M(0x2e) support 12bit * 10x4074560=40M(0x28) support 10bit */ - size = <0x0 0x02800000>; + size = <0x0 0x05800000>; alignment = <0x0 0x400000>; }; /* POST PROCESS MANAGER */ @@ -121,7 +121,7 @@ compatible = "shared-dma-pool"; reusable; /* ion_codec_mm max can alloc size 80M*/ - size = <0x0 0x13400000>; + size = <0x0 0x16400000>; alignment = <0x0 0x400000>; linux,contiguous-region; }; @@ -265,13 +265,37 @@ status = "okay"; }; + multi-di { + compatible = "amlogic, dim-sm1"; + status = "okay"; + /* 0:use reserved; 1:use cma; 2:use cma as reserved */ + flag_cma = <1>; + //memory-region = <&di_reserved>; + memory-region = <&di_cma_reserved>; + interrupts = <0 46 1 + 0 40 1>; + interrupt-names = "pre_irq", "post_irq"; + clocks = <&clkc CLKID_VPU_CLKB_TMP_COMP>, + <&clkc CLKID_VPU_CLKB_COMP>; + clock-names = "vpu_clkb_tmp_composite", + "vpu_clkb_composite"; + clock-range = <334 667>; + /* buffer-size = <3621952>;(yuv422 8bit) */ + buffer-size = <4074560>;/*yuv422 fullpack*/ + /* reserve-iomap = "true"; */ + /* if enable nr10bit, set nr10bit-support to 1 */ + post-wr-support = <1>; + nr10bit-support = <1>; + nrds-enable = <1>; + pps-enable = <1>; + }; deinterlace { compatible = "amlogic, deinterlace"; status = "okay"; /* 0:use reserved; 1:use cma; 2:use cma as reserved */ flag_cma = <1>; //memory-region = <&di_reserved>; - memory-region = <&di_cma_reserved>; + //memory-region = <&di_cma_reserved>; interrupts = <0 46 1 0 40 1>; interrupt-names = "pre_irq", "post_irq"; diff --git a/arch/arm64/boot/dts/amlogic/sm1_s905x3_ac213.dts b/arch/arm64/boot/dts/amlogic/sm1_s905x3_ac213.dts index d5f1f0654c66..1b6c39d878b3 100644 --- a/arch/arm64/boot/dts/amlogic/sm1_s905x3_ac213.dts +++ b/arch/arm64/boot/dts/amlogic/sm1_s905x3_ac213.dts @@ -109,7 +109,7 @@ * 10x4736064=45.2M(0x2e) support 12bit * 10x4074560=40M(0x28) support 10bit */ - size = <0x0 0x02800000>; + size = <0x0 0x05800000>; alignment = <0x0 0x400000>; }; /* POST PROCESS MANAGER */ @@ -122,7 +122,7 @@ compatible = "shared-dma-pool"; reusable; /* ion_codec_mm max can alloc size 80M*/ - size = <0x0 0x13400000>; + size = <0x0 0x16400000>; alignment = <0x0 0x400000>; linux,contiguous-region; }; @@ -301,8 +301,8 @@ status = "okay"; }; - deinterlace { - compatible = "amlogic, deinterlace"; + multi-di { + compatible = "amlogic, dim-sm1"; status = "okay"; /* 0:use reserved; 1:use cma; 2:use cma as reserved */ flag_cma = <1>; @@ -325,7 +325,30 @@ nrds-enable = <1>; pps-enable = <1>; }; - + deinterlace { + compatible = "amlogic, deinterlace"; + status = "disable";//status = "okay"; + /* 0:use reserved; 1:use cma; 2:use cma as reserved */ + flag_cma = <1>; + //memory-region = <&di_reserved>; + //memory-region = <&di_cma_reserved>; + interrupts = <0 46 1 + 0 40 1>; + interrupt-names = "pre_irq", "post_irq"; + clocks = <&clkc CLKID_VPU_CLKB_TMP_COMP>, + <&clkc CLKID_VPU_CLKB_COMP>; + clock-names = "vpu_clkb_tmp_composite", + "vpu_clkb_composite"; + clock-range = <334 667>; + /* buffer-size = <3621952>;(yuv422 8bit) */ + buffer-size = <4074560>;/*yuv422 fullpack*/ + /* reserve-iomap = "true"; */ + /* if enable nr10bit, set nr10bit-support to 1 */ + post-wr-support = <1>; + nr10bit-support = <1>; + nrds-enable = <1>; + pps-enable = <1>; + }; dvb_avl6762 { compatible = "amlogic, dvb"; dev_name = "dvb"; diff --git a/arch/arm64/boot/dts/amlogic/sm1_s905x3_ac214.dts b/arch/arm64/boot/dts/amlogic/sm1_s905x3_ac214.dts index 3f8b9774d657..c2723f1a2aca 100644 --- a/arch/arm64/boot/dts/amlogic/sm1_s905x3_ac214.dts +++ b/arch/arm64/boot/dts/amlogic/sm1_s905x3_ac214.dts @@ -109,7 +109,7 @@ * 10x4736064=45.2M(0x2e) support 12bit * 10x4074560=40M(0x28) support 10bit */ - size = <0x0 0x02800000>; + size = <0x0 0x05800000>; alignment = <0x0 0x400000>; }; /* POST PROCESS MANAGER */ @@ -122,7 +122,7 @@ compatible = "shared-dma-pool"; reusable; /* ion_codec_mm max can alloc size 80M*/ - size = <0x0 0x13400000>; + size = <0x0 0x16400000>; alignment = <0x0 0x400000>; linux,contiguous-region; }; @@ -301,8 +301,8 @@ status = "okay"; }; - deinterlace { - compatible = "amlogic, deinterlace"; + multi-di { + compatible = "amlogic, dim-sm1"; status = "okay"; /* 0:use reserved; 1:use cma; 2:use cma as reserved */ flag_cma = <1>; @@ -326,6 +326,31 @@ pps-enable = <1>; }; + deinterlace { + compatible = "amlogic, deinterlace"; + status = "disable";//status = "okay"; + /* 0:use reserved; 1:use cma; 2:use cma as reserved */ + flag_cma = <1>; + //memory-region = <&di_reserved>; + //memory-region = <&di_cma_reserved>; + interrupts = <0 46 1 + 0 40 1>; + interrupt-names = "pre_irq", "post_irq"; + clocks = <&clkc CLKID_VPU_CLKB_TMP_COMP>, + <&clkc CLKID_VPU_CLKB_COMP>; + clock-names = "vpu_clkb_tmp_composite", + "vpu_clkb_composite"; + clock-range = <334 667>; + /* buffer-size = <3621952>;(yuv422 8bit) */ + buffer-size = <4074560>;/*yuv422 fullpack*/ + /* reserve-iomap = "true"; */ + /* if enable nr10bit, set nr10bit-support to 1 */ + post-wr-support = <1>; + nr10bit-support = <1>; + nrds-enable = <1>; + pps-enable = <1>; + }; + dvb_avl6762 { compatible = "amlogic, dvb"; dev_name = "dvb"; diff --git a/arch/arm64/boot/dts/amlogic/sm1_s905x3_ac214_buildroot.dts b/arch/arm64/boot/dts/amlogic/sm1_s905x3_ac214_buildroot.dts index 336569a7c653..7aa731550c2c 100644 --- a/arch/arm64/boot/dts/amlogic/sm1_s905x3_ac214_buildroot.dts +++ b/arch/arm64/boot/dts/amlogic/sm1_s905x3_ac214_buildroot.dts @@ -100,7 +100,7 @@ * 10x4736064=45.2M(0x2e) support 12bit * 10x4074560=40M(0x28) support 10bit */ - size = <0x0 0x02800000>; + size = <0x0 0x05800000>; alignment = <0x0 0x400000>; }; /* POST PROCESS MANAGER */ @@ -113,7 +113,7 @@ compatible = "shared-dma-pool"; reusable; /* ion_codec_mm max can alloc size 80M*/ - size = <0x0 0x13400000>; + size = <0x0 0x16400000>; alignment = <0x0 0x400000>; linux,contiguous-region; }; @@ -292,8 +292,8 @@ status = "okay"; }; - deinterlace { - compatible = "amlogic, deinterlace"; + multi-di { + compatible = "amlogic, dim-sm1"; status = "okay"; /* 0:use reserved; 1:use cma; 2:use cma as reserved */ flag_cma = <1>; @@ -316,6 +316,32 @@ nrds-enable = <1>; pps-enable = <1>; }; + + deinterlace { + compatible = "amlogic, deinterlace"; + status = "disable";//status = "okay"; + /* 0:use reserved; 1:use cma; 2:use cma as reserved */ + flag_cma = <1>; + //memory-region = <&di_reserved>; + //memory-region = <&di_cma_reserved>; + interrupts = <0 46 1 + 0 40 1>; + interrupt-names = "pre_irq", "post_irq"; + clocks = <&clkc CLKID_VPU_CLKB_TMP_COMP>, + <&clkc CLKID_VPU_CLKB_COMP>; + clock-names = "vpu_clkb_tmp_composite", + "vpu_clkb_composite"; + clock-range = <334 667>; + /* buffer-size = <3621952>;(yuv422 8bit) */ + buffer-size = <4074560>;/*yuv422 fullpack*/ + /* reserve-iomap = "true"; */ + /* if enable nr10bit, set nr10bit-support to 1 */ + post-wr-support = <1>; + nr10bit-support = <1>; + nrds-enable = <1>; + pps-enable = <1>; + }; + dvb { compatible = "amlogic, dvb"; dev_name = "dvb"; diff --git a/arch/arm64/configs/meson64_defconfig b/arch/arm64/configs/meson64_defconfig index 6fed4a796dcd..f71838b08ea4 100644 --- a/arch/arm64/configs/meson64_defconfig +++ b/arch/arm64/configs/meson64_defconfig @@ -331,6 +331,8 @@ CONFIG_AMLOGIC_VIDEOBUF2_ION=y CONFIG_AMLOGIC_IONVIDEO=y CONFIG_AMLOGIC_PIC_DEC=y CONFIG_AMLOGIC_VIDEOSYNC=y +CONFIG_AMLOGIC_V4L_VIDEO3=y +CONFIG_AMLOGIC_VIDEO_COMPOSER=y CONFIG_AMLOGIC_MEDIA_ENHANCEMENT=y CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_VECM=y CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION=y diff --git a/drivers/amlogic/media/common/codec_mm/codec_mm_keeper.c b/drivers/amlogic/media/common/codec_mm/codec_mm_keeper.c index 114ef6fa7914..4fbb1f4b8877 100644 --- a/drivers/amlogic/media/common/codec_mm/codec_mm_keeper.c +++ b/drivers/amlogic/media/common/codec_mm/codec_mm_keeper.c @@ -29,7 +29,7 @@ #include "codec_mm_priv.h" #include "codec_mm_scatter_priv.h" #define KEEP_NAME "keeper" -#define MAX_KEEP_FRAME 16 +#define MAX_KEEP_FRAME 64 #define START_KEEP_ID 0x9 #define MAX_KEEP_ID (INT_MAX - 1) diff --git a/drivers/amlogic/media/deinterlace/deinterlace.c b/drivers/amlogic/media/deinterlace/deinterlace.c index 589834a670d7..9e3acb8300be 100644 --- a/drivers/amlogic/media/deinterlace/deinterlace.c +++ b/drivers/amlogic/media/deinterlace/deinterlace.c @@ -578,6 +578,11 @@ void di_trig_free_mirror_mem(void) up(&di_sema); di_pr_info("%s\n", __func__); } + + if (atomic_read(&di_flag_unreg)) { + diwr_set_power_control_pst(0); + di_pr_info("disable pst pd\n"); + } } EXPORT_SYMBOL(di_trig_free_mirror_mem); static bool di_free_mem_pre(void) @@ -7092,6 +7097,7 @@ static void di_reg_process_irq(void) /*di pre h scaling down: sm1 tm2*/ de_devp->h_sc_down_en = pre_hsc_down_en; switch_vpu_clk_gate_vmod(VPU_VPU_CLKB, VPU_CLK_GATE_ON); + diwr_set_power_control_pst(1); if (post_wr_en && post_wr_support) diwr_set_power_control(1); /* up for vpu clkb rate change */ diff --git a/drivers/amlogic/media/deinterlace/deinterlace_hw.c b/drivers/amlogic/media/deinterlace/deinterlace_hw.c index f8907af16076..29b9918b624d 100644 --- a/drivers/amlogic/media/deinterlace/deinterlace_hw.c +++ b/drivers/amlogic/media/deinterlace/deinterlace_hw.c @@ -3367,6 +3367,12 @@ void diwr_set_power_control(unsigned char enable) enable?VPU_MEM_POWER_ON:VPU_MEM_POWER_DOWN); } +void diwr_set_power_control_pst(unsigned char enable) +{ + switch_vpu_mem_pd_vmod(VPU_DI_POST, + enable ? VPU_MEM_POWER_ON : VPU_MEM_POWER_DOWN); +} + void di_hdr2_hist_init(void) { if (cpu_after_eq(MESON_CPU_MAJOR_ID_TM2)) { diff --git a/drivers/amlogic/media/deinterlace/deinterlace_hw.h b/drivers/amlogic/media/deinterlace/deinterlace_hw.h index 21cbf8523434..96699cef8cb6 100644 --- a/drivers/amlogic/media/deinterlace/deinterlace_hw.h +++ b/drivers/amlogic/media/deinterlace/deinterlace_hw.h @@ -189,6 +189,7 @@ void di_top_gate_control(bool top_en, bool mc_en); void di_pre_gate_control(bool enable, bool mc_enable); void di_post_gate_control(bool gate); void diwr_set_power_control(unsigned char enable); +void diwr_set_power_control_pst(unsigned char enable); void di_hw_disable(bool mc_enable); void enable_di_pre_mif(bool enable, bool mc_enable); void enable_di_post_mif(enum gate_mode_e mode); diff --git a/drivers/amlogic/media/di_multi/deinterlace.c b/drivers/amlogic/media/di_multi/deinterlace.c index 751b5ee43d55..b17f45d0752b 100644 --- a/drivers/amlogic/media/di_multi/deinterlace.c +++ b/drivers/amlogic/media/di_multi/deinterlace.c @@ -1156,7 +1156,7 @@ static void dis2_di(void) ppre->di_inp_buf = NULL; } dim_uninit_buf(0, channel); - if (get_blackout_policy()) { + if (0/*get_blackout_policy()*/) { dim_DI_Wr(DI_CLKG_CTRL, 0x2); if (is_meson_txlx_cpu() || is_meson_txhd_cpu()) { dimh_enable_di_post_mif(GATE_OFF); @@ -1839,7 +1839,9 @@ static unsigned int di_cma_alloc(struct di_dev_s *devp, unsigned int channel) } } } - PR_INF("%s:num_local[%d]\n", __func__, mm->sts.num_local); + PR_INF("%s:num_local[%d]:[%d]\n", __func__, mm->sts.num_local, + alloc_cnt); + alloc_cnt = 0; if (dimp_get(eDI_MP_post_wr_en) && dimp_get(eDI_MP_post_wr_support)) { di_que_list(channel, QUE_POST_FREE, &tmpa[0], &psize); @@ -1875,7 +1877,8 @@ static unsigned int di_cma_alloc(struct di_dev_s *devp, unsigned int channel) if (dimp_get(eDI_MP_cma_print)) pr_info(" addr 0x%lx ok.\n", buf_p->nr_adr); } - PR_INF("%s:num_pst[%d]\n", __func__, mm->sts.num_post); + PR_INF("%s:num_pst[%d]:%d\n", __func__, mm->sts.num_post, + alloc_cnt); } if (de_devp->flag_cma != 0 && de_devp->nrds_enable) { dim_nr_ds_buf_init(de_devp->flag_cma, 0, @@ -1884,8 +1887,8 @@ static unsigned int di_cma_alloc(struct di_dev_s *devp, unsigned int channel) end_time = jiffies_to_msecs(jiffies); delta_time = end_time - start_time; - pr_info("%s:alloc %u buffer use %u ms(%u~%u)\n", - __func__, alloc_cnt, delta_time, start_time, end_time); + pr_info("%s:alloc use %u ms(%u~%u)\n", + __func__, delta_time, start_time, end_time); return 1; } @@ -1895,7 +1898,7 @@ static void di_cma_release(struct di_dev_s *devp, unsigned int channel) struct di_buf_s *buf_p; struct di_buf_s *pbuf_local = get_buf_local(channel); struct di_buf_s *pbuf_post = get_buf_post(channel); - struct di_post_stru_s *ppost = get_post_stru(channel); +/* struct di_post_stru_s *ppost = get_post_stru(channel);*/ struct di_dev_s *de_devp = get_dim_de_devp(); bool ret; struct di_mm_s *mm = dim_mm_get(); @@ -1933,12 +1936,12 @@ static void di_cma_release(struct di_dev_s *devp, unsigned int channel) /*mm-0705 for (i = 0; i < ppost->di_post_num; i++) {*/ for (i = 0; i < mm->cfg.num_post; i++) { buf_p = &pbuf_post[i]; - if (ppost->keep_buf_post && - i == ppost->keep_buf_post->index) + + if (di_que_is_in_que(channel, QUE_POST_KEEP, buf_p)) continue; if (!buf_p->pages) { - PR_ERR("2:%s:post buf[%d] is null\n", + PR_INF("2:%s:post buf[%d] is null\n", __func__, i); continue; } @@ -1995,11 +1998,11 @@ bool dim_cma_top_release(unsigned int ch) #ifdef CONFIG_CMA di_cma_release(de_devp, ch); - #endif return true; } +#ifdef DIM_HIS /*no use*/ /******************************************* * * @@ -2036,6 +2039,7 @@ void keep_buf_in_full(struct di_buf_s *ready_buf) di_keep_buf[i] = ready_buf; } } +#endif int di_cnt_buf(int width, int height, int prog_flag, int mc_mm, int bit10_support, int pack422) @@ -2134,7 +2138,7 @@ static int di_init_buf(int width, int height, unsigned char prog_flag, struct di_post_stru_s *ppost = get_post_stru(channel); struct di_buf_s *keep_buf = ppost->keep_buf; struct di_dev_s *de_devp = get_dim_de_devp(); - struct di_buf_s *keep_buf_post = ppost->keep_buf_post; +/* struct di_buf_s *keep_buf_post = ppost->keep_buf_post;*/ struct di_mm_s *mm = dim_mm_get(); /*mm-0705*/ unsigned int mem_st_local; @@ -2361,11 +2365,11 @@ static int di_init_buf(int width, int height, unsigned char prog_flag, if (di_buf) { if (dimp_get(eDI_MP_post_wr_en) && dimp_get(eDI_MP_post_wr_support)) { - /*ary:for keep buf*/ - if (keep_buf_post && di_buf == keep_buf_post) { - dbg_reg("%s:post keep buf %d:%d\n", + if (di_que_is_in_que(channel, QUE_POST_KEEP, + di_buf)) { + dbg_reg("%s:post keep buf %d\n", __func__, - i, keep_buf_post->index); + di_buf->index); continue; } } @@ -2405,6 +2409,7 @@ static int di_init_buf(int width, int height, unsigned char prog_flag, return 0; } +#ifdef DIM_HIS /*no use*/ void dim_keep_mirror_buffer(unsigned int channel) /*not use*/ { struct di_buf_s *p = NULL; @@ -2444,6 +2449,7 @@ void dim_keep_mirror_buffer(unsigned int channel) /*not use*/ } } } +#endif void dim_post_keep_mirror_buffer(unsigned int channel) { @@ -2471,6 +2477,247 @@ void dim_post_keep_mirror_buffer(unsigned int channel) } } +void dim_post_keep_mirror_buffer2(unsigned int ch) +{ + struct di_buf_s *p = NULL; + int itmp; + + queue_for_each_entry(p, ch, QUEUE_DISPLAY, list) { + if (p->type != VFRAME_TYPE_POST || + !p->process_fun_index) { + dbg_keep("%s:not post buf:%d\n", __func__, p->type); + continue; + } + if (di_que_is_in_que(ch, QUE_POST_BACK, p)) { + dbg_keep("%s:is in back[%d]\n", __func__, p->index); + continue; + } + + p->queue_index = -1; + di_que_in(ch, QUE_POST_KEEP, p); + p->invert_top_bot_flag = 0; + + dbg_keep("%s %d\n", __func__, p->index); + } +} + +bool dim_post_keep_is_in(unsigned int ch, struct di_buf_s *di_buf) +{ + if (di_que_is_in_que(ch, QUE_POST_KEEP, di_buf)) + return true; + return false; +} + +bool dim_post_keep_release_one(unsigned int ch, unsigned int di_buf_index) +{ + struct di_buf_s *pbuf_post; + struct di_buf_s *di_buf; + + /*must post or err*/ + pbuf_post = get_buf_post(ch); + di_buf = &pbuf_post[di_buf_index]; + + if (!di_que_is_in_que(ch, QUE_POST_KEEP, di_buf)) { + PR_ERR("%s:buf[%d] is not in keep\n", __func__, di_buf_index); + return false; + } + di_que_out_not_fifo(ch, QUE_POST_KEEP, di_buf); + di_que_in(ch, QUE_POST_FREE, di_buf); + dbg_keep("%s:buf[%d]\n", __func__, di_buf_index); + return true; +} + +bool dim_post_keep_release_all_2free(unsigned int ch) +{ + struct di_buf_s *di_buf; + struct di_buf_s *pbuf_post; + unsigned int i = 0; + + if (di_que_is_empty(ch, QUE_POST_KEEP)) + return true; + + pbuf_post = get_buf_post(ch); + dbg_keep("%s:ch[%d]\n", __func__, ch); + + while (i <= MAX_POST_BUF_NUM) { + i++; + di_buf = di_que_peek(ch, QUE_POST_KEEP); + if (!di_buf) + break; + + if (!di_que_out(ch, QUE_POST_KEEP, di_buf)) { + PR_ERR("%s:out err\n", __func__); + break; + } + + di_que_in(ch, QUE_POST_FREE, di_buf); + + dbg_keep("\ttype[%d],index[%d]\n", di_buf->type, di_buf->index); + } + + return true; +} + +void dim_post_keep_cmd_release(unsigned int ch, struct vframe_s *vframe) +{ + struct di_buf_s *di_buf; + + if (!vframe) + return; + + di_buf = (struct di_buf_s *)vframe->private_data; + + if (!di_buf) { + PR_WARN("%s:ch[%d]:no di_buf\n", __func__, ch); + return; + } + + if (di_buf->type != VFRAME_TYPE_POST) { + PR_WARN("%s:ch[%d]:not post\n", __func__, ch); + return; + } + dbg_keep("release keep ch[%d],index[%d]\n", + di_buf->channel, + di_buf->index); + task_send_cmd(LCMD2(ECMD_RL_KEEP, di_buf->channel, di_buf->index)); +} +EXPORT_SYMBOL(dim_post_keep_cmd_release); + +void dim_post_keep_cmd_release2(struct vframe_s *vframe) +{ + struct di_buf_s *di_buf; + + if (!vframe) + return; + + di_buf = (struct di_buf_s *)vframe->private_data; + + if (!di_buf) { + PR_WARN("%s:no di_buf\n", __func__); + return; + } + + if (di_buf->type != VFRAME_TYPE_POST) { + PR_WARN("%s:ch[%d]:not post\n", __func__, di_buf->channel); + return; + } + dbg_keep("release keep ch[%d],index[%d]\n", + di_buf->channel, + di_buf->index); + task_send_cmd(LCMD2(ECMD_RL_KEEP, di_buf->channel, di_buf->index)); +} +EXPORT_SYMBOL(dim_post_keep_cmd_release2); + +void dim_dbg_release_keep_all(unsigned int ch) +{ + unsigned int tmpa[MAX_FIFO_SIZE]; + unsigned int psize, itmp; + struct di_buf_s *p; + + di_que_list(ch, QUE_POST_KEEP, &tmpa[0], &psize); + dbg_keep("post_keep: curr(%d)\n", psize); + + for (itmp = 0; itmp < psize; itmp++) { + p = pw_qindex_2_buf(ch, tmpa[itmp]); + dbg_keep("\ttype[%d],index[%d]\n", p->type, p->index); + dim_post_keep_cmd_release(ch, p->vframe); + } + dbg_keep("%s:end\n", __func__); +} + +void dim_post_keep_back_recycle(unsigned int ch) +{ + unsigned int tmpa[MAX_FIFO_SIZE]; + unsigned int psize, itmp; + struct di_buf_s *p; + + if (di_que_is_empty(ch, QUE_POST_KEEP_BACK)) + return; + di_que_list(ch, QUE_POST_KEEP_BACK, &tmpa[0], &psize); + dbg_keep("post_keep_back: curr(%d)\n", psize); + for (itmp = 0; itmp < psize; itmp++) { + p = pw_qindex_2_buf(ch, tmpa[itmp]); + dbg_keep("keep back recycle %d\n", p->index); + dim_post_keep_release_one(ch, p->index); + } + pw_queue_clear(ch, QUE_POST_KEEP_BACK); +} + +void dim_post_keep_cmd_proc(unsigned int ch, unsigned int index) +{ + struct di_dev_s *di_dev; + enum EDI_TOP_STATE chst; + unsigned int len_keep, len_back; + struct di_buf_s *pbuf_post; + struct di_buf_s *di_buf; + + /*must post or err*/ + di_dev = get_dim_de_devp(); + + if (!di_dev || !di_dev->data_l) { + PR_WARN("%s: no di_dev\n", __func__); + return; + } + + chst = dip_chst_get(ch); + switch (chst) { + case EDI_TOP_STATE_READY: + dim_post_keep_release_one(ch, index); + break; + case EDI_TOP_STATE_IDLE: + case eDI_TOP_STATE_BYPASS: + pbuf_post = get_buf_post(ch); + if (!pbuf_post) { + PR_ERR("%s:no pbuf_post\n", __func__); + break; + } + + di_buf = &pbuf_post[index]; + di_buf->queue_index = -1; + di_que_in(ch, QUE_POST_KEEP_BACK, di_buf); + len_keep = di_que_list_count(ch, QUE_POST_KEEP); + len_back = di_que_list_count(ch, QUE_POST_KEEP_BACK); + if (len_back >= len_keep) { + /*release all*/ + pw_queue_clear(ch, QUE_POST_KEEP); + pw_queue_clear(ch, QUE_POST_KEEP_BACK); + dip_wq_cma_run(ch, false); + } + break; + case eDI_TOP_STATE_REG_STEP1: + case eDI_TOP_STATE_REG_STEP1_P1: + case eDI_TOP_STATE_REG_STEP2: + pbuf_post = get_buf_post(ch); + if (!pbuf_post) { + PR_ERR("%s:no pbuf_post\n", __func__); + break; + } + + di_buf = &pbuf_post[index]; + di_buf->queue_index = -1; + di_que_in(ch, QUE_POST_KEEP_BACK, di_buf); + + break; + case eDI_TOP_STATE_UNREG_STEP1: + pbuf_post = get_buf_post(ch); + if (!pbuf_post) { + PR_ERR("%s:no pbuf_post\n", __func__); + break; + } + + di_buf = &pbuf_post[index]; + di_buf->queue_index = -1; + di_que_in(ch, QUE_POST_KEEP_BACK, di_buf); + break; + default: + PR_ERR("%s:do nothing? %s:%d\n", + __func__, + dip_chst_get_name(chst), + index); + break; + } +} + void dim_uninit_buf(unsigned int disable_mirror, unsigned int channel) { /*int i = 0;*/ @@ -2498,7 +2745,7 @@ void dim_uninit_buf(unsigned int disable_mirror, unsigned int channel) } #else if (!disable_mirror) - dim_post_keep_mirror_buffer(channel); + dim_post_keep_mirror_buffer2(channel); #endif queue_init(channel, 0); di_que_init(channel); /*new que*/ @@ -6648,7 +6895,8 @@ void dim_unreg_process(unsigned int channel) void di_unreg_setting(void) { - unsigned int mirror_disable = get_blackout_policy(); + /*unsigned int mirror_disable = get_blackout_policy();*/ + unsigned int mirror_disable = 0; if (!get_hw_reg_flg()) { PR_ERR("%s:have setting?do nothing\n", __func__); @@ -6748,7 +6996,8 @@ void di_unreg_variable(unsigned int channel) #endif pr_info("%s:\n", __func__); set_init_flag(channel, false); /*init_flag = 0;*/ - mirror_disable = get_blackout_policy(); + /*mirror_disable = get_blackout_policy();*/ + mirror_disable = 0; di_lock_irqfiq_save(irq_flag2); dim_print("%s: dim_uninit_buf\n", __func__); dim_uninit_buf(mirror_disable, channel); @@ -7138,9 +7387,10 @@ void di_reg_setting(unsigned int channel, struct vframe_s *vframe) /*if (!use_2_interlace_buff) {*/ if (1) { dim_top_gate_control(true, true); - dim_post_gate_control(true); + /*dim_post_gate_control(true);*/ /* freerun for reg configuration */ - dimh_enable_di_post_mif(GATE_AUTO); + /*dimh_enable_di_post_mif(GATE_AUTO);*/ + hpst_power_ctr(true); } else { dim_top_gate_control(true, false); } @@ -7622,7 +7872,7 @@ struct vframe_s *di_vf_l_get(unsigned int channel) } /**************************/ - if (list_count(channel, QUEUE_DISPLAY) > 2) { + if (list_count(channel, QUEUE_DISPLAY) > DI_POST_GET_LIMIT) { dim_tr_ops.post_get2(2); return NULL; } @@ -7794,7 +8044,12 @@ void di_vf_l_put(struct vframe_s *vf, unsigned char channel) recycle_vframe_type_post_print(di_buf, __func__, __LINE__); #endif #else + #ifdef DIM_HIS /*no use*/ pw_queue_in(channel, QUE_POST_BACK, di_buf->index); + #else + di_buf->queue_index = -1; + di_que_in(channel, QUE_POST_BACK, di_buf); + #endif #endif } else { di_lock_irqfiq_save(irq_flag2); @@ -7811,15 +8066,13 @@ void di_vf_l_put(struct vframe_s *vf, unsigned char channel) void dim_recycle_post_back(unsigned int channel) { struct di_buf_s *di_buf = NULL; - unsigned int post_buf_index; - struct di_buf_s *pbuf_post = get_buf_post(channel); ulong irq_flag2 = 0; + unsigned int i = 0; - struct di_post_stru_s *ppost = get_post_stru(channel); - - if (pw_queue_empty(channel, QUE_POST_BACK)) + if (di_que_is_empty(channel, QUE_POST_BACK)) return; + #ifdef DIM_HIS /*history*/ while (pw_queue_out(channel, QUE_POST_BACK, &post_buf_index)) { /*pr_info("dp2:%d\n", post_buf_index);*/ if (post_buf_index >= MAX_POST_BUF_NUM) { @@ -7836,6 +8089,39 @@ void dim_recycle_post_back(unsigned int channel) recycle_vframe_type_post(di_buf, channel); di_unlock_irqfiq_restore(irq_flag2); } + #else + while (i < MAX_FIFO_SIZE) { + i++; + + di_buf = di_que_peek(channel, QUE_POST_BACK); + /*pr_info("dp2:%d\n", post_buf_index);*/ + if (!di_buf) + break; + + if (di_buf->type != VFRAME_TYPE_POST) { + queue_out(channel, di_buf); + PR_ERR("%s:type is not post\n", __func__); + continue; + } + + dim_print("di_back:%d\n", di_buf->index); + di_lock_irqfiq_save(irq_flag2); /**/ + di_que_out(channel, QUE_POST_BACK, di_buf); + di_buf->queue_index = QUEUE_DISPLAY; + queue_out(channel, di_buf); + + if (!atomic_dec_and_test(&di_buf->di_cnt)) + PR_ERR("%s,di_cnt > 0\n", __func__); + + /*recycle_vframe_type_post(di_buf, channel);*/ + di_buf->invert_top_bot_flag = 0; + di_que_in(channel, QUE_POST_FREE, di_buf); + + di_unlock_irqfiq_restore(irq_flag2); + } + + #endif + #ifdef DIM_HIS /*history*/ /*back keep_buf:*/ if (ppost->keep_buf_post) { PR_INF("ch[%d]:%s:%d\n", @@ -7847,6 +8133,10 @@ void dim_recycle_post_back(unsigned int channel) di_unlock_irqfiq_restore(irq_flag2); ppost->keep_buf_post = NULL; } + #else + if (di_cfg_top_get(EDI_CFG_KEEP_CLEAR_AUTO)) + dim_post_keep_release_all_2free(channel); + #endif } struct vframe_s *di_vf_l_peek(unsigned int channel) @@ -7878,7 +8168,7 @@ struct vframe_s *di_vf_l_peek(unsigned int channel) } /**************************/ dim_log_buffer_state("pek", channel); - + task_send_ready(); #ifdef SUPPORT_START_FRAME_HOLD if ((disp_frame_count == 0) && (dim_is_bypass(NULL, channel) == 0)) { int ready_count = di_que_list_count(channel, QUE_POST_READY); diff --git a/drivers/amlogic/media/di_multi/deinterlace.h b/drivers/amlogic/media/di_multi/deinterlace.h index 96abc673f676..2cc8feb7f96c 100644 --- a/drivers/amlogic/media/di_multi/deinterlace.h +++ b/drivers/amlogic/media/di_multi/deinterlace.h @@ -51,14 +51,14 @@ /* buffer management related */ #define MAX_IN_BUF_NUM (4) #define MAX_LOCAL_BUF_NUM (7) -#define MAX_POST_BUF_NUM (7) /*(5)*/ /* 16 */ +#define MAX_POST_BUF_NUM (11) /*(5)*/ /* 16 */ #define VFRAME_TYPE_IN 1 #define VFRAME_TYPE_LOCAL 2 #define VFRAME_TYPE_POST 3 #define VFRAME_TYPE_NUM 3 -#define DI_POST_GET_LIMIT 4 +#define DI_POST_GET_LIMIT 8 #define DI_PRE_READY_LIMIT 4 /*vframe define*/ #define vframe_t struct vframe_s @@ -583,6 +583,7 @@ void dim_reg_timeout_inc(void); void dim_reg_process(unsigned int channel); bool is_bypass2(struct vframe_s *vf_in, unsigned int ch); +void dim_post_keep_cmd_proc(unsigned int ch, unsigned int index); /*--------------------------*/ int di_ori_event_unreg(unsigned int channel); @@ -610,6 +611,8 @@ void di_vf_l_put(struct vframe_s *vf, unsigned char channel); struct vframe_s *di_vf_l_get(unsigned int channel); unsigned char pre_p_asi_de_buf_config(unsigned int ch); +void dim_dbg_release_keep_all(unsigned int ch); +void dim_post_keep_back_recycle(unsigned int ch); /*---------------------*/ diff --git a/drivers/amlogic/media/di_multi/deinterlace_dbg.c b/drivers/amlogic/media/di_multi/deinterlace_dbg.c index 153f6e07bbb5..8ddb257b397d 100644 --- a/drivers/amlogic/media/di_multi/deinterlace_dbg.c +++ b/drivers/amlogic/media/di_multi/deinterlace_dbg.c @@ -900,7 +900,6 @@ int dim_state_show(struct seq_file *seq, void *v, unsigned int channel) unsigned int psize; /*new que*/ struct di_hpre_s *pre = get_hw_pre(); struct di_hpst_s *post = get_hw_pst(); - struct di_buf_s *keep_buf_post = NULL; char *splt = "---------------------------"; struct di_mm_s *mm = dim_mm_get(); /*mm-0705*/ @@ -933,17 +932,7 @@ int dim_state_show(struct seq_file *seq, void *v, unsigned int channel) IS_ERR_OR_NULL(p) ? -1 : p->index, p); } } - /********************************/ - /* check keep buf post */ - /********************************/ - keep_buf_post = di_post_stru_p->keep_buf_post; - if (IS_ERR_OR_NULL(keep_buf_post)) - seq_printf(seq, "%s:NULL\n", "keep_buf_post"); - else - seq_printf(seq, "%s:type=%d:index=%d\n", - "keep_buf_post", - keep_buf_post->type, keep_buf_post->index); /********************************/ /* in_free_list */ /********************************/ @@ -1056,8 +1045,33 @@ int dim_state_show(struct seq_file *seq, void *v, unsigned int channel) di_que_list(channel, QUE_POST_BACK, &tmpa[0], &psize); /*new que*/ seq_printf(seq, "post_back: curr(%d)\n", psize); - for (itmp = 0; itmp < psize; itmp++) { /*new que*/ - seq_printf(seq, "%d\n", tmpa[itmp]); + for (itmp = 0; itmp < psize; itmp++) { + p = pw_qindex_2_buf(channel, tmpa[itmp]); + seq_printf(seq, "\ttype[%d],index[%d]\n", p->type, p->index); + } + seq_printf(seq, "%s\n", splt); + + /********************************/ + /* post keep */ + /********************************/ + di_que_list(channel, QUE_POST_KEEP, &tmpa[0], &psize); + seq_printf(seq, "post_keep: curr(%d)\n", psize); + + for (itmp = 0; itmp < psize; itmp++) { + p = pw_qindex_2_buf(channel, tmpa[itmp]); + seq_printf(seq, "\ttype[%d],index[%d]\n", p->type, p->index); + } + seq_printf(seq, "%s\n", splt); + + /******************************** + * post keep back + ********************************/ + di_que_list(channel, QUE_POST_KEEP_BACK, &tmpa[0], &psize); + seq_printf(seq, "post_keep_back: curr(%d)\n", psize); + + for (itmp = 0; itmp < psize; itmp++) { + p = pw_qindex_2_buf(channel, tmpa[itmp]); + seq_printf(seq, "\ttype[%d],index[%d]\n", p->type, p->index); } seq_printf(seq, "%s\n", splt); diff --git a/drivers/amlogic/media/di_multi/deinterlace_hw.c b/drivers/amlogic/media/di_multi/deinterlace_hw.c index 5fa6bfb65c50..7a7baebd1ad6 100644 --- a/drivers/amlogic/media/di_multi/deinterlace_hw.c +++ b/drivers/amlogic/media/di_multi/deinterlace_hw.c @@ -2680,8 +2680,10 @@ void dimh_initial_di_post_2(int hsize_post, int vsize_post, DI_VSYNC_WR_MPEG_REG_BITS(VD1_AFBCD0_MISC_CTRL, 1, 8, 1); #endif + #ifdef DIM_HIS dim_VSYNC_WR_MPEG_REG_BITS(VD1_AFBCD0_MISC_CTRL, 0, 8, 1); + #endif } else { dim_VSYNC_WR_MPEG_REG_BITS(VD1_AFBCD0_MISC_CTRL, 1, 8, 1); @@ -3050,9 +3052,11 @@ void dimh_disable_post_deinterlace_2(void) if (cpu_after_eq(MESON_CPU_MAJOR_ID_G12A)) { /*dbg a dim_VSYNC_WR_MPEG_REG(DI_POST_GL_CTRL, 0);*/ di_post_set_flow(1, eDI_POST_FLOW_STEP1_STOP); + #ifdef DIM_HIS dim_print("%s:VD1_AFBCD0_MISC_CTRL 0", __func__); dim_VSYNC_WR_MPEG_REG_BITS(VD1_AFBCD0_MISC_CTRL, 0, 8, 2); dim_VSYNC_WR_MPEG_REG_BITS(VD1_AFBCD0_MISC_CTRL, 0, 20, 2); + #endif } } diff --git a/drivers/amlogic/media/di_multi/di_data_l.h b/drivers/amlogic/media/di_multi/di_data_l.h index bdec462730b3..b512d919a7ab 100644 --- a/drivers/amlogic/media/di_multi/di_data_l.h +++ b/drivers/amlogic/media/di_multi/di_data_l.h @@ -64,6 +64,7 @@ enum eDI_CFG_TOP_IDX { eDI_CFG_BEGIN, eDI_CFG_first_bypass, eDI_CFG_ref_2, + EDI_CFG_KEEP_CLEAR_AUTO, eDI_CFG_END, }; @@ -360,16 +361,16 @@ struct di_hpst_s { /**************************************/ /* channel status */ /**************************************/ -enum eDI_TOP_STATE { +enum EDI_TOP_STATE { eDI_TOP_STATE_NOPROB, - eDI_TOP_STATE_IDLE, /*idle not work*/ + EDI_TOP_STATE_IDLE, /*idle not work*/ /* STEP1 * till peek vframe and set irq;before this state, event reg finish */ eDI_TOP_STATE_REG_STEP1, eDI_TOP_STATE_REG_STEP1_P1, /*2019-05-21*/ eDI_TOP_STATE_REG_STEP2, /*till alloc and ready*/ - eDI_TOP_STATE_READY, /*can do DI*/ + EDI_TOP_STATE_READY, /*can do DI*/ eDI_TOP_STATE_BYPASS, /*complet bypass*/ eDI_TOP_STATE_UNREG_STEP1, /*till pre/post is finish;*/ /* do unreg and to IDLE. @@ -415,6 +416,7 @@ union DI_L_CMD_BITS { }; #define LCMD1(id, ch) ((id) | ((ch) << 8)) +#define LCMD2(id, ch, p2) ((id) | ((ch) << 8) | ((p2) << 16)) enum eCMD_LOCAL { eCMD_NONE, @@ -422,18 +424,22 @@ enum eCMD_LOCAL { eCMD_UNREG, eCMD_READY, eCMD_CHG, + ECMD_RL_KEEP, NR_FINISH, }; -/**************************************/ -/*QUE*/ -/**************************************/ +/************************************** + * QUE + * keep same order as di_name_new_que + **************************************/ enum QUE_TYPE { /*mast start from 0 */ QUE_IN_FREE, /*5*/ QUE_PRE_READY, /*6*/ QUE_POST_FREE, /*7*/ QUE_POST_READY, /*8*/ QUE_POST_BACK, /*new*/ + QUE_POST_KEEP, /*below use pw_queue_in*/ + QUE_POST_KEEP_BACK, /*----------------*/ QUE_DBG, QUE_NUB, @@ -734,10 +740,11 @@ struct di_ores_s { }; enum eDI_CMA_ST { - eDI_CMA_ST_IDL, - eDI_CMA_ST_ALLOC, /*do*/ - eDI_CMA_ST_READY, - eDI_CMA_ST_RELEASE, /*do*/ + EDI_CMA_ST_IDL, + EDI_CMA_ST_ALLOC, /*do*/ + EDI_CMA_ST_READY, + EDI_CMA_ST_RELEASE, /*do*/ + EDI_CMA_ST_PART, }; /********************************** @@ -805,10 +812,16 @@ struct di_meson_data { /*struct ddemod_reg_off regoff;*/ }; -struct di_mng_s { - /*workqueue*/ +struct dim_wq_s { + char *name; + unsigned int ch; struct workqueue_struct *wq_cma; struct work_struct wq_work; +}; + +struct di_mng_s { + /*workqueue*/ + struct dim_wq_s wq; /*use enum eDI_CMA_ST*/ atomic_t cma_mem_state[DI_CHANNEL_NUB]; @@ -958,6 +971,7 @@ struct di_data_l_s { #define DBG_M_POLLING 0x100 #define DBG_M_ONCE 0x200 +#define DBG_M_KEEP 0x400 extern unsigned int di_dbg; @@ -986,6 +1000,7 @@ extern unsigned int di_dbg; #define dbg_first_frame(fmt, args ...) dbg_m(DBG_M_FIRSTFRAME, fmt, ##args) #define dbg_dbg(fmt, args ...) dbg_m(DBG_M_DBG, fmt, ##args) #define dbg_once(fmt, args ...) dbg_m(DBG_M_ONCE, fmt, ##args) +#define dbg_keep(fmt, args ...) dbg_m(DBG_M_KEEP, fmt, ##args) char *di_cfgx_get_name(enum eDI_CFGX_IDX idx); bool di_cfgx_get(unsigned int ch, enum eDI_CFGX_IDX idx); diff --git a/drivers/amlogic/media/di_multi/di_dbg.c b/drivers/amlogic/media/di_multi/di_dbg.c index 9c7763bcd733..e14346f603b2 100644 --- a/drivers/amlogic/media/di_multi/di_dbg.c +++ b/drivers/amlogic/media/di_multi/di_dbg.c @@ -1010,6 +1010,40 @@ static ssize_t wcfgx_store(struct file *file, const char __user *userbuf, return count; } +/*********************************************** + * + ***********************************************/ +ssize_t keep_buf_clear_store(struct file *file, const char __user *userbuf, + size_t count, loff_t *ppos) +{ + char buf[20]; + int ret; + + unsigned int ch; + + count = min_t(size_t, count, (sizeof(buf) - 1)); + if (copy_from_user(buf, userbuf, count)) + return -EFAULT; + + buf[count] = 0; + /*reg, bit, width, val*/ + + ret = kstrtouint(buf, 0, &ch); + if (ret) { + pr_info("war:please enter ch\n"); + return 0; + } + pr_info("ch:%d", ch); + + if (ch >= DI_CHANNEL_NUB) { + PR_ERR("%s:ch is overflow %d\n", __func__, ch); + return 0; + } + + dim_dbg_release_keep_all(ch); + + return count; +} /*************************************************************** * parameter show and store for top : DI **************************************************************/ @@ -1519,6 +1553,7 @@ DEFINE_STORE_ONLY(mpw_nr); DEFINE_STORE_ONLY(mpw_pd); DEFINE_STORE_ONLY(mpw_mtn); DEFINE_STORE_ONLY(buf_cnt); +DEFINE_STORE_ONLY(keep_buf_clear); DEFINE_SHOW_STORE(reg); @@ -1550,6 +1585,7 @@ static const struct di_dbgfs_files_t di_debugfs_files_top[] = { {"mr_mtn", S_IFREG | 0644, &mpr_mtn_fops}, {"mw_mtn", S_IFREG | 0644, &mpw_mtn_fops}, {"buf_cnt", S_IFREG | 0644, &buf_cnt_fops}, + {"keep_clear", S_IFREG | 0644, &keep_buf_clear_fops}, }; static const struct di_dbgfs_files_t di_debugfs_files[] = { diff --git a/drivers/amlogic/media/di_multi/di_prc.c b/drivers/amlogic/media/di_multi/di_prc.c index 8929fdfd4d12..3e65aa47a6eb 100644 --- a/drivers/amlogic/media/di_multi/di_prc.c +++ b/drivers/amlogic/media/di_multi/di_prc.c @@ -49,6 +49,8 @@ const struct di_cfg_ctr_s di_cfg_top_ctr[K_DI_CFG_NUB] = { eDI_CFG_first_bypass, 1}, [eDI_CFG_ref_2] = {"ref_2", eDI_CFG_ref_2, 0}, + [EDI_CFG_KEEP_CLEAR_AUTO] = {"keep_buf clear auto", + EDI_CFG_KEEP_CLEAR_AUTO, 1}, [eDI_CFG_END] = {"cfg top end ", eDI_CFG_END, 0}, }; @@ -823,7 +825,7 @@ static void dip_cma_init_val(void) for (ch = 0; ch < DI_CHANNEL_NUB; ch++) { /* CMA state */ - atomic_set(&pbm->cma_mem_state[ch], eDI_CMA_ST_IDL); + atomic_set(&pbm->cma_mem_state[ch], EDI_CMA_ST_IDL); /* CMA reg/unreg cmd */ pbm->cma_reg_cmd[ch] = 0; @@ -842,7 +844,7 @@ void dip_cma_close(void) if (!dip_cma_st_is_idle(ch)) { dim_cma_top_release(ch); pr_info("%s:force release ch[%d]", __func__, ch); - atomic_set(&pbm->cma_mem_state[ch], eDI_CMA_ST_IDL); + atomic_set(&pbm->cma_mem_state[ch], EDI_CMA_ST_IDL); pbm->cma_reg_cmd[ch] = 0; } @@ -851,48 +853,78 @@ void dip_cma_close(void) static void dip_wq_cma_handler(struct work_struct *work) { - unsigned int ch; struct di_mng_s *pbm = get_bufmng(); enum eDI_CMA_ST cma_st; bool do_flg; + struct dim_wq_s *wq = container_of(work, struct dim_wq_s, wq_work); - pr_info("%s:start\n", __func__); - for (ch = 0; ch < DI_CHANNEL_NUB; ch++) { - do_flg = false; - cma_st = dip_cma_get_st(ch); - switch (cma_st) { - case eDI_CMA_ST_IDL: - if (pbm->cma_reg_cmd[ch]) { - do_flg = true; - /*set:alloc:*/ + unsigned int ch = wq->ch; + + pr_info("%s:ch[%d],start\n", __func__, ch); + + do_flg = false; + cma_st = dip_cma_get_st(ch); + switch (cma_st) { + case EDI_CMA_ST_IDL: + if (pbm->cma_reg_cmd[ch]) { + do_flg = true; + /*set:alloc:*/ + atomic_set(&pbm->cma_mem_state[ch], EDI_CMA_ST_ALLOC); + if (dim_cma_top_alloc(ch)) { atomic_set(&pbm->cma_mem_state[ch], - eDI_CMA_ST_ALLOC); - if (dim_cma_top_alloc(ch)) { - atomic_set(&pbm->cma_mem_state[ch], - eDI_CMA_ST_READY); - } + EDI_CMA_ST_READY); } - break; - case eDI_CMA_ST_READY: - if (!pbm->cma_reg_cmd[ch]) { - do_flg = true; + } + break; + case EDI_CMA_ST_READY: + + if (!pbm->cma_reg_cmd[ch]) { + do_flg = true; + atomic_set(&pbm->cma_mem_state[ch], + EDI_CMA_ST_RELEASE); + dim_cma_top_release(ch); + if (di_que_is_empty(ch, QUE_POST_KEEP)) + atomic_set(&pbm->cma_mem_state[ch], + EDI_CMA_ST_IDL); + else atomic_set(&pbm->cma_mem_state[ch], - eDI_CMA_ST_RELEASE); - dim_cma_top_release(ch); + EDI_CMA_ST_PART); + } + break; + case EDI_CMA_ST_PART: + if (pbm->cma_reg_cmd[ch]) { + do_flg = true; + /*set:alloc:*/ + atomic_set(&pbm->cma_mem_state[ch], EDI_CMA_ST_ALLOC); + if (dim_cma_top_alloc(ch)) { atomic_set(&pbm->cma_mem_state[ch], - eDI_CMA_ST_IDL); + EDI_CMA_ST_READY); } - break; - case eDI_CMA_ST_ALLOC: /*do*/ - case eDI_CMA_ST_RELEASE:/*do*/ - default: - break; + } else { + do_flg = true; + atomic_set(&pbm->cma_mem_state[ch], + EDI_CMA_ST_RELEASE); + dim_cma_top_release(ch); + if (di_que_is_empty(ch, QUE_POST_KEEP)) + atomic_set(&pbm->cma_mem_state[ch], + EDI_CMA_ST_IDL); + else + atomic_set(&pbm->cma_mem_state[ch], + EDI_CMA_ST_PART); + } - if (!do_flg) - pr_info("\tch[%d],do nothing[%d]\n", ch, cma_st); - else - task_send_ready(); + + break; + case EDI_CMA_ST_ALLOC: /*do*/ + case EDI_CMA_ST_RELEASE:/*do*/ + default: + break; } + if (!do_flg) + pr_info("\tch[%d],do nothing[%d]\n", ch, cma_st); + else + task_send_ready(); + pr_info("%s:end\n", __func__); } @@ -900,16 +932,16 @@ static void dip_wq_prob(void) { struct di_mng_s *pbm = get_bufmng(); - pbm->wq_cma = create_singlethread_workqueue("deinterlace"); - INIT_WORK(&pbm->wq_work, dip_wq_cma_handler); + pbm->wq.wq_cma = create_singlethread_workqueue("deinterlace"); + INIT_WORK(&pbm->wq.wq_work, dip_wq_cma_handler); } static void dip_wq_ext(void) { struct di_mng_s *pbm = get_bufmng(); - cancel_work_sync(&pbm->wq_work); - destroy_workqueue(pbm->wq_cma); + cancel_work_sync(&pbm->wq.wq_work); + destroy_workqueue(pbm->wq.wq_cma); pr_info("%s:finish\n", __func__); } @@ -922,7 +954,8 @@ void dip_wq_cma_run(unsigned char ch, bool reg_cmd) else pbm->cma_reg_cmd[ch] = 0; - queue_work(pbm->wq_cma, &pbm->wq_work); + pbm->wq.ch = ch; + queue_work(pbm->wq.wq_cma, &pbm->wq.wq_work); } bool dip_cma_st_is_ready(unsigned int ch) @@ -930,7 +963,7 @@ bool dip_cma_st_is_ready(unsigned int ch) struct di_mng_s *pbm = get_bufmng(); bool ret = false; - if (atomic_read(&pbm->cma_mem_state[ch]) == eDI_CMA_ST_READY) + if (atomic_read(&pbm->cma_mem_state[ch]) == EDI_CMA_ST_READY) ret = true; return ret; @@ -941,7 +974,7 @@ bool dip_cma_st_is_idle(unsigned int ch) struct di_mng_s *pbm = get_bufmng(); bool ret = false; - if (atomic_read(&pbm->cma_mem_state[ch]) == eDI_CMA_ST_IDL) + if (atomic_read(&pbm->cma_mem_state[ch]) == EDI_CMA_ST_IDL) ret = true; return ret; @@ -954,7 +987,7 @@ bool dip_cma_st_is_idl_all(void) bool ret = true; for (ch = 0; ch < DI_CHANNEL_NUB; ch++) { - if (atomic_read(&pbm->cma_mem_state[ch]) != eDI_CMA_ST_IDL) { + if (atomic_read(&pbm->cma_mem_state[ch]) != EDI_CMA_ST_IDL) { ret = true; break; } @@ -981,7 +1014,7 @@ const char *di_cma_dbg_get_st_name(unsigned int ch) enum eDI_CMA_ST st = dip_cma_get_st(ch); const char *p = ""; - if (st <= eDI_CMA_ST_RELEASE) + if (st <= EDI_CMA_ST_RELEASE) p = di_cma_state_name[st]; return p; } @@ -992,20 +1025,20 @@ void dip_cma_st_set_ready_all(void) struct di_mng_s *pbm = get_bufmng(); for (ch = 0; ch < DI_CHANNEL_NUB; ch++) - atomic_set(&pbm->cma_mem_state[ch], eDI_CMA_ST_READY); + atomic_set(&pbm->cma_mem_state[ch], EDI_CMA_ST_READY); } /****************************/ /*channel STATE*/ /****************************/ -void dip_chst_set(unsigned int ch, enum eDI_TOP_STATE chSt) +void dip_chst_set(unsigned int ch, enum EDI_TOP_STATE chst) { struct di_mng_s *pbm = get_bufmng(); - atomic_set(&pbm->ch_state[ch], chSt); + atomic_set(&pbm->ch_state[ch], chst); } -enum eDI_TOP_STATE dip_chst_get(unsigned int ch) +enum EDI_TOP_STATE dip_chst_get(unsigned int ch) { struct di_mng_s *pbm = get_bufmng(); @@ -1017,12 +1050,12 @@ void dip_chst_init(void) unsigned int ch; for (ch = 0; ch < DI_CHANNEL_NUB; ch++) - dip_chst_set(ch, eDI_TOP_STATE_IDLE); + dip_chst_set(ch, EDI_TOP_STATE_IDLE); } bool dip_event_reg_chst(unsigned int ch) { - enum eDI_TOP_STATE chst; + enum EDI_TOP_STATE chst; struct di_pre_stru_s *ppre = get_pre_stru(ch); bool err_flg = false; bool ret = true; @@ -1035,7 +1068,7 @@ bool dip_event_reg_chst(unsigned int ch) set_flag_trig_unreg(ch, false); #endif switch (chst) { - case eDI_TOP_STATE_IDLE: + case EDI_TOP_STATE_IDLE: queue_init2(ch); di_que_init(ch); @@ -1048,7 +1081,7 @@ bool dip_event_reg_chst(unsigned int ch) case eDI_TOP_STATE_REG_STEP1: case eDI_TOP_STATE_REG_STEP1_P1: case eDI_TOP_STATE_REG_STEP2: - case eDI_TOP_STATE_READY: + case EDI_TOP_STATE_READY: case eDI_TOP_STATE_BYPASS: PR_WARN("have reg\n"); ret = false; @@ -1057,7 +1090,7 @@ bool dip_event_reg_chst(unsigned int ch) case eDI_TOP_STATE_UNREG_STEP2: /*wait*/ ppre->reg_req_flag_cnt = 0; - while (dip_chst_get(ch) != eDI_TOP_STATE_IDLE) { + while (dip_chst_get(ch) != EDI_TOP_STATE_IDLE) { usleep_range(10000, 10001); if (ppre->reg_req_flag_cnt++ > dim_get_reg_unreg_cnt()) { @@ -1093,7 +1126,7 @@ bool dip_event_reg_chst(unsigned int ch) bool dip_event_unreg_chst(unsigned int ch) { - enum eDI_TOP_STATE chst, chst2; + enum EDI_TOP_STATE chst, chst2; struct di_pre_stru_s *ppre = get_pre_stru(ch); bool ret = false; bool err_flg = false; @@ -1109,7 +1142,7 @@ bool dip_event_unreg_chst(unsigned int ch) set_flag_trig_unreg(ch, true); switch (chst) { - case eDI_TOP_STATE_READY: + case EDI_TOP_STATE_READY: di_vframe_unreg(ch); /*trig unreg*/ @@ -1121,7 +1154,7 @@ bool dip_event_unreg_chst(unsigned int ch) ppre->unreg_req_flag_cnt = 0; chst2 = dip_chst_get(ch); - while (chst2 != eDI_TOP_STATE_IDLE) { + while (chst2 != EDI_TOP_STATE_IDLE) { task_send_ready(); usleep_range(10000, 10001); /*msleep(5);*/ @@ -1161,18 +1194,18 @@ bool dip_event_unreg_chst(unsigned int ch) dpre_init(); dpost_init(); } - dip_chst_set(ch, eDI_TOP_STATE_IDLE); + dip_chst_set(ch, EDI_TOP_STATE_IDLE); ret = true; break; - case eDI_TOP_STATE_IDLE: + case EDI_TOP_STATE_IDLE: PR_WARN("have unreg\n"); break; case eDI_TOP_STATE_REG_STEP1: dbg_dbg("%s:in reg step1\n", __func__); di_vframe_unreg(ch); set_reg_flag(ch, false); - dip_chst_set(ch, eDI_TOP_STATE_IDLE); + dip_chst_set(ch, EDI_TOP_STATE_IDLE); ret = true; break; @@ -1199,7 +1232,7 @@ bool dip_event_unreg_chst(unsigned int ch) ppre->unreg_req_flag_cnt = 0; chst2 = dip_chst_get(ch); - while (chst2 != eDI_TOP_STATE_IDLE) { + while (chst2 != EDI_TOP_STATE_IDLE) { task_send_ready(); usleep_range(10000, 10001); /*msleep(5);*/ @@ -1232,7 +1265,7 @@ bool dip_event_unreg_chst(unsigned int ch) dpost_init(); } - dip_chst_set(ch, eDI_TOP_STATE_IDLE); + dip_chst_set(ch, EDI_TOP_STATE_IDLE); ret = true; break; @@ -1242,7 +1275,7 @@ bool dip_event_unreg_chst(unsigned int ch) /*wait*/ ppre->unreg_req_flag_cnt = 0; - while (dip_chst_get(ch) != eDI_TOP_STATE_IDLE) { + while (dip_chst_get(ch) != EDI_TOP_STATE_IDLE) { usleep_range(10000, 10001); if (ppre->unreg_req_flag_cnt++ > dim_get_reg_unreg_cnt()) { @@ -1269,7 +1302,7 @@ bool dip_event_unreg_chst(unsigned int ch) /*process for reg and unreg cmd*/ void dip_chst_process_reg(unsigned int ch) { - enum eDI_TOP_STATE chst; + enum EDI_TOP_STATE chst; struct vframe_s *vframe; struct di_pre_stru_s *ppre = get_pre_stru(ch); bool reflesh = true; @@ -1283,7 +1316,7 @@ void dip_chst_process_reg(unsigned int ch) switch (chst) { case eDI_TOP_STATE_NOPROB: - case eDI_TOP_STATE_IDLE: + case EDI_TOP_STATE_IDLE: break; case eDI_TOP_STATE_REG_STEP1:/*wait peek*/ vframe = pw_vf_peek(ch); @@ -1363,7 +1396,7 @@ void dip_chst_process_reg(unsigned int ch) reflesh = true; break; case eDI_TOP_STATE_REG_STEP2:/*now no change to do*/ - if (dip_cma_get_st(ch) == eDI_CMA_ST_READY) { + if (dip_cma_get_st(ch) == EDI_CMA_ST_READY) { if (di_cfg_top_get(eDI_CFG_first_bypass)) { if (get_sum_g(ch) == 0) dim_bypass_first_frame(ch); @@ -1371,12 +1404,12 @@ void dip_chst_process_reg(unsigned int ch) PR_INF("ch[%d],g[%d]\n", ch, get_sum_g(ch)); } - dip_chst_set(ch, eDI_TOP_STATE_READY); + dip_chst_set(ch, EDI_TOP_STATE_READY); set_reg_flag(ch, true); /*move to step1 dim_bypass_first_frame(ch);*/ } break; - case eDI_TOP_STATE_READY: + case EDI_TOP_STATE_READY: break; case eDI_TOP_STATE_BYPASS: @@ -1408,7 +1441,7 @@ void dip_chst_process_reg(unsigned int ch) dpost_init(); } - dip_chst_set(ch, eDI_TOP_STATE_IDLE); + dip_chst_set(ch, EDI_TOP_STATE_IDLE); /*debug only dbg_reg("ch[%d]UNREG_STEP2 end\n",ch);*/ break; } @@ -1424,7 +1457,7 @@ void dip_chst_process_ch(void) chst = dip_chst_get(ch); switch (chst) { case eDI_TOP_STATE_REG_STEP2: - if (dip_cma_get_st(ch) == eDI_CMA_ST_READY) { + if (dip_cma_get_st(ch) == EDI_CMA_ST_READY) { if (di_cfg_top_get(eDI_CFG_first_bypass)) { if (get_sum_g(ch) == 0) dim_bypass_first_frame(ch); @@ -1432,7 +1465,7 @@ void dip_chst_process_ch(void) PR_INF("ch[%d],g[%d]\n", ch, get_sum_g(ch)); } - dip_chst_set(ch, eDI_TOP_STATE_READY); + dip_chst_set(ch, EDI_TOP_STATE_READY); set_reg_flag(ch, true); } break; @@ -1454,9 +1487,14 @@ void dip_chst_process_ch(void) dpost_init(); } - dip_chst_set(ch, eDI_TOP_STATE_IDLE); + dip_chst_set(ch, EDI_TOP_STATE_IDLE); dbg_reg("ch[%d]STEP2 end\n", ch); break; + case EDI_TOP_STATE_READY: + dim_post_keep_back_recycle(ch); + break; + default: + break; } } } @@ -1517,7 +1555,7 @@ const char * const di_top_state_name[] = { const char *dip_chst_get_name_curr(unsigned int ch) { const char *p = ""; - enum eDI_TOP_STATE chst; + enum EDI_TOP_STATE chst; chst = dip_chst_get(ch); @@ -1527,7 +1565,7 @@ const char *dip_chst_get_name_curr(unsigned int ch) return p; } -const char *dip_chst_get_name(enum eDI_TOP_STATE chst) +const char *dip_chst_get_name(enum EDI_TOP_STATE chst) { const char *p = ""; @@ -1858,7 +1896,6 @@ void do_table_working(struct do_table_s *pdo) void dip_init_value_reg(unsigned int ch) { struct di_post_stru_s *ppost; - struct di_buf_s *keep_post_buf; struct di_pre_stru_s *ppre = get_pre_stru(ch); pr_info("%s:\n", __func__); @@ -1866,11 +1903,10 @@ void dip_init_value_reg(unsigned int ch) /*post*/ ppost = get_post_stru(ch); /*keep buf:*/ - keep_post_buf = ppost->keep_buf_post; + /*keep_post_buf = ppost->keep_buf_post;*/ memset(ppost, 0, sizeof(struct di_post_stru_s)); ppost->next_canvas_id = 1; - ppost->keep_buf_post = keep_post_buf; /*pre*/ memset(ppre, 0, sizeof(struct di_pre_stru_s)); @@ -1890,6 +1926,10 @@ static bool dip_init_value(void) /*que*/ ret = di_que_alloc(ch); + if (ret) { + pw_queue_clear(ch, QUE_POST_KEEP); + pw_queue_clear(ch, QUE_POST_KEEP_BACK); + } } set_current_channel(0); diff --git a/drivers/amlogic/media/di_multi/di_prc.h b/drivers/amlogic/media/di_multi/di_prc.h index 8083bc469c04..86f73642e80d 100644 --- a/drivers/amlogic/media/di_multi/di_prc.h +++ b/drivers/amlogic/media/di_multi/di_prc.h @@ -48,9 +48,9 @@ void dip_hw_process(void); void dip_chst_process_ch(void); bool dip_chst_change_2unreg(void); -enum eDI_TOP_STATE dip_chst_get(unsigned int ch); +enum EDI_TOP_STATE dip_chst_get(unsigned int ch); const char *dip_chst_get_name_curr(unsigned int ch); -const char *dip_chst_get_name(enum eDI_TOP_STATE chst); +const char *dip_chst_get_name(enum EDI_TOP_STATE chst); /************************************** * diff --git a/drivers/amlogic/media/di_multi/di_que.c b/drivers/amlogic/media/di_multi/di_que.c index 1d96da958743..8e8bad67f0ad 100644 --- a/drivers/amlogic/media/di_multi/di_que.c +++ b/drivers/amlogic/media/di_multi/di_que.c @@ -35,6 +35,8 @@ const char * const di_name_new_que[QUE_NUB] = { "QUE_POST_FREE", /*2*/ "QUE_POST_READY", /*3*/ "QUE_POST_BACK", /*4*/ + "QUE_POST_KEEP", + "QUE_POST_KEEP_BACK", "QUE_DBG", /* "QUE_NUB",*/ @@ -42,7 +44,7 @@ const char * const di_name_new_que[QUE_NUB] = { #define que_dbg dim_print -static void pw_queue_clear(unsigned int ch, enum QUE_TYPE qtype) +void pw_queue_clear(unsigned int ch, enum QUE_TYPE qtype) { struct di_ch_s *pch = get_chdata(ch); @@ -166,6 +168,9 @@ bool pw_queue_empty(unsigned int ch, enum QUE_TYPE qtype) return false; } +/********************************************************** + * + **********************************************************/ int di_que_list_count(unsigned int ch, enum QUE_TYPE qtype) { struct di_ch_s *pch = get_chdata(ch); @@ -249,8 +254,12 @@ void di_que_init(unsigned int ch) { int i; - for (i = 0; i < QUE_NUB; i++) + for (i = 0; i < QUE_NUB; i++) { + if (i == QUE_POST_KEEP || + i == QUE_POST_KEEP_BACK) + continue; pw_queue_clear(ch, i); + } } bool di_que_alloc(unsigned int ch) @@ -437,6 +446,39 @@ bool di_que_is_in_que(unsigned int ch, enum QUE_TYPE qtype, return ret; } +/* clear and rebuild que*/ +bool di_que_out_not_fifo(unsigned int ch, enum QUE_TYPE qtype, + struct di_buf_s *di_buf) +{ + unsigned int q_index; + unsigned int arr[MAX_FIFO_SIZE + 1]; + unsigned int asize = 0; + unsigned int i; + bool ret = false; + + if (!pw_queue_peek(ch, qtype, &q_index)) + return false; + + q_index = pw_buf_2_qindex(ch, di_buf); + + di_que_list(ch, qtype, &arr[0], &asize); + + pw_queue_clear(ch, qtype); + + if (asize == 0) + return ret; + + for (i = 0; i < asize; i++) { + if (arr[i] == q_index) { + ret = true; + di_buf->queue_index = -1; + continue; + } + pw_queue_in(ch, qtype, arr[i]); + } + return ret; +} + /*same as get_di_buf_head*/ struct di_buf_s *di_que_peek(unsigned int ch, enum QUE_TYPE qtype) { diff --git a/drivers/amlogic/media/di_multi/di_que.h b/drivers/amlogic/media/di_multi/di_que.h index f2f35ab0332d..237c80503ae3 100644 --- a/drivers/amlogic/media/di_multi/di_que.h +++ b/drivers/amlogic/media/di_multi/di_que.h @@ -37,6 +37,7 @@ bool pw_queue_in(unsigned int ch, enum QUE_TYPE qtype, bool pw_queue_out(unsigned int ch, enum QUE_TYPE qtype, unsigned int *buf_index); bool pw_queue_empty(unsigned int ch, enum QUE_TYPE qtype); +void pw_queue_clear(unsigned int ch, enum QUE_TYPE qtype); /******************************************/ /*new api*/ @@ -60,6 +61,9 @@ bool di_que_out(unsigned int ch, enum QUE_TYPE qtype, struct di_buf_s *di_que_out_to_di_buf(unsigned int ch, enum QUE_TYPE qtype); +bool di_que_out_not_fifo(unsigned int ch, enum QUE_TYPE qtype, + struct di_buf_s *di_buf); + bool di_que_in(unsigned int ch, enum QUE_TYPE qtype, struct di_buf_s *di_buf); bool di_que_is_in_que(unsigned int ch, enum QUE_TYPE qtype, diff --git a/drivers/amlogic/media/di_multi/di_sys.c b/drivers/amlogic/media/di_multi/di_sys.c index 64be0556e67c..ab462a863b31 100644 --- a/drivers/amlogic/media/di_multi/di_sys.c +++ b/drivers/amlogic/media/di_multi/di_sys.c @@ -528,7 +528,7 @@ static int dim_probe(struct platform_device *pdev) fail_cdev_add: pr_info("%s:fail_cdev_add\n", __func__); kfree(di_devp->data_l); - + di_devp->data_l = NULL; fail_kmalloc_datal: pr_info("%s:fail_kmalloc datal\n", __func__); @@ -539,6 +539,7 @@ fail_class_create: unregister_chrdev_region(di_pdev->devno, DI_COUNT); fail_alloc_cdev_region: kfree(di_pdev); + di_pdev = NULL; fail_kmalloc_dev: return ret; @@ -612,8 +613,9 @@ static int dim_remove(struct platform_device *pdev) #endif kfree(di_devp->data_l); + di_devp->data_l = NULL; kfree(di_pdev); - + di_pdev = NULL; PR_INF("%s:finish\n", __func__); return 0; } @@ -649,7 +651,7 @@ static void di_clear_for_suspend(struct di_dev_s *di_devp) di_vframe_unreg(channel);/*have flag*/ - if (dip_chst_get(channel) != eDI_TOP_STATE_IDLE) + if (dip_chst_get(channel) != EDI_TOP_STATE_IDLE) dim_unreg_process_irq(channel); dip_cma_close(); diff --git a/drivers/amlogic/media/di_multi/di_task.c b/drivers/amlogic/media/di_multi/di_task.c index 9912fd45500f..84d899708525 100644 --- a/drivers/amlogic/media/di_multi/di_task.c +++ b/drivers/amlogic/media/di_multi/di_task.c @@ -96,6 +96,10 @@ void task_polling_cmd(void) for (i = 0; i < MAX_KFIFO_L_CMD_NUB; i++) { if (!task_get_cmd(&cmdbyte.cmd32)) break; + if (cmdbyte.b.id == ECMD_RL_KEEP) { + dim_post_keep_cmd_proc(cmdbyte.b.ch, cmdbyte.b.p2); + continue; + } dip_chst_process_reg(cmdbyte.b.ch); } } diff --git a/drivers/amlogic/media/video_processor/Kconfig b/drivers/amlogic/media/video_processor/Kconfig index ef42224d59d8..cd0d40136496 100644 --- a/drivers/amlogic/media/video_processor/Kconfig +++ b/drivers/amlogic/media/video_processor/Kconfig @@ -18,6 +18,8 @@ source "drivers/amlogic/media/video_processor/ppmgr/Kconfig" source "drivers/amlogic/media/video_processor/ionvideo/Kconfig" source "drivers/amlogic/media/video_processor/pic_dev/Kconfig" source "drivers/amlogic/media/video_processor/videosync/Kconfig" +source "drivers/amlogic/media/video_processor/v4lvideo/Kconfig" +source "drivers/amlogic/media/video_processor/video_composer/Kconfig" endif endmenu diff --git a/drivers/amlogic/media/video_processor/Makefile b/drivers/amlogic/media/video_processor/Makefile index 354b2478a554..1def20612a29 100644 --- a/drivers/amlogic/media/video_processor/Makefile +++ b/drivers/amlogic/media/video_processor/Makefile @@ -2,4 +2,6 @@ obj-$(CONFIG_AMLOGIC_V4L_VIDEO2) += video_dev/ obj-$(CONFIG_AMLOGIC_POST_PROCESS_MANAGER) += ppmgr/ obj-$(CONFIG_AMLOGIC_IONVIDEO) += ionvideo/ obj-$(CONFIG_AMLOGIC_PIC_DEC) += pic_dev/ -obj-$(CONFIG_AMLOGIC_VIDEOSYNC) += videosync/ \ No newline at end of file +obj-$(CONFIG_AMLOGIC_VIDEOSYNC) += videosync/ +obj-$(CONFIG_AMLOGIC_V4L_VIDEO3) += v4lvideo/ +obj-$(CONFIG_AMLOGIC_VIDEO_COMPOSER) += video_composer/ diff --git a/drivers/amlogic/media/video_processor/ppmgr/ppmgr_vpp.c b/drivers/amlogic/media/video_processor/ppmgr/ppmgr_vpp.c index 7e64cc6149aa..6864740a274d 100644 --- a/drivers/amlogic/media/video_processor/ppmgr/ppmgr_vpp.c +++ b/drivers/amlogic/media/video_processor/ppmgr/ppmgr_vpp.c @@ -953,7 +953,7 @@ static int process_vf_tb_detect(struct vframe_s *vf, { struct canvas_s cs0, cs1, cs2, cd; int interlace_mode; - struct vframe_s src_vf; + int canvas_id; u32 format = GE2D_FORMAT_M24_YUV420; u32 h_scale_coef_type = context->config.h_scale_coef_type; @@ -1000,36 +1000,32 @@ static int process_vf_tb_detect(struct vframe_s *vf, ge2d_config->src1_gb_alpha = 0;/* 0xff; */ ge2d_config->dst_xy_swap = 0; - src_vf = *vf; - if (vf->canvas0Addr == (u32)-1) { canvas_config_config( tb_src_canvas[0] & 0xff, - &src_vf.canvas0_config[0]); - if (src_vf.plane_num == 2) { + &vf->canvas0_config[0]); + if (vf->plane_num == 2) { canvas_config_config( tb_src_canvas[1] & 0xff, - &src_vf.canvas0_config[1]); - } else if (src_vf.plane_num == 3) { + &vf->canvas0_config[1]); + } else if (vf->plane_num == 3) { canvas_config_config( tb_src_canvas[2] & 0xff, - &src_vf.canvas0_config[2]); + &vf->canvas0_config[2]); } - src_vf.canvas0Addr = - (tb_src_canvas[0] & 0xff) + canvas_id = (tb_src_canvas[0] & 0xff) | ((tb_src_canvas[1] & 0xff) << 8) | ((tb_src_canvas[2] & 0xff) << 16); - canvas_read( - src_vf.canvas0Addr & 0xff, &cs0); - canvas_read( - (src_vf.canvas0Addr >> 8) & 0xff, &cs1); - canvas_read( - (src_vf.canvas0Addr >> 16) & 0xff, &cs2); + canvas_read(canvas_id & 0xff, &cs0); + canvas_read((canvas_id >> 8) & 0xff, &cs1); + canvas_read((canvas_id >> 16) & 0xff, &cs2); + ge2d_config->src_para.canvas_index = canvas_id; } else { canvas_read(vf->canvas0Addr & 0xff, &cs0); canvas_read((vf->canvas0Addr >> 8) & 0xff, &cs1); canvas_read((vf->canvas0Addr >> 16) & 0xff, &cs2); + ge2d_config->src_para.canvas_index = vf->canvas0Addr; } ge2d_config->src_planes[0].addr = cs0.addr; ge2d_config->src_planes[0].w = cs0.width; @@ -1047,7 +1043,6 @@ static int process_vf_tb_detect(struct vframe_s *vf, ge2d_config->src_key.key_enable = 0; ge2d_config->src_key.key_mask = 0; ge2d_config->src_key.key_mode = 0; - ge2d_config->src_para.canvas_index = src_vf.canvas0Addr; ge2d_config->src_para.mem_type = CANVAS_TYPE_INVALID; ge2d_config->src_para.format = format; ge2d_config->src_para.fill_color_en = 0; diff --git a/drivers/amlogic/media/video_processor/v4lvideo/Kconfig b/drivers/amlogic/media/video_processor/v4lvideo/Kconfig new file mode 100644 index 000000000000..032b8c604658 --- /dev/null +++ b/drivers/amlogic/media/video_processor/v4lvideo/Kconfig @@ -0,0 +1,19 @@ +# +# Amlogic v4lvideo device configuation +# + +menu "Amlogic v4l video support" + +config AMLOGIC_V4L_VIDEO3 + tristate "Amlogic v4l video3 device support" + depends on VIDEO_DEV + depends on VIDEO_V4L2 + depends on VIDEOBUF2_CORE + depends on VIDEOBUF2_MEMOPS + depends on DMA_SHARED_BUFFER + default n + + ---help--- + Select to enable "Amlogic v4l video3 device support. + +endmenu diff --git a/drivers/amlogic/media/video_processor/v4lvideo/Makefile b/drivers/amlogic/media/video_processor/v4lvideo/Makefile new file mode 100644 index 000000000000..a95a1a760b2f --- /dev/null +++ b/drivers/amlogic/media/video_processor/v4lvideo/Makefile @@ -0,0 +1,4 @@ +asflags-y=-mfloat-abi=softfp -mfpu=neon +ccflags-y += -Idrivers/staging/android/ion + +obj-$(CONFIG_AMLOGIC_V4L_VIDEO3) += v4lvideo.o diff --git a/drivers/amlogic/media/video_processor/v4lvideo/v4lvideo.c b/drivers/amlogic/media/video_processor/v4lvideo/v4lvideo.c new file mode 100644 index 000000000000..acb973c69f8c --- /dev/null +++ b/drivers/amlogic/media/video_processor/v4lvideo/v4lvideo.c @@ -0,0 +1,1162 @@ +/* + * drivers/amlogic/media/video_processor/v4lvideo/v4lvideo.c + * + * Copyright (C) 2017 Amlogic, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +#define DEBUG +#include +#include +#include +#include +#include "v4lvideo.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define V4LVIDEO_MODULE_NAME "v4lvideo" + +#define V4LVIDEO_VERSION "1.0" +#define RECEIVER_NAME "v4lvideo" +#define V4LVIDEO_DEVICE_NAME "v4lvideo" +#define DUR2PTS(x) ((x) - ((x) >> 4)) + +#define V4L2_CID_USER_AMLOGIC_V4LVIDEO_BASE (V4L2_CID_USER_BASE + 0x1100) + +static unsigned int video_nr_base = 30; +module_param(video_nr_base, uint, 0644); +MODULE_PARM_DESC(video_nr_base, "videoX start number, 30 is the base nr"); + +static unsigned int n_devs = 9; + +module_param(n_devs, uint, 0644); +MODULE_PARM_DESC(n_devs, "number of video devices to create"); + +static unsigned int debug; +module_param(debug, uint, 0644); +MODULE_PARM_DESC(debug, "activates debug info"); + +#define MAX_KEEP_FRAME 64 + +struct keep_mem_info { + void *handle; + int keep_id; + int count; +}; + +struct keeper_mgr { + /* lock*/ + spinlock_t lock; + struct keep_mem_info keep_list[MAX_KEEP_FRAME]; +}; + +static struct keeper_mgr keeper_mgr_private; + +static struct keeper_mgr *get_keeper_mgr(void) +{ + return &keeper_mgr_private; +} + +void keeper_mgr_init(void) +{ + struct keeper_mgr *mgr = get_keeper_mgr(); + + memset(mgr, 0, sizeof(struct keeper_mgr)); + spin_lock_init(&mgr->lock); +} + +static const struct v4lvideo_fmt formats[] = { + {.name = "RGB32 (LE)", + .fourcc = V4L2_PIX_FMT_RGB32, /* argb */ + .depth = 32, }, + + {.name = "RGB565 (LE)", + .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */ + .depth = 16, }, + + {.name = "RGB24 (LE)", + .fourcc = V4L2_PIX_FMT_RGB24, /* rgb */ + .depth = 24, }, + + {.name = "RGB24 (BE)", + .fourcc = V4L2_PIX_FMT_BGR24, /* bgr */ + .depth = 24, }, + + {.name = "12 Y/CbCr 4:2:0", + .fourcc = V4L2_PIX_FMT_NV12, + .depth = 12, }, + + {.name = "12 Y/CrCb 4:2:0", + .fourcc = V4L2_PIX_FMT_NV21, + .depth = 12, }, + + {.name = "YUV420P", + .fourcc = V4L2_PIX_FMT_YUV420, + .depth = 12, }, + + {.name = "YVU420P", + .fourcc = V4L2_PIX_FMT_YVU420, + .depth = 12, } +}; + +static const struct v4lvideo_fmt *__get_format(u32 pixelformat) +{ + const struct v4lvideo_fmt *fmt; + unsigned int k; + + for (k = 0; k < ARRAY_SIZE(formats); k++) { + fmt = &formats[k]; + if (fmt->fourcc == pixelformat) + break; + } + + if (k == ARRAY_SIZE(formats)) + return NULL; + + return &formats[k]; +} + +static const struct v4lvideo_fmt *get_format(struct v4l2_format *f) +{ + return __get_format(f->fmt.pix.pixelformat); +} + +static void video_keeper_keep_mem( + void *mem_handle, int type, + int *id) +{ + int ret; + int old_id = *id; + struct keeper_mgr *mgr = get_keeper_mgr(); + int i; + unsigned long flags; + int have_samed = 0; + int keep_id = -1; + int slot_i = -1; + + if (!mem_handle) + return; + + spin_lock_irqsave(&mgr->lock, flags); + for (i = 0; i < MAX_KEEP_FRAME; i++) { + if (!mgr->keep_list[i].handle && slot_i < 0) { + slot_i = i; + } else if (mem_handle == mgr->keep_list[i].handle) { + mgr->keep_list[i].count++; + have_samed = true; + keep_id = mgr->keep_list[i].keep_id; + break; + } + } + + if (have_samed) { + spin_unlock_irqrestore(&mgr->lock, flags); + *id = keep_id; + /* pr_info("v4lvideo: keep same mem handle=%p, keep_id=%d\n", */ + /* mem_handle, keep_id); */ + return; + } + mgr->keep_list[slot_i].count++; + if (mgr->keep_list[slot_i].count != 1) + pr_err("v4lvideo: keep error mem handle=%p\n", mem_handle); + mgr->keep_list[slot_i].handle = mem_handle; + + spin_unlock_irqrestore(&mgr->lock, flags); + + ret = codec_mm_keeper_mask_keep_mem(mem_handle, + type); + if (ret > 0) { + if (old_id > 0 && ret != old_id) { + /* wait 80 ms for vsync post. */ + codec_mm_keeper_unmask_keeper(old_id, 0); + } + *id = ret; + } + mgr->keep_list[slot_i].keep_id = *id; +} + +static void video_keeper_free_mem( + int keep_id, int delayms) +{ + struct keeper_mgr *mgr = get_keeper_mgr(); + int i; + unsigned long flags; + int need_continue_keep = 0; + + if (keep_id <= 0) { + pr_err("invalid keepid %d\n", keep_id); + return; + } + + spin_lock_irqsave(&mgr->lock, flags); + for (i = 0; i < MAX_KEEP_FRAME; i++) { + if (keep_id == mgr->keep_list[i].keep_id) { + mgr->keep_list[i].count--; + if (mgr->keep_list[i].count > 0) { + need_continue_keep = 1; + break; + } else if (mgr->keep_list[i].count == 0) { + mgr->keep_list[i].keep_id = -1; + mgr->keep_list[i].handle = NULL; + } else + pr_err("v4lvideo: free mem err count =%d\n", + mgr->keep_list[i].count); + } + } + spin_unlock_irqrestore(&mgr->lock, flags); + + if (need_continue_keep) { + pr_info("v4lvideo: need_continue_keep keep_id=%d\n", keep_id); + return; + } + codec_mm_keeper_unmask_keeper(keep_id, delayms); +} + +static void vf_keep(struct file_private_data *file_private_data) +{ + struct vframe_s *vf_p = file_private_data->vf_p; + int type = MEM_TYPE_CODEC_MM; + int keep_id = 0; + int keep_head_id = 0; + + if (!file_private_data) { + V4LVID_ERR("vf_keep error: file_private_data is NULL"); + return; + } + if (vf_p->type & VIDTYPE_SCATTER) + type = MEM_TYPE_CODEC_MM_SCATTER; + video_keeper_keep_mem( + vf_p->mem_handle, + type, + &keep_id); + video_keeper_keep_mem( + vf_p->mem_head_handle, + MEM_TYPE_CODEC_MM, + &keep_head_id); + + file_private_data->keep_id = keep_id; + file_private_data->keep_head_id = keep_head_id; + file_private_data->is_keep = true; +} + +static void vf_free(struct file_private_data *file_private_data) +{ + struct vframe_s *vf_p; + struct vframe_s vf; + + if (file_private_data->keep_id > 0) { + video_keeper_free_mem( + file_private_data->keep_id, 0); + file_private_data->keep_id = -1; + } + if (file_private_data->keep_head_id > 0) { + video_keeper_free_mem( + file_private_data->keep_head_id, 0); + file_private_data->keep_head_id = -1; + } + + vf = file_private_data->vf; + vf_p = file_private_data->vf_p; + + if (vf.type & VIDTYPE_DI_PW) + dim_post_keep_cmd_release2(vf_p); +} + +void init_file_private_data(struct file_private_data *file_private_data) +{ + if (file_private_data) { + memset(&file_private_data->vf, 0, sizeof(struct vframe_s)); + file_private_data->vf_p = NULL; + file_private_data->is_keep = false; + file_private_data->keep_id = -1; + file_private_data->keep_head_id = -1; + file_private_data->file = NULL; + } else { + V4LVID_ERR("init_file_private_data is NULL!!"); + } +} + +static DEFINE_SPINLOCK(devlist_lock); +static unsigned long v4lvideo_devlist_lock(void) +{ + unsigned long flags; + + spin_lock_irqsave(&devlist_lock, flags); + return flags; +} + +static void v4lvideo_devlist_unlock(unsigned long flags) +{ + spin_unlock_irqrestore(&devlist_lock, flags); +} + +static LIST_HEAD(v4lvideo_devlist); + +int v4lvideo_assign_map(char **receiver_name, int *inst) +{ + unsigned long flags; + struct v4lvideo_dev *dev = NULL; + struct list_head *p; + + flags = v4lvideo_devlist_lock(); + + list_for_each(p, &v4lvideo_devlist) { + dev = list_entry(p, struct v4lvideo_dev, v4lvideo_devlist); + + if (dev->inst == *inst) { + *receiver_name = dev->vf_receiver_name; + v4lvideo_devlist_unlock(flags); + return 0; + } + } + + v4lvideo_devlist_unlock(flags); + + return -ENODEV; +} +EXPORT_SYMBOL(v4lvideo_assign_map); + +int v4lvideo_alloc_map(int *inst) +{ + unsigned long flags; + struct v4lvideo_dev *dev = NULL; + struct list_head *p; + + flags = v4lvideo_devlist_lock(); + + list_for_each(p, &v4lvideo_devlist) { + dev = list_entry(p, struct v4lvideo_dev, v4lvideo_devlist); + + if ((dev->inst >= 0) && (!dev->mapped)) { + dev->mapped = true; + *inst = dev->inst; + v4lvideo_devlist_unlock(flags); + return 0; + } + } + + v4lvideo_devlist_unlock(flags); + return -ENODEV; +} + +void v4lvideo_release_map(int inst) +{ + unsigned long flags; + struct v4lvideo_dev *dev = NULL; + struct list_head *p; + + flags = v4lvideo_devlist_lock(); + + list_for_each(p, &v4lvideo_devlist) { + dev = list_entry(p, struct v4lvideo_dev, v4lvideo_devlist); + if ((dev->inst == inst) && (dev->mapped)) { + dev->mapped = false; + pr_debug("v4lvideo_release_map %d OK\n", dev->inst); + break; + } + } + + v4lvideo_devlist_unlock(flags); +} + +void v4lvideo_release_map_force(struct v4lvideo_dev *dev) +{ + unsigned long flags; + + flags = v4lvideo_devlist_lock(); + + if (dev->mapped) { + dev->mapped = false; + pr_debug("v4lvideo_release_map %d OK\n", dev->inst); + } + + v4lvideo_devlist_unlock(flags); +} + +void v4lvideo_data_copy(struct v4l_data_t *v4l_data) +{ + struct vframe_s *vf = NULL; + char *src_ptr_y = NULL; + char *src_ptr_uv = NULL; + char *dst_ptr = NULL; + u32 src_phy_addr_y; + u32 src_phy_addr_uv; + u32 size_y; + u32 size_uv; + u32 size_pic; + + vf = v4l_data->vf; + size_y = vf->width * vf->height; + size_uv = size_y >> 1; + size_pic = size_y + size_uv; + + if ((vf->canvas0Addr == vf->canvas1Addr) && + (vf->canvas0Addr != 0) && + (vf->canvas0Addr != -1)) { + src_phy_addr_y = canvas_get_addr(canvasY(vf->canvas0Addr)); + src_phy_addr_uv = canvas_get_addr(canvasUV(vf->canvas0Addr)); + } else { + src_phy_addr_y = vf->canvas0_config[0].phy_addr; + src_phy_addr_uv = vf->canvas0_config[1].phy_addr; + } + dst_ptr = v4l_data->dst_addr; + + src_ptr_y = codec_mm_vmap(src_phy_addr_y, size_y); + if (!src_ptr_y) { + pr_err("src_phy_addr_y map fail size_y=%d\n", size_y); + return; + } + memcpy(dst_ptr, src_ptr_y, size_y); + codec_mm_unmap_phyaddr(src_ptr_y); + + src_ptr_uv = codec_mm_vmap(src_phy_addr_uv, size_uv); + if (!src_ptr_uv) { + pr_err("src_phy_addr_uv map fail size_uv=%d\n", size_uv); + return; + } + memcpy(dst_ptr + size_y, src_ptr_uv, size_uv); + codec_mm_unmap_phyaddr(src_ptr_uv); +} + +struct vframe_s *v4lvideo_get_vf(int fd) +{ + struct file *file_vf = NULL; + struct vframe_s *vf = NULL; + struct file_private_data *file_private_data; + + file_vf = fget(fd); + file_private_data = (struct file_private_data *)file_vf->private_data; + vf = &file_private_data->vf; + fput(file_vf); + return vf; +} + +/* ------------------------------------------------------------------ + * DMA and thread functions + * ------------------------------------------------------------------ + */ +unsigned int get_v4lvideo_debug(void) +{ + return debug; +} +EXPORT_SYMBOL(get_v4lvideo_debug); + +static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) +{ + struct v4lvideo_dev *dev = video_drvdata(file); + + dprintk(dev, 2, "%s\n", __func__); + + dprintk(dev, 2, "returning from %s\n", __func__); + + return 0; +} + +static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) +{ + struct v4lvideo_dev *dev = video_drvdata(file); + + dprintk(dev, 2, "%s\n", __func__); + + /* + * Typical driver might need to wait here until dma engine stops. + * In this case we can abort imiedetly, so it's just a noop. + */ + v4l2q_init(&dev->input_queue, V4LVIDEO_POOL_SIZE, + (void **)&dev->v4lvideo_input_queue[0]); + return 0; +} + +/* ------------------------------------------------------------------ + * Videobuf operations + * ------------------------------------------------------------------ + */ + +static int vidioc_g_parm(struct file *file, void *priv, + struct v4l2_streamparm *parms) +{ + struct v4lvideo_dev *dev = video_drvdata(file); + + if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + memcpy(parms->parm.raw_data, (u8 *)&dev->am_parm, + sizeof(struct v4l2_amlogic_parm)); + + return 0; +} + +/* ------------------------------------------------------------------ + * IOCTL vidioc handling + * ------------------------------------------------------------------ + */ +static int vidioc_open(struct file *file) +{ + struct v4lvideo_dev *dev = video_drvdata(file); + + if (dev->fd_num > 0) { + pr_err("vidioc_open error\n"); + return -EBUSY; + } + + dev->fd_num++; + dev->vf_wait_cnt = 0; + + v4l2q_init(&dev->input_queue, + V4LVIDEO_POOL_SIZE, + (void **)&dev->v4lvideo_input_queue[0]); + + //dprintk(dev, 2, "vidioc_open\n"); + V4LVID_DBG("v4lvideo open\n"); + return 0; +} + +static int vidioc_close(struct file *file) +{ + struct v4lvideo_dev *dev = video_drvdata(file); + + V4LVID_DBG("vidioc_close!!!!\n"); + if (dev->mapped) + v4lvideo_release_map_force(dev); + + if (dev->fd_num > 0) + dev->fd_num--; + + return 0; +} + +static int vidioc_querycap(struct file *file, + void *priv, + struct v4l2_capability *cap) +{ + struct v4lvideo_dev *dev = video_drvdata(file); + + strcpy(cap->driver, "v4lvideo"); + strcpy(cap->card, "v4lvideo"); + snprintf(cap->bus_info, + sizeof(cap->bus_info), + "platform:%s", + dev->v4l2_dev.name); + cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING + | V4L2_CAP_READWRITE; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; + return 0; +} + +static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + const struct v4lvideo_fmt *fmt; + + if (f->index >= ARRAY_SIZE(formats)) + return -EINVAL; + + fmt = &formats[f->index]; + + strlcpy(f->description, fmt->name, sizeof(f->description)); + f->pixelformat = fmt->fourcc; + return 0; +} + +static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct v4lvideo_dev *dev = video_drvdata(file); + + f->fmt.pix.width = dev->width; + f->fmt.pix.height = dev->height; + + f->fmt.pix.field = V4L2_FIELD_INTERLACED; + f->fmt.pix.pixelformat = dev->fmt->fourcc; + f->fmt.pix.bytesperline = (f->fmt.pix.width * dev->fmt->depth) >> 3; + f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; + if (dev->fmt->is_yuv) + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + else + f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; + + return 0; +} + +static int vidioc_try_fmt_vid_cap(struct file *file, + void *priv, + struct v4l2_format *f) +{ + struct v4lvideo_dev *dev = video_drvdata(file); + const struct v4lvideo_fmt *fmt; + + fmt = get_format(f); + if (!fmt) { + dprintk(dev, 1, "Fourcc format (0x%08x) unknown.\n", + f->fmt.pix.pixelformat); + return -EINVAL; + } + + f->fmt.pix.field = V4L2_FIELD_INTERLACED; + v4l_bound_align_image(&f->fmt.pix.width, + 48, + MAX_WIDTH, + 4, + &f->fmt.pix.height, + 32, + MAX_HEIGHT, + 0, + 0); + f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3; + f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; + if (fmt->is_yuv) + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + else + f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; + f->fmt.pix.priv = 0; + return 0; +} + +static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct v4lvideo_dev *dev = video_drvdata(file); + + int ret = vidioc_try_fmt_vid_cap(file, priv, f); + + if (ret < 0) + return ret; + + dev->fmt = get_format(f); + dev->width = f->fmt.pix.width; + dev->height = f->fmt.pix.height; + if ((dev->width == 0) || (dev->height == 0)) + V4LVID_ERR("ion buffer w/h info is invalid!!!!!!!!!!!\n"); + + return 0; +} + +static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) +{ + struct v4lvideo_dev *dev = video_drvdata(file); + struct vframe_s *vf_p; + struct file *file_vf = NULL; + struct file_private_data *file_private_data = NULL; + + dev->v4lvideo_input[p->index] = *p; + + file_vf = fget(p->m.fd); + file_private_data = (struct file_private_data *)(file_vf->private_data); + vf_p = file_private_data->vf_p; + + mutex_lock(&dev->mutex_input); + if (vf_p) { + if (file_private_data->is_keep) { + vf_free(file_private_data); + } else { + if (v4l2q_pop_specific(&dev->display_queue, + file_private_data)) { + if (dev->receiver_register) { + vf_put(vf_p, dev->vf_receiver_name); + } else { + vf_free(file_private_data); + pr_err("vidioc_qbuf: vfm is unreg\n"); + } + } else { + pr_err("vidioc_qbuf: maybe in unreg\n"); + } + } + } else { + dprintk(dev, 1, + "vidioc_qbuf: vf is NULL, at the start of playback\n"); + } + init_file_private_data(file_private_data); + fput(file_vf); + + v4l2q_push(&dev->input_queue, &dev->v4lvideo_input[p->index]); + mutex_unlock(&dev->mutex_input); + + return 0; +} + +static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) +{ + struct v4lvideo_dev *dev = video_drvdata(file); + struct v4l2_buffer *buf = NULL; + struct vframe_s *vf; + struct file *file_vf = NULL; + struct file_private_data *file_private_data = NULL; + u64 pts_us64 = 0; + u64 pts_tmp; + + mutex_lock(&dev->mutex_input); + buf = v4l2q_peek(&dev->input_queue); + if (!buf) { + dprintk(dev, 3, "No active queue to serve\n"); + mutex_unlock(&dev->mutex_input); + return -EAGAIN; + } + mutex_unlock(&dev->mutex_input); + + vf = vf_peek(dev->vf_receiver_name); + if (!vf) { + dev->vf_wait_cnt++; + return -EAGAIN; + } + vf = vf_get(dev->vf_receiver_name); + if (!vf) + return -EAGAIN; + vf->omx_index = dev->frame_num; + dev->am_parm.signal_type = vf->signal_type; + dev->am_parm.master_display_colour + = vf->prop.master_display_colour; + + mutex_lock(&dev->mutex_input); + buf = v4l2q_pop(&dev->input_queue); + dev->vf_wait_cnt = 0; + file_vf = fget(buf->m.fd); + file_private_data = (struct file_private_data *)(file_vf->private_data); + file_private_data->vf = *vf; + file_private_data->vf_p = vf; + //pr_err("dqbuf: file_private_data=%p, vf=%p\n", file_private_data, vf); + v4l2q_push(&dev->display_queue, file_private_data); + fput(file_vf); + mutex_unlock(&dev->mutex_input); + + if (vf->pts_us64) { + dev->first_frame = 1; + pts_us64 = vf->pts_us64; + } else if (dev->first_frame == 0) { + dev->first_frame = 1; + pts_us64 = 0; + } else { + pts_tmp = DUR2PTS(vf->duration) * 100; + do_div(pts_tmp, 9); + pts_us64 = dev->last_pts_us64 + + pts_tmp; + pts_tmp = pts_us64 * 9; + do_div(pts_tmp, 100); + vf->pts = pts_tmp; + } + /*workrun for decoder i pts err, if decoder fix it, this should remove*/ + if ((vf->type & VIDTYPE_DI_PW || + vf->type & VIDTYPE_INTERLACE) && + (vf->pts_us64 == dev->last_pts_us64)) { + dprintk(dev, 1, "pts same\n"); + pts_tmp = DUR2PTS(vf->duration) * 100; + do_div(pts_tmp, 9); + pts_us64 = dev->last_pts_us64 + + pts_tmp; + pts_tmp = pts_us64 * 9; + do_div(pts_tmp, 100); + vf->pts = pts_tmp; + } + + *p = *buf; + p->timestamp.tv_sec = pts_us64 >> 32; + p->timestamp.tv_usec = pts_us64 & 0xFFFFFFFF; + dev->last_pts_us64 = pts_us64; + + if ((vf->type & VIDTYPE_COMPRESS) != 0) { + p->timecode.type = vf->compWidth; + p->timecode.flags = vf->compHeight; + } else { + p->timecode.type = vf->width; + p->timecode.flags = vf->height; + } + p->sequence = dev->frame_num++; + //pr_err("dqbuf: frame_num=%d\n", p->sequence); + return 0; +} + +/* ------------------------------------------------------------------ + * File operations for the device + * ------------------------------------------------------------------ + */ +static const struct v4l2_file_operations v4lvideo_v4l2_fops = { + .owner = THIS_MODULE, + .open = vidioc_open, + .release = vidioc_close, + .read = vb2_fop_read, + .poll = vb2_fop_poll, + .unlocked_ioctl = video_ioctl2,/* V4L2 ioctl handler */ + .mmap = vb2_fop_mmap, +}; + +static const struct v4l2_ioctl_ops v4lvideo_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, + .vidioc_qbuf = vidioc_qbuf, + .vidioc_dqbuf = vidioc_dqbuf, + .vidioc_streamon = vidioc_streamon, + .vidioc_streamoff = vidioc_streamoff, + .vidioc_g_parm = vidioc_g_parm, +}; + +static const struct video_device v4lvideo_template = { + .name = "v4lvideo", + .fops = &v4lvideo_v4l2_fops, + .ioctl_ops = &v4lvideo_ioctl_ops, + .release = video_device_release, +}; + +static int v4lvideo_v4l2_release(void) +{ + struct v4lvideo_dev *dev; + struct list_head *list; + unsigned long flags; + + flags = v4lvideo_devlist_lock(); + + while (!list_empty(&v4lvideo_devlist)) { + list = v4lvideo_devlist.next; + list_del(list); + v4lvideo_devlist_unlock(flags); + + dev = list_entry(list, struct v4lvideo_dev, v4lvideo_devlist); + + v4l2_info(&dev->v4l2_dev, + "unregistering %s\n", + video_device_node_name(&dev->vdev)); + video_unregister_device(&dev->vdev); + v4l2_device_unregister(&dev->v4l2_dev); + kfree(dev); + + flags = v4lvideo_devlist_lock(); + } + /* vb2_dma_contig_cleanup_ctx(v4lvideo_dma_ctx); */ + + v4lvideo_devlist_unlock(flags); + + return 0; +} + +static int video_receiver_event_fun(int type, void *data, void *private_data) +{ + struct v4lvideo_dev *dev = (struct v4lvideo_dev *)private_data; + struct file_private_data *file_private_data = NULL; + + if (type == VFRAME_EVENT_PROVIDER_UNREG) { + mutex_lock(&dev->mutex_input); + dev->receiver_register = false; + while (!v4l2q_empty(&dev->display_queue)) { + file_private_data = v4l2q_pop(&dev->display_queue); + vf_keep(file_private_data); + /*pr_err("unreg:v4lvideo, keep last frame\n");*/ + } + mutex_unlock(&dev->mutex_input); + pr_err("unreg:v4lvideo\n"); + } else if (type == VFRAME_EVENT_PROVIDER_REG) { + mutex_lock(&dev->mutex_input); + v4l2q_init(&dev->display_queue, + VF_POOL_SIZE, + (void **)&dev->v4lvideo_display_queue[0]); + dev->receiver_register = true; + dev->frame_num = 0; + dev->first_frame = 0; + mutex_unlock(&dev->mutex_input); + pr_err("reg:v4lvideo\n"); + } else if (type == VFRAME_EVENT_PROVIDER_QUREY_STATE) { + if (dev->vf_wait_cnt > 1) + return RECEIVER_INACTIVE; + return RECEIVER_ACTIVE; + } + return 0; +} + +static const struct vframe_receiver_op_s video_vf_receiver = { + .event_cb = video_receiver_event_fun +}; + +static int __init v4lvideo_create_instance(int inst) +{ + struct v4lvideo_dev *dev; + struct video_device *vfd; + int ret; + unsigned long flags; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + snprintf(dev->v4l2_dev.name, + sizeof(dev->v4l2_dev.name), + "%s-%03d", + V4LVIDEO_MODULE_NAME, + inst); + ret = v4l2_device_register(NULL, &dev->v4l2_dev); + if (ret) + goto free_dev; + + dev->fmt = &formats[0]; + dev->width = 640; + dev->height = 480; + dev->fd_num = 0; + + vfd = &dev->vdev; + *vfd = v4lvideo_template; + vfd->dev_debug = debug; + vfd->v4l2_dev = &dev->v4l2_dev; + + /* + * Provide a mutex to v4l2 core. It will be used to protect + * all fops and v4l2 ioctls. + */ + ret = video_register_device(vfd, + VFL_TYPE_GRABBER, + inst + video_nr_base); + if (ret < 0) + goto unreg_dev; + + video_set_drvdata(vfd, dev); + dev->inst = inst; + snprintf(dev->vf_receiver_name, + ION_VF_RECEIVER_NAME_SIZE, + RECEIVER_NAME ".%x", + inst & 0xff); + + vf_receiver_init(&dev->video_vf_receiver, + dev->vf_receiver_name, + &video_vf_receiver, dev); + vf_reg_receiver(&dev->video_vf_receiver); + v4l2_info(&dev->v4l2_dev, + "V4L2 device registered as %s\n", + video_device_node_name(vfd)); + + /* add to device list */ + flags = v4lvideo_devlist_lock(); + list_add_tail(&dev->v4lvideo_devlist, &v4lvideo_devlist); + v4lvideo_devlist_unlock(flags); + + mutex_init(&dev->mutex_input); + + return 0; + +unreg_dev: + v4l2_device_unregister(&dev->v4l2_dev); +free_dev: + kfree(dev); + return ret; +} + +static const struct file_operations v4lvideo_file_fops; + +static int v4lvideo_file_release(struct inode *inode, struct file *file) +{ + struct file_private_data *file_private_data = file->private_data; + /*pr_err("v4lvideo_file_release\n");*/ + + if (file_private_data) { + if (file_private_data->is_keep) + vf_free(file_private_data); + memset(file_private_data, 0, sizeof(struct file_private_data)); + kfree((u8 *)file_private_data); + file->private_data = NULL; + } + return 0; +} + +static const struct file_operations v4lvideo_file_fops = { + .release = v4lvideo_file_release, + //.poll = v4lvideo_file_poll, + //.unlocked_ioctl = v4lvideo_file_ioctl, + //.compat_ioctl = v4lvideo_file_ioctl, +}; + +int v4lvideo_alloc_fd(int *fd) +{ + struct file *file = NULL; + struct file_private_data *private_date = NULL; + int file_fd = get_unused_fd_flags(O_CLOEXEC); + + if (file_fd < 0) { + pr_err("v4lvideo_alloc_fd: get unused fd fail\n"); + return -ENODEV; + } + + private_date = kzalloc(sizeof(*private_date), GFP_KERNEL); + if (!private_date) { + put_unused_fd(file_fd); + pr_err("v4lvideo_alloc_fd: private_date fail\n"); + return -ENOMEM; + } + init_file_private_data(private_date); + + file = anon_inode_getfile("v4lvideo_file", + &v4lvideo_file_fops, + private_date, 0); + if (IS_ERR(file)) { + kfree((u8 *)private_date); + put_unused_fd(file_fd); + pr_err("v4lvideo_alloc_fd: anon_inode_getfile fail\n"); + return -ENODEV; + } + fd_install(file_fd, file); + *fd = file_fd; + return 0; +} + +static struct class_attribute ion_video_class_attrs[] = { +}; + +static struct class v4lvideo_class = { + .name = "v4lvideo", + .class_attrs = ion_video_class_attrs, +}; + +static int v4lvideo_open(struct inode *inode, struct file *file) +{ + return 0; +} + +static int v4lvideo_release(struct inode *inode, struct file *file) +{ + return 0; +} + +static long v4lvideo_ioctl(struct file *file, + unsigned int cmd, + ulong arg) +{ + long ret = 0; + void __user *argp = (void __user *)arg; + + switch (cmd) { + case V4LVIDEO_IOCTL_ALLOC_ID:{ + u32 v4lvideo_id = 0; + + ret = v4lvideo_alloc_map(&v4lvideo_id); + if (ret != 0) + break; + put_user(v4lvideo_id, (u32 __user *)argp); + } + break; + case V4LVIDEO_IOCTL_FREE_ID:{ + u32 v4lvideo_id; + + get_user(v4lvideo_id, (u32 __user *)argp); + v4lvideo_release_map(v4lvideo_id); + } + break; + case V4LVIDEO_IOCTL_ALLOC_FD:{ + u32 v4lvideo_fd = 0; + + ret = v4lvideo_alloc_fd(&v4lvideo_fd); + if (ret != 0) + break; + put_user(v4lvideo_fd, (u32 __user *)argp); + } + break; + default: + return -EINVAL; + } + return ret; +} + +#ifdef CONFIG_COMPAT +static long v4lvideo_compat_ioctl(struct file *file, + unsigned int cmd, + ulong arg) +{ + long ret = 0; + + ret = v4lvideo_ioctl(file, cmd, (ulong)compat_ptr(arg)); + return ret; +} +#endif +static const struct file_operations v4lvideo_fops = { + .owner = THIS_MODULE, + .open = v4lvideo_open, + .release = v4lvideo_release, + .unlocked_ioctl = v4lvideo_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = v4lvideo_compat_ioctl, +#endif + .poll = NULL, +}; + +static int __init v4lvideo_init(void) +{ + int ret = -1, i; + struct device *devp; + + keeper_mgr_init(); + + ret = class_register(&v4lvideo_class); + if (ret < 0) + return ret; + + ret = register_chrdev(V4LVIDEO_MAJOR, "v4lvideo", &v4lvideo_fops); + if (ret < 0) { + pr_err("Can't allocate major for v4lvideo device\n"); + goto error1; + } + + devp = device_create(&v4lvideo_class, + NULL, + MKDEV(V4LVIDEO_MAJOR, 0), + NULL, + V4LVIDEO_DEVICE_NAME); + if (IS_ERR(devp)) { + pr_err("failed to create v4lvideo device node\n"); + ret = PTR_ERR(devp); + return ret; + } + + if (n_devs <= 0) + n_devs = 1; + for (i = 0; i < n_devs; i++) { + ret = v4lvideo_create_instance(i); + if (ret) { + /* If some instantiations succeeded, keep driver */ + if (i) + ret = 0; + break; + } + } + + if (ret < 0) { + V4LVID_ERR("v4lvideo: error %d while loading driver\n", ret); + goto error1; + } + + return 0; + +error1: + unregister_chrdev(V4LVIDEO_MAJOR, "v4lvideo"); + class_unregister(&v4lvideo_class); + return ret; +} + +static void __exit v4lvideo_exit(void) +{ + v4lvideo_v4l2_release(); + device_destroy(&v4lvideo_class, MKDEV(V4LVIDEO_MAJOR, 0)); + unregister_chrdev(V4LVIDEO_MAJOR, V4LVIDEO_DEVICE_NAME); + class_unregister(&v4lvideo_class); +} + +MODULE_DESCRIPTION("Video Technology Magazine V4l Video Capture Board"); +MODULE_AUTHOR("Amlogic, Jintao Xu"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_VERSION(V4LVIDEO_VERSION); + +module_init(v4lvideo_init); +module_exit(v4lvideo_exit); diff --git a/drivers/amlogic/media/video_processor/v4lvideo/v4lvideo.h b/drivers/amlogic/media/video_processor/v4lvideo/v4lvideo.h new file mode 100644 index 000000000000..8042befaca1c --- /dev/null +++ b/drivers/amlogic/media/video_processor/v4lvideo/v4lvideo.h @@ -0,0 +1,235 @@ +/* + * drivers/amlogic/media/video_processor/v4lvideo/v4lvideo.h + * + * Copyright (C) 2017 Amlogic, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +#ifndef _v4lvideo_H +#define _v4lvideo_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +/* #include */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#define MAX_WIDTH 4096 +#define MAX_HEIGHT 4096 + +#define V4LVIDEO_POOL_SIZE 16 +#define VF_POOL_SIZE 32 +#define ION_VF_RECEIVER_NAME_SIZE 32 + +#define V4LVID_INFO(fmt, args...) pr_info("v4lvid: info: " fmt, ## args) +#define V4LVID_DBG(fmt, args...) pr_debug("v4lvid: dbg: " fmt, ## args) +#define V4LVID_ERR(fmt, args...) pr_err("v4lvid: err: " fmt, ## args) + +#define dprintk(dev, level, fmt, arg...) \ +v4l2_dbg(level, debug, &(dev)->v4l2_dev, fmt, ## arg) + +struct v4l2q_s { + int rp; + int wp; + int size; + int pre_rp; + int pre_wp; + void **pool; +}; + +static inline void v4l2q_lookup_start(struct v4l2q_s *q) +{ + q->pre_rp = q->rp; + q->pre_wp = q->wp; +} + +static inline void v4l2q_lookup_end(struct v4l2q_s *q) +{ + q->rp = q->pre_rp; + q->wp = q->pre_wp; +} + +static inline void v4l2q_init(struct v4l2q_s *q, u32 size, + void **pool) +{ + q->rp = 0; + q->wp = 0; + q->size = size; + q->pool = pool; +} + +static inline bool v4l2q_empty(struct v4l2q_s *q) +{ + return q->rp == q->wp; +} + +static inline int v4l2q_level(struct v4l2q_s *q) +{ + int level = q->wp - q->rp; + + if (level < 0) + level += q->size; + + return level; +} + +static inline void v4l2q_push(struct v4l2q_s *q, void *vf) +{ + int wp = q->wp; + + /*ToDo*/ + smp_mb(); + + q->pool[wp] = vf; + + /*ToDo*/ + smp_wmb(); + + q->wp = (wp == (q->size - 1)) ? 0 : (wp + 1); +} + +static inline void *v4l2q_pop(struct v4l2q_s *q) +{ + void *vf; + int rp; + + if (v4l2q_empty(q)) + return NULL; + + rp = q->rp; + + /*ToDo*/ + smp_rmb(); + + vf = q->pool[rp]; + + /*ToDo*/ + smp_mb(); + + q->rp = (rp == (q->size - 1)) ? 0 : (rp + 1); + + return vf; +} + +static inline void *v4l2q_peek(struct v4l2q_s *q) +{ + return (v4l2q_empty(q)) ? NULL : q->pool[q->rp]; +} + +static inline bool v4l2q_pop_specific(struct v4l2q_s *q, void *vf) +{ + void *vf_tmp = NULL; + int i = v4l2q_level(q); + + if (i <= 0) { + pr_err("v4l2q_pop_specific fail i =%d\n", i); + return false; + } + + while (i > 0) { + i--; + vf_tmp = v4l2q_pop(q); + if (vf_tmp != vf) { + v4l2q_push(q, vf_tmp); + if (i < 1) { + pr_err("v4l2q_pop_specific fail\n"); + return false; + } + } else { + break; + } + } + return true; +} + +/* ------------------------------------------------------------------ + * Basic structures + * ------------------------------------------------------------------ + */ +struct v4lvideo_fmt { + char *name; + u32 fourcc; /* v4l2 format id */ + u8 depth; + bool is_yuv; +}; + +/* v4l2_amlogic_parm must < u8[200] */ +struct v4l2_amlogic_parm { + u32 signal_type; + struct vframe_master_display_colour_s + master_display_colour; + }; + +struct v4lvideo_dev { + struct list_head v4lvideo_devlist; + struct v4l2_device v4l2_dev; + struct video_device vdev; + int fd_num; + + /* video capture */ + const struct v4lvideo_fmt *fmt; + unsigned int width, height; + struct vframe_receiver_s video_vf_receiver; + u64 last_pts_us64; + + char vf_receiver_name[ION_VF_RECEIVER_NAME_SIZE]; + int inst; + bool mapped; + int vf_wait_cnt; + bool receiver_register; + u32 frame_num; + + struct v4l2q_s input_queue; + struct v4l2q_s display_queue; + struct v4l2_buffer *v4lvideo_input_queue[V4LVIDEO_POOL_SIZE]; + struct file_private_data *v4lvideo_display_queue[VF_POOL_SIZE]; + /* mutex_input */ + struct mutex mutex_input; + struct v4l2_buffer v4lvideo_input[V4LVIDEO_POOL_SIZE]; + struct v4l2_amlogic_parm am_parm; + u8 first_frame; +}; + +unsigned int get_v4lvideo_debug(void); + +#define V4LVIDEO_IOC_MAGIC 'I' +#define V4LVIDEO_IOCTL_ALLOC_ID _IOW(V4LVIDEO_IOC_MAGIC, 0x00, int) +#define V4LVIDEO_IOCTL_FREE_ID _IOW(V4LVIDEO_IOC_MAGIC, 0x01, int) +#define V4LVIDEO_IOCTL_ALLOC_FD _IOW(V4LVIDEO_IOC_MAGIC, 0x02, int) + +#endif diff --git a/drivers/amlogic/media/video_processor/video_composer/Kconfig b/drivers/amlogic/media/video_processor/video_composer/Kconfig new file mode 100644 index 000000000000..83a91805e1ff --- /dev/null +++ b/drivers/amlogic/media/video_processor/video_composer/Kconfig @@ -0,0 +1,15 @@ +# +# Amlogic video_composer device configuation +# + +menu "Amlogic video_composer support" + +config AMLOGIC_VIDEO_COMPOSER + tristate "Amlogic video_composer device support" + select VIDEO_DEV + default n + + ---help--- + Select to enable "Amlogic video_composer device support. + +endmenu diff --git a/drivers/amlogic/media/video_processor/video_composer/Makefile b/drivers/amlogic/media/video_processor/video_composer/Makefile new file mode 100644 index 000000000000..786b2d1d13f9 --- /dev/null +++ b/drivers/amlogic/media/video_processor/video_composer/Makefile @@ -0,0 +1,5 @@ +asflags-y=-mfloat-abi=softfp -mfpu=neon +ccflags-y += -Idrivers/staging/android/ + +obj-$(CONFIG_AMLOGIC_VIDEO_COMPOSER) += video_composer.o +obj-$(CONFIG_AMLOGIC_VIDEO_COMPOSER) += vframe_ge2d_composer.o \ No newline at end of file diff --git a/drivers/amlogic/media/video_processor/video_composer/vfq.h b/drivers/amlogic/media/video_processor/video_composer/vfq.h new file mode 100644 index 000000000000..02423afe4df2 --- /dev/null +++ b/drivers/amlogic/media/video_processor/video_composer/vfq.h @@ -0,0 +1,115 @@ +/* + * drivers/amlogic/media/video_processor/video_composer/vfq.h + * + * Copyright (C) 2017 Amlogic, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +#ifndef __VFQ_H_ +#define __VFQ_H_ + +struct vfq_s { + int rp; + int wp; + int size; + int pre_rp; + int pre_wp; + struct vframe_s **pool; +}; + +static inline void vfq_lookup_start(struct vfq_s *q) +{ + q->pre_rp = q->rp; + q->pre_wp = q->wp; +} + +static inline void vfq_lookup_end(struct vfq_s *q) +{ + q->rp = q->pre_rp; + q->wp = q->pre_wp; +} + +static inline void vfq_init(struct vfq_s *q, u32 size, struct vframe_s **pool) +{ + q->rp = 0; + q->wp = 0; + q->size = size; + q->pool = pool; +} + +static inline bool vfq_empty(struct vfq_s *q) +{ + return q->rp == q->wp; +} + +static inline bool vfq_full(struct vfq_s *q) +{ + bool ret = (((q->wp + 1) % q->size) == q->rp); + + return ret; +} + +static inline void vfq_push(struct vfq_s *q, struct vframe_s *vf) +{ + int wp = q->wp; + + /*ToDo*/ + smp_mb(); + + q->pool[wp] = vf; + + /*ToDo*/ + smp_wmb(); + + q->wp = (wp == (q->size - 1)) ? 0 : (wp + 1); +} + +static inline struct vframe_s *vfq_pop(struct vfq_s *q) +{ + struct vframe_s *vf; + int rp; + + if (vfq_empty(q)) + return NULL; + + rp = q->rp; + + /*ToDo*/ + smp_rmb(); + + vf = q->pool[rp]; + + /*ToDo*/ + smp_mb(); + + q->rp = (rp == (q->size - 1)) ? 0 : (rp + 1); + + return vf; +} + +static inline struct vframe_s *vfq_peek(struct vfq_s *q) +{ + return (vfq_empty(q)) ? NULL : q->pool[q->rp]; +} + +static inline int vfq_level(struct vfq_s *q) +{ + int level = q->wp - q->rp; + + if (level < 0) + level += q->size; + + return level; +} + +#endif /* __VFP_H_ */ diff --git a/drivers/amlogic/media/video_processor/video_composer/vframe_ge2d_composer.c b/drivers/amlogic/media/video_processor/video_composer/vframe_ge2d_composer.c new file mode 100644 index 000000000000..715d79dbed9d --- /dev/null +++ b/drivers/amlogic/media/video_processor/video_composer/vframe_ge2d_composer.c @@ -0,0 +1,560 @@ +/* + * drivers/amlogic/media/video_processor/video_composer/vframe_ge2d_composer.c + * + * Copyright (C) 2017 Amlogic, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +#include +#include +#include +#include +#include +#include "vframe_ge2d_composer.h" +#include "vfq.h" +#include +#include +#include +#include + +static unsigned int ge2d_com_debug; +MODULE_PARM_DESC(ge2d_com_debug, "\n ge2d_com_debug\n"); +module_param(ge2d_com_debug, uint, 0664); + +static int get_source_type(struct src_data_para *src_data) +{ + enum videocom_source_type ret; + int interlace_mode; + + interlace_mode = src_data->type & VIDTYPE_TYPEMASK; + if ((src_data->source_type == VFRAME_SOURCE_TYPE_HDMI) || + (src_data->source_type == VFRAME_SOURCE_TYPE_CVBS)) { + if ((src_data->bitdepth & BITDEPTH_Y10) && + (!(src_data->type & VIDTYPE_COMPRESS)) && + (get_cpu_type() >= MESON_CPU_MAJOR_ID_TXL)) + ret = VDIN_10BIT_NORMAL; + else + ret = VDIN_8BIT_NORMAL; + } else { + if ((src_data->bitdepth & BITDEPTH_Y10) && + (!(src_data->type & VIDTYPE_COMPRESS)) && + (get_cpu_type() >= MESON_CPU_MAJOR_ID_TXL)) { + if (interlace_mode == VIDTYPE_INTERLACE_TOP) + ret = DECODER_10BIT_TOP; + else if (interlace_mode == VIDTYPE_INTERLACE_BOTTOM) + ret = DECODER_10BIT_BOTTOM; + else + ret = DECODER_10BIT_NORMAL; + } else { + if (interlace_mode == VIDTYPE_INTERLACE_TOP) + ret = DECODER_8BIT_TOP; + else if (interlace_mode == VIDTYPE_INTERLACE_BOTTOM) + ret = DECODER_8BIT_BOTTOM; + else + ret = DECODER_8BIT_NORMAL; + } + } + return ret; +} + +static int get_input_format(struct src_data_para *src_data) +{ + int format = GE2D_FORMAT_M24_YUV420; + enum videocom_source_type soure_type; + + soure_type = get_source_type(src_data); + switch (soure_type) { + case DECODER_8BIT_NORMAL: + if (src_data->type & VIDTYPE_VIU_422) + format = GE2D_FORMAT_S16_YUV422; + else if (src_data->type & VIDTYPE_VIU_NV21) + format = GE2D_FORMAT_M24_NV21; + else if (src_data->type & VIDTYPE_VIU_444) + format = GE2D_FORMAT_S24_YUV444; + else + format = GE2D_FORMAT_M24_YUV420; + break; + case DECODER_8BIT_BOTTOM: + if (src_data->type & VIDTYPE_VIU_422) + format = GE2D_FORMAT_S16_YUV422 + | (GE2D_FORMAT_S16_YUV422B & (3 << 3)); + else if (src_data->type & VIDTYPE_VIU_NV21) + format = GE2D_FORMAT_M24_NV21 + | (GE2D_FORMAT_M24_NV21B & (3 << 3)); + else if (src_data->type & VIDTYPE_VIU_444) + format = GE2D_FORMAT_S24_YUV444 + | (GE2D_FORMAT_S24_YUV444B & (3 << 3)); + else + format = GE2D_FORMAT_M24_YUV420 + | (GE2D_FMT_M24_YUV420B & (3 << 3)); + break; + case DECODER_8BIT_TOP: + if (src_data->type & VIDTYPE_VIU_422) + format = GE2D_FORMAT_S16_YUV422 + | (GE2D_FORMAT_S16_YUV422T & (3 << 3)); + else if (src_data->type & VIDTYPE_VIU_NV21) + format = GE2D_FORMAT_M24_NV21 + | (GE2D_FORMAT_M24_NV21T & (3 << 3)); + else if (src_data->type & VIDTYPE_VIU_444) + format = GE2D_FORMAT_S24_YUV444 + | (GE2D_FORMAT_S24_YUV444T & (3 << 3)); + else + format = GE2D_FORMAT_M24_YUV420 + | (GE2D_FMT_M24_YUV420T & (3 << 3)); + break; + case DECODER_10BIT_NORMAL: + if (src_data->type & VIDTYPE_VIU_422) { + if (src_data->bitdepth & FULL_PACK_422_MODE) + format = GE2D_FORMAT_S16_10BIT_YUV422; + else + format = GE2D_FORMAT_S16_12BIT_YUV422; + } + break; + case DECODER_10BIT_BOTTOM: + if (src_data->type & VIDTYPE_VIU_422) { + if (src_data->bitdepth & FULL_PACK_422_MODE) + format = GE2D_FORMAT_S16_10BIT_YUV422 + | (GE2D_FORMAT_S16_10BIT_YUV422B + & (3 << 3)); + else + format = GE2D_FORMAT_S16_12BIT_YUV422 + | (GE2D_FORMAT_S16_12BIT_YUV422B + & (3 << 3)); + } + break; + case DECODER_10BIT_TOP: + if (src_data->type & VIDTYPE_VIU_422) { + if (src_data->bitdepth & FULL_PACK_422_MODE) + format = GE2D_FORMAT_S16_10BIT_YUV422 + | (GE2D_FORMAT_S16_10BIT_YUV422T + & (3 << 3)); + else + format = GE2D_FORMAT_S16_12BIT_YUV422 + | (GE2D_FORMAT_S16_12BIT_YUV422T + & (3 << 3)); + } + break; + case VDIN_8BIT_NORMAL: + if (src_data->type & VIDTYPE_VIU_422) + format = GE2D_FORMAT_S16_YUV422; + else if (src_data->type & VIDTYPE_VIU_NV21) + format = GE2D_FORMAT_M24_NV21; + else if (src_data->type & VIDTYPE_VIU_444) + format = GE2D_FORMAT_S24_YUV444; + else + format = GE2D_FORMAT_M24_YUV420; + break; + case VDIN_10BIT_NORMAL: + if (src_data->type & VIDTYPE_VIU_422) { + if (src_data->bitdepth & FULL_PACK_422_MODE) + format = GE2D_FORMAT_S16_10BIT_YUV422; + else + format = GE2D_FORMAT_S16_12BIT_YUV422; + } + break; + default: + format = GE2D_FORMAT_M24_YUV420; + } + return format; +} + +static int alloc_src_canvas(struct ge2d_composer_para *ge2d_comp_para) +{ + const char *keep_owner = "ge2d_composer"; + + if (ge2d_comp_para->canvas_scr[0] < 0) + ge2d_comp_para->canvas_scr[0] = + canvas_pool_map_alloc_canvas(keep_owner); + if (ge2d_comp_para->canvas_scr[1] < 0) + ge2d_comp_para->canvas_scr[1] = + canvas_pool_map_alloc_canvas(keep_owner); + if (ge2d_comp_para->canvas_scr[2] < 0) + ge2d_comp_para->canvas_scr[2] = + canvas_pool_map_alloc_canvas(keep_owner); + + if ((ge2d_comp_para->canvas_scr[0] < 0) || + (ge2d_comp_para->canvas_scr[1] < 0) || + (ge2d_comp_para->canvas_scr[2] < 0)) { + VIDEOCOM_INFO("scr_canvas alloc failed\n"); + return -1; + } + return 0; +} + +static int free_src_canvas(struct ge2d_composer_para *ge2d_comp_para) +{ + if (ge2d_comp_para->canvas_scr[0] >= 0) { + canvas_pool_map_free_canvas( + ge2d_comp_para->canvas_scr[0]); + ge2d_comp_para->canvas_scr[0] = -1; + } + + if (ge2d_comp_para->canvas_scr[1] >= 0) { + canvas_pool_map_free_canvas( + ge2d_comp_para->canvas_scr[1]); + ge2d_comp_para->canvas_scr[1] = -1; + } + + if (ge2d_comp_para->canvas_scr[2] >= 0) { + canvas_pool_map_free_canvas( + ge2d_comp_para->canvas_scr[2]); + ge2d_comp_para->canvas_scr[2] = -1; + } + if ((ge2d_comp_para->canvas_scr[0] >= 0) || + (ge2d_comp_para->canvas_scr[1] >= 0) || + (ge2d_comp_para->canvas_scr[2] >= 0)) { + VIDEOCOM_INFO("scr_canvas free failed!\n"); + return -1; + } + return 0; +} + +int init_ge2d_composer(struct ge2d_composer_para *ge2d_comp_para) +{ + const char *keep_owner = "ge2d_dest_comp"; + + ge2d_comp_para->context = create_ge2d_work_queue(); + if (IS_ERR_OR_NULL(ge2d_comp_para->context)) { + VIDEOCOM_INFO("creat ge2d work failed\n"); + return -1; + } + + if (ge2d_comp_para->plane_num > 0) { + if (ge2d_comp_para->canvas_dst[0] < 0) + ge2d_comp_para->canvas_dst[0] = + canvas_pool_map_alloc_canvas(keep_owner); + if (ge2d_comp_para->canvas_dst[0] < 0) { + VIDEOCOM_ERR("ge2d init dst canvas_0 failed!\n"); + return -1; + } + } + + if (ge2d_comp_para->plane_num > 1) { + if (ge2d_comp_para->canvas_dst[1] < 0) + ge2d_comp_para->canvas_dst[1] = + canvas_pool_map_alloc_canvas(keep_owner); + if (ge2d_comp_para->canvas_dst[1] < 0) { + VIDEOCOM_ERR("ge2d init dst canvas_1 failed!\n"); + return -1; + } + } + + if (ge2d_comp_para->plane_num > 2) { + if (ge2d_comp_para->canvas_dst[2] < 0) + ge2d_comp_para->canvas_dst[2] = + canvas_pool_map_alloc_canvas(keep_owner); + if (ge2d_comp_para->canvas_dst[2] < 0) { + VIDEOCOM_ERR("ge2d init dst canvas_2 failed!\n"); + return -1; + } + } + return 0; +} + +int uninit_ge2d_composer(struct ge2d_composer_para *ge2d_comp_para) +{ + destroy_ge2d_work_queue(ge2d_comp_para->context); + ge2d_comp_para->context = NULL; + + if (free_src_canvas(ge2d_comp_para) < 0) { + VIDEOCOM_ERR("free src canvas failed!\n"); + return -1; + } + + if (ge2d_comp_para->canvas_dst[0] >= 0) { + canvas_pool_map_free_canvas( + ge2d_comp_para->canvas_dst[0]); + ge2d_comp_para->canvas_dst[0] = -1; + } + + if (ge2d_comp_para->canvas_dst[1] >= 0) { + canvas_pool_map_free_canvas( + ge2d_comp_para->canvas_dst[1]); + ge2d_comp_para->canvas_dst[1] = -1; + } + + if (ge2d_comp_para->canvas_dst[2] >= 0) { + canvas_pool_map_free_canvas( + ge2d_comp_para->canvas_dst[2]); + ge2d_comp_para->canvas_dst[2] = -1; + } + + if ((ge2d_comp_para->canvas_dst[0] >= 0) || + (ge2d_comp_para->canvas_dst[1] >= 0) || + (ge2d_comp_para->canvas_dst[2] >= 0)) { + VIDEOCOM_ERR("free dst canvas failed!\n"); + return -1; + } + return 0; +} + +int fill_vframe_black(struct ge2d_composer_para *ge2d_comp_para) +{ + struct canvas_config_s dst_canvas0_config[3]; + u32 dst_plane_num; + + memset(ge2d_comp_para->ge2d_config, 0, sizeof(struct config_para_ex_s)); + + if (ge2d_comp_para->format == GE2D_FORMAT_S24_YUV444) { + dst_canvas0_config[0].phy_addr = ge2d_comp_para->phy_addr[0]; + dst_canvas0_config[0].width = ge2d_comp_para->buffer_w * 3; + dst_canvas0_config[0].height = ge2d_comp_para->buffer_h; + dst_canvas0_config[0].block_mode = 0; + dst_canvas0_config[0].endian = 0; + } + dst_plane_num = 1; + + if (ge2d_comp_para->canvas0Addr == (u32)-1) { + canvas_config_config( + ge2d_comp_para->canvas_dst[0], + &dst_canvas0_config[0]); + if (dst_plane_num == 2) { + canvas_config_config( + ge2d_comp_para->canvas_dst[1], + &dst_canvas0_config[1]); + } else if (dst_plane_num == 3) { + canvas_config_config( + ge2d_comp_para->canvas_dst[2], + &dst_canvas0_config[2]); + } + ge2d_comp_para->ge2d_config->src_para.canvas_index = + ge2d_comp_para->canvas_dst[0] + | (ge2d_comp_para->canvas_dst[1] << 8) + | (ge2d_comp_para->canvas_dst[2] << 16); + + } else { + ge2d_comp_para->ge2d_config->src_para.canvas_index = + ge2d_comp_para->canvas0Addr; + } + ge2d_comp_para->ge2d_config->alu_const_color = 0;/*0x000000ff;*/ + ge2d_comp_para->ge2d_config->bitmask_en = 0; + ge2d_comp_para->ge2d_config->src1_gb_alpha = 0;/*0xff;*/ + ge2d_comp_para->ge2d_config->dst_xy_swap = 0; + + ge2d_comp_para->ge2d_config->src_key.key_enable = 0; + ge2d_comp_para->ge2d_config->src_key.key_mask = 0; + ge2d_comp_para->ge2d_config->src_key.key_mode = 0; + + ge2d_comp_para->ge2d_config->src_para.mem_type = + CANVAS_TYPE_INVALID; + ge2d_comp_para->ge2d_config->src_para.format = + ge2d_comp_para->format; + ge2d_comp_para->ge2d_config->src_para.fill_color_en = 0; + ge2d_comp_para->ge2d_config->src_para.fill_mode = 0; + ge2d_comp_para->ge2d_config->src_para.x_rev = 0; + ge2d_comp_para->ge2d_config->src_para.y_rev = 0; + ge2d_comp_para->ge2d_config->src_para.color = 0; + ge2d_comp_para->ge2d_config->src_para.top = 0; + ge2d_comp_para->ge2d_config->src_para.left = 0; + ge2d_comp_para->ge2d_config->src_para.width = + ge2d_comp_para->buffer_w; + ge2d_comp_para->ge2d_config->src_para.height = + ge2d_comp_para->buffer_h; + ge2d_comp_para->ge2d_config->src2_para.mem_type = + CANVAS_TYPE_INVALID; + ge2d_comp_para->ge2d_config->dst_para.canvas_index = + ge2d_comp_para->ge2d_config->src_para.canvas_index; + ge2d_comp_para->ge2d_config->dst_para.mem_type = + CANVAS_TYPE_INVALID; + ge2d_comp_para->ge2d_config->dst_para.fill_color_en = 0; + ge2d_comp_para->ge2d_config->dst_para.fill_mode = 0; + ge2d_comp_para->ge2d_config->dst_para.x_rev = 0; + ge2d_comp_para->ge2d_config->dst_para.y_rev = 0; + ge2d_comp_para->ge2d_config->dst_para.color = 0; + ge2d_comp_para->ge2d_config->dst_para.top = 0; + ge2d_comp_para->ge2d_config->dst_para.left = 0; + ge2d_comp_para->ge2d_config->dst_para.format = + ge2d_comp_para->format; + ge2d_comp_para->ge2d_config->dst_para.width = + ge2d_comp_para->buffer_w; + ge2d_comp_para->ge2d_config->dst_para.height = + ge2d_comp_para->buffer_h; + + if (ge2d_context_config_ex(ge2d_comp_para->context, + ge2d_comp_para->ge2d_config) < 0) { + VIDEOCOM_ERR("++ge2d configing error.\n"); + return -1; + } + fillrect(ge2d_comp_para->context, 0, 0, + ge2d_comp_para->buffer_w, + ge2d_comp_para->buffer_h, + 0x008080ff); + return 0; +} + +int ge2d_data_composer( + struct src_data_para *scr_data, + struct ge2d_composer_para *ge2d_comp_para) +{ + int ret; + struct canvas_config_s dst_canvas0_config[3]; + u32 dst_plane_num; + int src_canvas_id, dst_canvas_id; + int input_width, input_height; + int position_left, position_top; + int position_width, position_height; + + memset(ge2d_comp_para->ge2d_config, + 0, sizeof(struct config_para_ex_s)); + + if (ge2d_comp_para->format == GE2D_FORMAT_S24_YUV444) { + dst_canvas0_config[0].phy_addr = ge2d_comp_para->phy_addr[0]; + dst_canvas0_config[0].width = ge2d_comp_para->buffer_w * 3; + dst_canvas0_config[0].height = ge2d_comp_para->buffer_h; + dst_canvas0_config[0].block_mode = 0; + dst_canvas0_config[0].endian = 0; + } + dst_plane_num = 1; + + if (scr_data->canvas0Addr == (u32)-1) { + ret = alloc_src_canvas(ge2d_comp_para); + if (ret < 0) { + VIDEOCOM_ERR("alloc src canvas failed!\n"); + return -1; + } + canvas_config_config( + ge2d_comp_para->canvas_scr[0], + &scr_data->canvas0_config[0]); + if (scr_data->plane_num == 2) { + canvas_config_config( + ge2d_comp_para->canvas_scr[1], + &scr_data->canvas0_config[1]); + } else if (scr_data->plane_num == 3) { + canvas_config_config( + ge2d_comp_para->canvas_scr[2], + &scr_data->canvas0_config[2]); + } + src_canvas_id = ge2d_comp_para->canvas_scr[0] + | (ge2d_comp_para->canvas_scr[1] << 8) + | (ge2d_comp_para->canvas_scr[2] << 16); + } else { + src_canvas_id = scr_data->canvas0Addr; + } + + if (ge2d_comp_para->canvas0Addr == (u32)-1) { + canvas_config_config( + ge2d_comp_para->canvas_dst[0], + &dst_canvas0_config[0]); + if (dst_plane_num == 2) { + canvas_config_config( + ge2d_comp_para->canvas_dst[1], + &dst_canvas0_config[1]); + } else if (dst_plane_num == 3) { + canvas_config_config( + ge2d_comp_para->canvas_dst[2], + &dst_canvas0_config[2]); + } + dst_canvas_id = ge2d_comp_para->canvas_dst[0] + | (ge2d_comp_para->canvas_dst[1] << 8) + | (ge2d_comp_para->canvas_dst[2] << 16); + } else { + dst_canvas_id = ge2d_comp_para->canvas0Addr; + } + input_width = scr_data->width; + input_height = scr_data->height; + + if (scr_data->type & VIDTYPE_INTERLACE) + input_height = scr_data->height >> 1; + else + input_height = scr_data->height; + ge2d_comp_para->ge2d_config->alu_const_color = 0; + ge2d_comp_para->ge2d_config->bitmask_en = 0; + ge2d_comp_para->ge2d_config->src1_gb_alpha = 0; + ge2d_comp_para->ge2d_config->dst_xy_swap = 0; + + ge2d_comp_para->ge2d_config->src_key.key_enable = 0; + ge2d_comp_para->ge2d_config->src_key.key_mask = 0; + ge2d_comp_para->ge2d_config->src_key.key_mode = 0; + ge2d_comp_para->ge2d_config->src_para.mem_type = + CANVAS_TYPE_INVALID; + if (scr_data->is_vframe) + ge2d_comp_para->ge2d_config->src_para.format = + get_input_format(scr_data); + else + ge2d_comp_para->ge2d_config->src_para.format = + get_input_format(scr_data) | GE2D_LITTLE_ENDIAN; + + ge2d_comp_para->ge2d_config->src_para.fill_color_en = 0; + ge2d_comp_para->ge2d_config->src_para.fill_mode = 0; + ge2d_comp_para->ge2d_config->src_para.x_rev = 0; + ge2d_comp_para->ge2d_config->src_para.y_rev = 0; + ge2d_comp_para->ge2d_config->src_para.color = + 0xffffffff; + ge2d_comp_para->ge2d_config->src_para.top = 0; + ge2d_comp_para->ge2d_config->src_para.left = 0; + ge2d_comp_para->ge2d_config->src_para.width = input_width; + ge2d_comp_para->ge2d_config->src_para.height = input_height; + ge2d_comp_para->ge2d_config->src_para.canvas_index = src_canvas_id; + + ge2d_comp_para->ge2d_config->src2_para.mem_type = + CANVAS_TYPE_INVALID; + + ge2d_comp_para->ge2d_config->dst_para.mem_type = + CANVAS_TYPE_INVALID; + + ge2d_comp_para->ge2d_config->dst_para.fill_color_en = 0; + ge2d_comp_para->ge2d_config->dst_para.fill_mode = 0; + ge2d_comp_para->ge2d_config->dst_para.x_rev = 0; + ge2d_comp_para->ge2d_config->dst_para.y_rev = 0; + ge2d_comp_para->ge2d_config->dst_xy_swap = 0; + + if (ge2d_comp_para->angle == 1) { + ge2d_comp_para->ge2d_config->dst_xy_swap = 1; + ge2d_comp_para->ge2d_config->dst_para.x_rev = 1; + } else if (ge2d_comp_para->angle == 2) { + ge2d_comp_para->ge2d_config->dst_para.x_rev = 1; + ge2d_comp_para->ge2d_config->dst_para.y_rev = 1; + } else if (ge2d_comp_para->angle == 3) { + ge2d_comp_para->ge2d_config->dst_xy_swap = 1; + ge2d_comp_para->ge2d_config->dst_para.y_rev = 1; + } + ge2d_comp_para->ge2d_config->dst_para.canvas_index = dst_canvas_id; + + ge2d_comp_para->ge2d_config->dst_para.color = 0; + ge2d_comp_para->ge2d_config->dst_para.top = 0; + ge2d_comp_para->ge2d_config->dst_para.left = 0; + + ge2d_comp_para->ge2d_config->dst_para.format = + ge2d_comp_para->format; + ge2d_comp_para->ge2d_config->dst_para.width = + ge2d_comp_para->buffer_w; + ge2d_comp_para->ge2d_config->dst_para.height = + ge2d_comp_para->buffer_h; + + if (ge2d_context_config_ex(ge2d_comp_para->context, + ge2d_comp_para->ge2d_config) < 0) { + VIDEOCOM_ERR("++ge2d configing error.\n"); + return -1; + } + + position_left = ge2d_comp_para->position_left; + position_top = ge2d_comp_para->position_top; + position_width = ge2d_comp_para->position_width; + position_height = ge2d_comp_para->position_height; + + stretchblt_noalpha(ge2d_comp_para->context, + 0, + 0, + input_width, + input_height, + position_left, + position_top, + position_width, + position_height); + if (ge2d_com_debug & 1) + VIDEOCOM_INFO("scr format: %0x, dst format: %0x!\n", + ge2d_comp_para->ge2d_config->src_para.format, + ge2d_comp_para->ge2d_config->dst_para.format); + return 0; +} + diff --git a/drivers/amlogic/media/video_processor/video_composer/vframe_ge2d_composer.h b/drivers/amlogic/media/video_processor/video_composer/vframe_ge2d_composer.h new file mode 100644 index 000000000000..de8ece82887a --- /dev/null +++ b/drivers/amlogic/media/video_processor/video_composer/vframe_ge2d_composer.h @@ -0,0 +1,88 @@ +/* + * drivers/amlogic/media/video_processor/video_composer/vframe_ge2d_composer.h + * + * Copyright (C) 2017 Amlogic, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +#ifndef VFRAME_GE2D_COMPOSER_H +#define VFRAME_GE2D_COMPOSER_H +#include +#include +#include +#include +//#include "video_composer.h" + +#define VIDEOCOM_INFO(fmt, args...) \ + pr_info("video_composer: info:" fmt "", ## args) +#define VIDEOCOM_DBG(fmt, args...) \ + pr_debug("video_composer: dbg:" fmt "", ## args) +#define VIDEOCOM_WARN(fmt, args...) \ + pr_warn("video_composer: warn:" fmt "", ## args) +#define VIDEOCOM_ERR(fmt, args...) \ + pr_err("video_composer: err:" fmt "", ## args) + +enum videocom_source_type { + DECODER_8BIT_NORMAL = 0, + DECODER_8BIT_BOTTOM, + DECODER_8BIT_TOP, + DECODER_10BIT_NORMAL, + DECODER_10BIT_BOTTOM, + DECODER_10BIT_TOP, + VDIN_8BIT_NORMAL, + VDIN_10BIT_NORMAL, +}; + +struct ge2d_composer_para { + int count; + int format; + int position_left; + int position_top; + int position_width; + int position_height; + int buffer_w; + int buffer_h; + int plane_num; + int canvas_scr[3]; + int canvas_dst[3]; + u32 phy_addr[3]; + u32 canvas0Addr; + struct ge2d_context_s *context; + struct config_para_ex_s *ge2d_config; + int angle; +}; + +struct src_data_para { + u32 canvas0Addr; + u32 canvas1Addr; + u32 plane_num; + u32 type; + u32 width; + u32 height; + u32 bitdepth; + struct canvas_config_s canvas0_config[3]; + struct canvas_config_s canvas1_config[3]; + enum vframe_source_type_e source_type; + bool is_vframe; +}; + +int init_ge2d_composer(struct ge2d_composer_para *ge2d_comp_para); + +int uninit_ge2d_composer(struct ge2d_composer_para *ge2d_comp_para); + +int fill_vframe_black(struct ge2d_composer_para *ge2d_comp_para); + +int ge2d_data_composer(struct src_data_para *src_para, + struct ge2d_composer_para *ge2d_comp_para); + +#endif diff --git a/drivers/amlogic/media/video_processor/video_composer/video_composer.c b/drivers/amlogic/media/video_processor/video_composer/video_composer.c new file mode 100644 index 000000000000..9c1c56330fb7 --- /dev/null +++ b/drivers/amlogic/media/video_processor/video_composer/video_composer.c @@ -0,0 +1,1901 @@ +/* + * drivers/amlogic/media/video_processor/video_composer/video_composer.c + * + * Copyright (C) 2017 Amlogic, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "video_composer.h" + +#define VIDEO_COMPOSER_VERSION "1.0" + +#define VIDEO_COMPOSER_NAME_SIZE 32 + +#define VIDEO_COMPOSER_DEVICE_NAME "video_composer-dev" + +#define MAX_VIDEO_COMPOSER_INSTANCE_NUM ARRAY_SIZE(ports) + +#define WAIT_THREAD_STOPPED_TIMEOUT 20 + +#define WAIT_READY_Q_TIMEOUT 100 + +static u32 video_composer_instance_num; +static unsigned int force_composer; +MODULE_PARM_DESC(force_composer, "\n vidc_bypass\n"); +module_param(force_composer, uint, 0664); + +static unsigned int force_composer_pip; +MODULE_PARM_DESC(force_composer_pip, "\n vidc_pip_bypass\n"); +module_param(force_composer_pip, uint, 0664); + +static unsigned int transform; +MODULE_PARM_DESC(transform, "\n transform\n"); +module_param(transform, uint, 0664); + +static unsigned int vidc_debug; +MODULE_PARM_DESC(vidc_debug, "\n vidc_debug\n"); +module_param(vidc_debug, uint, 0664); + +static u32 print_flag; +MODULE_PARM_DESC(print_flag, "\n print_flag\n"); +module_param(print_flag, uint, 0664); + +static u32 full_axis; +MODULE_PARM_DESC(full_axis, "\n print_flag\n"); +module_param(full_axis, uint, 0664); + +static u32 print_close; +MODULE_PARM_DESC(print_close, "\n print_close\n"); +module_param(print_close, uint, 0664); + +static u32 receive_wait = 15; +MODULE_PARM_DESC(receive_wait, "\n receive_wait\n"); +module_param(receive_wait, uint, 0664); + +static u32 margin_time = 2000; +MODULE_PARM_DESC(margin_time, "\n margin_time\n"); +module_param(margin_time, uint, 0664); + +static u32 max_width = 2560; +MODULE_PARM_DESC(max_width, "\n max_width\n"); +module_param(max_width, uint, 0664); + +static u32 max_height = 1440; +MODULE_PARM_DESC(max_height, "\n max_height\n"); +module_param(max_height, uint, 0664); + +static u32 rotate_width = 1280; +MODULE_PARM_DESC(rotate_width, "\n rotate_width\n"); +module_param(rotate_width, uint, 0664); + +static u32 rotate_height = 720; +MODULE_PARM_DESC(rotate_height, "\n rotate_height\n"); +module_param(rotate_height, uint, 0664); + +static u32 close_black; +MODULE_PARM_DESC(close_black, "\n close_black\n"); +module_param(close_black, uint, 0664); + +static struct class *video_composer_dev_class; + +static struct class_attribute video_composer_class_attrs[] = { +}; + +static struct class video_composer_class = { + .name = "video_composer", + .class_attrs = video_composer_class_attrs, +}; + +#define PRINT_ERROR 0X0 +#define PRINT_QUEUE_STATUS 0X0001 +#define PRINT_FENCE 0X0002 +#define PRINT_PERFORMANCE 0X0004 +#define PRINT_OTHER 0X0008 + +#define to_dst_buf(vf) \ + container_of(vf, struct dst_buf_t, frame) + +int vc_print(int index, int debug_flag, const char *fmt, ...) +{ + if (index + 1 == print_close) + return 0; + + if ((print_flag & debug_flag) || + (debug_flag == PRINT_ERROR)) { + unsigned char buf[256]; + int len = 0; + va_list args; + + va_start(args, fmt); + len = sprintf(buf, "vc:[%d]", index); + vsnprintf(buf + len, 256 - len, fmt, args); + pr_info("%s", buf); + va_end(args); + } + return 0; +} + +static DEFINE_MUTEX(video_composer_mutex); + +static struct video_composer_port_s ports[] = { + { + .name = "video_composer.0", + .index = 0, + .open_count = 0, + }, + { + .name = "video_composer.1", + .index = 1, + .open_count = 0, + }, +}; + +static struct timeval vsync_time; +static int get_count[MAX_VIDEO_COMPOSER_INSTANCE_NUM]; + +void vsync_notify_video_composer(void) +{ + int i; + int count = MAX_VIDEO_COMPOSER_INSTANCE_NUM; + + for (i = 0; i < count; i++) + get_count[i] = 0; + do_gettimeofday(&vsync_time); +} + +static void *video_timeline_create(struct composer_dev *dev) +{ + const char *tl_name = "videocomposer_timeline_0"; + + if (dev->index == 0) + tl_name = "videocomposer_timeline_0"; + else if (dev->index == 1) + tl_name = "videocomposer_timeline_1"; + + if (IS_ERR_OR_NULL(dev->video_timeline)) { + dev->cur_streamline_val = 0; + dev->video_timeline = aml_sync_create_timeline(tl_name); + vc_print(dev->index, PRINT_FENCE, + "timeline create tlName =%s, video_timeline=%p\n", + tl_name, dev->video_timeline); + } + + return dev->video_timeline; +} + +static int video_timeline_create_fence(struct composer_dev *dev) +{ + int out_fence_fd = -1; + u32 pt_val = 0; + + pt_val = dev->cur_streamline_val + 1; + out_fence_fd = aml_sync_create_fence(dev->video_timeline, pt_val); + if (out_fence_fd >= 0) { + dev->cur_streamline_val++; + dev->fence_creat_count++; + } else { + vc_print(dev->index, PRINT_ERROR, + "create fence returned %d", out_fence_fd); + } + return out_fence_fd; +} + +static void video_timeline_increase(struct composer_dev *dev, + unsigned int value) +{ + aml_sync_inc_timeline(dev->video_timeline, value); + dev->fence_release_count += value; + vc_print(dev->index, PRINT_FENCE, + "receive_cnt=%lld,fen_creat_cnt=%lld,fen_release_cnt=%lld\n", + dev->received_count, + dev->fence_creat_count, + dev->fence_release_count); +} + +static int video_composer_init_buffer(struct composer_dev *dev) +{ + int i, ret = 0; + u32 buf_width, buf_height; + u32 buf_size; + struct vinfo_s *video_composer_vinfo; + struct vinfo_s vinfo = {.width = 1280, .height = 720, }; + int flags = CODEC_MM_FLAGS_DMA | CODEC_MM_FLAGS_CMA_CLEAR; + + switch (dev->buffer_status) { + case UNINITIAL:/*not config*/ + break; + case INIT_SUCCESS:/*config before , return ok*/ + return 0; + case INIT_ERROR:/*config fail, won't retry , return failure*/ + return -1; + default: + return -1; + } + + video_composer_vinfo = get_current_vinfo(); + + if (IS_ERR_OR_NULL(video_composer_vinfo)) + video_composer_vinfo = &vinfo; + dev->vinfo_w = video_composer_vinfo->width; + dev->vinfo_h = video_composer_vinfo->height; + buf_width = (video_composer_vinfo->width + 0x1f) & ~0x1f; + buf_height = video_composer_vinfo->height; + if (dev->need_rotate) { + buf_width = rotate_width; + buf_height = rotate_height; + } + if (buf_width > max_width) + buf_width = max_width; + if (buf_height > max_height) + buf_height = max_height; + buf_size = buf_width * buf_height * 3; + buf_size = PAGE_ALIGN(buf_size); + dev->composer_buf_w = buf_width; + dev->composer_buf_h = buf_height; + + for (i = 0; i < BUFFER_LEN; i++) { + if (dev->dst_buf[i].phy_addr == 0) + dev->dst_buf[i].phy_addr = codec_mm_alloc_for_dma( + "video_composer", + buf_size / PAGE_SIZE, 0, flags); + vc_print(dev->index, PRINT_OTHER, + "video_composer: cma memory is %x , size is %x\n", + (unsigned int)dev->dst_buf[i].phy_addr, + (unsigned int)buf_size); + + if (dev->dst_buf[i].phy_addr == 0) { + dev->buffer_status = INIT_ERROR; + vc_print(dev->index, PRINT_ERROR, + "cma memory config fail\n"); + return -1; + } + dev->dst_buf[i].index = i; + dev->dst_buf[i].dirty = true; + dev->dst_buf[i].buf_w = buf_width; + dev->dst_buf[i].buf_h = buf_height; + dev->dst_buf[i].buf_size = buf_size; + if (!kfifo_put(&dev->free_q, &dev->dst_buf[i].frame)) + vc_print(dev->index, PRINT_ERROR, + "init buffer free_q is full\n"); + } + + if (IS_ERR_OR_NULL(dev->ge2d_para.context)) + ret = init_ge2d_composer(&dev->ge2d_para); + + if (ret < 0) + vc_print(dev->index, PRINT_ERROR, + "create ge2d composer fail!\n"); + //vf_local_init(dev); + dev->buffer_status = INIT_SUCCESS; + + return 0; +} + +static void video_composer_uninit_buffer(struct composer_dev *dev) +{ + int i; + int ret = 0; + + if (dev->buffer_status == UNINITIAL) { + vc_print(dev->index, PRINT_OTHER, + "%s buffer have uninit already finished!\n", __func__); + return; + } + dev->buffer_status = UNINITIAL; + for (i = 0; i < BUFFER_LEN; i++) { + if (dev->dst_buf[i].phy_addr != 0) { + pr_info("video_composer: cma free addr is %x\n", + (unsigned int)dev->dst_buf[i].phy_addr); + codec_mm_free_for_dma("video_composer", + dev->dst_buf[i].phy_addr); + dev->dst_buf[i].phy_addr = 0; + } + } + + if (dev->ge2d_para.context) + ret = uninit_ge2d_composer(&dev->ge2d_para); + dev->ge2d_para.context = NULL; + if (ret < 0) + vc_print(dev->index, PRINT_ERROR, + "uninit ge2d composer failed!\n"); +} + +static void frames_put_file(struct composer_dev *dev, + struct received_frames_t *current_frames) +{ + struct file *file_vf; + int current_count; + int i; + + current_count = current_frames->frames_info.frame_count; + for (i = 0; i < current_count; i++) { + file_vf = current_frames->file_vf[i]; + fput(file_vf); + } + dev->fput_count++; +} + +static void vf_pop_display_q(struct composer_dev *dev, struct vframe_s *vf) +{ + struct vframe_s *dis_vf = NULL; + + int k = kfifo_len(&dev->display_q); + + while (kfifo_len(&dev->display_q) > 0) { + if (kfifo_get(&dev->display_q, &dis_vf)) { + if (dis_vf == vf) + break; + if (!kfifo_put(&dev->display_q, dis_vf)) + vc_print(dev->index, PRINT_ERROR, + "display_q is full!\n"); + } + k--; + if (k < 0) { + vc_print(dev->index, PRINT_ERROR, + "can find vf in display_q\n"); + break; + } + } +} + +static void display_q_uninit(struct composer_dev *dev) +{ + struct vframe_s *dis_vf = NULL; + int repeat_count; + int i; + + vc_print(dev->index, PRINT_OTHER, "vc: unit display_q len=%d\n", + kfifo_len(&dev->display_q)); + + while (kfifo_len(&dev->display_q) > 0) { + if (kfifo_get(&dev->display_q, &dis_vf)) { + if (dis_vf->flag + & VFRAME_FLAG_VIDEO_COMPOSER_BYPASS) { + repeat_count = dis_vf->repeat_count[dev->index]; + vc_print(dev->index, PRINT_OTHER, + "vc: unit repeat_count=%d\n", + repeat_count); + for (i = 0; i <= repeat_count; i++) { + fput(dis_vf->file_vf); + dev->fput_count++; + } + } else if (!(dis_vf->flag + & VFRAME_FLAG_VIDEO_COMPOSER)) { + pr_err("vc: unit display_q flag is null\n"); + } + } + } +} + +static void receive_q_uninit(struct composer_dev *dev) +{ + int i = 0; + struct received_frames_t *received_frames = NULL; + + vc_print(dev->index, PRINT_OTHER, "vc: unit receive_q len=%d\n", + kfifo_len(&dev->receive_q)); + while (kfifo_len(&dev->receive_q) > 0) { + if (kfifo_get(&dev->receive_q, &received_frames)) + frames_put_file(dev, received_frames); + } + + for (i = 0; i < FRAMES_INFO_POOL_SIZE; i++) { + atomic_set(&dev->received_frames[i].on_use, + false); + } +} + +static void ready_q_uninit(struct composer_dev *dev) +{ + struct vframe_s *dis_vf = NULL; + int repeat_count; + int i; + + vc_print(dev->index, PRINT_OTHER, "vc: unit ready_q len=%d\n", + kfifo_len(&dev->ready_q)); + + while (kfifo_len(&dev->ready_q) > 0) { + if (kfifo_get(&dev->ready_q, &dis_vf)) { + if (dis_vf->flag + & VFRAME_FLAG_VIDEO_COMPOSER_BYPASS) { + repeat_count = dis_vf->repeat_count[dev->index]; + for (i = 0; i <= repeat_count; i++) { + fput(dis_vf->file_vf); + dev->fput_count++; + } + } + } + } +} + +static void videocom_vf_put(struct vframe_s *vf, struct composer_dev *dev) +{ + struct dst_buf_t *dst_buf; + + if (IS_ERR_OR_NULL(vf)) { + vc_print(dev->index, PRINT_ERROR, "vf is NULL\n"); + return; + } + + dst_buf = to_dst_buf(vf); + if (IS_ERR_OR_NULL(dst_buf)) { + vc_print(dev->index, PRINT_ERROR, "dst_buf is NULL\n"); + return; + } + + if (IS_ERR_OR_NULL(dev)) { + vc_print(dev->index, PRINT_ERROR, "dev is NULL\n"); + return; + } + + if (!kfifo_put(&dev->free_q, vf)) + vc_print(dev->index, PRINT_ERROR, "put free_q is full\n"); + vc_print(dev->index, PRINT_OTHER, + "%s free buffer count: %d %d\n", + __func__, kfifo_len(&dev->free_q), __LINE__); + + if (kfifo_is_full(&dev->free_q)) { + dev->need_free_buffer = true; + vc_print(dev->index, PRINT_ERROR, + "free_q is full, could uninit buffer!\n"); + } + wake_up_interruptible(&dev->wq); +} + +static unsigned long get_dma_phy_addr(int fd) +{ + unsigned long phy_addr = 0; + struct dma_buf *dbuf = NULL; + struct sg_table *table = NULL; + struct page *page = NULL; + struct ion_buffer *buffer = NULL; + + dbuf = dma_buf_get(fd); + buffer = dbuf->priv; + table = buffer->sg_table; + page = sg_page(table->sgl); + phy_addr = PFN_PHYS(page_to_pfn(page)); + dma_buf_put(dbuf); + return phy_addr; +} + +static struct vframe_s *get_dst_vframe_buffer(struct composer_dev *dev) +{ + struct vframe_s *dst_vf; + + if (!kfifo_get(&dev->free_q, &dst_vf)) { + vc_print(dev->index, PRINT_OTHER, "free q is empty\n"); + return NULL; + } + return dst_vf; +} + +static void check_window_change(struct composer_dev *dev, + struct frames_info_t cur_frame_info) +{ + int last_width, last_height, current_width, current_height; + int cur_pos_x, cur_pos_y, cur_pos_w, cur_pos_h; + int last_pos_x, last_pos_y, last_pos_w, last_pos_h; + struct frames_info_t last_frame_info; + int last_zorder, cur_zorder; + bool window_changed = false; + int i; + + last_frame_info = dev->last_frames.frames_info; + if (cur_frame_info.frame_count != last_frame_info.frame_count) { + window_changed = true; + vc_print(dev->index, PRINT_ERROR, + "last count=%d, current count=%d\n", + last_frame_info.frame_count, + cur_frame_info.frame_count); + } else { + for (i = 0; i < cur_frame_info.frame_count; i++) { + current_width = cur_frame_info.frame_info[i].crop_w; + current_height = cur_frame_info.frame_info[i].crop_h; + last_width = last_frame_info.frame_info[i].crop_w; + last_height = last_frame_info.frame_info[i].crop_h; + + if (current_width * last_height != + current_height * last_width) { + vc_print(dev->index, PRINT_ERROR, + "frame width or height changed!"); + window_changed = true; + break; + } + + cur_pos_x = cur_frame_info.frame_info[i].dst_x; + cur_pos_y = cur_frame_info.frame_info[i].dst_y; + cur_pos_w = cur_frame_info.frame_info[i].dst_w; + cur_pos_h = cur_frame_info.frame_info[i].dst_h; + last_pos_x = last_frame_info.frame_info[i].dst_x; + last_pos_y = last_frame_info.frame_info[i].dst_y; + last_pos_w = last_frame_info.frame_info[i].dst_w; + last_pos_h = last_frame_info.frame_info[i].dst_h; + + if ((cur_pos_x != last_pos_x) || + (cur_pos_y != last_pos_y) || + (cur_pos_w != last_pos_w) || + (cur_pos_h != last_pos_h)) { + vc_print(dev->index, PRINT_ERROR, + "frame axis changed!"); + window_changed = true; + break; + } + + cur_zorder = cur_frame_info.frame_info[i].zorder; + last_zorder = last_frame_info.frame_info[i].zorder; + if (cur_zorder != last_zorder) { + vc_print(dev->index, PRINT_ERROR, + "frame zorder changed!"); + window_changed = true; + break; + } + } + } + + if (!window_changed) + return; + + for (i = 0; i < BUFFER_LEN; i++) + dev->dst_buf[i].dirty = true; +} + +static struct output_axis output_axis_adjust( + struct composer_dev *dev, + struct frame_info_t *vframe_info, + struct ge2d_composer_para *ge2d_comp_para) +{ + int input_width = 0, input_height = 0; + int output_w = 0, output_h = 0; + int disp_w, disp_h; + struct output_axis axis; + + input_width = vframe_info->crop_w; + input_height = vframe_info->crop_h; + disp_w = ge2d_comp_para->position_width; + disp_h = ge2d_comp_para->position_height; + + if (ge2d_comp_para->angle & 1) { + output_h = disp_h; + output_w = + (input_height * disp_h) / input_width; + if (output_w > disp_w) { + output_h = + (output_h * disp_w) / output_w; + output_w = disp_w; + } + } else { + output_w = disp_w; + output_h = disp_w * input_height / input_width; + if (output_h > disp_h) { + output_h = disp_h; + output_w = disp_h * input_width / input_height; + } + } + axis.left = ge2d_comp_para->position_left + + (ge2d_comp_para->position_width - output_w) / 2; + axis.top = ge2d_comp_para->position_top + + (ge2d_comp_para->position_height - output_h) / 2; + axis.width = output_w; + axis.height = output_h; + + axis.left = axis.left * dev->composer_buf_w / dev->vinfo_w; + axis.top = axis.top * dev->composer_buf_h / dev->vinfo_h; + axis.width = axis.width * dev->composer_buf_w / dev->vinfo_w; + axis.height = axis.height * dev->composer_buf_h / dev->vinfo_h; + + return axis; +} + +static void vframe_composer(struct composer_dev *dev) +{ + struct received_frames_t *received_frames = NULL; + struct received_frames_t *received_frames_tmp = NULL; + struct frames_info_t *frames_info = NULL; + struct vframe_s *scr_vf = NULL; + struct file *file_vf = NULL; + int vf_dev[MXA_LAYER_COUNT]; + struct frame_info_t *vframe_info[MXA_LAYER_COUNT]; + int i, j, tmp; + u32 zd1, zd2; + struct file_private_data *file_private_data; + struct config_para_ex_s ge2d_config; + struct timeval begin_time; + struct timeval end_time; + int cost_time; + int ret = 0; + struct vframe_s *dst_vf = NULL; + int count; + struct dst_buf_t *dst_buf = NULL; + u32 cur_transform = 0; + struct src_data_para src_data; + u32 drop_count = 0; + struct output_axis dst_axis; + int min_left = 0, min_top = 0; + int max_right = 0, max_bottom = 0; + + do_gettimeofday(&begin_time); + + dev->ge2d_para.ge2d_config = &ge2d_config; + ret = video_composer_init_buffer(dev); + if (ret != 0) { + vc_print(dev->index, PRINT_ERROR, "vc: init buffer failed!\n"); + video_composer_uninit_buffer(dev); + } else { + dst_vf = get_dst_vframe_buffer(dev); + } + if (IS_ERR_OR_NULL(dst_vf)) { + vc_print(dev->index, PRINT_OTHER, "dst vf is NULL\n"); + return; + } + memset(dst_vf, 0, sizeof(struct vframe_s)); + while (1) { + if (!kfifo_get(&dev->receive_q, &received_frames)) { + vc_print(dev->index, PRINT_ERROR, + "com: get failed\n"); + return; + } + if (!kfifo_peek(&dev->receive_q, &received_frames_tmp)) + break; + drop_count++; + frames_put_file(dev, received_frames); + vc_print(dev->index, PRINT_ERROR, "com: drop frame\n"); + atomic_set(&received_frames->on_use, false); + } + + frames_info = &received_frames->frames_info; + count = frames_info->frame_count; + check_window_change(dev, received_frames->frames_info); + + dst_buf = to_dst_buf(dst_vf); + dev->ge2d_para.format = GE2D_FORMAT_S24_YUV444; + dev->ge2d_para.phy_addr[0] = dst_buf->phy_addr; + dev->ge2d_para.buffer_w = dst_buf->buf_w; + dev->ge2d_para.buffer_h = dst_buf->buf_h; + dev->ge2d_para.canvas0Addr = -1; + + if (dst_buf->dirty && !close_black) { + ret = fill_vframe_black(&dev->ge2d_para); + if (ret < 0) { + vc_print(dev->index, PRINT_ERROR, + "ge2d fill black failed\n"); + } + vc_print(dev->index, PRINT_OTHER, "fill black\n"); + dst_buf->dirty = false; + } + + for (i = 0; i < count; i++) { + vf_dev[i] = i; + vframe_info[i] = &frames_info->frame_info[i]; + } + + for (i = 0; i < count - 1; i++) { + for (j = 0; j < count - 1 - i; j++) { + zd1 = vframe_info[vf_dev[j]]->zorder; + zd2 = vframe_info[vf_dev[j + 1]]->zorder; + if (zd1 > zd2) { + tmp = vf_dev[j]; + vf_dev[j] = vf_dev[j + 1]; + vf_dev[j + 1] = tmp; + } + } + } + min_left = vframe_info[0]->dst_x; + min_top = vframe_info[0]->dst_y; + max_right = vframe_info[0]->dst_x + vframe_info[0]->dst_w; + max_bottom = vframe_info[0]->dst_y + vframe_info[0]->dst_h; + for (i = 0; i < count; i++) { + if (vframe_info[vf_dev[i]]->type == 1) { + src_data.canvas0Addr = -1; + src_data.canvas1Addr = -1; + src_data.canvas0_config[0].phy_addr = (u32)( + received_frames->phy_addr[vf_dev[i]]); + src_data.canvas0_config[0].width = + (vframe_info[vf_dev[i]]->buffer_w + + 0x1f) & ~0x1f; + src_data.canvas0_config[0].height = + vframe_info[vf_dev[i]]->buffer_h; + src_data.canvas0_config[0].block_mode = + CANVAS_BLKMODE_LINEAR; + src_data.canvas0_config[0].endian = 0; + src_data.canvas0_config[1].phy_addr = + (u32)(received_frames->phy_addr[vf_dev[i]] + + (src_data.canvas0_config[0].width) + * (src_data.canvas0_config[0].height)); + + src_data.canvas0_config[1].width = + (vframe_info[vf_dev[i]]->buffer_w + + 0x1f) & ~0x1f; + src_data.canvas0_config[1].height = + (vframe_info[vf_dev[i]]->buffer_h) / 2; + src_data.canvas0_config[1].block_mode = + CANVAS_BLKMODE_LINEAR; + src_data.canvas0_config[1].endian = 0; + + src_data.bitdepth = BITDEPTH_Y8 + | BITDEPTH_U8 + | BITDEPTH_V8; + src_data.source_type = 0; + src_data.type = VIDTYPE_PROGRESSIVE + | VIDTYPE_VIU_FIELD + | VIDTYPE_VIU_NV21; + src_data.plane_num = 2; + src_data.width = vframe_info[vf_dev[i]]->buffer_w; + src_data.height = vframe_info[vf_dev[i]]->buffer_h; + src_data.is_vframe = false; + } else { + file_vf = received_frames->file_vf[vf_dev[i]]; + file_private_data = + (struct file_private_data *)(file_vf->private_data); + scr_vf = &file_private_data->vf; + + src_data.canvas0Addr = scr_vf->canvas0Addr; + src_data.canvas1Addr = scr_vf->canvas1Addr; + src_data.canvas0_config[0] = scr_vf->canvas0_config[0]; + src_data.canvas0_config[1] = scr_vf->canvas0_config[1]; + src_data.canvas0_config[2] = scr_vf->canvas0_config[2]; + src_data.canvas1_config[0] = scr_vf->canvas1_config[0]; + src_data.canvas1_config[1] = scr_vf->canvas1_config[1]; + src_data.canvas1_config[2] = scr_vf->canvas1_config[2]; + src_data.bitdepth = scr_vf->bitdepth; + src_data.source_type = scr_vf->source_type; + src_data.type = scr_vf->type; + src_data.plane_num = scr_vf->plane_num; + src_data.width = scr_vf->width; + src_data.height = scr_vf->height; + if (scr_vf->flag & VFRAME_FLAG_VIDEO_LINEAR) + src_data.is_vframe = false; + else + src_data.is_vframe = true; + } + cur_transform = vframe_info[vf_dev[i]]->transform; + if (min_left > vframe_info[vf_dev[i]]->dst_x) + min_left = vframe_info[vf_dev[i]]->dst_x; + if (min_top > vframe_info[vf_dev[i]]->dst_y) + min_top = vframe_info[vf_dev[i]]->dst_y; + if (max_right < (vframe_info[vf_dev[i]]->dst_x + + vframe_info[vf_dev[i]]->dst_w)) + max_right = vframe_info[vf_dev[i]]->dst_x + + vframe_info[vf_dev[i]]->dst_w; + if (max_bottom < (vframe_info[vf_dev[i]]->dst_y + + vframe_info[vf_dev[i]]->dst_h)) + max_bottom = vframe_info[vf_dev[i]]->dst_y + + vframe_info[vf_dev[i]]->dst_h; + dev->ge2d_para.position_left = + vframe_info[vf_dev[i]]->dst_x; + dev->ge2d_para.position_top = + vframe_info[vf_dev[i]]->dst_y; + dev->ge2d_para.position_width = + vframe_info[vf_dev[i]]->dst_w; + dev->ge2d_para.position_height = + vframe_info[vf_dev[i]]->dst_h; + + if (cur_transform == VC_TRANSFORM_ROT_90) + dev->ge2d_para.angle = 1; + else if (cur_transform == VC_TRANSFORM_ROT_180) + dev->ge2d_para.angle = 2; + else if (cur_transform == VC_TRANSFORM_ROT_270) + dev->ge2d_para.angle = 3; + else if (cur_transform != 0) + vc_print(dev->index, PRINT_ERROR, + "not support transform=%d\n", cur_transform); + if (!full_axis) { + dst_axis = + output_axis_adjust(dev, vframe_info[vf_dev[i]], + &dev->ge2d_para); + dev->ge2d_para.position_left = dst_axis.left; + dev->ge2d_para.position_top = dst_axis.top; + dev->ge2d_para.position_width = dst_axis.width; + dev->ge2d_para.position_height = dst_axis.height; + } + + ret = ge2d_data_composer(&src_data, &dev->ge2d_para); + if (ret < 0) + vc_print(dev->index, PRINT_ERROR, + "ge2d composer failed\n"); + } + + frames_put_file(dev, received_frames); + + do_gettimeofday(&end_time); + cost_time = (1000000 * (end_time.tv_sec - begin_time.tv_sec) + + (end_time.tv_usec - begin_time.tv_usec)) / 1000; + vc_print(dev->index, PRINT_PERFORMANCE, + "ge2d cost: %d ms\n", + cost_time); + + dst_vf->flag |= + VFRAME_FLAG_VIDEO_COMPOSER + | VFRAME_FLAG_COMPOSER_DONE; + + dst_vf->bitdepth = + BITDEPTH_Y8 | BITDEPTH_U8 | BITDEPTH_V8; + + dst_vf->type = + VIDTYPE_VIU_444 + | VIDTYPE_VIU_SINGLE_PLANE + | VIDTYPE_VIU_FIELD; + + dst_vf->axis[0] = 0; + dst_vf->axis[1] = 0; + dst_vf->axis[2] = 0; + dst_vf->axis[3] = 0; + dst_vf->crop[0] = min_top; + dst_vf->crop[1] = min_left; + dst_vf->crop[2] = dst_buf->buf_h - max_bottom; + dst_vf->crop[3] = dst_buf->buf_w - max_right; + dst_vf->zorder = frames_info->disp_zorder; + dst_vf->canvas0_config[0].phy_addr = dst_buf->phy_addr; + dst_vf->canvas0Addr = -1; + dst_vf->canvas1Addr = -1; + dst_vf->plane_num = 1; + dst_vf->width = dst_buf->buf_w; + dst_vf->height = dst_buf->buf_h; + dst_vf->canvas0_config[0].width = dst_vf->width * 3; + dst_vf->canvas0_config[0].height = dst_vf->height; + dst_vf->canvas0_config[0].block_mode = 0; + dst_vf->repeat_count[dev->index] = 0; + + if (dev->last_dst_vf) + dev->last_dst_vf->repeat_count[dev->index] += drop_count; + else + dst_vf->repeat_count[dev->index] += drop_count; + dev->last_dst_vf = dst_vf; + dev->last_frames = *received_frames; + dev->fake_vf = *dev->last_dst_vf; + + if (!kfifo_put(&dev->ready_q, (const struct vframe_s *)dst_vf)) + vc_print(dev->index, PRINT_ERROR, "ready_q is full\n"); + + vc_print(dev->index, PRINT_PERFORMANCE, + "ready len=%d\n", kfifo_len(&dev->ready_q)); + + atomic_set(&received_frames->on_use, false); +} + +static void empty_ready_queue(struct composer_dev *dev) +{ + int repeat_count; + int omx_index; + bool is_composer; + int i; + struct file *file_vf; + bool is_dma_buf; + struct vframe_s *vf = NULL; + + vc_print(dev->index, PRINT_OTHER, "vc: empty ready_q len=%d\n", + kfifo_len(&dev->ready_q)); + + while (kfifo_len(&dev->ready_q) > 0) { + if (kfifo_get(&dev->ready_q, &vf)) { + if (!vf) + break; + repeat_count = vf->repeat_count[dev->index]; + omx_index = vf->omx_index; + is_composer = vf->flag & VFRAME_FLAG_COMPOSER_DONE; + file_vf = vf->file_vf; + is_dma_buf = vf->flag & VFRAME_FLAG_VIDEO_COMPOSER_DMA; + vc_print(dev->index, PRINT_OTHER, + "empty: repeat_count =%d, omx_index=%d\n", + repeat_count, omx_index); + video_timeline_increase(dev, repeat_count + 1); + if (!is_composer) { + for (i = 0; i <= repeat_count; i++) { + fput(file_vf); + dev->fput_count++; + } + } else { + videocom_vf_put(vf, dev); + } + if (is_dma_buf) { + if (!kfifo_put(&dev->dma_free_q, vf)) + vc_print(dev->index, PRINT_ERROR, + "dma_free is full!\n"); + } + } + } +} + +static void video_composer_task(struct composer_dev *dev) +{ + struct vframe_s *vf = NULL; + struct file *file_vf = NULL; + struct frame_info_t *frame_info = NULL; + struct file_private_data *file_private_data; + struct received_frames_t *received_frames = NULL; + struct frames_info_t *frames_info = NULL; + int count; + bool need_composer = false; + int ready_count = 0; + unsigned long phy_addr; + u64 time_us64; + + if (!kfifo_peek(&dev->receive_q, &received_frames)) { + vc_print(dev->index, PRINT_ERROR, "task: peek failed\n"); + return; + } + + if (IS_ERR_OR_NULL(received_frames)) { + vc_print(dev->index, PRINT_ERROR, + "task: get received_frames is NULL\n"); + return; + } + + count = received_frames->frames_info.frame_count; + time_us64 = received_frames->time_us64; + + if (count == 1) { + if (transform) + received_frames->frames_info.frame_info[0].transform = + transform; + if (((dev->index == 0) && force_composer) || + ((dev->index == 1) && force_composer_pip)) + need_composer = true; + if (received_frames->frames_info.frame_info[0].transform) { + need_composer = true; + dev->need_rotate = true; + } + } else { + need_composer = true; + } + if (!need_composer) { + frames_info = &received_frames->frames_info; + frame_info = frames_info->frame_info; + phy_addr = received_frames->phy_addr[0]; + vc_print(dev->index, PRINT_OTHER, + "task:frame_cnt=%d,z=%d,index=%d,receive_q len=%d\n", + frames_info->frame_count, + frames_info->disp_zorder, + dev->index, + kfifo_len(&dev->receive_q)); + file_vf = received_frames->file_vf[0]; + if (frame_info->type == 0) { + file_private_data = + (struct file_private_data *)(file_vf->private_data); + vf = &file_private_data->vf; + } else if (frame_info->type == 1) { + if (!kfifo_get(&dev->dma_free_q, &vf)) { + vc_print(dev->index, PRINT_ERROR, + "task: get dma_free_q failed\n"); + return; + } + memset(vf, 0, sizeof(struct vframe_s)); + } + if (!kfifo_get(&dev->receive_q, &received_frames)) { + vc_print(dev->index, PRINT_ERROR, + "task: get failed\n"); + return; + } + + vf->axis[0] = frame_info->dst_x; + vf->axis[1] = frame_info->dst_y; + vf->axis[2] = frame_info->dst_w + frame_info->dst_x - 1; + vf->axis[3] = frame_info->dst_h + frame_info->dst_y - 1; + vf->crop[0] = 0; + vf->crop[1] = 0; + vf->crop[2] = 0; + vf->crop[3] = 0; + vf->zorder = frames_info->disp_zorder; + vf->file_vf = file_vf; + //vf->zorder = 1; + vf->flag |= VFRAME_FLAG_VIDEO_COMPOSER + | VFRAME_FLAG_VIDEO_COMPOSER_BYPASS; + vf->pts_us64 = time_us64; + vf->disp_pts = 0; + + if (frame_info->type == 1) { + vf->flag |= VFRAME_FLAG_VIDEO_COMPOSER_DMA; + vf->flag |= VFRAME_FLAG_VIDEO_LINEAR; + vf->canvas0Addr = -1; + vf->canvas0_config[0].phy_addr = phy_addr; + vf->canvas0_config[0].width = (frame_info->buffer_w + + 0x1f) & ~0x1f; + vf->canvas0_config[0].height = frame_info->buffer_h; + vf->canvas1Addr = -1; + vf->canvas0_config[1].phy_addr = phy_addr + + vf->canvas0_config[0].width + * vf->canvas0_config[0].height; + vf->canvas0_config[1].width = (frame_info->buffer_w + + 0x1f) & ~0x1f; + vf->canvas0_config[1].height = frame_info->buffer_h; + vf->width = frame_info->buffer_w; + vf->height = frame_info->buffer_h; + vf->plane_num = 2; + vf->type = VIDTYPE_PROGRESSIVE + | VIDTYPE_VIU_FIELD + | VIDTYPE_VIU_NV21; + vf->bitdepth = + BITDEPTH_Y8 | BITDEPTH_U8 | BITDEPTH_V8; + vf->crop[0] = frame_info->crop_y; + vf->crop[1] = frame_info->crop_x; + vf->crop[2] = frame_info->buffer_h + - frame_info->crop_h + - frame_info->crop_y; + vf->crop[3] = frame_info->buffer_w + - frame_info->crop_w + - frame_info->crop_x; + } + vc_print(dev->index, PRINT_OTHER, + "axis: %d %d %d %d\ncrop: %d %d %d %d\n", + vf->axis[0], vf->axis[1], vf->axis[2], vf->axis[3], + vf->crop[0], vf->crop[1], vf->crop[2], vf->crop[3]); + vc_print(dev->index, PRINT_OTHER, + "vf_width: %d, vf_height: %d\n", + vf->width, vf->height); + vc_print(dev->index, PRINT_OTHER, + "=========frame info:==========\n"); + vc_print(dev->index, PRINT_OTHER, + "frame aixs x,y,w,h: %d %d %d %d\n", + frame_info->dst_x, frame_info->dst_y, + frame_info->dst_w, frame_info->dst_h); + vc_print(dev->index, PRINT_OTHER, + "frame crop t,l,b,r: %d %d %d %d\n", + frame_info->crop_y, frame_info->crop_x, + frame_info->crop_h, frame_info->crop_w); + vc_print(dev->index, PRINT_OTHER, + "frame buffer Width X Height: %d X %d\n", + frame_info->buffer_w, frame_info->buffer_h); + vc_print(dev->index, PRINT_OTHER, + "===============================\n"); + if (dev->last_file == file_vf && frame_info->type == 0) { + vf->repeat_count[dev->index]++; + vc_print(dev->index, PRINT_OTHER, + "repeat =%d, omx_index=%d\n", + vf->repeat_count[dev->index], + vf->omx_index); + } else { + dev->last_file = file_vf; + vf->repeat_count[dev->index] = 0; + if (!kfifo_put(&dev->ready_q, + (const struct vframe_s *)vf)) + vc_print(dev->index, PRINT_ERROR, + "by_pass ready_q is full\n"); + ready_count = kfifo_len(&dev->ready_q); + if (ready_count > 1) + vc_print(dev->index, PRINT_ERROR, + "ready len=%d\n", ready_count); + vc_print(dev->index, PRINT_OTHER, + "ready len=%d\n", kfifo_len(&dev->ready_q)); + } + dev->fake_vf = *vf; + atomic_set(&received_frames->on_use, false); + } else { + vframe_composer(dev); + dev->last_file = NULL; + } +} + +static int video_composer_thread(void *data) +{ + struct composer_dev *dev = data; + + vc_print(dev->index, PRINT_OTHER, "thread: started\n"); + init_waitqueue_head(&dev->wq); + + dev->thread_stopped = 0; + while (1) { + if (kthread_should_stop()) + break; + + if (kfifo_len(&dev->receive_q) == 0) { + wait_event_interruptible_timeout( + dev->wq, + ((kfifo_len(&dev->receive_q) > 0) && + dev->enable_composer) || + dev->need_free_buffer || + dev->need_unint_receive_q || + dev->need_empty_ready, + msecs_to_jiffies(5000)); + } + + if (dev->need_empty_ready) { + vc_print(dev->index, PRINT_OTHER, + "empty_ready_queue\n"); + dev->need_empty_ready = false; + empty_ready_queue(dev); + dev->fake_vf.flag |= VFRAME_FLAG_FAKE_FRAME; + if (!kfifo_put(&dev->ready_q, + (const struct vframe_s *)&dev->fake_vf)) + vc_print(dev->index, PRINT_ERROR, + "by_pass ready_q is full\n"); + } + + if (dev->need_free_buffer) { + dev->need_free_buffer = false; + video_composer_uninit_buffer(dev); + vc_print(dev->index, PRINT_OTHER, + "%s video composer release!\n", __func__); + continue; + } + if (kthread_should_stop()) + break; + + if (!dev->enable_composer && dev->need_unint_receive_q) { + receive_q_uninit(dev); + dev->need_unint_receive_q = false; + ready_q_uninit(dev); + complete(&dev->task_done); + continue; + } + if (kfifo_len(&dev->receive_q) > 0 && dev->enable_composer) + video_composer_task(dev); + } + dev->thread_stopped = 1; + vc_print(dev->index, PRINT_OTHER, "thread: exit\n"); + return 0; +} + +static int video_composer_open(struct inode *inode, struct file *file) +{ + struct composer_dev *dev; + struct video_composer_port_s *port = &ports[iminor(inode)]; + int i; + struct sched_param param = {.sched_priority = 2}; + + pr_err("video_composer_open iminor(inode) =%d\n", iminor(inode)); + if (iminor(inode) >= video_composer_instance_num) + return -ENODEV; + + mutex_lock(&video_composer_mutex); + + if (port->open_count > 0) { + mutex_unlock(&video_composer_mutex); + pr_err("video_composer: instance %d is aleady opened", + port->index); + return -EBUSY; + } + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (IS_ERR_OR_NULL(dev)) { + mutex_unlock(&video_composer_mutex); + pr_err("video_composer: instance %d alloc dev failed", + port->index); + return -ENOMEM; + } + dev->ge2d_para.context = NULL; + + dev->ge2d_para.count = 0; + dev->ge2d_para.canvas_dst[0] = -1; + dev->ge2d_para.canvas_dst[1] = -1; + dev->ge2d_para.canvas_dst[2] = -1; + dev->ge2d_para.canvas_scr[0] = -1; + dev->ge2d_para.canvas_scr[1] = -1; + dev->ge2d_para.canvas_scr[2] = -1; + dev->ge2d_para.plane_num = 1; + + dev->buffer_status = UNINITIAL; + + dev->port = port; + file->private_data = dev; + dev->index = port->index; + dev->need_free_buffer = false; + dev->last_frames.frames_info.frame_count = 0; + dev->is_sideband = false; + dev->need_empty_ready = false; + + memcpy(dev->vf_provider_name, port->name, + strlen(port->name) + 1); + + port->open_count++; + do_gettimeofday(&dev->start_time); + + mutex_unlock(&video_composer_mutex); + dev->kthread = kthread_create(video_composer_thread, + dev, dev->port->name); + if (IS_ERR(dev->kthread)) { + pr_err("video_composer_thread creat failed\n"); + return -ENOMEM; + } + + if (sched_setscheduler(dev->kthread, SCHED_FIFO, ¶m)) + pr_err("vc:Could not set realtime priority.\n"); + + wake_up_process(dev->kthread); + //mutex_init(&dev->mutex_input); + + for (i = 0; i < FRAMES_INFO_POOL_SIZE; i++) + dev->received_frames[i].index = i; + + video_timeline_create(dev); + + return 0; +} + +static int video_composer_release(struct inode *inode, struct file *file) +{ + struct composer_dev *dev = file->private_data; + struct video_composer_port_s *port = dev->port; + int i = 0; + + if (iminor(inode) >= video_composer_instance_num) + return -ENODEV; + + if (dev->kthread) { + kthread_stop(dev->kthread); + wake_up_interruptible(&dev->wq); + dev->kthread = NULL; + } + + mutex_lock(&video_composer_mutex); + + port->open_count--; + + mutex_unlock(&video_composer_mutex); + while (1) { + i++; + if (dev->thread_stopped) + break; + usleep_range(9000, 10000); + if (i > WAIT_THREAD_STOPPED_TIMEOUT) { + pr_err("wait thread timeout\n"); + break; + } + } + kfree(dev); + return 0; +} + +static void set_frames_info(struct composer_dev *dev, + struct frames_info_t *frames_info) +{ + u32 fence_fd; + int i = 0; + int j = 0; + struct file *file_vf = NULL; + struct vframe_s *vf = NULL; + struct file_private_data *file_private_data; + struct timeval time1; + struct timeval time2; + u64 time_us64; + u64 time_vsync; + int axis[4]; + int crop[4]; + int ready_len = 0; + bool current_is_sideband = false; + + for (j = 0; j < frames_info->frame_count; j++) { + if (frames_info->frame_info[j].type == 2) { + vc_print(dev->index, PRINT_OTHER, + "sideband:i=%d,z=%d\n", + i, + frames_info->disp_zorder); + if (dev->index == 0) + set_video_path_select("amvideo", 0); + else if (dev->index == 1) + set_video_path_select("pipvideo", 1); + ready_len = kfifo_len(&dev->ready_q); + vc_print(dev->index, PRINT_OTHER, + "sideband: ready_len =%d\n", + ready_len); + frames_info->frame_info[j].composer_fen_fd = -1; + axis[0] = frames_info->frame_info[j].dst_x; + axis[1] = frames_info->frame_info[j].dst_y; + axis[2] = frames_info->frame_info[j].dst_w + + axis[0] - 1; + axis[3] = frames_info->frame_info[j].dst_h + + axis[1] - 1; + crop[0] = frames_info->frame_info[j].crop_x; + crop[1] = frames_info->frame_info[j].crop_y; + crop[2] = frames_info->frame_info[j].crop_w; + crop[3] = frames_info->frame_info[j].crop_h; + set_video_window_ext(dev->index, axis); + set_video_crop_ext(dev->index, crop); + set_video_zorder_ext(dev->index, + frames_info->disp_zorder); + if (!dev->is_sideband && dev->received_count > 0) { + vc_print(dev->index, PRINT_OTHER, + "non change to sideband:wake_up\n"); + dev->need_empty_ready = true; + wake_up_interruptible(&dev->wq); + } + dev->is_sideband = true; + current_is_sideband = true; + } + } + if (current_is_sideband) { + if (frames_info->frame_count > 1) + vc_print(dev->index, PRINT_ERROR, + "sideband count not 1\n"); + return; + } + + if ((dev->is_sideband && !current_is_sideband) || + (dev->received_count == 0)) { + if (dev->is_sideband && !current_is_sideband) + vc_print(dev->index, PRINT_OTHER, + "sideband to non\n"); + dev->is_sideband = false; + if (dev->index == 0) + set_video_path_select("video_render.0", 0); + else if (dev->index == 1) + set_video_path_select("video_render.1", 1); + } + dev->is_sideband = false; + + time1 = dev->start_time; + do_gettimeofday(&time2); + time_us64 = 1000000 * (time2.tv_sec - time1.tv_sec) + + time2.tv_usec - time1.tv_usec; + + time_vsync = 1000000 * (time2.tv_sec - vsync_time.tv_sec) + + time2.tv_usec - vsync_time.tv_usec; + + if ((frames_info->frame_count > MXA_LAYER_COUNT) || + frames_info->frame_count < 1) { + vc_print(dev->index, PRINT_ERROR, + "vc: layer count %d\n", frames_info->frame_count); + return; + } + + while (1) { + j = 0; + for (i = 0; i < FRAMES_INFO_POOL_SIZE; i++) { + if (!atomic_read(&dev->received_frames[i].on_use)) + break; + } + if (i == FRAMES_INFO_POOL_SIZE) { + j++; + if (j > WAIT_READY_Q_TIMEOUT) { + pr_err("receive_q is full, wait timeout!\n"); + return; + } + usleep_range(1000 * receive_wait, + 1000 * (receive_wait + 1)); + pr_err("receive_q is full!!! need wait =%d\n", j); + continue; + } else { + break; + } + } + + fence_fd = video_timeline_create_fence(dev); + dev->received_frames[i].frames_info = *frames_info; + dev->received_frames[i].frames_num = dev->received_count; + dev->received_frames[i].time_us64 = time_us64; + + vc_print(dev->index, PRINT_PERFORMANCE, + "len =%d,frame_count=%d,i=%d,z=%d,time_us64=%lld,fd=%d, time_vsync=%lld\n", + kfifo_len(&dev->receive_q), + frames_info->frame_count, + i, + frames_info->disp_zorder, + time_us64, + fence_fd, + time_vsync); + + for (j = 0; j < frames_info->frame_count; j++) { + frames_info->frame_info[j].composer_fen_fd = fence_fd; + file_vf = fget(frames_info->frame_info[j].fd); + dev->received_frames[i].file_vf[j] = file_vf; + if (frames_info->frame_info[j].type == 0) { + file_private_data = + (struct file_private_data *)(file_vf->private_data); + vf = &file_private_data->vf; + vc_print(dev->index, PRINT_OTHER, + "received_cnt=%lld,i=%d,z=%d,omx_index=%d\n", + dev->received_count + 1, + i, + frames_info->frame_info[j].zorder, + vf->omx_index); + } else if (frames_info->frame_info[j].type == 1) { + vc_print(dev->index, PRINT_OTHER, + "received_cnt=%lld,i=%d,z=%d,DMA_fd=%d\n", + dev->received_count + 1, + i, + frames_info->frame_info[j].zorder, + frames_info->frame_info[j].fd); + dev->received_frames[i].phy_addr[j] = + get_dma_phy_addr(frames_info->frame_info[j].fd); + } else { + vc_print(dev->index, PRINT_ERROR, + "unsupport type=%d\n", + frames_info->frame_info[j].type); + } + } + atomic_set(&dev->received_frames[i].on_use, true); + + dev->received_count++; + if (!kfifo_put(&dev->receive_q, &dev->received_frames[i])) + vc_print(dev->index, PRINT_ERROR, "put ready fail\n"); + wake_up_interruptible(&dev->wq); + + //vc_print(dev->index, PRINT_PERFORMANCE, "set_frames_info_out\n"); +} + +/* ----------------------------------------------------------------- + * provider opeations + * ----------------------------------------------------------------- + */ +static struct vframe_s *vc_vf_peek(void *op_arg) +{ + struct composer_dev *dev = (struct composer_dev *)op_arg; + struct vframe_s *vf = NULL; + struct timeval time1; + struct timeval time2; + u64 time_vsync; + int interval_time; + + time1 = dev->start_time; + time2 = vsync_time; + if (kfifo_peek(&dev->ready_q, &vf)) { + if (vf && get_count[dev->index] > 0) { + time_vsync = 1000000 * (time2.tv_sec - time1.tv_sec) + + time2.tv_usec - time1.tv_usec; + interval_time = abs(time_vsync - vf->pts_us64); + vc_print(dev->index, PRINT_PERFORMANCE, + "time_vsync=%lld, vf->pts_us64=%lld\n", + time_vsync, vf->pts_us64); + if (interval_time < margin_time) { + vc_print(dev->index, PRINT_ERROR, + "display next vsync\n"); + return NULL; + } + } + return vf; + } else { + return NULL; + } +} + +static struct vframe_s *vc_vf_get(void *op_arg) +{ + struct composer_dev *dev = (struct composer_dev *)op_arg; + struct vframe_s *vf = NULL; + + if (kfifo_get(&dev->ready_q, &vf)) { + if (vf) { + if (!kfifo_put(&dev->display_q, vf)) + vc_print(dev->index, PRINT_ERROR, + "display_q is full!\n"); + get_count[dev->index]++; + } + vc_print(dev->index, PRINT_OTHER, + "get: omx_index=%d\n", + vf->omx_index); + + return vf; + } else { + return NULL; + } +} + +static void vc_vf_put(struct vframe_s *vf, void *op_arg) +{ + struct composer_dev *dev = (struct composer_dev *)op_arg; + int repeat_count; + int omx_index; + bool rendered; + bool is_composer; + int i; + struct file *file_vf; + bool is_dma_buf; + + if (!vf) + return; + + repeat_count = vf->repeat_count[dev->index]; + omx_index = vf->omx_index; + rendered = vf->rendered; + is_composer = vf->flag & VFRAME_FLAG_COMPOSER_DONE; + file_vf = vf->file_vf; + is_dma_buf = vf->flag & VFRAME_FLAG_VIDEO_COMPOSER_DMA; + + if (vf->flag & VFRAME_FLAG_FAKE_FRAME) { + vc_print(dev->index, PRINT_OTHER, + "put: fake frame\n"); + return; + } + + vc_print(dev->index, PRINT_OTHER, + "put: repeat_count =%d, omx_index=%d\n", + repeat_count, omx_index); + + vf_pop_display_q(dev, vf); + + if (rendered) { + video_timeline_increase(dev, repeat_count + + 1 + dev->drop_frame_count); + dev->drop_frame_count = 0; + } else { + dev->drop_frame_count += repeat_count + 1; + vc_print(dev->index, PRINT_ERROR, + "put: drop repeat_count=%d\n", repeat_count); + } + + if (!is_composer) { + for (i = 0; i <= repeat_count; i++) { + fput(file_vf); + dev->fput_count++; + } + } else { + videocom_vf_put(vf, dev); + } + if (is_dma_buf) { + if (!kfifo_put(&dev->dma_free_q, vf)) + vc_print(dev->index, PRINT_ERROR, + "dma_free is full!\n"); + } +} + +static int vc_event_cb(int type, void *data, void *private_data) +{ + if (type & VFRAME_EVENT_RECEIVER_PUT) + ; + else if (type & VFRAME_EVENT_RECEIVER_GET) + ; + else if (type & VFRAME_EVENT_RECEIVER_FRAME_WAIT) + ; + return 0; +} + +static int vc_vf_states(struct vframe_states *states, void *op_arg) +{ + struct composer_dev *dev = (struct composer_dev *)op_arg; + + states->vf_pool_size = COMPOSER_READY_POOL_SIZE; + states->buf_recycle_num = 0; + states->buf_free_num = COMPOSER_READY_POOL_SIZE + - kfifo_len(&dev->ready_q); + states->buf_avail_num = kfifo_len(&dev->ready_q); + return 0; +} + +static const struct vframe_operations_s vc_vf_provider = { + .peek = vc_vf_peek, + .get = vc_vf_get, + .put = vc_vf_put, + .event_cb = vc_event_cb, + .vf_states = vc_vf_states, +}; + +static void disable_video_layer(struct composer_dev *dev, int val) +{ + pr_info("dev->index =%d, val=%d", dev->index, val); + if (dev->index == 0) + _video_set_disable(val); + else if (dev->index == 1) + _videopip_set_disable(val); +} + +static int video_composer_creat_path(struct composer_dev *dev) +{ + if (dev->index == 0) + snprintf(dev->vfm_map_chain, VCOM_MAP_NAME_SIZE, + "%s %s", dev->vf_provider_name, + "video_render.0"); + else if (dev->index == 1) + snprintf(dev->vfm_map_chain, VCOM_MAP_NAME_SIZE, + "%s %s", dev->vf_provider_name, + "video_render.1"); + + snprintf(dev->vfm_map_id, VCOM_MAP_NAME_SIZE, + "vcom-map-%d", dev->index); + + if (vfm_map_add(dev->vfm_map_id, + dev->vfm_map_chain) < 0) { + pr_err("vcom pipeline map creation failed %s.\n", + dev->vfm_map_id); + dev->vfm_map_id[0] = 0; + return -ENOMEM; + } + + vf_provider_init(&dev->vc_vf_prov, dev->vf_provider_name, + &vc_vf_provider, dev); + + vf_reg_provider(&dev->vc_vf_prov); + + vf_notify_receiver(dev->vf_provider_name, + VFRAME_EVENT_PROVIDER_START, NULL); + return 0; +} + +static int video_composer_release_path(struct composer_dev *dev) +{ + vf_unreg_provider(&dev->vc_vf_prov); + + if (dev->vfm_map_id[0]) { + vfm_map_remove(dev->vfm_map_id); + dev->vfm_map_id[0] = 0; + } + return 0; +} + +static int video_composer_init(struct composer_dev *dev) +{ + int ret; + int i; + + if (!dev) + return -1; + INIT_KFIFO(dev->ready_q); + INIT_KFIFO(dev->receive_q); + INIT_KFIFO(dev->free_q); + INIT_KFIFO(dev->display_q); + INIT_KFIFO(dev->dma_free_q); + kfifo_reset(&dev->ready_q); + kfifo_reset(&dev->receive_q); + kfifo_reset(&dev->free_q); + kfifo_reset(&dev->display_q); + kfifo_reset(&dev->dma_free_q); + + for (i = 0; i < DMA_BUF_COUNT; i++) + kfifo_put(&dev->dma_free_q, &dev->dma_vf[i]); + + dev->received_count = 0; + dev->fence_creat_count = 0; + dev->fence_release_count = 0; + dev->fput_count = 0; + dev->last_dst_vf = NULL; + dev->drop_frame_count = 0; + dev->is_sideband = false; + dev->need_empty_ready = false; + init_completion(&dev->task_done); + + disable_video_layer(dev, 2); + video_set_global_output(dev->index, 1); + + ret = video_composer_creat_path(dev); + if (dev->index == 0) + set_video_path_select("video_render.0", 0); + else if (dev->index == 1) + set_video_path_select("video_render.1", 1); + + return ret; +} + +static int video_composer_uninit(struct composer_dev *dev) +{ + int ret; + int timeout = 0; + + disable_video_layer(dev, 1); + video_set_global_output(dev->index, 0); + ret = video_composer_release_path(dev); + + dev->need_unint_receive_q = true; + + /* free buffer */ + dev->need_free_buffer = true; + wake_up_interruptible(&dev->wq); + + timeout = wait_for_completion_timeout(&dev->task_done, + msecs_to_jiffies(100)); + if (!timeout) + vc_print(dev->index, PRINT_ERROR, "unreg:wait timeout\n"); + + display_q_uninit(dev); + + if (dev->fence_creat_count != dev->fput_count) { + vc_print(dev->index, PRINT_ERROR, + "uninit: fence_r=%lld, fence_c=%lld\n", + dev->fence_release_count, + dev->fence_creat_count); + vc_print(dev->index, PRINT_ERROR, + "uninit: received=%lld, fput=%lld, drop=%d\n", + dev->received_count, + dev->fput_count, + dev->drop_frame_count); + } + video_timeline_increase(dev, + dev->fence_creat_count + - dev->fence_release_count); + dev->is_sideband = false; + dev->need_empty_ready = false; + + return ret; +} + +int video_composer_set_enable(struct composer_dev *dev, u32 val) +{ + int ret = 0; + + if (val > VIDEO_COMPOSER_ENABLE_NORMAL) + return -EINVAL; + + vc_print(dev->index, PRINT_ERROR, + "vc: set enable index=%d, val=%d\n", + dev->index, val); + + if (dev->enable_composer == val) { + pr_err("vc: set_enable repeat set dev->index =%d,val=%d\n", + dev->index, val); + return ret; + } + dev->enable_composer = val; + wake_up_interruptible(&dev->wq); + + if (val == VIDEO_COMPOSER_ENABLE_NORMAL) + ret = video_composer_init(dev); + else if (val == VIDEO_COMPOSER_ENABLE_NONE) + ret = video_composer_uninit(dev); + + if (ret != 0) + pr_err("vc: set failed\n"); + return ret; +} + +static long video_composer_ioctl(struct file *file, + unsigned int cmd, ulong arg) +{ + long ret = 0; + void __user *argp = (void __user *)arg; + u32 val; + struct composer_dev *dev = (struct composer_dev *)file->private_data; + struct frames_info_t frames_info; + + switch (cmd) { + case VIDEO_COMPOSER_IOCTL_SET_FRAMES: + if (copy_from_user(&frames_info, argp, + sizeof(frames_info)) == 0) { + set_frames_info(dev, &frames_info); + ret = copy_to_user(argp, &frames_info, + sizeof(struct frames_info_t)); + + } else { + ret = -EFAULT; + } + break; + case VIDEO_COMPOSER_IOCTL_SET_ENABLE: + if (copy_from_user(&val, argp, sizeof(u32)) == 0) + ret = video_composer_set_enable(dev, val); + else + ret = -EFAULT; + break; + case VIDEO_COMPOSER_IOCTL_SET_DISABLE: + break; + default: + return -EINVAL; + } + return ret; +} + +#ifdef CONFIG_COMPAT +static long video_composer_compat_ioctl(struct file *file, unsigned int cmd, + ulong arg) +{ + long ret = 0; + + ret = video_composer_ioctl(file, cmd, (ulong)compat_ptr(arg)); + return ret; +} +#endif + +static const struct file_operations video_composer_fops = { + .owner = THIS_MODULE, + .open = video_composer_open, + .release = video_composer_release, + .unlocked_ioctl = video_composer_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = video_composer_compat_ioctl, +#endif + .poll = NULL, +}; + +static int video_composer_probe(struct platform_device *pdev) +{ + int ret = 0; + int i = 0; + u32 layer_cap = 0; + struct video_composer_port_s *st; + + layer_cap = video_get_layer_capability(); + video_composer_instance_num = 0; + if (layer_cap & LAYER0_SCALER) + video_composer_instance_num++; + if (layer_cap & LAYER1_SCALER) + video_composer_instance_num++; + + ret = class_register(&video_composer_class); + if (ret < 0) + return ret; + + ret = register_chrdev(VIDEO_COMPOSER_MAJOR, + "video_composer", &video_composer_fops); + if (ret < 0) { + pr_err("Can't allocate major for video_composer device\n"); + goto error1; + } + + video_composer_dev_class = + class_create(THIS_MODULE, VIDEO_COMPOSER_DEVICE_NAME); + + for (st = &ports[0], i = 0; + i < video_composer_instance_num; i++, st++) { + pr_err("video_composer_probe_3.1:ports[i].name=%s, i=%d\n", + ports[i].name, i); + st->class_dev = device_create(video_composer_dev_class, NULL, + MKDEV(VIDEO_COMPOSER_MAJOR, i), NULL, + ports[i].name); + } + pr_err("video_composer_probe num=%d\n", video_composer_instance_num); + return ret; + +error1: + pr_err("video_composer_probe error\n"); + unregister_chrdev(VIDEO_COMPOSER_MAJOR, "video_composer"); + class_unregister(&video_composer_class); + return ret; +} + +static const struct of_device_id amlogic_video_composer_dt_match[] = { + { + .compatible = "amlogic, video_composer", + }, + {}, +}; + +static int video_composer_remove(struct platform_device *pdev) + +{ + int i; + struct video_composer_port_s *st; + + for (st = &ports[0], i = 0; + i < video_composer_instance_num; i++, st++) + device_destroy(video_composer_dev_class, + MKDEV(VIDEO_COMPOSER_MAJOR, i)); + + class_destroy(video_composer_dev_class); + + unregister_chrdev(VIDEO_COMPOSER_MAJOR, VIDEO_COMPOSER_DEVICE_NAME); + + class_unregister(&video_composer_class); + return 0; +}; + +static struct platform_driver video_composer_driver = { + .probe = video_composer_probe, + .remove = video_composer_remove, + .driver = { + .owner = THIS_MODULE, + .name = "video_composer", + .of_match_table = amlogic_video_composer_dt_match, + } +}; + +static int __init video_composer_module_init(void) +{ + pr_err("video_composer_module_init_1\n"); + + if (platform_driver_register(&video_composer_driver)) { + pr_err("failed to register video_composer module\n"); + return -ENODEV; + } + return 0; +} + +static void __exit video_composer_module_exit(void) +{ + platform_driver_unregister(&video_composer_driver); +} + +MODULE_DESCRIPTION("Video Technology Magazine video composer Capture Boad"); +MODULE_AUTHOR("Amlogic, Jintao Xu"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(VIDEO_COMPOSER_VERSION); + +module_init(video_composer_module_init); +module_exit(video_composer_module_exit); diff --git a/drivers/amlogic/media/video_processor/video_composer/video_composer.h b/drivers/amlogic/media/video_processor/video_composer/video_composer.h new file mode 100644 index 000000000000..cbc5136feed6 --- /dev/null +++ b/drivers/amlogic/media/video_processor/video_composer/video_composer.h @@ -0,0 +1,211 @@ +/* + * drivers/amlogic/media/video_processor/video_composer/video_composer.h + * + * Copyright (C) 2017 Amlogic, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +#ifndef VIDEO_COMPOSER_H +#define VIDEO_COMPOSER_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include "vfq.h" +#include +#include "vframe_ge2d_composer.h" + +#define MXA_LAYER_COUNT 9 +#define COMPOSER_READY_POOL_SIZE 32 +#define FRAMES_INFO_POOL_SIZE 32 + +/* disable video_composer mode */ +#define VIDEO_COMPOSER_ENABLE_NONE 0 +#define VIDEO_COMPOSER_ENABLE_NORMAL 1 +#define BUFFER_LEN 4 +#define DMA_BUF_COUNT 4 + +#define VCOM_MAP_NAME_SIZE 90 +#define VCOM_PROVIDER_NAME_SIZE 32 + +enum vc_transform_t { + /* flip source image horizontally */ + VC_TRANSFORM_FLIP_H = 1, + /* flip source image vertically */ + VC_TRANSFORM_FLIP_V = 2, + /* rotate source image 90 degrees clock-wise */ + VC_TRANSFORM_ROT_90 = 4, + /* rotate source image 180 degrees */ + VC_TRANSFORM_ROT_180 = 3, + /* rotate source image 270 degrees clock-wise */ + VC_TRANSFORM_ROT_270 = 7, + /* flip source image horizontally, the rotate 90 degrees clock-wise */ + VC_TRANSFORM_FLIP_H_ROT_90 = VC_TRANSFORM_FLIP_H | VC_TRANSFORM_ROT_90, + /* flip source image vertically, the rotate 90 degrees clock-wise */ + VC_TRANSFORM_FLIP_V_ROT_90 = VC_TRANSFORM_FLIP_V | VC_TRANSFORM_ROT_90, +}; + +struct frame_info_t { + u32 fd; + u32 composer_fen_fd; + u32 disp_fen_fd; + u32 buffer_w; + u32 buffer_h; + u32 dst_x; + u32 dst_y; + u32 dst_w; + u32 dst_h; + u32 crop_x; + u32 crop_y; + u32 crop_w; + u32 crop_h; + u32 zorder; + u32 transform; + u32 type; + u32 reserved[4]; +}; + +struct frames_info_t { + u32 frame_count; + struct frame_info_t frame_info[MXA_LAYER_COUNT]; + u32 layer_index; + u32 disp_zorder; + u32 reserved[4]; +}; + +enum com_buffer_status { + UNINITIAL = 0, + INIT_SUCCESS, + INIT_ERROR, +}; + +struct video_composer_port_s { + const char *name; + u32 index; + u32 open_count; + struct device *class_dev; +}; + +struct videocom_frame_s { + struct vframe_s frame; + int index; +}; + +struct vidc_buf_status { + int index; + int dirty; +}; + +struct dst_buf_t { + int index; + struct vframe_s frame; + bool dirty; + u32 phy_addr; + u32 buf_w; + u32 buf_h; + u32 buf_size; +}; + +struct output_axis { + int left; + int top; + int width; + int height; +}; + +struct received_frames_t { + int index; + atomic_t on_use; + struct frames_info_t frames_info; + unsigned long long frames_num; + struct file *file_vf[MXA_LAYER_COUNT]; + unsigned long phy_addr[MXA_LAYER_COUNT]; + u64 time_us64; +}; + +struct composer_dev { + u32 index; + struct video_composer_port_s *port; + u32 enable_composer; + DECLARE_KFIFO(ready_q, struct vframe_s *, COMPOSER_READY_POOL_SIZE); + DECLARE_KFIFO(receive_q, struct received_frames_t *, + FRAMES_INFO_POOL_SIZE); + DECLARE_KFIFO(free_q, struct vframe_s *, BUFFER_LEN); + DECLARE_KFIFO(display_q, struct vframe_s *, COMPOSER_READY_POOL_SIZE); + DECLARE_KFIFO(dma_free_q, struct vframe_s *, BUFFER_LEN); + char vf_provider_name[VCOM_PROVIDER_NAME_SIZE]; + char vfm_map_id[VCOM_MAP_NAME_SIZE]; + char vfm_map_chain[VCOM_MAP_NAME_SIZE]; + struct vframe_provider_s vc_vf_prov; + void *video_timeline; + u32 cur_streamline_val; + struct file *last_file; + enum com_buffer_status buffer_status; + struct ge2d_composer_para ge2d_para; + struct task_struct *kthread; + struct received_frames_t received_frames[FRAMES_INFO_POOL_SIZE]; + unsigned long long received_count; + unsigned long long fence_creat_count; + unsigned long long fence_release_count; + unsigned long long fput_count; + bool need_free_buffer; + //struct mutex mutex_input; + wait_queue_head_t wq; + bool thread_stopped; + struct vframe_s *last_dst_vf; + bool need_unint_receive_q; + struct completion task_done; + struct dst_buf_t dst_buf[BUFFER_LEN]; + struct vframe_s dma_vf[DMA_BUF_COUNT]; + u32 drop_frame_count; + struct received_frames_t last_frames; + struct timeval start_time; + u32 vinfo_w; + u32 vinfo_h; + u32 composer_buf_w; + u32 composer_buf_h; + bool need_rotate; + bool is_sideband; + bool need_empty_ready; + struct vframe_s fake_vf; +}; + +#define VIDEO_COMPOSER_IOC_MAGIC 'V' +#define VIDEO_COMPOSER_IOCTL_SET_FRAMES \ + _IOW(VIDEO_COMPOSER_IOC_MAGIC, 0x00, struct frames_info_t) +#define VIDEO_COMPOSER_IOCTL_SET_ENABLE \ + _IOW(VIDEO_COMPOSER_IOC_MAGIC, 0x01, int) +#define VIDEO_COMPOSER_IOCTL_SET_DISABLE \ + _IOW(VIDEO_COMPOSER_IOC_MAGIC, 0x02, int) + +#endif /* VIDEO_COMPOSER_H */ diff --git a/drivers/amlogic/media/video_sink/Makefile b/drivers/amlogic/media/video_sink/Makefile index 3ac0996d5ed1..e83c7eade799 100644 --- a/drivers/amlogic/media/video_sink/Makefile +++ b/drivers/amlogic/media/video_sink/Makefile @@ -1,2 +1,2 @@ obj-y += amvideo.o -amvideo-objs += video.o video_keeper.o vpp.o video_hw.o +amvideo-objs += video.o video_keeper.o vpp.o video_hw.o video_receiver.o diff --git a/drivers/amlogic/media/video_sink/video.c b/drivers/amlogic/media/video_sink/video.c index e425526b2930..e11a0de72f0c 100644 --- a/drivers/amlogic/media/video_sink/video.c +++ b/drivers/amlogic/media/video_sink/video.c @@ -93,6 +93,8 @@ MODULE_AMLOG(LOG_LEVEL_ERROR, 0, LOG_DEFAULT_LEVEL_DESC, LOG_MASK_DESC); #endif #include +#include "video_receiver.h" + static int get_count; static int get_count_pip; @@ -284,6 +286,8 @@ static int vpts_chase_pts_diff; static int step_enable; static int step_flag; +struct video_recv_s *gvideo_recv[2] = {NULL, NULL}; + /*seek values on.video_define.h*/ static int debug_flag; int get_video_debug_flags(void) @@ -680,7 +684,7 @@ static u32 blackout; #else static u32 blackout = 1; #endif -static u32 force_blackout; +u32 force_blackout; static u32 blackout_pip; /* disable video */ @@ -894,7 +898,7 @@ static inline struct vframe_s *pip_vf_get(void) if (vf) { get_count_pip++; /* video_notify_flag |= VIDEO_NOTIFY_PROVIDER_GET; */ - atomic_set(&vf->use_cnt, 1); + atomic_set(&vf->use_cnt_pip, 1); } return vf; @@ -920,7 +924,7 @@ static inline void pip_vf_put(struct vframe_s *vf) if (pip_loop) return; - if (vfp && vf && atomic_dec_and_test(&vf->use_cnt)) { + if (vfp && vf && atomic_dec_and_test(&vf->use_cnt_pip)) { vf_put(vf, RECEIVERPIP_NAME); #ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION if ((glayer_info[0].display_path_id @@ -1055,7 +1059,9 @@ static inline void video_vf_put(struct vframe_s *vf) if (vf == &hist_test_vf) return; - if (vfp && vf && atomic_dec_and_test(&vf->use_cnt)) { + if (!vfp || !vf) + return; + if (atomic_dec_and_test(&vf->use_cnt)) { vf_put(vf, RECEIVER_NAME); #ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION if (is_dolby_vision_enable()) @@ -1881,6 +1887,10 @@ static inline bool vpts_expire(struct vframe_s *cur_vf, if (next_vf->flag & VFRAME_FLAG_GAME_MODE) return true; + /* FIXME: remove it */ + if (next_vf->flag & VFRAME_FLAG_VIDEO_COMPOSER) + return true; + if (step_enable) { if (step_flag) return false; @@ -2379,7 +2389,6 @@ static int dvel_swap_frame(struct vframe_s *vf) /* check if el available first */ if (!dvel_status) { - //safe_switch_videolayer(1, true, true); dvel_changed = true; dvel_size = new_dvel_w; need_disable_vd2 = false; @@ -2392,7 +2401,6 @@ static int dvel_swap_frame(struct vframe_s *vf) layer_info); dvel_status = true; } else if (dvel_status) { - //safe_switch_videolayer(1, false, true); dvel_changed = true; dvel_status = false; dvel_size = 0; @@ -2752,10 +2760,160 @@ bool black_threshold_check(u8 id) return ret; } +static void _set_video_crop( + struct disp_info_s *layer, int *p) +{ + int last_l, last_r, last_t, last_b; + int new_l, new_r, new_t, new_b; + + if (!layer) + return; + + last_t = layer->crop_top; + last_l = layer->crop_left; + last_b = layer->crop_bottom; + last_r = layer->crop_right; + + layer->crop_top = p[0]; + layer->crop_left = p[1]; + layer->crop_bottom = p[2]; + layer->crop_right = p[3]; + + new_t = layer->crop_top; + new_l = layer->crop_left; + new_b = layer->crop_bottom; + new_r = layer->crop_right; + if ((new_t != last_t) || (new_l != last_l) || + (new_b != last_b) || (new_r != last_r)) { + if (layer->layer_id == 0) + vd_layer[0].property_changed = true; + else if (layer->layer_id == 1) + vd_layer[1].property_changed = true; + } +} + +static void _set_video_window( + struct disp_info_s *layer, int *p) +{ + int w, h; + int *parsed = p; + int last_x, last_y, last_w, last_h; + int new_x, new_y, new_w, new_h; +#ifdef TV_REVERSE + int temp, temp1; + const struct vinfo_s *info = get_current_vinfo(); +#endif + + if (!layer) + return; + +#ifdef TV_REVERSE + if (reverse) { + temp = parsed[0]; + temp1 = parsed[1]; + parsed[0] = info->width - parsed[2] - 1; + parsed[1] = info->height - parsed[3] - 1; + parsed[2] = info->width - temp - 1; + parsed[3] = info->height - temp1 - 1; + } +#endif + + last_x = layer->layer_left; + last_y = layer->layer_top; + last_w = layer->layer_width; + last_h = layer->layer_height; + + if (parsed[0] < 0 && parsed[2] < 2) { + parsed[2] = 2; + parsed[0] = 0; + } + if (parsed[1] < 0 && parsed[3] < 2) { + parsed[3] = 2; + parsed[1] = 0; + } + w = parsed[2] - parsed[0] + 1; + h = parsed[3] - parsed[1] + 1; + +#ifdef CONFIG_AMLOGIC_POST_PROCESS_MANAGER_PPSCALER + if (video_scaler_mode) { + if ((w == 1) && (h == 1)) { + w = 0; + h = 0; + } + if ((content_left != parsed[0]) || + (content_top != parsed[1]) || + (content_w != w) || + (content_h != h)) + scaler_pos_changed = 1; + content_left = parsed[0]; + content_top = parsed[1]; + content_w = w; + content_h = h; + /* video_notify_flag =*/ + /*video_notify_flag|VIDEO_NOTIFY_POS_CHANGED; */ + } else +#endif + { + if ((w > 0) && (h > 0)) { + if ((w == 1) && (h == 1)) { + w = 0; + h = 0; + } + layer->layer_left = parsed[0]; + layer->layer_top = parsed[1]; + layer->layer_width = w; + layer->layer_height = h; + } + } + + new_x = layer->layer_left; + new_y = layer->layer_top; + new_w = layer->layer_width; + new_h = layer->layer_height; + + if ((last_x != new_x) || (last_y != new_y) || + (last_w != new_w) || (last_h != new_h)) { + if (layer->layer_id == 0) + vd_layer[0].property_changed = true; + else if (layer->layer_id == 1) + vd_layer[1].property_changed = true; + } +} + +void set_video_crop_ext(int layer_index, int *p) +{ + struct disp_info_s *layer = &glayer_info[layer_index]; + + _set_video_crop(layer, p); +} + +void set_video_window_ext(int layer_index, int *p) +{ + struct disp_info_s *layer = &glayer_info[layer_index]; + + _set_video_window(layer, p); +} + +void set_video_zorder_ext(int layer_index, int zorder) +{ + struct disp_info_s *layer = &glayer_info[layer_index]; + + if (layer->zorder != zorder) { + layer->zorder = zorder; + if (layer->layer_id == 0) { + vd_layer[0].property_changed = true; + } else if (layer->layer_id == 1) { + vd_layer[1].property_changed = true; + } + } +} + static void pip_swap_frame(struct vframe_s *vf) { struct video_layer_s *layer = NULL; struct disp_info_s *layer_info = NULL; + int axis[4]; + int crop[4]; int ret; if (!vf) @@ -2768,6 +2926,21 @@ static void pip_swap_frame(struct vframe_s *vf) DEBUG_FLAG_PRINT_TOGGLE_FRAME) pr_info("%s()\n", __func__); + if (vf->flag & VFRAME_FLAG_VIDEO_COMPOSER) { + axis[0] = vf->axis[0]; + axis[1] = vf->axis[1]; + axis[2] = vf->axis[2]; + axis[3] = vf->axis[3]; + crop[0] = vf->crop[0]; + crop[1] = vf->crop[1]; + crop[2] = vf->crop[2]; + crop[3] = vf->crop[3]; + _set_video_window(&glayer_info[1], axis); + _set_video_crop(&glayer_info[1], crop); + + glayer_info[1].zorder = vf->zorder; + } + ret = layer_swap_frame( vf, layer->layer_id, false, vinfo); @@ -2775,7 +2948,7 @@ static void pip_swap_frame(struct vframe_s *vf) if (!is_local_vf(layer->dispbuf)) { if (layer->keep_frame_id == 1) video_pip_keeper_new_frame_notify(); - else + else if (layer->keep_frame_id == 0) video_keeper_new_frame_notify(); } if (stop_update) @@ -2865,6 +3038,8 @@ static void primary_swap_frame( int ret; struct video_layer_s *layer = NULL; struct disp_info_s *layer_info = NULL; + int axis[4]; + int crop[4]; ATRACE_COUNTER(__func__, line); @@ -2874,6 +3049,20 @@ static void primary_swap_frame( layer = &vd_layer[0]; layer_info = &glayer_info[0]; + if (vf->flag & VFRAME_FLAG_VIDEO_COMPOSER) { + axis[0] = vf->axis[0]; + axis[1] = vf->axis[1]; + axis[2] = vf->axis[2]; + axis[3] = vf->axis[3]; + crop[0] = vf->crop[0]; + crop[1] = vf->crop[1]; + crop[2] = vf->crop[2]; + crop[3] = vf->crop[3]; + _set_video_window(&glayer_info[0], axis); + _set_video_crop(&glayer_info[0], crop); + glayer_info[0].zorder = vf->zorder; + } + if ((layer->layer_id == 0) && vf && !(vf->type & VIDTYPE_COMPRESS) && layer_info->need_no_compress) { @@ -2891,7 +3080,8 @@ static void primary_swap_frame( force_toggle = true; } else { #ifdef CONFIG_AMLOGIC_MEDIA_DEINTERLACE - if (is_di_on()) { + /* FIXME: is_di_on */ + if (is_di_post_mode(vf)) { /* check mif enable status, disable post di */ VSYNC_WR_MPEG_REG(DI_POST_CTRL, 0x3 << 30); VSYNC_WR_MPEG_REG( @@ -2974,7 +3164,7 @@ static void primary_swap_frame( if (!is_local_vf(layer->dispbuf)) { if (layer->keep_frame_id == 1) video_pip_keeper_new_frame_notify(); - else + else if (layer->keep_frame_id == 0) video_keeper_new_frame_notify(); } @@ -3182,6 +3372,8 @@ static irqreturn_t vsync_isr_in(int irq, void *dev_id) struct vframe_s *dv_new_vf = NULL; struct vframe_s *path0_new_frame = NULL; struct vframe_s *path1_new_frame = NULL; + struct vframe_s *path2_new_frame = NULL; + struct vframe_s *path3_new_frame = NULL; struct vframe_s *new_frame = NULL; struct vframe_s *new_frame2 = NULL; struct vframe_s *cur_dispbuf_back = cur_dispbuf; @@ -3293,6 +3485,8 @@ static irqreturn_t vsync_isr_in(int irq, void *dev_id) } } + vsync_notify_video_composer(); + #ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION if (is_dolby_vision_enable() && dovi_drop_flag) { struct vframe_s *vf = NULL; @@ -3432,9 +3626,9 @@ static irqreturn_t vsync_isr_in(int irq, void *dev_id) #endif #ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION /* check video frame before VECM process */ - if (is_dolby_vision_enable() && + if (is_dolby_vision_enable() && vf && ((vd1_path_id == VFM_PATH_AMVIDEO) || - (vd1_path_id == VFM_PATH_DEF)) && vf) { + (vd1_path_id == VFM_PATH_DEF))) { dolby_vision_check_mvc(vf); dolby_vision_check_hdr10(vf); dolby_vision_check_hdr10plus(vf); @@ -3444,6 +3638,7 @@ static irqreturn_t vsync_isr_in(int irq, void *dev_id) if (cur_vd1_path_id != vd1_path_id) { char *provider_name = NULL; + /* FIXME: add more receiver check */ if (vd1_path_id == VFM_PATH_PIP) { provider_name = vf_get_provider_name("videopip"); while (provider_name) { @@ -3601,17 +3796,24 @@ static irqreturn_t vsync_isr_in(int irq, void *dev_id) for (i = 0; i < dispbuf_to_put_num; i++) { if (dispbuf_to_put[i]) { + dispbuf_to_put[i]->rendered = true; video_vf_put(dispbuf_to_put[i]); dispbuf_to_put[i] = NULL; } dispbuf_to_put_num = 0; } if (pipbuf_to_put) { + pipbuf_to_put->rendered = true; pip_vf_put(pipbuf_to_put); pipbuf_to_put = NULL; } #endif + if (gvideo_recv[0]) + gvideo_recv[0]->func->early_proc(gvideo_recv[0]); + if (gvideo_recv[1]) + gvideo_recv[1]->func->early_proc(gvideo_recv[1]); + if ((!cur_dispbuf) || (cur_dispbuf == &vf_local)) { vf = video_vf_peek(); if (vf) { @@ -3815,7 +4017,8 @@ static irqreturn_t vsync_isr_in(int irq, void *dev_id) if (trickmode_fffb == 1) { trickmode_vpts = vf->pts; #ifdef CONFIG_AMLOGIC_MEDIA_VSYNC_RDMA - if (is_di_on()) { + /* FIXME: replace is_di_on */ + if (is_di_post_mode(vf)) { atomic_set(&trickmode_framedone, 1); video_notify_flag |= VIDEO_NOTIFY_TRICK_WAIT; @@ -3831,6 +4034,15 @@ static irqreturn_t vsync_isr_in(int irq, void *dev_id) if (slowsync_repeat_enable) frame_repeat_count = 0; vf = video_vf_peek(); + if (vf) { + if ((vf->flag & VFRAME_FLAG_VIDEO_COMPOSER) && + (debug_flag & + DEBUG_FLAG_COMPOSER_NO_DROP_FRAME)) { + pr_info("composer not drop\n"); + vf = NULL; + } + } + if (!vf) next_peek_underflow++; #ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION @@ -3977,8 +4189,8 @@ SET_FILTER: videopip_get_vf_cnt = 0; #ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION /* check video frame before VECM process */ - if (vd1_path_id == VFM_PATH_PIP && - is_dolby_vision_enable() && vf) { + if (vd1_path_id == VFM_PATH_PIP && vf && + is_dolby_vision_enable()) { dolby_vision_check_hdr10(vf); dolby_vision_check_hdr10plus(vf); dolby_vision_check_hlg(vf); @@ -4050,6 +4262,85 @@ SET_FILTER: pr_info("videopip drop frame: drop count %d\n", videopip_drop_vf_cnt); } + + /* video_render.0 toggle frame */ + if (gvideo_recv[0]) { + path2_new_frame = + gvideo_recv[0]->func->dequeue_frame(gvideo_recv[0]); + if (vd1_path_id == gvideo_recv[0]->path_id) { + /* FIXME: need DV dual layer case */ +#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION + dv_new_vf = dvel_toggle_frame(vf, true); +#endif + amvecm_on_vs( + (gvideo_recv[0]->cur_buf != + &gvideo_recv[0]->local_buf) + ? gvideo_recv[0]->cur_buf : NULL, + path2_new_frame, + CSC_FLAG_CHECK_OUTPUT, + 0, + 0, + 0, + 0, + 0, + 0, + VD1_PATH); + } + if (vd2_path_id == gvideo_recv[0]->path_id) + amvecm_on_vs( + (gvideo_recv[0]->cur_buf != + &gvideo_recv[0]->local_buf) + ? gvideo_recv[0]->cur_buf : NULL, + path2_new_frame, + CSC_FLAG_CHECK_OUTPUT, + 0, + 0, + 0, + 0, + 0, + 0, + VD2_PATH); + } + + /* video_render.1 toggle frame */ + if (gvideo_recv[1]) { + path3_new_frame = + gvideo_recv[1]->func->dequeue_frame(gvideo_recv[1]); + if (vd1_path_id == gvideo_recv[1]->path_id) { + /* FIXME: need DV dual layer case */ +#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION + dv_new_vf = dvel_toggle_frame(vf, true); +#endif + amvecm_on_vs( + (gvideo_recv[1]->cur_buf != + &gvideo_recv[1]->local_buf) + ? gvideo_recv[1]->cur_buf : NULL, + path3_new_frame, + CSC_FLAG_CHECK_OUTPUT, + 0, + 0, + 0, + 0, + 0, + 0, + VD1_PATH); + } + if (vd2_path_id == gvideo_recv[1]->path_id) + amvecm_on_vs( + (gvideo_recv[1]->cur_buf != + &gvideo_recv[1]->local_buf) + ? gvideo_recv[1]->cur_buf : NULL, + path3_new_frame, + CSC_FLAG_CHECK_OUTPUT, + 0, + 0, + 0, + 0, + 0, + 0, + VD2_PATH); + } + /* FIXME: if need enable for vd1 */ #ifdef CHECK_LATER if (!vd_layer[0].global_output) { @@ -4065,28 +4356,35 @@ SET_FILTER: cur_vd2_path_id != vd2_path_id) && (debug_flag & DEBUG_FLAG_PRINT_PATH_SWITCH)) { pr_info("VID: === before path switch ===\n"); - pr_info("VID: \tcur_path_id: %d, %d;\nVID: \tnew_path_id: %d, %d;\nVID: \ttoggle:%p, %p,\nVID: \tcur:%p, %p;\n", + pr_info("VID: \tcur_path_id: %d, %d;\nVID: \tnew_path_id: %d, %d;\nVID: \ttoggle:%p, %p, %p %p\nVID: \tcur:%p, %p, %p, %p;\n", cur_vd1_path_id, cur_vd2_path_id, vd1_path_id, vd2_path_id, path0_new_frame, path1_new_frame, - cur_dispbuf, cur_pipbuf); - pr_info("VID: \tdispbuf:%p, %p;\nVID: \tlocal:%p, %p\n", + path2_new_frame, path3_new_frame, + cur_dispbuf, cur_pipbuf, + gvideo_recv[0] ? gvideo_recv[0]->cur_buf : NULL, + gvideo_recv[1] ? gvideo_recv[1]->cur_buf : NULL); + pr_info("VID: \tdispbuf:%p, %p;\nVID: \tlocal:%p, %p, %p, %p\n", vd_layer[0].dispbuf, vd_layer[1].dispbuf, - &vf_local, &local_pip); + &vf_local, &local_pip, + gvideo_recv[0] ? &gvideo_recv[0]->local_buf : NULL, + gvideo_recv[1] ? &gvideo_recv[1]->local_buf : NULL); pr_info("VID: \tblackout:%d %d force:%d;\n", blackout, blackout_pip, force_blackout); } if (debug_flag & DEBUG_FLAG_PRINT_DISBUF_PER_VSYNC) - pr_info("VID: path id: %d, %d; new_frame:%p, %p, cur:%p, %p; vd dispbuf:%p, %p; local:%p, %p\n", + pr_info("VID: path id: %d, %d; new_frame:%p, %p, %p, %p cur:%p, %p, %p, %p; vd dispbuf:%p, %p; local:%p, %p, %p, %p\n", vd1_path_id, vd2_path_id, - path0_new_frame, - path1_new_frame, + path0_new_frame, path1_new_frame, + path2_new_frame, path3_new_frame, cur_dispbuf, cur_pipbuf, - vd_layer[0].dispbuf, - vd_layer[1].dispbuf, - &vf_local, - &local_pip); + gvideo_recv[0] ? gvideo_recv[0]->cur_buf : NULL, + gvideo_recv[1] ? gvideo_recv[1]->cur_buf : NULL, + vd_layer[0].dispbuf, vd_layer[1].dispbuf, + &vf_local, &local_pip, + gvideo_recv[0] ? &gvideo_recv[0]->local_buf : NULL, + gvideo_recv[1] ? &gvideo_recv[0]->local_buf : NULL); if ((vd_layer[0].dispbuf_mapping == &cur_dispbuf) && ((cur_dispbuf == &vf_local) || @@ -4100,8 +4398,66 @@ SET_FILTER: (vd_layer[0].dispbuf != cur_pipbuf)) vd_layer[0].dispbuf = cur_pipbuf; + if (gvideo_recv[0] && + (vd_layer[0].dispbuf_mapping == &gvideo_recv[0]->cur_buf) && + ((gvideo_recv[0]->cur_buf == &gvideo_recv[0]->local_buf) || + !gvideo_recv[0]->cur_buf) && + (vd_layer[0].dispbuf != gvideo_recv[0]->cur_buf)) + vd_layer[0].dispbuf = gvideo_recv[0]->cur_buf; + + if (gvideo_recv[1] && + (vd_layer[0].dispbuf_mapping == &gvideo_recv[1]->cur_buf) && + ((gvideo_recv[1]->cur_buf == &gvideo_recv[1]->local_buf) || + !gvideo_recv[1]->cur_buf) && + (vd_layer[0].dispbuf != gvideo_recv[1]->cur_buf)) + vd_layer[0].dispbuf = gvideo_recv[1]->cur_buf; + /* vd1 config */ - if (vd1_path_id == VFM_PATH_PIP) { + if (gvideo_recv[0] && + (gvideo_recv[0]->path_id == vd1_path_id)) { + /* video_render.0 display on VD1 */ + new_frame = path2_new_frame; + if (!new_frame) { + if (!gvideo_recv[0]->cur_buf) { + /* video_render.0 no frame in display */ + if (cur_vd1_path_id != vd1_path_id) + safe_switch_videolayer(0, false, true); + vd_layer[0].dispbuf = NULL; + } else if (gvideo_recv[0]->cur_buf == + &gvideo_recv[0]->local_buf) { + /* video_render.0 keep frame */ + vd_layer[0].dispbuf = gvideo_recv[0]->cur_buf; + } else if (vd_layer[0].dispbuf + != gvideo_recv[0]->cur_buf) { + /* video_render.0 has frame in display */ + new_frame = gvideo_recv[0]->cur_buf; + } + } + vd_layer[0].dispbuf_mapping = &gvideo_recv[0]->cur_buf; + cur_blackout = 1; + } else if (gvideo_recv[1] && + (gvideo_recv[1]->path_id == vd1_path_id)) { + /* video_render.1 display on VD1 */ + new_frame = path3_new_frame; + if (!new_frame) { + if (!gvideo_recv[1]->cur_buf) { + /* video_render.1 no frame in display */ + if (cur_vd1_path_id != vd1_path_id) + safe_switch_videolayer(0, false, true); + vd_layer[0].dispbuf = NULL; + } else if (gvideo_recv[1]->cur_buf == + &gvideo_recv[1]->local_buf) { + /* video_render.1 keep frame */ + vd_layer[0].dispbuf = gvideo_recv[1]->cur_buf; + } else if (vd_layer[0].dispbuf + != gvideo_recv[1]->cur_buf) { + /* video_render.1 has frame in display */ + new_frame = gvideo_recv[1]->cur_buf; + } + } + vd_layer[0].dispbuf_mapping = &gvideo_recv[1]->cur_buf; + cur_blackout = 1; + } else if (vd1_path_id == VFM_PATH_PIP) { /* pip display on VD1 */ new_frame = path1_new_frame; if (!new_frame) { @@ -4149,7 +4505,7 @@ SET_FILTER: is_local_vf(vd_layer[0].dispbuf)) { if (cur_blackout) { vd_layer[0].property_changed = false; - } else if (!is_di_on()) { + } else if (!is_di_post_mode(vd_layer[0].dispbuf)) { vd_layer[0].dispbuf->canvas0Addr = get_layer_display_canvas(0); } @@ -4169,10 +4525,13 @@ SET_FILTER: #endif } - if (vd1_path_id == VFM_PATH_PIP) + if ((vd1_path_id == VFM_PATH_AMVIDEO) || + (vd1_path_id == VFM_PATH_DEF)) + vd_layer[0].keep_frame_id = 0; + else if (vd1_path_id == VFM_PATH_PIP) vd_layer[0].keep_frame_id = 1; else - vd_layer[0].keep_frame_id = 0; + vd_layer[0].keep_frame_id = 0xff; #if defined(CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_VECM) if (new_frame) @@ -4218,8 +4577,66 @@ SET_FILTER: (vd_layer[1].dispbuf != cur_pipbuf)) vd_layer[1].dispbuf = cur_pipbuf; + if (gvideo_recv[0] && + (vd_layer[1].dispbuf_mapping == &gvideo_recv[0]->cur_buf) && + ((gvideo_recv[0]->cur_buf == &gvideo_recv[0]->local_buf) || + !gvideo_recv[0]->cur_buf) && + (vd_layer[1].dispbuf != gvideo_recv[0]->cur_buf)) + vd_layer[1].dispbuf = gvideo_recv[0]->cur_buf; + + if (gvideo_recv[1] && + (vd_layer[1].dispbuf_mapping == &gvideo_recv[1]->cur_buf) && + ((gvideo_recv[1]->cur_buf == &gvideo_recv[1]->local_buf) || + !gvideo_recv[1]->cur_buf) && + (vd_layer[1].dispbuf != gvideo_recv[1]->cur_buf)) + vd_layer[1].dispbuf = gvideo_recv[1]->cur_buf; + /* vd2 config */ - if (vd2_path_id == VFM_PATH_AMVIDEO) { + if (gvideo_recv[0] && + (gvideo_recv[0]->path_id == vd2_path_id)) { + /* video_render.0 display on VD2 */ + new_frame2 = path2_new_frame; + if (!new_frame2) { + if (!gvideo_recv[0]->cur_buf) { + /* video_render.0 no frame in display */ + if (cur_vd2_path_id != vd2_path_id) + safe_switch_videolayer(1, false, true); + vd_layer[1].dispbuf = NULL; + } else if (gvideo_recv[0]->cur_buf == + &gvideo_recv[0]->local_buf) { + /* video_render.0 keep frame */ + vd_layer[1].dispbuf = gvideo_recv[0]->cur_buf; + } else if (vd_layer[1].dispbuf + != gvideo_recv[0]->cur_buf) { + /* video_render.0 has frame in display */ + new_frame2 = gvideo_recv[0]->cur_buf; + } + } + vd_layer[1].dispbuf_mapping = &gvideo_recv[0]->cur_buf; + cur_blackout = 1; + } else if (gvideo_recv[1] && + (gvideo_recv[1]->path_id == vd2_path_id)) { + /* video_render.1 display on VD1 */ + new_frame2 = path3_new_frame; + if (!new_frame2) { + if (!gvideo_recv[1]->cur_buf) { + /* video_render.1 no frame in display */ + if (cur_vd2_path_id != vd2_path_id) + safe_switch_videolayer(1, false, true); + vd_layer[1].dispbuf = NULL; + } else if (gvideo_recv[1]->cur_buf == + &gvideo_recv[1]->local_buf) { + /* video_render.1 keep frame */ + vd_layer[1].dispbuf = gvideo_recv[1]->cur_buf; + } else if (vd_layer[1].dispbuf + != gvideo_recv[1]->cur_buf) { + /* video_render.1 has frame in display */ + new_frame2 = gvideo_recv[1]->cur_buf; + } + } + vd_layer[1].dispbuf_mapping = &gvideo_recv[1]->cur_buf; + cur_blackout = 1; + } else if (vd2_path_id == VFM_PATH_AMVIDEO) { /* priamry display in VD2 */ new_frame2 = path0_new_frame; if (!new_frame2) { @@ -4282,10 +4699,13 @@ SET_FILTER: need_disable_vd2 = false; } - if (vd2_path_id == VFM_PATH_AMVIDEO) + if ((vd2_path_id == VFM_PATH_PIP) || + (vd2_path_id == VFM_PATH_DEF)) + vd_layer[1].keep_frame_id = 1; + else if (vd2_path_id == VFM_PATH_AMVIDEO) vd_layer[1].keep_frame_id = 0; else - vd_layer[1].keep_frame_id = 1; + vd_layer[1].keep_frame_id = 0xff; #if defined(CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_VECM) amvecm_on_vs( @@ -4324,18 +4744,30 @@ SET_FILTER: pip_render_frame( &vd_layer[1], vd_layer[1].dispbuf); + if (vd_layer[0].dispbuf && + (vd_layer[0].dispbuf->flag & VFRAME_FLAG_FAKE_FRAME)) + safe_switch_videolayer(0, false, true); + + if (vd_layer[1].dispbuf && + (vd_layer[1].dispbuf->flag & VFRAME_FLAG_FAKE_FRAME)) + safe_switch_videolayer(1, false, true); + if ((cur_vd1_path_id != vd1_path_id || cur_vd2_path_id != vd2_path_id) && (debug_flag & DEBUG_FLAG_PRINT_PATH_SWITCH)) { pr_info("VID: === After path switch ===\n"); - pr_info("VID: \tpath_id: %d, %d;\nVID: \ttoggle:%p, %p\nVID: \tnew:%p, %p\nVID: \tcur:%p, %p;\n", + pr_info("VID: \tpath_id: %d, %d;\nVID: \ttoggle:%p, %p, %p %p\nVID: \tcur:%p, %p, %p, %p;\n", vd1_path_id, vd2_path_id, path0_new_frame, path1_new_frame, - new_frame, new_frame2, - cur_dispbuf, cur_pipbuf); - pr_info("VID: \tdispbuf:%p, %p;\nVID: \tlocal:%p, %p\n", + path2_new_frame, path3_new_frame, + cur_dispbuf, cur_pipbuf, + gvideo_recv[0] ? gvideo_recv[0]->cur_buf : NULL, + gvideo_recv[1] ? gvideo_recv[1]->cur_buf : NULL); + pr_info("VID: \tdispbuf:%p, %p;\nVID: \tlocal:%p, %p, %p, %p\n", vd_layer[0].dispbuf, vd_layer[1].dispbuf, - &vf_local, &local_pip); + &vf_local, &local_pip, + gvideo_recv[0] ? &gvideo_recv[0]->local_buf : NULL, + gvideo_recv[1] ? &gvideo_recv[1]->local_buf : NULL); pr_info("VID: \tblackout:%d %d force:%d;\n", blackout, blackout_pip, force_blackout); } @@ -4370,15 +4802,22 @@ SET_FILTER: di_post_process_done = true; } exit: +#ifdef CONFIG_AMLOGIC_MEDIA_DEINTERLACE if (legacy_vpp && !di_post_process_done && is_di_post_on()) DI_POST_UPDATE_MC(); +#endif #if defined(PTS_LOGGING) || defined(PTS_TRACE_DEBUG) pts_trace++; #endif vpp_blend_update(vinfo); + if (gvideo_recv[0]) + gvideo_recv[0]->func->late_proc(gvideo_recv[0]); + if (gvideo_recv[1]) + gvideo_recv[1]->func->late_proc(gvideo_recv[1]); + #ifdef CONFIG_AMLOGIC_MEDIA_VSYNC_RDMA cur_rdma_buf = cur_dispbuf; pip_rdma_buf = cur_pipbuf; @@ -5062,7 +5501,7 @@ int _video_set_disable(u32 val) /* FIXME */ if (layer->keep_frame_id == 1) try_free_keep_videopip(0); - else + else if (layer->keep_frame_id == 0) try_free_keep_video(0); } else { if (layer->dispbuf && @@ -5076,120 +5515,28 @@ int _video_set_disable(u32 val) return 0; } -static void _set_video_crop( - struct disp_info_s *layer, int *p) +void video_set_global_output(u32 index, u32 val) { - int last_l, last_r, last_t, last_b; - int new_l, new_r, new_t, new_b; - - if (!layer) - return; - - last_t = layer->crop_top; - last_l = layer->crop_left; - last_b = layer->crop_bottom; - last_r = layer->crop_right; - - new_t = layer->crop_top = p[0]; - new_l = layer->crop_left = p[1]; - new_b = layer->crop_bottom = p[2]; - new_r = layer->crop_right = p[3]; - if ((new_t != last_t) || (new_l != last_l) || - (new_b != last_b) || (new_r != last_r)) { - if (layer->layer_id == 0) - vd_layer[0].property_changed = true; - else if (layer->layer_id == 1) - vd_layer[1].property_changed = true; + if (index == 0) { + if (val != 0) + vd_layer[0].global_output = 1; + else + vd_layer[0].global_output = 0; + } else if (index == 1) { + if (val != 0) + vd_layer[1].global_output = 1; + else + vd_layer[1].global_output = 0; } + pr_info("VID: VD%d set global output as %d\n", + index + 1, (val != 0) ? 1 : 0); } -static void _set_video_window( - struct disp_info_s *layer, int *p) +u32 video_get_layer_capability(void) { - int w, h; - int *parsed = p; - int last_x, last_y, last_w, last_h; - int new_x, new_y, new_w, new_h; -#ifdef TV_REVERSE - int temp, temp1; - const struct vinfo_s *info = get_current_vinfo(); -#endif - - if (!layer) - return; - -#ifdef TV_REVERSE - if (reverse) { - temp = parsed[0]; - temp1 = parsed[1]; - parsed[0] = info->width - parsed[2] - 1; - parsed[1] = info->height - parsed[3] - 1; - parsed[2] = info->width - temp - 1; - parsed[3] = info->height - temp1 - 1; - } -#endif - - last_x = layer->layer_left; - last_y = layer->layer_top; - last_w = layer->layer_width; - last_h = layer->layer_height; - - if (parsed[0] < 0 && parsed[2] < 2) { - parsed[2] = 2; - parsed[0] = 0; - } - if (parsed[1] < 0 && parsed[3] < 2) { - parsed[3] = 2; - parsed[1] = 0; - } - w = parsed[2] - parsed[0] + 1; - h = parsed[3] - parsed[1] + 1; - -#ifdef CONFIG_AMLOGIC_POST_PROCESS_MANAGER_PPSCALER - if (video_scaler_mode) { - if ((w == 1) && (h == 1)) { - w = 0; - h = 0; - } - if ((content_left != parsed[0]) || - (content_top != parsed[1]) || - (content_w != w) || - (content_h != h)) - scaler_pos_changed = 1; - content_left = parsed[0]; - content_top = parsed[1]; - content_w = w; - content_h = h; - /* video_notify_flag =*/ - /*video_notify_flag|VIDEO_NOTIFY_POS_CHANGED; */ - } else -#endif - { - if ((w > 0) && (h > 0)) { - if ((w == 1) && (h == 1)) { - w = 0; - h = 0; - } - layer->layer_left = parsed[0]; - layer->layer_top = parsed[1]; - layer->layer_width = w; - layer->layer_height = h; - } - } - - new_x = layer->layer_left; - new_y = layer->layer_top; - new_w = layer->layer_width; - new_h = layer->layer_height; - - if ((last_x != new_x) || (last_y != new_y) || - (last_w != new_w) || (last_h != new_h)) { - if (layer->layer_id == 0) - vd_layer[0].property_changed = true; - else if (layer->layer_id == 1) - vd_layer[1].property_changed = true; - } + return layer_cap; } + #if ENABLE_UPDATE_HDR_FROM_USER static void config_hdr_info(const struct vframe_master_display_colour_s p) { @@ -5865,19 +6212,7 @@ static long amvideo_ioctl(struct file *file, unsigned int cmd, ulong arg) case AMSTREAM_IOC_GLOBAL_SET_VIDEOPIP_OUTPUT: case AMSTREAM_IOC_GLOBAL_SET_VIDEO_OUTPUT: - if (layer->layer_id == 0) { - if (arg != 0) - vd_layer[0].global_output = 1; - else - vd_layer[0].global_output = 0; - } else if (layer->layer_id == 1) { - if (arg != 0) - vd_layer[1].global_output = 1; - else - vd_layer[1].global_output = 0; - } - pr_info("VID: VD%d set global output as %d\n", - layer->layer_id + 1, (arg != 0) ? 1 : 0); + video_set_global_output(layer->layer_id, arg ? 1 : 0); break; case AMSTREAM_IOC_GLOBAL_GET_VIDEOPIP_OUTPUT: @@ -7968,7 +8303,7 @@ static ssize_t video_free_keep_buffer_store(struct class *cla, if (val == 1) { if (vd_layer[0].keep_frame_id == 1) try_free_keep_videopip(1); - else + else if (vd_layer[0].keep_frame_id == 0) try_free_keep_video(1); } return count; @@ -8356,7 +8691,7 @@ int _videopip_set_disable(u32 val) /* FIXME */ if (layer->keep_frame_id == 1) try_free_keep_videopip(0); - else + else if (vd_layer[0].keep_frame_id == 0) try_free_keep_video(0); } else { if (layer->dispbuf && @@ -8712,6 +9047,41 @@ static ssize_t videopip_state_show( return len; } +s32 set_video_path_select(const char *recv_name, u8 layer_id) +{ + u32 new_path_id; + struct disp_info_s *layer_info; + struct video_layer_s *layer; + + if (!recv_name || + (layer_id >= MAX_VD_LAYERS)) + return -1; + + layer_info = &glayer_info[layer_id]; + layer = &vd_layer[layer_id]; + new_path_id = layer_info->display_path_id; + if (!strcmp(recv_name, "default")) + new_path_id = VFM_PATH_DEF; + else if (!strcmp(recv_name, RECEIVER_NAME)) + new_path_id = VFM_PATH_AMVIDEO; + else if (!strcmp(recv_name, RECEIVERPIP_NAME)) + new_path_id = VFM_PATH_PIP; + else if (!strcmp(recv_name, "video_render.0")) + new_path_id = VFM_PATH_VIDEO_RENDER0; + else if (!strcmp(recv_name, "video_render.1")) + new_path_id = VFM_PATH_VIDEO_RENDER1; + else if (!strcmp(recv_name, "invalid")) + new_path_id = VFM_PATH_INVAILD; + if (layer_info->display_path_id != new_path_id) { + pr_info("VID: store VD%d path_id changed %d->%d\n", + layer_id, layer_info->display_path_id, new_path_id); + layer_info->display_path_id = new_path_id; + layer->property_changed = true; + } + return 0; +} +EXPORT_SYMBOL(set_video_path_select); + static ssize_t path_select_show( struct class *cla, struct class_attribute *attr, @@ -9488,11 +9858,16 @@ static int __init video_init(void) dispbuf_to_put[dispbuf_to_put_num] = NULL; } #endif + gvideo_recv[0] = create_video_receiver( + "video_render.0", VFM_PATH_VIDEO_RENDER0); + gvideo_recv[1] = create_video_receiver( + "video_render.1", VFM_PATH_VIDEO_RENDER1); vsync_fiq_up(); - vf_receiver_init(&video_vf_recv, RECEIVER_NAME, &video_vf_receiver, - NULL); + vf_receiver_init( + &video_vf_recv, RECEIVER_NAME, + &video_vf_receiver, NULL); vf_reg_receiver(&video_vf_recv); vf_receiver_init( @@ -9537,6 +9912,13 @@ static void __exit video_exit(void) vsync_fiq_down(); + if (gvideo_recv[0]) + destroy_video_receiver(gvideo_recv[0]); + gvideo_recv[0] = NULL; + if (gvideo_recv[1]) + destroy_video_receiver(gvideo_recv[1]); + gvideo_recv[1] = NULL; + device_destroy(&amvideo_class, MKDEV(AMVIDEO_MAJOR, 0)); device_destroy(&amvideo_poll_class, MKDEV(amvideo_poll_major, 0)); diff --git a/drivers/amlogic/media/video_sink/video_hw.c b/drivers/amlogic/media/video_sink/video_hw.c index ab8d27ce974d..0a0ce1ede727 100644 --- a/drivers/amlogic/media/video_sink/video_hw.c +++ b/drivers/amlogic/media/video_sink/video_hw.c @@ -64,6 +64,9 @@ #include #include "../common/vfm/vfm.h" #include +#include "video_receiver.h" + +/* #define DI_POST_PWR */ struct video_layer_s vd_layer[MAX_VD_LAYER]; struct disp_info_s glayer_info[MAX_VD_LAYERS]; @@ -118,7 +121,7 @@ static int vpu_mem_power_off_count; spin_unlock_irqrestore(&delay_work_lock, flags); \ } \ } while (0) - +#ifdef DI_POST_PWR #define VD1_MEM_POWER_ON() \ do { \ unsigned long flags; \ @@ -132,6 +135,20 @@ static int vpu_mem_power_off_count; switch_vpu_mem_pd_vmod( \ VPU_VD1_SCALE, VPU_MEM_POWER_ON); \ } while (0) +#else +#define VD1_MEM_POWER_ON() \ + do { \ + unsigned long flags; \ + spin_lock_irqsave(&delay_work_lock, flags); \ + vpu_delay_work_flag &= ~VPU_DELAYWORK_MEM_POWER_OFF_VD1; \ + spin_unlock_irqrestore(&delay_work_lock, flags); \ + switch_vpu_mem_pd_vmod(VPU_VIU_VD1, VPU_MEM_POWER_ON); \ + switch_vpu_mem_pd_vmod(VPU_AFBC_DEC, VPU_MEM_POWER_ON); \ + if (!legacy_vpp) \ + switch_vpu_mem_pd_vmod( \ + VPU_VD1_SCALE, VPU_MEM_POWER_ON); \ + } while (0) +#endif #define VD2_MEM_POWER_ON() \ do { \ unsigned long flags; \ @@ -391,6 +408,16 @@ bool is_di_post_link_on(void) return ret; } +bool is_di_post_mode(struct vframe_s *vf) +{ + bool ret = false; + + if (vf && (vf->type & VIDTYPE_PRE_INTERLACE) && + !(vf->type & VIDTYPE_DI_PW)) + ret = true; + return ret; +} + bool is_afbc_enabled(u8 layer_id) { struct video_layer_s *layer = NULL; @@ -416,6 +443,14 @@ bool is_local_vf(struct vframe_s *vf) (vf == &vf_local2) || (vf == &local_pip))) return true; + + /* FIXEME: remove gvideo_recv */ + if (vf && gvideo_recv[0] && + (vf == &gvideo_recv[0]->local_buf)) + return true; + if (vf && gvideo_recv[1] && + (vf == &gvideo_recv[1]->local_buf)) + return true; return false; } @@ -475,7 +510,7 @@ void safe_switch_videolayer(u8 layer_id, bool on, bool async) static void vd1_path_select( struct video_layer_s *layer, - bool afbc, bool di_afbc) + bool afbc, bool di_afbc, bool di_post) { u32 misc_off = layer->misc_reg_offt; @@ -507,9 +542,7 @@ static void vd1_path_select( /* Vd1_afbc0_mem_sel */ (afbc ? 1 : 0), 22, 1); - if ((glayer_info[0].display_path_id - != VFM_PATH_PIP) && - is_di_post_on()) { + if (di_post) { /* check di_vpp_out_en bit */ VSYNC_WR_MPEG_REG_BITS( VD1_AFBCD0_MISC_CTRL, @@ -523,9 +556,7 @@ static void vd1_path_select( 20, 2); } } else { - if ((glayer_info[0].display_path_id - != VFM_PATH_PIP) && - is_di_post_on()) + if (di_post) VSYNC_WR_MPEG_REG_BITS( VIU_MISC_CTRL0 + misc_off, 0, 16, 3); @@ -593,6 +624,7 @@ static void vd1_set_dcu( u8 burst_len = 1; u32 vd_off = layer->vd_reg_offt; u32 afbc_off = layer->afbc_reg_offt; + bool di_post = false; if (!vf) { pr_info("vd1_set_dcu vf NULL, return\n"); @@ -606,6 +638,12 @@ static void vd1_set_dcu( pr_debug("%s for vd%d %p, type:0x%x\n", __func__, layer->layer_id, vf, type); +#ifdef CONFIG_AMLOGIC_MEDIA_DEINTERLACE + if ((glayer_info[0].display_path_id != VFM_PATH_PIP) && + is_di_post_mode(vf) && is_di_post_on()) + di_post = true; +#endif + if (frame_par->nocomp) type &= ~VIDTYPE_COMPRESS; @@ -696,7 +734,7 @@ static void vd1_set_dcu( VSYNC_WR_MPEG_REG( AFBCDEC_IQUANT_ENABLE + afbc_off, 0); } - vd1_path_select(layer, true, false); + vd1_path_select(layer, true, false, di_post); if (is_mvc) vd2_path_select(layer, true, false); VSYNC_WR_MPEG_REG( @@ -737,6 +775,14 @@ static void vd1_set_dcu( VSYNC_WR_MPEG_REG_BITS( G12_VD1_IF0_GEN_REG3, (burst_len & 0x3), 1, 2); + if (vf->flag & VFRAME_FLAG_VIDEO_LINEAR) + VSYNC_WR_MPEG_REG_BITS( + G12_VD1_IF0_GEN_REG3, + 0, 0, 1); + else + VSYNC_WR_MPEG_REG_BITS( + G12_VD1_IF0_GEN_REG3, + 1, 0, 1); if (is_mvc) { VSYNC_WR_MPEG_REG_BITS( G12_VD2_IF0_GEN_REG3, @@ -744,6 +790,14 @@ static void vd1_set_dcu( VSYNC_WR_MPEG_REG_BITS( G12_VD2_IF0_GEN_REG3, (burst_len & 0x3), 1, 2); + if (vf->flag & VFRAME_FLAG_VIDEO_LINEAR) + VSYNC_WR_MPEG_REG_BITS( + G12_VD2_IF0_GEN_REG3, + 0, 0, 1); + else + VSYNC_WR_MPEG_REG_BITS( + G12_VD2_IF0_GEN_REG3, + 1, 0, 1); } } else { VSYNC_WR_MPEG_REG_BITS( @@ -757,23 +811,25 @@ static void vd1_set_dcu( (bit_mode & 0x3), 8, 2); } #ifdef CONFIG_AMLOGIC_MEDIA_DEINTERLACE - DI_POST_WR_REG_BITS( - DI_IF1_GEN_REG3, - (bit_mode & 0x3), 8, 2); - if (cpu_after_eq(MESON_CPU_MAJOR_ID_TXLX)) + if (is_di_post_mode(vf)) { DI_POST_WR_REG_BITS( - DI_IF2_GEN_REG3, - (bit_mode & 0x3), 8, 2); - if (cpu_after_eq(MESON_CPU_MAJOR_ID_G12A)) - DI_POST_WR_REG_BITS( - DI_IF0_GEN_REG3, + DI_IF1_GEN_REG3, (bit_mode & 0x3), 8, 2); + if (cpu_after_eq(MESON_CPU_MAJOR_ID_TXLX)) + DI_POST_WR_REG_BITS( + DI_IF2_GEN_REG3, + (bit_mode & 0x3), 8, 2); + if (cpu_after_eq(MESON_CPU_MAJOR_ID_G12A)) + DI_POST_WR_REG_BITS( + DI_IF0_GEN_REG3, + (bit_mode & 0x3), 8, 2); + } #endif if (glayer_info[0].need_no_compress || (vf->type & VIDTYPE_PRE_DI_AFBC)) { - vd1_path_select(layer, false, true); + vd1_path_select(layer, false, true, di_post); } else { - vd1_path_select(layer, false, false); + vd1_path_select(layer, false, false, di_post); if (is_mvc) vd2_path_select(layer, false, false); VSYNC_WR_MPEG_REG( @@ -801,6 +857,9 @@ static void vd1_set_dcu( if (frame_par->hscale_skip_count) r |= VDIF_CHROMA_HZ_AVG | VDIF_LUMA_HZ_AVG; + if (vf->flag & VFRAME_FLAG_VIDEO_LINEAR) + r |= (1 << 4); + /*enable go field reset default according to vlsi*/ r |= VDIF_RESET_ON_GO_FIELD; VSYNC_WR_MPEG_REG(VD1_IF0_GEN_REG + vd_off, r); @@ -845,9 +904,8 @@ static void vd1_set_dcu( } else { /* TODO: if always use HFORMATTER_REPEAT */ if (is_crop_left_odd(frame_par)) { - if (!(type & VIDTYPE_PRE_INTERLACE) && - ((type & VIDTYPE_VIU_NV21) || - (type & VIDTYPE_VIU_422))) + if ((type & VIDTYPE_VIU_NV21) || + (type & VIDTYPE_VIU_422)) hphase = 0x8 << HFORMATTER_PHASE_BIT; } if (is_dolby_vision_on()) @@ -1168,6 +1226,14 @@ static void vd2_set_dcu( VSYNC_WR_MPEG_REG_BITS( G12_VD2_IF0_GEN_REG3, (burst_len & 0x3), 1, 2); + if (vf->flag & VFRAME_FLAG_VIDEO_LINEAR) + VSYNC_WR_MPEG_REG_BITS( + G12_VD2_IF0_GEN_REG3, + 0, 0, 1); + else + VSYNC_WR_MPEG_REG_BITS( + G12_VD2_IF0_GEN_REG3, + 1, 0, 1); } else { VSYNC_WR_MPEG_REG_BITS( VD2_IF0_GEN_REG3 + vd_off, @@ -1198,6 +1264,9 @@ static void vd2_set_dcu( if (frame_par->hscale_skip_count) r |= VDIF_CHROMA_HZ_AVG | VDIF_LUMA_HZ_AVG; + if (vf->flag & VFRAME_FLAG_VIDEO_LINEAR) + r |= (1 << 4); + VSYNC_WR_MPEG_REG(VD2_IF0_GEN_REG + vd_off, r); if (type & VIDTYPE_VIU_NV21) @@ -1229,9 +1298,8 @@ static void vd2_set_dcu( } else { /* TODO: if always use HFORMATTER_REPEAT */ if (is_crop_left_odd(frame_par)) { - if (!(type & VIDTYPE_PRE_INTERLACE) && - ((type & VIDTYPE_VIU_NV21) || - (type & VIDTYPE_VIU_422))) + if ((type & VIDTYPE_VIU_NV21) || + (type & VIDTYPE_VIU_422)) hphase = 0x8 << HFORMATTER_PHASE_BIT; } if (is_dolby_vision_on()) @@ -2295,11 +2363,13 @@ static void disable_vd1_blend(struct video_layer_s *layer) vd_off = layer->vd_reg_offt; afbc_off = layer->afbc_reg_offt; if (layer->global_debug & DEBUG_FLAG_BLACKOUT) - pr_info("VIDEO: VD1 AFBC off now. dispbuf:%p, *dispbuf_mapping:%p, local: %p-%p\n", + pr_info("VIDEO: VD1 AFBC off now. dispbuf:%p, *dispbuf_mapping:%p, local: %p, %p, %p, %p\n", layer->dispbuf, layer->dispbuf_mapping ? *layer->dispbuf_mapping : NULL, - &vf_local, &local_pip); + &vf_local, &local_pip, + gvideo_recv[0] ? &gvideo_recv[0]->local_buf : NULL, + gvideo_recv[1] ? &gvideo_recv[1]->local_buf : NULL); VSYNC_WR_MPEG_REG(AFBC_ENABLE + afbc_off, 0); VSYNC_WR_MPEG_REG(VD1_IF0_GEN_REG + vd_off, 0); if (!legacy_vpp) @@ -2350,11 +2420,13 @@ static void disable_vd2_blend(struct video_layer_s *layer) vd_off = layer->vd_reg_offt; afbc_off = layer->afbc_reg_offt; if (layer->global_debug & DEBUG_FLAG_BLACKOUT) - pr_info("VIDEO: VD2 AFBC off now. dispbuf:%p, *dispbuf_mapping:%p, local: %p-%p\n", + pr_info("VIDEO: VD2 AFBC off now. dispbuf:%p, *dispbuf_mapping:%p, local: %p, %p, %p, %p\n", layer->dispbuf, layer->dispbuf_mapping ? *layer->dispbuf_mapping : NULL, - &vf_local, &local_pip); + &vf_local, &local_pip, + gvideo_recv[0] ? &gvideo_recv[0]->local_buf : NULL, + gvideo_recv[1] ? &gvideo_recv[1]->local_buf : NULL); VSYNC_WR_MPEG_REG(VD2_AFBC_ENABLE + afbc_off, 0); VSYNC_WR_MPEG_REG(VD2_IF0_GEN_REG + vd_off, 0); if (!legacy_vpp) @@ -3454,6 +3526,14 @@ EXPORT_SYMBOL(get_video_mute); static void check_video_mute(void) { + u32 black_val; + + if (is_meson_tl1_cpu()) + black_val = (0x0 << 20) | (0x0 << 10) | 0; /* RGB */ + else + black_val = + (0x0 << 20) | (0x200 << 10) | 0x200; /* YUV */ + if (video_mute_on) { if (is_dolby_vision_on()) { /* core 3 black */ @@ -3465,14 +3545,18 @@ static void check_video_mute(void) } else { if (video_mute_status != VIDEO_MUTE_ON_VPP) { /* vpp black */ - VSYNC_WR_MPEG_REG(VPP_CLIP_MISC0, - (0x0 << 20) | - (0x200 << 10) | - 0x200); - VSYNC_WR_MPEG_REG(VPP_CLIP_MISC1, - (0x0 << 20) | - (0x200 << 10) | - 0x200); + VSYNC_WR_MPEG_REG( + VPP_CLIP_MISC0, + black_val); + VSYNC_WR_MPEG_REG( + VPP_CLIP_MISC1, + black_val); + WRITE_VCBUS_REG( + VPP_CLIP_MISC0, + black_val); + WRITE_VCBUS_REG( + VPP_CLIP_MISC1, + black_val); pr_info("DOLBY: check_video_mute: VIDEO_MUTE_ON_VPP\n"); } video_mute_status = VIDEO_MUTE_ON_VPP; @@ -3486,13 +3570,15 @@ static void check_video_mute(void) video_mute_status = VIDEO_MUTE_OFF; } else { if (video_mute_status != VIDEO_MUTE_OFF) { - VSYNC_WR_MPEG_REG(VPP_CLIP_MISC0, - (0x3ff << 20) | - (0x3ff << 10) | - 0x3ff); - VSYNC_WR_MPEG_REG(VPP_CLIP_MISC1, - (0x0 << 20) | - (0x0 << 10) | 0x0); + VSYNC_WR_MPEG_REG( + VPP_CLIP_MISC0, + (0x3ff << 20) | + (0x3ff << 10) | + 0x3ff); + VSYNC_WR_MPEG_REG( + VPP_CLIP_MISC1, + (0x0 << 20) | + (0x0 << 10) | 0x0); pr_info("DOLBY: check_video_mute: VIDEO_MUTE_OFF dv off\n"); } video_mute_status = VIDEO_MUTE_OFF; @@ -4041,6 +4127,7 @@ int set_layer_display_canvas( #ifdef CONFIG_AMLOGIC_MEDIA_DEINTERLACE if ((layer_id == 0) && + is_di_post_mode(vf) && is_di_post_link_on()) update_mif = false; #endif @@ -4391,9 +4478,11 @@ static void do_vpu_delay_work(struct work_struct *work) switch_vpu_mem_pd_vmod( VPU_AFBC_DEC, VPU_MEM_POWER_DOWN); +#ifdef DI_POST_PWR switch_vpu_mem_pd_vmod( VPU_DI_POST, VPU_MEM_POWER_DOWN); +#endif if (!legacy_vpp) switch_vpu_mem_pd_vmod( VPU_VD1_SCALE, @@ -4569,7 +4658,7 @@ int video_early_init(void) vd_layer[i].next_canvas_id = 1; #endif /* vd_layer[i].global_output = 1; */ - vd_layer[i].keep_frame_id = i; + vd_layer[i].keep_frame_id = 0xff; vd_layer[i].disable_video = VIDEO_DISABLE_FORNEXT; vpp_disp_info_init(&glayer_info[i], i); memset(&gpic_info[i], 0, sizeof(struct vframe_pic_mode_s)); diff --git a/drivers/amlogic/media/video_sink/video_priv.h b/drivers/amlogic/media/video_sink/video_priv.h index c33abd7b8cdb..f10625b436e5 100644 --- a/drivers/amlogic/media/video_sink/video_priv.h +++ b/drivers/amlogic/media/video_sink/video_priv.h @@ -44,6 +44,7 @@ #define DEBUG_FLAG_OMX_DISABLE_DROP_FRAME 0x2000000 #define DEBUG_FLAG_PRINT_DROP_FRAME 0x4000000 #define DEBUG_FLAG_OMX_DV_DROP_FRAME 0x8000000 +#define DEBUG_FLAG_COMPOSER_NO_DROP_FRAME 0x10000000 #define VOUT_TYPE_TOP_FIELD 0 #define VOUT_TYPE_BOT_FIELD 1 @@ -86,6 +87,8 @@ enum vd_path_id { VFM_PATH_DEF = -1, VFM_PATH_AMVIDEO = 0, VFM_PATH_PIP = 1, + VFM_PATH_VIDEO_RENDER0 = 2, + VFM_PATH_VIDEO_RENDER1 = 3, VFM_PATH_INVAILD = 0xff }; @@ -272,6 +275,8 @@ u32 get_videopip_enabled(void); bool is_di_on(void); bool is_di_post_on(void); bool is_di_post_link_on(void); +bool is_di_post_mode(struct vframe_s *vf); + bool is_afbc_enabled(u8 layer_id); bool is_local_vf(struct vframe_s *vf); @@ -383,10 +388,15 @@ extern struct vframe_s *cur_dispbuf; extern struct vframe_s *cur_pipbuf; extern bool need_disable_vd2; extern u32 last_el_status; +extern u32 force_blackout; +extern atomic_t video_unreg_flag; +extern atomic_t video_inirq_flag; +extern struct video_recv_s *gvideo_recv[2]; bool black_threshold_check(u8 id); void update_cur_dispbuf(void *buf); struct vframe_s *get_cur_dispbuf(void); +s32 set_video_path_select(const char *recv_name, u8 layer_id); /*for video related files only.*/ void video_module_lock(void); diff --git a/drivers/amlogic/media/video_sink/video_receiver.c b/drivers/amlogic/media/video_sink/video_receiver.c new file mode 100644 index 000000000000..db4439239449 --- /dev/null +++ b/drivers/amlogic/media/video_sink/video_receiver.c @@ -0,0 +1,428 @@ +/* + * drivers/amlogic/media/video_sink/video_receiver.c + * + * Copyright (C) 2017 Amlogic, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_AMLOGIC_MEDIA_VSYNC_RDMA +#include "../common/rdma/rdma.h" +#endif +#include +#include +#include +#include +#include + +#include "video_priv.h" +#include "video_receiver.h" + +/* #define ENABLE_DV */ + +/********************************************************* + * vframe APIs + *********************************************************/ +static inline struct vframe_s *common_vf_peek(struct video_recv_s *ins) +{ + struct vframe_s *vf = NULL; + + if (!ins || !ins->recv_name || !ins->active) + return NULL; + + vf = vf_peek(ins->recv_name); + if (vf && vf->disp_pts && vf->disp_pts_us64) { + vf->pts = vf->disp_pts; + vf->pts_us64 = vf->disp_pts_us64; + vf->disp_pts = 0; + vf->disp_pts_us64 = 0; + } + return vf; +} + +static inline struct vframe_s *common_vf_get(struct video_recv_s *ins) +{ + struct vframe_s *vf = NULL; + + if (!ins || !ins->recv_name || !ins->active) + return NULL; + + vf = vf_get(ins->recv_name); + + if (vf) { + if (vf->disp_pts && vf->disp_pts_us64) { + vf->pts = vf->disp_pts; + vf->pts_us64 = vf->disp_pts_us64; + vf->disp_pts = 0; + vf->disp_pts_us64 = 0; + } + ins->notify_flag |= VIDEO_NOTIFY_PROVIDER_GET; + } + return vf; +} + +#ifdef MORE_FUNCTION +static int common_vf_get_states( + struct video_recv_s *ins, + struct vframe_states *states) +{ + int ret = -1; + unsigned long flags; + + if (!ins || !ins->recv_name || !ins->active || !states) + return ret; + + spin_lock_irqsave(&ins->lock, flags); + ret = vf_get_states_by_name(ins->recv_name, states); + spin_unlock_irqrestore(&ins->lock, flags); + return ret; +} +#endif + +static inline void common_vf_put( + struct video_recv_s *ins, + struct vframe_s *vf) +{ + struct vframe_provider_s *vfp = NULL; + + if (!ins || !ins->recv_name) + return; + + vfp = vf_get_provider(ins->recv_name); + if (vfp && vf) { + vf_put(vf, ins->recv_name); +/* FIXME: chek if need enable */ +#ifdef ENABLE_DV /* CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION */ + if ((glayer_info[0].display_path_id == ins->path_id) && + is_dolby_vision_enable()) + dolby_vision_vf_put(vf); +#endif + ins->notify_flag |= VIDEO_NOTIFY_PROVIDER_PUT; + } +} + +/* TODO: need add keep frame function */ +static void common_vf_unreg_provider(struct video_recv_s *ins) +{ + ulong flags; + bool layer1_used = false; + bool layer2_used = false; + + if (!ins) + return; + + /* FIXME: remove the global variable */ + atomic_inc(&video_unreg_flag); + while (atomic_read(&video_inirq_flag) > 0) + schedule(); + + spin_lock_irqsave(&ins->lock, flags); + ins->buf_to_put = NULL; + ins->rdma_buf = NULL; + + if (ins->cur_buf) { + ins->local_buf = *ins->cur_buf; + ins->cur_buf = &ins->local_buf; + } + spin_unlock_irqrestore(&ins->lock, flags); + + if (vd_layer[0].dispbuf_mapping + == &ins->cur_buf) { + layer1_used = true; + } + if (vd_layer[1].dispbuf_mapping + == &ins->cur_buf) { + layer2_used = true; + } + + if (!layer1_used && !layer2_used) + ins->cur_buf = NULL; + + if (layer1_used) + safe_switch_videolayer( + 0, false, false); + if (layer2_used) + safe_switch_videolayer( + 1, false, false); + + pr_info("common_vf_unreg_provider %s: vd1 used: %s, vd2 used: %s, black_out:%d, cur_buf:%p\n", + ins->recv_name, + layer1_used ? "true" : "false", + layer2_used ? "true" : "false", + ins->blackout | force_blackout, + ins->cur_buf); + + ins->active = false; + atomic_dec(&video_unreg_flag); +} + +static void common_vf_light_unreg_provider( + struct video_recv_s *ins) +{ + ulong flags; + + if (!ins) + return; + + /* FIXME: remove the global variable */ + atomic_inc(&video_unreg_flag); + while (atomic_read(&video_inirq_flag) > 0) + schedule(); + + spin_lock_irqsave(&ins->lock, flags); + ins->buf_to_put = NULL; + ins->rdma_buf = NULL; + + if (ins->cur_buf) { + ins->local_buf = *ins->cur_buf; + ins->cur_buf = &ins->local_buf; + } + spin_unlock_irqrestore(&ins->lock, flags); + + atomic_dec(&video_unreg_flag); +} + +static int common_receiver_event_fun( + int type, void *data, void *private_data) +{ + struct video_recv_s *ins = (struct video_recv_s *)private_data; + + if (!ins) { + pr_err("common_receiver_event: ins invalid, type:%d\n", type); + return -1; + } + if (type == VFRAME_EVENT_PROVIDER_UNREG) { + common_vf_unreg_provider(ins); + } else if (type == VFRAME_EVENT_PROVIDER_RESET) { + common_vf_light_unreg_provider(ins); + } else if (type == VFRAME_EVENT_PROVIDER_LIGHT_UNREG) { + common_vf_light_unreg_provider(ins); + } else if (type == VFRAME_EVENT_PROVIDER_REG) { + common_vf_light_unreg_provider(ins); + ins->drop_vf_cnt = 0; + ins->active = true; + } + return 0; +} + +static const struct vframe_receiver_op_s common_recv_func = { + .event_cb = common_receiver_event_fun +}; + +#ifdef ENABLE_DV /* CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION */ +static int dolby_vision_need_wait_common(struct video_recv_s *ins) +{ + struct vframe_s *vf; + + if (!is_dolby_vision_enable() || !ins) + return 0; + + vf = common_vf_peek(ins); + if (!vf || (dolby_vision_wait_metadata(vf) == 1)) + return 1; + return 0; +} +#endif + +static void common_toggle_frame( + struct video_recv_s *ins, struct vframe_s *vf) +{ + if (!ins || !vf) + return; + + if ((vf->width == 0) || (vf->height == 0)) { + pr_err("common_toggle_frame %s: invalid frame dimension\n", + ins->recv_name); + return; + } + if (ins->cur_buf && + (ins->cur_buf != &ins->local_buf) && + (ins->cur_buf != vf)) { + ins->frame_count++; +#ifdef CONFIG_AMLOGIC_MEDIA_VSYNC_RDMA + if (is_vsync_rdma_enable()) { + if (ins->rdma_buf == ins->cur_buf) + ins->buf_to_put = ins->cur_buf; + else + common_vf_put( + ins, ins->cur_buf); + } else { + if (ins->buf_to_put) { + common_vf_put( + ins, ins->buf_to_put); + ins->buf_to_put = NULL; + } + common_vf_put(ins, ins->cur_buf); + } +#else + common_vf_put(ins, ins->cur_buf); +#endif + } + if (ins->cur_buf != vf) + vf->type_backup = vf->type; + ins->cur_buf = vf; +} + +/********************************************************* + * recv func APIs + *********************************************************/ +static s32 recv_common_early_process( + struct video_recv_s *ins) +{ + if (!ins) { + pr_err("recv_common_early_process error, empty ins\n"); + return -1; + } + + if (ins->buf_to_put) { + ins->buf_to_put->rendered = true; + common_vf_put( + ins, ins->buf_to_put); + ins->buf_to_put = NULL; + } + return 0; +} + +static struct vframe_s *recv_common_dequeue_frame( + struct video_recv_s *ins) +{ + struct vframe_s *vf = NULL; + + if (!ins) { + pr_err("recv_common_dequeue_frame error, empty ins\n"); + return NULL; + } + + vf = common_vf_peek(ins); +/* FIXME: chek if need enable */ +#ifdef ENABLE_DV /* CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION */ + if ((glayer_info[0].display_path_id == ins->path_id) && vf && + is_dolby_vision_enable()) { + dolby_vision_check_hdr10(vf); + dolby_vision_check_hdr10plus(vf); + dolby_vision_check_hlg(vf); + } +#endif + while (vf) { + if (!vf->frame_dirty) { +#ifdef ENABLE_DV /* CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION */ + if ((glayer_info[0].display_path_id == ins->path_id) && + dolby_vision_need_wait_common(ins)) + break; +#endif + vf = common_vf_get(ins); + if (vf) + common_toggle_frame(ins, vf); + } else { + vf = common_vf_get(ins); + if (vf) + common_vf_put(ins, vf); + } + vf = common_vf_peek(ins); + } + return vf; +} + +static s32 recv_common_return_frame( + struct video_recv_s *ins, struct vframe_s *vf) +{ + if (!ins) { + pr_err("recv_common_return_frame error, empty ins\n"); + return -1; + } + if (vf) + common_vf_put(ins, vf); + return 0; +} + +static s32 recv_common_late_proc( + struct video_recv_s *ins) +{ + if (!ins) { + pr_err("recv_common_late_proc error, empty ins\n"); + return -1; + } +#ifdef CONFIG_AMLOGIC_MEDIA_VSYNC_RDMA + ins->rdma_buf = ins->cur_buf; +#endif + return 0; +} + +const struct recv_func_s recv_common_ops = { + .early_proc = recv_common_early_process, + .dequeue_frame = recv_common_dequeue_frame, + .return_frame = recv_common_return_frame, + .late_proc = recv_common_late_proc, +}; + +struct video_recv_s *create_video_receiver(const char *recv_name, u8 path_id) +{ + struct video_recv_s *ins = NULL; + + if (!recv_name) { + pr_err("create_video_receiver: recv_name is NULL.\n"); + goto CREATE_FAIL; + } + ins = kmalloc(sizeof(*ins), GFP_KERNEL); + if (!ins) + goto CREATE_FAIL; + + memset(ins, 0, sizeof(struct video_recv_s)); + ins->recv_name = (char *)recv_name; + ins->vf_ops = (struct vframe_receiver_op_s *)&common_recv_func; + ins->func = (struct recv_func_s *)&recv_common_ops; + ins->path_id = path_id; + spin_lock_init(&ins->lock); + vf_receiver_init( + &ins->handle, + ins->recv_name, + ins->vf_ops, ins); + if (vf_reg_receiver(&ins->handle)) { + pr_err( + "create_video_receiver %s: reg recv fail\n", + recv_name); + goto CREATE_FAIL; + } + pr_info( + "create_video_receiver %s %p, path_id:%d success\n", + recv_name, ins, ins->path_id); + return ins; +CREATE_FAIL: + kfree(ins); + return NULL; +} + +void destroy_video_receiver(struct video_recv_s *ins) +{ + if (!ins) { + pr_err("destroy_video_receiver: ins is NULL.\n"); + return; + } + vf_unreg_receiver(&ins->handle); + kfree(ins); + pr_info("destroy_video_receiver\n"); +} diff --git a/drivers/amlogic/media/video_sink/video_receiver.h b/drivers/amlogic/media/video_sink/video_receiver.h new file mode 100644 index 000000000000..51f0b9223e25 --- /dev/null +++ b/drivers/amlogic/media/video_sink/video_receiver.h @@ -0,0 +1,56 @@ +/* + * drivers/amlogic/media/video_sink/video_receiver.h + * + * Copyright (C) 2017 Amlogic, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +#ifndef VIDEO_RECEIVER_HEADER_HH +#define VIDEO_RECEIVER_HEADER_HH + +#include + +struct video_layer_s; + +struct recv_func_s { + s32 (*early_proc)(struct video_recv_s *ins); + struct vframe_s *(*dequeue_frame)(struct video_recv_s *ins); + s32 (*return_frame)(struct video_recv_s *ins, struct vframe_s *vf); + s32 (*late_proc)(struct video_recv_s *ins); +}; + +struct video_recv_s { + char *recv_name; + /* recv lock */ + spinlock_t lock; + struct vframe_receiver_s handle; + struct vframe_receiver_op_s *vf_ops; + struct vframe_s local_buf; + struct vframe_s *cur_buf; + struct vframe_s *rdma_buf; + struct vframe_s *buf_to_put; + + bool active; + + u32 notify_flag; + u32 blackout; + u32 frame_count; + u32 drop_vf_cnt; + u8 path_id; + struct recv_func_s *func; +}; + +struct video_recv_s *create_video_receiver(const char *recv_name, u8 path_id); +void destroy_video_receiver(struct video_recv_s *ins); + +#endif diff --git a/include/linux/amlogic/major.h b/include/linux/amlogic/major.h index d385f8887127..459850e21645 100644 --- a/include/linux/amlogic/major.h +++ b/include/linux/amlogic/major.h @@ -32,6 +32,8 @@ #define IONVIDEO_MAJOR (15+(AML_BASE)) #define VAD_MAJOR (16+(AML_BASE)) #define VIDEOSYNC_MAJOR (17+(AML_BASE)) +#define V4LVIDEO_MAJOR (18 + (AML_BASE)) +#define VIDEO_COMPOSER_MAJOR (19 + (AML_BASE)) /* *#define UIO_MAJOR 4+(AML_BASE) *#define USB_DEV_EP_MAJOR 5+(AML_BASE) diff --git a/include/linux/amlogic/media/utils/amstream.h b/include/linux/amlogic/media/utils/amstream.h index a684bf5b2e39..c13843daebdb 100644 --- a/include/linux/amlogic/media/utils/amstream.h +++ b/include/linux/amlogic/media/utils/amstream.h @@ -278,6 +278,7 @@ enum FRAME_BASE_VIDEO_PATH { FRAME_BASE_PATH_V4L_VIDEO, FRAME_BASE_PATH_TUNNEL_MODE, FRAME_BASE_PATH_V4L_OSD, + FRAME_BASE_PATH_DI_V4LVIDEO, FRAME_BASE_PATH_MAX }; diff --git a/include/linux/amlogic/media/vfm/vframe.h b/include/linux/amlogic/media/vfm/vframe.h index f801aa94a461..04de43d4b1cc 100644 --- a/include/linux/amlogic/media/vfm/vframe.h +++ b/include/linux/amlogic/media/vfm/vframe.h @@ -84,7 +84,13 @@ #define VFRAME_FLAG_ERROR_RECOVERY 8 #define VFRAME_FLAG_SYNCFRAME 0x10 #define VFRAME_FLAG_GAME_MODE 0x20 +#define VFRAME_FLAG_VIDEO_COMPOSER 0x40 +#define VFRAME_FLAG_VIDEO_COMPOSER_BYPASS 0x80 +#define VFRAME_FLAG_COMPOSER_DONE 0x100 +#define VFRAME_FLAG_VIDEO_COMPOSER_DMA 0x200 +#define VFRAME_FLAG_VIDEO_LINEAR 0x400 #define VFRAME_FLAG_EMPTY_FRAME_V4L 0x800 +#define VFRAME_FLAG_FAKE_FRAME 0x1000 enum pixel_aspect_ratio_e { PIXEL_ASPECT_RATIO_1_1, @@ -405,6 +411,7 @@ struct vframe_s { long long ready_clock[5];/*ns*/ long long ready_clock_hist[2];/*ns*/ atomic_t use_cnt; + atomic_t use_cnt_pip; u32 frame_dirty; /* *prog_proc_config: @@ -428,6 +435,7 @@ struct vframe_s { u32 sar_width; u32 sar_height; + /***************** * di pulldown info * bit 3: interlace @@ -437,6 +445,12 @@ struct vframe_s { *****************/ u32 di_pulldown; u32 di_gmv; + u32 axis[4]; + u32 crop[4]; + u32 zorder; + u32 repeat_count[2]; + struct file *file_vf; + bool rendered; } /*vframe_t */; #if 0 diff --git a/include/linux/amlogic/media/video_processor/video_composer_ext.h b/include/linux/amlogic/media/video_processor/video_composer_ext.h new file mode 100644 index 000000000000..57ef9e1bce29 --- /dev/null +++ b/include/linux/amlogic/media/video_processor/video_composer_ext.h @@ -0,0 +1,35 @@ +/* + * include/linux/amlogic/media/video_processor/video_composer_ext.h + * + * Copyright (C) 2017 Amlogic, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +#ifndef VIDEO_COMPOSER_EXT_H +#define VIDEO_COMPOSER_EXT_H + +#include + +struct composer_dst { + dma_addr_t phy_addr; + u32 buffer_width; + u32 buffer_height; + u32 content_left; + u32 content_top; + u32 content_w; + u32 content_h; + u32 format; +}; + +#endif /* VIDEO_COMPOSER_EXT_H */ + diff --git a/include/linux/amlogic/media/video_sink/v4lvideo_ext.h b/include/linux/amlogic/media/video_sink/v4lvideo_ext.h new file mode 100644 index 000000000000..52d9127cc6f7 --- /dev/null +++ b/include/linux/amlogic/media/video_sink/v4lvideo_ext.h @@ -0,0 +1,46 @@ +/* + * include/linux/amlogic/media/video_sink/v4lvideo_ext.h + * + * Copyright (C) 2017 Amlogic, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +#ifndef V4LVIDEO_EXT_H +#define V4LVIDEO_EXT_H + +int v4lvideo_assign_map(char **receiver_name, int *inst); + +int v4lvideo_alloc_map(int *inst); + +void v4lvideo_release_map(int inst); + +struct file_private_data { + struct vframe_s vf; + struct vframe_s *vf_p; + bool is_keep; + int keep_id; + int keep_head_id; + struct file *file; +}; + +struct v4l_data_t { + struct vframe_s *vf; + char *dst_addr; +}; + +void v4lvideo_data_copy(struct v4l_data_t *v4l_data); +struct vframe_s *v4lvideo_get_vf(int fd); +void dim_post_keep_cmd_release2(struct vframe_s *vframe); + +#endif /* V4LVIDEO_EXT_H */ + diff --git a/include/linux/amlogic/media/video_sink/video.h b/include/linux/amlogic/media/video_sink/video.h index a9b3c6046110..ce28fd1b8739 100644 --- a/include/linux/amlogic/media/video_sink/video.h +++ b/include/linux/amlogic/media/video_sink/video.h @@ -260,4 +260,14 @@ void DI_POST_UPDATE_MC(void); extern void videosync_pcrscr_update(s32 inc, u32 base); void vsync_notify_videosync(void); +void vsync_notify_video_composer(void); +int _video_set_disable(u32 val); +int _videopip_set_disable(u32 val); +void video_set_global_output(u32 index, u32 val); +u32 video_get_layer_capability(void); +void set_video_crop_ext(int layer_index, int *p); +void set_video_window_ext(int layer_index, int *p); +void set_video_zorder_ext(int layer_index, int zorder); +s32 set_video_path_select(const char *recv_name, u8 layer_id); + #endif /* VIDEO_H */