M: Brian Zhu <brian.zhu@amlogic.com>
F: drivers/amlogic/media/video_sink/video_hw.c
+AMLOGIC T962X3 DRM DTS
+M: Dezhi Kong <dezhi.kong@amlogic.com>
+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 <jintao.xu@amlogic.com>
+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 <brian.zhu@amlogic.com>
+F: drivers/amlogic/media/video_sink/video_receiver.c
+F: drivers/amlogic/media/video_sink/video_receiver.h
* 10x4736064=45.2M(0x2e) support 12bit
* 10x4074560=40M(0x28) support 10bit
*/
- size = <0x02800000>;
+ //size = <0x02800000>;
+ size = <0x05800000>;
alignment = <0x400000>;
};
/* POST PROCESS MANAGER */
compatible = "shared-dma-pool";
reusable;
/* ion_codec_mm max can alloc size 80M*/
- size = <0x13400000>;
+ size = <0x16400000>;
alignment = <0x400000>;
linux,contiguous-region;
};
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>;
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";
* 10x4736064=45.2M(0x2e) support 12bit
* 10x4074560=40M(0x28) support 10bit
*/
- size = <0x02800000>;
+ //size = <0x02800000>;
+ size = <0x05800000>;
alignment = <0x400000>;
alloc-ranges = <0x30000000 0x10000000>;
};
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>;
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";
* 10x4736064=45.2M(0x2e) support 12bit
* 10x4074560=40M(0x28) support 10bit
*/
- size = <0x02800000>;
+ //size = <0x02800000>;
+ size = <0x05800000>;
alignment = <0x400000>;
};
/* POST PROCESS MANAGER */
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>;
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";
status = "okay";
};
+ video_composer {
+ compatible = "amlogic, video_composer";
+ dev_name = "video_composer";
+ status = "okay";
+ };
+
amvenc_avc{
compatible = "amlogic, amvenc_avc";
dev_name = "amvenc_avc";
status = "okay";
};
+ video_composer {
+ compatible = "amlogic, video_composer";
+ dev_name = "video_composer";
+ status = "okay";
+ };
+
amvenc_avc{
compatible = "amlogic, amvenc_avc";
dev_name = "amvenc_avc";
status = "okay";
};
+ video_composer {
+ compatible = "amlogic, video_composer";
+ dev_name = "video_composer";
+ status = "okay";
+ };
+
amvenc_avc{
compatible = "amlogic, amvenc_avc";
dev_name = "amvenc_avc";
status = "okay";
};
+ video_composer {
+ compatible = "amlogic, video_composer";
+ dev_name = "video_composer";
+ status = "okay";
+ };
+
amvenc_avc{
compatible = "amlogic, amvenc_avc";
dev_name = "amvenc_avc";
* 10x4736064=45.2M(0x2e) support 12bit
* 10x4074560=40M(0x28) support 10bit
*/
- size = <0x02800000>;
+ size = <0x05800000>;
alignment = <0x400000>;
};
/* POST PROCESS MANAGER */
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>;
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>;
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";
* 10x4736064=45.2M(0x2e) support 12bit
* 10x4074560=40M(0x28) support 10bit
*/
- size = <0x02800000>;
+ size = <0x05800000>;
alignment = <0x400000>;
};
/* POST PROCESS MANAGER */
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>;
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>;
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";
* 10x4736064=45.2M(0x2e) support 12bit
* 10x4074560=40M(0x28) support 10bit
*/
- size = <0x02800000>;
+ size = <0x05800000>;
alignment = <0x400000>;
};
/* POST PROCESS MANAGER */
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>;
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";
* 10x4736064=45.2M(0x2e) support 12bit
* 10x4074560=40M(0x28) support 10bit
*/
- size = <0x02800000>;
+ size = <0x05800000>;
alignment = <0x400000>;
};
/* POST PROCESS MANAGER */
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>;
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>;
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";
* 10x4736064=45.2M(0x2e) support 12bit
* 10x4074560=40M(0x28) support 10bit
*/
- size = <0x02800000>;
+ size = <0x05800000>;
alignment = <0x400000>;
};
/* POST PROCESS MANAGER */
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>;
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>;
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";
* 10x4736064=45.2M(0x2e) support 12bit
* 10x4074560=40M(0x28) support 10bit
*/
- size = <0x02800000>;
+ size = <0x05800000>;
alignment = <0x400000>;
};
/* POST PROCESS MANAGER */
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>;
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>;
* 10x4736064=45.2M(0x2e) support 12bit
* 10x4074560=40M(0x28) support 10bit
*/
- size = <0x02800000>;
+ size = <0x05800000>;
alignment = <0x400000>;
};
/* POST PROCESS MANAGER */
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>;
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>;
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";
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
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
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
* 10x4736064=45.2M(0x2e) support 12bit
* 10x4074560=40M(0x28) support 10bit
*/
- size = <0x0 0x02800000>;
+ size = <0x0 0x05800000>;
alignment = <0x0 0x400000>;
};
/* POST PROCESS MANAGER */
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;
};
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>;
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";
* 10x4736064=45.2M(0x2e) support 12bit
* 10x4074560=40M(0x28) support 10bit
*/
- size = <0x0 0x02800000>;
+ size = <0x0 0x05800000>;
alignment = <0x0 0x400000>;
};
/* POST PROCESS MANAGER */
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>;
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";
* 10x4736064=45.2M(0x2e) support 12bit
* 10x4074560=40M(0x28) support 10bit
*/
- size = <0x0 0x02800000>;
+ size = <0x0 0x05800000>;
alignment = <0x0 0x400000>;
};
/* POST PROCESS MANAGER */
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;
};
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";
status = "okay";
};
+ video_composer {
+ compatible = "amlogic, video_composer";
+ dev_name = "video_composer";
+ status = "okay";
+ };
+
amvenc_avc{
compatible = "amlogic, amvenc_avc";
dev_name = "amvenc_avc";
status = "okay";
};
+ video_composer {
+ compatible = "amlogic, video_composer";
+ dev_name = "video_composer";
+ status = "okay";
+ };
+
amvenc_avc{
compatible = "amlogic, amvenc_avc";
dev_name = "amvenc_avc";
status = "okay";
};
+ video_composer {
+ compatible = "amlogic, video_composer";
+ dev_name = "video_composer";
+ status = "okay";
+ };
+
amvenc_avc{
compatible = "amlogic, amvenc_avc";
dev_name = "amvenc_avc";
status = "okay";
};
+ video_composer {
+ compatible = "amlogic, video_composer";
+ dev_name = "video_composer";
+ status = "okay";
+ };
+
amvenc_avc{
compatible = "amlogic, amvenc_avc";
dev_name = "amvenc_avc";
* 10x4736064=45.2M(0x2e) support 12bit
* 10x4074560=40M(0x28) support 10bit
*/
- size = <0x0 0x02800000>;
+ size = <0x0 0x05800000>;
alignment = <0x0 0x400000>;
};
/* POST PROCESS MANAGER */
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;
};
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>;
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";
* 10x4736064=45.2M(0x2e) support 12bit
* 10x4074560=40M(0x28) support 10bit
*/
- size = <0x0 0x02800000>;
+ size = <0x0 0x05800000>;
alignment = <0x0 0x400000>;
};
/* POST PROCESS MANAGER */
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;
};
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>;
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";
* 10x4736064=45.2M(0x2e) support 12bit
* 10x4074560=40M(0x28) support 10bit
*/
- size = <0x0 0x02800000>;
+ size = <0x0 0x05800000>;
alignment = <0x0 0x400000>;
};
/* POST PROCESS MANAGER */
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>;
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";
* 10x4736064=45.2M(0x2e) support 12bit
* 10x4074560=40M(0x28) support 10bit
*/
- size = <0x0 0x02800000>;
+ size = <0x0 0x05800000>;
alignment = <0x0 0x400000>;
};
/* POST PROCESS MANAGER */
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;
};
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";
* 10x4736064=45.2M(0x2e) support 12bit
* 10x4074560=40M(0x28) support 10bit
*/
- size = <0x0 0x02800000>;
+ size = <0x0 0x05800000>;
alignment = <0x0 0x400000>;
};
/* POST PROCESS MANAGER */
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;
};
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>;
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";
* 10x4736064=45.2M(0x2e) support 12bit
* 10x4074560=40M(0x28) support 10bit
*/
- size = <0x0 0x02800000>;
+ size = <0x0 0x05800000>;
alignment = <0x0 0x400000>;
};
/* POST PROCESS MANAGER */
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;
};
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>;
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";
* 10x4736064=45.2M(0x2e) support 12bit
* 10x4074560=40M(0x28) support 10bit
*/
- size = <0x0 0x02800000>;
+ size = <0x0 0x05800000>;
alignment = <0x0 0x400000>;
};
/* POST PROCESS MANAGER */
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;
};
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>;
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";
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
#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)
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)
/*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 */
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)) {
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);
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);
}
}
}
- 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);
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,
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;
}
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();
/*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;
}
#ifdef CONFIG_CMA
di_cma_release(de_devp, ch);
-
#endif
return true;
}
+#ifdef DIM_HIS /*no use*/
/*******************************************
*
*
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)
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;
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;
}
}
return 0;
}
+#ifdef DIM_HIS /*no use*/
void dim_keep_mirror_buffer(unsigned int channel) /*not use*/
{
struct di_buf_s *p = NULL;
}
}
}
+#endif
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;*/
}
#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*/
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__);
#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);
/*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);
}
}
/**************************/
- 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;
}
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);
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) {
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",
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)
}
/**************************/
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);
/* 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
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);
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);
/*---------------------*/
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*/
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 */
/********************************/
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);
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);
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
}
}
eDI_CFG_BEGIN,
eDI_CFG_first_bypass,
eDI_CFG_ref_2,
+ EDI_CFG_KEEP_CLEAR_AUTO,
eDI_CFG_END,
};
/**************************************/
/* 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.
};
#define LCMD1(id, ch) ((id) | ((ch) << 8))
+#define LCMD2(id, ch, p2) ((id) | ((ch) << 8) | ((p2) << 16))
enum eCMD_LOCAL {
eCMD_NONE,
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,
};
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,
};
/**********************************
/*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];
#define DBG_M_POLLING 0x100
#define DBG_M_ONCE 0x200
+#define DBG_M_KEEP 0x400
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);
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
**************************************************************/
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);
{"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[] = {
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},
};
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;
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;
}
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__);
}
{
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__);
}
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)
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;
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;
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;
}
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;
}
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();
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;
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);
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;
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()) {
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;
set_flag_trig_unreg(ch, true);
switch (chst) {
- case eDI_TOP_STATE_READY:
+ case EDI_TOP_STATE_READY:
di_vframe_unreg(ch);
/*trig unreg*/
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);*/
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;
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);*/
dpost_init();
}
- dip_chst_set(ch, eDI_TOP_STATE_IDLE);
+ dip_chst_set(ch, EDI_TOP_STATE_IDLE);
ret = true;
break;
/*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()) {
/*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;
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);
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);
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:
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;
}
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);
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;
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;
}
}
}
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);
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 = "";
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__);
/*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));
/*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);
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);
/**************************************
*
"QUE_POST_FREE", /*2*/
"QUE_POST_READY", /*3*/
"QUE_POST_BACK", /*4*/
+ "QUE_POST_KEEP",
+ "QUE_POST_KEEP_BACK",
"QUE_DBG",
/* "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);
return false;
}
+/**********************************************************
+ *
+ **********************************************************/
int di_que_list_count(unsigned int ch, enum QUE_TYPE qtype)
{
struct di_ch_s *pch = get_chdata(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)
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)
{
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*/
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,
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__);
unregister_chrdev_region(di_pdev->devno, DI_COUNT);
fail_alloc_cdev_region:
kfree(di_pdev);
+ di_pdev = NULL;
fail_kmalloc_dev:
return ret;
#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;
}
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();
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);
}
}
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
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/
{
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;
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;
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;
--- /dev/null
+#
+# 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
--- /dev/null
+asflags-y=-mfloat-abi=softfp -mfpu=neon
+ccflags-y += -Idrivers/staging/android/ion
+
+obj-$(CONFIG_AMLOGIC_V4L_VIDEO3) += v4lvideo.o
--- /dev/null
+/*
+ * 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 <linux/amlogic/media/vout/vout_notify.h>
+#include <linux/amlogic/media/vfm/vframe.h>
+#include <linux/amlogic/media/vfm/vframe_provider.h>
+#include <linux/amlogic/media/vfm/vframe_receiver.h>
+#include "v4lvideo.h"
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-v4l2.h>
+#include <linux/platform_device.h>
+#include <linux/amlogic/major.h>
+#include <linux/amlogic/media/codec_mm/codec_mm.h>
+#include <linux/amlogic/media/codec_mm/codec_mm_keeper.h>
+#include <linux/amlogic/media/utils/amstream.h>
+#include <linux/amlogic/media/video_sink/video_keeper.h>
+#include <linux/anon_inodes.h>
+#include <linux/file.h>
+#include <linux/amlogic/media/canvas/canvas_mgr.h>
+
+#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<jintao.xu@amlogic.com>");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_VERSION(V4LVIDEO_VERSION);
+
+module_init(v4lvideo_init);
+module_exit(v4lvideo_exit);
--- /dev/null
+/*
+ * 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 <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/videodev2.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/delay.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-common.h>
+
+#include <linux/mm.h>
+/* #include <mach/mod_gate.h> */
+
+#include <linux/amlogic/media/vfm/vframe.h>
+#include <linux/amlogic/media/vfm/vframe_provider.h>
+#include <linux/amlogic/media/vfm/vframe_receiver.h>
+#include <linux/amlogic/media/ge2d/ge2d.h>
+#include <linux/amlogic/media/canvas/canvas.h>
+
+#include <linux/amlogic/media/frame_sync/timestamp.h>
+#include <linux/amlogic/media/frame_sync/tsync.h>
+#include <linux/amlogic/media/video_sink/v4lvideo_ext.h>
+
+#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
--- /dev/null
+#
+# 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
--- /dev/null
+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
--- /dev/null
+/*
+ * 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_ */
--- /dev/null
+/*
+ * 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 <linux/amlogic/media/ge2d/ge2d.h>
+#include <linux/amlogic/media/canvas/canvas.h>
+#include <linux/amlogic/media/canvas/canvas_mgr.h>
+#include <linux/amlogic/media/utils/amlog.h>
+#include <linux/amlogic/media/ge2d/ge2d_func.h>
+#include "vframe_ge2d_composer.h"
+#include "vfq.h"
+#include <linux/amlogic/cpu_version.h>
+#include <linux/mm.h>
+#include <linux/file.h>
+#include <linux/delay.h>
+
+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;
+}
+
--- /dev/null
+/*
+ * 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 <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/amlogic/media/vout/vout_notify.h>
+#include <linux/amlogic/media/vfm/vframe.h>
+//#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
--- /dev/null
+/*
+ * 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 <linux/amlogic/major.h>
+#include <linux/platform_device.h>
+#include <linux/time.h>
+#include <linux/uaccess.h>
+#include <linux/file.h>
+#include <linux/amlogic/media/video_sink/video.h>
+#include <linux/amlogic/aml_sync_api.h>
+#include <linux/amlogic/media/canvas/canvas.h>
+#include <linux/amlogic/media/canvas/canvas_mgr.h>
+#include <linux/amlogic/media/codec_mm/codec_mm.h>
+#include <linux/dma-buf.h>
+#include <ion/ion.h>
+#include <ion/ion_priv.h>
+#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<jintao.xu@amlogic.com>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(VIDEO_COMPOSER_VERSION);
+
+module_init(video_composer_module_init);
+module_exit(video_composer_module_exit);
--- /dev/null
+/*
+ * 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 <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/videodev2.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/delay.h>
+#include <linux/amlogic/media/video_processor/video_composer_ext.h>
+#include <linux/amlogic/media/vout/vout_notify.h>
+#include <linux/amlogic/media/vfm/vframe.h>
+#include <linux/amlogic/media/vfm/vframe_provider.h>
+#include <linux/amlogic/media/vfm/vframe_receiver.h>
+#include <linux/amlogic/media/vfm/vfm_ext.h>
+
+#include <linux/kfifo.h>
+#include <linux/amlogic/media/video_sink/v4lvideo_ext.h>
+#include <linux/dma-mapping.h>
+#include <linux/dma-mapping.h>
+#include <linux/dma-contiguous.h>
+#include "vfq.h"
+#include <linux/amlogic/media/ge2d/ge2d.h>
+#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 */
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
#endif
#include <linux/math64.h>
+#include "video_receiver.h"
+
static int get_count;
static int get_count_pip;
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)
#else
static u32 blackout = 1;
#endif
-static u32 force_blackout;
+u32 force_blackout;
static u32 blackout_pip;
/* disable video */
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;
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
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())
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;
/* 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;
layer_info);
dvel_status = true;
} else if (dvel_status) {
- //safe_switch_videolayer(1, false, true);
dvel_changed = true;
dvel_status = false;
dvel_size = 0;
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)
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);
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)
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);
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) {
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(
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();
}
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;
}
}
+ vsync_notify_video_composer();
+
#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
if (is_dolby_vision_enable() && dovi_drop_flag) {
struct vframe_s *vf = NULL;
#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);
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) {
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) {
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;
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
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);
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) {
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) ||
(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) {
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);
}
#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)
(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) {
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(
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);
}
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;
/* 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 &&
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)
{
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:
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;
/* 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 &&
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,
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(
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));
#include <linux/amlogic/media/video_sink/video.h>
#include "../common/vfm/vfm.h"
#include <linux/amlogic/media/amdolbyvision/dolby_vision.h>
+#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];
spin_unlock_irqrestore(&delay_work_lock, flags); \
} \
} while (0)
-
+#ifdef DI_POST_PWR
#define VD1_MEM_POWER_ON() \
do { \
unsigned long flags; \
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; \
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;
(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;
}
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;
/* 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,
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);
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");
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;
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(
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,
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(
(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(
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);
} 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())
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,
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)
} 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())
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)
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)
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 */
} 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;
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;
#ifdef CONFIG_AMLOGIC_MEDIA_DEINTERLACE
if ((layer_id == 0) &&
+ is_di_post_mode(vf) &&
is_di_post_link_on())
update_mif = false;
#endif
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,
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));
#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
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
};
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);
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);
--- /dev/null
+/*
+ * 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 <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/ctype.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+#ifdef CONFIG_AMLOGIC_MEDIA_VSYNC_RDMA
+#include "../common/rdma/rdma.h"
+#endif
+#include <linux/amlogic/media/vfm/vframe.h>
+#include <linux/amlogic/media/vfm/vframe_provider.h>
+#include <linux/amlogic/media/vfm/vframe_receiver.h>
+#include <linux/amlogic/media/video_sink/vpp.h>
+#include <linux/amlogic/media/video_sink/video.h>
+
+#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");
+}
--- /dev/null
+/*
+ * 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 <linux/amlogic/media/vfm/vframe.h>
+
+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
#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)
FRAME_BASE_PATH_V4L_VIDEO,
FRAME_BASE_PATH_TUNNEL_MODE,
FRAME_BASE_PATH_V4L_OSD,
+ FRAME_BASE_PATH_DI_V4LVIDEO,
FRAME_BASE_PATH_MAX
};
#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,
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:
u32 sar_width;
u32 sar_height;
+
/*****************
* di pulldown info
* bit 3: interlace
*****************/
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
--- /dev/null
+/*
+ * 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 <linux/amlogic/media/vfm/vframe.h>
+
+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 */
+
--- /dev/null
+/*
+ * 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 */
+
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 */