From 4dafe9905ea05fd91c00ab84ac74f448fe874978 Mon Sep 17 00:00:00 2001 From: Pengcheng Chen Date: Tue, 24 Jan 2017 13:06:19 +0800 Subject: [PATCH] media: add osd & ge2d driver PD#138714: add osd & ge2d driver Change-Id: I70c0e1e2b5e29a158b8a41e27bbc4db2fd49bb9a Signed-off-by: Pengcheng Chen --- MAINTAINERS | 19 + arch/arm64/boot/dts/amlogic/gxl_p212_1g.dts | 40 +- arch/arm64/boot/dts/amlogic/gxl_p212_2g.dts | 39 +- arch/arm64/boot/dts/amlogic/gxm_q200_2g.dts | 44 +- arch/arm64/boot/dts/amlogic/gxm_skt.dts | 38 + arch/arm64/configs/meson64_defconfig | 7 + drivers/amlogic/clk/clk_media.c | 2 + drivers/amlogic/media/Kconfig | 3 + drivers/amlogic/media/Makefile | 3 + drivers/amlogic/media/common/Kconfig | 3 +- drivers/amlogic/media/common/Makefile | 2 +- drivers/amlogic/media/common/ge2d/Kconfig | 2 +- drivers/amlogic/media/common/ge2d/Makefile | 3 +- drivers/amlogic/media/common/ge2d/blend.c | 116 + drivers/amlogic/media/common/ge2d/ge2d_hw.c | 46 +- drivers/amlogic/media/common/ge2d/ge2d_io.h | 25 +- drivers/amlogic/media/common/ge2d/ge2d_main.c | 261 +- drivers/amlogic/media/common/ge2d/ge2d_wq.c | 176 +- drivers/amlogic/media/common/ge2d/ge2dgen.c | 8 +- .../amlogic/media/common/ion_dev/dev_ion.c | 1 + .../amlogic/media/common/ion_dev/meson_ion.h | 5 + drivers/amlogic/media/common/rdma/Kconfig | 2 +- drivers/amlogic/media/common/rdma/rdma_mgr.c | 30 +- drivers/amlogic/media/logo/Kconfig | 10 + drivers/amlogic/media/logo/Makefile | 4 + drivers/amlogic/media/logo/logo.c | 307 ++ drivers/amlogic/media/osd/Kconfig | 70 + drivers/amlogic/media/osd/Makefile | 10 + drivers/amlogic/media/osd/osd.h | 339 ++ drivers/amlogic/media/osd/osd_antiflicker.c | 197 + drivers/amlogic/media/osd/osd_antiflicker.h | 47 + drivers/amlogic/media/osd/osd_backup.c | 519 +++ drivers/amlogic/media/osd/osd_backup.h | 63 + drivers/amlogic/media/osd/osd_canvas.h | 27 + drivers/amlogic/media/osd/osd_clone.c | 205 + drivers/amlogic/media/osd/osd_clone.h | 50 + drivers/amlogic/media/osd/osd_debug.c | 465 +++ drivers/amlogic/media/osd/osd_fb.c | 2716 +++++++++++++ drivers/amlogic/media/osd/osd_fb.h | 78 + drivers/amlogic/media/osd/osd_hw.c | 3513 +++++++++++++++++ drivers/amlogic/media/osd/osd_hw.h | 148 + drivers/amlogic/media/osd/osd_hw_def.h | 140 + drivers/amlogic/media/osd/osd_io.h | 108 + drivers/amlogic/media/osd/osd_log.h | 61 + drivers/amlogic/media/osd/osd_progressbar.c | 252 ++ drivers/amlogic/media/osd/osd_prot.c | 125 + drivers/amlogic/media/osd/osd_prot.h | 59 + drivers/amlogic/media/osd/osd_rdma.c | 1120 ++++++ drivers/amlogic/media/osd/osd_rdma.h | 75 + drivers/amlogic/media/osd/osd_reg.h | 1379 +++++++ drivers/amlogic/media/osd/osd_sync.h | 30 + drivers/amlogic/media/osd_ext/Kconfig | 17 + drivers/amlogic/media/osd_ext/Makefile | 5 + drivers/amlogic/media/osd_ext/osd_clone.c | 193 + drivers/amlogic/media/osd_ext/osd_clone.h | 46 + drivers/amlogic/media/osd_ext/osd_fb.c | 1703 ++++++++ drivers/amlogic/media/osd_ext/osd_fb.h | 274 ++ drivers/amlogic/media/osd_ext/osd_hw.c | 2520 ++++++++++++ drivers/amlogic/media/osd_ext/osd_hw.h | 98 + drivers/amlogic/media/osd_ext/osd_hw_def.h | 108 + drivers/amlogic/media/osd_ext/osd_prot.c | 132 + drivers/amlogic/media/osd_ext/osd_prot.h | 57 + drivers/amlogic/media/video_sink/video_priv.h | 4 +- include/linux/amlogic/display/vinfo.h | 66 - include/linux/amlogic/media/ge2d/ge2d.h | 8 + include/linux/amlogic/media/ge2d/ge2d_cmd.h | 8 +- include/linux/amlogic/media/ge2d/ge2d_func.h | 11 + include/linux/amlogic/media/rdma/rdma_mgr.h | 2 + .../amlogic/media/video_sink/video/video.h | 2 +- .../linux/amlogic/media/vout/vout_notify.h | 2 +- 70 files changed, 18063 insertions(+), 185 deletions(-) create mode 100644 drivers/amlogic/media/logo/Kconfig create mode 100644 drivers/amlogic/media/logo/Makefile create mode 100644 drivers/amlogic/media/logo/logo.c create mode 100644 drivers/amlogic/media/osd/Kconfig create mode 100644 drivers/amlogic/media/osd/Makefile create mode 100644 drivers/amlogic/media/osd/osd.h create mode 100644 drivers/amlogic/media/osd/osd_antiflicker.c create mode 100644 drivers/amlogic/media/osd/osd_antiflicker.h create mode 100644 drivers/amlogic/media/osd/osd_backup.c create mode 100644 drivers/amlogic/media/osd/osd_backup.h create mode 100644 drivers/amlogic/media/osd/osd_canvas.h create mode 100644 drivers/amlogic/media/osd/osd_clone.c create mode 100644 drivers/amlogic/media/osd/osd_clone.h create mode 100644 drivers/amlogic/media/osd/osd_debug.c create mode 100644 drivers/amlogic/media/osd/osd_fb.c create mode 100644 drivers/amlogic/media/osd/osd_fb.h create mode 100644 drivers/amlogic/media/osd/osd_hw.c create mode 100644 drivers/amlogic/media/osd/osd_hw.h create mode 100644 drivers/amlogic/media/osd/osd_hw_def.h create mode 100644 drivers/amlogic/media/osd/osd_io.h create mode 100644 drivers/amlogic/media/osd/osd_log.h create mode 100644 drivers/amlogic/media/osd/osd_progressbar.c create mode 100644 drivers/amlogic/media/osd/osd_prot.c create mode 100644 drivers/amlogic/media/osd/osd_prot.h create mode 100644 drivers/amlogic/media/osd/osd_rdma.c create mode 100644 drivers/amlogic/media/osd/osd_rdma.h create mode 100644 drivers/amlogic/media/osd/osd_reg.h create mode 100644 drivers/amlogic/media/osd/osd_sync.h create mode 100644 drivers/amlogic/media/osd_ext/Kconfig create mode 100644 drivers/amlogic/media/osd_ext/Makefile create mode 100644 drivers/amlogic/media/osd_ext/osd_clone.c create mode 100644 drivers/amlogic/media/osd_ext/osd_clone.h create mode 100644 drivers/amlogic/media/osd_ext/osd_fb.c create mode 100644 drivers/amlogic/media/osd_ext/osd_fb.h create mode 100644 drivers/amlogic/media/osd_ext/osd_hw.c create mode 100644 drivers/amlogic/media/osd_ext/osd_hw.h create mode 100644 drivers/amlogic/media/osd_ext/osd_hw_def.h create mode 100644 drivers/amlogic/media/osd_ext/osd_prot.c create mode 100644 drivers/amlogic/media/osd_ext/osd_prot.h delete mode 100644 include/linux/amlogic/display/vinfo.h diff --git a/MAINTAINERS b/MAINTAINERS index 0c80bbaff6de..4e10b1d7c82a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13540,3 +13540,22 @@ AMLOGIC driver for vout M: Evoke Zhang F: drivers/amlogic/dispaly/* +AMLOGIC ION device +M: Simon Zheng +F: drivers/amlogic/media/common/ion_dev/* + +AMLOGIC multimedia osd & ge2d +M: Pengcheng Chen +F: drivers/amlogic/media/osd/* +F: drivers/amlogic/media/osd_ext/* +F: drivers/amlogic/media/logo/* +F: drivers/amlogic/media/common/ge2d/* +F: include/linux/amlogic/media/ge2d/* +F: arch/arm64/configs/meson64_defconfig +F: drivers/amlogic/media/Kconfig +F: drivers/amlogic/media/Makefile +F: arch/arm64/boot/dts/amlogic/gxl_p212_1g.dts +F: arch/arm64/boot/dts/amlogic/gxl_p212_2g.dts +F: arch/arm64/boot/dts/amlogic/gxm_q200_2g.dts +F: drivers/amlogic/clk/clk_media.c +F: include/linux/amlogic/media/vout/vout_notify.h diff --git a/arch/arm64/boot/dts/amlogic/gxl_p212_1g.dts b/arch/arm64/boot/dts/amlogic/gxl_p212_1g.dts index 48a66b18c255..f625cf4892cb 100644 --- a/arch/arm64/boot/dts/amlogic/gxl_p212_1g.dts +++ b/arch/arm64/boot/dts/amlogic/gxl_p212_1g.dts @@ -306,8 +306,46 @@ "mailbox_1", "mailbox_2"; }; -}; + meson-fb { + compatible = "amlogic, meson-fb"; + memory-region = <&fb_reserved>; + dev_name = "meson-fb"; + status = "okay"; + interrupts = <0 3 1 + 0 89 1>; + interrupt-names = "viu-vsync", "rdma"; + mem_size = <0x01851000 0x00100000>; /* fb0/fb1 memory size */ + display_mode_default = "1080p60hz"; + scale_mode = <1>; + /** 0:VPU free scale 1:OSD free scale 2:OSD super scale */ + display_size_default = <1920 1080 1920 3240 32>; + /*1920*1080*4*3 = 0x17BB000*/ + logo_addr = "0x3d851000"; + /*ion base + fb0 memory size for uboot logo osd1*/ + }; + ge2d { + compatible = "amlogic, ge2d"; + dev_name = "ge2d"; + status = "okay"; + interrupts = <0 150 1>; + interrupt-names = "ge2d"; + clocks = <&clkc CLKID_VAPB_MUX>, + <&clkc CLKID_GE2D_GATE>, + <&clkc CLKID_G2D>; + clock-names = "clk_vapb_0", + "clk_ge2d", + "clk_ge2d_gate"; + }; + + rdma{ + compatible = "amlogic, meson, rdma"; + dev_name = "amlogic-rdma"; + status = "ok"; + interrupts = <0 89 1>; + interrupt-names = "rdma"; + }; +}; &efuse { status = "ok"; }; diff --git a/arch/arm64/boot/dts/amlogic/gxl_p212_2g.dts b/arch/arm64/boot/dts/amlogic/gxl_p212_2g.dts index c069eb91ed5d..b9589ecaa1ce 100644 --- a/arch/arm64/boot/dts/amlogic/gxl_p212_2g.dts +++ b/arch/arm64/boot/dts/amlogic/gxl_p212_2g.dts @@ -307,8 +307,45 @@ /*all channels use the default clock source XTAL_CLK*/ /*and you can shoose it in file dt-bindings/pwm/meson.h*/ }; -}; + meson-fb { + compatible = "amlogic, meson-fb"; + memory-region = <&fb_reserved>; + dev_name = "meson-fb"; + status = "okay"; + interrupts = <0 3 1 + 0 89 1>; + interrupt-names = "viu-vsync", "rdma"; + mem_size = <0x01851000 0x00100000>; /* fb0/fb1 memory size */ + display_mode_default = "1080p60hz"; + scale_mode = <1>; + /** 0:VPU free scale 1:OSD free scale 2:OSD super scale */ + display_size_default = <1920 1080 1920 3240 32>; + /*1920*1080*4*3 = 0x17BB000*/ + logo_addr = "0x3d851000"; + /*ion base + fb0 memory size for uboot logo osd1*/ + }; + ge2d { + compatible = "amlogic, ge2d"; + dev_name = "ge2d"; + status = "okay"; + interrupts = <0 150 1>; + interrupt-names = "ge2d"; + clocks = <&clkc CLKID_VAPB_MUX>, + <&clkc CLKID_GE2D_GATE>, + <&clkc CLKID_G2D>; + clock-names = "clk_vapb_0", + "clk_ge2d", + "clk_ge2d_gate"; + }; + rdma{ + compatible = "amlogic, meson, rdma"; + dev_name = "amlogic-rdma"; + status = "ok"; + interrupts = <0 89 1>; + interrupt-names = "rdma"; + }; +}; &efuse { status = "ok"; }; diff --git a/arch/arm64/boot/dts/amlogic/gxm_q200_2g.dts b/arch/arm64/boot/dts/amlogic/gxm_q200_2g.dts index 29a7f00376db..6922f2bf9939 100644 --- a/arch/arm64/boot/dts/amlogic/gxm_q200_2g.dts +++ b/arch/arm64/boot/dts/amlogic/gxm_q200_2g.dts @@ -61,6 +61,11 @@ reg = <0x0 0x07300000 0x0 0x100000>; no-map; }; + fb_reserved:linux,meson-fb { + compatible = "amlogic, fb-memory"; + size = <0x0 0x2000000>; + no-map; + }; di_reserved:linux,di { compatible = "amlogic, di-mem"; @@ -301,8 +306,45 @@ /*all channels use the default clock source XTAL_CLK*/ /*and you can shoose it in file dt-bindings/pwm/meson.h*/ }; -}; + meson-fb { + compatible = "amlogic, meson-fb"; + memory-region = <&fb_reserved>; + dev_name = "meson-fb"; + status = "okay"; + interrupts = <0 3 1 + 0 89 1>; + interrupt-names = "viu-vsync", "rdma"; + mem_size = <0x01851000 0x00100000>; /* fb0/fb1 memory size */ + display_mode_default = "1080p60hz"; + scale_mode = <1>; + /** 0:VPU free scale 1:OSD free scale 2:OSD super scale */ + display_size_default = <1920 1080 1920 3240 32>; + /*1920*1080*4*3 = 0x17BB000*/ + logo_addr = "0x3d851000"; + /*ion base + fb0 memory size for uboot logo osd1*/ + }; + ge2d { + compatible = "amlogic, ge2d"; + dev_name = "ge2d"; + status = "okay"; + interrupts = <0 150 1>; + interrupt-names = "ge2d"; + clocks = <&clkc CLKID_VAPB_MUX>, + <&clkc CLKID_GE2D_GATE>, + <&clkc CLKID_G2D>; + clock-names = "clk_vapb_0", + "clk_ge2d", + "clk_ge2d_gate"; + }; + rdma{ + compatible = "amlogic, meson, rdma"; + dev_name = "amlogic-rdma"; + status = "ok"; + interrupts = <0 89 1>; + interrupt-names = "rdma"; + }; +}; &efuse { status = "ok"; }; diff --git a/arch/arm64/boot/dts/amlogic/gxm_skt.dts b/arch/arm64/boot/dts/amlogic/gxm_skt.dts index 025b3862ce3f..7e7b687bdecf 100644 --- a/arch/arm64/boot/dts/amlogic/gxm_skt.dts +++ b/arch/arm64/boot/dts/amlogic/gxm_skt.dts @@ -207,6 +207,44 @@ dev_name = "cvbsout"; status = "okay"; }; + + meson-fb { + compatible = "amlogic, meson-fb"; + /* memory-region = <&fb_reserved>; */ + dev_name = "meson-fb"; + status = "okay"; + interrupts = <0 3 1 + 0 89 1>; + interrupt-names = "viu-vsync", "rdma"; + mem_size = <0x01851000 0x00100000>; /* fb0/fb1 memory size */ + display_mode_default = "1080p60hz"; + scale_mode = <1>; + /** 0:VPU free scale 1:OSD free scale 2:OSD super scale */ + display_size_default = <1920 1080 1920 3240 32>; + /*1920*1080*4*3 = 0x17BB000*/ + logo_addr = "0x3d851000"; + /*ion base + fb0 memory size for uboot logo osd1*/ + }; + ge2d { + compatible = "amlogic, ge2d"; + dev_name = "ge2d"; + status = "okay"; + interrupts = <0 150 1>; + interrupt-names = "ge2d"; + clocks = <&clkc CLKID_VAPB_MUX>, + <&clkc CLKID_GE2D_GATE>, + <&clkc CLKID_G2D>; + clock-names = "clk_vapb_0", + "clk_ge2d", + "clk_ge2d_gate"; + }; + rdma{ + compatible = "amlogic, meson, rdma"; + dev_name = "amlogic-rdma"; + status = "ok"; + interrupts = <0 89 1>; + interrupt-names = "rdma"; + }; }; &efuse { diff --git a/arch/arm64/configs/meson64_defconfig b/arch/arm64/configs/meson64_defconfig index 736f78e77a4a..6eaff5855c60 100644 --- a/arch/arm64/configs/meson64_defconfig +++ b/arch/arm64/configs/meson64_defconfig @@ -192,7 +192,9 @@ CONFIG_AMLOGIC_MEDIA_COMMON=y CONFIG_AMLOGIC_MEDIA_DRIVERS=y CONFIG_AMLOGIC_MEDIA_CODEC_MM=y CONFIG_AMLOGIC_MEDIA_CANVAS=y +CONFIG_AMLOGIC_MEDIA_GE2D=y CONFIG_AMLOGIC_ION=y +CONFIG_AMLOGIC_MEDIA_RDMA=y CONFIG_AMLOGIC_MEDIA_VFM=y CONFIG_AMLOGIC_VPU=y CONFIG_AMLOGIC_VOUT=y @@ -200,6 +202,10 @@ CONFIG_AMLOGIC_VOUT_SERVE=y CONFIG_AMLOGIC_CVBS_OUTPUT=y CONFIG_AMLOGIC_WSS=y CONFIG_AMLOGIC_VDAC=y +CONFIG_AMLOGIC_MEDIA_FB=y +CONFIG_AMLOGIC_MEDIA_FB_OSD_VSYNC_RDMA=y +CONFIG_AMLOGIC_MEDIA_FB_OSD2_ENABLE=y +CONFIG_AMLOGIC_MEDIA_FB_OSD2_CURSOR=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y @@ -263,6 +269,7 @@ CONFIG_MEDIA_CAMERA_SUPPORT=y CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y CONFIG_MEDIA_USB_SUPPORT=y CONFIG_USB_VIDEO_CLASS=y +CONFIG_FB=y CONFIG_UHID=y CONFIG_USB_HIDDEV=y CONFIG_USB_XHCI_HCD=y diff --git a/drivers/amlogic/clk/clk_media.c b/drivers/amlogic/clk/clk_media.c index 38a79483d0d5..7ba5e2f52ffa 100644 --- a/drivers/amlogic/clk/clk_media.c +++ b/drivers/amlogic/clk/clk_media.c @@ -763,6 +763,7 @@ void amlogic_init_media(void) clks[CLKID_VPU_MUX] = clk_register(NULL, vpu_clk_hws[CLKID_VPU_MUX - CLKID_VPU_P0_MUX]); WARN_ON(IS_ERR(clks[CLKID_VPU_MUX])); + clk_prepare_enable(clks[CLKID_VPU_MUX]); /* cts_vapb_clk */ clks[CLKID_VAPB_P0_COMP] = clk_register_composite(NULL, @@ -794,6 +795,7 @@ void amlogic_init_media(void) clks[CLKID_VAPB_MUX] = clk_register(NULL, vapb_clk_hws[CLKID_VAPB_MUX - CLKID_VAPB_P0_MUX]); WARN_ON(IS_ERR(clks[CLKID_VAPB_MUX])); + clk_prepare_enable(clks[CLKID_VAPB_MUX]); clks[CLKID_GE2D_GATE] = clk_register(NULL, &ge2d_gate.hw); diff --git a/drivers/amlogic/media/Kconfig b/drivers/amlogic/media/Kconfig index ecb0b5bf06f2..bdbdaf274ad7 100644 --- a/drivers/amlogic/media/Kconfig +++ b/drivers/amlogic/media/Kconfig @@ -42,6 +42,9 @@ endif if AMLOGIC_MEDIA_DRIVERS source "drivers/amlogic/media/video_sink/Kconfig" source "drivers/amlogic/media/vout/Kconfig" +source "drivers/amlogic/media/osd/Kconfig" +source "drivers/amlogic/media/osd_ext/Kconfig" +source "drivers/amlogic/media/logo/Kconfig" endif endmenu diff --git a/drivers/amlogic/media/Makefile b/drivers/amlogic/media/Makefile index 2b24e38eb257..b2e969f9ee49 100644 --- a/drivers/amlogic/media/Makefile +++ b/drivers/amlogic/media/Makefile @@ -2,3 +2,6 @@ obj-$(CONFIG_AMLOGIC_MEDIA_COMMON) += common/ obj-$(CONFIG_AMLOGIC_MEDIA_DRIVERS) += frame_sync/ obj-$(CONFIG_AMLOGIC_MEDIA_DRIVERS) += video_sink/ obj-$(CONFIG_AMLOGIC_VOUT) += vout/ +obj-$(CONFIG_AMLOGIC_MEDIA_DRIVERS) += osd/ +obj-$(CONFIG_AMLOGIC_MEDIA_DRIVERS) += osd_ext/ +obj-$(CONFIG_AMLOGIC_MEDIA_DRIVERS) += logo/ diff --git a/drivers/amlogic/media/common/Kconfig b/drivers/amlogic/media/common/Kconfig index c458ab7ee4ea..5ca33ab526c7 100644 --- a/drivers/amlogic/media/common/Kconfig +++ b/drivers/amlogic/media/common/Kconfig @@ -1,9 +1,8 @@ #Ascending by module name's ASCII source "drivers/amlogic/media/common/codec_mm/Kconfig" source "drivers/amlogic/media/common/canvas/Kconfig" +source "drivers/amlogic/media/common/ge2d/Kconfig" source "drivers/amlogic/media/common/ion_dev/Kconfig" source "drivers/amlogic/media/common/rdma/Kconfig" source "drivers/amlogic/media/common/vfm/Kconfig" -source "drivers/amlogic/media/common/ge2d/Kconfig" -source "drivers/amlogic/media/common/ion_dev/Kconfig" source "drivers/amlogic/media/common/vpu/Kconfig" diff --git a/drivers/amlogic/media/common/Makefile b/drivers/amlogic/media/common/Makefile index a0ae49fd15e6..e953b9225bbd 100644 --- a/drivers/amlogic/media/common/Makefile +++ b/drivers/amlogic/media/common/Makefile @@ -2,7 +2,7 @@ obj-y += arch/ obj-$(CONFIG_AMLOGIC_MEDIA_CANVAS) += canvas/ obj-$(CONFIG_AMLOGIC_MEDIA_CODEC_MM) += codec_mm/ -obj-$(CONFIG_AMLOGIC_GE2D) += ge2d/ +obj-$(CONFIG_AMLOGIC_MEDIA_GE2D) += ge2d/ obj-$(CONFIG_AMLOGIC_ION) += ion_dev/ obj-$(CONFIG_AMLOGIC_MEDIA_RDMA) += rdma/ obj-$(CONFIG_AMLOGIC_MEDIA_VFM) += vfm/ diff --git a/drivers/amlogic/media/common/ge2d/Kconfig b/drivers/amlogic/media/common/ge2d/Kconfig index 82592e825e6a..e8c3d53a0a95 100644 --- a/drivers/amlogic/media/common/ge2d/Kconfig +++ b/drivers/amlogic/media/common/ge2d/Kconfig @@ -1,7 +1,7 @@ # # GE2D Module # -config AMLOGIC_GE2D +config AMLOGIC_MEDIA_GE2D bool "Amlogic GE2D Module" default n help diff --git a/drivers/amlogic/media/common/ge2d/Makefile b/drivers/amlogic/media/common/ge2d/Makefile index 3831ee52d82f..4be27ccec0c6 100644 --- a/drivers/amlogic/media/common/ge2d/Makefile +++ b/drivers/amlogic/media/common/ge2d/Makefile @@ -7,5 +7,6 @@ ge2d-objs = bitblt.o \ ge2d_main.o \ blend.o -obj-$(CONFIG_AMLOGIC_GE2D) += ge2d.o +obj-$(CONFIG_AMLOGIC_MEDIA_GE2D) += ge2d.o ccflags-y += -Iinclude/linux/media/ge2d/ +ccflags-y += -Idrivers/amlogic/media/osd/ \ No newline at end of file diff --git a/drivers/amlogic/media/common/ge2d/blend.c b/drivers/amlogic/media/common/ge2d/blend.c index 80e70c0ec365..367f5d2a5b4d 100644 --- a/drivers/amlogic/media/common/ge2d/blend.c +++ b/drivers/amlogic/media/common/ge2d/blend.c @@ -143,3 +143,119 @@ void blend_noblk(struct ge2d_context_s *wq, ge2d_wq_add_work(wq); } EXPORT_SYMBOL(blend_noblk); +void blend_noalpha(struct ge2d_context_s *wq, + int src_x, int src_y, int src_w, int src_h, + int src2_x, int src2_y, int src2_w, int src2_h, + int dst_x, int dst_y, int dst_w, int dst_h, + int op) +{ + struct ge2d_cmd_s *ge2d_cmd_cfg = ge2d_wq_get_cmd(wq); + + ge2d_cmd_cfg->src1_x_start = src_x; + ge2d_cmd_cfg->src1_x_end = src_x + src_w - 1; + ge2d_cmd_cfg->src1_y_start = src_y; + ge2d_cmd_cfg->src1_y_end = src_y + src_h - 1; + + ge2d_cmd_cfg->src2_x_start = src2_x; + ge2d_cmd_cfg->src2_x_end = src2_x + src2_w - 1; + ge2d_cmd_cfg->src2_y_start = src2_y; + ge2d_cmd_cfg->src2_y_end = src2_y + src2_h - 1; + + ge2d_cmd_cfg->dst_x_start = dst_x; + ge2d_cmd_cfg->dst_x_end = dst_x + dst_w - 1; + ge2d_cmd_cfg->dst_y_start = dst_y; + ge2d_cmd_cfg->dst_y_end = dst_y + dst_h - 1; + + /* if ((dst_w != src_w) || (dst_h != src_h)) { */ + if (1) { + ge2d_cmd_cfg->sc_hsc_en = 1; + ge2d_cmd_cfg->sc_vsc_en = 1; + ge2d_cmd_cfg->hsc_rpt_p0_num = 1; + ge2d_cmd_cfg->vsc_rpt_l0_num = 1; + ge2d_cmd_cfg->hsc_div_en = 1; + } else { + ge2d_cmd_cfg->sc_hsc_en = 0; + ge2d_cmd_cfg->sc_vsc_en = 0; + ge2d_cmd_cfg->hsc_rpt_p0_num = 0; + ge2d_cmd_cfg->vsc_rpt_l0_num = 0; + ge2d_cmd_cfg->hsc_div_en = 0; + } + + ge2d_cmd_cfg->color_blend_mode = (op >> 24) & 0xff; + ge2d_cmd_cfg->color_src_blend_factor = (op >> 20) & 0xf; + ge2d_cmd_cfg->color_dst_blend_factor = (op >> 16) & 0xf; + ge2d_cmd_cfg->alpha_src_blend_factor = (op >> 4) & 0xf; + ge2d_cmd_cfg->alpha_dst_blend_factor = (op >> 0) & 0xf; + + if (ge2d_cmd_cfg->color_blend_mode >= BLENDOP_LOGIC) { + ge2d_cmd_cfg->color_logic_op = + ge2d_cmd_cfg->color_blend_mode - BLENDOP_LOGIC; + ge2d_cmd_cfg->color_blend_mode = OPERATION_LOGIC; + } + ge2d_cmd_cfg->alpha_blend_mode = OPERATION_LOGIC; + ge2d_cmd_cfg->alpha_logic_op = LOGIC_OPERATION_SET; + + ge2d_cmd_cfg->wait_done_flag = 1; + + ge2d_wq_add_work(wq); +} +EXPORT_SYMBOL(blend_noalpha); + + +void blend_noalpha_noblk(struct ge2d_context_s *wq, + int src_x, int src_y, int src_w, int src_h, + int src2_x, int src2_y, int src2_w, int src2_h, + int dst_x, int dst_y, int dst_w, int dst_h, + int op) +{ + struct ge2d_cmd_s *ge2d_cmd_cfg = ge2d_wq_get_cmd(wq); + + ge2d_cmd_cfg->src1_x_start = src_x; + ge2d_cmd_cfg->src1_x_end = src_x + src_w - 1; + ge2d_cmd_cfg->src1_y_start = src_y; + ge2d_cmd_cfg->src1_y_end = src_y + src_h - 1; + + ge2d_cmd_cfg->src2_x_start = src2_x; + ge2d_cmd_cfg->src2_x_end = src2_x + src2_w - 1; + ge2d_cmd_cfg->src2_y_start = src2_y; + ge2d_cmd_cfg->src2_y_end = src2_y + src2_h - 1; + + ge2d_cmd_cfg->dst_x_start = dst_x; + ge2d_cmd_cfg->dst_x_end = dst_x + dst_w - 1; + ge2d_cmd_cfg->dst_y_start = dst_y; + ge2d_cmd_cfg->dst_y_end = dst_y + dst_h - 1; + + /* if ((dst_w != src_w) || (dst_h != src_h)) { */ + if (1) { + ge2d_cmd_cfg->sc_hsc_en = 1; + ge2d_cmd_cfg->sc_vsc_en = 1; + ge2d_cmd_cfg->hsc_rpt_p0_num = 1; + ge2d_cmd_cfg->vsc_rpt_l0_num = 1; + ge2d_cmd_cfg->hsc_div_en = 1; + } else { + ge2d_cmd_cfg->sc_hsc_en = 0; + ge2d_cmd_cfg->sc_vsc_en = 0; + ge2d_cmd_cfg->hsc_rpt_p0_num = 0; + ge2d_cmd_cfg->vsc_rpt_l0_num = 0; + ge2d_cmd_cfg->hsc_div_en = 0; + } + + ge2d_cmd_cfg->color_blend_mode = (op >> 24) & 0xff; + ge2d_cmd_cfg->color_src_blend_factor = (op >> 20) & 0xf; + ge2d_cmd_cfg->color_dst_blend_factor = (op >> 16) & 0xf; + ge2d_cmd_cfg->alpha_src_blend_factor = (op >> 4) & 0xf; + ge2d_cmd_cfg->alpha_dst_blend_factor = (op >> 0) & 0xf; + + if (ge2d_cmd_cfg->color_blend_mode >= BLENDOP_LOGIC) { + ge2d_cmd_cfg->color_logic_op = + ge2d_cmd_cfg->color_blend_mode - BLENDOP_LOGIC; + ge2d_cmd_cfg->color_blend_mode = OPERATION_LOGIC; + } + ge2d_cmd_cfg->alpha_blend_mode = OPERATION_LOGIC; + ge2d_cmd_cfg->alpha_logic_op = LOGIC_OPERATION_SET; + + ge2d_cmd_cfg->wait_done_flag = 0; + + ge2d_wq_add_work(wq); +} +EXPORT_SYMBOL(blend_noalpha_noblk); diff --git a/drivers/amlogic/media/common/ge2d/ge2d_hw.c b/drivers/amlogic/media/common/ge2d/ge2d_hw.c index 9d5cd099769f..d2d64f02486a 100644 --- a/drivers/amlogic/media/common/ge2d/ge2d_hw.c +++ b/drivers/amlogic/media/common/ge2d/ge2d_hw.c @@ -19,7 +19,7 @@ #include /* Amlogic Headers */ -#include +#include #include /* Local Headers */ @@ -633,6 +633,22 @@ void ge2d_set_dp_gen(struct ge2d_dp_gen_s *cfg) cfg->matrix_sat_in_en = 0; cfg->matrix_minus_16_ctrl = 0; cfg->matrix_sign_ctrl = 0x3; + } else if (cfg->use_matrix_default == MATRIX_RGB_TO_FULL_RANGE_YCC) { + cfg->matrix_coef[0] = 0x132; + cfg->matrix_coef[1] = 0x259; + cfg->matrix_coef[2] = 0x75; + cfg->matrix_coef[3] = 0x1f53; + cfg->matrix_coef[4] = 0x1ead; + cfg->matrix_coef[5] = 0x200; + cfg->matrix_coef[6] = 0x200; + cfg->matrix_coef[7] = 0x1e53; + cfg->matrix_coef[8] = 0x1fad; + cfg->matrix_offset[0] = 0; + cfg->matrix_offset[1] = 128; + cfg->matrix_offset[2] = 128; + cfg->matrix_sat_in_en = 0; + cfg->matrix_minus_16_ctrl = 0; + cfg->matrix_sign_ctrl = 0; } if (cfg->matrix_minus_16_ctrl) @@ -726,32 +742,6 @@ void ge2d_set_cmd(struct ge2d_cmd_s *cfg) x_yc_ratio = ge2d_reg_get_bits(GE2D_GEN_CTRL0, 11, 1); y_yc_ratio = ge2d_reg_get_bits(GE2D_GEN_CTRL0, 10, 1); - /* #if MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6 */ - if (get_cpu_type() == MESON_CPU_MAJOR_ID_M6) { - if (x_yc_ratio) { - if (cfg->src1_x_rev) { - x_extra_bit_start = 0; - x_extra_bit_end = 3; - x_chr_phase = 0x80; - } else { - x_extra_bit_start = 3; - x_extra_bit_end = 0; - x_chr_phase = 0x08; - } - } - if (y_yc_ratio) { - if (cfg->src1_y_rev) { - y_extra_bit_start = 2; - y_extra_bit_end = 3; - y_chr_phase = 0xc4; - } else { - y_extra_bit_start = 3; - y_extra_bit_end = 2; - y_chr_phase = 0x4c; - } - } - } else { - /* #else */ if (x_yc_ratio) { if ((cfg->src1_x_rev + cfg->dst_x_rev) == 1) { x_extra_bit_start = 3; @@ -774,9 +764,7 @@ void ge2d_set_cmd(struct ge2d_cmd_s *cfg) y_extra_bit_end = 3; y_chr_phase = 0x4c; } - } } - /* #endif */ ge2d_reg_write(GE2D_SRC1_X_START_END, (x_extra_bit_start << 30) | /* x start extra */ diff --git a/drivers/amlogic/media/common/ge2d/ge2d_io.h b/drivers/amlogic/media/common/ge2d/ge2d_io.h index 684c26891ab2..01547046e5ca 100644 --- a/drivers/amlogic/media/common/ge2d/ge2d_io.h +++ b/drivers/amlogic/media/common/ge2d/ge2d_io.h @@ -20,11 +20,13 @@ #include #include -#include +#include #include "ge2d_log.h" #define GE2DBUS_REG_ADDR(reg) (((reg - 0x1800) << 2)) +extern unsigned int ge2d_dump_reg_cnt; +extern unsigned int ge2d_dump_reg_enable; struct reg_map_s { unsigned int phy_addr; @@ -40,18 +42,21 @@ static struct reg_map_s reg_map = { static int check_map_flag(unsigned int addr) { + int ret = 0; + if (reg_map.flag) return 1; reg_map.vir_addr = ioremap(reg_map.phy_addr, reg_map.size); if (!reg_map.vir_addr) { pr_info("failed map phy: 0x%x\n", addr); - return 0; + ret = 0; + } else { + reg_map.flag = 1; + pr_info("mapped phy: 0x%x\n", reg_map.phy_addr); + ret = 1; } - - reg_map.flag = 1; - pr_info("mapped phy: 0x%x\n", reg_map.phy_addr); - return 1; + return ret; } static uint32_t ge2d_reg_read(unsigned int reg) @@ -74,7 +79,6 @@ static uint32_t ge2d_reg_read(unsigned int reg) static void ge2d_reg_write(unsigned int reg, unsigned int val) { - unsigned int ret = 0; unsigned int addr = 0; if (get_meson_cpu_version(MESON_CPU_VERSION_LVL_MAJOR) @@ -88,8 +92,11 @@ static void ge2d_reg_write(unsigned int reg, unsigned int val) writel(val, reg_map.vir_addr + addr); /* ret = readl(reg_map.vir_addr + addr); */ } - ge2d_log_dbg2("write(0x%x, 0x%x)=0x%x\n", - reg_map.phy_addr + addr, val, ret); + if (ge2d_dump_reg_enable && (ge2d_dump_reg_cnt > 0)) { + ge2d_log_info("write(0x%x) = 0x%x\n", + reg, val); + ge2d_dump_reg_cnt--; + } } static inline uint32_t ge2d_vcbus_read(uint32_t reg) diff --git a/drivers/amlogic/media/common/ge2d/ge2d_main.c b/drivers/amlogic/media/common/ge2d/ge2d_main.c index d5036ac5b835..6733650cb3af 100644 --- a/drivers/amlogic/media/common/ge2d/ge2d_main.c +++ b/drivers/amlogic/media/common/ge2d/ge2d_main.c @@ -16,9 +16,7 @@ */ /* Linux Headers */ -#include #include -#include #include #include #include @@ -39,7 +37,7 @@ /* Amlogic Headers */ #include #include -#include +#include /* Local Headers */ #include "ge2dgen.h" @@ -60,6 +58,8 @@ struct ge2d_device_s { static struct ge2d_device_s ge2d_device; static DEFINE_MUTEX(ge2d_mutex); unsigned int ge2d_log_level; +unsigned int ge2d_dump_reg_enable; +unsigned int ge2d_dump_reg_cnt; static int ge2d_open(struct inode *inode, struct file *file); static long ge2d_ioctl(struct file *filp, unsigned int cmd, @@ -75,6 +75,19 @@ static ssize_t log_level_show(struct class *cla, static ssize_t log_level_store(struct class *cla, struct class_attribute *attr, const char *buf, size_t count); +static ssize_t dump_reg_enable_show(struct class *cla, + struct class_attribute *attr, + char *buf); +static ssize_t dump_reg_enable_store(struct class *cla, + struct class_attribute *attr, + const char *buf, size_t count); +static ssize_t dump_reg_cnt_show(struct class *cla, + struct class_attribute *attr, + char *buf); +static ssize_t dump_reg_cnt_store(struct class *cla, + struct class_attribute *attr, + const char *buf, size_t count); + static const struct file_operations ge2d_fops = { .owner = THIS_MODULE, @@ -93,6 +106,10 @@ static struct class_attribute ge2d_class_attrs[] = { free_queue_status_show, NULL), __ATTR(log_level, 0644, log_level_show, log_level_store), + __ATTR(dump_reg_enable, 0644, + dump_reg_enable_show, dump_reg_enable_store), + __ATTR(dump_reg_cnt, 0644, + dump_reg_cnt_show, dump_reg_cnt_store), __ATTR_NULL }; @@ -101,6 +118,47 @@ static struct class ge2d_class = { .class_attrs = ge2d_class_attrs, }; +static ssize_t dump_reg_enable_show(struct class *cla, + struct class_attribute *attr, + char *buf) +{ + return snprintf(buf, 40, "%d\n", ge2d_dump_reg_enable); +} + +static ssize_t dump_reg_enable_store(struct class *cla, + struct class_attribute *attr, + const char *buf, size_t count) +{ + int res = 0; + int ret = 0; + + ret = kstrtoint(buf, 0, &res); + ge2d_log_info("ge2d dump_reg_enbale: %d->%d\n", + ge2d_dump_reg_enable, res); + ge2d_dump_reg_enable = res; + + return count; +} + +static ssize_t dump_reg_cnt_show(struct class *cla, + struct class_attribute *attr, + char *buf) +{ + return snprintf(buf, 40, "%d\n", ge2d_dump_reg_cnt); +} + +static ssize_t dump_reg_cnt_store(struct class *cla, + struct class_attribute *attr, + const char *buf, size_t count) +{ + int res = 0; + int ret = 0; + + ret = kstrtoint(buf, 0, &res); + ge2d_log_info("ge2d dump_reg: %d->%d\n", ge2d_dump_reg_cnt, res); + ge2d_dump_reg_cnt = res; + return count; +} static ssize_t log_level_show(struct class *cla, struct class_attribute *attr, @@ -123,19 +181,6 @@ static ssize_t log_level_store(struct class *cla, return count; } -static bool command_valid(unsigned int cmd) -{ - bool ret = false; -#ifdef CONFIG_COMPAT - ret = (cmd <= GE2D_CONFIG_EX32 && - cmd >= GE2D_ANTIFLICKER_ENABLE); -#else - ret = (cmd <= GE2D_CONFIG_EX && - cmd >= GE2D_ANTIFLICKER_ENABLE); -#endif - return ret; -} - static int ge2d_open(struct inode *inode, struct file *file) { struct ge2d_context_s *context = NULL; @@ -161,22 +206,53 @@ static long ge2d_ioctl(struct file *filp, unsigned int cmd, unsigned long args) int ret = 0; #ifdef CONFIG_COMPAT struct compat_config_para_s __user *uf; + struct compat_config_para_ex_s __user *uf_ex; int r = 0; int i, j; #endif void __user *argp = (void __user *)args; - if (!command_valid(cmd)) - return -1; - context = (struct ge2d_context_s *)filp->private_data; memset(&ge2d_config, 0, sizeof(struct config_para_s)); + memset(&ge2d_config_ex, 0, sizeof(struct config_para_ex_s)); switch (cmd) { case GE2D_CONFIG: case GE2D_SRCCOLORKEY: ret = copy_from_user(&ge2d_config, argp, sizeof(struct config_para_s)); break; +#ifdef CONFIG_COMPAT + case GE2D_SRCCOLORKEY32: + uf = (struct compat_config_para_s *)argp; + r = get_user(ge2d_config.src_dst_type, &uf->src_dst_type); + r |= get_user(ge2d_config.alu_const_color, + &uf->alu_const_color); + r |= get_user(ge2d_config.src_format, &uf->src_format); + r |= get_user(ge2d_config.dst_format, &uf->dst_format); + for (i = 0; i < 4; i++) { + r |= get_user(ge2d_config.src_planes[i].addr, + &uf->src_planes[i].addr); + r |= get_user(ge2d_config.src_planes[i].w, + &uf->src_planes[i].w); + r |= get_user(ge2d_config.src_planes[i].h, + &uf->src_planes[i].h); + } + for (j = 0; j < 4; j++) { + r |= get_user(ge2d_config.dst_planes[j].addr, + &uf->dst_planes[j].addr); + r |= get_user(ge2d_config.dst_planes[j].w, + &uf->dst_planes[j].w); + r |= get_user(ge2d_config.dst_planes[j].h, + &uf->dst_planes[j].h); + } + r |= copy_from_user(&ge2d_config.src_key, &uf->src_key, + sizeof(struct src_key_ctrl_s)); + if (r) { + pr_err("GE2D_SRCCOLORKEY32 get parameter failed .\n"); + return -EFAULT; + } + break; +#endif #ifdef CONFIG_COMPAT case GE2D_CONFIG32: uf = (struct compat_config_para_s *)argp; @@ -214,9 +290,96 @@ static long ge2d_ioctl(struct file *filp, unsigned int cmd, unsigned long args) ret = copy_from_user(&ge2d_config_ex, argp, sizeof(struct config_para_ex_s)); break; +#ifdef CONFIG_COMPAT + case GE2D_CONFIG_EX32: + uf_ex = (struct compat_config_para_ex_s *)argp; + r = copy_from_user(&ge2d_config_ex.src_para, &uf_ex->src_para, + sizeof(struct src_dst_para_ex_s)); + r |= copy_from_user(&ge2d_config_ex.src2_para, + &uf_ex->src2_para, + sizeof(struct src_dst_para_ex_s)); + r |= copy_from_user(&ge2d_config_ex.dst_para, &uf_ex->dst_para, + sizeof(struct src_dst_para_ex_s)); + + r |= copy_from_user(&ge2d_config_ex.src_key, &uf_ex->src_key, + sizeof(struct src_key_ctrl_s)); + r |= copy_from_user(&ge2d_config_ex.src2_key, &uf_ex->src2_key, + sizeof(struct src_key_ctrl_s)); + + r |= get_user(ge2d_config_ex.alu_const_color, + &uf_ex->alu_const_color); + r |= get_user(ge2d_config_ex.src1_gb_alpha, + &uf_ex->src1_gb_alpha); + r |= get_user(ge2d_config_ex.op_mode, &uf_ex->op_mode); + r |= get_user(ge2d_config_ex.bitmask_en, &uf_ex->bitmask_en); + r |= get_user(ge2d_config_ex.bytemask_only, + &uf_ex->bytemask_only); + r |= get_user(ge2d_config_ex.bitmask, &uf_ex->bitmask); + r |= get_user(ge2d_config_ex.dst_xy_swap, &uf_ex->dst_xy_swap); + r |= get_user(ge2d_config_ex.hf_init_phase, + &uf_ex->hf_init_phase); + r |= get_user(ge2d_config_ex.hf_rpt_num, &uf_ex->hf_rpt_num); + r |= get_user(ge2d_config_ex.hsc_start_phase_step, + &uf_ex->hsc_start_phase_step); + r |= get_user(ge2d_config_ex.hsc_phase_slope, + &uf_ex->hsc_phase_slope); + r |= get_user(ge2d_config_ex.vf_init_phase, + &uf_ex->vf_init_phase); + r |= get_user(ge2d_config_ex.vf_rpt_num, &uf_ex->vf_rpt_num); + r |= get_user(ge2d_config_ex.vsc_start_phase_step, + &uf_ex->vsc_start_phase_step); + r |= get_user(ge2d_config_ex.vsc_phase_slope, + &uf_ex->vsc_phase_slope); + r |= get_user(ge2d_config_ex.src1_vsc_phase0_always_en, + &uf_ex->src1_vsc_phase0_always_en); + r |= get_user(ge2d_config_ex.src1_hsc_phase0_always_en, + &uf_ex->src1_hsc_phase0_always_en); + r |= get_user(ge2d_config_ex.src1_hsc_rpt_ctrl, + &uf_ex->src1_hsc_rpt_ctrl); + r |= get_user(ge2d_config_ex.src1_vsc_rpt_ctrl, + &uf_ex->src1_vsc_rpt_ctrl); + + for (i = 0; i < 4; i++) { + r |= get_user(ge2d_config_ex.src_planes[i].addr, + &uf_ex->src_planes[i].addr); + r |= get_user(ge2d_config_ex.src_planes[i].w, + &uf_ex->src_planes[i].w); + r |= get_user(ge2d_config_ex.src_planes[i].h, + &uf_ex->src_planes[i].h); + } + + for (i = 0; i < 4; i++) { + r |= get_user(ge2d_config_ex.src2_planes[i].addr, + &uf_ex->src2_planes[i].addr); + r |= get_user(ge2d_config_ex.src2_planes[i].w, + &uf_ex->src2_planes[i].w); + r |= get_user(ge2d_config_ex.src2_planes[i].h, + &uf_ex->src2_planes[i].h); + } + + for (j = 0; j < 4; j++) { + r |= get_user(ge2d_config_ex.dst_planes[j].addr, + &uf_ex->dst_planes[j].addr); + r |= get_user(ge2d_config_ex.dst_planes[j].w, + &uf_ex->dst_planes[j].w); + r |= get_user(ge2d_config_ex.dst_planes[j].h, + &uf_ex->dst_planes[j].h); + } + + if (r) { + pr_err("GE2D_CONFIG_EX32 get parameter failed .\n"); + return -EFAULT; + } + break; +#endif case GE2D_SET_COEF: case GE2D_ANTIFLICKER_ENABLE: break; + case GE2D_CONFIG_OLD: + case GE2D_CONFIG_EX_OLD: + case GE2D_SRCCOLORKEY_OLD: + pr_err("ioctl not support yed.\n"); + return -EINVAL; default: ret = copy_from_user(¶, argp, sizeof(struct ge2d_para_s)); break; @@ -231,6 +394,9 @@ static long ge2d_ioctl(struct file *filp, unsigned int cmd, unsigned long args) ret = ge2d_context_config(context, &ge2d_config); break; case GE2D_CONFIG_EX: +#ifdef CONFIG_COMPAT + case GE2D_CONFIG_EX32: +#endif ret = ge2d_context_config_ex(context, &ge2d_config_ex); break; case GE2D_SET_COEF: @@ -240,6 +406,15 @@ static long ge2d_ioctl(struct file *filp, unsigned int cmd, unsigned long args) ge2d_antiflicker_enable(context, args); break; case GE2D_SRCCOLORKEY: +#ifdef CONFIG_COMPAT + case GE2D_SRCCOLORKEY32: +#endif + ge2d_log_dbg("src colorkey...,key_enable=0x%x,key_color=0x%x,key_mask=0x%x,key_mode=0x%x\n", + ge2d_config.src_key.key_enable, + ge2d_config.src_key.key_color, + ge2d_config.src_key.key_mask, + ge2d_config.src_key.key_mode); + ge2dgen_src_key(context, ge2d_config.src_key.key_enable, ge2d_config.src_key.key_color, ge2d_config.src_key.key_mask, @@ -334,6 +509,28 @@ static long ge2d_ioctl(struct file *filp, unsigned int cmd, unsigned long args) para.dst_rect.w, para.dst_rect.h, para.op); break; + case GE2D_BLEND_NOALPHA: + ge2d_log_dbg("blend_noalpha ...\n"); + blend_noalpha(context, + para.src1_rect.x, para.src1_rect.y, + para.src1_rect.w, para.src1_rect.h, + para.src2_rect.x, para.src2_rect.y, + para.src2_rect.w, para.src2_rect.h, + para.dst_rect.x, para.dst_rect.y, + para.dst_rect.w, para.dst_rect.h, + para.op); + break; + case GE2D_BLEND_NOALPHA_NOBLOCK: + ge2d_log_dbg("blend_noalpha ...,noblk\n"); + blend_noalpha_noblk(context, + para.src1_rect.x, para.src1_rect.y, + para.src1_rect.w, para.src1_rect.h, + para.src2_rect.x, para.src2_rect.y, + para.src2_rect.w, para.src2_rect.h, + para.dst_rect.x, para.dst_rect.y, + para.dst_rect.w, para.dst_rect.h, + para.op); + break; case GE2D_BLIT_NOALPHA: /* bitblt_noalpha */ ge2d_log_dbg("blit_noalpha...\n"); @@ -413,6 +610,7 @@ static int ge2d_probe(struct platform_device *pdev) int ret = 0; int irq = 0; struct reset_control *rstc = NULL; + struct clk *clk_gate; struct clk *clk; /* get interrupt resource */ irq = platform_get_irq_byname(pdev, "ge2d"); @@ -422,35 +620,42 @@ static int ge2d_probe(struct platform_device *pdev) goto failed1; } - rstc = devm_reset_control_get(&pdev->dev, "ge2d"); - if (IS_ERR(rstc)) { - ge2d_log_err("get ge2d rstc error: %lx\n", PTR_ERR(rstc)); - rstc = NULL; + clk_gate = devm_clk_get(&pdev->dev, "clk_ge2d_gate"); + if (IS_ERR(clk_gate)) { + ge2d_log_err("cannot get clock\n"); + clk_gate = NULL; ret = -ENOENT; goto failed1; } + ge2d_log_info("clock source clk_ge2d_gate %p\n", clk_gate); + clk_prepare_enable(clk_gate); - reset_control_assert(rstc); - clk = clk_get(&pdev->dev, "clk_ge2d"); + clk = devm_clk_get(&pdev->dev, "clk_ge2d"); if (IS_ERR(clk)) { ge2d_log_err("cannot get clock\n"); clk = NULL; ret = -ENOENT; goto failed1; } + ge2d_log_info("clock clk_ge2d source %p\n", clk); + clk_prepare_enable(clk); + if (get_cpu_type() >= MESON_CPU_MAJOR_ID_GXBB) { struct clk *clk_vapb0; int vapb_rate; - clk_vapb0 = clk_get(&pdev->dev, "clk_vapb_0"); + clk_vapb0 = devm_clk_get(&pdev->dev, "clk_vapb_0"); + ge2d_log_info("clock source clk_vapb_0 %p\n", clk_vapb0); + clk_prepare_enable(clk_vapb0); + if (!IS_ERR(clk_vapb0)) { vapb_rate = clk_get_rate(clk_vapb0); - clk_put(clk_vapb0); + clk_set_rate(clk_vapb0, vapb_rate); ge2d_log_info("ge2d clock is %d MHZ\n", vapb_rate/1000000); } } - ret = ge2d_wq_init(pdev, irq, rstc, clk); + ret = ge2d_wq_init(pdev, irq, rstc, clk_gate); failed1: return ret; } diff --git a/drivers/amlogic/media/common/ge2d/ge2d_wq.c b/drivers/amlogic/media/common/ge2d/ge2d_wq.c index b4176099d5ef..912ef38856d1 100644 --- a/drivers/amlogic/media/common/ge2d/ge2d_wq.c +++ b/drivers/amlogic/media/common/ge2d/ge2d_wq.c @@ -28,7 +28,6 @@ #include /* Amlogic Headers */ -#include #include #include #include @@ -41,6 +40,7 @@ #include "ge2d_reg.h" #include "ge2d_wq.h" +#include "osd_io.h" #define OSD1_CANVAS_INDEX 0x40 #define OSD2_CANVAS_INDEX 0x43 #define OSD3_CANVAS_INDEX 0x41 @@ -52,6 +52,39 @@ static int ge2d_irq = -ENXIO; static struct reset_control *ge2d_rstc; static struct clk *ge2d_clk; +enum color_index_e { + COLOR_INDEX_02_PAL4 = 2, + COLOR_INDEX_04_PAL16 = 4, + COLOR_INDEX_08_PAL256 = 8, + COLOR_INDEX_16_655 = 9, + COLOR_INDEX_16_844 = 10, + COLOR_INDEX_16_6442 = 11, + COLOR_INDEX_16_4444_R = 12, + COLOR_INDEX_16_4642_R = 13, + COLOR_INDEX_16_1555_A = 14, + COLOR_INDEX_16_4444_A = 15, + COLOR_INDEX_16_565 = 16, + + COLOR_INDEX_24_6666_A = 19, + COLOR_INDEX_24_6666_R = 20, + COLOR_INDEX_24_8565 = 21, + COLOR_INDEX_24_5658 = 22, + COLOR_INDEX_24_888_B = 23, + COLOR_INDEX_24_RGB = 24, + + COLOR_INDEX_32_BGRX = 25, + COLOR_INDEX_32_XBGR = 26, + COLOR_INDEX_32_RGBX = 27, + COLOR_INDEX_32_XRGB = 28, + + COLOR_INDEX_32_BGRA = 29, + COLOR_INDEX_32_ABGR = 30, + COLOR_INDEX_32_RGBA = 31, + COLOR_INDEX_32_ARGB = 32, + + COLOR_INDEX_YUV_422 = 33, +}; + static const int bpp_type_lut[] = { /* 16bit */ COLOR_INDEX_16_655, /* 0 */ @@ -115,28 +148,14 @@ static const int default_ge2d_color_lut[] = { GE2D_FORMAT_S32_ARGB,/* BPP_TYPE_32_ARGB=32, */ }; -static long ge2d_sleep_on(wait_queue_head_t *q, long timeout) -{ - DEFINE_WAIT(wait); - - prepare_to_wait(q, &wait, TASK_INTERRUPTIBLE); - timeout = schedule_timeout(timeout); - finish_wait(q, &wait); - return timeout; -} - static int ge2d_clk_config(bool enable) { if (ge2d_clk == NULL) return -1; if (enable) { - if (ge2d_rstc != NULL) - reset_control_deassert(ge2d_rstc); clk_prepare_enable(ge2d_clk); } else { clk_disable_unprepare(ge2d_clk); - if (ge2d_rstc != NULL) - reset_control_assert(ge2d_rstc); } return 0; } @@ -183,6 +202,75 @@ static inline int work_queue_no_space(struct ge2d_context_s *queue) return list_empty(&queue->free_queue); } +static void ge2d_dump_cmd(struct ge2d_cmd_s *cfg) +{ + ge2d_log_dbg("src1_x_start=%d,src1_y_start=%d\n", + cfg->src1_x_start, cfg->src1_y_start); + ge2d_log_dbg("src1_x_end=%d,src1_y_end=%d\n", + cfg->src1_x_end, cfg->src1_y_end); + ge2d_log_dbg("src1_x_rev=%d,src1_y_rev=%d\n", + cfg->src1_x_rev, cfg->src1_y_rev); + ge2d_log_dbg("src1_fill_color_en=%d\n", + cfg->src1_fill_color_en); + + ge2d_log_dbg("src2_x_start=%d,src2_y_start=%d\n", + cfg->src2_x_start, cfg->src2_y_start); + ge2d_log_dbg("src2_x_end=%d,src2_y_end=%d\n", + cfg->src2_x_end, cfg->src2_y_end); + ge2d_log_dbg("src2_x_rev=%d,src2_y_rev=%d\n", + cfg->src2_x_rev, cfg->src2_y_rev); + ge2d_log_dbg("src2_fill_color_en=%d\n", + cfg->src2_fill_color_en); + + ge2d_log_dbg("dst_x_start=%d,dst_y_start=%d\n", + cfg->dst_x_start, cfg->dst_y_start); + ge2d_log_dbg("dst_x_end=%d,dst_y_end=%d\n", + cfg->dst_x_end, cfg->dst_y_end); + ge2d_log_dbg("dst_x_rev=%d,dst_y_rev=%d\n", + cfg->dst_x_rev, cfg->dst_y_rev); + ge2d_log_dbg("dst_xy_swap=%d\n", + cfg->dst_xy_swap); + + ge2d_log_dbg("color_blend_mode=0x%x\n", + cfg->color_blend_mode); + ge2d_log_dbg("color_src_blend_factor=0x%x\n", + cfg->color_src_blend_factor); + ge2d_log_dbg("color_dst_blend_factor=0x%x\n", + cfg->color_dst_blend_factor); + ge2d_log_dbg("color_logic_op=0x%x\n", + cfg->color_logic_op); + ge2d_log_dbg("alpha_blend_mode=0x%x\n", + cfg->alpha_blend_mode); + ge2d_log_dbg("alpha_src_blend_factor=0x%x\n", + cfg->alpha_src_blend_factor); + ge2d_log_dbg("alpha_src_blend_factor=0x%x\n", + cfg->alpha_dst_blend_factor); + ge2d_log_dbg("alpha_logic_op=0x%x\n", + cfg->alpha_logic_op); + + ge2d_log_dbg("sc_prehsc_en=%d\n", cfg->sc_prehsc_en); + ge2d_log_dbg("sc_prevsc_en=%d\n", cfg->sc_prevsc_en); + ge2d_log_dbg("sc_hsc_en=%d\n", cfg->sc_hsc_en); + ge2d_log_dbg("sc_vsc_en=%d\n", cfg->sc_vsc_en); + ge2d_log_dbg("vsc_phase_step=%d\n", cfg->vsc_phase_step); + ge2d_log_dbg("vsc_phase_slope=%d\n", cfg->vsc_phase_slope); + ge2d_log_dbg("vsc_rpt_l0_num=%d\n", cfg->vsc_rpt_l0_num); + ge2d_log_dbg("vsc_ini_phase=%d\n", cfg->vsc_ini_phase); + ge2d_log_dbg("hsc_phase_step=%d\n", cfg->hsc_phase_step); + ge2d_log_dbg("hsc_phase_slope=%d\n", cfg->hsc_phase_slope); + ge2d_log_dbg("hsc_rpt_p0_num=%d\n", cfg->hsc_rpt_p0_num); + ge2d_log_dbg("hsc_ini_phase=%d\n", cfg->hsc_ini_phase); + ge2d_log_dbg("hsc_div_en=%d\n", cfg->hsc_div_en); + ge2d_log_dbg("hsc_div_length=%d\n", cfg->hsc_div_length); + ge2d_log_dbg("hsc_adv_num=%d\n", cfg->hsc_adv_num); + ge2d_log_dbg("hsc_adv_phase=%d\n", cfg->hsc_adv_phase); + ge2d_log_dbg("src1_cmult_asel=%d\n", cfg->src1_cmult_asel); + ge2d_log_dbg("src2_cmult_asel=%d\n", cfg->src2_cmult_asel); + + ge2d_log_dbg("GE2D_STATUS0=0x%x\n", ge2d_reg_read(GE2D_STATUS0)); + ge2d_log_dbg("GE2D_STATUS1=0x%x\n", ge2d_reg_read(GE2D_STATUS1)); +} + static int ge2d_process_work_queue(struct ge2d_context_s *wq) { struct ge2d_config_s *cfg; @@ -191,6 +279,7 @@ static int ge2d_process_work_queue(struct ge2d_context_s *wq) struct list_head *head = &wq->work_queue, *pos; int ret = 0; unsigned int block_mode; + int timeout = 0; ge2d_manager.ge2d_state = GE2D_STATE_RUNNING; pos = head->next; @@ -253,14 +342,18 @@ static int ge2d_process_work_queue(struct ge2d_context_s *wq) /* list_move_tail(&pitem->list,&wq->free_queue); */ /* spin_unlock(&wq->lock); */ -/* - * while (ge2d_is_busy()) - * interruptible_sleep_on_timeout( - * &ge2d_manager.event.cmd_complete, 1); - */ - while (ge2d_is_busy()) - ge2d_sleep_on(&ge2d_manager.event.cmd_complete, 1); - + while (ge2d_is_busy()) { + timeout = wait_event_interruptible_timeout( + ge2d_manager.event.cmd_complete, + !ge2d_is_busy(), + 100); + if (timeout == 0) { + ge2d_log_err("ge2d timeout!!!\n"); + ge2d_dump_cmd(&pitem->cmd); + ge2d_soft_rst(); + break; + } + } /* if block mode (cmd) */ if (block_mode) { pitem->cmd.wait_done_flag = 0; @@ -338,15 +431,12 @@ int ge2d_wq_add_work(struct ge2d_context_s *wq) if (work_queue_no_space(wq)) { ge2d_log_dbg("work queue no space\n"); /* we should wait for queue empty at this point. */ -/* - * while (work_queue_no_space(wq)) - * interruptible_sleep_on_timeout( - * &ge2d_manager.event.cmd_complete, 3); - */ + #if 0 while (work_queue_no_space(wq)) - ge2d_sleep_on(&ge2d_manager.event.cmd_complete, 3); - - ge2d_log_dbg("got free space\n"); + interruptible_sleep_on_timeout( + &ge2d_manager.event.cmd_complete, 3); + #endif + return -1; } pitem = list_entry(wq->free_queue.next, struct ge2d_queue_item_s, list); @@ -406,7 +496,8 @@ static int ge2d_monitor_thread(void *data) while ((manager->current_wq = get_next_work_queue(manager)) != NULL) ge2d_process_work_queue(manager->current_wq); - ge2d_clk_config(false); + if (!ge2d_dump_reg_enable) + ge2d_clk_config(false); } ge2d_log_info("exit ge2d_monitor_thread\n"); return 0; @@ -448,6 +539,9 @@ static inline int bpp(unsigned int format) case GE2D_BPP_16BIT: return 16; case GE2D_BPP_24BIT: + if ((GE2D_COLOR_MAP_NV21 == (format & GE2D_COLOR_MAP_NV21)) || + (GE2D_COLOR_MAP_NV12 == (format & GE2D_COLOR_MAP_NV12))) + return 8; return 24; case GE2D_BPP_32BIT: default: @@ -565,8 +659,14 @@ static int setup_display_property(struct src_dst_para_s *src_dst, int index) index = (index == OSD1_CANVAS_INDEX ? 0 : 1); ge2d_log_dbg("osd%d ", index); - data32 = ge2d_vcbus_read(VIU_OSD1_BLK0_CFG_W0 + REG_OFFSET * index); - +#ifdef CONFIG_AMLOGIC_MEDIA_FB + data32 = VSYNCOSD_RD_MPEG_REG( + VIU_OSD1_BLK0_CFG_W0 + REG_OFFSET * index); + src_dst->canvas_index = (data32 >> 16) & 0xff; + canvas_read(src_dst->canvas_index, &canvas); +#else + data32 = 0; +#endif index = (data32 >> 8) & 0xf; bpp = block_mode[index]; /* OSD_BLK_MODE[8..11] */ ge2d_log_dbg("%d bpp\n", bpp); @@ -787,6 +887,8 @@ int ge2d_context_config_ex(struct ge2d_context_s *context, ge2d_log_dbg("ge2d src error: out of range\n"); return -1; } + ge2d_config->src_para.width = tmp.xres; + ge2d_config->src_para.height = tmp.yres; break; case CANVAS_ALLOC: top = ge2d_config->src_para.top; @@ -835,6 +937,8 @@ int ge2d_context_config_ex(struct ge2d_context_s *context, ge2d_config->src2_para.mem_type - CANVAS_OSD0); return -1; } + ge2d_config->src2_para.width = tmp.xres; + ge2d_config->src2_para.height = tmp.yres; break; case CANVAS_ALLOC: top = ge2d_config->src2_para.top; @@ -886,6 +990,8 @@ int ge2d_context_config_ex(struct ge2d_context_s *context, ge2d_config->dst_para.mem_type - CANVAS_OSD0); return -1; } + ge2d_config->dst_para.width = tmp.xres; + ge2d_config->dst_para.height = tmp.yres; break; case CANVAS_ALLOC: top = ge2d_config->dst_para.top; @@ -1162,7 +1268,7 @@ int ge2d_wq_deinit(void) } ge2d_irq = -1; ge2d_rstc = NULL; - clk_put(ge2d_clk); + clk_disable_unprepare(ge2d_clk); ge2d_manager.pdev = NULL; return 0; } diff --git a/drivers/amlogic/media/common/ge2d/ge2dgen.c b/drivers/amlogic/media/common/ge2d/ge2dgen.c index c0cd640828c5..3deaac035820 100644 --- a/drivers/amlogic/media/common/ge2d/ge2dgen.c +++ b/drivers/amlogic/media/common/ge2d/ge2dgen.c @@ -54,7 +54,9 @@ static inline void _set_src1_format(struct ge2d_src1_data_s *src1_data_cfg, dp_gen_cfg->conv_matrix_en = 1; } else if (((format_src & GE2D_FORMAT_YUV) == 0) && (format_dst & GE2D_FORMAT_YUV)) { - dp_gen_cfg->use_matrix_default = MATRIX_RGB_TO_YCC; + dp_gen_cfg->use_matrix_default = + (format_dst & GE2D_FORMAT_COMP_RANGE) ? + MATRIX_RGB_TO_YCC : MATRIX_RGB_TO_FULL_RANGE_YCC; dp_gen_cfg->conv_matrix_en = 1; } else dp_gen_cfg->conv_matrix_en = 0; @@ -103,7 +105,9 @@ static inline void _set_dst_format( dp_gen_cfg->conv_matrix_en = 1; } else if (((format_src & GE2D_FORMAT_YUV) == 0) && (format_dst & GE2D_FORMAT_YUV)) { - dp_gen_cfg->use_matrix_default = MATRIX_RGB_TO_YCC; + dp_gen_cfg->use_matrix_default = + (format_dst & GE2D_FORMAT_COMP_RANGE) ? + MATRIX_RGB_TO_YCC : MATRIX_RGB_TO_FULL_RANGE_YCC; dp_gen_cfg->conv_matrix_en = 1; } else dp_gen_cfg->conv_matrix_en = 0; diff --git a/drivers/amlogic/media/common/ion_dev/dev_ion.c b/drivers/amlogic/media/common/ion_dev/dev_ion.c index f0004c01c263..8b4fbc801770 100644 --- a/drivers/amlogic/media/common/ion_dev/dev_ion.c +++ b/drivers/amlogic/media/common/ion_dev/dev_ion.c @@ -99,6 +99,7 @@ int ion_phys(struct ion_client *client, struct ion_handle *handle, } return 0; } +EXPORT_SYMBOL(ion_phys); int meson_ion_share_fd_to_phys(struct ion_client *client, int share_fd, ion_phys_addr_t *addr, size_t *len) diff --git a/drivers/amlogic/media/common/ion_dev/meson_ion.h b/drivers/amlogic/media/common/ion_dev/meson_ion.h index a865df6c0804..d89a27c1f86f 100644 --- a/drivers/amlogic/media/common/ion_dev/meson_ion.h +++ b/drivers/amlogic/media/common/ion_dev/meson_ion.h @@ -53,4 +53,9 @@ struct ion_client *meson_ion_client_create(unsigned int heap_mask, int meson_ion_share_fd_to_phys(struct ion_client *client, int share_fd, ion_phys_addr_t *addr, size_t *len); + + +int ion_phys(struct ion_client *client, struct ion_handle *handle, + ion_phys_addr_t *addr, size_t *len); + #endif diff --git a/drivers/amlogic/media/common/rdma/Kconfig b/drivers/amlogic/media/common/rdma/Kconfig index c9ec5e8690ff..b1a8f8386ff1 100644 --- a/drivers/amlogic/media/common/rdma/Kconfig +++ b/drivers/amlogic/media/common/rdma/Kconfig @@ -10,7 +10,7 @@ config AMLOGIC_MEDIA_RDMA help Select to enable RDMA management driver. - config CONFIG_AMLOGIC_MEDIA_VSYNC_RDMA + config AMLOGIC_MEDIA_VSYNC_RDMA bool "Amlogic RDMA VSYNC" depends on AMLOGIC_MEDIA_RDMA default n diff --git a/drivers/amlogic/media/common/rdma/rdma_mgr.c b/drivers/amlogic/media/common/rdma/rdma_mgr.c index 0bdff0a0b5af..03dc8d62776a 100644 --- a/drivers/amlogic/media/common/rdma/rdma_mgr.c +++ b/drivers/amlogic/media/common/rdma/rdma_mgr.c @@ -326,6 +326,7 @@ int rdma_config(int handle, int trigger_type) unsigned long flags; struct rdma_device_info *info = &rdma_info; struct rdma_instance_s *ins = &info->rdma_ins[handle]; + bool auto_start = false; if (handle == 0) pr_info("%s error, rdma_config(handle == 0) not allowed\n", @@ -339,7 +340,34 @@ int rdma_config(int handle, int trigger_type) return -1; } - if (ins->rdma_item_count <= 0 || trigger_type == 0) { + if (trigger_type & RDMA_AUTO_START_MASK) + auto_start = true; + + trigger_type &= ~RDMA_AUTO_START_MASK; + if (auto_start) { + WRITE_VCBUS_REG_BITS( + ins->rdma_regadr->trigger_mask_reg, + 0, + ins->rdma_regadr->trigger_mask_reg_bitpos, + 8); + + WRITE_VCBUS_REG_BITS( + ins->rdma_regadr->addr_inc_reg, + 0, + ins->rdma_regadr->addr_inc_reg_bitpos, + 1); + WRITE_VCBUS_REG_BITS( + ins->rdma_regadr->rw_flag_reg, + 1, + ins->rdma_regadr->rw_flag_reg_bitpos, + 1); + WRITE_VCBUS_REG_BITS( + ins->rdma_regadr->trigger_mask_reg, + trigger_type, + ins->rdma_regadr->trigger_mask_reg_bitpos, + 8); + ret = 1; + } else if (ins->rdma_item_count <= 0 || trigger_type == 0) { if (trigger_type == RDMA_TRIGGER_MANUAL) WRITE_VCBUS_REG(RDMA_ACCESS_MAN, READ_VCBUS_REG(RDMA_ACCESS_MAN) & (~1)); diff --git a/drivers/amlogic/media/logo/Kconfig b/drivers/amlogic/media/logo/Kconfig new file mode 100644 index 000000000000..3edd503cd286 --- /dev/null +++ b/drivers/amlogic/media/logo/Kconfig @@ -0,0 +1,10 @@ +# +# Amlogic Logo configuration +# +config AMLOGIC_MEDIA_LOGO + bool "Amlogic Logo Module" + default n + depends on AMLOGIC_MEDIA_FB + depends on AMLOGIC_VOUT + help + Select to enable Logo module diff --git a/drivers/amlogic/media/logo/Makefile b/drivers/amlogic/media/logo/Makefile new file mode 100644 index 000000000000..c797306b0142 --- /dev/null +++ b/drivers/amlogic/media/logo/Makefile @@ -0,0 +1,4 @@ +obj-$(CONFIG_AMLOGIC_MEDIA_LOGO) += logo.o + +ccflags-y += -Idrivers/amlogic/display/ +ccflags-y += -Idrivers/amlogic/media/ \ No newline at end of file diff --git a/drivers/amlogic/media/logo/logo.c b/drivers/amlogic/media/logo/logo.c new file mode 100644 index 000000000000..0de0b0fc3056 --- /dev/null +++ b/drivers/amlogic/media/logo/logo.c @@ -0,0 +1,307 @@ +/* + * drivers/amlogic/media/logo/logo.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. + * + */ + +/* Linux Headers */ +#include +#include +#include + +/* Amlogic Headers */ +#include +#include + +/* Local Headers */ +#include + + +#undef pr_fmt +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#define LOGO_DEV_OSD0 0x0 +#define LOGO_DEV_OSD1 0x1 +#define LOGO_DEBUG 0x1001 +#define LOGO_LOADED 0x1002 + +static enum vmode_e hdmimode = VMODE_MAX; +static enum vmode_e cvbsmode = VMODE_MAX; +static enum vmode_e last_mode = VMODE_MAX; +static u32 vout_init_vmode = VMODE_INIT_NULL; + +struct delayed_work logo_work; +static DEFINE_MUTEX(logo_lock); + +struct para_pair_s { + char *name; + int value; +}; + +static struct para_pair_s logo_args[] = { + {"osd0", LOGO_DEV_OSD0}, + {"osd1", LOGO_DEV_OSD1}, + {"debug", LOGO_DEBUG}, + {"loaded", LOGO_LOADED}, +}; + +struct logo_info_s { + int index; + u32 vmode; + u32 debug; + u32 loaded; +} logo_info = { + .index = -1, + .vmode = VMODE_MAX, + .debug = 0, + .loaded = 0, +}; + + +static int get_value_by_name(char *name, struct para_pair_s *pair, u32 cnt) +{ + u32 i = 0; + int found = -1; + + for (i = 0; i < cnt; i++, pair++) { + if (strcmp(pair->name, name) == 0) { + found = pair->value; + break; + } + } + + return found; +} + +int set_osd_freescaler(int index, enum vmode_e new_mode) +{ + const struct vinfo_s *vinfo; + + osd_set_free_scale_mode_hw(index, 1); + osd_set_free_scale_enable_hw(index, 0); + + osd_set_free_scale_axis_hw(index, 0, 0, 1919, 1079); + osd_update_disp_axis_hw(index, 0, 1919, 0, 1079, 0, 0, 0); + vinfo = get_current_vinfo(); + if (vinfo) { + pr_info("outputmode changed to %s, reset osd%d scaler\n", + vinfo->name, index); + osd_set_window_axis_hw(index, 0, 0, + (vinfo->width - 1), (vinfo->height - 1)); + } else { + osd_set_window_axis_hw(index, 0, 0, 1919, 1079); + pr_info("error: vinfo is NULL\n"); + } + + if (osd_get_logo_index() != logo_info.index) { + pr_info("logo changed, return"); + return -1; + } + osd_set_free_scale_enable_hw(index, 0x10001); + osd_enable_hw(index, 1); + pr_info("finish"); + return 0; +} + +enum vmode_e get_logo_vmode(void) +{ + return vout_init_vmode; +} + +static int set_logo_vmode(enum vmode_e mode) +{ + int ret = 0; + + if (mode == VMODE_INIT_NULL) + return -1; + + vout_init_vmode = mode; + set_current_vmode(mode); + + return ret; +} + +static int refresh_mode_and_logo(bool first) +{ + enum vmode_e cur_mode = VMODE_MAX; + int hdp_state = 0; + +#ifdef AMLOGIC_HDMI_TX + hdp_state = get_hpd_state(); +#endif + + if (!first && osd_get_logo_index() != logo_info.index) + return -1; + + if (hdp_state) + cur_mode = hdmimode; + else + cur_mode = cvbsmode; + + if (first) { + last_mode = get_logo_vmode(); + + if (logo_info.index >= 0) { + osd_set_logo_index(logo_info.index); + /* osd_init_hw(logo_info.loaded); */ + } + } + + if (cur_mode >= VMODE_MAX) /* not box platform */ + return -1; + if (cur_mode != last_mode) { + pr_info("mode chang\n"); + if (logo_info.index >= 0) + osd_enable_hw(logo_info.index, 0); + set_logo_vmode(cur_mode); + pr_info("set vmode: %s\n", + get_current_vinfo()->name); + last_mode = cur_mode; + vout_notifier_call_chain(VOUT_EVENT_MODE_CHANGE, &cur_mode); + if (logo_info.index >= 0) + set_osd_freescaler(logo_info.index, cur_mode); + } + + return 0; +} + +void aml_logo_work(struct work_struct *work) +{ + mutex_lock(&logo_lock); + + refresh_mode_and_logo(false); + + mutex_unlock(&logo_lock); + + if (osd_get_logo_index() == logo_info.index) + schedule_delayed_work(&logo_work, 1*HZ/2); + +} + +static int logo_info_init(char *para) +{ + u32 count = 0; + int value = -1; + + count = ARRAY_SIZE(logo_args) / sizeof(logo_args[0]); + value = get_value_by_name(para, logo_args, count); + if (value >= 0) { + switch (value) { + case LOGO_DEV_OSD0: + logo_info.index = LOGO_DEV_OSD0; + break; + case LOGO_DEV_OSD1: + logo_info.index = LOGO_DEV_OSD1; + break; + case LOGO_DEBUG: + logo_info.debug = 1; + break; + case LOGO_LOADED: + logo_info.loaded = 1; + break; + default: + break; + } + return 0; + } + + return 0; +} + +static int str2lower(char *str) +{ + while (*str != '\0') { + *str = tolower(*str); + str++; + } + return 0; +} + +static int __init logo_setup(char *str) +{ + char *ptr = str; + char sep[2]; + char *option; + int count = 5; + char find = 0; + + if (str == NULL) + return -EINVAL; + + do { + if (!isalpha(*ptr) && !isdigit(*ptr)) { + find = 1; + break; + } + } while (*++ptr != '\0'); + + if (!find) + return -EINVAL; + + logo_info.index = -1; + logo_info.debug = 0; + logo_info.loaded = 0; + logo_info.vmode = VMODE_MAX; + + sep[0] = *ptr; + sep[1] = '\0'; + while ((count--) && (option = strsep(&str, sep))) { + pr_info("%s\n", option); + str2lower(option); + logo_info_init(option); + } + return 0; +} +__setup("logo=", logo_setup); + +static int __init get_hdmi_mode(char *str) +{ + hdmimode = get_current_vmode(); + /* hdmimode = vmode_name_to_mode(str); */ + + pr_info("get hdmimode: %s\n", str); + return 1; +} +__setup("hdmimode=", get_hdmi_mode); + +static int __init get_cvbs_mode(char *str) +{ + if (strncmp("480", str, 3) == 0) + cvbsmode = VMODE_480CVBS; + else if (strncmp("576", str, 3) == 0) + cvbsmode = VMODE_576CVBS; + else if (strncmp("nocvbs", str, 6) == 0) + cvbsmode = hdmimode; + pr_info("get cvbsmode: %s\n", str); + return 1; +} +__setup("cvbsmode=", get_cvbs_mode); + +static int __init logo_init(void) +{ + int ret = 0; + + pr_info("%s\n", __func__); + + if (logo_info.loaded == 0) + return 0; + + refresh_mode_and_logo(true); + + INIT_DELAYED_WORK(&logo_work, aml_logo_work); + schedule_delayed_work(&logo_work, 1*HZ/2); + + return ret; +} +subsys_initcall(logo_init); diff --git a/drivers/amlogic/media/osd/Kconfig b/drivers/amlogic/media/osd/Kconfig new file mode 100644 index 000000000000..93e4d3341840 --- /dev/null +++ b/drivers/amlogic/media/osd/Kconfig @@ -0,0 +1,70 @@ +# +# Frame buffer configuration +# +menu "Amlogic OSD Module" + +config AMLOGIC_MEDIA_FB + bool "Amlogic OSD Support" + depends on FB + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + depends on AMLOGIC_MEDIA_CANVAS +# depends on AMLOGIC_VOUT_SERVE + default n + help + This is the frame buffer device driver. + It provide basic frame buffer device driver. + + It need enable canvas. + It need enable vout. + +config AMLOGIC_MEDIAFB_OSD_SYNC_FENCE + bool "OSD SYNC FENCE" + default n + depends on AMLOGIC_MEDIA_FB + depends on STAGING + depends on ANDROID + depends on SYNC + depends on SW_SYNC + help + Select to enable OSD SYNC FENCE. + This is the frame buffer device driver. + It provide basic frame buffer device driver. + + This module is used in android system. + It used sync fence. + +config AMLOGIC_MEDIA_FB_OSD_VSYNC_RDMA + bool "OSD VSYNC RDMA" + default n + depends on AMLOGIC_MEDIA_FB + depends on AMLOGIC_MEDIA_RDMA + help + This is the frame buffer device driver. + Select to enable OSD VSYNC RDMA. + + This module used VSYNC RDMA. + It used rdma. + +config AMLOGIC_MEDIA_FB_OSD2_ENABLE + bool "OSD2 Layer Support" + default n + depends on AMLOGIC_MEDIA_FB + help + This is the frame buffer device driver. + Select to enable OSD2 Layer. + + This module enable OSD2 layer, + otherwise we used OSD1 only. + +config AMLOGIC_MEDIA_FB_OSD2_CURSOR + bool "OSD2 Cursor Support" + depends on AMLOGIC_MEDIA_FB_OSD2_ENABLE + default n + help + This is the frame buffer device driver. + Select to enable OSD2 cursor. + + This module used2 OSD2 as cursor. +endmenu diff --git a/drivers/amlogic/media/osd/Makefile b/drivers/amlogic/media/osd/Makefile new file mode 100644 index 000000000000..313138692023 --- /dev/null +++ b/drivers/amlogic/media/osd/Makefile @@ -0,0 +1,10 @@ +obj-$(CONFIG_AMLOGIC_MEDIA_FB) += fb.o +fb-objs = osd_hw.o osd_fb.o osd_debug.o osd_backup.o +fb-objs += osd_antiflicker.o osd_clone.o + +obj-$(CONFIG_AMLOGIC_MEDIA_FB_OSD_VSYNC_RDMA) += osd_rdma.o + +obj-$(CONFIG_INSTABOOT) += osd_progressbar.o + +ccflags-y += -Idrivers/amlogic/media/common/ion_dev/ +ccflags-y += -Idrivers/staging/android/ diff --git a/drivers/amlogic/media/osd/osd.h b/drivers/amlogic/media/osd/osd.h new file mode 100644 index 000000000000..828ff688d0af --- /dev/null +++ b/drivers/amlogic/media/osd/osd.h @@ -0,0 +1,339 @@ +/* + * drivers/amlogic/media/osd/osd.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 _OSD_H_ +#define _OSD_H_ + +enum color_index_e { + COLOR_INDEX_02_PAL4 = 2, /* 0 */ + COLOR_INDEX_04_PAL16 = 4, /* 0 */ + COLOR_INDEX_08_PAL256 = 8, + COLOR_INDEX_16_655 = 9, + COLOR_INDEX_16_844 = 10, + COLOR_INDEX_16_6442 = 11, + COLOR_INDEX_16_4444_R = 12, + COLOR_INDEX_16_4642_R = 13, + COLOR_INDEX_16_1555_A = 14, + COLOR_INDEX_16_4444_A = 15, + COLOR_INDEX_16_565 = 16, + + COLOR_INDEX_24_6666_A = 19, + COLOR_INDEX_24_6666_R = 20, + COLOR_INDEX_24_8565 = 21, + COLOR_INDEX_24_5658 = 22, + COLOR_INDEX_24_888_B = 23, + COLOR_INDEX_24_RGB = 24, + + COLOR_INDEX_32_BGRX = 25, + COLOR_INDEX_32_XBGR = 26, + COLOR_INDEX_32_RGBX = 27, + COLOR_INDEX_32_XRGB = 28, + + COLOR_INDEX_32_BGRA = 29, + COLOR_INDEX_32_ABGR = 30, + COLOR_INDEX_32_RGBA = 31, + COLOR_INDEX_32_ARGB = 32, + + COLOR_INDEX_YUV_422 = 33, +}; + +#define VPP_OSD2_PREBLEND (1 << 17) +#define VPP_OSD1_PREBLEND (1 << 16) +#define VPP_VD2_PREBLEND (1 << 15) +#define VPP_VD1_PREBLEND (1 << 14) +#define VPP_OSD2_POSTBLEND (1 << 13) +#define VPP_OSD1_POSTBLEND (1 << 12) +#define VPP_VD2_POSTBLEND (1 << 11) +#define VPP_VD1_POSTBLEND (1 << 10) +#define VPP_POSTBLEND_EN (1 << 7) +#define VPP_PRE_FG_OSD2 (1 << 5) +#define VPP_PREBLEND_EN (1 << 6) +#define VPP_POST_FG_OSD2 (1 << 4) + +/* OSD device ioctl definition */ +#define FBIOPUT_OSD_SRCKEY_ENABLE 0x46fa +#define FBIOPUT_OSD_SRCCOLORKEY 0x46fb +#define FBIOGET_OSD_DMABUF 0x46fc +#define FBIOPUT_OSD_SET_GBL_ALPHA 0x4500 +#define FBIOGET_OSD_GET_GBL_ALPHA 0x4501 +#define FBIOPUT_OSD_2X_SCALE 0x4502 +#define FBIOPUT_OSD_ENABLE_3D_MODE 0x4503 +#define FBIOPUT_OSD_FREE_SCALE_ENABLE 0x4504 +#define FBIOPUT_OSD_FREE_SCALE_WIDTH 0x4505 +#define FBIOPUT_OSD_FREE_SCALE_HEIGHT 0x4506 +#define FBIOPUT_OSD_ORDER 0x4507 +#define FBIOGET_OSD_ORDER 0x4508 +#define FBIOGET_OSD_SCALE_AXIS 0x4509 +#define FBIOPUT_OSD_SCALE_AXIS 0x450a +#define FBIOGET_OSD_BLOCK_WINDOWS 0x450b +#define FBIOPUT_OSD_BLOCK_WINDOWS 0x450c +#define FBIOGET_OSD_BLOCK_MODE 0x450d +#define FBIOPUT_OSD_BLOCK_MODE 0x450e +#define FBIOGET_OSD_FREE_SCALE_AXIS 0x450f +#define FBIOPUT_OSD_FREE_SCALE_AXIS 0x4510 +#define FBIOPUT_OSD_FREE_SCALE_MODE 0x4511 +#define FBIOGET_OSD_WINDOW_AXIS 0x4512 +#define FBIOPUT_OSD_WINDOW_AXIS 0x4513 +#define FBIOGET_OSD_FLUSH_RATE 0x4514 +#define FBIOPUT_OSD_REVERSE 0x4515 +#define FBIOPUT_OSD_ROTATE_ON 0x4516 +#define FBIOPUT_OSD_ROTATE_ANGLE 0x4517 +#define FBIOPUT_OSD_SYNC_ADD 0x4518 + +/* OSD color definition */ +#define KEYCOLOR_FLAG_TARGET 1 +#define KEYCOLOR_FLAG_ONHOLD 2 +#define KEYCOLOR_FLAG_CURRENT 4 + +#define HW_OSD_COUNT 2 +/* OSD block definition */ +#define HW_OSD_BLOCK_COUNT 4 +#define HW_OSD_BLOCK_REG_COUNT (HW_OSD_BLOCK_COUNT*2) +#define HW_OSD_BLOCK_ENABLE_MASK 0x000F +#define HW_OSD_BLOCK_ENABLE_0 0x0001 /* osd blk0 enable */ +#define HW_OSD_BLOCK_ENABLE_1 0x0002 /* osd blk1 enable */ +#define HW_OSD_BLOCK_ENABLE_2 0x0004 /* osd blk2 enable */ +#define HW_OSD_BLOCK_ENABLE_3 0x0008 /* osd blk3 enable */ +#define HW_OSD_BLOCK_LAYOUT_MASK 0xFFFF0000 +#define HW_OSD_BLOCK_LAYOUT_HORIZONTAL 0x00010000 +#define HW_OSD_BLOCK_LAYOUT_VERTICAL 0x00020000 +#define HW_OSD_BLOCK_LAYOUT_GRID 0x00030000 +#define HW_OSD_BLOCK_LAYOUT_CUSTOMER 0xFFFF0000 + +#define OSD_LEFT 0 +#define OSD_RIGHT 1 +#define OSD_ORDER_01 1 +#define OSD_ORDER_10 2 +#define OSD_GLOBAL_ALPHA_DEF 0x100 +#define OSD_DATA_BIG_ENDIAN 0 +#define OSD_DATA_LITTLE_ENDIAN 1 +#define OSD_TC_ALPHA_ENABLE_DEF 0 /* disable tc_alpha */ + +#define INT_VIU_VSYNC 30 /* 35 */ +#define INT_VIU2_VSYNC 45 +#define INT_RDMA 121 + +#define OSD_MAX_BUF_NUM 3 /* fence relative */ + +enum osd_index_e { + OSD1 = 0, + OSD2 +}; + +enum osd_enable_e { + DISABLE = 0, + ENABLE +}; + +enum scan_mode_e { + SCAN_MODE_INTERLACE, + SCAN_MODE_PROGRESSIVE +}; + +struct color_bit_define_s { + enum color_index_e color_index; + u8 hw_colormat; + u8 hw_blkmode; + + u8 red_offset; + u8 red_length; + u8 red_msb_right; + + u8 green_offset; + u8 green_length; + u8 green_msb_right; + + u8 blue_offset; + u8 blue_length; + u8 blue_msb_right; + + u8 transp_offset; + u8 transp_length; + u8 transp_msb_right; + + u8 color_type; + u8 bpp; +}; + +struct osd_ctl_s { + u32 xres_virtual; + u32 yres_virtual; + u32 xres; + u32 yres; + u32 disp_start_x; /* coordinate of screen */ + u32 disp_start_y; + u32 disp_end_x; + u32 disp_end_y; + u32 addr; + u32 index; +}; + +struct osd_info_s { + u32 index; + u32 osd_reverse; +}; + +struct para_osd_info_s { + char *name; + u32 info; + u32 prev_idx; + u32 next_idx; + u32 cur_group_start; + u32 cur_group_end; +}; + +enum osd_dev_e { + DEV_OSD0 = 0, + DEV_OSD1, + DEV_ALL, + DEV_MAX +}; + +enum reverse_info_e { + REVERSE_FALSE = 0, + REVERSE_TRUE, + REVERSE_X, + REVERSE_Y, + REVERSE_MAX +}; + +enum hw_reg_index_e { + OSD_COLOR_MODE = 0, + OSD_ENABLE, + OSD_COLOR_KEY, + OSD_COLOR_KEY_ENABLE, + OSD_GBL_ALPHA, + OSD_CHANGE_ORDER, + OSD_FREESCALE_COEF, + DISP_GEOMETRY, + DISP_SCALE_ENABLE, + DISP_FREESCALE_ENABLE, + DISP_OSD_REVERSE, + DISP_OSD_ROTATE, + OSD_FIFO, + HW_REG_INDEX_MAX +}; + +struct pandata_s { + s32 x_start; + s32 x_end; + s32 y_start; + s32 y_end; +}; + +struct fb_geometry_s { + u32 width; /* in byte unit */ + u32 height; + u32 canvas_idx; + u32 addr; +}; + +struct osd_scale_s { + u16 h_enable; + u16 v_enable; +}; + +struct osd_3d_mode_s { + struct osd_scale_s origin_scale; + u16 enable; + u16 left_right; + u16 l_start; + u16 l_end; + u16 r_start; + u16 r_end; +}; + +struct osd_rotate_s { + u32 on_off; + u32 angle; +}; + +struct osd_fence_map_s { + struct list_head list; + + u32 fb_index; + u32 buf_num; + u32 xoffset; + u32 yoffset; + u32 yres; + s32 in_fd; + s32 out_fd; + u32 val; + struct sync_fence *in_fence; + struct files_struct *files; +}; + +struct afbcd_data_s { + u32 enable; + u32 phy_addr; + u32 addr[OSD_MAX_BUF_NUM]; + u32 frame_width; + u32 frame_height; + u32 conv_lbuf_len; +}; + +typedef void (*update_func_t)(void); +struct hw_list_s { + struct list_head list; + update_func_t update_func; +}; + +struct hw_para_s { + struct pandata_s pandata[HW_OSD_COUNT]; + struct pandata_s dispdata[HW_OSD_COUNT]; + struct pandata_s scaledata[HW_OSD_COUNT]; + struct pandata_s free_src_data[HW_OSD_COUNT]; + struct pandata_s free_dst_data[HW_OSD_COUNT]; + /* struct pandata_s rotation_pandata[HW_OSD_COUNT]; */ + struct pandata_s cursor_dispdata[HW_OSD_COUNT]; + + u32 gbl_alpha[HW_OSD_COUNT]; + u32 color_key[HW_OSD_COUNT]; + u32 color_key_enable[HW_OSD_COUNT]; + u32 enable[HW_OSD_COUNT]; + u32 reg_status_save; +#ifdef FIQ_VSYNC + bridge_item_t fiq_handle_item; +#endif + struct osd_scale_s scale[HW_OSD_COUNT]; + struct osd_scale_s free_scale[HW_OSD_COUNT]; + u32 free_scale_enable[HW_OSD_COUNT]; + struct fb_geometry_s fb_gem[HW_OSD_COUNT]; + const struct color_bit_define_s *color_info[HW_OSD_COUNT]; + u32 scan_mode; + u32 order; + struct osd_3d_mode_s mode_3d[HW_OSD_COUNT]; + u32 updated[HW_OSD_COUNT]; + /* u32 block_windows[HW_OSD_COUNT][HW_OSD_BLOCK_REG_COUNT]; */ + u32 block_mode[HW_OSD_COUNT]; + u32 free_scale_mode[HW_OSD_COUNT]; + u32 osd_reverse[HW_OSD_COUNT]; + /* struct osd_rotate_s rotate[HW_OSD_COUNT]; */ + struct hw_list_s reg[HW_OSD_COUNT][HW_REG_INDEX_MAX]; + u32 field_out_en; + u32 scale_workaround; + u32 fb_for_4k2k; + u32 antiflicker_mode; + u32 angle[HW_OSD_COUNT]; + u32 clone[HW_OSD_COUNT]; + u32 bot_type; + u32 hw_reset_flag; + struct afbcd_data_s osd_afbcd[HW_OSD_COUNT]; + u32 urgent[HW_OSD_COUNT]; +}; + +#endif /* _OSD_H_ */ diff --git a/drivers/amlogic/media/osd/osd_antiflicker.c b/drivers/amlogic/media/osd/osd_antiflicker.c new file mode 100644 index 000000000000..799d18260046 --- /dev/null +++ b/drivers/amlogic/media/osd/osd_antiflicker.c @@ -0,0 +1,197 @@ +/* + * drivers/amlogic/media/osd/osd_antiflicker.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. + * + */ + +/* Linux Headers */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Amlogic Headers */ +#include +#include +#ifdef CONFIG_AMLOGIC_MEDIA_CANVAS +#include +#include +#endif +#ifdef CONFIG_AMLOGIC_MEDIA_GE2D +#include +#endif +/* Local Headers */ +#include "osd_canvas.h" +#include "osd_antiflicker.h" +#include "osd_log.h" +#include "osd_io.h" + + +#ifdef OSD_GE2D_ANTIFLICKER_SUPPORT +struct osd_antiflicker_s { + bool inited; + u32 yoffset; + u32 yres; + struct config_para_ex_s ge2d_config; + struct ge2d_context_s *ge2d_context; +}; + +static DEFINE_MUTEX(osd_antiflicker_mutex); +static struct osd_antiflicker_s ge2d_osd_antiflicker; + +void osd_antiflicker_enable(u32 enable) +{ + ge2d_antiflicker_enable(ge2d_osd_antiflicker.ge2d_context, enable); +} + +static int osd_antiflicker_process(void) +{ + int ret = -1; + struct canvas_s cs, cd; + u32 x0 = 0; + u32 y0 = 0; + u32 y1 = 0; + u32 yres = 0; + struct config_para_ex_s *ge2d_config = NULL; + struct ge2d_context_s *context = NULL; + + ge2d_config = &ge2d_osd_antiflicker.ge2d_config; + context = ge2d_osd_antiflicker.ge2d_context; + + mutex_lock(&osd_antiflicker_mutex); + + canvas_read(OSD1_CANVAS_INDEX, &cs); + canvas_read(OSD1_CANVAS_INDEX, &cd); + + if (ge2d_osd_antiflicker.yoffset > 0) { + y0 = ge2d_osd_antiflicker.yoffset; + y1 = ge2d_osd_antiflicker.yoffset; + } + + yres = cs.height / ge2d_osd_antiflicker.yres; + memset(ge2d_config, 0, sizeof(struct config_para_ex_s)); + ge2d_config->alu_const_color = 0; + ge2d_config->bitmask_en = 0; + ge2d_config->src1_gb_alpha = 0; + + ge2d_config->src_planes[0].addr = cs.addr; + ge2d_config->src_planes[0].w = cs.width / 4; + ge2d_config->src_planes[0].h = cs.height; + + ge2d_config->dst_planes[0].addr = cd.addr; + ge2d_config->dst_planes[0].w = cd.width / 4; + ge2d_config->dst_planes[0].h = cd.height; + + ge2d_config->src_para.canvas_index = OSD1_CANVAS_INDEX; + ge2d_config->src_para.mem_type = CANVAS_OSD0; + ge2d_config->dst_para.format = GE2D_FORMAT_S32_ARGB; + ge2d_config->src_para.fill_color_en = 0; + ge2d_config->src_para.fill_mode = 0; + ge2d_config->src_para.x_rev = 0; + ge2d_config->src_para.y_rev = 0; + ge2d_config->src_para.color = 0xffffffff; + ge2d_config->src_para.top = 0; + ge2d_config->src_para.left = 0; + ge2d_config->src_para.width = cs.width / 4; + ge2d_config->src_para.height = cs.height; + + ge2d_config->dst_para.canvas_index = OSD1_CANVAS_INDEX; + ge2d_config->dst_para.mem_type = CANVAS_OSD0; + ge2d_config->dst_para.format = GE2D_FORMAT_S32_ARGB; + ge2d_config->dst_para.top = 0; + ge2d_config->dst_para.left = 0; + ge2d_config->dst_para.width = cd.width / 4; + ge2d_config->dst_para.height = cd.height; + ge2d_config->dst_para.fill_color_en = 0; + ge2d_config->dst_para.fill_mode = 0; + ge2d_config->dst_para.color = 0; + ge2d_config->dst_para.x_rev = 0; + ge2d_config->dst_para.y_rev = 0; + ge2d_config->dst_xy_swap = 0; + + ret = ge2d_context_config_ex(context, ge2d_config); + mutex_unlock(&osd_antiflicker_mutex); + + if (ret < 0) { + osd_log_info("++ osd antiflicker ge2d config ex error.\n"); + return ret; + } + + stretchblt(context, x0, y0, cs.width / 4, (cs.height / yres), x0, y1, + cd.width / 4, (cd.height / yres)); + return ret; +} + +void osd_antiflicker_update_pan(u32 yoffset, u32 yres) +{ + int ret = -1; + + if (!ge2d_osd_antiflicker.inited) + return; + + mutex_lock(&osd_antiflicker_mutex); + ge2d_osd_antiflicker.yoffset = yoffset; + ge2d_osd_antiflicker.yres = yres; + mutex_unlock(&osd_antiflicker_mutex); +#if 0 + osd_antiflicker_process(); + osd_antiflicker_process_2(); +#endif + ret = osd_antiflicker_process(); + + if (ret < 0) + osd_antiflicker_task_stop(); +} + +int osd_antiflicker_task_start(void) +{ + if (ge2d_osd_antiflicker.inited) { + osd_log_info("osd_antiflicker_task already started.\n"); + return 0; + } + + osd_log_info("osd_antiflicker_task start.\n"); + + if (ge2d_osd_antiflicker.ge2d_context == NULL) + ge2d_osd_antiflicker.ge2d_context = create_ge2d_work_queue(); + + memset(&ge2d_osd_antiflicker.ge2d_config, + 0, sizeof(struct config_para_ex_s)); + ge2d_osd_antiflicker.inited = true; + + return 0; +} + +void osd_antiflicker_task_stop(void) +{ + if (!ge2d_osd_antiflicker.inited) { + osd_log_info("osd_antiflicker_task already stopped.\n"); + return; + } + + osd_log_info("osd_antiflicker_task stop.\n"); + + if (ge2d_osd_antiflicker.ge2d_context) { + destroy_ge2d_work_queue(ge2d_osd_antiflicker.ge2d_context); + ge2d_osd_antiflicker.ge2d_context = NULL; + } + + ge2d_osd_antiflicker.inited = false; +} +#endif diff --git a/drivers/amlogic/media/osd/osd_antiflicker.h b/drivers/amlogic/media/osd/osd_antiflicker.h new file mode 100644 index 000000000000..e3e54e6de6df --- /dev/null +++ b/drivers/amlogic/media/osd/osd_antiflicker.h @@ -0,0 +1,47 @@ +/* + * drivers/amlogic/media/osd/osd_antiflicker.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 _OSD_ANTIFLICKER_H_ +#define _OSD_ANTIFLICKER_H_ + +#include "osd_log.h" + +#ifdef CONFIG_AMLOGIC_MEDIA_GE2D +#define OSD_GE2D_ANTIFLICKER_SUPPORT 1 +#endif + +#ifdef OSD_GE2D_ANTIFLICKER_SUPPORT +extern void osd_antiflicker_update_pan(u32 yoffset, u32 yres); +extern int osd_antiflicker_task_start(void); +extern void osd_antiflicker_task_stop(void); +extern void osd_antiflicker_enable(u32 enable); +#else +static inline void osd_antiflicker_enable(u32 enable) {} +static inline void osd_antiflicker_update_pan(u32 yoffset, u32 yres) {} +static inline int osd_antiflicker_task_start(void) +{ + osd_log_info("++ osd_antiflicker depends on GE2D module!\n"); + return 0; +} +static inline void osd_antiflicker_task_stop(void) +{ + osd_log_info("-- osd_antiflicker depends on GE2D module!\n"); +} +#endif + +#endif + diff --git a/drivers/amlogic/media/osd/osd_backup.c b/drivers/amlogic/media/osd/osd_backup.c new file mode 100644 index 000000000000..07a374f91729 --- /dev/null +++ b/drivers/amlogic/media/osd/osd_backup.c @@ -0,0 +1,519 @@ +/* + * drivers/amlogic/media/osd/osd_backup.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. + * + */ + +/* Linux Headers */ +#include +#include +#include + +/* Local Headers */ +#include "osd_io.h" +#include "osd_backup.h" + +const u16 osd_reg_backup[OSD_REG_BACKUP_COUNT] = { + 0x1a10, 0x1a13, + 0x1a17, 0x1a18, 0x1a19, 0x1a1a, 0x1a1b, 0x1a1c, 0x1a1d, 0x1a1e, + 0x1a2b, 0x1a2d +}; + +const u16 osd_afbc_reg_backup[OSD_AFBC_REG_BACKUP_COUNT] = { + 0x31aa, 0x31a9, + 0x31a6, 0x31a5, 0x31a4, 0x31a3, 0x31a2, 0x31a1, 0x31a0 +}; + +static u32 osd_backup_count = OSD_VALUE_COUNT; +static u32 afbc_backup_count = OSD_AFBC_VALUE_COUNT; +u32 osd_backup[OSD_VALUE_COUNT]; +u32 osd_afbc_backup[OSD_AFBC_VALUE_COUNT]; +module_param_array(osd_backup, uint, &osd_backup_count, 0444); +MODULE_PARM_DESC(osd_backup, "\n osd register backup\n"); +module_param_array(osd_afbc_backup, uint, &afbc_backup_count, 0444); +MODULE_PARM_DESC(osd_afbc_backup, "\n osd afbc register backup\n"); + +/* 0: not backup */ +static u32 backup_enable; +module_param(backup_enable, uint, 0444); +void update_backup_reg(u32 addr, u32 value) +{ + u32 base = OSD1_AFBCD_ENABLE; + + if (!backup_enable) + return; + if ((addr >= OSD1_AFBCD_ENABLE) && + (addr <= OSD1_AFBCD_PIXEL_VSCOPE) && + (backup_enable & HW_RESET_AFBCD_REGS)) { + osd_afbc_backup[addr - base] = value; + } + base = VIU_OSD1_CTRL_STAT; + if ((addr >= VIU_OSD1_CTRL_STAT) && + (addr <= VIU_OSD1_CTRL_STAT2) && + (backup_enable & HW_RESET_OSD1_REGS)) { + osd_backup[addr - base] = value; + } +} + +s32 get_backup_reg(u32 addr, u32 *value) +{ + int i; + u32 base = OSD1_AFBCD_ENABLE; + + if (!backup_enable || !value) + return -1; + + if ((addr >= OSD1_AFBCD_ENABLE) && + (addr <= OSD1_AFBCD_PIXEL_VSCOPE) && + (backup_enable & HW_RESET_AFBCD_REGS)) { + for (i = 0; i < OSD_AFBC_REG_BACKUP_COUNT; i++) + if (addr == osd_afbc_reg_backup[i]) { + *value = osd_afbc_backup[addr - base]; + return 0; + } + } + base = VIU_OSD1_CTRL_STAT; + if ((addr >= VIU_OSD1_CTRL_STAT) && + (addr <= VIU_OSD1_CTRL_STAT2) && + (backup_enable & HW_RESET_OSD1_REGS)) { + for (i = 0; i < OSD_REG_BACKUP_COUNT; i++) + if (addr == osd_reg_backup[i]) { + *value = osd_backup[addr - base]; + return 0; + } + } + return -1; +} + +void backup_regs_init(u32 backup_mask) +{ + int i = 0; + u32 addr; + u32 base = VIU_OSD1_CTRL_STAT; + + if (backup_enable) + return; + + while ((backup_mask & HW_RESET_OSD1_REGS) + && (i < OSD_REG_BACKUP_COUNT)) { + addr = osd_reg_backup[i]; + osd_backup[addr - base] = + osd_reg_read(addr); + i++; + } + i = 0; + base = OSD1_AFBCD_ENABLE; + while ((backup_mask & HW_RESET_AFBCD_REGS) + && (i < OSD_AFBC_REG_BACKUP_COUNT)) { + addr = osd_afbc_reg_backup[i]; + osd_afbc_backup[addr - base] = + osd_reg_read(addr); + i++; + } + backup_enable = backup_mask; +} + +u32 is_backup(void) +{ + return backup_enable; +} + +#ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD_VSYNC_RDMA +/* recovery section */ +#define INVAILD_REG_ITEM {0xffff, 0x0, 0x0, 0x0} +#define REG_RECOVERY_TABLE 5 + +static struct reg_recovery_table gRecovery[REG_RECOVERY_TABLE]; +static u32 recovery_enable; + +static struct reg_item osd1_recovery_table[] = { + {VIU_OSD1_CTRL_STAT, 0x0, 0x401ff9f1, 1}, + INVAILD_REG_ITEM, /* VIU_OSD1_COLOR_ADDR 0x1a11 */ + INVAILD_REG_ITEM, /* VIU_OSD1_COLOR 0x1a12 */ + {VIU_OSD1_BLK0_CFG_W4, 0x0, 0x0fff0fff, 1}, + INVAILD_REG_ITEM, /* VIU_OSD1_BLK1_CFG_W4 0x1a14 */ + INVAILD_REG_ITEM, /* VIU_OSD1_BLK2_CFG_W4 0x1a15 */ + INVAILD_REG_ITEM, /* VIU_OSD1_BLK3_CFG_W4 0x1a16 */ + {VIU_OSD1_TCOLOR_AG0, 0x0, 0xffffffff, 1}, + {VIU_OSD1_TCOLOR_AG1, 0x0, 0xffffffff, 0}, + {VIU_OSD1_TCOLOR_AG2, 0x0, 0xffffffff, 0}, + {VIU_OSD1_TCOLOR_AG3, 0x0, 0xffffffff, 0}, + {VIU_OSD1_BLK0_CFG_W0, 0x0, 0x30ffffff, 1}, + {VIU_OSD1_BLK0_CFG_W1, 0x0, 0x1fff1fff, 1}, + {VIU_OSD1_BLK0_CFG_W2, 0x0, 0x1fff1fff, 1}, + {VIU_OSD1_BLK0_CFG_W3, 0x0, 0x0fff0fff, 1}, + INVAILD_REG_ITEM, /* VIU_OSD1_BLK1_CFG_W0 0x1a1f */ + INVAILD_REG_ITEM, /* VIU_OSD1_BLK1_CFG_W1 0x1a20 */ + INVAILD_REG_ITEM, /* VIU_OSD1_BLK1_CFG_W2 0x1a21 */ + INVAILD_REG_ITEM, /* VIU_OSD1_BLK1_CFG_W3 0x1a22 */ + INVAILD_REG_ITEM, /* VIU_OSD1_BLK2_CFG_W0 0x1a23 */ + INVAILD_REG_ITEM, /* VIU_OSD1_BLK2_CFG_W1 0x1a24 */ + INVAILD_REG_ITEM, /* VIU_OSD1_BLK2_CFG_W2 0x1a25 */ + INVAILD_REG_ITEM, /* VIU_OSD1_BLK2_CFG_W3 0x1a26 */ + INVAILD_REG_ITEM, /* VIU_OSD1_BLK3_CFG_W0 0x1a27 */ + INVAILD_REG_ITEM, /* VIU_OSD1_BLK3_CFG_W1 0x1a28 */ + INVAILD_REG_ITEM, /* VIU_OSD1_BLK3_CFG_W2 0x1a29 */ + INVAILD_REG_ITEM, /* VIU_OSD1_BLK3_CFG_W3 0x1a2a */ + {VIU_OSD1_FIFO_CTRL_STAT, 0x0, 0xffc3ffff, 1}, + INVAILD_REG_ITEM, /* VIU_OSD1_TEST_RDDATA 0x1a2c */ + {VIU_OSD1_CTRL_STAT2, 0x0, 0x0000ffff, 1}, +}; + +static struct reg_item osd_afbcd_recovery_table[] = { + {OSD1_AFBCD_ENABLE, 0x0, 0x0000ff01, 1}, + {OSD1_AFBCD_MODE, 0x0, 0x937f007f, 1}, + {OSD1_AFBCD_SIZE_IN, 0x0, 0xffffffff, 1}, + {OSD1_AFBCD_HDR_PTR, 0x0, 0xffffffff, 1}, + {OSD1_AFBCD_FRAME_PTR, 0x0, 0xffffffff, 1}, + {OSD1_AFBCD_CHROMA_PTR, 0x0, 0xffffffff, 1}, + {OSD1_AFBCD_CONV_CTRL, 0x0, 0x0000ffff, 1}, + INVAILD_REG_ITEM, /* unused 0x31a7 */ + INVAILD_REG_ITEM, /* OSD1_AFBCD_STATUS 0x31a8 */ + {OSD1_AFBCD_PIXEL_HSCOPE, 0x0, 0xffffffff, 1}, + {OSD1_AFBCD_PIXEL_VSCOPE, 0x0, 0xffffffff, 1} +}; + +static struct reg_item freescale_recovery_table[] = { + {VPP_OSD_VSC_PHASE_STEP, 0x0, 0x0fffffff, 1}, + {VPP_OSD_VSC_INI_PHASE, 0x0, 0xffffffff, 1}, + {VPP_OSD_VSC_CTRL0, 0x0, 0x01fb7b7f, 1}, + {VPP_OSD_HSC_PHASE_STEP, 0x0, 0x0fffffff, 1}, + {VPP_OSD_HSC_INI_PHASE, 0x0, 0xffffffff, 1}, + {VPP_OSD_HSC_CTRL0, 0x0, 0x007b7b7f, 1}, + {VPP_OSD_HSC_INI_PAT_CTRL, 0x0, 0x0000ff77, 1}, + {VPP_OSD_SC_DUMMY_DATA, 0x0, 0xffffffff, 0}, + {VPP_OSD_SC_CTRL0, 0x0, 0x00007ffb, 1}, + {VPP_OSD_SCI_WH_M1, 0x0, 0x1fff1fff, 1}, + {VPP_OSD_SCO_H_START_END, 0x0, 0x0fff0fff, 1}, + {VPP_OSD_SCO_V_START_END, 0x0, 0x0fff0fff, 1}, + {VPP_OSD_SCALE_COEF_IDX, 0x0, 0x0000c37f, 0}, + {VPP_OSD_SCALE_COEF, 0x0, 0xffffffff, 0} +}; + +static struct reg_item osd2_recovery_table[] = { + {VIU_OSD2_CTRL_STAT, 0x0, 0x401ff9f1, 1}, + INVAILD_REG_ITEM, /* VIU_OSD2_COLOR_ADDR 0x1a31 */ + INVAILD_REG_ITEM, /* VIU_OSD2_COLOR 0x1a32 */ + INVAILD_REG_ITEM, /* VIU_OSD2_HL1_H_START_END 0x1a33 */ + INVAILD_REG_ITEM, /* VIU_OSD2_HL1_V_START_END 0x1a34 */ + INVAILD_REG_ITEM, /* VIU_OSD2_HL2_H_START_END 0x1a35 */ + INVAILD_REG_ITEM, /* VIU_OSD2_HL2_V_START_END 0x1a36 */ + {VIU_OSD2_TCOLOR_AG0, 0x0, 0xffffffff, 1}, + {VIU_OSD2_TCOLOR_AG1, 0x0, 0xffffffff, 0}, + {VIU_OSD2_TCOLOR_AG2, 0x0, 0xffffffff, 0}, + {VIU_OSD2_TCOLOR_AG3, 0x0, 0xffffffff, 0}, + {VIU_OSD2_BLK0_CFG_W0, 0x0, 0x00ffffff, 1}, + {VIU_OSD2_BLK0_CFG_W1, 0x0, 0x1fff1fff, 1}, + {VIU_OSD2_BLK0_CFG_W2, 0x0, 0x1fff1fff, 1}, + {VIU_OSD2_BLK0_CFG_W3, 0x0, 0x0fff0fff, 1}, + {VIU_OSD2_BLK1_CFG_W0, 0x0, 0x00ffffff, 0}, + {VIU_OSD2_BLK1_CFG_W1, 0x0, 0x1fff1fff, 0}, + {VIU_OSD2_BLK1_CFG_W2, 0x0, 0x1fff1fff, 0}, + {VIU_OSD2_BLK1_CFG_W3, 0x0, 0x0fff0fff, 0}, + {VIU_OSD2_BLK2_CFG_W0, 0x0, 0x00ffffff, 0}, + {VIU_OSD2_BLK2_CFG_W1, 0x0, 0x1fff1fff, 0}, + {VIU_OSD2_BLK2_CFG_W2, 0x0, 0x1fff1fff, 0}, + {VIU_OSD2_BLK2_CFG_W3, 0x0, 0x0fff0fff, 0}, + {VIU_OSD2_BLK3_CFG_W0, 0x0, 0x00ffffff, 0}, + {VIU_OSD2_BLK3_CFG_W1, 0x0, 0x1fff1fff, 0}, + {VIU_OSD2_BLK3_CFG_W2, 0x0, 0x1fff1fff, 0}, + {VIU_OSD2_BLK3_CFG_W3, 0x0, 0x0fff0fff, 0}, + {VIU_OSD2_FIFO_CTRL_STAT, 0x0, 0xffc3ffff, 1}, + INVAILD_REG_ITEM, /* VIU_OSD2_TEST_RDDATA 0x1a4c */ + {VIU_OSD2_CTRL_STAT2, 0x0, 0x00007ffd, 1} +}; + + +static struct reg_item misc_recovery_table[] = { + {VIU_OSD2_BLK0_CFG_W4, 0x0, 0x0fff0fff, 1}, + {VIU_OSD2_BLK1_CFG_W4, 0x0, 0xffffffff, 0}, + {VIU_OSD2_BLK2_CFG_W4, 0x0, 0xffffffff, 0}, + {VIU_OSD2_BLK3_CFG_W4, 0x0, 0xffffffff, 0}, + {VPU_RDARB_MODE_L1C2, 0x0, 0x00010000, 1}, + {VIU_MISC_CTRL1, 0x0, 0x0000ff00, 1} +}; + +void recovery_regs_init(void) +{ + int i = 0; + + if (recovery_enable) + return; + memset(gRecovery, 0, sizeof(gRecovery)); + gRecovery[i].base_addr = VIU_OSD1_CTRL_STAT; + gRecovery[i].size = sizeof(osd1_recovery_table) + / sizeof(struct reg_item); + gRecovery[i].table = + (struct reg_item *)&osd1_recovery_table[0]; + + i++; + gRecovery[i].base_addr = OSD1_AFBCD_ENABLE; + gRecovery[i].size = sizeof(osd_afbcd_recovery_table) + / sizeof(struct reg_item); + gRecovery[i].table = + (struct reg_item *)&osd_afbcd_recovery_table[0]; + + i++; + gRecovery[i].base_addr = VPP_OSD_VSC_PHASE_STEP; + gRecovery[i].size = sizeof(freescale_recovery_table) + / sizeof(struct reg_item); + gRecovery[i].table = + (struct reg_item *)&freescale_recovery_table[0]; + + i++; + gRecovery[i].base_addr = VIU_OSD2_CTRL_STAT; + gRecovery[i].size = sizeof(osd2_recovery_table) + / sizeof(struct reg_item); + gRecovery[i].table = + (struct reg_item *)&osd2_recovery_table[0]; + + i++; + gRecovery[i].base_addr = 0xffffffff; /* not base addr */ + gRecovery[i].size = sizeof(misc_recovery_table) + / sizeof(struct reg_item); + gRecovery[i].table = + (struct reg_item *)&misc_recovery_table[0]; + recovery_enable = 1; +} + +int update_recovery_item(u32 addr, u32 value) +{ + u32 base, size; + int i; + struct reg_item *table = NULL; + int ret = -1; + + if (!recovery_enable) + return ret; + + base = addr & 0xfff0; + switch (base) { + case VIU_OSD1_CTRL_STAT: + case VIU_OSD1_BLK1_CFG_W1: + /* osd1 */ + if (backup_enable & + HW_RESET_OSD1_REGS) { + ret = 1; + break; + } + base = gRecovery[0].base_addr; + size = gRecovery[0].size; + table = gRecovery[0].table; + if ((addr >= base) && + (addr < base + size)) { + table[addr - base].val = value; + if (table[addr - base].recovery) + table[addr - base].recovery = 1; + ret = 0; + } + break; + case VIU_OSD2_CTRL_STAT: + case VIU_OSD2_BLK1_CFG_W1: + /* osd2 */ + base = gRecovery[3].base_addr; + size = gRecovery[3].size; + table = gRecovery[3].table; + if ((addr >= base) && + (addr < base + size)) { + table[addr - base].val = value; + if (table[addr - base].recovery) + table[addr - base].recovery = 1; + ret = 0; + } + break; + case OSD1_AFBCD_ENABLE: + /* osd1 afbcd */ + if (backup_enable & + HW_RESET_AFBCD_REGS) { + ret = 1; + break; + } + base = gRecovery[1].base_addr; + size = gRecovery[1].size; + table = gRecovery[1].table; + if ((addr >= base) && + (addr < base + size)) { + table[addr - base].val = value; + if (table[addr - base].recovery) + table[addr - base].recovery = 1; + ret = 0; + } + break; + case VPP_OSD_VSC_PHASE_STEP: + base = gRecovery[2].base_addr; + size = gRecovery[2].size; + table = gRecovery[2].table; + if ((addr >= base) && + (addr < base + size)) { + table[addr - base].val = value; + if (table[addr - base].recovery) + table[addr - base].recovery = 1; + ret = 0; + } + break; + default: + break; + } + if ((addr == VIU_OSD2_BLK0_CFG_W4) || + (addr == VIU_OSD2_BLK1_CFG_W4) || + (addr == VIU_OSD2_BLK2_CFG_W4) || + (addr == VIU_OSD2_BLK3_CFG_W4) || + (addr == VPU_RDARB_MODE_L1C2) || + (addr == VIU_MISC_CTRL1)) { + table = gRecovery[4].table; + for (i = 0; i < gRecovery[4].size; i++) { + if (addr == table[i].addr) { + table[i].val = value; + if (table[i].recovery) + table[i].recovery = 1; + ret = 0; + break; + } + } + } + return ret; +} + +s32 get_recovery_item(u32 addr, u32 *value, u32 *mask) +{ + u32 base, size; + int i; + struct reg_item *table = NULL; + int ret = -1; + + if (!recovery_enable) + return ret; + + base = addr & 0xfff0; + switch (base) { + case VIU_OSD1_CTRL_STAT: + case VIU_OSD1_BLK1_CFG_W1: + /* osd1 */ + if (backup_enable & + HW_RESET_OSD1_REGS) { + ret = 2; + break; + } + base = gRecovery[0].base_addr; + size = gRecovery[0].size; + table = gRecovery[0].table; + if ((addr >= base) && + (addr < base + size)) { + table += (addr - base); + ret = 0; + } + break; + case VIU_OSD2_CTRL_STAT: + case VIU_OSD2_BLK1_CFG_W1: + /* osd2 */ + base = gRecovery[3].base_addr; + size = gRecovery[3].size; + table = gRecovery[3].table; + if ((addr >= base) && + (addr < base + size)) { + table += (addr - base); + ret = 0; + } + break; + case OSD1_AFBCD_ENABLE: + /* osd1 afbcd */ + if (backup_enable & + HW_RESET_AFBCD_REGS) { + ret = 2; + break; + } + base = gRecovery[1].base_addr; + size = gRecovery[1].size; + table = gRecovery[1].table; + if ((addr >= base) && + (addr < base + size)) { + table += (addr - base); + ret = 0; + } + break; + case VPP_OSD_VSC_PHASE_STEP: + base = gRecovery[2].base_addr; + size = gRecovery[2].size; + table = gRecovery[2].table; + if ((addr >= base) && + (addr < base + size)) { + table += (addr - base); + ret = 0; + } + break; + default: + break; + } + + if ((addr == VIU_OSD2_BLK0_CFG_W4) || + (addr == VIU_OSD2_BLK1_CFG_W4) || + (addr == VIU_OSD2_BLK2_CFG_W4) || + (addr == VIU_OSD2_BLK3_CFG_W4) || + (addr == VPU_RDARB_MODE_L1C2) || + (addr == VIU_MISC_CTRL1)) { + table = gRecovery[4].table; + for (i = 0; i < gRecovery[4].size; i++) { + if (addr == table[i].addr) { + table += i; + ret = 0; + break; + } + } + } + if (ret == 0 && table) { + if (table->recovery == 1) { + u32 regmask = table->mask; + u32 real_value = osd_reg_read(addr); + + if ((real_value & regmask) + == (table->val & regmask)) { + ret = 1; + *mask = regmask; + *value = real_value; + } else { + *mask = regmask; + *value = real_value & ~(regmask); + *value |= (table->val & regmask); + } + table->recovery = 2; + } else if (table->recovery == 2) + ret = 1; + else + ret = -1; + } + /* ret = 1, 2 need not recovery, + * ret = 0 need recovery, + * ret = -1, not find + */ + return ret; +} +#else +void recovery_regs_init(void) +{ +} + +int update_recovery_item(u32 addr, u32 value) +{ + addr = 0; + value = 0; + return 0; +} +s32 get_recovery_item(u32 addr, u32 *value, u32 *mask) +{ + addr = 0; + value = NULL; + mask = NULL; + return 0; +} +#endif diff --git a/drivers/amlogic/media/osd/osd_backup.h b/drivers/amlogic/media/osd/osd_backup.h new file mode 100644 index 000000000000..b61df4a68806 --- /dev/null +++ b/drivers/amlogic/media/osd/osd_backup.h @@ -0,0 +1,63 @@ +/* + * drivers/amlogic/media/osd/osd_backup.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 _OSD_BACKUP_H_ +#define _OSD_BACKUP_H_ + +#include "osd_reg.h" + +#define OSD_REG_BACKUP_COUNT 12 +#define OSD_AFBC_REG_BACKUP_COUNT 9 + +#define OSD_VALUE_COUNT (VIU_OSD1_CTRL_STAT2 - VIU_OSD1_CTRL_STAT + 1) +#define OSD_AFBC_VALUE_COUNT (OSD1_AFBCD_PIXEL_VSCOPE - OSD1_AFBCD_ENABLE + 1) + +extern const u16 osd_reg_backup[OSD_REG_BACKUP_COUNT]; +extern const u16 osd_afbc_reg_backup[OSD_AFBC_REG_BACKUP_COUNT]; +extern u32 osd_backup[OSD_VALUE_COUNT]; +extern u32 osd_afbc_backup[OSD_AFBC_VALUE_COUNT]; + +enum hw_reset_flag_e { + HW_RESET_NONE = 0, + HW_RESET_AFBCD_REGS = 0x80000000, + HW_RESET_OSD1_REGS = 0x00000001, + HW_RESET_AFBCD_HARDWARE = 0x80000000, +}; + +struct reg_item { + u32 addr; + u32 val; + u32 mask; + int recovery; +}; + +struct reg_recovery_table { + u32 base_addr; + u32 size; + struct reg_item *table; +}; + +extern void update_backup_reg(u32 addr, u32 value); +extern s32 get_backup_reg(u32 addr, u32 *value); +extern void backup_regs_init(u32 backup_mask); +extern u32 is_backup(void); + +extern void recovery_regs_init(void); +extern int update_recovery_item(u32 addr, u32 value); +extern s32 get_recovery_item(u32 addr, u32 *value, u32 *mask); +#endif + diff --git a/drivers/amlogic/media/osd/osd_canvas.h b/drivers/amlogic/media/osd/osd_canvas.h new file mode 100644 index 000000000000..f35df041ba7c --- /dev/null +++ b/drivers/amlogic/media/osd/osd_canvas.h @@ -0,0 +1,27 @@ +/* + * drivers/amlogic/media/osd/osd_canvas.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 _OSD_CANVAS_H_ +#define _OSD_CANVAS_H_ + +#define OSD1_CANVAS_INDEX 0x40 +#define OSD2_CANVAS_INDEX 0x43 +#define OSD3_CANVAS_INDEX 0x41 +#define OSD4_CANVAS_INDEX 0x42 +#define ALLOC_CANVAS_INDEX 0x44 + +#endif diff --git a/drivers/amlogic/media/osd/osd_clone.c b/drivers/amlogic/media/osd/osd_clone.c new file mode 100644 index 000000000000..1869f9c0d7fa --- /dev/null +++ b/drivers/amlogic/media/osd/osd_clone.c @@ -0,0 +1,205 @@ +/* + * drivers/amlogic/media/osd/osd_clone.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. + * + */ + +/* Linux Headers */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Amlogic Headers */ +#include +#ifdef CONFIG_AMLOGIC_MEDIA_CANVAS +#include +#include +#endif +#ifdef CONFIG_AMLOGIC_MEDIA_GE2D +#include +#endif +/* Local Headers */ +#include "osd_clone.h" +#include "osd_log.h" +#include "osd_io.h" +#include "osd_canvas.h" + + +#ifdef OSD_GE2D_CLONE_SUPPORT +struct osd_clone_s { + bool inited; + int angle; + int buffer_number; + u32 osd1_yres; + u32 osd2_yres; + struct config_para_ex_s ge2d_config; + struct ge2d_context_s *ge2d_context; +}; + +static DEFINE_MUTEX(osd_clone_mutex); +static struct osd_clone_s s_osd_clone; + +static void osd_clone_process(void) +{ + struct canvas_s cs, cd; + u32 x0 = 0; + u32 y0 = 0; + u32 y1 = 0; + unsigned char x_rev = 0; + unsigned char y_rev = 0; + unsigned char xy_swap = 0; + struct config_para_ex_s *ge2d_config = &s_osd_clone.ge2d_config; + struct ge2d_context_s *context = s_osd_clone.ge2d_context; + + canvas_read(OSD1_CANVAS_INDEX, &cs); + canvas_read(OSD2_CANVAS_INDEX, &cd); + + y0 = s_osd_clone.osd1_yres * s_osd_clone.buffer_number; + y1 = s_osd_clone.osd2_yres * s_osd_clone.buffer_number; + + if (s_osd_clone.angle == 1) { + xy_swap = 1; + x_rev = 1; + } else if (s_osd_clone.angle == 2) { + x_rev = 1; + y_rev = 1; + } else if (s_osd_clone.angle == 3) { + xy_swap = 1; + y_rev = 1; + } + + memset(ge2d_config, 0, sizeof(struct config_para_ex_s)); + ge2d_config->alu_const_color = 0; + ge2d_config->bitmask_en = 0; + ge2d_config->src1_gb_alpha = 0; + ge2d_config->dst_xy_swap = 0; + + ge2d_config->src_planes[0].addr = cs.addr; + ge2d_config->src_planes[0].w = cs.width / 4; + ge2d_config->src_planes[0].h = cs.height; + + ge2d_config->dst_planes[0].addr = cd.addr; + ge2d_config->dst_planes[0].w = cd.width / 4; + ge2d_config->dst_planes[0].h = cd.height; + + ge2d_config->src_para.canvas_index = OSD1_CANVAS_INDEX; + ge2d_config->src_para.mem_type = CANVAS_OSD0; + ge2d_config->dst_para.format = GE2D_FORMAT_S32_ABGR; + ge2d_config->src_para.fill_color_en = 0; + ge2d_config->src_para.fill_mode = 0; + ge2d_config->src_para.x_rev = 0; + ge2d_config->src_para.y_rev = 0; + ge2d_config->src_para.color = 0xffffffff; + ge2d_config->src_para.top = 0; + ge2d_config->src_para.left = 0; + ge2d_config->src_para.width = cs.width / 4; + ge2d_config->src_para.height = cs.height; + + ge2d_config->dst_para.canvas_index = OSD2_CANVAS_INDEX; + ge2d_config->dst_para.mem_type = CANVAS_OSD1; + ge2d_config->dst_para.format = GE2D_FORMAT_S32_ABGR; + ge2d_config->dst_para.top = 0; + ge2d_config->dst_para.left = 0; + ge2d_config->dst_para.width = cd.width / 4; + ge2d_config->dst_para.height = cd.height; + ge2d_config->dst_para.fill_color_en = 0; + ge2d_config->dst_para.fill_mode = 0; + ge2d_config->dst_para.color = 0; + ge2d_config->dst_para.x_rev = x_rev; + ge2d_config->dst_para.y_rev = y_rev; + ge2d_config->dst_xy_swap = xy_swap; + + if (ge2d_context_config_ex(context, ge2d_config) < 0) { + osd_log_err("++ osd clone ge2d config error.\n"); + return; + } + + stretchblt(context, x0, y0, cs.width / 4, s_osd_clone.osd1_yres, x0, y1, + cd.width / 4, s_osd_clone.osd2_yres); +} + +void osd_clone_update_pan(int buffer_number) +{ + if (!s_osd_clone.inited) + return; + + mutex_lock(&osd_clone_mutex); + s_osd_clone.buffer_number = buffer_number; + mutex_unlock(&osd_clone_mutex); + osd_clone_process(); +} + +void osd_clone_set_virtual_yres(u32 osd1_yres, u32 osd2_yres) +{ + mutex_lock(&osd_clone_mutex); + s_osd_clone.osd1_yres = osd1_yres; + s_osd_clone.osd2_yres = osd2_yres; + mutex_unlock(&osd_clone_mutex); +} + +void osd_clone_get_virtual_yres(u32 *osd2_yres) +{ + mutex_lock(&osd_clone_mutex); + *osd2_yres = s_osd_clone.osd2_yres; + mutex_unlock(&osd_clone_mutex); +} + +void osd_clone_set_angle(int angle) +{ + mutex_lock(&osd_clone_mutex); + s_osd_clone.angle = angle; + mutex_unlock(&osd_clone_mutex); +} + +int osd_clone_task_start(void) +{ + if (s_osd_clone.inited) { + osd_log_info("osd_clone_task already started.\n"); + return 0; + } + + osd_log_info("osd_clone_task start.\n"); + + if (s_osd_clone.ge2d_context == NULL) + s_osd_clone.ge2d_context = create_ge2d_work_queue(); + + memset(&s_osd_clone.ge2d_config, 0, sizeof(struct config_para_ex_s)); + s_osd_clone.inited = true; + + return 1; +} + +void osd_clone_task_stop(void) +{ + if (!s_osd_clone.inited) { + osd_log_info("osd_clone_task already stopped.\n"); + return; + } + + osd_log_info("osd_clone_task stop.\n"); + + if (s_osd_clone.ge2d_context) { + destroy_ge2d_work_queue(s_osd_clone.ge2d_context); + s_osd_clone.ge2d_context = NULL; + } + + s_osd_clone.inited = false; +} +#endif diff --git a/drivers/amlogic/media/osd/osd_clone.h b/drivers/amlogic/media/osd/osd_clone.h new file mode 100644 index 000000000000..533df3befda4 --- /dev/null +++ b/drivers/amlogic/media/osd/osd_clone.h @@ -0,0 +1,50 @@ +/* + * drivers/amlogic/media/osd/osd_clone.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 _OSD_CLONE_H_ +#define _OSD_CLONE_H_ + +#include "osd_log.h" + +#ifdef CONFIG_AMLOGIC_MEDIA_GE2D +#define OSD_GE2D_CLONE_SUPPORT 1 +#endif + +#ifdef OSD_GE2D_CLONE_SUPPORT +extern void osd_clone_set_virtual_yres(u32 osd1_yres, u32 osd2_yres); +extern void osd_clone_get_virtual_yres(u32 *osd2_yres); +extern void osd_clone_set_angle(int angle); +extern void osd_clone_update_pan(int buffer_number); +extern int osd_clone_task_start(void); +extern void osd_clone_task_stop(void); +#else +static inline void osd_clone_set_virtual_yres(u32 osd1_yres, u32 osd2_yres) {} +static inline void osd_clone_get_virtual_yres(u32 *osd2_yres) {} +static inline void osd_clone_set_angle(int angle) {} +static inline void osd_clone_update_pan(int buffer_number) {} +static inline int osd_clone_task_start(void) +{ + osd_log_info("++ osd_clone depends on GE2D module!\n"); + return 0; +} +static inline void osd_clone_task_stop(void) +{ + osd_log_info("-- osd_clone depends on GE2D module!\n"); +} +#endif + +#endif diff --git a/drivers/amlogic/media/osd/osd_debug.c b/drivers/amlogic/media/osd/osd_debug.c new file mode 100644 index 000000000000..21fe8d89987c --- /dev/null +++ b/drivers/amlogic/media/osd/osd_debug.c @@ -0,0 +1,465 @@ +/* + * drivers/amlogic/media/osd/osd_debug.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. + * + */ + +/* Linux Headers */ +#include +#include +#include +#include +#include +#include + +/* Amlogic Headers */ +#include +#ifdef CONFIG_AMLOGIC_MEDIA_CANVAS +#include +#include +#endif +#ifdef CONFIG_AMLOGIC_MEDIA_GE2D +#include +#endif + +/* Local Headers */ +#include "osd_canvas.h" +#include "osd_log.h" +#include "osd_reg.h" +#include "osd_io.h" +#include "osd_hw.h" + +#define OSD_TEST_DURATION 200 + +#ifdef CONFIG_AMLOGIC_MEDIA_GE2D +static struct config_para_s ge2d_config; +static struct config_para_ex_s ge2d_config_ex; +static struct ge2d_context_s *ge2d_context; +#endif + +char osd_debug_help[] = "Usage:\n" +" echo [i | info] > debug ; Show osd pan/display/scale information\n" +" echo [t | test] > debug ; Start osd auto test\n" +" echo [r | read] reg > debug ; Read VCBUS register\n" +" echo [w | write] reg val > debug ; Write VCBUS register\n" +" echo [d | dump] {start end} > debug ; Dump VCBUS register\n\n"; + +static void osd_debug_dump_value(void) +{ + u32 index = 0; + struct hw_para_s *hwpara = NULL; + struct pandata_s *pdata = NULL; + + osd_get_hw_para(&hwpara); + if (hwpara == NULL) + return; + + osd_log_info("--- OSD ---\n"); + osd_log_info("scan_mode: %d\n", hwpara->scan_mode); + osd_log_info("order: %d\n", hwpara->order); + osd_log_info("bot_type: %d\n", hwpara->bot_type); + osd_log_info("field_out_en: %d\n", hwpara->field_out_en); + + for (index = 0; index < HW_OSD_COUNT; index++) { + osd_log_info("\n--- OSD%d ---\n", index); + osd_log_info("enable: %d\n", hwpara->enable[index]); + osd_log_info("2x-scale enable.h:%d .v: %d\n", + hwpara->scale[index].h_enable, + hwpara->scale[index].v_enable); + osd_log_info("free-scale-mode: %d\n", + hwpara->free_scale_mode[index]); + osd_log_info("free-scale enable.h:%d .v: %d\n", + hwpara->free_scale[index].h_enable, + hwpara->free_scale[index].v_enable); + pdata = &hwpara->pandata[index]; + osd_log_info("pan data:\n"); + osd_log_info("\tx_start: 0x%08x, x_end: 0x%08x\n", + pdata->x_start, pdata->x_end); + osd_log_info("\ty_start: 0x%08x, y_end: 0x%08x\n", + pdata->y_start, pdata->y_end); + + pdata = &hwpara->dispdata[index]; + osd_log_info("disp data:\n"); + osd_log_info("\tx_start: 0x%08x, x_end: 0x%08x\n", + pdata->x_start, pdata->x_end); + osd_log_info("\ty_start: 0x%08x, y_end: 0x%08x\n", + pdata->y_start, pdata->y_end); + + pdata = &hwpara->scaledata[index]; + osd_log_info("2x-scale data:\n"); + osd_log_info("\tx_start: 0x%08x, x_end: 0x%08x\n", + pdata->x_start, pdata->x_end); + osd_log_info("\ty_start: 0x%08x, y_end: 0x%08x\n", + pdata->y_start, pdata->y_end); + + pdata = &hwpara->free_src_data[index]; + osd_log_info("free-scale src data:\n"); + osd_log_info("\tx_start: 0x%08x, x_end: 0x%08x\n", + pdata->x_start, pdata->x_end); + osd_log_info("\ty_start: 0x%08x, y_end: 0x%08x\n", + pdata->y_start, pdata->y_end); + + pdata = &hwpara->free_dst_data[index]; + osd_log_info("free-scale dst data:\n"); + osd_log_info("\tx_start: 0x%08x, x_end: 0x%08x\n", + pdata->x_start, pdata->x_end); + osd_log_info("\ty_start: 0x%08x, y_end: 0x%08x\n", + pdata->y_start, pdata->y_end); + } + +} + +static void osd_debug_dump_register_all(void) +{ + u32 reg = 0; + u32 offset = 0; + u32 index = 0; + + reg = VPU_VIU_VENC_MUX_CTRL; + osd_log_info("reg[0x%x]: 0x%08x\n", reg, osd_reg_read(reg)); + reg = VPP_MISC; + osd_log_info("reg[0x%x]: 0x%08x\n", reg, osd_reg_read(reg)); + reg = VPP_OFIFO_SIZE; + osd_log_info("reg[0x%x]: 0x%08x\n", reg, osd_reg_read(reg)); + reg = VPP_HOLD_LINES; + osd_log_info("reg[0x%x]: 0x%08x\n", reg, osd_reg_read(reg)); + reg = VPP_OSD_SC_CTRL0; + osd_log_info("reg[0x%x]: 0x%08x\n", reg, osd_reg_read(reg)); + reg = VPP_OSD_SCI_WH_M1; + osd_log_info("reg[0x%x]: 0x%08x\n", reg, osd_reg_read(reg)); + reg = VPP_OSD_SCO_H_START_END; + osd_log_info("reg[0x%x]: 0x%08x\n", reg, osd_reg_read(reg)); + reg = VPP_OSD_SCO_V_START_END; + osd_log_info("reg[0x%x]: 0x%08x\n\n", reg, osd_reg_read(reg)); + + for (index = 0; index < 2; index++) { + if (index == 1) + offset = REG_OFFSET; + reg = offset + VIU_OSD1_FIFO_CTRL_STAT; + osd_log_info("reg[0x%x]: 0x%08x\n", reg, osd_reg_read(reg)); + reg = offset + VIU_OSD1_CTRL_STAT; + osd_log_info("reg[0x%x]: 0x%08x\n", reg, osd_reg_read(reg)); + reg = offset + VIU_OSD1_CTRL_STAT2; + osd_log_info("reg[0x%x]: 0x%08x\n", reg, osd_reg_read(reg)); + reg = offset + VIU_OSD1_BLK0_CFG_W0; + osd_log_info("reg[0x%x]: 0x%08x\n", reg, osd_reg_read(reg)); + reg = offset + VIU_OSD1_BLK0_CFG_W1; + osd_log_info("reg[0x%x]: 0x%08x\n", reg, osd_reg_read(reg)); + reg = offset + VIU_OSD1_BLK0_CFG_W2; + osd_log_info("reg[0x%x]: 0x%08x\n", reg, osd_reg_read(reg)); + reg = offset + VIU_OSD1_BLK0_CFG_W3; + osd_log_info("reg[0x%x]: 0x%08x\n", reg, osd_reg_read(reg)); + reg = VIU_OSD1_BLK0_CFG_W4; + if (index == 1) + reg = VIU_OSD2_BLK0_CFG_W4; + osd_log_info("reg[0x%x]: 0x%08x\n\n", reg, osd_reg_read(reg)); + } + + if ((get_cpu_type() == MESON_CPU_MAJOR_ID_GXTVBB) || + (get_cpu_type() == MESON_CPU_MAJOR_ID_GXM)) { + reg = VIU_MISC_CTRL1; + osd_log_info("reg[0x%x]: 0x%08x\n", + reg, osd_reg_read(reg)); + for (reg = OSD1_AFBCD_ENABLE; + reg <= OSD1_AFBCD_PIXEL_VSCOPE; reg++) + osd_log_info("reg[0x%x]: 0x%08x\n", + reg, osd_reg_read(reg)); + } +} + +static void osd_debug_dump_register_region(u32 start, u32 end) +{ + u32 reg = 0; + + for (reg = start; reg <= end; reg += 4) + osd_log_info("reg[0x%x]: 0x%08x\n", reg, osd_reg_read(reg)); +} +static void osd_debug_dump_register(int argc, char **argv) +{ + int reg_start, reg_end; + int ret; + +#ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD_VSYNC_RDMA + read_rdma_table(); +#endif + if ((argc == 3) && argv[1] && argv[2]) { + ret = kstrtoint(argv[1], 16, ®_start); + ret = kstrtoint(argv[2], 16, ®_end); + osd_debug_dump_register_region(reg_start, reg_end); + } else { + osd_debug_dump_register_all(); + } +} + +static void osd_debug_read_register(int argc, char **argv) +{ + int reg; + int ret; + + if ((argc == 2) && argv[1]) { + ret = kstrtoint(argv[1], 16, ®); + osd_log_info("reg[0x%x]: 0x%08x\n", reg, osd_reg_read(reg)); + } else { + osd_log_err("read: arg error\n"); + } +} + +static void osd_debug_write_register(int argc, char **argv) +{ + int reg, val; + int ret; + + if ((argc == 3) && argv[1] && argv[2]) { + ret = kstrtoint(argv[1], 16, ®); + ret = kstrtoint(argv[2], 16, &val); + osd_reg_write(reg, val); + osd_log_info("reg[0x%x]: 0x%08x =0x%08x\n", + reg, val, osd_reg_read(reg)); + } else { + osd_log_err("write: arg error\n"); + } +} + +static void osd_test_colorbar(void) +{ +#define HHI_GCLK_OTHER 0x1054 + u32 gclk_other = 0; + u32 encp_video_adv = 0; + + gclk_other = aml_read_cbus(HHI_GCLK_OTHER); + encp_video_adv = osd_reg_read(ENCP_VIDEO_MODE_ADV); + + /* start test mode */ + osd_log_info("--- OSD TEST COLORBAR ---\n"); + aml_write_cbus(HHI_GCLK_OTHER, 0xFFFFFFFF); + osd_reg_write(ENCP_VIDEO_MODE_ADV, 0); + osd_reg_write(VENC_VIDEO_TST_EN, 1); + /* TST_MODE COLORBAR */ + osd_log_info("- COLORBAR -\n"); + osd_reg_write(VENC_VIDEO_TST_MDSEL, 1); + msleep(OSD_TEST_DURATION); + + /* TST_MODE THINLINE */ + osd_log_info("- THINLINE -\n"); + osd_reg_write(VENC_VIDEO_TST_MDSEL, 2); + msleep(OSD_TEST_DURATION); + /* TST_MODE DOTGRID */ + osd_log_info("- DOTGRID -\n"); + osd_reg_write(VENC_VIDEO_TST_MDSEL, 3); + msleep(OSD_TEST_DURATION); + + /* stop test mode */ + aml_write_cbus(HHI_GCLK_OTHER, gclk_other); + osd_reg_write(ENCP_VIDEO_MODE_ADV, encp_video_adv); + osd_reg_write(VENC_VIDEO_TST_EN, 0); + osd_reg_write(VENC_VIDEO_TST_MDSEL, 0); +} + +static void osd_reset(void) +{ + osd_set_free_scale_enable_hw(0, 0); + osd_enable_hw(0, 1); +} + +static void osd_test_dummydata(void) +{ + u32 dummy_data = 0; + + dummy_data = osd_reg_read(VPP_DUMMY_DATA1); + osd_reset(); + osd_log_info("--- OSD TEST DUMMYDATA ---\n"); + osd_reg_write(VPP_DUMMY_DATA1, 0xFF); + msleep(OSD_TEST_DURATION); + osd_reg_write(VPP_DUMMY_DATA1, 0); + msleep(OSD_TEST_DURATION); + osd_reg_write(VPP_DUMMY_DATA1, 0xFF00); + msleep(OSD_TEST_DURATION); + osd_reg_write(VPP_DUMMY_DATA1, dummy_data); +} + +static void osd_test_rect(void) +{ +#ifdef CONFIG_AMLOGIC_MEDIA_GE2D + u32 x = 0; + u32 y = 0; + u32 w = 0; + u32 h = 0; + u32 color = 0; + struct canvas_s cs; + struct config_para_s *cfg = &ge2d_config; + struct config_para_ex_s *cfg_ex = &ge2d_config_ex; + struct ge2d_context_s *context = ge2d_context; + + canvas_read(OSD1_CANVAS_INDEX, &cs); + context = create_ge2d_work_queue(); + if (!context) { + osd_log_err("create work queue error\n"); + return; + } + + memset(cfg, 0, sizeof(struct config_para_s)); + cfg->src_dst_type = OSD0_OSD0; + cfg->src_format = GE2D_FORMAT_S32_ARGB; + cfg->src_planes[0].addr = cs.addr; + cfg->src_planes[0].w = cs.width / 4; + cfg->src_planes[0].h = cs.height; + cfg->dst_planes[0].addr = cs.addr; + cfg->dst_planes[0].w = cs.width / 4; + cfg->dst_planes[0].h = cs.height; + + if (ge2d_context_config(context, cfg) < 0) { + osd_log_err("ge2d config error.\n"); + return; + } + + x = 0; + y = 0; + w = cs.width / 4; + h = cs.height; + color = 0x0; + osd_log_info("- BLACK -"); + osd_log_info("- (%d, %d)-(%d, %d) -\n", x, y, w, h); + fillrect(context, x, y, h, w, color); + msleep(OSD_TEST_DURATION); + + x = 100; + y = 0; + w = 100; + h = 100; + color = 0xFF0000FF; + osd_log_info("- RED -\n"); + osd_log_info("- (%d, %d)-(%d, %d) -\n", x, y, w, h); + fillrect(context, x, y, h, w, color); + msleep(OSD_TEST_DURATION); + + x += 100; + color = 0x00FF00FF; + osd_log_info("- GREEN -\n"); + osd_log_info("- (%d, %d)-(%d, %d) -\n", x, y, w, h); + fillrect(context, x, y, h, w, color); + msleep(OSD_TEST_DURATION); + + x += 100; + color = 0x0000FFFF; + osd_log_info("- BlUE -\n"); + osd_log_info("- (%d, %d)-(%d, %d) -\n", x, y, w, h); + fillrect(context, x, y, h, w, color); + msleep(OSD_TEST_DURATION); + + memset(cfg_ex, 0, sizeof(struct config_para_ex_s)); + cfg_ex->src_planes[0].addr = cs.addr; + cfg_ex->src_planes[0].w = cs.width / 4; + cfg_ex->src_planes[0].h = cs.height; + cfg_ex->dst_planes[0].addr = cs.addr; + cfg_ex->dst_planes[0].w = cs.width / 4; + cfg_ex->dst_planes[0].h = cs.height; + + cfg_ex->src_para.canvas_index = OSD1_CANVAS_INDEX; + cfg_ex->src_para.mem_type = CANVAS_OSD0; + cfg_ex->src_para.format = GE2D_FORMAT_S32_ARGB; + cfg_ex->src_para.fill_color_en = 0; + cfg_ex->src_para.fill_mode = 0; + cfg_ex->src_para.x_rev = 0; + cfg_ex->src_para.y_rev = 0; + cfg_ex->src_para.color = 0xffffffff; + cfg_ex->src_para.top = 0; + cfg_ex->src_para.left = 0; + cfg_ex->src_para.width = cs.width / 4; + cfg_ex->src_para.height = cs.height; + + cfg_ex->dst_para.canvas_index = OSD1_CANVAS_INDEX; + cfg_ex->dst_para.mem_type = CANVAS_OSD0; + cfg_ex->dst_para.format = GE2D_FORMAT_S32_ARGB; + cfg_ex->dst_para.top = 0; + cfg_ex->dst_para.left = 0; + cfg_ex->dst_para.width = cs.width / 4; + cfg_ex->dst_para.height = cs.height; + cfg_ex->dst_para.fill_color_en = 0; + cfg_ex->dst_para.fill_mode = 0; + cfg_ex->dst_para.color = 0; + cfg_ex->dst_para.x_rev = 0; + cfg_ex->dst_para.y_rev = 0; + cfg_ex->dst_xy_swap = 0; + + if (ge2d_context_config_ex(context, cfg_ex) < 0) { + osd_log_err("ge2d config error.\n"); + return; + } + + stretchblt(context, 100, 0, 400, 100, 100, 200, 700, 200); + + destroy_ge2d_work_queue(ge2d_context); +#endif +} + +static void osd_debug_auto_test(void) +{ + osd_test_colorbar(); + + osd_test_dummydata(); + + osd_test_rect(); +} + +char *osd_get_debug_hw(void) +{ + return osd_debug_help; +} + +int osd_set_debug_hw(const char *buf) +{ + int argc; + char *buffer, *p, *para; + char *argv[4]; + char cmd; + + buffer = kstrdup(buf, GFP_KERNEL); + p = buffer; + for (argc = 0; argc < 4; argc++) { + para = strsep(&p, " "); + if (para == NULL) + break; + argv[argc] = para; + } + + if (argc < 1 || argc > 4) { + kfree(buffer); + return -EINVAL; + } + + cmd = argv[0][0]; + switch (cmd) { + case 'i': + osd_debug_dump_value(); + break; + case 'd': + osd_debug_dump_register(argc, argv); + break; + case 'r': + osd_debug_read_register(argc, argv); + break; + case 'w': + osd_debug_write_register(argc, argv); + break; + case 't': + osd_debug_auto_test(); + break; + default: + osd_log_err("arg error\n"); + break; + } + + kfree(buffer); + return 0; +} diff --git a/drivers/amlogic/media/osd/osd_fb.c b/drivers/amlogic/media/osd/osd_fb.c new file mode 100644 index 000000000000..5fad73bf977e --- /dev/null +++ b/drivers/amlogic/media/osd/osd_fb.c @@ -0,0 +1,2716 @@ +/* + * drivers/amlogic/media/osd/osd_fb.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. + * + */ + +/* Linux Headers */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* Amlogic Headers */ +#include +#include +#ifdef CONFIG_INSTABOOT +#include +#endif +/* Local Headers */ +#include "osd.h" +#include "osd_fb.h" +#include "osd_hw.h" +#include "osd_log.h" +#include "osd_sync.h" + +static __u32 var_screeninfo[5]; + +struct osd_info_s osd_info = { + .index = 0, + .osd_reverse = 0, +}; + +const struct color_bit_define_s default_color_format_array[] = { + INVALID_BPP_ITEM, + INVALID_BPP_ITEM, + { + COLOR_INDEX_02_PAL4, 0, 0, + 0, 2, 0, 0, 2, 0, 0, 2, 0, 0, 0, 0, + FB_VISUAL_PSEUDOCOLOR, 2, + }, + INVALID_BPP_ITEM, + { + COLOR_INDEX_04_PAL16, 0, 1, + 0, 4, 0, 0, 4, 0, 0, 4, 0, 0, 0, 0, + FB_VISUAL_PSEUDOCOLOR, 4, + }, + INVALID_BPP_ITEM, + INVALID_BPP_ITEM, + INVALID_BPP_ITEM, + { + COLOR_INDEX_08_PAL256, 0, 2, + 0, 8, 0, 0, 8, 0, 0, 8, 0, 0, 0, 0, + FB_VISUAL_PSEUDOCOLOR, 8, + }, + /*16 bit color*/ + { + COLOR_INDEX_16_655, 0, 4, + 10, 6, 0, 5, 5, 0, 0, 5, 0, 0, 0, 0, + FB_VISUAL_TRUECOLOR, 16 + }, + { + COLOR_INDEX_16_844, 1, 4, + 8, 8, 0, 4, 4, 0, 0, 4, 0, 0, 0, 0, + FB_VISUAL_TRUECOLOR, 16 + }, + { + COLOR_INDEX_16_6442, 2, 4, + 10, 6, 0, 6, 4, 0, 2, 4, 0, 0, 2, 0, + FB_VISUAL_TRUECOLOR, 16 + }, + { + COLOR_INDEX_16_4444_R, 3, 4, + 12, 4, 0, 8, 4, 0, 4, 4, 0, 0, 4, 0, + FB_VISUAL_TRUECOLOR, 16 + }, + { + COLOR_INDEX_16_4642_R, 7, 4, + 12, 4, 0, 6, 6, 0, 2, 4, 0, 0, 2, 0, + FB_VISUAL_TRUECOLOR, 16 + }, + { + COLOR_INDEX_16_1555_A, 6, 4, + 10, 5, 0, 5, 5, 0, 0, 5, 0, 15, 1, 0, + FB_VISUAL_TRUECOLOR, 16 + }, + { + COLOR_INDEX_16_4444_A, 5, 4, + 8, 4, 0, 4, 4, 0, 0, 4, 0, 12, 4, 0, + FB_VISUAL_TRUECOLOR, 16 + }, + { + COLOR_INDEX_16_565, 4, 4, + 11, 5, 0, 5, 6, 0, 0, 5, 0, 0, 0, 0, + FB_VISUAL_TRUECOLOR, 16 + }, + /*24 bit color*/ + INVALID_BPP_ITEM, + INVALID_BPP_ITEM, + { + COLOR_INDEX_24_6666_A, 4, 7, + 12, 6, 0, 6, 6, 0, 0, 6, 0, 18, 6, 0, + FB_VISUAL_TRUECOLOR, 24 + }, + { + COLOR_INDEX_24_6666_R, 3, 7, + 18, 6, 0, 12, 6, 0, 6, 6, 0, 0, 6, 0, + FB_VISUAL_TRUECOLOR, 24 + }, + { + COLOR_INDEX_24_8565, 2, 7, + 11, 5, 0, 5, 6, 0, 0, 5, 0, 16, 8, 0, + FB_VISUAL_TRUECOLOR, 24 + }, + { + COLOR_INDEX_24_5658, 1, 7, + 19, 5, 0, 13, 6, 0, 8, 5, 0, 0, 8, 0, + FB_VISUAL_TRUECOLOR, 24 + }, + { + COLOR_INDEX_24_888_B, 5, 7, + 0, 8, 0, 8, 8, 0, 16, 8, 0, 0, 0, 0, + FB_VISUAL_TRUECOLOR, 24 + }, + { + COLOR_INDEX_24_RGB, 0, 7, + 16, 8, 0, 8, 8, 0, 0, 8, 0, 0, 0, 0, + FB_VISUAL_TRUECOLOR, 24 + }, + /*32 bit color RGBX */ + { + COLOR_INDEX_32_BGRX, 3, 5, + 8, 8, 0, 16, 8, 0, 24, 8, 0, 0, 0, 0, + FB_VISUAL_TRUECOLOR, 32 + }, + { + COLOR_INDEX_32_XBGR, 2, 5, + 0, 8, 0, 8, 8, 0, 16, 8, 0, 24, 0, 0, + FB_VISUAL_TRUECOLOR, 32 + }, + { + COLOR_INDEX_32_RGBX, 0, 5, + 24, 8, 0, 16, 8, 0, 8, 8, 0, 0, 0, 0, + FB_VISUAL_TRUECOLOR, 32 + }, + { + COLOR_INDEX_32_XRGB, 1, 5, + 16, 8, 0, 8, 8, 0, 0, 8, 0, 24, 0, 0, + FB_VISUAL_TRUECOLOR, 32 + }, + /*32 bit color RGBA */ + { + COLOR_INDEX_32_BGRA, 3, 5, + 8, 8, 0, 16, 8, 0, 24, 8, 0, 0, 8, 0, + FB_VISUAL_TRUECOLOR, 32 + }, + { + COLOR_INDEX_32_ABGR, 2, 5, + 0, 8, 0, 8, 8, 0, 16, 8, 0, 24, 8, 0, + FB_VISUAL_TRUECOLOR, 32 + }, + { + COLOR_INDEX_32_RGBA, 0, 5, + 24, 8, 0, 16, 8, 0, 8, 8, 0, 0, 8, 0, + FB_VISUAL_TRUECOLOR, 32 + }, + { + COLOR_INDEX_32_ARGB, 1, 5, + 16, 8, 0, 8, 8, 0, 0, 8, 0, 24, 8, 0, + FB_VISUAL_TRUECOLOR, 32 + }, + /*YUV color*/ + {COLOR_INDEX_YUV_422, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16}, +}; + +static struct fb_var_screeninfo fb_def_var[] = { + { + .xres = 1920, + .yres = 1080, + .xres_virtual = 1920, + .yres_virtual = 2160, + .xoffset = 0, + .yoffset = 0, + .bits_per_pixel = 32, + .grayscale = 0, + .red = {0, 0, 0}, + .green = {0, 0, 0}, + .blue = {0, 0, 0}, + .transp = {0, 0, 0}, + .nonstd = 0, + .activate = FB_ACTIVATE_NOW, + .height = -1, + .width = -1, + .accel_flags = 0, + .pixclock = 0, + .left_margin = 0, + .right_margin = 0, + .upper_margin = 0, + .lower_margin = 0, + .hsync_len = 0, + .vsync_len = 0, + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED, + .rotate = 0, + } +#ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD2_ENABLE + , + { + .xres = 32, + .yres = 32, + .xres_virtual = 32, + .yres_virtual = 32, + .xoffset = 0, + .yoffset = 0, + .bits_per_pixel = 32, + .grayscale = 0, + /* leave as it is ,set by system. */ + .red = {0, 0, 0}, + .green = {0, 0, 0}, + .blue = {0, 0, 0}, + .transp = {0, 0, 0}, + .nonstd = 0, + .activate = FB_ACTIVATE_NOW, + .height = -1, + .width = -1, + .accel_flags = 0, + .pixclock = 0, + .left_margin = 0, + .right_margin = 0, + .upper_margin = 0, + .lower_margin = 0, + .hsync_len = 0, + .vsync_len = 0, + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED, + .rotate = 0, + } +#endif +}; + +static struct fb_fix_screeninfo fb_def_fix = { + .id = "OSD FB", + .xpanstep = 1, + .ypanstep = 1, + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_TRUECOLOR, + .accel = FB_ACCEL_NONE, +}; + +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +static struct early_suspend early_suspend; +static int early_suspend_flag; +#endif +#ifdef CONFIG_SCREEN_ON_EARLY +static int early_resume_flag; +#endif + +static int osd_shutdown_flag; + +unsigned int osd_log_level; +int int_viu_vsync = -ENXIO; +#ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD_VSYNC_RDMA +int int_rdma = INT_RDMA; +#endif +struct osd_fb_dev_s *gp_fbdev_list[OSD_COUNT] = {}; +static struct reserved_mem fb_rmem = {.base = 0, .size = 0}; +static u32 fb_memsize[2]; +static phys_addr_t fb_rmem_paddr[2]; +static void __iomem *fb_rmem_vaddr[OSD_COUNT]; +static size_t fb_rmem_size[OSD_COUNT]; +static phys_addr_t fb_rmem_afbc_paddr[OSD_COUNT][OSD_MAX_BUF_NUM]; +static void __iomem *fb_rmem_afbc_vaddr[OSD_COUNT][OSD_MAX_BUF_NUM]; +static size_t fb_rmem_afbc_size[OSD_COUNT][OSD_MAX_BUF_NUM]; + +struct ion_client *fb_ion_client; +struct ion_handle *fb_ion_handle[OSD_COUNT][OSD_MAX_BUF_NUM] = { + {NULL, NULL, NULL}, {NULL, NULL, NULL} +}; + +phys_addr_t get_fb_rmem_paddr(int index) +{ + if (index < 0 || index > 1) + return 0; + return fb_rmem_paddr[index]; +} + +void __iomem *get_fb_rmem_vaddr(int index) +{ + if (index < 0 || index > 1) + return 0; + return fb_rmem_vaddr[index]; +} + +size_t get_fb_rmem_size(int index) +{ + if (index < 0 || index > 1) + return 0; + return fb_rmem_size[index]; +} + + +static void osddev_setup(struct osd_fb_dev_s *fbdev) +{ + mutex_lock(&fbdev->lock); + osd_setup_hw(fbdev->fb_info->node, + &fbdev->osd_ctl, + fbdev->fb_info->var.xoffset, + fbdev->fb_info->var.yoffset, + fbdev->fb_info->var.xres, + fbdev->fb_info->var.yres, + fbdev->fb_info->var.xres_virtual, + fbdev->fb_info->var.yres_virtual, + fbdev->osd_ctl.disp_start_x, + fbdev->osd_ctl.disp_start_y, + fbdev->osd_ctl.disp_end_x, + fbdev->osd_ctl.disp_end_y, + fbdev->fb_mem_paddr, /*phys_addr_t -> u32*/ + fbdev->fb_mem_afbc_paddr, /* afbc phys_addr_t* */ + fbdev->color); + mutex_unlock(&fbdev->lock); +} + +static void osddev_update_disp_axis(struct osd_fb_dev_s *fbdev, + int mode_change) +{ + osd_update_disp_axis_hw(fbdev->fb_info->node, + fbdev->osd_ctl.disp_start_x, + fbdev->osd_ctl.disp_end_x, + fbdev->osd_ctl.disp_start_y, + fbdev->osd_ctl.disp_end_y, + fbdev->fb_info->var.xoffset, + fbdev->fb_info->var.yoffset, + mode_change); +} + +static int osddev_setcolreg(unsigned int regno, u16 red, u16 green, u16 blue, + u16 transp, struct osd_fb_dev_s *fbdev) +{ + struct fb_info *info = fbdev->fb_info; + + if ((fbdev->color->color_index == COLOR_INDEX_02_PAL4) || + (fbdev->color->color_index == COLOR_INDEX_04_PAL16) || + (fbdev->color->color_index == COLOR_INDEX_08_PAL256)) { + mutex_lock(&fbdev->lock); + osd_setpal_hw(fbdev->fb_info->node, regno, red, green, + blue, transp); + mutex_lock(&fbdev->lock); + } + if (info->fix.visual == FB_VISUAL_TRUECOLOR) { + u32 v, r, g, b, a; + + if (regno >= 16) + return 1; + r = red >> (16 - info->var.red.length); + g = green >> (16 - info->var.green.length); + b = blue >> (16 - info->var.blue.length); + a = transp >> (16 - info->var.transp.length); + v = (r << info->var.red.offset) | + (g << info->var.green.offset) | + (b << info->var.blue.offset) | + (a << info->var.transp.offset); + ((u32 *)(info->pseudo_palette))[regno] = v; + } + return 0; +} + +static const struct color_bit_define_s * +_find_color_format(struct fb_var_screeninfo *var) +{ + u32 upper_margin, lower_margin, i, level; + const struct color_bit_define_s *found = NULL; + const struct color_bit_define_s *color = NULL; + + level = (var->bits_per_pixel - 1) / 8; + switch (level) { + case 0: + upper_margin = COLOR_INDEX_08_PAL256; + lower_margin = COLOR_INDEX_02_PAL4; + break; + case 1: + upper_margin = COLOR_INDEX_16_565; + lower_margin = COLOR_INDEX_16_655; + break; + case 2: + upper_margin = COLOR_INDEX_24_RGB; + lower_margin = COLOR_INDEX_24_6666_A; + break; + case 3: + if ((var->nonstd != 0) + && (var->transp.length == 0)) { + /* RGBX Mode */ + upper_margin = COLOR_INDEX_32_XRGB; + lower_margin = COLOR_INDEX_32_BGRX; + } else { + upper_margin = COLOR_INDEX_32_ARGB; + lower_margin = COLOR_INDEX_32_BGRA; + } + break; + case 4: + upper_margin = COLOR_INDEX_YUV_422; + lower_margin = COLOR_INDEX_YUV_422; + break; + default: + osd_log_err("unsupported color format."); + return NULL; + } + /* + * if not provide color component length + * then we find the first depth match. + */ + + if ((var->nonstd != 0) && (level == 3) + && (var->transp.length == 0)) { + /* RGBX Mode */ + for (i = upper_margin; i >= lower_margin; i--) { + color = &default_color_format_array[i]; + if ((color->red_length == var->red.length) && + (color->green_length == var->green.length) && + (color->blue_length == var->blue.length) && + (color->transp_offset == var->transp.offset) && + (color->green_offset == var->green.offset) && + (color->blue_offset == var->blue.offset) && + (color->red_offset == var->red.offset)) { + found = color; + break; + } + color--; + } + } else if ((var->red.length == 0) || (var->green.length == 0) + || (var->blue.length == 0) || + var->bits_per_pixel != (var->red.length + var->green.length + + var->blue.length + var->transp.length)) { + osd_log_dbg("not provide color length, use default color\n"); + found = &default_color_format_array[upper_margin]; + } else { + for (i = upper_margin; i >= lower_margin; i--) { + color = &default_color_format_array[i]; + if ((color->red_length == var->red.length) && + (color->green_length == var->green.length) && + (color->blue_length == var->blue.length) && + (color->transp_length == var->transp.length) && + (color->transp_offset == var->transp.offset) && + (color->green_offset == var->green.offset) && + (color->blue_offset == var->blue.offset) && + (color->red_offset == var->red.offset)) { + found = color; + break; + } + color--; + } + } + return found; +} + +static void __init _fbdev_set_default(struct osd_fb_dev_s *fbdev, int index) +{ + /* setup default value */ + fbdev->fb_info->var = fb_def_var[index]; + fbdev->fb_info->fix = fb_def_fix; + fbdev->color = _find_color_format(&fbdev->fb_info->var); +} + +static int osd_check_fbsize(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct osd_fb_dev_s *fbdev = (struct osd_fb_dev_s *)info->par; + + if (fbdev->fb_index == 0 && osd_get_afbc()) { + /* fb_afbc_len = fbdev->fb_afbc_len[0] * ((info->node == 0) ? + * OSD_MAX_BUF_NUM : 1); + */ + if (var->xres_virtual * var->yres_virtual * + var->bits_per_pixel / 8 > + fbdev->fb_afbc_len[0] * OSD_MAX_BUF_NUM) { + osd_log_err("afbc no enough memory for %d*%d*%d\n", + var->xres, + var->yres, + var->bits_per_pixel); + return -ENOMEM; + } + } else { + if (var->xres_virtual * var->yres_virtual * + var->bits_per_pixel / 8 > fbdev->fb_len) { + osd_log_err("no enough memory for %d*%d*%d\n", + var->xres, + var->yres, + var->bits_per_pixel); + return -ENOMEM; + } + } + return 0; +} +static int osd_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct fb_fix_screeninfo *fix; + struct osd_fb_dev_s *fbdev = (struct osd_fb_dev_s *)info->par; + const struct color_bit_define_s *color_format_pt; + + fix = &info->fix; + color_format_pt = _find_color_format(var); + if (color_format_pt == NULL || color_format_pt->color_index == 0) + return -EFAULT; + + osd_log_dbg("select color format :index %d, bpp %d\n", + color_format_pt->color_index, + color_format_pt->bpp); + fbdev->color = color_format_pt; + var->red.offset = color_format_pt->red_offset; + var->red.length = color_format_pt->red_length; + var->red.msb_right = color_format_pt->red_msb_right; + var->green.offset = color_format_pt->green_offset; + var->green.length = color_format_pt->green_length; + var->green.msb_right = color_format_pt->green_msb_right; + var->blue.offset = color_format_pt->blue_offset; + var->blue.length = color_format_pt->blue_length; + var->blue.msb_right = color_format_pt->blue_msb_right; + var->transp.offset = color_format_pt->transp_offset; + var->transp.length = color_format_pt->transp_length; + var->transp.msb_right = color_format_pt->transp_msb_right; + var->bits_per_pixel = color_format_pt->bpp; + osd_log_dbg("rgba(L/O):%d/%d-%d/%d-%d/%d-%d/%d\n", + var->red.length, var->red.offset, + var->green.length, var->green.offset, + var->blue.length, var->blue.offset, + var->transp.length, var->transp.offset); + fix->visual = color_format_pt->color_type; + /* adjust memory length. */ + fix->line_length = var->xres_virtual * var->bits_per_pixel / 8; + osd_log_dbg("xvirtual=%d, bpp:%d, line_length=%d\n", + var->xres_virtual, var->bits_per_pixel, fix->line_length); + + if (var->xres_virtual < var->xres) + var->xres_virtual = var->xres; + if (var->yres_virtual < var->yres) + var->yres_virtual = var->yres; + var->left_margin = var->right_margin = 0; + var->upper_margin = var->lower_margin = 0; + if (var->xres + var->xoffset > var->xres_virtual) + var->xoffset = var->xres_virtual - var->xres; + if (var->yres + var->yoffset > var->yres_virtual) + var->yoffset = var->yres_virtual - var->yres; + return 0; +} + +static int osd_set_par(struct fb_info *info) +{ + const struct vinfo_s *vinfo; + struct osd_fb_dev_s *fbdev = (struct osd_fb_dev_s *)info->par; + struct osd_ctl_s *osd_ctrl = &fbdev->osd_ctl; + u32 virt_end_x, virt_end_y; + + vinfo = get_current_vinfo(); + if (!vinfo) { + osd_log_err("current vinfo NULL\n"); + return -1; + } + virt_end_x = osd_ctrl->disp_start_x + info->var.xres; + virt_end_y = osd_ctrl->disp_start_y + info->var.yres; + if (virt_end_x > vinfo->width) + osd_ctrl->disp_end_x = vinfo->width - 1; + else + osd_ctrl->disp_end_x = virt_end_x - 1; + if (virt_end_y > vinfo->height) + osd_ctrl->disp_end_y = vinfo->height - 1; + else + osd_ctrl->disp_end_y = virt_end_y - 1; + osddev_setup((struct osd_fb_dev_s *)info->par); + + return 0; +} + +static int +osd_setcolreg(unsigned int regno, unsigned int red, unsigned int green, + unsigned int blue, unsigned int transp, struct fb_info *info) +{ + return osddev_setcolreg(regno, red, green, blue, + transp, (struct osd_fb_dev_s *)info->par); +} + +static int +osd_setcmap(struct fb_cmap *cmap, struct fb_info *info) +{ + int count, index, r; + u16 *red, *green, *blue, *transp; + u16 trans = 0xffff; + + red = cmap->red; + green = cmap->green; + blue = cmap->blue; + transp = cmap->transp; + index = cmap->start; + + for (count = 0; count < cmap->len; count++) { + if (transp) + trans = *transp++; + r = osddev_setcolreg(index++, *red++, *green++, *blue++, trans, + (struct osd_fb_dev_s *)info->par); + if (r != 0) + return r; + } + return 0; +} + +static int osd_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) +{ + struct osd_fb_dev_s *fbdev = (struct osd_fb_dev_s *)info->par; + void __user *argp = (void __user *)arg; + u32 src_colorkey;/* 16 bit or 24 bit */ + u32 srckey_enable; + u32 gbl_alpha; + u32 osd_order; + s32 osd_axis[4] = {0}; + s32 osd_dst_axis[4] = {0}; + u32 block_windows[8] = {0}; + u32 block_mode; + unsigned long ret; + u32 flush_rate; + struct fb_sync_request_s sync_request; + struct fb_dmabuf_export dmaexp; + + switch (cmd) { + case FBIOPUT_OSD_SRCKEY_ENABLE: + ret = copy_from_user(&srckey_enable, argp, sizeof(u32)); + break; + case FBIOPUT_OSD_SRCCOLORKEY: + ret = copy_from_user(&src_colorkey, argp, sizeof(u32)); + break; + case FBIOPUT_OSD_SET_GBL_ALPHA: + ret = copy_from_user(&gbl_alpha, argp, sizeof(u32)); + break; + case FBIOPUT_OSD_SCALE_AXIS: + ret = copy_from_user(&osd_axis, argp, 4 * sizeof(s32)); + break; + case FBIOPUT_OSD_SYNC_ADD: + ret = copy_from_user(&sync_request, argp, + sizeof(struct fb_sync_request_s)); + break; + case FBIO_WAITFORVSYNC: + case FBIOGET_OSD_SCALE_AXIS: + case FBIOPUT_OSD_ORDER: + case FBIOGET_OSD_ORDER: + case FBIOGET_OSD_GET_GBL_ALPHA: + case FBIOPUT_OSD_2X_SCALE: + case FBIOPUT_OSD_ENABLE_3D_MODE: + case FBIOPUT_OSD_FREE_SCALE_ENABLE: + case FBIOPUT_OSD_FREE_SCALE_MODE: + case FBIOPUT_OSD_FREE_SCALE_WIDTH: + case FBIOPUT_OSD_FREE_SCALE_HEIGHT: + case FBIOGET_OSD_BLOCK_WINDOWS: + case FBIOGET_OSD_BLOCK_MODE: + case FBIOGET_OSD_FREE_SCALE_AXIS: + case FBIOGET_OSD_WINDOW_AXIS: + case FBIOPUT_OSD_REVERSE: + case FBIOPUT_OSD_ROTATE_ON: + case FBIOPUT_OSD_ROTATE_ANGLE: + break; + case FBIOGET_OSD_DMABUF: + ret = copy_from_user(&dmaexp, argp, + sizeof(struct fb_dmabuf_export)); + break; + case FBIOPUT_OSD_BLOCK_MODE: + ret = copy_from_user(&block_mode, argp, sizeof(u32)); + break; + case FBIOPUT_OSD_BLOCK_WINDOWS: + ret = copy_from_user(&block_windows, argp, 8 * sizeof(u32)); + break; + case FBIOPUT_OSD_FREE_SCALE_AXIS: + ret = copy_from_user(&osd_axis, argp, 4 * sizeof(s32)); + break; + case FBIOPUT_OSD_WINDOW_AXIS: + ret = copy_from_user(&osd_dst_axis, argp, 4 * sizeof(s32)); + break; + default: + osd_log_err("command 0x%x not supported (%s)\n", + cmd, current->comm); + return -1; + } + mutex_lock(&fbdev->lock); + switch (cmd) { + case FBIOPUT_OSD_ORDER: + osd_set_order_hw(info->node, arg); + break; + case FBIOGET_OSD_ORDER: + osd_get_order_hw(info->node, &osd_order); + ret = copy_to_user(argp, &osd_order, sizeof(u32)); + break; + case FBIOPUT_OSD_FREE_SCALE_ENABLE: + osd_set_free_scale_enable_hw(info->node, arg); + break; + case FBIOPUT_OSD_FREE_SCALE_MODE: + osd_set_free_scale_mode_hw(info->node, arg); + break; + case FBIOPUT_OSD_ENABLE_3D_MODE: + osd_enable_3d_mode_hw(info->node, arg); + break; + case FBIOPUT_OSD_2X_SCALE: + /* + * high 16 bits for h_scale_enable; + * low 16 bits for v_scale_enable + */ + osd_set_2x_scale_hw(info->node, arg & 0xffff0000 ? 1 : 0, + arg & 0xffff ? 1 : 0); + break; + case FBIOGET_OSD_FLUSH_RATE: + osd_get_flush_rate_hw(&flush_rate); + if (copy_to_user(argp, &flush_rate, sizeof(u32))) + return -EFAULT; + break; + case FBIOPUT_OSD_REVERSE: + if (arg >= REVERSE_MAX) + arg = REVERSE_FALSE; + osd_set_reverse_hw(info->node, arg); + break; + case FBIOPUT_OSD_ROTATE_ON: + break; + case FBIOPUT_OSD_ROTATE_ANGLE: + break; + case FBIOPUT_OSD_SRCCOLORKEY: + switch (fbdev->color->color_index) { + case COLOR_INDEX_16_655: + case COLOR_INDEX_16_844: + case COLOR_INDEX_16_565: + case COLOR_INDEX_24_888_B: + case COLOR_INDEX_24_RGB: + case COLOR_INDEX_YUV_422: + osd_log_dbg("set osd color key 0x%x\n", src_colorkey); + fbdev->color_key = src_colorkey; + osd_set_color_key_hw(info->node, + fbdev->color->color_index, src_colorkey); + break; + default: + break; + } + break; + case FBIOPUT_OSD_SRCKEY_ENABLE: + switch (fbdev->color->color_index) { + case COLOR_INDEX_16_655: + case COLOR_INDEX_16_844: + case COLOR_INDEX_16_565: + case COLOR_INDEX_24_888_B: + case COLOR_INDEX_24_RGB: + case COLOR_INDEX_YUV_422: + osd_log_dbg("set osd color key %s\n", + srckey_enable ? "enable" : "disable"); + if (srckey_enable != 0) { + fbdev->enable_key_flag |= KEYCOLOR_FLAG_TARGET; + if (!(fbdev->enable_key_flag & + KEYCOLOR_FLAG_ONHOLD)) { + osd_srckey_enable_hw(info->node, 1); + fbdev->enable_key_flag |= + KEYCOLOR_FLAG_CURRENT; + } + } else { + osd_srckey_enable_hw(info->node, 0); + fbdev->enable_key_flag &= ~(KEYCOLOR_FLAG_TARGET + | KEYCOLOR_FLAG_CURRENT); + } + break; + default: + break; + } + break; + case FBIOPUT_OSD_SET_GBL_ALPHA: + osd_set_gbl_alpha_hw(info->node, gbl_alpha); + break; + case FBIOGET_OSD_GET_GBL_ALPHA: + gbl_alpha = osd_get_gbl_alpha_hw(info->node); + ret = copy_to_user(argp, &gbl_alpha, sizeof(u32)); + break; + case FBIOGET_OSD_SCALE_AXIS: + osd_get_scale_axis_hw(info->node, &osd_axis[0], + &osd_axis[1], &osd_axis[2], &osd_axis[3]); + ret = copy_to_user(argp, &osd_axis, 4 * sizeof(s32)); + break; + case FBIOPUT_OSD_SCALE_AXIS: + osd_set_scale_axis_hw(info->node, osd_axis[0], osd_axis[1], + osd_axis[2], osd_axis[3]); + break; + case FBIOGET_OSD_BLOCK_WINDOWS: + osd_get_block_windows_hw(info->node, block_windows); + ret = copy_to_user(argp, &block_windows, 8 * sizeof(u32)); + break; + case FBIOPUT_OSD_BLOCK_WINDOWS: + osd_set_block_windows_hw(info->node, block_windows); + break; + case FBIOPUT_OSD_BLOCK_MODE: + osd_set_block_mode_hw(info->node, block_mode); + break; + case FBIOGET_OSD_BLOCK_MODE: + osd_get_block_mode_hw(info->node, &block_mode); + ret = copy_to_user(argp, &block_mode, sizeof(u32)); + break; + case FBIOGET_OSD_FREE_SCALE_AXIS: + osd_get_free_scale_axis_hw(info->node, &osd_axis[0], + &osd_axis[1], &osd_axis[2], &osd_axis[3]); + ret = copy_to_user(argp, &osd_axis, 4 * sizeof(s32)); + break; + case FBIOGET_OSD_WINDOW_AXIS: + osd_get_window_axis_hw(info->node, &osd_dst_axis[0], + &osd_dst_axis[1], &osd_dst_axis[2], &osd_dst_axis[3]); + ret = copy_to_user(argp, &osd_dst_axis, 4 * sizeof(s32)); + break; + case FBIOPUT_OSD_FREE_SCALE_AXIS: + osd_set_free_scale_axis_hw(info->node, osd_axis[0], + osd_axis[1], osd_axis[2], osd_axis[3]); + break; + case FBIOPUT_OSD_WINDOW_AXIS: + osd_set_window_axis_hw(info->node, osd_dst_axis[0], + osd_dst_axis[1], osd_dst_axis[2], osd_dst_axis[3]); + break; + case FBIOPUT_OSD_SYNC_ADD: + sync_request.out_fen_fd = + osd_sync_request(info->node, info->var.yres, + sync_request.xoffset, + sync_request.yoffset, + sync_request.in_fen_fd); + ret = copy_to_user(argp, &sync_request, + sizeof(struct fb_sync_request_s)); + if (sync_request.out_fen_fd < 0) { + /* fence create fail. */ + ret = -1; + } else { + info->var.xoffset = sync_request.xoffset; + info->var.yoffset = sync_request.yoffset; + } + break; + case FBIOGET_OSD_DMABUF: +#ifdef CONFIG_ION + if (info->node == DEV_OSD0 && osd_get_afbc()) { + dmaexp.fd = + ion_share_dma_buf_fd( + fb_ion_client, + fb_ion_handle[info->node] + [dmaexp.buffer_idx]); + } else { + dmaexp.fd = + ion_share_dma_buf_fd( + fb_ion_client, + fb_ion_handle[info->node][0]); + } + dmaexp.flags = O_CLOEXEC; + + ret = copy_to_user(argp, &dmaexp, sizeof(dmaexp)) + ? -EFAULT : 0; + break; +#endif + case FBIO_WAITFORVSYNC: + osd_wait_vsync_event(); + ret = copy_to_user(argp, &ret, sizeof(u32)); + break; + default: + break; + } + mutex_unlock(&fbdev->lock); + return ret; +} + +#ifdef CONFIG_COMPAT +struct fb_cursor_user32 { + __u16 set; /* what to set */ + __u16 enable; /* cursor on/off */ + __u16 rop; /* bitop operation */ + compat_caddr_t mask; + struct fbcurpos hot; /* cursor hot spot */ + struct fb_image image; /* Cursor image */ +}; + +static int osd_compat_cursor(struct fb_info *info, unsigned long arg) +{ + unsigned long ret; + struct fb_cursor_user __user *ucursor; + struct fb_cursor_user32 __user *ucursor32; + struct fb_cursor cursor; + void __user *argp; + __u32 data; + + ucursor = compat_alloc_user_space(sizeof(*ucursor)); + ucursor32 = compat_ptr(arg); + + if (copy_in_user(&ucursor->set, &ucursor32->set, 3 * sizeof(__u16))) + return -EFAULT; + if (get_user(data, &ucursor32->mask) || + put_user(compat_ptr(data), &ucursor->mask)) + return -EFAULT; + if (copy_in_user(&ucursor->hot, &ucursor32->hot, 2 * sizeof(__u16))) + return -EFAULT; + + argp = (void __user *)ucursor; + if (copy_from_user(&cursor, argp, sizeof(cursor))) + return -EFAULT; + + if (!lock_fb_info(info)) + return -ENODEV; + if (!info->fbops->fb_cursor) + return -EINVAL; + console_lock(); + ret = info->fbops->fb_cursor(info, &cursor); + console_unlock(); + unlock_fb_info(info); + + if (ret == 0 && copy_to_user(argp, &cursor, sizeof(cursor))) + return -EFAULT; + + return ret; +} + +static int osd_compat_ioctl(struct fb_info *info, + unsigned int cmd, unsigned long arg) +{ + unsigned long ret; + + arg = (unsigned long)compat_ptr(arg); + + /* handle fbio cursor command for 32-bit app */ + if ((cmd & 0xFFFF) == (FBIO_CURSOR & 0xFFFF)) + ret = osd_compat_cursor(info, arg); + else + ret = osd_ioctl(info, cmd, arg); + + return ret; +} +#endif + +static int osd_open(struct fb_info *info, int arg) +{ + int j; + int ret = 0; + u32 fb_index; + int logo_index = -1; + struct osd_fb_dev_s *fbdev; + struct fb_fix_screeninfo *fix = NULL; + struct fb_var_screeninfo *var = NULL; + struct platform_device *pdev = NULL; + + fbdev = (struct osd_fb_dev_s *)info->par; + if (info->screen_base != NULL) + return 0; + pdev = fbdev->dev; + fb_index = fbdev->fb_index; + fix = &info->fix; + var = &info->var; + if (fb_rmem.base == 0) { + #ifdef CONFIG_AMLOGIC_ION + pr_info("use ion buffer for fb memory\n"); + if (!fb_ion_client) + fb_ion_client = meson_ion_client_create(-1, "meson-fb"); + if (fb_index == DEV_OSD0 && osd_get_afbc()) { + pr_info("OSD0 as afbcd mode\n"); + for (j = 0; j < OSD_MAX_BUF_NUM; j++) { + fb_ion_handle[fb_index][j] = + ion_alloc(fb_ion_client, + PAGE_ALIGN(fb_memsize[fb_index]/ + OSD_MAX_BUF_NUM), + 0, + (1 << ION_HEAP_TYPE_CARVEOUT), + 0); + ret = ion_phys(fb_ion_client, + fb_ion_handle[fb_index][j], + (ion_phys_addr_t *) + &fb_rmem_afbc_paddr[fb_index][j], + (size_t *) + &fb_rmem_afbc_size[fb_index][j]); + fb_rmem_afbc_vaddr[fb_index][j] = + ion_map_kernel(fb_ion_client, + fb_ion_handle[fb_index][j]); + dev_alert(&pdev->dev, + "create ion_client %p, handle=%p\n", + fb_ion_client, + fb_ion_handle[fb_index][j]); + dev_alert(&pdev->dev, + "ion memory(%d): created fb at 0x%p, size %ld MiB\n", + fb_index, + (void *)fb_rmem_afbc_paddr + [fb_index][j], + (unsigned long)fb_rmem_afbc_size + [fb_index][j] / SZ_1M); + fbdev->fb_afbc_len[j] = + fb_rmem_afbc_size[fb_index][j]; + fbdev->fb_mem_afbc_paddr[j] = + fb_rmem_afbc_paddr[fb_index][j]; + fbdev->fb_mem_afbc_vaddr[j] = + fb_rmem_afbc_vaddr[fb_index][j]; + if (!fbdev->fb_mem_afbc_vaddr[j]) { + osd_log_err("failed to ioremap afbc frame buffer\n"); + return -1; + } + osd_log_info(" %d, phy: 0x%p, vir:0x%p, size=%dK\n\n", + fb_index, + (void *)fbdev->fb_mem_afbc_paddr[j], + fbdev->fb_mem_afbc_vaddr[j], + fbdev->fb_afbc_len[j] >> 10); + } + fb_rmem_paddr[fb_index] = + fb_rmem_afbc_paddr[fb_index][0]; + fb_rmem_vaddr[fb_index] = + fb_rmem_afbc_vaddr[fb_index][0]; + fb_rmem_size[fb_index] = + fb_rmem_afbc_size[fb_index][0]; + } else { + fb_ion_handle[fb_index][0] = + ion_alloc(fb_ion_client, + fb_memsize[fb_index], + 0, + (1 << ION_HEAP_TYPE_CARVEOUT), + 0); + ret = ion_phys(fb_ion_client, + fb_ion_handle[fb_index][0], + (ion_phys_addr_t *)&fb_rmem_paddr[fb_index], + (size_t *)&fb_rmem_size[fb_index]); + fb_rmem_vaddr[fb_index] = + ion_map_kernel(fb_ion_client, + fb_ion_handle[fb_index][0]); + dev_notice(&pdev->dev, + "create ion_client %p, handle=%p\n", + fb_ion_client, + fb_ion_handle[fb_index][0]); + dev_notice(&pdev->dev, + "ion memory(%d): created fb at 0x%p, size %ld MiB\n", + fb_index, + (void *)fb_rmem_paddr[fb_index], + (unsigned long)fb_rmem_size[fb_index] / SZ_1M); + } + #endif + } else { + fb_rmem_size[fb_index] = fb_memsize[fb_index]; + if (fb_index == DEV_OSD0) + fb_rmem_paddr[fb_index] = fb_rmem.base; + else if (fb_index == DEV_OSD1) { + if ((OSD_COUNT == 2) && + ((fb_memsize[0] + fb_memsize[1]) <= fb_rmem.size)) { + fb_rmem_paddr[fb_index] = + fb_rmem.base + fb_memsize[0]; + } + } + if ((fb_rmem_paddr[fb_index] > 0) && + (fb_rmem_size[fb_index] > 0)) { + fb_rmem_vaddr[fb_index] = + ioremap_wc(fb_rmem_paddr[fb_index], + fb_rmem_size[fb_index]); + if (!fb_rmem_vaddr[fb_index]) + osd_log_err("fb[%d] ioremap error", + fb_index); + } + } + fbdev->fb_len = fb_rmem_size[fb_index]; + fbdev->fb_mem_paddr = fb_rmem_paddr[fb_index]; + fbdev->fb_mem_vaddr = fb_rmem_vaddr[fb_index]; + if (!fbdev->fb_mem_vaddr) { + osd_log_err("failed to ioremap frame buffer\n"); + ret = -ENOMEM; + } + osd_log_info("Frame buffer memory assigned at"); + osd_log_info(" %d, phy: 0x%p, vir:0x%p, size=%dK\n\n", + fb_index, (void *)fbdev->fb_mem_paddr, + fbdev->fb_mem_vaddr, fbdev->fb_len >> 10); + if (fb_index == DEV_OSD0 && osd_get_afbc()) { + for (j = 0; j < OSD_MAX_BUF_NUM; j++) { + fbdev->fb_afbc_len[j] = + fb_rmem_afbc_size[fb_index][j]; + fbdev->fb_mem_afbc_paddr[j] = + fb_rmem_afbc_paddr[fb_index][j]; + fbdev->fb_mem_afbc_vaddr[j] = + fb_rmem_afbc_vaddr[fb_index][j]; + if (!fbdev->fb_mem_afbc_vaddr[j]) { + osd_log_err("failed to ioremap afbc frame buffer\n"); + return -ENOMEM; + } + osd_log_info(" %d, phy: 0x%p, vir:0x%p, size=%dK\n\n", + fb_index, + (void *) + fbdev->fb_mem_afbc_paddr[j], + fbdev->fb_mem_afbc_vaddr[j], + fbdev->fb_afbc_len[j] >> 10); + } + } + fix->smem_start = fbdev->fb_mem_paddr; + fix->smem_len = fbdev->fb_len; + info->screen_base = (char __iomem *)fbdev->fb_mem_vaddr; + info->screen_size = fix->smem_len; + logo_index = osd_get_logo_index(); + if (osd_check_fbsize(var, info)) + return -ENOMEM; + /* clear osd buffer if not logo layer */ + if ((logo_index < 0) || (logo_index != fb_index)) { + osd_log_info("---------------clear fb%d memory %p\n", + fb_index, fbdev->fb_mem_vaddr); + memset(fbdev->fb_mem_vaddr, 0x0, fbdev->fb_len); + if (fb_index == DEV_OSD0 && osd_get_afbc()) { + for (j = 1; j < OSD_MAX_BUF_NUM; j++) { + osd_log_info( + "---------------clear fb%d memory %p\n", + fb_index, + fbdev->fb_mem_afbc_vaddr[j]); + memset(fbdev->fb_mem_afbc_vaddr[j], + 0x0, + fbdev->fb_afbc_len[j]); + } + } else { + /* two case in one + * 1. the big buffer ion alloc + * 2. reserved memory + */ + + memset(fb_rmem_vaddr[fb_index], + 0x0, + fb_rmem_size[fb_index]); + } + /* setup osd if not logo layer */ + osddev_setup(fbdev); + } else { + /* memset(fb_rmem_vaddr[fb_index], + * 0x0, + * fb_rmem_size[fb_index]); + */ + osd_log_info("fb%d open, logo index:%d\n", + fb_index, logo_index); + } + return 0; +} + +static ssize_t osd_clear(struct device *device, struct device_attribute *attr, + const char *buf, size_t count) +{ + u32 res = 0; + int ret = 0; + + ret = kstrtoint(buf, 0, &res); + osd_log_info("clear: osd %d\n", res); + + memset(fb_rmem_vaddr[res], + 0x0, + fb_rmem_size[res]); + + return count; +} + +int osd_blank(int blank_mode, struct fb_info *info) +{ + osd_enable_hw(info->node, (blank_mode != 0) ? 0 : 1); + return 0; +} + +static int osd_pan_display(struct fb_var_screeninfo *var, + struct fb_info *fbi) +{ + osd_pan_display_hw(fbi->node, var->xoffset, var->yoffset); + osd_log_dbg("osd_pan_display:=>osd%d xoff=%d, yoff=%d\n", + fbi->node, var->xoffset, var->yoffset); + return 0; +} + +#if defined(CONFIG_AMLOGIC_MEDIA_FB_OSD2_CURSOR) +static int osd_cursor(struct fb_info *fbi, struct fb_cursor *var) +{ + s16 startx = 0, starty = 0; + struct osd_fb_dev_s *fb_dev = gp_fbdev_list[1]; + + if (fb_dev) { + startx = fb_dev->osd_ctl.disp_start_x; + starty = fb_dev->osd_ctl.disp_start_y; + } + osd_cursor_hw(fbi->node, (s16)var->hot.x, (s16)var->hot.y, (s16)startx, + (s16)starty, fbi->var.xres, fbi->var.yres); + return 0; +} +#endif + +static int osd_sync(struct fb_info *info) +{ + return 0; +} + + +/* fb_ops structures */ +static struct fb_ops osd_ops = { + .owner = THIS_MODULE, + .fb_check_var = osd_check_var, + .fb_set_par = osd_set_par, + .fb_setcolreg = osd_setcolreg, + .fb_setcmap = osd_setcmap, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, +#ifdef CONFIG_FB_SOFT_CURSOR + .fb_cursor = soft_cursor, +#elif defined(CONFIG_AMLOGIC_MEDIA_FB_OSD2_CURSOR) + .fb_cursor = osd_cursor, +#endif + .fb_ioctl = osd_ioctl, +#ifdef CONFIG_COMPAT + .fb_compat_ioctl = osd_compat_ioctl, +#endif + .fb_open = osd_open, + .fb_blank = osd_blank, + .fb_pan_display = osd_pan_display, + .fb_sync = osd_sync, +}; + +static void set_default_display_axis(struct fb_var_screeninfo *var, + struct osd_ctl_s *osd_ctrl, const struct vinfo_s *vinfo) +{ + u32 virt_end_x = osd_ctrl->disp_start_x + var->xres; + u32 virt_end_y = osd_ctrl->disp_start_y + var->yres; + + if (virt_end_x > vinfo->width) { + /* screen axis */ + osd_ctrl->disp_end_x = vinfo->width - 1; + } else { + /* screen axis */ + osd_ctrl->disp_end_x = virt_end_x - 1; + } + if (virt_end_y > vinfo->height) + osd_ctrl->disp_end_y = vinfo->height - 1; + else { + /* screen axis */ + osd_ctrl->disp_end_y = virt_end_y - 1; + } +} + +int osd_notify_callback(struct notifier_block *block, unsigned long cmd, + void *para) +{ + struct vinfo_s *vinfo; + struct osd_fb_dev_s *fb_dev; + int i, blank; + struct disp_rect_s *disp_rect; + + vinfo = get_current_vinfo(); + if (!vinfo) { + osd_log_err("current vinfo NULL\n"); + return -1; + } + osd_log_info("current vmode=%s, cmd: 0x%lx\n", + vinfo->name, cmd); + switch (cmd) { +#if 0 + case VOUT_EVENT_MODE_CHANGE_PRE: + for (i = 0; i < OSD_COUNT; i++) { + fb_dev = gp_fbdev_list[i]; + if (osd_hw.enable[i]) { + fb_dev->dis_osd_mchange = true; + osd_enable_hw(i, false); + } + } + break; +#endif + case VOUT_EVENT_MODE_CHANGE: + for (i = 0; i < OSD_COUNT; i++) { + fb_dev = gp_fbdev_list[i]; + if (fb_dev == NULL) + continue; + set_default_display_axis(&fb_dev->fb_info->var, + &fb_dev->osd_ctl, vinfo); + console_lock(); + osddev_update_disp_axis(fb_dev, 1); +#ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD2_ENABLE + osd_set_antiflicker_hw(DEV_OSD1, vinfo, + gp_fbdev_list[DEV_OSD1]->fb_info->var.yres); +#endif + console_unlock(); +#if 0 + if (fb_dev->dis_osd_mchange) { + fb_dev->dis_osd_mchange = false; + osd_enable_hw(i, true); + } +#endif + } + break; + case VOUT_EVENT_OSD_BLANK: + blank = *(int *)para; + for (i = 0; i < OSD_COUNT; i++) { + fb_dev = gp_fbdev_list[i]; + if (fb_dev == NULL) + continue; + console_lock(); + osd_blank(blank, fb_dev->fb_info); + console_unlock(); + } + break; + case VOUT_EVENT_OSD_DISP_AXIS: + disp_rect = (struct disp_rect_s *)para; + for (i = 0; i < OSD_COUNT; i++) { + if (!disp_rect) + break; + fb_dev = gp_fbdev_list[i]; + /* + * if osd layer preblend, + * it's position is controlled by vpp. + if (fb_dev->preblend_enable) + break; + */ + fb_dev->osd_ctl.disp_start_x = disp_rect->x; + fb_dev->osd_ctl.disp_start_y = disp_rect->y; + osd_log_dbg("set disp axis: x:%d y:%d w:%d h:%d\n", + disp_rect->x, disp_rect->y, + disp_rect->w, disp_rect->h); + if (disp_rect->x + disp_rect->w > vinfo->width) + fb_dev->osd_ctl.disp_end_x = vinfo->width - 1; + else + fb_dev->osd_ctl.disp_end_x = + fb_dev->osd_ctl.disp_start_x + + disp_rect->w - 1; + if (disp_rect->y + disp_rect->h > vinfo->height) + fb_dev->osd_ctl.disp_end_y = vinfo->height - 1; + else + fb_dev->osd_ctl.disp_end_y = + fb_dev->osd_ctl.disp_start_y + + disp_rect->h - 1; + disp_rect++; + osd_log_dbg("new disp axis: x0:%d y0:%d x1:%d y1:%d\n", + fb_dev->osd_ctl.disp_start_x, + fb_dev->osd_ctl.disp_start_y, + fb_dev->osd_ctl.disp_end_x, + fb_dev->osd_ctl.disp_end_y); + console_lock(); + osddev_update_disp_axis(fb_dev, 0); + console_unlock(); + } + break; + } + return 0; +} + +static struct notifier_block osd_notifier_nb = { + .notifier_call = osd_notify_callback, +}; + +static ssize_t store_enable_3d(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + struct osd_fb_dev_s *fbdev = (struct osd_fb_dev_s *)fb_info->par; + int res = 0; + int ret = 0; + + ret = kstrtoint(buf, 0, &res); + fbdev->enable_3d = res; + osd_enable_3d_mode_hw(fb_info->node, fbdev->enable_3d); + return count; +} + +static ssize_t show_enable_3d(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + struct osd_fb_dev_s *fbdev = (struct osd_fb_dev_s *)fb_info->par; + + return snprintf(buf, PAGE_SIZE, "3d_enable:[0x%x]\n", fbdev->enable_3d); +} + +static ssize_t store_color_key(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + struct osd_fb_dev_s *fbdev = (struct osd_fb_dev_s *)fb_info->par; + int res = 0; + int ret = 0; + + ret = kstrtoint(buf, 16, &res); + switch (fbdev->color->color_index) { + case COLOR_INDEX_16_655: + case COLOR_INDEX_16_844: + case COLOR_INDEX_16_565: + case COLOR_INDEX_24_888_B: + case COLOR_INDEX_24_RGB: + case COLOR_INDEX_YUV_422: + fbdev->color_key = res; + osd_set_color_key_hw(fb_info->node, fbdev->color->color_index, + fbdev->color_key); + break; + default: + break; + } + + return count; +} + +static ssize_t show_color_key(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + struct osd_fb_dev_s *fbdev = (struct osd_fb_dev_s *)fb_info->par; + + return snprintf(buf, PAGE_SIZE, "0x%x\n", fbdev->color_key); +} + +static ssize_t store_enable_key(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + struct osd_fb_dev_s *fbdev = (struct osd_fb_dev_s *)fb_info->par; + int res = 0; + int ret = 0; + + ret = kstrtoint(buf, 0, &res); + mutex_lock(&fbdev->lock); + if (res != 0) { + fbdev->enable_key_flag |= KEYCOLOR_FLAG_TARGET; + if (!(fbdev->enable_key_flag & KEYCOLOR_FLAG_ONHOLD)) { + osd_srckey_enable_hw(fb_info->node, 1); + fbdev->enable_key_flag |= KEYCOLOR_FLAG_CURRENT; + } + } else { + fbdev->enable_key_flag &= + ~(KEYCOLOR_FLAG_TARGET | KEYCOLOR_FLAG_CURRENT); + osd_srckey_enable_hw(fb_info->node, 0); + } + mutex_unlock(&fbdev->lock); + return count; +} + +static ssize_t show_enable_key(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + struct osd_fb_dev_s *fbdev = (struct osd_fb_dev_s *)fb_info->par; + + return snprintf(buf, PAGE_SIZE, (fbdev->enable_key_flag + & KEYCOLOR_FLAG_TARGET) ? "1\n" : "0\n"); +} + +static ssize_t store_enable_key_onhold(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + struct osd_fb_dev_s *fbdev = (struct osd_fb_dev_s *)fb_info->par; + int res = 0; + int ret = 0; + + ret = kstrtoint(buf, 0, &res); + mutex_lock(&fbdev->lock); + if (res != 0) { + /* hold all the calls to enable color key */ + fbdev->enable_key_flag |= KEYCOLOR_FLAG_ONHOLD; + fbdev->enable_key_flag &= ~KEYCOLOR_FLAG_CURRENT; + osd_srckey_enable_hw(fb_info->node, 0); + } else { + fbdev->enable_key_flag &= ~KEYCOLOR_FLAG_ONHOLD; + /* + * if target and current mistach + * then recover the pending key settings + */ + if (fbdev->enable_key_flag & KEYCOLOR_FLAG_TARGET) { + if ((fbdev->enable_key_flag & KEYCOLOR_FLAG_CURRENT) + == 0) { + fbdev->enable_key_flag |= KEYCOLOR_FLAG_CURRENT; + osd_srckey_enable_hw(fb_info->node, 1); + } + } else { + if (fbdev->enable_key_flag & KEYCOLOR_FLAG_CURRENT) { + fbdev->enable_key_flag &= + ~KEYCOLOR_FLAG_CURRENT; + osd_srckey_enable_hw(fb_info->node, 0); + } + } + } + mutex_unlock(&fbdev->lock); + return count; +} + +static ssize_t show_enable_key_onhold(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + struct osd_fb_dev_s *fbdev = (struct osd_fb_dev_s *)fb_info->par; + + return snprintf(buf, PAGE_SIZE, + (fbdev->enable_key_flag & KEYCOLOR_FLAG_ONHOLD) ? + "1\n" : "0\n"); +} + +static int parse_para(const char *para, int para_num, int *result) +{ + char *token = NULL; + char *params, *params_base; + int *out = result; + int len = 0, count = 0; + int res = 0; + int ret = 0; + + if (!para) + return 0; + + params = kstrdup(para, GFP_KERNEL); + params_base = params; + token = params; + len = strlen(token); + do { + token = strsep(¶ms, " "); + while (token && (isspace(*token) + || !isgraph(*token)) && len) { + token++; + len--; + } + if (len == 0) + break; + ret = kstrtoint(token, 0, &res); + if (ret < 0) + break; + len = strlen(token); + *out++ = res; + count++; + } while ((token) && (count < para_num) && (len > 0)); + + kfree(params_base); + return count; +} + +static ssize_t show_free_scale_axis(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + int x, y, w, h; + + osd_get_free_scale_axis_hw(fb_info->node, &x, &y, &w, &h); + return snprintf(buf, PAGE_SIZE, "%d %d %d %d\n", x, y, w, h); +} + +static ssize_t store_free_scale_axis(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + int parsed[4]; + + if (likely(parse_para(buf, 4, parsed) == 4)) + osd_set_free_scale_axis_hw(fb_info->node, + parsed[0], parsed[1], parsed[2], parsed[3]); + else + osd_log_err("set free scale axis error\n"); + return count; +} + +static ssize_t show_scale_axis(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + int x0, y0, x1, y1; + + osd_get_scale_axis_hw(fb_info->node, &x0, &y0, &x1, &y1); + return snprintf(buf, PAGE_SIZE, "%d %d %d %d\n", x0, y0, x1, y1); +} + +static ssize_t store_scale_axis(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + int parsed[4]; + + if (likely(parse_para(buf, 4, parsed) == 4)) + osd_set_scale_axis_hw(fb_info->node, + parsed[0], parsed[1], parsed[2], parsed[3]); + else + osd_log_err("set scale axis error\n"); + return count; +} + + +static ssize_t show_scale_width(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + unsigned int free_scale_width = 0; + + osd_get_free_scale_width_hw(fb_info->node, &free_scale_width); + return snprintf(buf, PAGE_SIZE, "free_scale_width:%d\n", + free_scale_width); +} + +static ssize_t show_scale_height(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + unsigned int free_scale_height = 0; + + osd_get_free_scale_height_hw(fb_info->node, &free_scale_height); + return snprintf(buf, PAGE_SIZE, "free_scale_height:%d\n", + free_scale_height); +} + +static ssize_t store_free_scale(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + unsigned int free_scale_enable = 0; + int res = 0; + int ret = 0; + + ret = kstrtoint(buf, 0, &res); + free_scale_enable = res; + osd_set_free_scale_enable_hw(fb_info->node, free_scale_enable); + return count; +} + +static ssize_t show_free_scale(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + unsigned int free_scale_enable = 0; + + osd_get_free_scale_enable_hw(fb_info->node, &free_scale_enable); + return snprintf(buf, PAGE_SIZE, "free_scale_enable:[0x%x]\n", + free_scale_enable); +} + +static ssize_t store_freescale_mode(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + unsigned int free_scale_mode = 0; + int res = 0; + int ret = 0; + + ret = kstrtoint(buf, 0, &res); + free_scale_mode = res; + osd_set_free_scale_mode_hw(fb_info->node, free_scale_mode); + return count; +} + +static ssize_t show_freescale_mode(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + unsigned int free_scale_mode = 0; + char *help_info = "free scale mode:\n" + " 0: VPU free scaler\n" + " 1: OSD free scaler\n" + " 2: OSD super scaler\n"; + + osd_get_free_scale_mode_hw(fb_info->node, &free_scale_mode); + return snprintf(buf, PAGE_SIZE, "%scurrent free_scale_mode:%d\n", + help_info, free_scale_mode); +} + +static ssize_t store_scale(struct device *device, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + struct osd_fb_dev_s *fbdev = (struct osd_fb_dev_s *)fb_info->par; + int res = 0; + int ret = 0; + + ret = kstrtoint(buf, 0, &res); + fbdev->scale = res; + osd_set_2x_scale_hw(fb_info->node, fbdev->scale & 0xffff0000 ? 1 : 0, + fbdev->scale & 0xffff ? 1 : 0); + return count; +} + +static ssize_t show_scale(struct device *device, struct device_attribute *attr, + char *buf) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + struct osd_fb_dev_s *fbdev = (struct osd_fb_dev_s *)fb_info->par; + + return snprintf(buf, PAGE_SIZE, "scale:[0x%x]\n", fbdev->scale); +} + +static ssize_t show_window_axis(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + int x0, y0, x1, y1; + + osd_get_window_axis_hw(fb_info->node, &x0, &y0, &x1, &y1); + return snprintf(buf, PAGE_SIZE, "%d %d %d %d\n", + x0, y0, x1, y1); +} + +static ssize_t store_window_axis(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + s32 parsed[4]; + + if (likely(parse_para(buf, 4, parsed) == 4)) + osd_set_window_axis_hw(fb_info->node, + parsed[0], parsed[1], parsed[2], parsed[3]); + else + osd_log_err("set window axis error\n"); + return count; +} + +static ssize_t show_debug(struct device *device, struct device_attribute *attr, + char *buf) +{ + char *help = osd_get_debug_hw(); + + return snprintf(buf, strlen(help), "%s", help); +} + +static ssize_t store_debug(struct device *device, struct device_attribute *attr, + const char *buf, size_t count) +{ + int ret = -EINVAL; + + ret = osd_set_debug_hw(buf); + if (ret == 0) + ret = count; + + return ret; +} + +static ssize_t show_afbcd(struct device *device, struct device_attribute *attr, + char *buf) +{ + u32 enable = osd_get_afbc(); + + return snprintf(buf, PAGE_SIZE, "%d\n", enable); +} + +static ssize_t store_afbcd(struct device *device, struct device_attribute *attr, + const char *buf, size_t count) +{ + u32 res = 0; + int ret = 0; + + ret = kstrtoint(buf, 0, &res); + osd_log_info("afbc: %d\n", res); + + osd_set_afbc(res); + + return count; +} + +static ssize_t show_log_level(struct device *device, + struct device_attribute *attr, + char *buf) +{ + return snprintf(buf, 40, "%d\n", osd_log_level); +} + +static ssize_t store_log_level(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int res = 0; + int ret = 0; + + ret = kstrtoint(buf, 0, &res); + osd_log_info("log_level: %d->%d\n", osd_log_level, res); + osd_log_level = res; + + return count; +} + +static ssize_t store_order(struct device *device, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + struct osd_fb_dev_s *fbdev = (struct osd_fb_dev_s *)fb_info->par; + int res = 0; + int ret = 0; + + ret = kstrtoint(buf, 0, &res); + fbdev->order = res; + osd_set_order_hw(fb_info->node, fbdev->order); + return count; +} + +static ssize_t show_order(struct device *device, struct device_attribute *attr, + char *buf) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + struct osd_fb_dev_s *fbdev = (struct osd_fb_dev_s *)fb_info->par; + + osd_get_order_hw(fb_info->node, &(fbdev->order)); + return snprintf(buf, PAGE_SIZE, "order:[0x%x]\n", fbdev->order); +} + +static ssize_t show_block_windows(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + u32 wins[8]; + + osd_get_block_windows_hw(fb_info->node, wins); + return snprintf(buf, PAGE_SIZE, + "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", + wins[0], wins[1], wins[2], wins[3], + wins[4], wins[5], wins[6], wins[7]); +} + +static ssize_t store_block_windows(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + int parsed[8]; + + if (likely(parse_para(buf, 8, parsed) == 8)) + osd_set_block_windows_hw(fb_info->node, parsed); + else + osd_log_err("set block windows error\n"); + return count; +} + +static ssize_t show_block_mode(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + u32 mode; + + osd_get_block_mode_hw(fb_info->node, &mode); + return snprintf(buf, PAGE_SIZE, "0x%x\n", mode); +} + +static ssize_t store_block_mode(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + u32 mode; + int res = 0; + int ret = 0; + + ret = kstrtoint(buf, 0, &res); + mode = res; + osd_set_block_mode_hw(fb_info->node, mode); + return count; +} + +static ssize_t show_flush_rate(struct device *device, + struct device_attribute *attr, + char *buf) +{ + u32 flush_rate = 0; + + osd_get_flush_rate_hw(&flush_rate); + return snprintf(buf, PAGE_SIZE, "flush_rate:[%d]\n", flush_rate); +} + +static ssize_t show_osd_reverse(struct device *device, + struct device_attribute *attr, + char *buf) +{ + char *str[4] = {"NONE", "ALL", "X_REV", "Y_REV"}; + struct fb_info *fb_info = dev_get_drvdata(device); + unsigned int osd_reverse = 0; + + osd_get_reverse_hw(fb_info->node, &osd_reverse); + if (osd_reverse >= REVERSE_MAX) + osd_reverse = REVERSE_FALSE; + return snprintf(buf, PAGE_SIZE, "osd_reverse:[%s]\n", + str[osd_reverse]); +} + +static ssize_t store_osd_reverse(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + unsigned int osd_reverse = 0; + int res = 0; + int ret = 0; + + ret = kstrtoint(buf, 0, &res); + osd_reverse = res; + if (osd_reverse >= REVERSE_MAX) + osd_reverse = REVERSE_FALSE; + osd_set_reverse_hw(fb_info->node, osd_reverse); + return count; +} + +static ssize_t show_antiflicker(struct device *device, + struct device_attribute *attr, + char *buf) +{ + unsigned int osd_antiflicker = 0; + struct fb_info *fb_info = dev_get_drvdata(device); + + osd_get_antiflicker_hw(fb_info->node, &osd_antiflicker); + return snprintf(buf, PAGE_SIZE, "osd_antifliter:[%s]\n", + osd_antiflicker ? "ON" : "OFF"); +} + +static ssize_t store_antiflicker(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct vinfo_s *vinfo; + unsigned int osd_antiflicker = 0; + struct fb_info *fb_info = dev_get_drvdata(device); + int res = 0; + int ret = 0; + + ret = kstrtoint(buf, 0, &res); + osd_antiflicker = res; + vinfo = get_current_vinfo(); + if (!vinfo) { + osd_log_err("get current vinfo NULL\n"); + return 0; + } + if (osd_antiflicker == 2) + osd_set_antiflicker_hw(fb_info->node, + vinfo, fb_info->var.yres); + else + osd_set_antiflicker_hw(fb_info->node, + vinfo, fb_info->var.yres); + return count; +} + +static ssize_t show_update_freescale(struct device *device, + struct device_attribute *attr, + char *buf) +{ + unsigned int update_state = 0; + + return snprintf(buf, PAGE_SIZE, "update_state:[%s]\n", + update_state ? "TRUE" : "FALSE"); +} + +static ssize_t store_update_freescale(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int update_state = 0; + int res = 0; + int ret = 0; + + ret = kstrtoint(buf, 0, &res); + update_state = res; + return count; +} + +static ssize_t show_ver_angle(struct device *device, + struct device_attribute *attr, + char *buf) +{ + unsigned int osd_angle = 0; + struct fb_info *fb_info = dev_get_drvdata(device); + + osd_get_angle_hw(fb_info->node, &osd_angle); + return snprintf(buf, PAGE_SIZE, "osd_angle:[%d]\n", osd_angle); +} + +static ssize_t store_ver_angle(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int osd_angle = 0; + struct fb_info *fb_info = dev_get_drvdata(device); + int res = 0; + int ret = 0; + + ret = kstrtoint(buf, 0, &res); + osd_angle = res; + memset((char *)fb_info->screen_base, 0x80, fb_info->screen_size); +#ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD2_ENABLE + osd_set_angle_hw(fb_info->node, osd_angle, fb_def_var[DEV_OSD1].yres, + fb_info->var.yres); +#endif + return count; +} + +static ssize_t show_ver_clone(struct device *device, + struct device_attribute *attr, + char *buf) +{ + unsigned int osd_clone = 0; + struct fb_info *fb_info = dev_get_drvdata(device); + + osd_get_clone_hw(fb_info->node, &osd_clone); + return snprintf(buf, PAGE_SIZE, "osd_clone:[%s]\n", + osd_clone ? "ON" : "OFF"); +} + +static ssize_t store_ver_clone(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int osd_clone = 0; + struct fb_info *fb_info = dev_get_drvdata(device); + int res = 0; + int ret = 0; + + ret = kstrtoint(buf, 0, &res); + osd_clone = res; + osd_set_clone_hw(fb_info->node, osd_clone); + return count; +} + +static ssize_t store_ver_update_pan(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + + osd_set_update_pan_hw(fb_info->node); + return count; +} + +static ssize_t show_reset_status(struct device *device, + struct device_attribute *attr, char *buf) +{ + u32 status = osd_get_reset_status(); + + return snprintf(buf, PAGE_SIZE, "0x%x\n", status); +} + +static ssize_t free_scale_switch(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + u32 res = 0; + int ret = 0; + unsigned int free_scale_enable = 0; + + ret = kstrtoint(buf, 0, &res); + free_scale_enable = res; + osd_switch_free_scale( + (fb_info->node == DEV_OSD0) ? DEV_OSD1 : DEV_OSD0, + 0, 0, fb_info->node, 1, free_scale_enable); + osd_log_info("free_scale_switch to fb%d, mode: 0x%x\n", + fb_info->node, free_scale_enable); + return count; +} + +static inline int str2lower(char *str) +{ + while (*str != '\0') { + *str = tolower(*str); + str++; + } + return 0; +} + +static struct para_osd_info_s para_osd_info[OSD_END + 2] = { + /* head */ + { + "head", OSD_INVALID_INFO, + OSD_END + 1, 1, + 0, OSD_END + 1 + }, + /* dev */ + { + "osd0", DEV_OSD0, + OSD_FIRST_GROUP_START - 1, OSD_FIRST_GROUP_START + 1, + OSD_FIRST_GROUP_START, OSD_SECOND_GROUP_START - 1 + }, + { + "osd1", DEV_OSD1, + OSD_FIRST_GROUP_START, OSD_FIRST_GROUP_START + 2, + OSD_FIRST_GROUP_START, OSD_SECOND_GROUP_START - 1 + }, + { + "all", DEV_ALL, + OSD_FIRST_GROUP_START + 1, OSD_FIRST_GROUP_START + 3, + OSD_FIRST_GROUP_START, OSD_SECOND_GROUP_START - 1 + }, + /* reverse_mode */ + { + "false", REVERSE_FALSE, + OSD_SECOND_GROUP_START - 1, OSD_SECOND_GROUP_START + 1, + OSD_SECOND_GROUP_START, OSD_END + }, + { + "true", REVERSE_TRUE, + OSD_SECOND_GROUP_START, OSD_SECOND_GROUP_START + 2, + OSD_SECOND_GROUP_START, OSD_END + }, + { + "x_rev", REVERSE_X, + OSD_SECOND_GROUP_START + 1, OSD_SECOND_GROUP_START + 3, + OSD_SECOND_GROUP_START, OSD_END + }, + { + "y_rev", REVERSE_Y, + OSD_SECOND_GROUP_START + 2, OSD_SECOND_GROUP_START + 4, + OSD_SECOND_GROUP_START, OSD_END + }, + { + "tail", OSD_INVALID_INFO, OSD_END, + 0, 0, + OSD_END + 1 + }, +}; + +static inline int install_osd_reverse_info(struct osd_info_s *init_osd_info, + char *para) +{ + u32 i = 0; + static u32 tail = OSD_END + 1; + u32 first = para_osd_info[0].next_idx; + + for (i = first; i < tail; i = para_osd_info[i].next_idx) { + if (strcmp(para_osd_info[i].name, para) == 0) { + u32 group_start = para_osd_info[i].cur_group_start; + u32 group_end = para_osd_info[i].cur_group_end; + u32 prev = para_osd_info[group_start].prev_idx; + u32 next = para_osd_info[group_end].next_idx; + + switch (para_osd_info[i].cur_group_start) { + case OSD_FIRST_GROUP_START: + init_osd_info->index = para_osd_info[i].info; + break; + case OSD_SECOND_GROUP_START: + init_osd_info->osd_reverse = + para_osd_info[i].info; + break; + } + para_osd_info[prev].next_idx = next; + para_osd_info[next].prev_idx = prev; + return 0; + } + } + return 0; +} + +static int __init osd_info_setup(char *str) +{ + char *ptr = str; + char sep[2]; + char *option; + int count = 2; + char find = 0; + struct osd_info_s *init_osd_info; + + if (str == NULL) + return -EINVAL; + + init_osd_info = &osd_info; + memset(init_osd_info, 0, sizeof(struct osd_info_s)); + do { + if (!isalpha(*ptr) && !isdigit(*ptr)) { + find = 1; + break; + } + } while (*++ptr != '\0'); + if (!find) + return -EINVAL; + sep[0] = *ptr; + sep[1] = '\0'; + while ((count--) && (option = strsep(&str, sep))) { + str2lower(option); + install_osd_reverse_info(init_osd_info, option); + } + return 0; +} + +__setup("osd_reverse=", osd_info_setup); +static struct device_attribute osd_attrs[] = { + __ATTR(scale, 0664, + show_scale, store_scale), + __ATTR(order, 0664, + show_order, store_order), + __ATTR(enable_3d, 0644, + show_enable_3d, store_enable_3d), + __ATTR(free_scale, 0664, + show_free_scale, store_free_scale), + __ATTR(scale_axis, 0644, + show_scale_axis, store_scale_axis), + __ATTR(scale_width, 0444, + show_scale_width, NULL), + __ATTR(scale_height, 0444, + show_scale_height, NULL), + __ATTR(color_key, 0644, + show_color_key, store_color_key), + __ATTR(enable_key, 0664, + show_enable_key, store_enable_key), + __ATTR(enable_key_onhold, 0664, + show_enable_key_onhold, store_enable_key_onhold), + __ATTR(block_windows, 0644, + show_block_windows, store_block_windows), + __ATTR(block_mode, 0664, + show_block_mode, store_block_mode), + __ATTR(free_scale_axis, 0664, + show_free_scale_axis, store_free_scale_axis), + __ATTR(debug, 0644, + show_debug, store_debug), + __ATTR(log_level, 0644, + show_log_level, store_log_level), + __ATTR(window_axis, 0664, + show_window_axis, store_window_axis), + __ATTR(freescale_mode, 0664, + show_freescale_mode, store_freescale_mode), + __ATTR(flush_rate, 0444, + show_flush_rate, NULL), + __ATTR(osd_reverse, 0644, + show_osd_reverse, store_osd_reverse), + __ATTR(osd_antiflicker, 0644, + show_antiflicker, store_antiflicker), + __ATTR(update_freescale, 0644, + show_update_freescale, store_update_freescale), + __ATTR(ver_angle, 0644, + show_ver_angle, store_ver_angle), + __ATTR(ver_clone, 0644, + show_ver_clone, store_ver_clone), + __ATTR(ver_update_pan, 0220, + NULL, store_ver_update_pan), + __ATTR(osd_afbcd, 0664, + show_afbcd, store_afbcd), + __ATTR(osd_clear, 0220, + NULL, osd_clear), + __ATTR(reset_status, 0444, + show_reset_status, NULL), + __ATTR(free_scale_switch, 0220, + NULL, free_scale_switch), +}; + +#ifdef CONFIG_PM +static int osd_suspend(struct platform_device *dev, pm_message_t state) +{ +#ifdef CONFIG_HAS_EARLYSUSPEND + if (early_suspend_flag) + return 0; +#endif + osd_suspend_hw(); + return 0; +} + +static int osd_resume(struct platform_device *dev) +{ +#ifdef CONFIG_SCREEN_ON_EARLY + if (early_resume_flag) { + early_resume_flag = 0; + return 0; + } +#endif +#ifdef CONFIG_HAS_EARLYSUSPEND + if (early_suspend_flag) + return 0; +#endif + osd_resume_hw(); + return 0; +} +#endif + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void osd_early_suspend(struct early_suspend *h) +{ + if (early_suspend_flag) + return; + osd_suspend_hw(); + early_suspend_flag = 1; +} + +static void osd_late_resume(struct early_suspend *h) +{ + if (!early_suspend_flag) + return; + early_suspend_flag = 0; + osd_resume_hw(); +} +#endif + +#ifdef CONFIG_SCREEN_ON_EARLY +void osd_resume_early(void) +{ +#ifdef CONFIG_HAS_EARLYSUSPEND + osd_resume_hw(); + early_suspend_flag = 0; +#endif + early_resume_flag = 1; +} +EXPORT_SYMBOL(osd_resume_early); +#endif + +#ifdef CONFIG_HIBERNATION +static int osd_realdata_save(void) +{ + osd_realdata_save_hw(); + return 0; +} + +static void osd_realdata_restore(void) +{ + osd_realdata_restore_hw(); +} + +static struct instaboot_realdata_ops osd_realdata_ops = { + .save = osd_realdata_save, + .restore = osd_realdata_restore, +}; + +static int osd_freeze(struct device *dev) +{ + osd_freeze_hw(); + return 0; +} + +static int osd_thaw(struct device *dev) +{ + osd_thaw_hw(); + return 0; +} + +static int osd_restore(struct device *dev) +{ + osd_restore_hw(); + return 0; +} +static int osd_pm_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + + return osd_suspend(pdev, PMSG_SUSPEND); +} +static int osd_pm_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + + return osd_resume(pdev); +} +#endif + +static int osd_probe(struct platform_device *pdev) +{ + struct fb_info *fbi = NULL; + const struct vinfo_s *vinfo; + struct fb_var_screeninfo *var; + struct fb_fix_screeninfo *fix; + int index, bpp; + struct osd_fb_dev_s *fbdev = NULL; + enum vmode_e current_mode = VMODE_MASK; + enum vmode_e logo_init = 0; + const void *prop; + int prop_idx = 0; + const char *str; + int i; + int ret = 0; + + /* get interrupt resource */ + int_viu_vsync = platform_get_irq_byname(pdev, "viu-vsync"); + if (int_viu_vsync == -ENXIO) { + osd_log_err("cannot get viu irq resource\n"); + goto failed1; + } else + osd_log_info("viu vsync irq: %d\n", int_viu_vsync); +#ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD_VSYNC_RDMA + int_rdma = platform_get_irq_byname(pdev, "rdma"); + if (int_viu_vsync == -ENXIO) { + osd_log_err("cannot get osd rdma irq resource\n"); + goto failed1; + } +#endif + /* get buffer size from dt */ + ret = of_property_read_u32_array(pdev->dev.of_node, + "mem_size", fb_memsize, 2); + if (ret) { + osd_log_err("not found mem_size from dtd\n"); + goto failed1; + } + + /* init reserved memory */ + ret = of_reserved_mem_device_init(&pdev->dev); + if ((ret != 0) && ((void *)fb_rmem.base == NULL)) + osd_log_err("failed to init reserved memory\n"); + + osd_log_dbg("%d, mem_size: 0x%x, 0x%x\n", + __LINE__, fb_memsize[0], fb_memsize[1]); + + /* get meson-fb resource from dt */ + prop = of_get_property(pdev->dev.of_node, "scale_mode", NULL); + if (prop) + prop_idx = of_read_ulong(prop, 1); + osd_set_free_scale_mode_hw(DEV_OSD0, prop_idx); + prop = of_get_property(pdev->dev.of_node, "4k2k_fb", NULL); + if (prop) + prop_idx = of_read_ulong(prop, 1); + osd_set_4k2k_fb_mode_hw(prop_idx); + /* get default display mode from dt */ + ret = of_property_read_string(pdev->dev.of_node, + "display_mode_default", &str); + if (ret) + current_mode = VMODE_MASK; + #ifdef CONFIG_AMLOGIC_TV_OUTPUT + else + current_mode = vmode_name_to_mode(str); + #endif + prop = of_get_property(pdev->dev.of_node, "pxp_mode", NULL); + if (prop) + prop_idx = of_read_ulong(prop, 1); + osd_set_pxp_mode(prop_idx); + + prop = of_get_property(pdev->dev.of_node, "ddr_urgent", NULL); + if (prop) { + prop_idx = of_read_ulong(prop, 1); + osd_set_urgent(0, (prop_idx != 0) ? 1 : 0); + osd_set_urgent(1, (prop_idx != 0) ? 1 : 0); + } + + /* if osd_init_hw is not set by logo, set vmode and init osd hw */ + logo_init = osd_get_init_hw_flag(); + if (logo_init == 0) { + if (current_mode < VMODE_MASK) + set_current_vmode(current_mode); + osd_init_hw(0); + } + + vinfo = get_current_vinfo(); + osd_log_info("%s vinfo:%p\n", __func__, vinfo); + for (index = 0; index < OSD_COUNT; index++) { + /* register frame buffer memory */ + fbi = framebuffer_alloc(sizeof(struct osd_fb_dev_s), + &pdev->dev); + if (!fbi) { + ret = -ENOMEM; + goto failed1; + } + fbdev = (struct osd_fb_dev_s *)fbi->par; + fbdev->fb_index = index; + fbdev->fb_info = fbi; + fbdev->dev = pdev; + mutex_init(&fbdev->lock); + var = &fbi->var; + fix = &fbi->fix; + gp_fbdev_list[index] = fbdev; + fbdev->fb_len = 0; + fbdev->fb_mem_paddr = 0; + fbdev->fb_mem_vaddr = 0; + if (vinfo) { + fb_def_var[index].width = vinfo->screen_real_width; + fb_def_var[index].height = vinfo->screen_real_height; + } + /* setup fb0 display size */ + if (index == DEV_OSD0) { + ret = of_property_read_u32_array(pdev->dev.of_node, + "display_size_default", + &var_screeninfo[0], 5); + if (ret) + osd_log_info("not found display_size_default\n"); + else { + fb_def_var[index].xres = var_screeninfo[0]; + fb_def_var[index].yres = var_screeninfo[1]; + fb_def_var[index].xres_virtual = + var_screeninfo[2]; + fb_def_var[index].yres_virtual = + var_screeninfo[3]; + fb_def_var[index].bits_per_pixel = + var_screeninfo[4]; + osd_log_info("init fbdev bpp is:%d\n", + fb_def_var[index].bits_per_pixel); + if (fb_def_var[index].bits_per_pixel > 32) + fb_def_var[index].bits_per_pixel = 32; + } + } + + _fbdev_set_default(fbdev, index); + if (fbdev->color == NULL) { + osd_log_err("fbdev->color NULL\n"); + ret = -ENOENT; + goto failed1; + } + bpp = (fbdev->color->color_index > 8 ? + (fbdev->color->color_index > 16 ? + (fbdev->color->color_index > 24 ? + 4 : 3) : 2) : 1); + fix->line_length = var->xres_virtual * bpp; + fix->smem_start = fbdev->fb_mem_paddr; + fix->smem_len = fbdev->fb_len; + if (fb_alloc_cmap(&fbi->cmap, 16, 0) != 0) { + osd_log_err("unable to allocate color map memory\n"); + ret = -ENOMEM; + goto failed2; + } + fbi->pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL); + if (!(fbi->pseudo_palette)) { + osd_log_err("unable to allocate pseudo palette mem\n"); + ret = -ENOMEM; + goto failed2; + } + memset(fbi->pseudo_palette, 0, sizeof(u32) * 16); + fbi->fbops = &osd_ops; + fbi->screen_base = (char __iomem *)fbdev->fb_mem_vaddr; + fbi->screen_size = fix->smem_len; + if (vinfo) + set_default_display_axis(&fbdev->fb_info->var, + &fbdev->osd_ctl, vinfo); + osd_check_var(var, fbi); + /* register frame buffer */ + register_framebuffer(fbi); + /* create device attribute files */ + for (i = 0; i < ARRAY_SIZE(osd_attrs); i++) + ret = device_create_file(fbi->dev, &osd_attrs[i]); + } +#ifdef CONFIG_HAS_EARLYSUSPEND + early_suspend.level = EARLY_SUSPEND_LEVEL_STOP_DRAWING; + early_suspend.suspend = osd_early_suspend; + early_suspend.resume = osd_late_resume; + register_early_suspend(&early_suspend); +#endif + + /* init osd reverse */ + if (osd_info.index == DEV_ALL) { + osd_set_reverse_hw(0, osd_info.osd_reverse); + osd_set_reverse_hw(1, osd_info.osd_reverse); + } else + osd_set_reverse_hw(osd_info.index, osd_info.osd_reverse); + + /* register vout client */ + vout_register_client(&osd_notifier_nb); + + osd_log_info("osd probe OK\n"); + return 0; +failed2: + fb_dealloc_cmap(&fbi->cmap); +failed1: + osd_log_err("osd probe failed.\n"); + return ret; +} + +static int osd_remove(struct platform_device *pdev) +{ + struct fb_info *fbi; + int i; + + osd_log_info("osd_remove.\n"); + if (!pdev) + return -ENODEV; +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&early_suspend); +#endif + vout_unregister_client(&osd_notifier_nb); + for (i = 0; i < OSD_COUNT; i++) { + int j; + + if (gp_fbdev_list[i]) { + struct osd_fb_dev_s *fbdev = gp_fbdev_list[i]; + + fbi = fbdev->fb_info; + for (j = 0; j < ARRAY_SIZE(osd_attrs); j++) + device_remove_file(fbi->dev, &osd_attrs[j]); + iounmap(fbdev->fb_mem_vaddr); + if (i == DEV_OSD0 && osd_get_afbc()) { + for (j = 1; j < OSD_MAX_BUF_NUM; j++) + iounmap(fbdev->fb_mem_afbc_vaddr[j]); + } + kfree(fbi->pseudo_palette); + fb_dealloc_cmap(&fbi->cmap); + unregister_framebuffer(fbi); + framebuffer_release(fbi); + } + } + return 0; +} + +static void osd_shutdown(struct platform_device *pdev) +{ + if (!osd_shutdown_flag) { + osd_shutdown_flag = 1; + osd_shutdown_hw(); + } +} + +/* Process kernel command line parameters */ +static int __init osd_setup_attribute(char *options) +{ + char *this_opt = NULL; + int r = 0; + unsigned long res; + + if (!options || !*options) + goto exit; + while (!r && (this_opt = strsep(&options, ",")) != NULL) { + if (!strncmp(this_opt, "xres:", 5)) { + r = kstrtol(this_opt + 5, 0, &res); + fb_def_var[0].xres = fb_def_var[0].xres_virtual = res; + } else if (!strncmp(this_opt, "yres:", 5)) { + r = kstrtol(this_opt + 5, 0, &res); + fb_def_var[0].yres = fb_def_var[0].yres_virtual = res; + } else { + osd_log_info("invalid option\n"); + r = -1; + } + } +exit: + return r; +} + +static int rmem_fb_device_init(struct reserved_mem *rmem, struct device *dev) +{ + return 0; +} + +static const struct reserved_mem_ops rmem_fb_ops = { + .device_init = rmem_fb_device_init, +}; + +static int __init rmem_fb_setup(struct reserved_mem *rmem) +{ + phys_addr_t align = PAGE_SIZE; + phys_addr_t mask = align - 1; + + if ((rmem->base & mask) || (rmem->size & mask)) { + pr_err("Reserved memory: incorrect alignment of region\n"); + return -EINVAL; + } + fb_rmem.base = rmem->base; + fb_rmem.size = rmem->size; + rmem->ops = &rmem_fb_ops; + osd_log_dbg("Reserved memory: created fb at 0x%p, size %ld MiB\n", + (void *)rmem->base, (unsigned long)rmem->size / SZ_1M); + return 0; +} +RESERVEDMEM_OF_DECLARE(fb, "amlogic, fb-memory", rmem_fb_setup); + +static const struct of_device_id meson_fb_dt_match[] = { + {.compatible = "amlogic, meson-fb",}, + {}, +}; + +#ifdef CONFIG_HIBERNATION +const struct dev_pm_ops osd_pm = { + .freeze = osd_freeze, + .thaw = osd_thaw, + .restore = osd_restore, + .suspend = osd_pm_suspend, + .resume = osd_pm_resume, +}; +#endif + +static struct platform_driver osd_driver = { + .probe = osd_probe, + .remove = osd_remove, + .shutdown = osd_shutdown, +#ifdef CONFIG_PM + .suspend = osd_suspend, + .resume = osd_resume, +#endif + .driver = { + .name = "meson-fb", + .of_match_table = meson_fb_dt_match, +#ifdef CONFIG_HIBERNATION + .pm = &osd_pm, +#endif + } +}; + +static int __init osd_init_module(void) +{ + char *option; + + osd_log_info("%s\n", __func__); + if (fb_get_options("meson-fb", &option)) { + osd_log_err("failed to get meson-fb options!\n"); + return -ENODEV; + } + osd_setup_attribute(option); + if (platform_driver_register(&osd_driver)) { + osd_log_err("failed to register OSD driver!\n"); + return -ENODEV; + } +#ifdef CONFIG_INSTABOOT + INIT_LIST_HEAD(&osd_realdata_ops.node); + register_instaboot_realdata_ops(&osd_realdata_ops); +#endif + return 0; +} + +static void __exit osd_exit_module(void) +{ + osd_log_info("%s\n", __func__); + platform_driver_unregister(&osd_driver); +} + +module_init(osd_init_module); +module_exit(osd_exit_module); + +MODULE_AUTHOR("Platform-BJ "); +MODULE_DESCRIPTION("OSD Module"); +MODULE_LICENSE("GPL"); diff --git a/drivers/amlogic/media/osd/osd_fb.h b/drivers/amlogic/media/osd/osd_fb.h new file mode 100644 index 000000000000..620ad7b9f48a --- /dev/null +++ b/drivers/amlogic/media/osd/osd_fb.h @@ -0,0 +1,78 @@ +/* + * drivers/amlogic/media/osd/osd_fb.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 _OSD_FB_H_ +#define _OSD_FB_H_ + +/* Linux Headers */ +#include +#include +#include + + +/* Local Headers */ +#include "osd.h" + +#ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD2_ENABLE +#define OSD_COUNT 2 /* enable two OSD layers */ +#else +#define OSD_COUNT 1 /* only enable one OSD layer */ +#endif + +#define INVALID_BPP_ITEM {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + +struct osd_fb_dev_s { + struct mutex lock; + struct fb_info *fb_info; + struct platform_device *dev; + phys_addr_t fb_mem_paddr; + void __iomem *fb_mem_vaddr; + u32 fb_len; + phys_addr_t fb_mem_afbc_paddr[OSD_MAX_BUF_NUM]; + void __iomem *fb_mem_afbc_vaddr[OSD_MAX_BUF_NUM]; + u32 fb_afbc_len[OSD_MAX_BUF_NUM]; + const struct color_bit_define_s *color; + enum vmode_e vmode; + struct osd_ctl_s osd_ctl; + u32 order; + u32 scale; + u32 enable_3d; + u32 preblend_enable; + u32 enable_key_flag; + u32 color_key; + u32 fb_index; + bool dis_osd_mchange; +}; + +struct fb_dmabuf_export { + __u32 buffer_idx; + __u32 fd; + __u32 flags; +}; + +#define OSD_INVALID_INFO 0xffffffff +#define OSD_FIRST_GROUP_START 1 +#define OSD_SECOND_GROUP_START 4 +#define OSD_END 7 + +extern phys_addr_t get_fb_rmem_paddr(int index); +extern void __iomem *get_fb_rmem_vaddr(int index); +extern size_t get_fb_rmem_size(int index); +extern int osd_blank(int blank_mode, struct fb_info *info); +extern struct osd_fb_dev_s *gp_fbdev_list[]; +extern const struct color_bit_define_s default_color_format_array[]; +#endif diff --git a/drivers/amlogic/media/osd/osd_hw.c b/drivers/amlogic/media/osd/osd_hw.c new file mode 100644 index 000000000000..5e87d4a33f6f --- /dev/null +++ b/drivers/amlogic/media/osd/osd_hw.c @@ -0,0 +1,3513 @@ +/* + * drivers/amlogic/media/osd/osd_hw.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. + * + */ + +/* Linux Headers */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* Android Headers */ + +/* Amlogic Headers */ +#include +#include +#include +#ifdef CONFIG_AMLOGIC_MEDIA_CANVAS +#include +#include +#endif +#ifdef CONFIG_AMLOGIC_VPU +#include +#endif +#ifdef CONFIG_AMLOGIC_VECM +#include +#endif + +#ifdef CONFIG_AMLOGIC_VIDEO +#include +#endif +/* Local Headers */ +#include "osd_canvas.h" +#include "osd_prot.h" +#include "osd_antiflicker.h" +#include "osd_clone.h" +#include "osd_log.h" +#include "osd_reg.h" +#include "osd_io.h" +#include "osd_backup.h" + +#include "osd_hw.h" +#include "osd_hw_def.h" + +#ifdef CONFIG_AMLOGIC_VSYNC_FIQ_ENABLE +#define FIQ_VSYNC +#endif +#define VOUT_ENCI 1 +#define VOUT_ENCP 2 +#define VOUT_ENCT 3 +#define OSD_TYPE_TOP_FIELD 0 +#define OSD_TYPE_BOT_FIELD 1 + +#define WAIT_AFBC_READY_COUNT 100 + +struct hw_para_s osd_hw; +static DEFINE_MUTEX(osd_mutex); +static DECLARE_WAIT_QUEUE_HEAD(osd_vsync_wq); + +static bool vsync_hit; +static bool osd_update_window_axis; +static int osd_afbc_dec_enable; +static void osd_clone_pan(u32 index, u32 yoffset, int debug_flag); + +#ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD_SYNC_FENCE +/* sync fence relative varible. */ +static int timeline_created; +static struct sw_sync_timeline *timeline; +static u32 cur_streamline_val; +/* thread control part */ +struct kthread_worker buffer_toggle_worker; +struct task_struct *buffer_toggle_thread; +struct kthread_work buffer_toggle_work; +struct list_head post_fence_list; +struct mutex post_fence_list_lock; +static void osd_pan_display_fence(struct osd_fence_map_s *fence_map); +#endif + +static int pxp_mode; + +static __nosavedata int use_h_filter_mode = -1; +static __nosavedata int use_v_filter_mode = -1; + +static unsigned int osd_h_filter_mode = 1; +module_param(osd_h_filter_mode, uint, 0664); +MODULE_PARM_DESC(osd_h_filter_mode, "osd_h_filter_mode"); + +static unsigned int osd_v_filter_mode = 1; +module_param(osd_v_filter_mode, uint, 0664); +MODULE_PARM_DESC(osd_v_filter_mode, "osd_v_filter_mode"); + +static unsigned int osd_auto_adjust_filter = 1; +module_param(osd_auto_adjust_filter, uint, 0664); +MODULE_PARM_DESC(osd_auto_adjust_filter, "osd_auto_adjust_filter"); + +static int osd_init_hw_flag; +static int osd_logo_index = 1; +module_param(osd_logo_index, int, 0664); +MODULE_PARM_DESC(osd_logo_index, "osd_logo_index"); + +module_param(osd_afbc_dec_enable, int, 0664); +MODULE_PARM_DESC(osd_afbc_dec_enable, "osd_afbc_dec_enable"); + +static u32 osd_vpp_misc; +static u32 osd_vpp_misc_mask = OSD_RELATIVE_BITS; +module_param(osd_vpp_misc, uint, 0444); +MODULE_PARM_DESC(osd_vpp_misc, "osd_vpp_misc"); + +static unsigned int osd_filter_coefs_bicubic_sharp[] = { + 0x01fa008c, 0x01fa0100, 0xff7f0200, 0xfe7f0300, + 0xfd7e0500, 0xfc7e0600, 0xfb7d0800, 0xfb7c0900, + 0xfa7b0b00, 0xfa7a0dff, 0xf9790fff, 0xf97711ff, + 0xf87613ff, 0xf87416fe, 0xf87218fe, 0xf8701afe, + 0xf76f1dfd, 0xf76d1ffd, 0xf76b21fd, 0xf76824fd, + 0xf76627fc, 0xf76429fc, 0xf7612cfc, 0xf75f2ffb, + 0xf75d31fb, 0xf75a34fb, 0xf75837fa, 0xf7553afa, + 0xf8523cfa, 0xf8503ff9, 0xf84d42f9, 0xf84a45f9, + 0xf84848f8 +}; + +static unsigned int osd_filter_coefs_bicubic[] = { /* bicubic coef0 */ + 0x00800000, 0x007f0100, 0xff7f0200, 0xfe7f0300, 0xfd7e0500, 0xfc7e0600, + 0xfb7d0800, 0xfb7c0900, 0xfa7b0b00, 0xfa7a0dff, 0xf9790fff, 0xf97711ff, + 0xf87613ff, 0xf87416fe, 0xf87218fe, 0xf8701afe, 0xf76f1dfd, 0xf76d1ffd, + 0xf76b21fd, 0xf76824fd, 0xf76627fc, 0xf76429fc, 0xf7612cfc, 0xf75f2ffb, + 0xf75d31fb, 0xf75a34fb, 0xf75837fa, 0xf7553afa, 0xf8523cfa, 0xf8503ff9, + 0xf84d42f9, 0xf84a45f9, 0xf84848f8 +}; + +static unsigned int osd_filter_coefs_bilinear[] = { /* 2 point bilinear coef1 */ + 0x00800000, 0x007e0200, 0x007c0400, 0x007a0600, 0x00780800, 0x00760a00, + 0x00740c00, 0x00720e00, 0x00701000, 0x006e1200, 0x006c1400, 0x006a1600, + 0x00681800, 0x00661a00, 0x00641c00, 0x00621e00, 0x00602000, 0x005e2200, + 0x005c2400, 0x005a2600, 0x00582800, 0x00562a00, 0x00542c00, 0x00522e00, + 0x00503000, 0x004e3200, 0x004c3400, 0x004a3600, 0x00483800, 0x00463a00, + 0x00443c00, 0x00423e00, 0x00404000 +}; + +static unsigned int osd_filter_coefs_2point_binilear[] = { + /* 2 point bilinear, bank_length == 2 coef2 */ + 0x80000000, 0x7e020000, 0x7c040000, 0x7a060000, 0x78080000, 0x760a0000, + 0x740c0000, 0x720e0000, 0x70100000, 0x6e120000, 0x6c140000, 0x6a160000, + 0x68180000, 0x661a0000, 0x641c0000, 0x621e0000, 0x60200000, 0x5e220000, + 0x5c240000, 0x5a260000, 0x58280000, 0x562a0000, 0x542c0000, 0x522e0000, + 0x50300000, 0x4e320000, 0x4c340000, 0x4a360000, 0x48380000, 0x463a0000, + 0x443c0000, 0x423e0000, 0x40400000 +}; + +/* filt_triangle, point_num =3, filt_len =2.6, group_num = 64 */ +static unsigned int osd_filter_coefs_3point_triangle_sharp[] = { + 0x40400000, 0x3e420000, 0x3d430000, 0x3b450000, + 0x3a460000, 0x38480000, 0x37490000, 0x354b0000, + 0x344c0000, 0x324e0000, 0x314f0000, 0x2f510000, + 0x2e520000, 0x2c540000, 0x2b550000, 0x29570000, + 0x28580000, 0x265a0000, 0x245c0000, 0x235d0000, + 0x215f0000, 0x20600000, 0x1e620000, 0x1d620100, + 0x1b620300, 0x19630400, 0x17630600, 0x15640700, + 0x14640800, 0x12640a00, 0x11640b00, 0x0f650c00, + 0x0d660d00 +}; + +static unsigned int osd_filter_coefs_3point_triangle[] = { + 0x40400000, 0x3f400100, 0x3d410200, 0x3c410300, + 0x3a420400, 0x39420500, 0x37430600, 0x36430700, + 0x35430800, 0x33450800, 0x32450900, 0x31450a00, + 0x30450b00, 0x2e460c00, 0x2d460d00, 0x2c470d00, + 0x2b470e00, 0x29480f00, 0x28481000, 0x27481100, + 0x26491100, 0x25491200, 0x24491300, 0x234a1300, + 0x224a1400, 0x214a1500, 0x204a1600, 0x1f4b1600, + 0x1e4b1700, 0x1d4b1800, 0x1c4c1800, 0x1b4c1900, + 0x1a4c1a00 +}; + +static unsigned int osd_filter_coefs_4point_triangle[] = { + 0x20402000, 0x20402000, 0x1f3f2101, 0x1f3f2101, + 0x1e3e2202, 0x1e3e2202, 0x1d3d2303, 0x1d3d2303, + 0x1c3c2404, 0x1c3c2404, 0x1b3b2505, 0x1b3b2505, + 0x1a3a2606, 0x1a3a2606, 0x19392707, 0x19392707, + 0x18382808, 0x18382808, 0x17372909, 0x17372909, + 0x16362a0a, 0x16362a0a, 0x15352b0b, 0x15352b0b, + 0x14342c0c, 0x14342c0c, 0x13332d0d, 0x13332d0d, + 0x12322e0e, 0x12322e0e, 0x11312f0f, 0x11312f0f, + 0x10303010 +}; + +/* 4th order (cubic) b-spline */ +/* filt_cubic point_num =4, filt_len =4, group_num = 64 */ +static unsigned int vpp_filter_coefs_4point_bspline[] = { + 0x15561500, 0x14561600, 0x13561700, 0x12561800, + 0x11551a00, 0x11541b00, 0x10541c00, 0x0f541d00, + 0x0f531e00, 0x0e531f00, 0x0d522100, 0x0c522200, + 0x0b522300, 0x0b512400, 0x0a502600, 0x0a4f2700, + 0x094e2900, 0x084e2a00, 0x084d2b00, 0x074c2c01, + 0x074b2d01, 0x064a2f01, 0x06493001, 0x05483201, + 0x05473301, 0x05463401, 0x04453601, 0x04433702, + 0x04423802, 0x03413a02, 0x03403b02, 0x033f3c02, + 0x033d3d03 +}; + +/* filt_quadratic, point_num =3, filt_len =3, group_num = 64 */ +static unsigned int osd_filter_coefs_3point_bspline[] = { + 0x40400000, 0x3e420000, 0x3c440000, 0x3a460000, + 0x38480000, 0x364a0000, 0x344b0100, 0x334c0100, + 0x314e0100, 0x304f0100, 0x2e500200, 0x2c520200, + 0x2a540200, 0x29540300, 0x27560300, 0x26570300, + 0x24580400, 0x23590400, 0x215a0500, 0x205b0500, + 0x1e5c0600, 0x1d5c0700, 0x1c5d0700, 0x1a5e0800, + 0x195e0900, 0x185e0a00, 0x175f0a00, 0x15600b00, + 0x14600c00, 0x13600d00, 0x12600e00, 0x11600f00, + 0x10601000 +}; + +static unsigned int *filter_table[] = { + osd_filter_coefs_bicubic_sharp, + osd_filter_coefs_bicubic, + osd_filter_coefs_bilinear, + osd_filter_coefs_2point_binilear, + osd_filter_coefs_3point_triangle_sharp, + osd_filter_coefs_3point_triangle, + osd_filter_coefs_4point_triangle, + vpp_filter_coefs_4point_bspline, + osd_filter_coefs_3point_bspline +}; + +#ifdef CONFIG_AMLOGIC_VECM +static bool osd_hdr_on; +#endif + +static void osd_vpu_power_on(void) +{ +#ifdef CONFIG_AMLOGIC_VPU + switch_vpu_mem_pd_vmod(VPU_VIU_OSD1, VPU_MEM_POWER_ON); + switch_vpu_mem_pd_vmod(VPU_VIU_OSD2, VPU_MEM_POWER_ON); + switch_vpu_mem_pd_vmod(VPU_VIU_OSD_SCALE, VPU_MEM_POWER_ON); + if ((get_cpu_type() == MESON_CPU_MAJOR_ID_GXTVBB) || + (get_cpu_type() == MESON_CPU_MAJOR_ID_GXM)) { + switch_vpu_mem_pd_vmod(VPU_AFBC_DEC, + VPU_MEM_POWER_ON); + } +#endif +} + +#ifdef CONFIG_AMLOGIC_SUPERSCALER +static void osd_super_scale_mem_power_on(void) +{ +#ifdef CONFIG_AMLOGIC_VPU + switch_vpu_mem_pd_vmod(VPU_VIU_OSDSR, VPU_MEM_POWER_ON); +#endif +} + +static void osd_super_scale_mem_power_off(void) +{ +#ifdef CONFIG_AMLOGIC_VPU + switch_vpu_mem_pd_vmod(VPU_VIU_OSDSR, VPU_MEM_POWER_DOWN); +#endif +} +#endif + +#ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD_SYNC_FENCE +static inline int find_buf_num(u32 yres, u32 yoffset) +{ + int n = yres; + int i; + + for (i = 0; i < OSD_MAX_BUF_NUM; i++) { + /* find current addr position. */ + if (yoffset < (n)) + break; + n += yres; + } + return i; +} + +/* next we will process two osd layer in toggle buffer. */ +static void osd_toggle_buffer(struct kthread_work *work) +{ + struct osd_fence_map_s *data, *next; + struct list_head saved_list; + + mutex_lock(&post_fence_list_lock); + saved_list = post_fence_list; + list_replace_init(&post_fence_list, &saved_list); + mutex_unlock(&post_fence_list_lock); + list_for_each_entry_safe(data, next, &saved_list, list) { + osd_pan_display_fence(data); + if (data->in_fence) + sync_fence_put(data->in_fence); + if (data->in_fd > 0) + __close_fd(data->files, data->in_fd); + list_del(&data->list); + kfree(data); + } +} + +static int out_fence_create(int *release_fence_fd, u32 *val, u32 buf_num) +{ + /* the first time create out_fence_fd==0 */ + /* sw_sync_timeline_inc will release fence and it's sync point */ + struct sync_pt *outer_sync_pt; + struct sync_fence *outer_fence; + int out_fence_fd = -1; + + out_fence_fd = get_unused_fd_flags(O_CLOEXEC); + /* no file descriptor could be used. Error. */ + if (out_fence_fd < 0) + return -1; + if (!timeline_created) { /* timeline has not been created */ + timeline = sw_sync_timeline_create("osd_timeline"); + cur_streamline_val = 1; + if (timeline == NULL) + return -1; + init_kthread_worker(&buffer_toggle_worker); + buffer_toggle_thread = kthread_run(kthread_worker_fn, + &buffer_toggle_worker, "aml_buf_toggle"); + init_kthread_work(&buffer_toggle_work, osd_toggle_buffer); + timeline_created = 1; + } + /* install fence map; first ,the simplest. */ + cur_streamline_val++; + *val = cur_streamline_val; + outer_sync_pt = sw_sync_pt_create(timeline, *val); + if (outer_sync_pt == NULL) + goto error_ret; + /* fence object will be released when no point */ + outer_fence = sync_fence_create("osd_fence_out", outer_sync_pt); + if (outer_fence == NULL) { + sync_pt_free(outer_sync_pt); /* free sync point. */ + goto error_ret; + } + sync_fence_install(outer_fence, out_fence_fd); + *release_fence_fd = out_fence_fd; + return out_fence_fd; + +error_ret: + cur_streamline_val--; /* pt or fence fail,restore timeline value. */ + osd_log_err("fence obj create fail\n"); + put_unused_fd(out_fence_fd); + return -1; +} + +int osd_sync_request(u32 index, u32 yres, u32 xoffset, u32 yoffset, + s32 in_fence_fd) +{ + int out_fence_fd = -1; + int buf_num = 0; + struct osd_fence_map_s *fence_map = + kzalloc(sizeof(struct osd_fence_map_s), GFP_KERNEL); + + buf_num = find_buf_num(yres, yoffset); + if (!fence_map) { + osd_log_err("could not allocate osd_fence_map\n"); + return -ENOMEM; + } + mutex_lock(&post_fence_list_lock); + fence_map->fb_index = index; + fence_map->buf_num = buf_num; + fence_map->yoffset = yoffset; + fence_map->xoffset = xoffset; + fence_map->yres = yres; + fence_map->in_fd = in_fence_fd; + fence_map->in_fence = sync_fence_fdget(in_fence_fd); + fence_map->files = current->files; + fence_map->out_fd = + out_fence_create(&out_fence_fd, &fence_map->val, buf_num); + list_add_tail(&fence_map->list, &post_fence_list); + mutex_unlock(&post_fence_list_lock); + queue_kthread_work(&buffer_toggle_worker, &buffer_toggle_work); + + return out_fence_fd; +} + +static int osd_wait_buf_ready(struct osd_fence_map_s *fence_map) +{ + s32 ret = -1; + struct sync_fence *buf_ready_fence = NULL; + + if (fence_map->in_fd <= 0) { + ret = -1; + return ret; + } + buf_ready_fence = fence_map->in_fence; + if (buf_ready_fence == NULL) { + ret = -1;/* no fence ,output directly. */ + return ret; + } + ret = sync_fence_wait(buf_ready_fence, -1); + if (ret < 0) { + osd_log_err("Sync Fence wait error:%d\n", ret); + osd_log_err("-----wait buf idx:[%d] ERROR\n" + "-----on screen buf idx:[%d]\n", + fence_map->buf_num, find_buf_num(fence_map->yres, + osd_hw.pandata[fence_map->fb_index].y_start)); + } else + ret = 1; + return ret; +} + +#else +int osd_sync_request(u32 index, u32 yres, u32 xoffset, u32 yoffset, + s32 in_fence_fd) +{ + osd_log_err("osd_sync_request not supported\n"); + return -5566; +} +#endif + +void osd_update_3d_mode(void) +{ + /* only called by vsync irq or rdma irq */ + if (osd_hw.mode_3d[OSD1].enable) + osd1_update_disp_3d_mode(); + if (osd_hw.mode_3d[OSD2].enable) + osd2_update_disp_3d_mode(); +} + +static inline void wait_vsync_wakeup(void) +{ + vsync_hit = true; + wake_up_interruptible(&osd_vsync_wq); +} + +void osd_update_vsync_hit(void) +{ + if (!vsync_hit) { +#ifdef FIQ_VSYNC + fiq_bridge_pulse_trigger(&osd_hw.fiq_handle_item); +#else + wait_vsync_wakeup(); +#endif + } +} + +static void osd_update_interlace_mode(void) +{ + /* only called by vsync irq or rdma irq */ + unsigned int fb0_cfg_w0, fb1_cfg_w0; + unsigned int scan_line_number = 0; + unsigned int odd_even; + + spin_lock_irqsave(&osd_lock, lock_flags); + fb0_cfg_w0 = VSYNCOSD_RD_MPEG_REG(VIU_OSD1_BLK0_CFG_W0); + fb1_cfg_w0 = VSYNCOSD_RD_MPEG_REG(VIU_OSD2_BLK0_CFG_W0); + if (osd_reg_read(ENCP_VIDEO_MODE) & (1 << 12)) { + /* 1080I */ + scan_line_number = ((osd_reg_read(ENCP_INFO_READ)) + & 0x1fff0000) >> 16; + if ((osd_hw.pandata[OSD1].y_start % 2) == 0) { + if (scan_line_number >= 562) { + /* bottom field, odd lines*/ + odd_even = OSD_TYPE_BOT_FIELD; + } else { + /* top field, even lines*/ + odd_even = OSD_TYPE_TOP_FIELD; + } + } else { + if (scan_line_number >= 562) { + /* top field, even lines*/ + odd_even = OSD_TYPE_TOP_FIELD; + } else { + /* bottom field, odd lines*/ + odd_even = OSD_TYPE_BOT_FIELD; + } + } + } else { + if ((osd_hw.pandata[OSD1].y_start % 2) == 1) { + odd_even = (osd_reg_read(ENCI_INFO_READ) & (1 << 29)) ? + OSD_TYPE_TOP_FIELD : OSD_TYPE_BOT_FIELD; + } else { + odd_even = (osd_reg_read(ENCI_INFO_READ) & (1 << 29)) ? + OSD_TYPE_BOT_FIELD : OSD_TYPE_TOP_FIELD; + } + } +#ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD_VSYNC_RDMA + /* when RDMA enabled, top/bottom fields changed in next vsync */ + odd_even = (odd_even == OSD_TYPE_TOP_FIELD) ? + OSD_TYPE_BOT_FIELD : OSD_TYPE_TOP_FIELD; +#endif + fb0_cfg_w0 &= ~1; + fb1_cfg_w0 &= ~1; + fb0_cfg_w0 |= odd_even; + fb1_cfg_w0 |= odd_even; + VSYNCOSD_IRQ_WR_MPEG_REG(VIU_OSD1_BLK0_CFG_W0, fb0_cfg_w0); + VSYNCOSD_IRQ_WR_MPEG_REG(VIU_OSD2_BLK0_CFG_W0, fb1_cfg_w0); + spin_unlock_irqrestore(&osd_lock, lock_flags); +} + +void osd_update_scan_mode(void) +{ + /* only called by vsync irq or rdma irq */ + unsigned int output_type = 0; + + output_type = osd_reg_read(VPU_VIU_VENC_MUX_CTRL) & 0x3; + osd_hw.scan_mode = SCAN_MODE_PROGRESSIVE; + switch (output_type) { + case VOUT_ENCP: + if (osd_reg_read(ENCP_VIDEO_MODE) & (1 << 12)) /* 1080i */ + osd_hw.scan_mode = SCAN_MODE_INTERLACE; + break; + case VOUT_ENCI: + if (osd_reg_read(ENCI_VIDEO_EN) & 1) + osd_hw.scan_mode = SCAN_MODE_INTERLACE; + break; + } + if (osd_hw.free_scale_enable[OSD1]) + osd_hw.scan_mode = SCAN_MODE_PROGRESSIVE; + if (osd_hw.osd_afbcd[OSD1].enable) + osd_hw.scan_mode = SCAN_MODE_PROGRESSIVE; + if (osd_hw.scan_mode == SCAN_MODE_INTERLACE) + osd_update_interlace_mode(); +} + +static inline void walk_through_update_list(void) +{ + u32 i, j; + + for (i = 0; i < HW_OSD_COUNT; i++) { + j = 0; + while (osd_hw.updated[i] && j < 32) { + if (osd_hw.updated[i] & (1 << j)) { + osd_hw.reg[i][j].update_func(); + remove_from_update_list(i, j); + } + j++; + } + } +} + +/*************** for GXL/GXM hardware alpha bug workaround ***************/ +u32 osd_get_hw_reset_flag(void) +{ + u32 hw_reset_flag = HW_RESET_NONE; + u32 cpu_type; + + cpu_type = get_cpu_type(); + /* check hw version */ + switch (cpu_type) { + case MESON_CPU_MAJOR_ID_GXTVBB: + if (osd_hw.osd_afbcd[OSD1].enable) + hw_reset_flag |= HW_RESET_AFBCD_REGS; + break; + case MESON_CPU_MAJOR_ID_GXM: + /* same bit, but gxm only reset hardware, not top reg*/ + if (osd_hw.osd_afbcd[OSD1].enable) + hw_reset_flag |= HW_RESET_AFBCD_HARDWARE; +#ifndef CONFIG_AMLOGIC_VECM + break; +#else + case MESON_CPU_MAJOR_ID_GXL: + case MESON_CPU_MAJOR_ID_TXL: + if (((hdr_osd_reg.viu_osd1_matrix_ctrl & 0x00000001) + != 0x0) || + ((hdr_osd_reg.viu_osd1_eotf_ctl & 0x80000000) + != 0) || + ((hdr_osd_reg.viu_osd1_oetf_ctl & 0xe0000000) + != 0)) { + hw_reset_flag |= HW_RESET_OSD1_REGS; + osd_hdr_on = true; + } else if (osd_hdr_on) { + hw_reset_flag |= HW_RESET_OSD1_REGS; + osd_hdr_on = false; + } + break; +#endif + default: + hw_reset_flag = HW_RESET_NONE; + break; + } + return hw_reset_flag; +} + +void osd_hw_reset(void) +{ + /* only called by vsync irq or rdma irq */ + u32 backup_mask; + u32 reset_bit = + osd_get_hw_reset_flag(); + + backup_mask = is_backup(); + osd_hw.hw_reset_flag = reset_bit; + if (reset_bit == HW_RESET_NONE) + return; + spin_lock_irqsave(&osd_lock, lock_flags); + if ((reset_bit & HW_RESET_OSD1_REGS) + && !(backup_mask & HW_RESET_OSD1_REGS)) + reset_bit &= ~HW_RESET_OSD1_REGS; + + if ((get_cpu_type() == MESON_CPU_MAJOR_ID_GXTVBB) + && (reset_bit & HW_RESET_AFBCD_REGS) + && !(backup_mask & HW_RESET_AFBCD_REGS)) + reset_bit &= ~HW_RESET_AFBCD_REGS; + +#ifndef CONFIG_AMLOGIC_MEDIA_FB_OSD_VSYNC_RDMA + /* if not osd rdma, don't reset osd1 for hdr */ + reset_bit &= ~HW_RESET_OSD1_REGS; + backup_mask &= ~HW_RESET_OSD1_REGS; + + VSYNCOSD_IRQ_WR_MPEG_REG( + VIU_SW_RESET, reset_bit); + VSYNCOSD_IRQ_WR_MPEG_REG( + VIU_SW_RESET, 0); + + if (reset_bit & HW_RESET_OSD1_REGS) { + /* restore osd regs */ + int i; + u32 addr; + u32 base = VIU_OSD1_CTRL_STAT; + + for (i = 0; i < OSD_REG_BACKUP_COUNT; i++) { + addr = osd_reg_backup[i]; + VSYNCOSD_IRQ_WR_MPEG_REG( + addr, osd_backup[addr - base]); + } + } + + if ((get_cpu_type() == MESON_CPU_MAJOR_ID_GXTVBB) + && (reset_bit & HW_RESET_AFBCD_REGS)) { + /* restore osd afbcd regs */ + int i; + u32 addr; + u32 value; + u32 base = OSD1_AFBCD_ENABLE; + + for (i = 0; i < OSD_AFBC_REG_BACKUP_COUNT; i++) { + addr = osd_afbc_reg_backup[i]; + value = osd_afbc_backup[addr - base]; + if (addr == OSD1_AFBCD_ENABLE) + value |= 0x100; + VSYNCOSD_IRQ_WR_MPEG_REG( + addr, value); + } + } +#else + osd_rdma_reset_and_flush(reset_bit); +#endif + spin_unlock_irqrestore(&osd_lock, lock_flags); + /* maybe change reset bit */ + osd_hw.hw_reset_flag = reset_bit; +} + +static int notify_to_amvideo(void) +{ + u32 para[2]; + + para[0] = osd_vpp_misc; + para[1] = osd_vpp_misc_mask; + pr_debug( + "osd notify_to_amvideo vpp misc:0x%08x, mask:0x%08x\n", + para[0], para[1]); +#ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD_VSYNC_RDMA +#ifdef CONFIG_AMLOGIC_VIDEO + amvideo_notifier_call_chain( + AMVIDEO_UPDATE_OSD_MODE, + (void *)¶[0]); +#endif +#endif + return 0; +} +/*************** end of GXL/GXM hardware alpha bug workaround ***************/ + +#ifdef FIQ_VSYNC +static irqreturn_t vsync_isr(int irq, void *dev_id) +{ + wait_vsync_wakeup(); + return IRQ_HANDLED; +} + +static void osd_fiq_isr(void) +#else +static irqreturn_t vsync_isr(int irq, void *dev_id) +#endif +{ +#ifndef CONFIG_AMLOGIC_MEDIA_FB_OSD_VSYNC_RDMA + osd_update_scan_mode(); + /* go through update list */ + walk_through_update_list(); + osd_update_3d_mode(); + osd_update_vsync_hit(); + osd_hw_reset(); +#else + osd_rdma_interrupt_done_clear(); +#endif +#ifndef FIQ_VSYNC + return IRQ_HANDLED; +#endif +} + + +void osd_set_pxp_mode(u32 mode) +{ + pxp_mode = mode; +} +void osd_set_afbc(u32 enable) +{ + if ((get_cpu_type() == MESON_CPU_MAJOR_ID_GXTVBB) || + (get_cpu_type() == MESON_CPU_MAJOR_ID_GXM)) + osd_hw.osd_afbcd[OSD1].enable = enable; +} + +u32 osd_get_afbc(void) +{ + return osd_hw.osd_afbcd[OSD1].enable; +} + +u32 osd_get_reset_status(void) +{ + return osd_hw.hw_reset_flag; +} + +void osd_wait_vsync_hw(void) +{ + unsigned long timeout; + + vsync_hit = false; + + if (pxp_mode) + timeout = msecs_to_jiffies(50); + else + timeout = HZ; + wait_event_interruptible_timeout(osd_vsync_wq, vsync_hit, timeout); +} + +s32 osd_wait_vsync_event(void) +{ + vsync_hit = false; + /* waiting for 10ms. */ + wait_event_interruptible_timeout(osd_vsync_wq, vsync_hit, 1); + + return 0; +} + +static int is_interlaced(struct vinfo_s *vinfo) +{ + if (vinfo->mode == VMODE_CVBS) + return 1; + if (vinfo->height != vinfo->field_height) + return 1; + else + return 0; +} + + +int osd_set_scan_mode(u32 index) +{ + struct vinfo_s *vinfo; + u32 data32 = 0x0; + int real_scan_mode; + s32 y_end = 0; + + osd_hw.scan_mode = SCAN_MODE_PROGRESSIVE; + vinfo = get_current_vinfo(); + if (vinfo) { + osd_hw.scale_workaround = 0; + if (osd_auto_adjust_filter) { + osd_h_filter_mode = 1; + osd_v_filter_mode = 1; + } + if (is_interlaced(vinfo)) { + osd_hw.scan_mode = real_scan_mode = SCAN_MODE_INTERLACE; + y_end = osd_hw.free_src_data[index].y_end; + if ((vinfo->width == 720) + && (vinfo->height == 480)) { + if (osd_hw.free_scale_mode[index]) { + osd_hw.field_out_en = 1; + switch (y_end) { + case 719: + osd_hw.bot_type = 2; + break; + case 1079: + osd_hw.bot_type = 3; + break; + default: + osd_hw.bot_type = 2; + break; + } + } + if (osd_auto_adjust_filter) { + osd_h_filter_mode = 6; + osd_v_filter_mode = 6; + } + } else if ((vinfo->width == 720) + && (vinfo->height == 576)) { + if (osd_hw.free_scale_mode[index]) { + osd_hw.field_out_en = 1; + switch (y_end) { + case 719: + osd_hw.bot_type = 2; + break; + case 1079: + osd_hw.bot_type = 2; + break; + default: + osd_hw.bot_type = 2; + break; + } + } + if (osd_auto_adjust_filter) { + osd_h_filter_mode = 6; + osd_v_filter_mode = 6; + } + + } else if ((vinfo->width == 1920) + && (vinfo->height == 1080)) { + if (osd_hw.free_scale_mode[index]) { + osd_hw.field_out_en = 1; + switch (y_end) { + case 719: + osd_hw.bot_type = 1; + break; + case 1079: + osd_hw.bot_type = 2; + break; + default: + osd_hw.bot_type = 1; + break; + } + } + } + } else { + if (((vinfo->width == 3840) + && (vinfo->height == 2160)) + || ((vinfo->width == 4096) + && (vinfo->height == 2160))) { + if ((osd_hw.fb_for_4k2k) + && (osd_hw.free_scale_enable[index])) + if (!(is_meson_gxtvbb_cpu() || + is_meson_gxm_cpu())) + osd_hw.scale_workaround = 1; + osd_hw.field_out_en = 0; + } else if (((vinfo->width == 720) + && (vinfo->height == 480)) + || ((vinfo->width == 720) + && (vinfo->height == 576))) { + if (osd_auto_adjust_filter) { + osd_h_filter_mode = 6; + osd_v_filter_mode = 6; + } + if (osd_hw.free_scale_mode[index]) + osd_hw.field_out_en = 0; + } else { + if (osd_hw.free_scale_mode[index]) + osd_hw.field_out_en = 0; + } + } + } + if (osd_hw.free_scale_enable[index]) + osd_hw.scan_mode = SCAN_MODE_PROGRESSIVE; + if (osd_hw.osd_afbcd[OSD1].enable) + osd_hw.scan_mode = SCAN_MODE_PROGRESSIVE; + if (index == OSD2) { + if (real_scan_mode == SCAN_MODE_INTERLACE) + return 1; + data32 = (VSYNCOSD_RD_MPEG_REG(VIU_OSD2_BLK0_CFG_W0) & 3) >> 1; + } else + data32 = (VSYNCOSD_RD_MPEG_REG(VIU_OSD1_BLK0_CFG_W0) & 3) >> 1; + if (data32 == osd_hw.scan_mode) + return 1; + else + return 0; +} + +void osd_set_gbl_alpha_hw(u32 index, u32 gbl_alpha) +{ + /* normalized */ + if (gbl_alpha == 0xff) + gbl_alpha = 0x100; + if (osd_hw.gbl_alpha[index] != gbl_alpha) { + osd_hw.gbl_alpha[index] = gbl_alpha; + add_to_update_list(index, OSD_GBL_ALPHA); + osd_wait_vsync_hw(); + } +} + +u32 osd_get_gbl_alpha_hw(u32 index) +{ + return osd_hw.gbl_alpha[index]; +} + +void osd_set_color_key_hw(u32 index, u32 color_index, u32 colorkey) +{ + u8 r = 0, g = 0, b = 0, a = (colorkey & 0xff000000) >> 24; + u32 data32; + + colorkey &= 0x00ffffff; + switch (color_index) { + case COLOR_INDEX_16_655: + r = (colorkey >> 10 & 0x3f) << 2; + g = (colorkey >> 5 & 0x1f) << 3; + b = (colorkey & 0x1f) << 3; + break; + case COLOR_INDEX_16_844: + r = colorkey >> 8 & 0xff; + g = (colorkey >> 4 & 0xf) << 4; + b = (colorkey & 0xf) << 4; + break; + case COLOR_INDEX_16_565: + r = (colorkey >> 11 & 0x1f) << 3; + g = (colorkey >> 5 & 0x3f) << 2; + b = (colorkey & 0x1f) << 3; + break; + case COLOR_INDEX_24_888_B: + b = colorkey >> 16 & 0xff; + g = colorkey >> 8 & 0xff; + r = colorkey & 0xff; + break; + case COLOR_INDEX_24_RGB: + case COLOR_INDEX_YUV_422: + r = colorkey >> 16 & 0xff; + g = colorkey >> 8 & 0xff; + b = colorkey & 0xff; + break; + } + data32 = r << 24 | g << 16 | b << 8 | a; + if (osd_hw.color_key[index] != data32) { + osd_hw.color_key[index] = data32; + osd_log_dbg2("bpp:%d--r:0x%x g:0x%x b:0x%x ,a:0x%x\n", + color_index, r, g, b, a); + add_to_update_list(index, OSD_COLOR_KEY); + osd_wait_vsync_hw(); + } +} +void osd_srckey_enable_hw(u32 index, u8 enable) +{ + if (enable != osd_hw.color_key_enable[index]) { + osd_hw.color_key_enable[index] = enable; + add_to_update_list(index, OSD_COLOR_KEY_ENABLE); + osd_wait_vsync_hw(); + } +} + +void osd_set_color_mode(u32 index, const struct color_bit_define_s *color) +{ + if (color != osd_hw.color_info[index]) { + osd_hw.color_info[index] = color; + add_to_update_list(index, OSD_COLOR_MODE); + } +} + +void osd_update_disp_axis_hw( + u32 index, + u32 display_h_start, + u32 display_h_end, + u32 display_v_start, + u32 display_v_end, + u32 xoffset, + u32 yoffset, + u32 mode_change) +{ + struct pandata_s disp_data; + struct pandata_s pan_data; + + if (index == OSD2) + return; + + if (osd_hw.color_info[index] == NULL) + return; + disp_data.x_start = display_h_start; + disp_data.y_start = display_v_start; + disp_data.x_end = display_h_end; + disp_data.y_end = display_v_end; + pan_data.x_start = xoffset; + pan_data.x_end = xoffset + (display_h_end - display_h_start); +#ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD_SYNC_FENCE + pan_data.y_start = osd_hw.pandata[index].y_start; + pan_data.y_end = osd_hw.pandata[index].y_start + + (display_v_end - display_v_start); +#else + pan_data.y_start = yoffset; + pan_data.y_end = yoffset + (display_v_end - display_v_start); +#endif + /* if output mode change then reset pan ofFfset. */ + memcpy(&osd_hw.pandata[index], &pan_data, sizeof(struct pandata_s)); + memcpy(&osd_hw.dispdata[index], &disp_data, sizeof(struct pandata_s)); + spin_lock_irqsave(&osd_lock, lock_flags); + if (mode_change) /* modify pandata . */ + osd_hw.reg[index][OSD_COLOR_MODE].update_func(); + osd_hw.reg[index][DISP_GEOMETRY].update_func(); + spin_unlock_irqrestore(&osd_lock, lock_flags); + osd_wait_vsync_hw(); +} + +void osd_setup_hw(u32 index, + struct osd_ctl_s *osd_ctl, + u32 xoffset, + u32 yoffset, + u32 xres, + u32 yres, + u32 xres_virtual, + u32 yres_virtual, + u32 disp_start_x, + u32 disp_start_y, + u32 disp_end_x, + u32 disp_end_y, + u32 fbmem, + phys_addr_t *afbc_fbmem, + const struct color_bit_define_s *color) +{ + struct pandata_s disp_data; + struct pandata_s pan_data; + int update_color_mode = 0; + int update_geometry = 0; + u32 w = (color->bpp * xres_virtual + 7) >> 3; + u32 i; + + pan_data.x_start = xoffset; + pan_data.y_start = yoffset; + disp_data.x_start = disp_start_x; + disp_data.y_start = disp_start_y; + if (likely(osd_hw.free_scale_enable[OSD1] && index == OSD1)) { + if (!(osd_hw.free_scale_mode[OSD1])) { + osd_log_info( + "osd[%d] osd_setup_hw scale mode is error %d\n", + index, osd_hw.free_scale_mode[OSD1]); + } else { + pan_data.x_end = xoffset + (disp_end_x - disp_start_x); + pan_data.y_end = yoffset + (disp_end_y - disp_start_y); + disp_data.x_end = disp_end_x; + disp_data.y_end = disp_end_y; + } + } else { + pan_data.x_end = xoffset + (disp_end_x - disp_start_x); + pan_data.y_end = yoffset + (disp_end_y - disp_start_y); + disp_data.x_end = disp_end_x; + disp_data.y_end = disp_end_y; + } + if (osd_hw.fb_gem[index].addr != fbmem + || osd_hw.fb_gem[index].width != w + || osd_hw.fb_gem[index].height != yres_virtual) { + osd_hw.fb_gem[index].addr = fbmem; + osd_hw.fb_gem[index].width = w; + osd_hw.fb_gem[index].height = yres_virtual; + if (index == OSD1 && + osd_hw.osd_afbcd[OSD1].enable == ENABLE && + afbc_fbmem != NULL) { + osd_hw.osd_afbcd[index].frame_width = xres; + /* osd_hw.osd_afbcd[index].frame_height = + * ALIGN_CALC(yres, 16) + + * ALIGN_CALC(yres, 64) / 64; + */ + osd_hw.osd_afbcd[index].frame_height = yres; + for (i = 0; i < OSD_MAX_BUF_NUM; i++) + osd_hw.osd_afbcd[index].addr[i] = + (u32)afbc_fbmem[i]; + if (pxp_mode) + osd_hw.osd_afbcd[index].phy_addr = + osd_hw.osd_afbcd[index].addr[0]; + else + osd_hw.osd_afbcd[index].phy_addr = 0; + /* we need update geometry + * and color mode for afbc mode + * update_geometry = 1; + * update_color_mode = 1; + */ + if (xres <= 128) + osd_hw.osd_afbcd[index].conv_lbuf_len = 32; + else if (xres <= 256) + osd_hw.osd_afbcd[index].conv_lbuf_len = 64; + else if (xres <= 512) + osd_hw.osd_afbcd[index].conv_lbuf_len = 128; + else if (xres <= 1024) + osd_hw.osd_afbcd[index].conv_lbuf_len = 256; + else if (xres <= 2048) + osd_hw.osd_afbcd[index].conv_lbuf_len = 512; + else + osd_hw.osd_afbcd[index].conv_lbuf_len = 1024; + } + osd_log_info("osd[%d] canvas.idx =0x%x\n", + index, osd_hw.fb_gem[index].canvas_idx); + osd_log_info("osd[%d] canvas.addr=0x%x\n", + index, osd_hw.fb_gem[index].addr); + osd_log_info("osd[%d] canvas.width=%d\n", + index, osd_hw.fb_gem[index].width); + osd_log_info("osd[%d] canvas.height=%d\n", + index, osd_hw.fb_gem[index].height); + osd_log_info("osd[%d] frame.width=%d\n", + index, xres); + osd_log_info("osd[%d] frame.height=%d\n", + index, yres); +#ifdef CONFIG_AMLOGIC_MEDIA_CANVAS + canvas_config(osd_hw.fb_gem[index].canvas_idx, + osd_hw.fb_gem[index].addr, + osd_hw.fb_gem[index].width, + osd_hw.fb_gem[index].height, + CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR); +#endif + } + + /* need always set color mode for osd2 */ + if ((color != osd_hw.color_info[index]) || (index == OSD2)) { + update_color_mode = 1; + osd_hw.color_info[index] = color; + } + /* osd blank only control by /sys/class/graphcis/fbx/blank */ +#if 0 + if (osd_hw.enable[index] == DISABLE) { + osd_hw.enable[index] = ENABLE; + add_to_update_list(index, OSD_ENABLE); + } +#endif + + if (memcmp(&pan_data, &osd_hw.pandata[index], + sizeof(struct pandata_s)) != 0 || + memcmp(&disp_data, &osd_hw.dispdata[index], + sizeof(struct pandata_s)) != 0) { + update_geometry = 1; + memcpy(&osd_hw.pandata[index], &pan_data, + sizeof(struct pandata_s)); + memcpy(&osd_hw.dispdata[index], &disp_data, + sizeof(struct pandata_s)); + } + spin_lock_irqsave(&osd_lock, lock_flags); + if (update_color_mode) + osd_hw.reg[index][OSD_COLOR_MODE].update_func(); + if (update_geometry) + osd_hw.reg[index][DISP_GEOMETRY].update_func(); + spin_unlock_irqrestore(&osd_lock, lock_flags); + + if (osd_hw.antiflicker_mode) + osd_antiflicker_update_pan(yoffset, yres); + if (osd_hw.clone[index]) + osd_clone_pan(index, yoffset, 0); +#ifdef CONFIG_AM_FB_EXT + osd_ext_clone_pan(index); +#endif + osd_wait_vsync_hw(); +} + +void osd_setpal_hw(u32 index, + unsigned int regno, + unsigned int red, + unsigned int green, + unsigned int blue, + unsigned int transp + ) +{ + if (get_cpu_type() >= MESON_CPU_MAJOR_ID_GXBB) + return; + + if (regno < 256) { + u32 pal; + + pal = ((red & 0xff) << 24) | + ((green & 0xff) << 16) | + ((blue & 0xff) << 8) | + (transp & 0xff); + spin_lock_irqsave(&osd_lock, lock_flags); + VSYNCOSD_WR_MPEG_REG(VIU_OSD1_COLOR_ADDR + REG_OFFSET * index, + regno); + VSYNCOSD_WR_MPEG_REG(VIU_OSD1_COLOR + REG_OFFSET * index, pal); + spin_unlock_irqrestore(&osd_lock, lock_flags); + } +} + +void osd_get_order_hw(u32 index, u32 *order) +{ + *order = osd_hw.order & 0x3; +} + +void osd_set_order_hw(u32 index, u32 order) +{ + if ((order != OSD_ORDER_01) && (order != OSD_ORDER_10)) + return; + osd_hw.order = order; + add_to_update_list(index, OSD_CHANGE_ORDER); + osd_wait_vsync_hw(); +} + +/* osd free scale mode */ +static void osd_set_free_scale_enable_mode1(u32 index, u32 enable) +{ + unsigned int h_enable = 0; + unsigned int v_enable = 0; + int ret = 0; + + h_enable = (enable & 0xffff0000 ? 1 : 0); + v_enable = (enable & 0xffff ? 1 : 0); + osd_hw.free_scale[index].h_enable = h_enable; + osd_hw.free_scale[index].v_enable = v_enable; + osd_hw.free_scale_enable[index] = enable; + if (osd_hw.free_scale_enable[index]) { + ret = osd_set_scan_mode(index); + spin_lock_irqsave(&osd_lock, lock_flags); + if (ret) + osd_hw.reg[index][OSD_COLOR_MODE].update_func(); + osd_hw.reg[index][OSD_FREESCALE_COEF].update_func(); + osd_hw.reg[index][DISP_GEOMETRY].update_func(); + osd_hw.reg[index][DISP_FREESCALE_ENABLE].update_func(); + osd_hw.reg[index][OSD_ENABLE].update_func(); + spin_unlock_irqrestore(&osd_lock, lock_flags); + } else { + ret = osd_set_scan_mode(index); + spin_lock_irqsave(&osd_lock, lock_flags); + if (ret) + osd_hw.reg[index][OSD_COLOR_MODE].update_func(); + osd_hw.reg[index][DISP_GEOMETRY].update_func(); + osd_hw.reg[index][DISP_FREESCALE_ENABLE].update_func(); + osd_hw.reg[index][OSD_ENABLE].update_func(); + spin_unlock_irqrestore(&osd_lock, lock_flags); + } + osd_wait_vsync_hw(); +} + +void osd_set_free_scale_enable_hw(u32 index, u32 enable) +{ + if (osd_hw.free_scale_mode[index]) + osd_set_free_scale_enable_mode1(index, enable); + else if (enable) + osd_log_info( + "osd[%d] free_scale_enable_hw mode is error %d\n", + index, osd_hw.free_scale_mode[index]); +} + +void osd_get_free_scale_enable_hw(u32 index, u32 *free_scale_enable) +{ + *free_scale_enable = osd_hw.free_scale_enable[index]; +} + +void osd_set_free_scale_mode_hw(u32 index, u32 freescale_mode) +{ + osd_hw.free_scale_mode[index] = freescale_mode; +} + +void osd_get_free_scale_mode_hw(u32 index, u32 *freescale_mode) +{ + *freescale_mode = osd_hw.free_scale_mode[index]; +} + +void osd_set_4k2k_fb_mode_hw(u32 fb_for_4k2k) +{ + osd_hw.fb_for_4k2k = fb_for_4k2k; +} + +void osd_get_free_scale_width_hw(u32 index, u32 *free_scale_width) +{ + *free_scale_width = osd_hw.free_src_data[index].x_end - + osd_hw.free_src_data[index].x_start + 1; +} + +void osd_get_free_scale_height_hw(u32 index, u32 *free_scale_height) +{ + *free_scale_height = osd_hw.free_src_data[index].y_end - + osd_hw.free_src_data[index].y_start + 1; +} + +void osd_get_free_scale_axis_hw(u32 index, s32 *x0, s32 *y0, s32 *x1, s32 *y1) +{ + *x0 = osd_hw.free_src_data[index].x_start; + *y0 = osd_hw.free_src_data[index].y_start; + *x1 = osd_hw.free_src_data[index].x_end; + *y1 = osd_hw.free_src_data[index].y_end; +} + +void osd_set_free_scale_axis_hw(u32 index, s32 x0, s32 y0, s32 x1, s32 y1) +{ + osd_hw.free_src_data[index].x_start = x0; + osd_hw.free_src_data[index].y_start = y0; + osd_hw.free_src_data[index].x_end = x1; + osd_hw.free_src_data[index].y_end = y1; +} + +void osd_get_scale_axis_hw(u32 index, s32 *x0, s32 *y0, s32 *x1, s32 *y1) +{ + *x0 = osd_hw.scaledata[index].x_start; + *x1 = osd_hw.scaledata[index].x_end; + *y0 = osd_hw.scaledata[index].y_start; + *y1 = osd_hw.scaledata[index].y_end; +} + +void osd_set_scale_axis_hw(u32 index, s32 x0, s32 y0, s32 x1, s32 y1) +{ + osd_hw.scaledata[index].x_start = x0; + osd_hw.scaledata[index].x_end = x1; + osd_hw.scaledata[index].y_start = y0; + osd_hw.scaledata[index].y_end = y1; +} + +void osd_get_window_axis_hw(u32 index, s32 *x0, s32 *y0, s32 *x1, s32 *y1) +{ + struct vinfo_s *vinfo; + s32 height; + + vinfo = get_current_vinfo(); + if (vinfo) { + if (is_interlaced(vinfo)) { + height = osd_hw.free_dst_data[index].y_end - + osd_hw.free_dst_data[index].y_start + 1; + height *= 2; + *y0 = osd_hw.free_dst_data[index].y_start * 2; + *y1 = height + *y0 - 1; + } else { + *y0 = osd_hw.free_dst_data[index].y_start; + *y1 = osd_hw.free_dst_data[index].y_end; + } + } else { + *y0 = osd_hw.free_dst_data[index].y_start; + *y1 = osd_hw.free_dst_data[index].y_end; + } + *x0 = osd_hw.free_dst_data[index].x_start; + *x1 = osd_hw.free_dst_data[index].x_end; +} + +void osd_set_window_axis_hw(u32 index, s32 x0, s32 y0, s32 x1, s32 y1) +{ + struct vinfo_s *vinfo; + + vinfo = get_current_vinfo(); + mutex_lock(&osd_mutex); + if (vinfo) { + if (is_interlaced(vinfo)) { + osd_hw.free_dst_data[index].y_start = y0 / 2; + osd_hw.free_dst_data[index].y_end = y1 / 2; + } else { + osd_hw.free_dst_data[index].y_start = y0; + osd_hw.free_dst_data[index].y_end = y1; + } + } else { + osd_hw.free_dst_data[index].y_start = y0; + osd_hw.free_dst_data[index].y_end = y1; + } + osd_hw.free_dst_data[index].x_start = x0; + osd_hw.free_dst_data[index].x_end = x1; +#if defined(CONFIG_AMLOGIC_MEDIA_FB_OSD2_CURSOR) + osd_hw.cursor_dispdata[index].x_start = x0; + osd_hw.cursor_dispdata[index].x_end = x1; + osd_hw.cursor_dispdata[index].y_start = y0; + osd_hw.cursor_dispdata[index].y_end = y1; +#endif + if (osd_hw.free_dst_data[index].y_end >= 2159) { + if (get_cpu_type() == MESON_CPU_MAJOR_ID_GXM) + osd_reg_write(VPP_OSD_SC_DUMMY_DATA, 0x002020ff); + else if (get_cpu_type() == + MESON_CPU_MAJOR_ID_GXTVBB) + osd_reg_write(VPP_OSD_SC_DUMMY_DATA, 0xff); + else + osd_reg_write(VPP_OSD_SC_DUMMY_DATA, 0x008080ff); + } + osd_update_window_axis = true; + mutex_unlock(&osd_mutex); +} + +void osd_get_block_windows_hw(u32 index, u32 *windows) +{ + /* + * memcpy(windows, osd_hw.block_windows[index], + * sizeof(osd_hw.block_windows[index])); + */ +} + +void osd_set_block_windows_hw(u32 index, u32 *windows) +{ + /* + * memcpy(osd_hw.block_windows[index], windows, + * sizeof(osd_hw.block_windows[index])); + */ + add_to_update_list(index, DISP_GEOMETRY); + osd_wait_vsync_hw(); +} + +void osd_get_block_mode_hw(u32 index, u32 *mode) +{ + *mode = osd_hw.block_mode[index]; +} + +void osd_set_block_mode_hw(u32 index, u32 mode) +{ + /* osd_hw.block_mode[index] = mode; */ + add_to_update_list(index, DISP_GEOMETRY); + osd_wait_vsync_hw(); +} + +void osd_enable_3d_mode_hw(u32 index, u32 enable) +{ + spin_lock_irqsave(&osd_lock, lock_flags); + osd_hw.mode_3d[index].enable = enable; + spin_unlock_irqrestore(&osd_lock, lock_flags); + if (enable) { + /* when disable 3d mode ,we should return to stardard state. */ + osd_hw.mode_3d[index].left_right = OSD_LEFT; + osd_hw.mode_3d[index].l_start = osd_hw.pandata[index].x_start; + osd_hw.mode_3d[index].l_end = (osd_hw.pandata[index].x_end + + osd_hw.pandata[index].x_start) >> 1; + osd_hw.mode_3d[index].r_start = osd_hw.mode_3d[index].l_end + 1; + osd_hw.mode_3d[index].r_end = osd_hw.pandata[index].x_end; + osd_hw.mode_3d[index].origin_scale.h_enable = + osd_hw.scale[index].h_enable; + osd_hw.mode_3d[index].origin_scale.v_enable = + osd_hw.scale[index].v_enable; + osd_set_2x_scale_hw(index, 1, 0); + } else { + osd_set_2x_scale_hw(index, + osd_hw.mode_3d[index].origin_scale.h_enable, + osd_hw.mode_3d[index].origin_scale.v_enable); + } +} + +void osd_enable_hw(u32 index, u32 enable) +{ + int i = 0; + int count = (pxp_mode == 1)?3:WAIT_AFBC_READY_COUNT; + + if (index == 0) { + osd_log_info("osd[%d] enable: %d (%s)\n", + index, enable, current->comm); + } else { + osd_log_info("osd[%d] enable: %d (%s)\n", + index, enable, current->comm); + } + + /* reset viu 31bit ?? */ + if (index == OSD1 && + !osd_hw.enable[index] && + osd_hw.osd_afbcd[index].enable && enable) { + spin_lock_irqsave(&osd_lock, lock_flags); + osd_reg_write(VIU_SW_RESET, 0x80000000); + osd_reg_write(VIU_SW_RESET, 0); + spin_unlock_irqrestore(&osd_lock, lock_flags); + osd_afbc_dec_enable = 0; + + add_to_update_list(index, OSD_COLOR_MODE); + add_to_update_list(index, OSD_GBL_ALPHA); + add_to_update_list(index, DISP_GEOMETRY); + osd_wait_vsync_hw(); + } + + while ((index == 0) && osd_hw.osd_afbcd[index].enable && + (osd_hw.osd_afbcd[index].phy_addr == 0) && + enable && (i < count)) { + osd_wait_vsync_hw(); + i++; + } + if (i > 0) + osd_log_info("osd[%d]: wait %d vsync first buffer ready.\n", + index, i); + osd_hw.enable[index] = enable; + add_to_update_list(index, OSD_ENABLE); + osd_wait_vsync_hw(); +} + +void osd_set_2x_scale_hw(u32 index, u16 h_scale_enable, u16 v_scale_enable) +{ + osd_log_info("osd[%d] set scale, h_scale: %s, v_scale: %s\n", + index, h_scale_enable ? "ENABLE" : "DISABLE", + v_scale_enable ? "ENABLE" : "DISABLE"); + osd_log_info("osd[%d].scaledata: %d %d %d %d\n", + index, + osd_hw.scaledata[index].x_start, + osd_hw.scaledata[index].x_end, + osd_hw.scaledata[index].y_start, + osd_hw.scaledata[index].y_end); + osd_log_info("osd[%d].pandata: %d %d %d %d\n", + index, + osd_hw.pandata[index].x_start, + osd_hw.pandata[index].x_end, + osd_hw.pandata[index].y_start, + osd_hw.pandata[index].y_end); + osd_hw.scale[index].h_enable = h_scale_enable; + osd_hw.scale[index].v_enable = v_scale_enable; + spin_lock_irqsave(&osd_lock, lock_flags); + osd_hw.reg[index][DISP_SCALE_ENABLE].update_func(); + osd_hw.reg[index][DISP_GEOMETRY].update_func(); + spin_unlock_irqrestore(&osd_lock, lock_flags); + osd_wait_vsync_hw(); +} + +void osd_get_flush_rate_hw(u32 *break_rate) +{ + const struct vinfo_s *vinfo; + + vinfo = get_current_vinfo(); + *break_rate = vinfo->sync_duration_num / vinfo->sync_duration_den; +} + +void osd_set_antiflicker_hw(u32 index, struct vinfo_s *vinfo, u32 yres) +{ + if (is_interlaced(vinfo)) { + osd_hw.antiflicker_mode = 1; + osd_antiflicker_task_start(); + osd_antiflicker_enable(1); + osd_antiflicker_update_pan(osd_hw.pandata[index].y_start, yres); + } else { + if (osd_hw.antiflicker_mode) + osd_antiflicker_task_stop(); + osd_hw.antiflicker_mode = 0; + } +} + +void osd_get_antiflicker_hw(u32 index, u32 *on_off) +{ + *on_off = osd_hw.antiflicker_mode; +} + +void osd_clone_pan(u32 index, u32 yoffset, int debug_flag) +{ + s32 offset = 0; + u32 index_buffer = 0; + s32 osd0_buffer_number = 0; + s32 height_osd1 = 0; + + if (yoffset != 0) { + index_buffer = osd_hw.fb_gem[index].height / yoffset; + if (index_buffer == 3) + osd0_buffer_number = 1; + else if (index_buffer == 1) + osd0_buffer_number = 2; + } else + osd0_buffer_number = 0; + osd_clone_get_virtual_yres(&height_osd1); + if (osd_hw.clone[index]) { + offset = osd0_buffer_number * height_osd1; + osd_hw.pandata[OSD2].y_start = offset; + osd_hw.pandata[OSD2].y_end = offset + height_osd1 - 1; + if (osd_hw.angle[OSD2]) { + if (debug_flag) + osd_log_dbg("++ osd_clone_pan start when enable clone\n"); + osd_clone_update_pan(osd0_buffer_number); + } + add_to_update_list(OSD2, DISP_GEOMETRY); + } +} + +void osd_set_angle_hw(u32 index, u32 angle, u32 virtual_osd1_yres, + u32 virtual_osd2_yres) +{ +#ifndef OSD_GE2D_CLONE_SUPPORT + osd_log_err("++ osd_clone depends on GE2D module!\n"); + return; +#endif + if (angle > 4) { + osd_log_err("++ invalid angle: %d\n", angle); + return; + } + osd_log_info("++ virtual_osd1_yres is %d, virtual_osd2_yres is %d!\n", + virtual_osd1_yres, virtual_osd2_yres); + osd_clone_set_virtual_yres(virtual_osd1_yres, virtual_osd2_yres); + if (osd_hw.clone[index] == 0) { + osd_log_info("++ set osd[%d]->angle: %d->%d\n", + index, osd_hw.angle[index], angle); + osd_clone_set_angle(angle); + osd_hw.angle[index] = angle; + } else if (!((osd_hw.angle[index] == 0) || (angle == 0))) { + osd_log_info("++ set osd[%d]->angle: %d->%d\n", + index, osd_hw.angle[index], angle); + osd_clone_set_angle(angle); + osd_hw.angle[index] = angle; + osd_clone_pan(index, osd_hw.pandata[OSD1].y_start, 1); + } +} + +void osd_get_angle_hw(u32 index, u32 *angle) +{ + *angle = osd_hw.angle[index]; +} + +void osd_set_clone_hw(u32 index, u32 clone) +{ + int ret = -1; + + osd_log_info("++ set osd[%d]->clone: %d->%d\n", + index, osd_hw.clone[index], clone); + osd_hw.clone[index] = clone; + if (osd_hw.clone[index]) { + if (osd_hw.angle[index]) { + osd_hw.color_info[index] = osd_hw.color_info[OSD1]; + ret = osd_clone_task_start(); + if (ret) + osd_clone_pan(index, + osd_hw.pandata[OSD1].y_start, 1); + else + osd_log_err("++ start clone error\n"); + } + } else { + if (osd_hw.angle[index]) + osd_clone_task_stop(); + } + add_to_update_list(index, OSD_COLOR_MODE); +} + +void osd_set_update_pan_hw(u32 index) +{ + osd_clone_pan(index, osd_hw.pandata[OSD1].y_start, 1); +} + +void osd_get_clone_hw(u32 index, u32 *clone) +{ + *clone = osd_hw.clone[index]; +} + +void osd_set_reverse_hw(u32 index, u32 reverse) +{ + char *str[4] = {"NONE", "ALL", "X_REV", "Y_REV"}; + + osd_hw.osd_reverse[index] = reverse; + pr_info("set osd%d reverse as %s\n", index, str[reverse]); + add_to_update_list(index, DISP_OSD_REVERSE); + osd_wait_vsync_hw(); +} + +void osd_get_reverse_hw(u32 index, u32 *reverse) +{ + *reverse = osd_hw.osd_reverse[index]; +} + +void osd_switch_free_scale( + u32 pre_index, u32 pre_enable, u32 pre_scale, + u32 next_index, u32 next_enable, u32 next_scale) +{ + unsigned int h_enable = 0; + unsigned int v_enable = 0; + int i = 0; + int count = (pxp_mode == 1)?3:WAIT_AFBC_READY_COUNT; + + osd_log_info("osd[%d] enable: %d scale:0x%x (%s)\n", + pre_index, pre_enable, pre_scale, current->comm); + osd_log_info("osd[%d] enable: %d scale:0x%x (%s)\n", + next_index, next_enable, next_scale, current->comm); + if (osd_hw.free_scale_mode[pre_index] + || osd_hw.free_scale_mode[next_index]) { + while ((next_index == OSD1) + && osd_hw.osd_afbcd[next_index].enable + && (osd_hw.osd_afbcd[next_index].phy_addr == 0) + && next_enable && (i < count)) { + osd_wait_vsync_hw(); + i++; + } + if (i > 0) + osd_log_info("osd[%d]: wait %d vsync first buffer ready.\n", + next_index, i); + h_enable = (pre_scale & 0xffff0000 ? 1 : 0); + v_enable = (pre_scale & 0xffff ? 1 : 0); + osd_hw.free_scale[pre_index].h_enable = h_enable; + osd_hw.free_scale[pre_index].v_enable = v_enable; + osd_hw.free_scale_enable[pre_index] = pre_scale; + osd_hw.enable[pre_index] = pre_enable; + + h_enable = (next_scale & 0xffff0000 ? 1 : 0); + v_enable = (next_scale & 0xffff ? 1 : 0); + osd_hw.free_scale[next_index].h_enable = h_enable; + osd_hw.free_scale[next_index].v_enable = v_enable; + osd_hw.free_scale_enable[next_index] = next_scale; + osd_hw.enable[next_index] = next_enable; + + osd_set_scan_mode(next_index); + spin_lock_irqsave(&osd_lock, lock_flags); + if (next_index == OSD1 + && osd_hw.osd_afbcd[next_index].enable + && next_enable) { + osd_reg_write(VIU_SW_RESET, 0x80000000); + osd_reg_write(VIU_SW_RESET, 0); + osd_afbc_dec_enable = 0; + osd_hw.reg[next_index][OSD_GBL_ALPHA].update_func(); + } + + osd_hw.reg[pre_index][OSD_COLOR_MODE].update_func(); + if (pre_scale) + osd_hw.reg[pre_index][OSD_FREESCALE_COEF].update_func(); + osd_hw.reg[pre_index][DISP_GEOMETRY].update_func(); + osd_hw.reg[pre_index][DISP_FREESCALE_ENABLE].update_func(); + osd_hw.reg[pre_index][OSD_ENABLE].update_func(); + + osd_hw.reg[next_index][OSD_COLOR_MODE].update_func(); + if (next_scale) + osd_hw.reg[next_index] + [OSD_FREESCALE_COEF].update_func(); + osd_hw.reg[next_index][DISP_GEOMETRY].update_func(); + osd_hw.reg[next_index][DISP_FREESCALE_ENABLE].update_func(); + osd_hw.reg[next_index][OSD_ENABLE].update_func(); + + spin_unlock_irqrestore(&osd_lock, lock_flags); + osd_wait_vsync_hw(); + } else { + osd_enable_hw(pre_index, pre_enable); + osd_enable_hw(next_index, next_enable); + } +} + +void osd_get_urgent(u32 index, u32 *urgent) +{ + *urgent = osd_hw.urgent[index]; +} + +void osd_set_urgent(u32 index, u32 urgent) +{ + osd_hw.urgent[index] = urgent; + add_to_update_list(index, OSD_FIFO); + osd_wait_vsync_hw(); +} + +#ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD_SYNC_FENCE +static void osd_pan_display_fence(struct osd_fence_map_s *fence_map) +{ + s32 ret = 1; + long diff_x, diff_y; + u32 index = fence_map->fb_index; + u32 xoffset = fence_map->xoffset; + u32 yoffset = fence_map->yoffset; + + if (index >= 2) + return; + if (timeline_created) { /* out fence created success. */ + ret = osd_wait_buf_ready(fence_map); + if (ret < 0) + osd_log_dbg("fence wait ret %d\n", ret); + } + if (ret) { + if (xoffset != osd_hw.pandata[index].x_start + || yoffset != osd_hw.pandata[index].y_start) { + spin_lock_irqsave(&osd_lock, lock_flags); + diff_x = xoffset - osd_hw.pandata[index].x_start; + diff_y = yoffset - osd_hw.pandata[index].y_start; + osd_hw.pandata[index].x_start += diff_x; + osd_hw.pandata[index].x_end += diff_x; + osd_hw.pandata[index].y_start += diff_y; + osd_hw.pandata[index].y_end += diff_y; + if (index == OSD1 && + osd_hw.osd_afbcd[index].enable == ENABLE) { + /* osd_hw.osd_afbcd[index].phy_addr = + * (osd_hw.pandata[index].y_start / + * osd_hw.osd_afbcd[index].frame_height) * + * osd_hw.osd_afbcd[index].frame_height * + * osd_hw.fb_gem[index].width; + * osd_hw.osd_afbcd[index].phy_addr += + * osd_hw.fb_gem[index].addr; + */ + osd_hw.osd_afbcd[index].phy_addr = + osd_hw.osd_afbcd[index].addr + [osd_hw.pandata[index].y_start / + osd_hw.osd_afbcd[index].frame_height]; + } + osd_hw.reg[index][DISP_GEOMETRY].update_func(); + if (osd_hw.free_scale_enable[index] + && osd_update_window_axis) { + osd_hw.reg[index][DISP_FREESCALE_ENABLE] + .update_func(); + osd_update_window_axis = false; + } + spin_unlock_irqrestore(&osd_lock, lock_flags); + osd_wait_vsync_hw(); + } + } + if (timeline_created) { + if (ret) + sw_sync_timeline_inc(timeline, 1); + else + osd_log_err("------NOT signal out_fence ERROR\n"); + } +#ifdef CONFIG_AM_FB_EXT + if (ret) + osd_ext_clone_pan(index); +#endif + osd_log_dbg2("offset[%d-%d]x[%d-%d]y[%d-%d]\n", + xoffset, yoffset, + osd_hw.pandata[index].x_start, + osd_hw.pandata[index].x_end, + osd_hw.pandata[index].y_start, + osd_hw.pandata[index].y_end); +} +#endif + +void osd_pan_display_hw(u32 index, unsigned int xoffset, unsigned int yoffset) +{ + long diff_x, diff_y; + +#if defined(CONFIG_AMLOGIC_MEDIA_FB_OSD2_CURSOR) + if (index >= 1) +#else + if (index >= 2) +#endif + return; + if (xoffset != osd_hw.pandata[index].x_start + || yoffset != osd_hw.pandata[index].y_start) { + diff_x = xoffset - osd_hw.pandata[index].x_start; + diff_y = yoffset - osd_hw.pandata[index].y_start; + osd_hw.pandata[index].x_start += diff_x; + osd_hw.pandata[index].x_end += diff_x; + osd_hw.pandata[index].y_start += diff_y; + osd_hw.pandata[index].y_end += diff_y; + add_to_update_list(index, DISP_GEOMETRY); + osd_wait_vsync_hw(); + } +#ifdef CONFIG_AM_FB_EXT + osd_ext_clone_pan(index); +#endif + osd_log_dbg2("offset[%d-%d]x[%d-%d]y[%d-%d]\n", + xoffset, yoffset, + osd_hw.pandata[index].x_start, + osd_hw.pandata[index].x_end, + osd_hw.pandata[index].y_start, + osd_hw.pandata[index].y_end); +} + +static void osd1_update_disp_scale_enable(void) +{ + if (osd_hw.scale[OSD1].h_enable) + VSYNCOSD_SET_MPEG_REG_MASK(VIU_OSD1_BLK0_CFG_W0, 3 << 12); + else + VSYNCOSD_CLR_MPEG_REG_MASK(VIU_OSD1_BLK0_CFG_W0, 3 << 12); + if (osd_hw.scan_mode != SCAN_MODE_INTERLACE) { + if (osd_hw.scale[OSD1].v_enable) + VSYNCOSD_SET_MPEG_REG_MASK( + VIU_OSD1_BLK0_CFG_W0, + 1 << 14); + else + VSYNCOSD_CLR_MPEG_REG_MASK( + VIU_OSD1_BLK0_CFG_W0, + 1 << 14); + } + remove_from_update_list(OSD1, DISP_SCALE_ENABLE); +} + +static void osd2_update_disp_scale_enable(void) +{ + if (osd_hw.scale[OSD2].h_enable) { +#if defined(CONFIG_AMLOGIC_MEDIA_FB_OSD2_CURSOR) + VSYNCOSD_CLR_MPEG_REG_MASK(VIU_OSD2_BLK0_CFG_W0, 3 << 12); +#else + VSYNCOSD_SET_MPEG_REG_MASK(VIU_OSD2_BLK0_CFG_W0, 3 << 12); +#endif + } else + VSYNCOSD_CLR_MPEG_REG_MASK(VIU_OSD2_BLK0_CFG_W0, 3 << 12); + if (osd_hw.scan_mode != SCAN_MODE_INTERLACE) { + if (osd_hw.scale[OSD2].v_enable) { +#if defined(CONFIG_AMLOGIC_MEDIA_FB_OSD2_CURSOR) + VSYNCOSD_CLR_MPEG_REG_MASK(VIU_OSD2_BLK0_CFG_W0, + 1 << 14); +#else + VSYNCOSD_SET_MPEG_REG_MASK(VIU_OSD2_BLK0_CFG_W0, + 1 << 14); +#endif + } else + VSYNCOSD_CLR_MPEG_REG_MASK(VIU_OSD2_BLK0_CFG_W0, + 1 << 14); + } + remove_from_update_list(OSD2, DISP_SCALE_ENABLE); +} + +#ifdef CONFIG_AMLOGIC_SUPERSCALER +static void osd_super_scale_enable(u32 index) +{ + u32 data32 = 0x0; + u32 src_w = 0, src_h = 0; + + osd_super_scale_mem_power_on(); + + /* enable osd scaler path */ + if (index == OSD1) + data32 = 8; + else { + data32 = 1; /* select osd2 input */ + data32 |= 1 << 3; /* enable osd scaler path */ + } + VSYNCOSD_WR_MPEG_REG(VPP_OSD_SC_CTRL0, data32); + /* enable osd super scaler */ + data32 = (1 << 0) + | (1 << 1) + | (1 << 2); + VSYNCOSD_WR_MPEG_REG(OSDSR_CTRL_MODE, data32); + /* config osd super scaler setting */ + VSYNCOSD_WR_MPEG_REG(OSDSR_UK_GRAD2DDIAG_LIMIT, 0xffffff); + VSYNCOSD_WR_MPEG_REG(OSDSR_UK_GRAD2DADJA_LIMIT, 0xffffff); + VSYNCOSD_WR_MPEG_REG(OSDSR_UK_BST_GAIN, 0x7a7a3a50); + /* config osd super scaler input size */ + src_w = osd_hw.free_src_data[OSD1].x_end - + osd_hw.free_src_data[OSD1].x_start + 1; + src_h = osd_hw.free_src_data[OSD1].y_end - + osd_hw.free_src_data[OSD1].y_start + 1; + data32 = (src_w & 0x1fff) | (src_h & 0x1fff) << 16; + VSYNCOSD_WR_MPEG_REG(OSDSR_HV_SIZEIN, data32); + /* config osd super scaler output size */ + data32 = ((osd_hw.free_dst_data[index].x_end & 0xfff) | + (osd_hw.free_dst_data[index].x_start & 0xfff) << 16); + VSYNCOSD_WR_MPEG_REG(VPP_OSD_SCO_H_START_END, data32); + data32 = ((osd_hw.free_dst_data[index].y_end & 0xfff) | + (osd_hw.free_dst_data[index].y_start & 0xfff) << 16); + VSYNCOSD_WR_MPEG_REG(VPP_OSD_SCO_V_START_END, data32); +} + +static void osd_super_scale_disable(void) +{ + /* disable osd scaler path */ + VSYNCOSD_WR_MPEG_REG(VPP_OSD_SC_CTRL0, 0); + /* disable osd super scaler */ + VSYNCOSD_WR_MPEG_REG(OSDSR_HV_SIZEIN, 0); + VSYNCOSD_WR_MPEG_REG(OSDSR_CTRL_MODE, 0); + osd_super_scale_mem_power_off(); +} +#endif +static void osd1_update_disp_freescale_enable(void) +{ + int hf_phase_step, vf_phase_step; + int src_w, src_h, dst_w, dst_h; + int bot_ini_phase; + int vsc_ini_rcv_num, vsc_ini_rpt_p0_num; + int vsc_bot_rcv_num = 0, vsc_bot_rpt_p0_num = 0; + int hsc_ini_rcv_num, hsc_ini_rpt_p0_num; + int hf_bank_len = 4; + int vf_bank_len = 0; + u32 data32 = 0x0; + + if (osd_hw.scale_workaround) + vf_bank_len = 2; + else + vf_bank_len = 4; + if (osd_hw.bot_type == 1) { + vsc_bot_rcv_num = 4; + vsc_bot_rpt_p0_num = 1; + } else if (osd_hw.bot_type == 2) { + vsc_bot_rcv_num = 6; + vsc_bot_rpt_p0_num = 2; + } else if (osd_hw.bot_type == 3) { + vsc_bot_rcv_num = 8; + vsc_bot_rpt_p0_num = 3; + } + hsc_ini_rcv_num = hf_bank_len; + vsc_ini_rcv_num = vf_bank_len; + hsc_ini_rpt_p0_num = + (hf_bank_len / 2 - 1) > 0 ? (hf_bank_len / 2 - 1) : 0; + vsc_ini_rpt_p0_num = + (vf_bank_len / 2 - 1) > 0 ? (vf_bank_len / 2 - 1) : 0; + + src_w = osd_hw.free_src_data[OSD1].x_end - + osd_hw.free_src_data[OSD1].x_start + 1; + src_h = osd_hw.free_src_data[OSD1].y_end - + osd_hw.free_src_data[OSD1].y_start + 1; + dst_w = osd_hw.free_dst_data[OSD1].x_end - + osd_hw.free_dst_data[OSD1].x_start + 1; + dst_h = osd_hw.free_dst_data[OSD1].y_end - + osd_hw.free_dst_data[OSD1].y_start + 1; + #ifdef CONFIG_AMLOGIC_SUPERSCALER + /* super scaler mode */ + if (osd_hw.free_scale_mode[OSD1] & 0x2) { + if (osd_hw.free_scale_enable[OSD1]) + osd_super_scale_enable(OSD1); + else + osd_super_scale_disable(); + remove_from_update_list(OSD1, DISP_FREESCALE_ENABLE); + return; + } + #endif + data32 = 0x0; + if (osd_hw.free_scale_enable[OSD1]) { + /* enable osd scaler */ + if (osd_hw.free_scale_mode[OSD1] & 0x1) { + data32 |= 1 << 2; /* enable osd scaler */ + data32 |= 1 << 3; /* enable osd scaler path */ + VSYNCOSD_WR_MPEG_REG(VPP_OSD_SC_CTRL0, data32); + } + } else { + /* disable osd scaler path */ + VSYNCOSD_WR_MPEG_REG(VPP_OSD_SC_CTRL0, 0); + } + hf_phase_step = (src_w << 18) / dst_w; + hf_phase_step = (hf_phase_step << 6); + vf_phase_step = (src_h << 20) / dst_h; + if (osd_hw.field_out_en) /* interface output */ + bot_ini_phase = ((vf_phase_step / 2) >> 4); + else + bot_ini_phase = 0; + vf_phase_step = (vf_phase_step << 4); + /* config osd scaler in/out hv size */ + data32 = 0x0; + if (osd_hw.free_scale_enable[OSD1]) { + data32 = (((src_h - 1) & 0x1fff) + | ((src_w - 1) & 0x1fff) << 16); + VSYNCOSD_WR_MPEG_REG(VPP_OSD_SCI_WH_M1, data32); + data32 = ((osd_hw.free_dst_data[OSD1].x_end & 0xfff) | + (osd_hw.free_dst_data[OSD1].x_start & 0xfff) << 16); + VSYNCOSD_WR_MPEG_REG(VPP_OSD_SCO_H_START_END, data32); + data32 = ((osd_hw.free_dst_data[OSD1].y_end & 0xfff) | + (osd_hw.free_dst_data[OSD1].y_start & 0xfff) << 16); + VSYNCOSD_WR_MPEG_REG(VPP_OSD_SCO_V_START_END, data32); + } + data32 = 0x0; + if (osd_hw.free_scale[OSD1].v_enable) { + data32 |= (vf_bank_len & 0x7) + | ((vsc_ini_rcv_num & 0xf) << 3) + | ((vsc_ini_rpt_p0_num & 0x3) << 8); + if (osd_hw.field_out_en) + data32 |= ((vsc_bot_rcv_num & 0xf) << 11) + | ((vsc_bot_rpt_p0_num & 0x3) << 16) + | (1 << 23); + if (osd_hw.scale_workaround) + data32 |= 1 << 21; + data32 |= 1 << 24; + } + VSYNCOSD_WR_MPEG_REG(VPP_OSD_VSC_CTRL0, data32); + data32 = 0x0; + if (osd_hw.free_scale[OSD1].h_enable) { + data32 |= (hf_bank_len & 0x7) + | ((hsc_ini_rcv_num & 0xf) << 3) + | ((hsc_ini_rpt_p0_num & 0x3) << 8); + data32 |= 1 << 22; + } + VSYNCOSD_WR_MPEG_REG(VPP_OSD_HSC_CTRL0, data32); + data32 = 0x0; + if (osd_hw.free_scale_enable[OSD1]) { + data32 |= (bot_ini_phase & 0xffff) << 16; + VSYNCOSD_WR_MPEG_REG_BITS(VPP_OSD_HSC_PHASE_STEP, + hf_phase_step, 0, 28); + VSYNCOSD_WR_MPEG_REG_BITS(VPP_OSD_HSC_INI_PHASE, 0, 0, 16); + VSYNCOSD_WR_MPEG_REG_BITS(VPP_OSD_VSC_PHASE_STEP, + vf_phase_step, 0, 28); + VSYNCOSD_WR_MPEG_REG(VPP_OSD_VSC_INI_PHASE, data32); + } + remove_from_update_list(OSD1, DISP_FREESCALE_ENABLE); +} + +static void osd1_update_coef(void) +{ + int i; + bool need_update_coef = false; + int hf_coef_wren = 1; + int vf_coef_wren = 1; + int *hf_coef, *vf_coef; + + if (osd_hw.scale_workaround) { + if (use_v_filter_mode != 3) { + use_v_filter_mode = 3; + need_update_coef = true; + } else + need_update_coef = false; + } else { + if (use_v_filter_mode != osd_v_filter_mode) { + use_v_filter_mode = osd_v_filter_mode; + need_update_coef = true; + } else + need_update_coef = false; + } + if (need_update_coef) { + vf_coef = filter_table[use_v_filter_mode]; + if (vf_coef_wren) { + osd_reg_set_bits(VPP_OSD_SCALE_COEF_IDX, 0x0000, 0, 9); + for (i = 0; i < 33; i++) + osd_reg_write(VPP_OSD_SCALE_COEF, vf_coef[i]); + } + } + need_update_coef = false; + if (use_h_filter_mode != osd_h_filter_mode) { + use_h_filter_mode = osd_h_filter_mode; + need_update_coef = true; + } + hf_coef = filter_table[use_h_filter_mode]; + if (need_update_coef) { + if (hf_coef_wren) { + osd_reg_set_bits(VPP_OSD_SCALE_COEF_IDX, 0x0100, 0, 9); + for (i = 0; i < 33; i++) + osd_reg_write(VPP_OSD_SCALE_COEF, hf_coef[i]); + } + } + remove_from_update_list(OSD1, OSD_FREESCALE_COEF); +} + +static void osd2_update_disp_freescale_enable(void) +{ + int hf_phase_step, vf_phase_step; + int src_w, src_h, dst_w, dst_h; + int bot_ini_phase; + int vsc_ini_rcv_num, vsc_ini_rpt_p0_num; + int vsc_bot_rcv_num = 6, vsc_bot_rpt_p0_num = 2; + int hsc_ini_rcv_num, hsc_ini_rpt_p0_num; + int hf_bank_len = 4; + int vf_bank_len = 4; + u32 data32 = 0x0; + + if (osd_hw.scale_workaround) + vf_bank_len = 2; + hsc_ini_rcv_num = hf_bank_len; + vsc_ini_rcv_num = vf_bank_len; + hsc_ini_rpt_p0_num = + (hf_bank_len / 2 - 1) > 0 ? (hf_bank_len / 2 - 1) : 0; + vsc_ini_rpt_p0_num = + (vf_bank_len / 2 - 1) > 0 ? (vf_bank_len / 2 - 1) : 0; + + src_w = osd_hw.free_src_data[OSD2].x_end - + osd_hw.free_src_data[OSD2].x_start + 1; + src_h = osd_hw.free_src_data[OSD2].y_end - + osd_hw.free_src_data[OSD2].y_start + 1; + dst_w = osd_hw.free_dst_data[OSD2].x_end - + osd_hw.free_dst_data[OSD2].x_start + 1; + dst_h = osd_hw.free_dst_data[OSD2].y_end - + osd_hw.free_dst_data[OSD2].y_start + 1; + #ifdef CONFIG_AMLOGIC_SUPERSCALER + /* super scaler mode */ + if (osd_hw.free_scale_mode[OSD2] & 0x2) { + if (osd_hw.free_scale_enable[OSD2]) + osd_super_scale_enable(OSD2); + else + osd_super_scale_disable(); + remove_from_update_list(OSD2, DISP_FREESCALE_ENABLE); + return; + #endif + /* config osd sc control reg */ + data32 = 0x0; + if (osd_hw.free_scale_enable[OSD2]) { + /* enable osd scaler */ + if (osd_hw.free_scale_mode[OSD2] & 0x1) { + data32 |= 1; /* select osd2 input */ + data32 |= 1 << 2; /* enable osd scaler */ + data32 |= 1 << 3; /* enable osd scaler path */ + VSYNCOSD_WR_MPEG_REG(VPP_OSD_SC_CTRL0, data32); + } + } else { + /* disable osd scaler path */ + VSYNCOSD_WR_MPEG_REG(VPP_OSD_SC_CTRL0, 0); + } + hf_phase_step = (src_w << 18) / dst_w; + hf_phase_step = (hf_phase_step << 6); + vf_phase_step = (src_h << 20) / dst_h; + if (osd_hw.field_out_en) /* interface output */ + bot_ini_phase = ((vf_phase_step / 2) >> 4); + else + bot_ini_phase = 0; + vf_phase_step = (vf_phase_step << 4); + /* config osd scaler in/out hv size */ + data32 = 0x0; + if (osd_hw.free_scale_enable[OSD2]) { + data32 = (((src_h - 1) & 0x1fff) + | ((src_w - 1) & 0x1fff) << 16); + VSYNCOSD_WR_MPEG_REG(VPP_OSD_SCI_WH_M1, data32); + data32 = ((osd_hw.free_dst_data[OSD2].x_end & 0xfff) | + (osd_hw.free_dst_data[OSD2].x_start & 0xfff) << 16); + VSYNCOSD_WR_MPEG_REG(VPP_OSD_SCO_H_START_END, data32); + data32 = ((osd_hw.free_dst_data[OSD2].y_end & 0xfff) | + (osd_hw.free_dst_data[OSD2].y_start & 0xfff) << 16); + VSYNCOSD_WR_MPEG_REG(VPP_OSD_SCO_V_START_END, data32); + } + data32 = 0x0; + if (osd_hw.free_scale[OSD2].h_enable) { + data32 |= (hf_bank_len & 0x7) + | ((hsc_ini_rcv_num & 0xf) << 3) + | ((hsc_ini_rpt_p0_num & 0x3) << 8); + data32 |= 1 << 22; + } + VSYNCOSD_WR_MPEG_REG(VPP_OSD_HSC_CTRL0, data32); + data32 = 0x0; + if (osd_hw.free_scale[OSD2].v_enable) { + data32 |= (vf_bank_len & 0x7) + | ((vsc_ini_rcv_num & 0xf) << 3) + | ((vsc_ini_rpt_p0_num & 0x3) << 8); + if (osd_hw.field_out_en) /* interface output */ + data32 |= ((vsc_bot_rcv_num & 0xf) << 11) + | ((vsc_bot_rpt_p0_num & 0x3) << 16) + | (1 << 23); + if (osd_hw.scale_workaround) + data32 |= 1 << 21; + data32 |= 1 << 24; + } + VSYNCOSD_WR_MPEG_REG(VPP_OSD_VSC_CTRL0, data32); + data32 = 0x0; + if (osd_hw.free_scale_enable[OSD2]) { + data32 |= (bot_ini_phase & 0xffff) << 16; + VSYNCOSD_WR_MPEG_REG_BITS(VPP_OSD_HSC_PHASE_STEP, + hf_phase_step, 0, 28); + VSYNCOSD_WR_MPEG_REG_BITS(VPP_OSD_HSC_INI_PHASE, 0, 0, 16); + VSYNCOSD_WR_MPEG_REG_BITS(VPP_OSD_VSC_PHASE_STEP, + vf_phase_step, 0, 28); + VSYNCOSD_WR_MPEG_REG(VPP_OSD_VSC_INI_PHASE, data32); + } + remove_from_update_list(OSD2, DISP_FREESCALE_ENABLE); +} + +static void osd2_update_coef(void) +{ + int i; + bool need_update_coef = false; + int hf_coef_wren = 1; + int vf_coef_wren = 1; + int *hf_coef, *vf_coef; + + if (osd_hw.scale_workaround) { + if (use_v_filter_mode != 3) { + use_v_filter_mode = 3; + need_update_coef = true; + } else + need_update_coef = false; + } else { + if (use_v_filter_mode != osd_v_filter_mode) { + use_v_filter_mode = osd_v_filter_mode; + need_update_coef = true; + } else + need_update_coef = false; + } + vf_coef = filter_table[use_v_filter_mode]; + if (need_update_coef) { + if (vf_coef_wren) { + osd_reg_set_bits(VPP_OSD_SCALE_COEF_IDX, 0x0000, 0, 9); + for (i = 0; i < 33; i++) + osd_reg_write(VPP_OSD_SCALE_COEF, vf_coef[i]); + } + } + need_update_coef = false; + if (use_h_filter_mode != osd_h_filter_mode) { + use_h_filter_mode = osd_h_filter_mode; + need_update_coef = true; + } + hf_coef = filter_table[use_h_filter_mode]; + if (need_update_coef) { + if (hf_coef_wren) { + osd_reg_set_bits(VPP_OSD_SCALE_COEF_IDX, 0x0100, 0, 9); + for (i = 0; i < 33; i++) + osd_reg_write(VPP_OSD_SCALE_COEF, hf_coef[i]); + } + } + remove_from_update_list(OSD2, OSD_FREESCALE_COEF); +} + +static void osd1_update_color_mode(void) +{ + u32 data32 = 0; + + if (osd_hw.color_info[OSD1] != NULL) { + data32 = (osd_hw.scan_mode == SCAN_MODE_INTERLACE) ? 2 : 0; + data32 |= VSYNCOSD_RD_MPEG_REG(VIU_OSD1_BLK0_CFG_W0) + & 0x30007040; + data32 |= osd_hw.fb_gem[OSD1].canvas_idx << 16; + /* if (!osd_hw.rotate[OSD1].on_off) */ + data32 |= OSD_DATA_LITTLE_ENDIAN << 15; + data32 |= osd_hw.color_info[OSD1]->hw_colormat << 2; + if (get_cpu_type() < MESON_CPU_MAJOR_ID_GXTVBB) { + if (osd_hw.color_info[OSD1]->color_index < + COLOR_INDEX_YUV_422) + data32 |= 1 << 7; /* yuv enable */ + } + /* osd_blk_mode */ + data32 |= osd_hw.color_info[OSD1]->hw_blkmode << 8; + VSYNCOSD_WR_MPEG_REG(VIU_OSD1_BLK0_CFG_W0, data32); + /* + * VSYNCOSD_WR_MPEG_REG(VIU_OSD1_BLK1_CFG_W0, data32); + * VSYNCOSD_WR_MPEG_REG(VIU_OSD1_BLK2_CFG_W0, data32); + * VSYNCOSD_WR_MPEG_REG(VIU_OSD1_BLK3_CFG_W0, data32); + */ + if (osd_hw.osd_afbcd[OSD1].enable) { + /* only the RGBA32 mode */ + VSYNCOSD_WR_MPEG_REG(OSD1_AFBCD_MODE, + (3 << 24) | + (4 << 16) | /* hold_line_num */ + (0xe4 << 8) | + (1 << 6) | + (1 << 5) | + (0x15 << 0)); /* pixel_packing_fmt */ + /* TODO: add pixel_packing_fmt setting */ + VSYNCOSD_WR_MPEG_REG(OSD1_AFBCD_CONV_CTRL, + (osd_hw.osd_afbcd[OSD1].conv_lbuf_len + & 0xffff)); + /* afbc mode RGBA32 -> RGB24 + * data32 = (0x1b << 24) | + * (osd_hw.osd_afbcd[OSD1].phy_addr & 0xffffff); + * VSYNCOSD_WR_MPEG_REG( + * OSD1_AFBCD_CHROMA_PTR, + * data32); + */ + VSYNCOSD_WR_MPEG_REG_BITS( + OSD1_AFBCD_CHROMA_PTR, + 0xe4, 24, 8); + /* + * data32 = (0xe4 << 24) | + * (osd_hw.osd_afbcd[OSD1].phy_addr & 0xffffff); + * VSYNCOSD_WR_MPEG_REG( + * OSD1_AFBCD_CHROMA_PTR, + * data32); + */ + } + if (get_cpu_type() >= MESON_CPU_MAJOR_ID_GXBB) { + enum color_index_e idx = + osd_hw.color_info[OSD1]->color_index; + if (idx >= COLOR_INDEX_32_BGRX + && idx <= COLOR_INDEX_32_XRGB) + VSYNCOSD_WR_MPEG_REG_BITS( + VIU_OSD1_CTRL_STAT2, + 0x1ff, 6, 9); + else + VSYNCOSD_WR_MPEG_REG_BITS( + VIU_OSD1_CTRL_STAT2, + 0, 6, 9); + } + } + remove_from_update_list(OSD1, OSD_COLOR_MODE); +} +static void osd2_update_color_mode(void) +{ + u32 data32 = 0; + + if (osd_hw.color_info[OSD2] != NULL) { + data32 = (osd_hw.scan_mode == SCAN_MODE_INTERLACE) ? 2 : 0; + data32 |= VSYNCOSD_RD_MPEG_REG(VIU_OSD2_BLK0_CFG_W0) + & 0x30007040; + data32 |= osd_hw.fb_gem[OSD2].canvas_idx << 16; + /* if (!osd_hw.rotate[OSD2].on_off) */ + data32 |= OSD_DATA_LITTLE_ENDIAN << 15; + data32 |= osd_hw.color_info[OSD2]->hw_colormat << 2; + if (get_cpu_type() != MESON_CPU_MAJOR_ID_GXTVBB) { + if (osd_hw.color_info[OSD2]->color_index < + COLOR_INDEX_YUV_422) + data32 |= 1 << 7; /* yuv enable */ + } + /* osd_blk_mode */ + data32 |= osd_hw.color_info[OSD2]->hw_blkmode << 8; + VSYNCOSD_WR_MPEG_REG(VIU_OSD2_BLK0_CFG_W0, data32); + if (get_cpu_type() >= MESON_CPU_MAJOR_ID_GXBB) { + enum color_index_e idx = + osd_hw.color_info[OSD2]->color_index; + if (idx >= COLOR_INDEX_32_BGRX + && idx <= COLOR_INDEX_32_XRGB) + VSYNCOSD_WR_MPEG_REG_BITS( + VIU_OSD2_CTRL_STAT2, + 0x1ff, 6, 9); + else + VSYNCOSD_WR_MPEG_REG_BITS( + VIU_OSD2_CTRL_STAT2, + 0, 6, 9); + } + } + remove_from_update_list(OSD2, OSD_COLOR_MODE); +} + +static void osd1_update_enable(void) +{ + if (((get_cpu_type() == MESON_CPU_MAJOR_ID_GXTVBB) || + (get_cpu_type() == MESON_CPU_MAJOR_ID_GXM)) && + (osd_hw.enable[OSD1] == ENABLE)) { + if ((VSYNCOSD_RD_MPEG_REG(VPU_RDARB_MODE_L1C2) & + (1 << 16)) == 0) { + VSYNCOSD_WR_MPEG_REG_BITS(VPU_RDARB_MODE_L1C2, + 1, 16, 1); + } + } + + if (osd_hw.enable[OSD1] == ENABLE) + osd_vpp_misc |= VPP_OSD1_POSTBLEND; + else + osd_vpp_misc &= ~VPP_OSD1_POSTBLEND; + + if (osd_hw.enable[OSD1] == ENABLE) { + VSYNCOSD_SET_MPEG_REG_MASK( + VIU_OSD1_CTRL_STAT, 1 << 0); + VSYNCOSD_SET_MPEG_REG_MASK(VPP_MISC, + VPP_OSD1_POSTBLEND | VPP_POSTBLEND_EN); + notify_to_amvideo(); + } else { + notify_to_amvideo(); + VSYNCOSD_CLR_MPEG_REG_MASK( + VPP_MISC, + VPP_OSD1_POSTBLEND); + VSYNCOSD_CLR_MPEG_REG_MASK( + VIU_OSD1_CTRL_STAT, 1 << 0); + + } + if ((osd_hw.osd_afbcd[OSD1].enable == ENABLE) && + ((get_cpu_type() == MESON_CPU_MAJOR_ID_GXTVBB) || + (get_cpu_type() == MESON_CPU_MAJOR_ID_GXM))) { + if (osd_hw.enable[OSD1] == ENABLE) { + if (!osd_afbc_dec_enable && + osd_hw.osd_afbcd[OSD1].phy_addr != 0) { + VSYNCOSD_WR_MPEG_REG( + OSD1_AFBCD_ENABLE, + 0x8100); + osd_afbc_dec_enable = 1; + } + VSYNCOSD_WR_MPEG_REG_BITS( + VIU_OSD1_CTRL_STAT2, + 1, 15, 1); + + } else { + if (osd_afbc_dec_enable) { + VSYNCOSD_WR_MPEG_REG( + OSD1_AFBCD_ENABLE, + 0x8000); + osd_afbc_dec_enable = 0; + } + VSYNCOSD_WR_MPEG_REG_BITS( + VIU_OSD1_CTRL_STAT2, + 0, 15, 1); + } + if ((VSYNCOSD_RD_MPEG_REG(VIU_MISC_CTRL1) & + (0xff << 8)) != 0x9000) { + VSYNCOSD_WR_MPEG_REG_BITS( + VIU_MISC_CTRL1, + 0x90, 8, 8); + } + } + remove_from_update_list(OSD1, OSD_ENABLE); +} + +static void osd2_update_enable(void) +{ + if (osd_hw.enable[OSD2] == ENABLE) + osd_vpp_misc |= VPP_OSD2_POSTBLEND; + else + osd_vpp_misc &= ~VPP_OSD2_POSTBLEND; + + if (osd_hw.enable[OSD2] == ENABLE) { + VSYNCOSD_SET_MPEG_REG_MASK( + VIU_OSD2_CTRL_STAT, + 1 << 0); + VSYNCOSD_SET_MPEG_REG_MASK( + VPP_MISC, + VPP_OSD2_POSTBLEND + | VPP_POSTBLEND_EN); + notify_to_amvideo(); + } else { + notify_to_amvideo(); + VSYNCOSD_CLR_MPEG_REG_MASK(VPP_MISC, + VPP_OSD2_POSTBLEND); + VSYNCOSD_CLR_MPEG_REG_MASK( + VIU_OSD2_CTRL_STAT, + 1 << 0); + } + remove_from_update_list(OSD2, OSD_ENABLE); +} + +static void osd1_update_disp_osd_reverse(void) +{ + if (osd_hw.osd_reverse[OSD1] == REVERSE_TRUE) + VSYNCOSD_WR_MPEG_REG_BITS(VIU_OSD1_BLK0_CFG_W0, 3, 28, 2); + else if (osd_hw.osd_reverse[OSD1] == REVERSE_X) + VSYNCOSD_WR_MPEG_REG_BITS(VIU_OSD1_BLK0_CFG_W0, 1, 28, 2); + else if (osd_hw.osd_reverse[OSD1] == REVERSE_Y) + VSYNCOSD_WR_MPEG_REG_BITS(VIU_OSD1_BLK0_CFG_W0, 2, 28, 2); + else + VSYNCOSD_WR_MPEG_REG_BITS(VIU_OSD1_BLK0_CFG_W0, 0, 28, 2); + remove_from_update_list(OSD1, DISP_OSD_REVERSE); +} + +static void osd2_update_disp_osd_reverse(void) +{ + if (osd_hw.osd_reverse[OSD2] == REVERSE_TRUE) + VSYNCOSD_WR_MPEG_REG_BITS(VIU_OSD2_BLK0_CFG_W0, 3, 28, 2); + else if (osd_hw.osd_reverse[OSD2] == REVERSE_X) + VSYNCOSD_WR_MPEG_REG_BITS(VIU_OSD2_BLK0_CFG_W0, 1, 28, 2); + else if (osd_hw.osd_reverse[OSD2] == REVERSE_Y) + VSYNCOSD_WR_MPEG_REG_BITS(VIU_OSD2_BLK0_CFG_W0, 2, 28, 2); + else + VSYNCOSD_WR_MPEG_REG_BITS(VIU_OSD2_BLK0_CFG_W0, 0, 28, 2); + remove_from_update_list(OSD2, DISP_OSD_REVERSE); +} +static void osd1_update_disp_osd_rotate(void) +{ + remove_from_update_list(OSD1, DISP_OSD_ROTATE); +} + +static void osd2_update_disp_osd_rotate(void) +{ + remove_from_update_list(OSD2, DISP_OSD_ROTATE); +} + + +static void osd1_update_color_key(void) +{ + VSYNCOSD_WR_MPEG_REG(VIU_OSD1_TCOLOR_AG0, osd_hw.color_key[OSD1]); + remove_from_update_list(OSD1, OSD_COLOR_KEY); +} + +static void osd2_update_color_key(void) +{ + VSYNCOSD_WR_MPEG_REG(VIU_OSD2_TCOLOR_AG0, osd_hw.color_key[OSD2]); + remove_from_update_list(OSD2, OSD_COLOR_KEY); +} + +static void osd1_update_color_key_enable(void) +{ + u32 data32; + + data32 = VSYNCOSD_RD_MPEG_REG(VIU_OSD1_BLK0_CFG_W0); + data32 &= ~(1 << 6); + data32 |= (osd_hw.color_key_enable[OSD1] << 6); + VSYNCOSD_WR_MPEG_REG(VIU_OSD1_BLK0_CFG_W0, data32); + /* + * VSYNCOSD_WR_MPEG_REG(VIU_OSD1_BLK1_CFG_W0, data32); + * VSYNCOSD_WR_MPEG_REG(VIU_OSD1_BLK2_CFG_W0, data32); + * VSYNCOSD_WR_MPEG_REG(VIU_OSD1_BLK3_CFG_W0, data32); + */ + remove_from_update_list(OSD1, OSD_COLOR_KEY_ENABLE); +} + +static void osd2_update_color_key_enable(void) +{ + u32 data32; + + data32 = VSYNCOSD_RD_MPEG_REG(VIU_OSD2_BLK0_CFG_W0); + data32 &= ~(1 << 6); + data32 |= (osd_hw.color_key_enable[OSD2] << 6); + VSYNCOSD_WR_MPEG_REG(VIU_OSD2_BLK0_CFG_W0, data32); + remove_from_update_list(OSD2, OSD_COLOR_KEY_ENABLE); +} +static void osd1_update_gbl_alpha(void) +{ + u32 data32; + + data32 = VSYNCOSD_RD_MPEG_REG(VIU_OSD1_CTRL_STAT); + data32 &= ~(0x1ff << 12); + data32 |= osd_hw.gbl_alpha[OSD1] << 12; + VSYNCOSD_WR_MPEG_REG(VIU_OSD1_CTRL_STAT, data32); + remove_from_update_list(OSD1, OSD_GBL_ALPHA); +} +static void osd2_update_gbl_alpha(void) +{ + u32 data32; + + data32 = VSYNCOSD_RD_MPEG_REG(VIU_OSD2_CTRL_STAT); + data32 &= ~(0x1ff << 12); + data32 |= osd_hw.gbl_alpha[OSD2] << 12; + VSYNCOSD_WR_MPEG_REG(VIU_OSD2_CTRL_STAT, data32); + remove_from_update_list(OSD2, OSD_GBL_ALPHA); +} +static void osd2_update_order(void) +{ + switch (osd_hw.order) { + case OSD_ORDER_01: +#ifndef CONFIG_AMLOGIC_MEDIA_FB_OSD_VSYNC_RDMA + osd_reg_clr_mask(VPP_MISC, VPP_POST_FG_OSD2 | VPP_PRE_FG_OSD2); +#endif + osd_vpp_misc &= ~(VPP_POST_FG_OSD2 | VPP_PRE_FG_OSD2); + break; + case OSD_ORDER_10: +#ifndef CONFIG_AMLOGIC_MEDIA_FB_OSD_VSYNC_RDMA + osd_reg_set_mask(VPP_MISC, VPP_POST_FG_OSD2 | VPP_PRE_FG_OSD2); +#endif + osd_vpp_misc |= (VPP_POST_FG_OSD2 | VPP_PRE_FG_OSD2); + break; + default: + break; + } + notify_to_amvideo(); + remove_from_update_list(OSD2, OSD_CHANGE_ORDER); +} +static void osd1_update_order(void) +{ + switch (osd_hw.order) { + case OSD_ORDER_01: +#ifndef CONFIG_AMLOGIC_MEDIA_FB_OSD_VSYNC_RDMA + osd_reg_clr_mask(VPP_MISC, VPP_POST_FG_OSD2 | VPP_PRE_FG_OSD2); +#endif + osd_vpp_misc &= ~(VPP_POST_FG_OSD2 | VPP_PRE_FG_OSD2); + break; + case OSD_ORDER_10: +#ifndef CONFIG_AMLOGIC_MEDIA_FB_OSD_VSYNC_RDMA + osd_reg_set_mask(VPP_MISC, VPP_POST_FG_OSD2 | VPP_PRE_FG_OSD2); +#endif + osd_vpp_misc |= (VPP_POST_FG_OSD2 | VPP_PRE_FG_OSD2); + break; + default: + break; + } + notify_to_amvideo(); + remove_from_update_list(OSD1, OSD_CHANGE_ORDER); +} + +#if 0 +static void osd_block_update_disp_geometry(u32 index) +{ + u32 data32; + u32 data_w1, data_w2, data_w3, data_w4; + u32 coef[4][2] = {{0, 0}, {1, 0}, {0, 1}, {1, 1} }; + u32 xoff, yoff; + u32 i; + u32 block_num; + + block_num = 4; + switch (osd_hw.block_mode[index] & HW_OSD_BLOCK_LAYOUT_MASK) { + case HW_OSD_BLOCK_LAYOUT_HORIZONTAL: + yoff = ((osd_hw.pandata[index].y_end & 0x1fff) - + (osd_hw.pandata[index].y_start & 0x1fff) + 1) >> 2; + data_w1 = (osd_hw.pandata[index].x_start & 0x1fff) | + (osd_hw.pandata[index].x_end & 0x1fff) << 16; + data_w3 = (osd_hw.dispdata[index].x_start & 0xfff) | + (osd_hw.dispdata[index].x_end & 0xfff) << 16; + for (i = 0; i < block_num; i++) { + if (i == 3) { + data_w2 = ((osd_hw.pandata[index].y_start + + yoff * i) & 0x1fff) + | (osd_hw.pandata[index].y_end + & 0x1fff) << 16; + data_w4 = ((osd_hw.dispdata[index].y_start + + yoff * i) & 0xfff) + | (osd_hw.dispdata[index].y_end + & 0xfff) << 16; + } else { + data_w2 = ((osd_hw.pandata[index].y_start + + yoff * i) & 0x1fff) + | ((osd_hw.pandata[index].y_start + + yoff * (i + 1) - 1) & 0x1fff) << 16; + data_w4 = ((osd_hw.dispdata[index].y_start + + yoff * i) & 0xfff) + | ((osd_hw.dispdata[index].y_start + + yoff * (i + 1) - 1) & 0xfff) << 16; + } + if (osd_hw.scan_mode == SCAN_MODE_INTERLACE) { + data32 = data_w4; + data_w4 = ((data32 & 0xfff) >> 1) | + ((((((data32 >> 16) & 0xfff) + 1) >> 1) + - 1) << 16); + } + VSYNCOSD_WR_MPEG_REG(VIU_OSD1_BLK0_CFG_W1 + (i << 4), + data_w1); + VSYNCOSD_WR_MPEG_REG(VIU_OSD1_BLK0_CFG_W2 + (i << 4), + data_w2); + VSYNCOSD_WR_MPEG_REG(VIU_OSD1_BLK0_CFG_W3 + (i << 4), + data_w3); + VSYNCOSD_WR_MPEG_REG(VIU_OSD1_BLK0_CFG_W4 + (i << 2), + data_w4); + osd_hw.block_windows[index][i << 1] = data_w1; + osd_hw.block_windows[index][(i << 1) + 1] = data_w2; + } + break; + case HW_OSD_BLOCK_LAYOUT_VERTICAL: + xoff = ((osd_hw.pandata[index].x_end & 0x1fff) + - (osd_hw.pandata[index].x_start & 0x1fff) + 1) >> 2; + data_w2 = (osd_hw.pandata[index].y_start & 0x1fff) | + (osd_hw.pandata[index].y_end & 0x1fff) << 16; + data_w4 = (osd_hw.dispdata[index].y_start & 0xfff) | + (osd_hw.dispdata[index].y_end & 0xfff) << 16; + if (osd_hw.scan_mode == SCAN_MODE_INTERLACE) { + data32 = data_w4; + data_w4 = ((data32 & 0xfff) >> 1) + | ((((((data32 >> 16) & 0xfff) + 1) >> 1) - 1) + << 16); + } + for (i = 0; i < block_num; i++) { + data_w1 = ((osd_hw.pandata[index].x_start + xoff * i) + & 0x1fff) + | ((osd_hw.pandata[index].x_start + + xoff * (i + 1) - 1) & 0x1fff) << 16; + data_w3 = ((osd_hw.dispdata[index].x_start + xoff * i) + & 0xfff) + | ((osd_hw.dispdata[index].x_start + + xoff * (i + 1) - 1) & 0xfff) << 16; + VSYNCOSD_WR_MPEG_REG(VIU_OSD1_BLK0_CFG_W1 + (i << 4), + data_w1); + VSYNCOSD_WR_MPEG_REG(VIU_OSD1_BLK0_CFG_W2 + (i << 4), + data_w2); + VSYNCOSD_WR_MPEG_REG(VIU_OSD1_BLK0_CFG_W3 + (i << 4), + data_w3); + VSYNCOSD_WR_MPEG_REG(VIU_OSD1_BLK0_CFG_W4 + (i << 2), + data_w4); + osd_hw.block_windows[index][i << 1] = data_w1; + osd_hw.block_windows[index][(i << 1) + 1] = data_w2; + } + break; + case HW_OSD_BLOCK_LAYOUT_GRID: + xoff = ((osd_hw.pandata[index].x_end & 0x1fff) - + (osd_hw.pandata[index].x_start & 0x1fff) + 1) >> 1; + yoff = ((osd_hw.pandata[index].y_end & 0x1fff) - + (osd_hw.pandata[index].y_start & 0x1fff) + 1) >> 1; + for (i = 0; i < block_num; i++) { + data_w1 = ((osd_hw.pandata[index].x_start + + xoff * coef[i][0]) & 0x1fff) + | ((osd_hw.pandata[index].x_start + + xoff * (coef[i][0] + 1) - 1) & 0x1fff) << 16; + data_w2 = ((osd_hw.pandata[index].y_start + + yoff * coef[i][1]) & 0x1fff) + | ((osd_hw.pandata[index].y_start + + yoff * (coef[i][1] + 1) - 1) & 0x1fff) << 16; + data_w3 = ((osd_hw.dispdata[index].x_start + + xoff * coef[i][0]) & 0xfff) + | ((osd_hw.dispdata[index].x_start + + xoff * (coef[i][0] + 1) - 1) & 0xfff) << 16; + data_w4 = ((osd_hw.dispdata[index].y_start + + yoff * coef[i][1]) & 0xfff) + | ((osd_hw.dispdata[index].y_start + + yoff * (coef[i][1] + 1) - 1) & 0xfff) << 16; + if (osd_hw.scan_mode == SCAN_MODE_INTERLACE) { + data32 = data_w4; + data_w4 = ((data32 & 0xfff) >> 1) + | ((((((data32 >> 16) & 0xfff) + + 1) >> 1) - 1) << 16); + } + VSYNCOSD_WR_MPEG_REG(VIU_OSD1_BLK0_CFG_W1 + (i << 4), + data_w1); + VSYNCOSD_WR_MPEG_REG(VIU_OSD1_BLK0_CFG_W2 + (i << 4), + data_w2); + VSYNCOSD_WR_MPEG_REG(VIU_OSD1_BLK0_CFG_W3 + (i << 4), + data_w3); + VSYNCOSD_WR_MPEG_REG(VIU_OSD1_BLK0_CFG_W4 + (i << 2), + data_w4); + osd_hw.block_windows[index][i << 1] = data_w1; + osd_hw.block_windows[index][(i << 1) + 1] = data_w2; + } + break; + case HW_OSD_BLOCK_LAYOUT_CUSTOMER: + for (i = 0; i < block_num; i++) { + if (((osd_hw.block_windows[index][i << 1] >> 16) + & 0x1fff) > + osd_hw.pandata[index].x_end) { + osd_hw.block_windows[index][i << 1] = + (osd_hw.block_windows[index][i << 1] + & 0x1fff) + | ((osd_hw.pandata[index].x_end + & 0x1fff) << 16); + } + data_w1 = osd_hw.block_windows[index][i << 1] + & 0x1fff1fff; + data_w2 = ((osd_hw.pandata[index].y_start & 0x1fff) + + (osd_hw.block_windows[index][(i << 1) + 1] + & 0x1fff)) + | (((osd_hw.pandata[index].y_start & 0x1fff) + << 16) + + (osd_hw.block_windows[index][(i << 1) + 1] + & 0x1fff0000)); + data_w3 = (osd_hw.dispdata[index].x_start + + (data_w1 & 0xfff)) + | (((osd_hw.dispdata[index].x_start & 0xfff) + << 16) + (data_w1 & 0xfff0000)); + data_w4 = (osd_hw.dispdata[index].y_start + + (osd_hw.block_windows[index][(i << 1) + 1] + & 0xfff)) + | (((osd_hw.dispdata[index].y_start & 0xfff) + << 16) + + (osd_hw.block_windows[index][(i << 1) + 1] + & 0xfff0000)); + if (osd_hw.scan_mode == SCAN_MODE_INTERLACE) { + data32 = data_w4; + data_w4 = ((data32 & 0xfff) >> 1) + | ((((((data32 >> 16) & 0xfff) + 1) + >> 1) - 1) << 16); + } + VSYNCOSD_WR_MPEG_REG(VIU_OSD1_BLK0_CFG_W1 + (i << 4), + data_w1); + VSYNCOSD_WR_MPEG_REG(VIU_OSD1_BLK0_CFG_W2 + (i << 4), + data_w2); + VSYNCOSD_WR_MPEG_REG(VIU_OSD1_BLK0_CFG_W3 + (i << 4), + data_w3); + VSYNCOSD_WR_MPEG_REG(VIU_OSD1_BLK0_CFG_W4 + (i << 2), + data_w4); + } + break; + default: + osd_log_err("ERROR block_mode: 0x%x\n", + osd_hw.block_mode[index]); + break; + } +} +#endif + +static void osd1_2x_scale_update_geometry(void) +{ + u32 data32; + + data32 = (osd_hw.scaledata[OSD1].x_start & 0x1fff) | + (osd_hw.scaledata[OSD1].x_end & 0x1fff) << 16; + VSYNCOSD_WR_MPEG_REG(VIU_OSD1_BLK0_CFG_W1, data32); + + if (osd_hw.osd_afbcd[OSD1].enable) { + data32 = (osd_hw.scaledata[OSD1].x_end & 0x1fff) | + (osd_hw.scaledata[OSD1].x_start & 0x1fff) << 16; + VSYNCOSD_WR_MPEG_REG(OSD1_AFBCD_PIXEL_HSCOPE, data32); + data32 = (osd_hw.scaledata[OSD1].y_end & 0x1fff) | + (osd_hw.scaledata[OSD1].y_start & 0x1fff) << 16; + VSYNCOSD_WR_MPEG_REG(OSD1_AFBCD_PIXEL_VSCOPE, data32); + VSYNCOSD_WR_MPEG_REG(OSD1_AFBCD_HDR_PTR, + osd_hw.osd_afbcd[OSD1].phy_addr >> 4); + VSYNCOSD_WR_MPEG_REG(OSD1_AFBCD_FRAME_PTR, + osd_hw.osd_afbcd[OSD1].phy_addr >> 4); + data32 = (0xe4 << 24) | + (osd_hw.osd_afbcd[OSD1].phy_addr & 0xffffff); + VSYNCOSD_WR_MPEG_REG( + OSD1_AFBCD_CHROMA_PTR, + data32); + } + + data32 = ((osd_hw.scaledata[OSD1].y_start + + osd_hw.pandata[OSD1].y_start) & 0x1fff) + | ((osd_hw.scaledata[OSD1].y_end + + osd_hw.pandata[OSD1].y_start) & 0x1fff) << 16; + VSYNCOSD_WR_MPEG_REG(VIU_OSD1_BLK0_CFG_W2, data32); + /* adjust display x-axis */ + if (osd_hw.scale[OSD1].h_enable) { + data32 = (osd_hw.dispdata[OSD1].x_start & 0xfff) + | ((osd_hw.dispdata[OSD1].x_start + + (osd_hw.scaledata[OSD1].x_end + - osd_hw.scaledata[OSD1].x_start) * 2 + 1) + & 0xfff) << 16; + VSYNCOSD_WR_MPEG_REG(VIU_OSD1_BLK0_CFG_W3, data32); + if (osd_hw.scan_mode == SCAN_MODE_INTERLACE) { + data32 = ((osd_hw.dispdata[OSD1].y_start >> 1) & 0xfff) + | (((((osd_hw.dispdata[OSD1].y_start + + (osd_hw.scaledata[OSD1].y_end + - osd_hw.scaledata[OSD1].y_start) * 2) + + 1) >> 1) - 1) & 0xfff) << 16; + } else { + data32 = (osd_hw.dispdata[OSD1].y_start & 0xfff) + | (((osd_hw.dispdata[OSD1].y_start + + (osd_hw.scaledata[OSD1].y_end + - osd_hw.scaledata[OSD1].y_start) * 2)) + & 0xfff) << 16; + } + VSYNCOSD_WR_MPEG_REG(VIU_OSD1_BLK0_CFG_W4, data32); + } + /* adjust display y-axis */ + if (osd_hw.scale[OSD1].v_enable) { + data32 = (osd_hw.dispdata[OSD1].x_start & 0xfff) + | ((osd_hw.dispdata[OSD1].x_start + + (osd_hw.scaledata[OSD1].x_end + - osd_hw.scaledata[OSD1].x_start) * 2 + 1) + & 0xfff) << 16; + VSYNCOSD_WR_MPEG_REG(VIU_OSD1_BLK0_CFG_W3, data32); + if (osd_hw.scan_mode == SCAN_MODE_INTERLACE) { + data32 = ((osd_hw.dispdata[OSD1].y_start >> 1) & 0xfff) + | (((((osd_hw.dispdata[OSD1].y_start + + (osd_hw.scaledata[OSD1].y_end + - osd_hw.scaledata[OSD1].y_start) * 2) + + 1) >> 1) - 1) & 0xfff) << 16; + } else { + data32 = (osd_hw.dispdata[OSD1].y_start & 0xfff) + | (((osd_hw.dispdata[OSD1].y_start + + (osd_hw.scaledata[OSD1].y_end + - osd_hw.scaledata[OSD1].y_start) * 2)) + & 0xfff) << 16; + } + VSYNCOSD_WR_MPEG_REG(VIU_OSD1_BLK0_CFG_W4, data32); + } +} + +static void osd1_basic_update_disp_geometry(void) +{ + u32 data32; + + data32 = (osd_hw.dispdata[OSD1].x_start & 0xfff) + | (osd_hw.dispdata[OSD1].x_end & 0xfff) << 16; + VSYNCOSD_WR_MPEG_REG(VIU_OSD1_BLK0_CFG_W3, data32); + if (osd_hw.scan_mode == SCAN_MODE_INTERLACE) + data32 = ((osd_hw.dispdata[OSD1].y_start >> 1) & 0xfff) + | ((((osd_hw.dispdata[OSD1].y_end + 1) + >> 1) - 1) & 0xfff) << 16; + else + data32 = (osd_hw.dispdata[OSD1].y_start & 0xfff) + | (osd_hw.dispdata[OSD1].y_end + & 0xfff) << 16; + VSYNCOSD_WR_MPEG_REG(VIU_OSD1_BLK0_CFG_W4, data32); + + if (osd_hw.osd_afbcd[OSD1].enable) + VSYNCOSD_WR_MPEG_REG(OSD1_AFBCD_SIZE_IN, + ((osd_hw.osd_afbcd[OSD1].frame_width + & 0xffff) << 16) | + ((osd_hw.osd_afbcd[OSD1].frame_height + & 0xffff) << 0)); + + /* enable osd 2x scale */ + if (osd_hw.scale[OSD1].h_enable || osd_hw.scale[OSD1].v_enable) { + osd1_2x_scale_update_geometry(); + } else if (osd_hw.free_scale_enable[OSD1] + && (osd_hw.free_src_data[OSD1].x_end > 0) + && (osd_hw.free_src_data[OSD1].y_end > 0)) { + /* enable osd free scale */ + data32 = (osd_hw.free_src_data[OSD1].x_start & 0x1fff) | + (osd_hw.free_src_data[OSD1].x_end & 0x1fff) << 16; + VSYNCOSD_WR_MPEG_REG(VIU_OSD1_BLK0_CFG_W1, data32); + if (osd_hw.osd_afbcd[OSD1].enable) { + data32 = + (osd_hw.free_src_data[OSD1].x_end & 0x1fff) | + (osd_hw.free_src_data[OSD1].x_start & 0x1fff) + << 16; + VSYNCOSD_WR_MPEG_REG(OSD1_AFBCD_PIXEL_HSCOPE, data32); + data32 = + (osd_hw.free_src_data[OSD1].y_end & 0x1fff) | + (osd_hw.free_src_data[OSD1].y_start & 0x1fff) + << 16; + VSYNCOSD_WR_MPEG_REG(OSD1_AFBCD_PIXEL_VSCOPE, data32); + VSYNCOSD_WR_MPEG_REG(OSD1_AFBCD_HDR_PTR, + osd_hw.osd_afbcd[OSD1].phy_addr >> 4); + VSYNCOSD_WR_MPEG_REG(OSD1_AFBCD_FRAME_PTR, + osd_hw.osd_afbcd[OSD1].phy_addr >> 4); + data32 = (0xe4 << 24) | + (osd_hw.osd_afbcd[OSD1].phy_addr & 0xffffff); + VSYNCOSD_WR_MPEG_REG( + OSD1_AFBCD_CHROMA_PTR, + data32); + } + data32 = ((osd_hw.free_src_data[OSD1].y_start + + osd_hw.pandata[OSD1].y_start) & 0x1fff) + | ((osd_hw.free_src_data[OSD1].y_end + + osd_hw.pandata[OSD1].y_start) & 0x1fff) << 16; + VSYNCOSD_WR_MPEG_REG(VIU_OSD1_BLK0_CFG_W2, data32); + } else { + /* normal mode */ + data32 = (osd_hw.pandata[OSD1].x_start & 0x1fff) + | (osd_hw.pandata[OSD1].x_end & 0x1fff) << 16; + VSYNCOSD_WR_MPEG_REG(VIU_OSD1_BLK0_CFG_W1, data32); + if (osd_hw.osd_afbcd[OSD1].enable) { + u32 virtual_y_start, virtual_y_end; + + data32 = (osd_hw.pandata[OSD1].x_end & 0x1fff) + | (osd_hw.pandata[OSD1].x_start & 0x1fff) << 16; + VSYNCOSD_WR_MPEG_REG(OSD1_AFBCD_PIXEL_HSCOPE, data32); + virtual_y_start = osd_hw.pandata[OSD1].y_start % + osd_hw.osd_afbcd[OSD1].frame_height; + virtual_y_end = osd_hw.pandata[OSD1].y_end - + osd_hw.pandata[OSD1].y_start + virtual_y_start; + data32 = (virtual_y_end & 0x1fff) | + (virtual_y_start & 0x1fff) << 16; + VSYNCOSD_WR_MPEG_REG(OSD1_AFBCD_PIXEL_VSCOPE, data32); + VSYNCOSD_WR_MPEG_REG(OSD1_AFBCD_HDR_PTR, + osd_hw.osd_afbcd[OSD1].phy_addr >> 4); + VSYNCOSD_WR_MPEG_REG(OSD1_AFBCD_FRAME_PTR, + osd_hw.osd_afbcd[OSD1].phy_addr >> 4); + data32 = (0xe4 << 24) | + (osd_hw.osd_afbcd[OSD1].phy_addr & 0xffffff); + VSYNCOSD_WR_MPEG_REG( + OSD1_AFBCD_CHROMA_PTR, + data32); + } + data32 = (osd_hw.pandata[OSD1].y_start & 0x1fff) + | (osd_hw.pandata[OSD1].y_end & 0x1fff) << 16; + VSYNCOSD_WR_MPEG_REG(VIU_OSD1_BLK0_CFG_W2, data32); + } + + if (osd_hw.osd_afbcd[OSD1].enable && + !osd_afbc_dec_enable && + osd_hw.osd_afbcd[OSD1].phy_addr != 0) { + VSYNCOSD_WR_MPEG_REG(OSD1_AFBCD_ENABLE, 0x8100); + osd_afbc_dec_enable = 1; + } + data32 = VSYNCOSD_RD_MPEG_REG(VIU_OSD1_CTRL_STAT); + data32 &= ~0x1ff00e; + data32 |= osd_hw.gbl_alpha[OSD1] << 12; + /* data32 |= HW_OSD_BLOCK_ENABLE_0; */ + VSYNCOSD_WR_MPEG_REG(VIU_OSD1_CTRL_STAT, data32); +} + +static void osd1_update_disp_geometry(void) +{ + if ((osd_hw.block_mode[OSD1]) && + (get_cpu_type() <= MESON_CPU_MAJOR_ID_GXBB)) { + /* multi block */ + /* + * osd_block_update_disp_geometry(OSD1); + * data32 = VSYNCOSD_RD_MPEG_REG(VIU_OSD1_CTRL_STAT); + * data32 &= 0xfffffff0; + * data32 |= (osd_hw.block_mode[OSD1] + * & HW_OSD_BLOCK_ENABLE_MASK); + * VSYNCOSD_WR_MPEG_REG(VIU_OSD1_CTRL_STAT, data32); + */ + osd_log_info( + "osd1_update_disp_geometry: not support block mode\n"); + } else { + /* single block */ + osd1_basic_update_disp_geometry(); + } + remove_from_update_list(OSD1, DISP_GEOMETRY); +} + +static void osd2_update_disp_geometry(void) +{ + u32 data32; + + data32 = (osd_hw.dispdata[OSD2].x_start & 0xfff) + | (osd_hw.dispdata[OSD2].x_end & 0xfff) << 16; + VSYNCOSD_WR_MPEG_REG(VIU_OSD2_BLK0_CFG_W3, data32); + if (osd_hw.scan_mode == SCAN_MODE_INTERLACE) + data32 = (osd_hw.dispdata[OSD2].y_start & 0xfff) + | ((((osd_hw.dispdata[OSD2].y_end + 1 + - osd_hw.dispdata[OSD2].y_start) >> 1) + + osd_hw.dispdata[OSD2].y_start - 1) + & 0xfff) << 16; + else + data32 = (osd_hw.dispdata[OSD2].y_start & 0xfff) + | (osd_hw.dispdata[OSD2].y_end & 0xfff) << 16; + VSYNCOSD_WR_MPEG_REG(VIU_OSD2_BLK0_CFG_W4, data32); + if (osd_hw.scale[OSD2].h_enable || osd_hw.scale[OSD2].v_enable) { +#if defined(CONFIG_AMLOGIC_MEDIA_FB_OSD2_CURSOR) + data32 = (osd_hw.pandata[OSD2].x_start & 0x1fff) + | (osd_hw.pandata[OSD2].x_end & 0x1fff) << 16; + VSYNCOSD_WR_MPEG_REG(VIU_OSD2_BLK0_CFG_W1, data32); + data32 = (osd_hw.pandata[OSD2].y_start & 0x1fff) + | (osd_hw.pandata[OSD2].y_end & 0x1fff) << 16; + VSYNCOSD_WR_MPEG_REG(VIU_OSD2_BLK0_CFG_W2, data32); +#else + data32 = (osd_hw.scaledata[OSD2].x_start & 0x1fff) | + (osd_hw.scaledata[OSD2].x_end & 0x1fff) << 16; + VSYNCOSD_WR_MPEG_REG(VIU_OSD2_BLK0_CFG_W1, data32); + data32 = ((osd_hw.scaledata[OSD2].y_start + + osd_hw.pandata[OSD2].y_start) & 0x1fff) + | ((osd_hw.scaledata[OSD2].y_end + + osd_hw.pandata[OSD2].y_start) & 0x1fff) << 16; + VSYNCOSD_WR_MPEG_REG(VIU_OSD2_BLK0_CFG_W2, data32); +#endif + } else if (osd_hw.free_scale_enable[OSD2] + && (osd_hw.free_src_data[OSD2].x_end > 0) + && (osd_hw.free_src_data[OSD2].y_end > 0)) { + /* enable osd free scale */ + data32 = (osd_hw.free_src_data[OSD2].x_start & 0x1fff) + | (osd_hw.free_src_data[OSD2].x_end & 0x1fff) << 16; + VSYNCOSD_WR_MPEG_REG(VIU_OSD2_BLK0_CFG_W1, data32); + data32 = ((osd_hw.free_src_data[OSD2].y_start + + osd_hw.pandata[OSD2].y_start) & 0x1fff) + | ((osd_hw.free_src_data[OSD2].y_end + + osd_hw.pandata[OSD2].y_start) & 0x1fff) << 16; + VSYNCOSD_WR_MPEG_REG(VIU_OSD2_BLK0_CFG_W2, data32); + } else { + data32 = (osd_hw.pandata[OSD2].x_start & 0x1fff) + | (osd_hw.pandata[OSD2].x_end & 0x1fff) << 16; + VSYNCOSD_WR_MPEG_REG(VIU_OSD2_BLK0_CFG_W1, data32); + data32 = (osd_hw.pandata[OSD2].y_start & 0x1fff) + | (osd_hw.pandata[OSD2].y_end & 0x1fff) << 16; + VSYNCOSD_WR_MPEG_REG(VIU_OSD2_BLK0_CFG_W2, data32); + } + data32 = VSYNCOSD_RD_MPEG_REG(VIU_OSD2_CTRL_STAT); + data32 &= ~0x1ff000; + data32 |= osd_hw.gbl_alpha[OSD2] << 12; + /* data32 |= HW_OSD_BLOCK_ENABLE_0; */ + VSYNCOSD_WR_MPEG_REG(VIU_OSD2_CTRL_STAT, data32); + remove_from_update_list(OSD2, DISP_GEOMETRY); +} + +static void osd1_update_disp_3d_mode(void) +{ + /*step 1 . set pan data */ + /* only called by vsync irq or rdma irq */ + u32 data32; + + if (osd_hw.mode_3d[OSD1].left_right == OSD_LEFT) { + data32 = (osd_hw.mode_3d[OSD1].l_start & 0x1fff) + | (osd_hw.mode_3d[OSD1].l_end & 0x1fff) << 16; + VSYNCOSD_IRQ_WR_MPEG_REG(VIU_OSD1_BLK0_CFG_W1, data32); + } else { + data32 = (osd_hw.mode_3d[OSD1].r_start & 0x1fff) + | (osd_hw.mode_3d[OSD1].r_end & 0x1fff) << 16; + VSYNCOSD_IRQ_WR_MPEG_REG(VIU_OSD1_BLK0_CFG_W1, data32); + } + osd_hw.mode_3d[OSD1].left_right ^= 1; +} +static void osd2_update_disp_3d_mode(void) +{ + /* only called by vsync irq or rdma irq */ + u32 data32; + + if (osd_hw.mode_3d[OSD2].left_right == OSD_LEFT) { + data32 = (osd_hw.mode_3d[OSD2].l_start & 0x1fff) + | (osd_hw.mode_3d[OSD2].l_end & 0x1fff) << 16; + VSYNCOSD_IRQ_WR_MPEG_REG(VIU_OSD2_BLK0_CFG_W1, data32); + } else { + data32 = (osd_hw.mode_3d[OSD2].r_start & 0x1fff) + | (osd_hw.mode_3d[OSD2].r_end & 0x1fff) << 16; + VSYNCOSD_IRQ_WR_MPEG_REG(VIU_OSD2_BLK0_CFG_W1, data32); + } + osd_hw.mode_3d[OSD2].left_right ^= 1; +} + +static void osd1_update_fifo(void) +{ + u32 data32; + + data32 = osd_hw.urgent[OSD1] & 1; + data32 |= 4 << 5; /* hold_fifo_lines */ + /* burst_len_sel: 3=64 */ + data32 |= 3 << 10; + /* fifo_depth_val: 32*8=256 */ + data32 |= 32 << 12; + /* if (get_cpu_type() >= MESON_CPU_MAJOR_ID_GXBB) */ + /* + * bit 23:22, fifo_ctrl + * 00 : for 1 word in 1 burst + * 01 : for 2 words in 1 burst + * 10 : for 4 words in 1 burst + * 11 : reserved + */ + data32 |= 2 << 22; + /* bit 28:24, fifo_lim */ + data32 |= 2 << 24; + VSYNCOSD_WR_MPEG_REG(VIU_OSD1_FIFO_CTRL_STAT, data32); + remove_from_update_list(OSD1, OSD_FIFO); +} + +static void osd2_update_fifo(void) +{ + u32 data32; + + data32 = osd_hw.urgent[OSD2] & 1; + data32 |= 4 << 5; /* hold_fifo_lines */ + /* burst_len_sel: 3=64 */ + data32 |= 3 << 10; + /* fifo_depth_val: 32*8=256 */ + data32 |= 32 << 12; + /* if (get_cpu_type() >= MESON_CPU_MAJOR_ID_GXBB) */ + /* + * bit 23:22, fifo_ctrl + * 00 : for 1 word in 1 burst + * 01 : for 2 words in 1 burst + * 10 : for 4 words in 1 burst + * 11 : reserved + */ + data32 |= 2 << 22; + /* bit 28:24, fifo_lim */ + data32 |= 2 << 24; + VSYNCOSD_WR_MPEG_REG(VIU_OSD2_FIFO_CTRL_STAT, data32); + remove_from_update_list(OSD2, OSD_FIFO); +} + +void osd_init_scan_mode(void) +{ +#define VOUT_ENCI 1 +#define VOUT_ENCP 2 +#define VOUT_ENCT 3 + unsigned int output_type = 0; + + output_type = osd_reg_read(VPU_VIU_VENC_MUX_CTRL) & 0x3; + osd_hw.scan_mode = SCAN_MODE_PROGRESSIVE; + switch (output_type) { + case VOUT_ENCP: + if (osd_reg_read(ENCP_VIDEO_MODE) & (1 << 12)) /* 1080i */ + osd_hw.scan_mode = SCAN_MODE_INTERLACE; + break; + case VOUT_ENCI: + if (osd_reg_read(ENCI_VIDEO_EN) & 1) + osd_hw.scan_mode = SCAN_MODE_INTERLACE; + break; + } +} + +void osd_init_hw(u32 logo_loaded) +{ + u32 group, idx, data32; + int err_num = 0; + + osd_vpu_power_on(); + + if (get_cpu_type() == + MESON_CPU_MAJOR_ID_GXTVBB) + backup_regs_init(HW_RESET_AFBCD_REGS); + else if (get_cpu_type() == + MESON_CPU_MAJOR_ID_GXM) + backup_regs_init(HW_RESET_OSD1_REGS); + else if ((get_cpu_type() >= MESON_CPU_MAJOR_ID_GXL) + && (get_cpu_type() <= MESON_CPU_MAJOR_ID_TXL)) + backup_regs_init(HW_RESET_OSD1_REGS); + else + backup_regs_init(HW_RESET_NONE); + + recovery_regs_init(); + for (group = 0; group < HW_OSD_COUNT; group++) + for (idx = 0; idx < HW_REG_INDEX_MAX; idx++) + osd_hw.reg[group][idx].update_func = + hw_func_array[group][idx]; + osd_hw.updated[OSD1] = 0; + osd_hw.updated[OSD2] = 0; + osd_hw.urgent[OSD1] = 1; + osd_hw.urgent[OSD2] = 1; +#ifdef CONFIG_AMLOGIC_VECM + osd_hdr_on = false; +#endif + osd_hw.hw_reset_flag = HW_RESET_NONE; + + /* here we will init default value ,these value only set once . */ + if (!logo_loaded) { + /* init vpu fifo control register */ + data32 = osd_reg_read(VPP_OFIFO_SIZE); + if ((get_cpu_type() == MESON_CPU_MAJOR_ID_GXTVBB) || + (get_cpu_type() == MESON_CPU_MAJOR_ID_GXM)) + data32 |= 0xfff; + else + data32 |= 0x77f; + osd_reg_write(VPP_OFIFO_SIZE, data32); + data32 = 0x08080808; + osd_reg_write(VPP_HOLD_LINES, data32); + + /* init osd fifo control register + * set DDR request priority to be urgent + */ + data32 = 1; + data32 |= 4 << 5; /* hold_fifo_lines */ + /* burst_len_sel: 3=64 */ + data32 |= 3 << 10; + /* fifo_depth_val: 32*8=256 */ + data32 |= 32 << 12; + if (get_cpu_type() >= MESON_CPU_MAJOR_ID_GXBB) { + /* + * bit 23:22, fifo_ctrl + * 00 : for 1 word in 1 burst + * 01 : for 2 words in 1 burst + * 10 : for 4 words in 1 burst + * 11 : reserved + */ + data32 |= 2 << 22; + /* bit 28:24, fifo_lim */ + data32 |= 2 << 24; + } + osd_reg_write(VIU_OSD1_FIFO_CTRL_STAT, data32); + osd_reg_write(VIU_OSD2_FIFO_CTRL_STAT, data32); + osd_reg_set_mask(VPP_MISC, VPP_POSTBLEND_EN); + osd_reg_clr_mask(VPP_MISC, VPP_PREBLEND_EN); + osd_vpp_misc = + osd_reg_read(VPP_MISC) & OSD_RELATIVE_BITS; + osd_vpp_misc &= + ~(VPP_OSD1_POSTBLEND | VPP_OSD2_POSTBLEND); + notify_to_amvideo(); + osd_reg_clr_mask(VPP_MISC, + VPP_OSD1_POSTBLEND | VPP_OSD2_POSTBLEND); + /* just disable osd to avoid booting hang up */ + data32 = 0x1 << 0; + data32 |= OSD_GLOBAL_ALPHA_DEF << 12; + osd_reg_write(VIU_OSD1_CTRL_STAT, data32); + osd_reg_write(VIU_OSD2_CTRL_STAT, data32); + } + osd_vpp_misc = + osd_reg_read(VPP_MISC) & OSD_RELATIVE_BITS; +#if defined(CONFIG_AMLOGIC_MEDIA_FB_OSD2_CURSOR) + osd_vpp_misc |= (VPP_POST_FG_OSD2 | VPP_PRE_FG_OSD2); + notify_to_amvideo(); + osd_reg_set_mask(VPP_MISC, VPP_POST_FG_OSD2 | VPP_PRE_FG_OSD2); + osd_hw.order = OSD_ORDER_10; +#else + osd_vpp_misc &= ~(VPP_POST_FG_OSD2 | VPP_PRE_FG_OSD2); + notify_to_amvideo(); + osd_reg_clr_mask(VPP_MISC, VPP_POST_FG_OSD2 | VPP_PRE_FG_OSD2); + osd_hw.order = OSD_ORDER_01; +#endif + osd_hw.enable[OSD2] = osd_hw.enable[OSD1] = DISABLE; + osd_hw.fb_gem[OSD1].canvas_idx = OSD1_CANVAS_INDEX; + osd_hw.fb_gem[OSD2].canvas_idx = OSD2_CANVAS_INDEX; + osd_hw.gbl_alpha[OSD1] = OSD_GLOBAL_ALPHA_DEF; + osd_hw.gbl_alpha[OSD2] = OSD_GLOBAL_ALPHA_DEF; + osd_hw.color_info[OSD1] = NULL; + osd_hw.color_info[OSD2] = NULL; + osd_hw.color_key[OSD1] = osd_hw.color_key[OSD2] = 0xffffffff; + osd_hw.free_scale_enable[OSD1] = osd_hw.free_scale_enable[OSD2] = 0; + osd_hw.scale[OSD1].h_enable = osd_hw.scale[OSD1].v_enable = 0; + osd_hw.scale[OSD2].h_enable = osd_hw.scale[OSD2].v_enable = 0; + osd_hw.mode_3d[OSD2].enable = osd_hw.mode_3d[OSD1].enable = 0; + osd_hw.block_mode[OSD1] = osd_hw.block_mode[OSD2] = 0; + osd_hw.free_scale[OSD1].h_enable = 0; + osd_hw.free_scale[OSD1].h_enable = 0; + osd_hw.free_scale[OSD2].v_enable = 0; + osd_hw.free_scale[OSD2].v_enable = 0; + osd_hw.osd_reverse[OSD1] = REVERSE_FALSE; + osd_hw.osd_reverse[OSD2] = REVERSE_FALSE; + /* + * osd_hw.rotation_pandata[OSD1].x_start = 0; + * osd_hw.rotation_pandata[OSD1].y_start = 0; + * osd_hw.rotation_pandata[OSD2].x_start = 0; + * osd_hw.rotation_pandata[OSD2].y_start = 0; + */ + osd_hw.antiflicker_mode = 0; + osd_hw.color_key_enable[OSD1] = 0; + osd_hw.color_key_enable[OSD2] = 0; + osd_hw.free_src_data[OSD1].x_start = 0; + osd_hw.free_src_data[OSD1].x_end = 0; + osd_hw.free_src_data[OSD1].y_start = 0; + osd_hw.free_src_data[OSD1].y_end = 0; + osd_hw.free_src_data[OSD2].x_start = 0; + osd_hw.free_src_data[OSD2].x_end = 0; + osd_hw.free_src_data[OSD2].y_start = 0; + osd_hw.free_src_data[OSD2].y_end = 0; + osd_hw.free_scale_mode[OSD1] = 0; + osd_hw.free_scale_mode[OSD2] = 1; + if (get_cpu_type() == MESON_CPU_MAJOR_ID_GXM) + osd_reg_write(VPP_OSD_SC_DUMMY_DATA, 0x002020ff); + else if (get_cpu_type() == + MESON_CPU_MAJOR_ID_GXTVBB) + osd_reg_write(VPP_OSD_SC_DUMMY_DATA, 0xff); + else + osd_reg_write(VPP_OSD_SC_DUMMY_DATA, 0x008080ff); + /* osd_hw.osd_afbcd[OSD1].enable = 0; + * osd_hw.osd_afbcd[OSD2].enable = 0; + */ + /* memset(osd_hw.rotate, 0, sizeof(struct osd_rotate_s)); */ + +#ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD_SYNC_FENCE + INIT_LIST_HEAD(&post_fence_list); + mutex_init(&post_fence_list_lock); +#endif +#ifdef FIQ_VSYNC + osd_hw.fiq_handle_item.handle = vsync_isr; + osd_hw.fiq_handle_item.key = (u32)vsync_isr; + osd_hw.fiq_handle_item.name = "osd_vsync"; + if (register_fiq_bridge_handle(&osd_hw.fiq_handle_item)) +#else + err_num = request_irq(int_viu_vsync, &vsync_isr, + IRQF_SHARED, "osd-vsync", osd_setup_hw); + if (err_num) +#endif + osd_log_err("can't request irq for vsync,err_num=%d\n", + -err_num); +#ifdef FIQ_VSYNC + request_fiq(INT_VIU_VSYNC, &osd_fiq_isr); +#endif + +#ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD_VSYNC_RDMA + osd_rdma_enable(1); +#endif + + osd_init_hw_flag = 1; +} + +#if defined(CONFIG_AMLOGIC_MEDIA_FB_OSD2_CURSOR) +void osd_cursor_hw(u32 index, s16 x, s16 y, s16 xstart, s16 ystart, u32 osd_w, + u32 osd_h) +{ + struct pandata_s disp_tmp; + + if (index != 1) + return; + + osd_log_dbg2("cursor: x=%d, y=%d, x0=%d, y0=%d, w=%d, h=%d\n", + x, y, xstart, ystart, osd_w, osd_h); + + if (osd_hw.free_scale_mode[OSD1]) { + if (osd_hw.free_scale_enable[OSD1]) + memcpy(&disp_tmp, &osd_hw.cursor_dispdata[OSD1], + sizeof(struct pandata_s)); + else + memcpy(&disp_tmp, &osd_hw.dispdata[OSD1], + sizeof(struct pandata_s)); + } else + memcpy(&disp_tmp, &osd_hw.dispdata[OSD1], + sizeof(struct pandata_s)); + if (osd_hw.scale[OSD2].h_enable && (osd_hw.scaledata[OSD2].x_start > 0) + && (osd_hw.scaledata[OSD2].x_end > 0)) { + x = x * osd_hw.scaledata[OSD2].x_end / + osd_hw.scaledata[OSD2].x_start; + if (osd_hw.scaledata[OSD2].x_end > + osd_hw.scaledata[OSD2].x_start) { + disp_tmp.x_start = osd_hw.dispdata[OSD1].x_start * + osd_hw.scaledata[OSD2].x_end / + osd_hw.scaledata[OSD2].x_start; + disp_tmp.x_end = osd_hw.dispdata[OSD1].x_end * + osd_hw.scaledata[OSD2].x_end / + osd_hw.scaledata[OSD2].x_start; + } + } + if (osd_hw.scale[OSD2].v_enable && (osd_hw.scaledata[OSD2].y_start > 0) + && (osd_hw.scaledata[OSD2].y_end > 0)) { + y = y * osd_hw.scaledata[OSD2].y_end / + osd_hw.scaledata[OSD2].y_start; + if (osd_hw.scaledata[OSD2].y_end > + osd_hw.scaledata[OSD2].y_start) { + disp_tmp.y_start = osd_hw.dispdata[OSD1].y_start * + osd_hw.scaledata[OSD2].y_end / + osd_hw.scaledata[OSD2].y_start; + disp_tmp.y_end = osd_hw.dispdata[OSD1].y_end * + osd_hw.scaledata[OSD2].y_end / + osd_hw.scaledata[OSD2].y_start; + } + } + x += xstart; + y += ystart; + /* + * Use pandata to show a partial cursor when it is at the edge because + * the registers can't have negative values and because we need to + * manually clip the cursor when it is past the edge. The edge is + * hardcoded to the OSD0 area. + */ + osd_hw.dispdata[OSD2].x_start = x; + osd_hw.dispdata[OSD2].y_start = y; + if (x < disp_tmp.x_start) { + /* if negative position, set osd to 0,y and pan. */ + if ((disp_tmp.x_start - x) < osd_w) { + osd_hw.pandata[OSD2].x_start = disp_tmp.x_start - x; + osd_hw.pandata[OSD2].x_end = osd_w - 1; + } + osd_hw.dispdata[OSD2].x_start = 0; + } else { + osd_hw.pandata[OSD2].x_start = 0; + if (x + osd_w > disp_tmp.x_end) { + /* + * if past positive edge, + * set osd to inside of the edge and pan. + */ + if (x < disp_tmp.x_end) + osd_hw.pandata[OSD2].x_end = disp_tmp.x_end - x; + } else + osd_hw.pandata[OSD2].x_end = osd_w - 1; + } + if (y < disp_tmp.y_start) { + if ((disp_tmp.y_start - y) < osd_h) { + osd_hw.pandata[OSD2].y_start = disp_tmp.y_start - y; + osd_hw.pandata[OSD2].y_end = osd_h - 1; + } + osd_hw.dispdata[OSD2].y_start = 0; + } else { + osd_hw.pandata[OSD2].y_start = 0; + if (y + osd_h > disp_tmp.y_end) { + if (y < disp_tmp.y_end) + osd_hw.pandata[OSD2].y_end = disp_tmp.y_end - y; + } else + osd_hw.pandata[OSD2].y_end = osd_h - 1; + } + osd_hw.dispdata[OSD2].x_end = osd_hw.dispdata[OSD2].x_start + + osd_hw.pandata[OSD2].x_end - osd_hw.pandata[OSD2].x_start; + osd_hw.dispdata[OSD2].y_end = osd_hw.dispdata[OSD2].y_start + + osd_hw.pandata[OSD2].y_end - osd_hw.pandata[OSD2].y_start; + add_to_update_list(OSD2, OSD_COLOR_MODE); + add_to_update_list(OSD2, DISP_GEOMETRY); +} +#endif /* CONFIG_AMLOGIC_MEDIA_FB_OSD2_CURSOR */ + +void osd_suspend_hw(void) +{ + osd_hw.reg_status_save = osd_reg_read(VPP_MISC) & OSD_RELATIVE_BITS; + osd_vpp_misc &= ~OSD_RELATIVE_BITS; + notify_to_amvideo(); + osd_reg_clr_mask(VPP_MISC, OSD_RELATIVE_BITS); + /* VSYNCOSD_CLR_MPEG_REG_MASK(VPP_MISC, OSD_RELATIVE_BITS); */ + osd_log_info("osd_suspended\n"); +} + +void osd_resume_hw(void) +{ + if (osd_hw.reg_status_save & + (VPP_OSD1_POSTBLEND | VPP_OSD2_POSTBLEND)) + osd_hw.reg_status_save |= VPP_POSTBLEND_EN; + osd_vpp_misc = osd_hw.reg_status_save & OSD_RELATIVE_BITS; + notify_to_amvideo(); + osd_reg_set_mask(VPP_MISC, osd_hw.reg_status_save); + /* VSYNCOSD_SET_MPEG_REG_MASK(VPP_MISC, osd_hw.reg_status_save); */ + osd_log_info("osd_resumed\n"); +} + +void osd_shutdown_hw(void) +{ +#ifdef CONFIG_VSYNC_RDMA + enable_rdma(0); +#endif +#ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD_VSYNC_RDMA + osd_rdma_enable(0); +#endif + pr_info("osd_shutdown\n"); +} + +#ifdef CONFIG_HIBERNATION +static unsigned int fb0_cfg_w0_save; +static u32 __nosavedata free_scale_enable[HW_OSD_COUNT]; + +void osd_realdata_save_hw(void) +{ + free_scale_enable[OSD1] = osd_hw.free_scale_enable[OSD1]; + free_scale_enable[OSD2] = osd_hw.free_scale_enable[OSD2]; +} + +void osd_realdata_restore_hw(void) +{ + osd_hw.free_scale_enable[OSD1] = free_scale_enable[OSD1]; + osd_hw.free_scale_enable[OSD2] = free_scale_enable[OSD2]; +} + +void osd_freeze_hw(void) +{ +#ifdef CONFIG_AMLOGIC_MEDIA_VSYNC_RDMA + enable_rdma(0); +#endif +#ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD_VSYNC_RDMA + osd_rdma_enable(0); + if (get_backup_reg(VIU_OSD1_BLK0_CFG_W0, + &fb0_cfg_w0_save) != 0) + fb0_cfg_w0_save = + osd_reg_read(VIU_OSD1_BLK0_CFG_W0); +#else + fb0_cfg_w0_save = osd_reg_read(VIU_OSD1_BLK0_CFG_W0); +#endif + pr_debug("osd_freezed\n"); +} +void osd_thaw_hw(void) +{ + pr_debug("osd_thawed\n"); +#ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD_VSYNC_RDMA + osd_rdma_enable(2); +#endif +#ifdef CONFIG_AMLOGIC_MEDIA_VSYNC_RDMA + enable_rdma(1); +#endif +} +void osd_restore_hw(void) +{ + osd_reg_write(VIU_OSD1_BLK0_CFG_W0, fb0_cfg_w0_save); +#ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD_VSYNC_RDMA + osd_rdma_enable(2); +#endif +#ifdef CONFIG_AMLOGIC_MEDIA_VSYNC_RDMA + enable_rdma(1); +#endif + canvas_config(osd_hw.fb_gem[0].canvas_idx, + osd_hw.fb_gem[0].addr, + osd_hw.fb_gem[0].width, + osd_hw.fb_gem[0].height, + CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR); + pr_debug("osd_restored\n"); +} +#endif + +int osd_get_logo_index(void) +{ + return osd_logo_index; +} + +void osd_set_logo_index(int index) +{ + osd_logo_index = index; +} + +int osd_get_init_hw_flag(void) +{ + return osd_init_hw_flag; +} + +void osd_get_hw_para(struct hw_para_s **para) +{ + *para = &osd_hw; +} diff --git a/drivers/amlogic/media/osd/osd_hw.h b/drivers/amlogic/media/osd/osd_hw.h new file mode 100644 index 000000000000..2171732f4748 --- /dev/null +++ b/drivers/amlogic/media/osd/osd_hw.h @@ -0,0 +1,148 @@ +/* + * drivers/amlogic/media/osd/osd_hw.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 _OSD_HW_H_ +#define _OSD_HW_H_ + +#include +#include "osd.h" + +#define REG_OFFSET (0x20) +#define OSD_RELATIVE_BITS 0x33330 +#ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD_VSYNC_RDMA +#include "osd_rdma.h" +#endif + +extern int int_viu_vsync; + +#ifdef CONFIG_HIBERNATION +extern void osd_freeze_hw(void); +extern void osd_thaw_hw(void); +extern void osd_restore_hw(void); +extern void osd_realdata_save_hw(void); +extern void osd_realdata_restore_hw(void); +#endif +extern void osd_set_color_key_hw(u32 index, u32 bpp, u32 colorkey); +extern void osd_srckey_enable_hw(u32 index, u8 enable); +extern void osd_set_gbl_alpha_hw(u32 index, u32 gbl_alpha); +extern u32 osd_get_gbl_alpha_hw(u32 index); +extern void osd_set_color_mode(u32 index, + const struct color_bit_define_s *color); +extern void osd_update_disp_axis_hw( + u32 index, + u32 display_h_start, + u32 display_h_end, + u32 display_v_start, + u32 display_v_end, + u32 xoffset, + u32 yoffset, + u32 mode_change); +extern void osd_setup_hw(u32 index, + struct osd_ctl_s *osd_ctl, + u32 xoffset, + u32 yoffset, + u32 xres, + u32 yres, + u32 xres_virtual, + u32 yres_virtual, + u32 disp_start_x, + u32 disp_start_y, + u32 disp_end_x, + u32 disp_end_y, + u32 fbmem, + phys_addr_t *afbc_fbmem, + const struct color_bit_define_s *color); +extern void osd_set_order_hw(u32 index, u32 order); +extern void osd_get_order_hw(u32 index, u32 *order); +extern void osd_set_free_scale_enable_hw(u32 index, u32 enable); +extern void osd_get_free_scale_enable_hw(u32 index, u32 *free_scale_enable); +extern void osd_set_free_scale_mode_hw(u32 index, u32 freescale_mode); +extern void osd_get_free_scale_mode_hw(u32 index, u32 *freescale_mode); +extern void osd_set_4k2k_fb_mode_hw(u32 fb_for_4k2k); +extern void osd_get_free_scale_mode_hw(u32 index, u32 *freescale_mode); +extern void osd_get_free_scale_width_hw(u32 index, u32 *free_scale_width); +extern void osd_get_free_scale_height_hw(u32 index, u32 *free_scale_height); +extern void osd_get_free_scale_axis_hw(u32 index, s32 *x0, s32 *y0, s32 *x1, + s32 *y1); +extern void osd_set_free_scale_axis_hw(u32 index, s32 x0, s32 y0, s32 x1, + s32 y1); +extern void osd_get_scale_axis_hw(u32 index, s32 *x0, s32 *y0, s32 *x1, + s32 *y1); +extern void osd_get_window_axis_hw(u32 index, s32 *x0, s32 *y0, s32 *x1, + s32 *y1); +extern void osd_set_window_axis_hw(u32 index, s32 x0, s32 y0, s32 x1, s32 y1); +extern void osd_set_scale_axis_hw(u32 index, s32 x0, s32 y0, s32 x1, s32 y1); +extern void osd_get_block_windows_hw(u32 index, u32 *windows); +extern void osd_set_block_windows_hw(u32 index, u32 *windows); +extern void osd_get_block_mode_hw(u32 index, u32 *mode); +extern void osd_set_block_mode_hw(u32 index, u32 mode); +extern void osd_enable_3d_mode_hw(u32 index, u32 enable); +extern void osd_set_2x_scale_hw(u32 index, u16 h_scale_enable, + u16 v_scale_enable); +extern void osd_get_flush_rate_hw(u32 *break_rate); +extern void osd_set_reverse_hw(u32 index, u32 reverse); +extern void osd_get_reverse_hw(u32 index, u32 *reverse); +extern void osd_set_antiflicker_hw(u32 index, struct vinfo_s *vinfo, u32 yres); +extern void osd_get_antiflicker_hw(u32 index, u32 *on_off); +extern void osd_get_angle_hw(u32 index, u32 *angle); +extern void osd_set_angle_hw(u32 index, u32 angle, u32 virtual_osd1_yres, + u32 virtual_osd2_yres); +extern void osd_get_clone_hw(u32 index, u32 *clone); +extern void osd_set_clone_hw(u32 index, u32 clone); +extern void osd_set_update_pan_hw(u32 index); +extern void osd_setpal_hw(u32 index, unsigned int regno, + unsigned int red, unsigned int green, + unsigned int blue, unsigned int transp); +extern void osd_enable_hw(u32 index, u32 enable); +extern void osd_pan_display_hw(u32 index, unsigned int xoffset, + unsigned int yoffset); +extern int osd_sync_request(u32 index, u32 yres, u32 xoffset, u32 yoffset, + s32 in_fence_fd); +extern s32 osd_wait_vsync_event(void); +#if defined(CONFIG_AMLOGIC_MEDIA_FB_OSD2_CURSOR) +extern void osd_cursor_hw(u32 index, s16 x, s16 y, s16 xstart, s16 ystart, + u32 osd_w, u32 osd_h); +#endif +extern void osd_init_scan_mode(void); +extern void osd_suspend_hw(void); +extern void osd_resume_hw(void); +extern void osd_shutdown_hw(void); +extern void osd_init_hw(u32 logo_loaded); +extern void osd_init_scan_mode(void); +extern void osd_set_logo_index(int index); +extern int osd_get_logo_index(void); +extern int osd_get_init_hw_flag(void); +extern void osd_get_hw_para(struct hw_para_s **para); +extern int osd_set_debug_hw(const char *buf); +extern char *osd_get_debug_hw(void); +#ifdef CONFIG_AMLOGIC_MEDIA_VSYNC_RDMA +extern void enable_rdma(int enable_flag); +#endif + +#ifdef CONFIG_AM_FB_EXT +extern void osd_ext_clone_pan(u32 index); +#endif +extern void osd_set_pxp_mode(u32 mode); +extern void osd_set_afbc(u32 enable); +extern u32 osd_get_afbc(void); +extern u32 osd_get_reset_status(void); +extern void osd_switch_free_scale( + u32 pre_index, u32 pre_enable, u32 pre_scale, + u32 next_index, u32 next_enable, u32 next_scale); +extern void osd_get_urgent(u32 index, u32 *urgent); +extern void osd_set_urgent(u32 index, u32 urgent); +#endif diff --git a/drivers/amlogic/media/osd/osd_hw_def.h b/drivers/amlogic/media/osd/osd_hw_def.h new file mode 100644 index 000000000000..96f076fd56ef --- /dev/null +++ b/drivers/amlogic/media/osd/osd_hw_def.h @@ -0,0 +1,140 @@ +/* + * drivers/amlogic/media/osd/osd_hw_def.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 _OSD_HW_DEF_H_ +#define _OSD_HW_DEF_H_ + +#include +#include "osd_hw.h" + +static void osd1_update_color_mode(void); +static void osd1_update_enable(void); +static void osd1_update_color_key(void); +static void osd1_update_color_key_enable(void); +static void osd1_update_gbl_alpha(void); +static void osd1_update_order(void); +static void osd1_update_disp_geometry(void); +static void osd1_update_coef(void); +static void osd1_update_disp_freescale_enable(void); +static void osd1_update_disp_osd_reverse(void); +static void osd1_update_disp_osd_rotate(void); +static void osd1_update_disp_scale_enable(void); +static void osd1_update_disp_3d_mode(void); +static void osd1_update_fifo(void); + +static void osd2_update_color_mode(void); +static void osd2_update_enable(void); +static void osd2_update_color_key(void); +static void osd2_update_color_key_enable(void); +static void osd2_update_gbl_alpha(void); +static void osd2_update_order(void); +static void osd2_update_disp_geometry(void); +static void osd2_update_coef(void); +static void osd2_update_disp_freescale_enable(void); +static void osd2_update_disp_osd_reverse(void); +static void osd2_update_disp_osd_rotate(void); +static void osd2_update_disp_scale_enable(void); +static void osd2_update_disp_3d_mode(void); +static void osd2_update_fifo(void); + +LIST_HEAD(update_list); +static DEFINE_SPINLOCK(osd_lock); +static unsigned long lock_flags; +#ifdef FIQ_VSYNC +static unsigned long fiq_flag; +#endif +static update_func_t hw_func_array[HW_OSD_COUNT][HW_REG_INDEX_MAX] = { + { + osd1_update_color_mode, + osd1_update_enable, + osd1_update_color_key, + osd1_update_color_key_enable, + osd1_update_gbl_alpha, + osd1_update_order, + osd1_update_coef, + osd1_update_disp_geometry, + osd1_update_disp_scale_enable, + osd1_update_disp_freescale_enable, + osd1_update_disp_osd_reverse, + osd1_update_disp_osd_rotate, + osd1_update_fifo, + }, + { + osd2_update_color_mode, + osd2_update_enable, + osd2_update_color_key, + osd2_update_color_key_enable, + osd2_update_gbl_alpha, + osd2_update_order, + osd2_update_coef, + osd2_update_disp_geometry, + osd2_update_disp_scale_enable, + osd2_update_disp_freescale_enable, + osd2_update_disp_osd_reverse, + osd2_update_disp_osd_rotate, + osd2_update_fifo, + }, +}; + +#ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD_VSYNC_RDMA +#ifdef FIQ_VSYNC +#define add_to_update_list(osd_idx, cmd_idx) \ + do { \ + spin_lock_irqsave(&osd_lock, lock_flags); \ + raw_local_save_flags(fiq_flag); \ + local_fiq_disable(); \ + osd_hw.reg[osd_idx][cmd_idx].update_func(); \ + raw_local_irq_restore(fiq_flag); \ + spin_unlock_irqrestore(&osd_lock, lock_flags); \ + } while (0) +#else +#define add_to_update_list(osd_idx, cmd_idx) \ + do { \ + spin_lock_irqsave(&osd_lock, lock_flags); \ + osd_hw.reg[osd_idx][cmd_idx].update_func(); \ + spin_unlock_irqrestore(&osd_lock, lock_flags); \ + } while (0) +#endif +#else +#ifdef FIQ_VSYNC +#define add_to_update_list(osd_idx, cmd_idx) \ + do { \ + spin_lock_irqsave(&osd_lock, lock_flags); \ + raw_local_save_flags(fiq_flag); \ + local_fiq_disable(); \ + osd_hw.updated[osd_idx] |= (1< + +#include "osd_log.h" +#include "osd_backup.h" + +static inline uint32_t osd_cbus_read(uint32_t reg) +{ + uint32_t ret = 0; + + ret = (uint32_t)aml_read_cbus(reg); + osd_log_dbg3("%s(0x%x)=0x%x\n", __func__, reg, ret); + + return ret; +}; + +static inline void osd_cbus_write(uint32_t reg, + const uint32_t val) +{ + uint32_t ret = 0; + + aml_write_cbus(reg, val); + ret = aml_read_cbus(reg); + osd_log_dbg3("%s(0x%x, 0x%x)=0x%x\n", __func__, reg, val, ret); +}; + + +static inline uint32_t osd_reg_read(uint32_t reg) +{ + uint32_t ret = 0; + + /* if (get_backup_reg(reg, &ret) != 0) */ + /* not read from bakcup */ + ret = (uint32_t)aml_read_vcbus(reg); + osd_log_dbg3("%s(0x%x)=0x%x\n", __func__, reg, ret); + + return ret; +}; + +static inline void osd_reg_write(uint32_t reg, + const uint32_t val) +{ + aml_write_vcbus(reg, val); + update_backup_reg(reg, val); + osd_log_dbg3("%s(0x%x, 0x%x)\n", __func__, reg, val); +}; + +static inline void osd_reg_set_mask(uint32_t reg, + const uint32_t mask) +{ + osd_reg_write(reg, (osd_reg_read(reg) | (mask))); +} + +static inline void osd_reg_clr_mask(uint32_t reg, + const uint32_t mask) +{ + osd_reg_write(reg, (osd_reg_read(reg) & (~(mask)))); +} + +static inline void osd_reg_set_bits(uint32_t reg, + const uint32_t value, + const uint32_t start, + const uint32_t len) +{ + osd_reg_write(reg, ((osd_reg_read(reg) & + ~(((1L << (len)) - 1) << (start))) | + (((value) & ((1L << (len)) - 1)) << (start)))); +} + +#ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD_VSYNC_RDMA +u32 VSYNCOSD_RD_MPEG_REG(u32 reg); +int VSYNCOSD_WR_MPEG_REG(u32 reg, u32 val); +int VSYNCOSD_WR_MPEG_REG_BITS(u32 reg, u32 val, u32 start, u32 len); +int VSYNCOSD_SET_MPEG_REG_MASK(u32 reg, u32 mask); +int VSYNCOSD_CLR_MPEG_REG_MASK(u32 reg, u32 mask); + +int VSYNCOSD_IRQ_WR_MPEG_REG(u32 reg, u32 val); +#else +#define VSYNCOSD_RD_MPEG_REG(reg) osd_reg_read(reg) +#define VSYNCOSD_WR_MPEG_REG(reg, val) osd_reg_write(reg, val) +#define VSYNCOSD_WR_MPEG_REG_BITS(reg, val, start, len) \ + osd_reg_set_bits(reg, val, start, len) +#define VSYNCOSD_SET_MPEG_REG_MASK(reg, mask) osd_reg_set_mask(reg, mask) +#define VSYNCOSD_CLR_MPEG_REG_MASK(reg, mask) osd_reg_clr_mask(reg, mask) + +#define VSYNCOSD_IRQ_WR_MPEG_REG(reg, val) osd_reg_write(reg, val) +#endif + +#endif diff --git a/drivers/amlogic/media/osd/osd_log.h b/drivers/amlogic/media/osd/osd_log.h new file mode 100644 index 000000000000..003654c2e57e --- /dev/null +++ b/drivers/amlogic/media/osd/osd_log.h @@ -0,0 +1,61 @@ +/* + * drivers/amlogic/media/osd/osd_log.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 _OSD_LOG_H_ +#define _OSD_LOG_H_ + +#include +#include + +#define OSD_LOG_LEVEL_NULL 0 +#define OSD_LOG_LEVEL_DEBUG 1 +#define OSD_LOG_LEVEL_DEBUG2 2 +#define OSD_LOG_LEVEL_DEBUG3 3 + +extern unsigned int osd_log_level; + +#undef pr_fmt +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#define osd_log_info(fmt, ...) \ + pr_info(fmt, ##__VA_ARGS__) + +#define osd_log_err(fmt, ...) \ + pr_err(fmt, ##__VA_ARGS__) + +#define osd_log_dbg(fmt, ...) \ + do { \ + if (osd_log_level >= OSD_LOG_LEVEL_DEBUG) { \ + pr_info(fmt, ##__VA_ARGS__); \ + } \ + } while (0) + +#define osd_log_dbg2(fmt, ...) \ + do { \ + if (osd_log_level >= OSD_LOG_LEVEL_DEBUG2) { \ + pr_info(fmt, ##__VA_ARGS__); \ + } \ + } while (0) + +#define osd_log_dbg3(fmt, ...) \ + do { \ + if (osd_log_level >= OSD_LOG_LEVEL_DEBUG3) { \ + pr_info(fmt, ##__VA_ARGS__); \ + } \ + } while (0) + +#endif diff --git a/drivers/amlogic/media/osd/osd_progressbar.c b/drivers/amlogic/media/osd/osd_progressbar.c new file mode 100644 index 000000000000..6db96f2ea494 --- /dev/null +++ b/drivers/amlogic/media/osd/osd_progressbar.c @@ -0,0 +1,252 @@ +/* + * drivers/amlogic/media/osd/osd_progressbar.c + * + * Copyright (C) 2017 Amlogic, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "osd_canvas.h" +#include "osd_fb.h" +#include "osd_hw.h" +#include "osd_io.h" +#include "osd_reg.h" + +struct src_dst_info_s { + struct rectangle_s src_rect; + struct rectangle_s dst_rect; + unsigned int color; +}; + +struct osd_progress_bar_s { + struct ge2d_context_s *ge2d_context; + const struct vinfo_s *vinfo; + struct src_dst_info_s op_info; + u32 bar_border; + u32 bar_width; + u32 bar_height; +}; + +static struct osd_progress_bar_s progress_bar; +static struct config_para_s ge2d_config; +static struct ge2d_context_s *ge2d_context; + +static int init_fb1_first(const struct vinfo_s *vinfo) +{ + struct osd_ctl_s osd_ctl; + const struct color_bit_define_s *color; + u32 reg = 0, data32 = 0; + size_t osd_size; + void __iomem *osd_vaddr; + + osd_ctl.index = 1; + color = &default_color_format_array[31]; + + osd_ctl.addr = get_fb_rmem_paddr(osd_ctl.index); + osd_vaddr = get_fb_rmem_vaddr(osd_ctl.index); + osd_size = get_fb_rmem_size(osd_ctl.index); + + osd_ctl.xres = vinfo->width; + osd_ctl.yres = vinfo->height; + osd_ctl.xres_virtual = osd_ctl.xres; + osd_ctl.yres_virtual = osd_ctl.yres; + osd_ctl.disp_start_x = 0; + osd_ctl.disp_end_x = osd_ctl.xres - 1; + osd_ctl.disp_start_y = (vinfo->height * 9) / 10; + osd_ctl.disp_end_y = osd_ctl.yres - 1; + + reg = osd_ctl.index == 0 ? VIU_OSD1_BLK0_CFG_W0 : VIU_OSD2_BLK0_CFG_W0; + data32 = VSYNCOSD_RD_MPEG_REG(reg) & (~(0xf<<8)); + data32 |= color->hw_blkmode << 8; /* osd_blk_mode */ + VSYNCOSD_WR_MPEG_REG(reg, data32); + + memset(osd_vaddr, 0, osd_size); + pr_debug("addr is 0x%08x, xres is %d, yres is %d\n", + osd_ctl.addr, osd_ctl.xres, osd_ctl.yres); + osd_setup_hw(osd_ctl.index, + &osd_ctl, + 0, + 0, + osd_ctl.xres, + osd_ctl.yres, + osd_ctl.xres_virtual, + osd_ctl.yres_virtual, + osd_ctl.disp_start_x, + osd_ctl.disp_start_y, + osd_ctl.disp_end_x, + osd_ctl.disp_end_y, + osd_ctl.addr, + NULL, + color); + + return 0; +} + +int osd_show_progress_bar(u32 percent) +{ + static u32 progress; + u32 step = 1; + /* wait_queue_head_t wait_head; */ + struct osd_fb_dev_s *fb_dev; + struct ge2d_context_s *context = progress_bar.ge2d_context; + struct src_dst_info_s *op_info = &progress_bar.op_info; + + if (context == NULL) { + /* osd_init_progress_bar(); */ + pr_debug("context is NULL\n"); + return -1; + } + fb_dev = gp_fbdev_list[1]; + if (fb_dev == NULL) { + pr_debug("fb1 should exit!!!"); + return -EFAULT; + } + + while (progress < percent) { + pr_debug("progress is %d, x: [%d], y: [%d], w: [%d], h: [%d]\n", + progress, op_info->dst_rect.x, op_info->dst_rect.y, + op_info->dst_rect.w, op_info->dst_rect.h); + + + fillrect(context, op_info->dst_rect.x, + op_info->dst_rect.y, + op_info->dst_rect.w, + op_info->dst_rect.h, + op_info->color); + + /* wait_event_interruptible_timeout(wait_head,0,4); */ + progress += step; + op_info->dst_rect.x += op_info->dst_rect.w; + op_info->color -= (0xff*step/100) << 16; + } + + if (percent == 100) { + progress = 0; + osd_blank(1, fb_dev->fb_info); + destroy_ge2d_work_queue(progress_bar.ge2d_context); + } + + return 0; +} +EXPORT_SYMBOL(osd_show_progress_bar); + +int osd_init_progress_bar(void) +{ + struct src_dst_info_s *op_info = &progress_bar.op_info; + const struct vinfo_s *vinfo = progress_bar.vinfo; + struct osd_fb_dev_s *fb_dev; + struct canvas_s cs; + struct config_para_s *cfg = &ge2d_config; + struct ge2d_context_s *context = ge2d_context; + u32 step = 1; + + memset(&progress_bar, 0, sizeof(struct osd_progress_bar_s)); + + vinfo = get_current_vinfo(); + + progress_bar.bar_border = + (((vinfo->field_height ? + vinfo->field_height : + vinfo->height) * 4 / 720)>>2)<<2; + progress_bar.bar_width = + (((vinfo->width * 200 / 1280)>>2)<<2) + progress_bar.bar_border; + progress_bar.bar_height = + (((vinfo->field_height ? + vinfo->field_height : + vinfo->height) * 32 / 720) >> 2) << 2; + + if (!init_fb1_first(vinfo)) { + fb_dev = gp_fbdev_list[1]; + if (fb_dev == NULL) { + pr_debug("fb1 should exit!!!"); + return -EFAULT; + } + + canvas_read(OSD2_CANVAS_INDEX, &cs); + context = create_ge2d_work_queue(); + if (!context) { + pr_debug("create work queue error\n"); + return -EFAULT; + } + + memset(cfg, 0, sizeof(struct config_para_s)); + cfg->src_dst_type = OSD1_OSD1; + cfg->src_format = GE2D_FORMAT_S32_ARGB; + cfg->src_planes[0].addr = cs.addr; + cfg->src_planes[0].w = cs.width / 4; + cfg->src_planes[0].h = cs.height; + cfg->dst_planes[0].addr = cs.addr; + cfg->dst_planes[0].w = cs.width / 4; + cfg->dst_planes[0].h = cs.height; + + if (ge2d_context_config(context, cfg) < 0) { + pr_debug("ge2d config error.\n"); + return -EFAULT; + } + + if (context == NULL) { + pr_debug("ge2d_context is NULL!!!!!!\n"); + return -EFAULT; + } + progress_bar.ge2d_context = context; + pr_debug("progress bar setup ge2d device OK\n"); + /* show fb1 */ + console_lock(); + osd_blank(0, fb_dev->fb_info); + console_unlock(); + op_info->color = 0x555555ff; + op_info->dst_rect.x = + (vinfo->width / 2) - progress_bar.bar_width; + op_info->dst_rect.y = 0; + op_info->dst_rect.w = progress_bar.bar_width * 2; + op_info->dst_rect.h = progress_bar.bar_height; + + pr_debug("fill==dst:%d-%d-%d-%d\n", + op_info->dst_rect.x, op_info->dst_rect.y, + op_info->dst_rect.w, op_info->dst_rect.h); + + fillrect(context, op_info->dst_rect.x, + op_info->dst_rect.y, + op_info->dst_rect.w, + op_info->dst_rect.h, + op_info->color); + } else { + pr_debug("fb1 init failed, exit!!!"); + return -EFAULT; + } + + /* initial op info before draw actrualy */ + op_info->dst_rect.x += progress_bar.bar_border; + op_info->dst_rect.y += progress_bar.bar_border; + op_info->dst_rect.w = + (progress_bar.bar_width - progress_bar.bar_border) + * 2 * step/100; + op_info->dst_rect.h = + progress_bar.bar_height - progress_bar.bar_border * 2; + op_info->color = 0xffffff; + + return 0; +} +EXPORT_SYMBOL(osd_init_progress_bar); + diff --git a/drivers/amlogic/media/osd/osd_prot.c b/drivers/amlogic/media/osd/osd_prot.c new file mode 100644 index 000000000000..953f7edc5305 --- /dev/null +++ b/drivers/amlogic/media/osd/osd_prot.c @@ -0,0 +1,125 @@ +/* + * drivers/amlogic/media/osd/osd_prot.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. + * + */ + +/* Linux Headers */ +#include +#include +#include +#include + +/* Local Headers */ +#include + +/* Local Headers */ +#include "osd_hw.h" +#include "osd_io.h" +#include "osd_reg.h" +#include "osd_prot.h" + +int osd_set_prot(unsigned char x_rev, + unsigned char y_rev, + unsigned char bytes_per_pixel, + unsigned char conv_422to444, + unsigned char little_endian, + unsigned int hold_lines, + unsigned int x_start, + unsigned int x_end, + unsigned int y_start, + unsigned int y_end, + unsigned int y_len_m1, + unsigned char y_step, + unsigned char pat_start_ptr, + unsigned char pat_end_ptr, + unsigned long pat_val, + unsigned int canv_addr, + unsigned int cid_val, + unsigned char cid_mode, + unsigned char cugt, + unsigned char req_onoff_en, + unsigned int req_on_max, + unsigned int req_off_min, + unsigned char osd_index, + unsigned char on) +{ + unsigned long data32; + + if (!on) { + /* no one use prot1. */ + VSYNCOSD_CLR_MPEG_REG_MASK(VPU_PROT1_MMC_CTRL, 0xf << 12); + VSYNCOSD_CLR_MPEG_REG_MASK(VPU_PROT1_CLK_GATE, 1 << 0); + if (osd_index == OSD1) { + /* switch back to little endian */ + VSYNCOSD_WR_MPEG_REG_BITS(VIU_OSD1_BLK0_CFG_W0, + 1, 15, 1); + VSYNCOSD_WR_MPEG_REG(VIU_OSD1_PROT_CTRL, 0); + } else if (osd_index == OSD2) { + /* switch back to little endian */ + VSYNCOSD_WR_MPEG_REG_BITS(VIU_OSD2_BLK0_CFG_W0, + 1, 15, 1); + VSYNCOSD_WR_MPEG_REG(VIU_OSD2_PROT_CTRL, 0); + } + return 0; + } + if (osd_index == OSD1) { + /* bit[12..15] OSD1 OSD2 OSD3 OSD4 */ + VSYNCOSD_WR_MPEG_REG_BITS(VPU_PROT1_MMC_CTRL, 1, 12, 4); + VSYNCOSD_WR_MPEG_REG(VIU_OSD1_PROT_CTRL, 1 << 15 | y_len_m1); + /* before rotate set big endian */ + VSYNCOSD_CLR_MPEG_REG_MASK(VIU_OSD1_BLK0_CFG_W0, 1 << 15); + } else if (osd_index == OSD2) { + VSYNCOSD_WR_MPEG_REG_BITS(VPU_PROT1_MMC_CTRL, 2, 12, 4); + /* bit[12..15] OSD1 OSD2 OSD3 OSD4 */ + VSYNCOSD_WR_MPEG_REG(VIU_OSD2_PROT_CTRL, 1 << 15 | y_len_m1); + /* before rotate set big endian */ + VSYNCOSD_CLR_MPEG_REG_MASK(VIU_OSD2_BLK0_CFG_W0, 1 << 15); + } + data32 = (x_end << 16) | + (x_start << 0); + VSYNCOSD_WR_MPEG_REG(VPU_PROT1_X_START_END, data32); + data32 = (y_end << 16) | + (y_start << 0); + VSYNCOSD_WR_MPEG_REG(VPU_PROT1_Y_START_END, data32); + data32 = (y_step << 16) | + (y_len_m1 << 0); + VSYNCOSD_WR_MPEG_REG(VPU_PROT1_Y_LEN_STEP, data32); + data32 = (pat_start_ptr << 4) | + (pat_end_ptr << 0); + VSYNCOSD_WR_MPEG_REG(VPU_PROT1_RPT_LOOP, data32); + VSYNCOSD_WR_MPEG_REG(VPU_PROT1_RPT_PAT, pat_val); + data32 = (cugt << 20) | + (cid_mode << 16) | + (cid_val << 8) | + (canv_addr << 0); + VSYNCOSD_WR_MPEG_REG(VPU_PROT1_DDR, data32); + data32 = (hold_lines << 8) | + (little_endian << 7) | + (conv_422to444 << 6) | + (bytes_per_pixel << 4) | + (y_rev << 3) | + (x_rev << 2) | + (1 << + 0); + /* [1:0] req_en: 0=Idle; 1=Rotate mode; 2=FIFO mode. */ + VSYNCOSD_WR_MPEG_REG(VPU_PROT1_GEN_CNTL, data32); + data32 = (req_onoff_en << 31) | + (req_off_min << 16) | + (req_on_max << 0); + VSYNCOSD_WR_MPEG_REG(VPU_PROT1_REQ_ONOFF, data32); + /* Enable clock */ + VSYNCOSD_WR_MPEG_REG(VPU_PROT1_CLK_GATE, 1); + return 0; +} diff --git a/drivers/amlogic/media/osd/osd_prot.h b/drivers/amlogic/media/osd/osd_prot.h new file mode 100644 index 000000000000..900645e1a8c2 --- /dev/null +++ b/drivers/amlogic/media/osd/osd_prot.h @@ -0,0 +1,59 @@ +/* + * drivers/amlogic/media/osd/osd_prot.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 _OSD_PROT_H_ +#define _OSD_PROT_H_ + +#include "osd_hw.h" + +#define CUGT 0 +#define CID_VALUE 161 +#define CID_MODE 6 +#define REQ_ONOFF_EN 0 +#define REQ_ON_MAX 0 +#define REQ_OFF_MIN 0 +#define PAT_VAL 0x00000000 +#define PAT_START_PTR 1 +#define PAT_END_PTR 1 +#define HOLD_LINES 14 +#define Y_STEP 0 + +extern int osd_set_prot(unsigned char x_rev, + unsigned char y_rev, + unsigned char bytes_per_pixel, + unsigned char conv_422to444, + unsigned char little_endian, + unsigned int hold_lines, + unsigned int x_start, + unsigned int x_end, + unsigned int y_start, + unsigned int y_end, + unsigned int y_len_m1, + unsigned char y_step, + unsigned char pat_start_ptr, + unsigned char pat_end_ptr, + unsigned long pat_val, + unsigned int canv_addr, + unsigned int cid_val, + unsigned char cid_mode, + unsigned char cugt, + unsigned char req_onoff_en, + unsigned int req_on_max, + unsigned int req_off_min, + unsigned char osd_index, + unsigned char on_off); +#endif diff --git a/drivers/amlogic/media/osd/osd_rdma.c b/drivers/amlogic/media/osd/osd_rdma.c new file mode 100644 index 000000000000..94705f03abc1 --- /dev/null +++ b/drivers/amlogic/media/osd/osd_rdma.c @@ -0,0 +1,1120 @@ +/* + * drivers/amlogic/media/osd/osd_rdma.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. + * + */ + +/* Linux Headers */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Local Headers */ +#include +#include "osd.h" +#include "osd_io.h" +#include "osd_reg.h" +#include "osd_rdma.h" +#include "osd_hw.h" +#include "osd_backup.h" +#ifdef CONFIG_AMLOGIC_MEDIA_RDMA +#include +#ifdef CONFIG_AMLOGIC_VECM +#include +#endif +#endif + +#if 0 +#ifndef CONFIG_AMLOGIC_MEDIA_RDMA +int rdma_mgr_irq_request; +int rdma_reset_tigger_flag; +#define OSD_RDMA_ISR +#endif +#endif + +#define RDMA_TABLE_INTERNAL_COUNT 512 + +static DEFINE_SPINLOCK(rdma_lock); +static struct rdma_table_item *rdma_table; +static struct device *osd_rdma_dev; +static struct page *table_pages; +static void *osd_rdma_table_virt; +static dma_addr_t osd_rdma_table_phy; +static u32 table_paddr; +static void *table_vaddr; +static u32 rdma_enable; +static u32 item_count; +static u32 rdma_debug; +static bool osd_rdma_init_flag; +#define OSD_RDMA_UPDATE_RETRY_COUNT 100 +static unsigned int debug_rdma_status; +static unsigned int rdma_irq_count; +static unsigned int rdma_lost_count; +static unsigned int dump_reg_trigger; +static unsigned int rdma_recovery_count; +#ifdef OSD_RDMA_ISR +static unsigned int second_rdma_irq; +#endif + +static int osd_rdma_handle = -1; + +static int osd_rdma_init(void); + +static inline void osd_rdma_mem_cpy(struct rdma_table_item *dst, + struct rdma_table_item *src, u32 len) +{ + asm volatile( + " stp x5, x6, [sp, #-16]!\n" + " cmp %2,#8\n" + " bne 1f\n" + " ldr x5, [%0]\n" + " str x5, [%1]\n" + " b 2f\n" + "1: ldp x5, x6, [%0]\n" + " stp x5, x6, [%1]\n" + "2: nop\n" + " ldp x5, x6, [sp], #16\n" + : + : "r" (src), "r" (dst), "r" (len) + : "x5", "x6"); +} + +static inline void reset_rdma_table(void) +{ + struct rdma_table_item *temp_tbl = NULL; + struct rdma_table_item request_item; + unsigned long flags; + u32 old_count; + u32 end_addr; + int i, j = 0; + struct rdma_table_item reset_item[2] = { + { + .addr = OSD_RDMA_FLAG_REG, + .val = OSD_RDMA_STATUS_MARK_TBL_RST, + }, + { + .addr = OSD_RDMA_FLAG_REG, + .val = OSD_RDMA_STATUS_MARK_TBL_DONE, + } + }; + + spin_lock_irqsave(&rdma_lock, flags); + if (!OSD_RDMA_STATUS_IS_REJECT) { + u32 val, mask; + int iret; + + if (item_count > 2) + temp_tbl = kzalloc( + sizeof(struct rdma_table_item) + * item_count, GFP_KERNEL); + end_addr = osd_reg_read(END_ADDR) + 1; + if (end_addr > table_paddr) + old_count = (end_addr - table_paddr) >> 3; + else + old_count = 0; + osd_reg_write(END_ADDR, table_paddr - 1); + + for (i = (int)(item_count - 1); + i >= 0; i--) { + if (!temp_tbl) + break; + if (rdma_table[i].addr == + OSD_RDMA_FLAG_REG) + continue; + if (rdma_table[i].addr == + VPP_MISC) + continue; + iret = get_recovery_item( + rdma_table[i].addr, + &val, &mask); + if (!iret) { + request_item.addr = + rdma_table[i].addr; + request_item.val = val; + osd_rdma_mem_cpy( + &temp_tbl[j], &request_item, 8); + j++; + pr_debug( + "recovery -- 0x%04x:0x%08x, mask:0x%08x\n", + rdma_table[i].addr, + val, mask); + rdma_recovery_count++; + } else if ((iret < 0) && (i >= old_count)) { + request_item.addr = + rdma_table[i].addr; + request_item.val = + rdma_table[i].val; + osd_rdma_mem_cpy( + &temp_tbl[j], &request_item, 8); + j++; + pr_debug( + "recovery -- 0x%04x:0x%08x, mask:0x%08x\n", + rdma_table[i].addr, + rdma_table[i].val, + mask); + pr_debug( + "recovery -- i:%d, item_count:%d, old_count:%d\n", + i, item_count, old_count); + rdma_recovery_count++; + } + } + for (i = 0; i < j; i++) { + osd_rdma_mem_cpy( + &rdma_table[1 + i], + &temp_tbl[j - i - 1], 8); + update_recovery_item( + temp_tbl[j - i - 1].addr, + temp_tbl[j - i - 1].val); + } + item_count = j + 2; + osd_rdma_mem_cpy(rdma_table, &reset_item[0], 8); + osd_rdma_mem_cpy(&rdma_table[item_count - 1], + &reset_item[1], 8); + osd_reg_write(END_ADDR, + (table_paddr + item_count * 8 - 1)); + kfree(temp_tbl); + } + spin_unlock_irqrestore(&rdma_lock, flags); +} + +static int update_table_item(u32 addr, u32 val, u8 irq_mode) +{ + unsigned long flags; + int retry_count = OSD_RDMA_UPDATE_RETRY_COUNT; + struct rdma_table_item request_item; + int reject1 = 0, reject2 = 0, ret = 0; + u32 paddr; + + if (item_count > 500) { + /* rdma table is full */ + pr_info("update_table_item overflow!\n"); + return -1; + } + /* pr_debug("%02dth, ctrl: 0x%x, status: 0x%x, auto:0x%x, flag:0x%x\n", + * item_count, osd_reg_read(RDMA_CTRL), + * osd_reg_read(RDMA_STATUS), + * osd_reg_read(RDMA_ACCESS_AUTO), + * osd_reg_read(OSD_RDMA_FLAG_REG)); + */ +retry: + if (0 == (retry_count--)) { + pr_debug("OSD RDMA stuck: 0x%x = 0x%x, status: 0x%x\n", + addr, val, osd_reg_read(RDMA_STATUS)); + pr_debug("::retry count: %d-%d, count: %d, flag: 0x%x\n", + reject1, reject2, item_count, + osd_reg_read(OSD_RDMA_FLAG_REG)); + spin_lock_irqsave(&rdma_lock, flags); + request_item.addr = OSD_RDMA_FLAG_REG; + request_item.val = OSD_RDMA_STATUS_MARK_TBL_DONE; + osd_rdma_mem_cpy( + &rdma_table[item_count], + &request_item, 8); + request_item.addr = addr; + request_item.val = val; + update_backup_reg(addr, val); + update_recovery_item(addr, val); + osd_rdma_mem_cpy( + &rdma_table[item_count - 1], + &request_item, 8); + item_count++; + spin_unlock_irqrestore(&rdma_lock, flags); + return -1; + } + + if ((OSD_RDMA_STATUS_IS_REJECT) && (irq_mode)) { + /* should not be here. Using the wrong write function + * or rdma isr is block + */ + pr_info("update reg but rdma running, mode: %d\n", + irq_mode); + return -2; + } + + if ((OSD_RDMA_STATUS_IS_REJECT) && (!irq_mode)) { + /* should not be here. Using the wrong write function + * or rdma isr is block + */ + reject1++; + pr_debug("update reg but rdma running, mode: %d,", + irq_mode); + pr_debug("retry count:%d (%d), flag: 0x%x, status: 0x%x\n", + retry_count, reject1, + osd_reg_read(OSD_RDMA_FLAG_REG), + osd_reg_read(RDMA_STATUS)); + goto retry; + } + + /*atom_lock_start:*/ + spin_lock_irqsave(&rdma_lock, flags); + request_item.addr = OSD_RDMA_FLAG_REG; + request_item.val = OSD_RDMA_STATUS_MARK_TBL_DONE; + osd_rdma_mem_cpy(&rdma_table[item_count], &request_item, 8); + request_item.addr = addr; + request_item.val = val; + update_backup_reg(addr, val); + update_recovery_item(addr, val); + osd_rdma_mem_cpy(&rdma_table[item_count - 1], &request_item, 8); + item_count++; + paddr = table_paddr + item_count * 8 - 1; + if (!OSD_RDMA_STATUS_IS_REJECT) { + osd_reg_write(END_ADDR, paddr); + } else if (!irq_mode) { + reject2++; + pr_debug("need update ---, but rdma running,"); + pr_debug("retry count:%d (%d), flag: 0x%x, status: 0x%x\n", + retry_count, reject2, + osd_reg_read(OSD_RDMA_FLAG_REG), + osd_reg_read(RDMA_STATUS)); + item_count--; + spin_unlock_irqrestore(&rdma_lock, flags); + goto retry; + } else + ret = -3; + /*atom_lock_end:*/ + spin_unlock_irqrestore(&rdma_lock, flags); + return ret; +} + +static inline u32 read_reg_internal(u32 addr) +{ + int i; + u32 val = 0; + + if (rdma_enable) { + for (i = (int)(item_count - 1); + i >= 0; i--) { + if (addr == rdma_table[i].addr) { + val = rdma_table[i].val; + break; + } + } + if (i >= 0) + return val; + } + return osd_reg_read(addr); +} + +static inline int wrtie_reg_internal(u32 addr, u32 val) +{ + struct rdma_table_item request_item; + + if (!rdma_enable) { + osd_reg_write(addr, val); + return 0; + } + + if (item_count > 500) { + /* rdma table is full */ + pr_info("wrtie_reg_internal overflow!\n"); + return -1; + } + /* TODO remove the Done write operation to save the time */ + request_item.addr = OSD_RDMA_FLAG_REG; + request_item.val = OSD_RDMA_STATUS_MARK_TBL_DONE; + osd_rdma_mem_cpy( + &rdma_table[item_count], + &request_item, 8); + request_item.addr = addr; + request_item.val = val; + update_backup_reg(addr, val); + update_recovery_item(addr, val); + osd_rdma_mem_cpy( + &rdma_table[item_count - 1], + &request_item, 8); + item_count++; + return 0; +} + +u32 VSYNCOSD_RD_MPEG_REG(u32 addr) +{ + int i; + bool find = false; + u32 val = 0; + unsigned long flags; + + if (rdma_enable) { + spin_lock_irqsave(&rdma_lock, flags); + /* 1st, read from rdma table */ + for (i = (int)(item_count - 1); + i >= 0; i--) { + if (addr == rdma_table[i].addr) { + val = rdma_table[i].val; + break; + } + } + if (i >= 0) + find = true; + else if (get_backup_reg(addr, &val) == 0) + find = true; + /* 2nd, read from backup reg */ + spin_unlock_irqrestore(&rdma_lock, flags); + if (find) + return val; + } + /* 3rd, read from osd reg */ + return osd_reg_read(addr); +} +EXPORT_SYMBOL(VSYNCOSD_RD_MPEG_REG); + +int VSYNCOSD_WR_MPEG_REG(u32 addr, u32 val) +{ + int ret = 0; + + if (rdma_enable) + ret = update_table_item(addr, val, 0); + else + osd_reg_write(addr, val); + return ret; +} +EXPORT_SYMBOL(VSYNCOSD_WR_MPEG_REG); + +int VSYNCOSD_WR_MPEG_REG_BITS(u32 addr, u32 val, u32 start, u32 len) +{ + unsigned long read_val; + unsigned long write_val; + int ret = 0; + + if (rdma_enable) { + read_val = VSYNCOSD_RD_MPEG_REG(addr); + write_val = (read_val & ~(((1L << (len)) - 1) << (start))) + | ((unsigned int)(val) << (start)); + ret = update_table_item(addr, write_val, 0); + } else + osd_reg_set_bits(addr, val, start, len); + return ret; +} +EXPORT_SYMBOL(VSYNCOSD_WR_MPEG_REG_BITS); + +int VSYNCOSD_SET_MPEG_REG_MASK(u32 addr, u32 _mask) +{ + unsigned long read_val; + unsigned long write_val; + int ret = 0; + + if (rdma_enable) { + read_val = VSYNCOSD_RD_MPEG_REG(addr); + write_val = read_val | _mask; + ret = update_table_item(addr, write_val, 0); + } else + osd_reg_set_mask(addr, _mask); + return ret; +} +EXPORT_SYMBOL(VSYNCOSD_SET_MPEG_REG_MASK); + +int VSYNCOSD_CLR_MPEG_REG_MASK(u32 addr, u32 _mask) +{ + unsigned long read_val; + unsigned long write_val; + int ret = 0; + + if (rdma_enable) { + read_val = VSYNCOSD_RD_MPEG_REG(addr); + write_val = read_val & (~_mask); + ret = update_table_item(addr, write_val, 0); + } else + osd_reg_clr_mask(addr, _mask); + return ret; +} +EXPORT_SYMBOL(VSYNCOSD_CLR_MPEG_REG_MASK); + +int VSYNCOSD_IRQ_WR_MPEG_REG(u32 addr, u32 val) +{ + int ret = 0; + + if (rdma_enable) + ret = update_table_item(addr, val, 1); + else + osd_reg_write(addr, val); + return ret; +} +EXPORT_SYMBOL(VSYNCOSD_IRQ_WR_MPEG_REG); + +/* number lines before vsync for reset */ +static unsigned int reset_line; +module_param(reset_line, uint, 0664); +MODULE_PARM_DESC(reset_line, "reset_line"); + +static unsigned int disable_osd_rdma_reset; +module_param(disable_osd_rdma_reset, uint, 0664); +MODULE_PARM_DESC(disable_osd_rdma_reset, "disable_osd_rdma_reset"); + +#ifdef CONFIG_AMLOGIC_MEDIA_RDMA +static int osd_reset_rdma_handle = -1; + +void set_reset_rdma_trigger_line(void) +{ + int trigger_line; + + switch (aml_read_vcbus(VPU_VIU_VENC_MUX_CTRL) & 0x3) { + case 0: + trigger_line = aml_read_vcbus(ENCL_VIDEO_VAVON_ELINE) + - aml_read_vcbus(ENCL_VIDEO_VSO_BLINE) - reset_line; + break; + case 1: + if ((aml_read_vcbus(ENCI_VIDEO_MODE) & 1) == 0) + trigger_line = 260; /* 480i */ + else + trigger_line = 310; /* 576i */ + break; + case 2: + if (aml_read_vcbus(ENCP_VIDEO_MODE) & (1 << 12)) + trigger_line = aml_read_vcbus(ENCP_DE_V_END_EVEN); + else + trigger_line = aml_read_vcbus(ENCP_VIDEO_VAVON_ELINE) + - aml_read_vcbus(ENCP_VIDEO_VSO_BLINE) + - reset_line; + break; + case 3: + trigger_line = aml_read_vcbus(ENCT_VIDEO_VAVON_ELINE) + - aml_read_vcbus(ENCT_VIDEO_VSO_BLINE) - reset_line; + break; + } + aml_write_vcbus(VPP_INT_LINE_NUM, trigger_line); +} + +#ifdef CONFIG_AMLOGIC_VECM +static void hdr_restore_osd_csc(void) +{ + u32 i = 0; + u32 addr_port; + u32 data_port; + struct hdr_osd_lut_s *lut = &hdr_osd_reg.lut_val; + + if ((osd_reset_rdma_handle == -1) + || disable_osd_rdma_reset) + return; + /* check osd matrix enable status */ + if (hdr_osd_reg.viu_osd1_matrix_ctrl & 0x00000001) { + /* osd matrix, VPP_MATRIX_0 */ + rdma_write_reg( + osd_reset_rdma_handle, + VIU_OSD1_MATRIX_PRE_OFFSET0_1, + hdr_osd_reg.viu_osd1_matrix_pre_offset0_1); + rdma_write_reg( + osd_reset_rdma_handle, + VIU_OSD1_MATRIX_PRE_OFFSET2, + hdr_osd_reg.viu_osd1_matrix_pre_offset2); + rdma_write_reg( + osd_reset_rdma_handle, + VIU_OSD1_MATRIX_COEF00_01, + hdr_osd_reg.viu_osd1_matrix_coef00_01); + rdma_write_reg( + osd_reset_rdma_handle, + VIU_OSD1_MATRIX_COEF02_10, + hdr_osd_reg.viu_osd1_matrix_coef02_10); + rdma_write_reg( + osd_reset_rdma_handle, + VIU_OSD1_MATRIX_COEF11_12, + hdr_osd_reg.viu_osd1_matrix_coef11_12); + rdma_write_reg( + osd_reset_rdma_handle, + VIU_OSD1_MATRIX_COEF20_21, + hdr_osd_reg.viu_osd1_matrix_coef20_21); + rdma_write_reg( + osd_reset_rdma_handle, + VIU_OSD1_MATRIX_COEF22_30, + hdr_osd_reg.viu_osd1_matrix_coef22_30); + rdma_write_reg( + osd_reset_rdma_handle, + VIU_OSD1_MATRIX_COEF31_32, + hdr_osd_reg.viu_osd1_matrix_coef31_32); + rdma_write_reg( + osd_reset_rdma_handle, + VIU_OSD1_MATRIX_COEF40_41, + hdr_osd_reg.viu_osd1_matrix_coef40_41); + rdma_write_reg( + osd_reset_rdma_handle, + VIU_OSD1_MATRIX_COLMOD_COEF42, + hdr_osd_reg.viu_osd1_matrix_colmod_coef42); + rdma_write_reg( + osd_reset_rdma_handle, + VIU_OSD1_MATRIX_OFFSET0_1, + hdr_osd_reg.viu_osd1_matrix_offset0_1); + rdma_write_reg( + osd_reset_rdma_handle, + VIU_OSD1_MATRIX_OFFSET2, + hdr_osd_reg.viu_osd1_matrix_offset2); + rdma_write_reg( + osd_reset_rdma_handle, + VIU_OSD1_MATRIX_CTRL, + hdr_osd_reg.viu_osd1_matrix_ctrl); + } + /* restore eotf lut */ + if ((hdr_osd_reg.viu_osd1_eotf_ctl & 0x80000000) != 0) { + addr_port = VIU_OSD1_EOTF_LUT_ADDR_PORT; + data_port = VIU_OSD1_EOTF_LUT_DATA_PORT; + rdma_write_reg( + osd_reset_rdma_handle, + addr_port, 0); + for (i = 0; i < 16; i++) + rdma_write_reg( + osd_reset_rdma_handle, + data_port, + lut->r_map[i * 2] + | (lut->r_map[i * 2 + 1] << 16)); + rdma_write_reg( + osd_reset_rdma_handle, + data_port, + lut->r_map[EOTF_LUT_SIZE - 1] + | (lut->g_map[0] << 16)); + for (i = 0; i < 16; i++) + rdma_write_reg( + osd_reset_rdma_handle, + data_port, + lut->g_map[i * 2 + 1] + | (lut->b_map[i * 2 + 2] << 16)); + for (i = 0; i < 16; i++) + rdma_write_reg( + osd_reset_rdma_handle, + data_port, + lut->b_map[i * 2] + | (lut->b_map[i * 2 + 1] << 16)); + rdma_write_reg( + osd_reset_rdma_handle, + data_port, lut->b_map[EOTF_LUT_SIZE - 1]); + + /* load eotf matrix */ + rdma_write_reg( + osd_reset_rdma_handle, + VIU_OSD1_EOTF_COEF00_01, + hdr_osd_reg.viu_osd1_eotf_coef00_01); + rdma_write_reg( + osd_reset_rdma_handle, + VIU_OSD1_EOTF_COEF02_10, + hdr_osd_reg.viu_osd1_eotf_coef02_10); + rdma_write_reg( + osd_reset_rdma_handle, + VIU_OSD1_EOTF_COEF11_12, + hdr_osd_reg.viu_osd1_eotf_coef11_12); + rdma_write_reg( + osd_reset_rdma_handle, + VIU_OSD1_EOTF_COEF20_21, + hdr_osd_reg.viu_osd1_eotf_coef20_21); + rdma_write_reg( + osd_reset_rdma_handle, + VIU_OSD1_EOTF_COEF22_RS, + hdr_osd_reg.viu_osd1_eotf_coef22_rs); + rdma_write_reg( + osd_reset_rdma_handle, + VIU_OSD1_EOTF_CTL, + hdr_osd_reg.viu_osd1_eotf_ctl); + } + /* restore oetf lut */ + if ((hdr_osd_reg.viu_osd1_oetf_ctl & 0xe0000000) != 0) { + addr_port = VIU_OSD1_OETF_LUT_ADDR_PORT; + data_port = VIU_OSD1_OETF_LUT_DATA_PORT; + for (i = 0; i < 20; i++) { + rdma_write_reg( + osd_reset_rdma_handle, + addr_port, i); + rdma_write_reg( + osd_reset_rdma_handle, + data_port, + lut->or_map[i * 2] + | (lut->or_map[i * 2 + 1] << 16)); + } + rdma_write_reg( + osd_reset_rdma_handle, + addr_port, 20); + rdma_write_reg( + osd_reset_rdma_handle, + data_port, + lut->or_map[41 - 1] + | (lut->og_map[0] << 16)); + for (i = 0; i < 20; i++) { + rdma_write_reg( + osd_reset_rdma_handle, + addr_port, 21 + i); + rdma_write_reg( + osd_reset_rdma_handle, + data_port, + lut->og_map[i * 2 + 1] + | (lut->og_map[i * 2 + 2] << 16)); + } + for (i = 0; i < 20; i++) { + rdma_write_reg( + osd_reset_rdma_handle, + addr_port, 41 + i); + rdma_write_reg( + osd_reset_rdma_handle, + data_port, + lut->ob_map[i * 2] + | (lut->ob_map[i * 2 + 1] << 16)); + } + rdma_write_reg( + osd_reset_rdma_handle, + addr_port, 61); + rdma_write_reg( + osd_reset_rdma_handle, + data_port, + lut->ob_map[41 - 1]); + rdma_write_reg( + osd_reset_rdma_handle, + VIU_OSD1_OETF_CTL, + hdr_osd_reg.viu_osd1_oetf_ctl); + } +} +#endif + +static void osd_reset_rdma_func(u32 reset_bit) +{ + if ((disable_osd_rdma_reset == 0) + && reset_bit){ + rdma_write_reg(osd_reset_rdma_handle, + VIU_SW_RESET, 1); + rdma_write_reg(osd_reset_rdma_handle, + VIU_SW_RESET, 0); +#ifdef CONFIG_AMLOGIC_VECM + hdr_restore_osd_csc(); +#endif + set_reset_rdma_trigger_line(); + rdma_config(osd_reset_rdma_handle, 1 << 6); + } else + rdma_clear(osd_reset_rdma_handle); +} + +static void osd_reset_rdma_irq(void *arg) +{ +} + +static void osd_rdma_irq(void *arg) +{ + u32 rdma_status; + + if (osd_rdma_handle == -1) + return; + + rdma_status = osd_reg_read(RDMA_STATUS); + debug_rdma_status = rdma_status; + OSD_RDMA_STATUS_CLEAR_REJECT; + reset_rdma_table(); + osd_update_scan_mode(); + osd_update_3d_mode(); + osd_update_vsync_hit(); + osd_hw_reset(); + rdma_irq_count++; + { + /*This is a memory barrier*/ + wmb(); + } +} + +static struct rdma_op_s osd_reset_rdma_op = { + osd_reset_rdma_irq, + NULL +}; + +static struct rdma_op_s osd_rdma_op = { + osd_rdma_irq, + NULL +}; +#endif + +static int start_osd_rdma(char channel) +{ +#ifndef CONFIG_AMLOGIC_MEDIA_RDMA + char intr_bit = 8 * channel; + char rw_bit = 4 + channel; + char inc_bit = channel; + u32 data32; + + data32 = 0; + data32 |= 1 << 7; /* [31: 6] Rsrv. */ + data32 |= 1 << 6; /* [31: 6] Rsrv. */ + data32 |= 3 << 4; + /* [ 5: 4] ctrl_ahb_wr_burst_size. 0=16; 1=24; 2=32; 3=48. */ + data32 |= 3 << 2; + /* [ 3: 2] ctrl_ahb_rd_burst_size. 0=16; 1=24; 2=32; 3=48. */ + data32 |= 0 << 1; + /* [ 1] ctrl_sw_reset.*/ + data32 |= 0 << 0; + /* [ 0] ctrl_free_clk_enable.*/ + osd_reg_write(RDMA_CTRL, data32); + + data32 = osd_reg_read(RDMA_ACCESS_AUTO); + /* + * [23: 16] interrupt inputs enable mask for auto-start + * 1: vsync int bit 0 + */ + data32 |= 0x1 << intr_bit; + /* [ 6] ctrl_cbus_write_1. 1=Register write; 0=Register read. */ + data32 |= 1 << rw_bit; + /* + * [ 2] ctrl_cbus_addr_incr_1. + * 1=Incremental register access; 0=Non-incremental. + */ + data32 &= ~(1 << inc_bit); + osd_reg_write(RDMA_ACCESS_AUTO, data32); +#else + rdma_config(channel, + RDMA_TRIGGER_VSYNC_INPUT + | RDMA_AUTO_START_MASK); +#endif + return 1; +} + +static int stop_rdma(char channel) +{ +#ifndef CONFIG_AMLOGIC_MEDIA_RDMA + char intr_bit = 8 * channel; + u32 data32 = 0x0; + + data32 = osd_reg_read(RDMA_ACCESS_AUTO); + data32 &= ~(0x1 << + intr_bit); + /* [23: 16] interrupt inputs enable mask + * for auto-start 1: vsync int bit 0 + */ + osd_reg_write(RDMA_ACCESS_AUTO, data32); +#else + rdma_clear(channel); + if (osd_reset_rdma_handle != -1) + rdma_clear(osd_reset_rdma_handle); +#endif + return 0; +} + + +void osd_rdma_interrupt_done_clear(void) +{ + u32 rdma_status; + + if (rdma_reset_tigger_flag) { + rdma_status = + osd_reg_read(RDMA_STATUS); + pr_info("osd rdma restart! 0x%x\n", + rdma_status); + rdma_reset_tigger_flag = 0; + osd_rdma_enable(0); + osd_rdma_enable(2); + } +} +int read_rdma_table(void) +{ + int rdma_count = 0; + int i, reg; + + if (rdma_debug) { + for (rdma_count = 0; rdma_count < item_count + 1; rdma_count++) + pr_info("rdma_table addr is 0x%x, value is 0x%x\n", + rdma_table[rdma_count].addr, + rdma_table[rdma_count].val); + reg = 0x1100; + pr_info("RDMA relative registers-----------------\n"); + for (i = 0 ; i < 24 ; i++) + pr_info("[0x%x]== 0x%x\n", reg+i, osd_reg_read(reg+i)); + } + return 0; +} +EXPORT_SYMBOL(read_rdma_table); + +int osd_rdma_enable(u32 enable) +{ + int ret = 0; + unsigned long flags; + + if ((enable && rdma_enable) + || (!enable && !rdma_enable)) + return 0; + + ret = osd_rdma_init(); + if (ret != 0) + return -1; + + rdma_enable = enable; + if (enable) { + spin_lock_irqsave(&rdma_lock, flags); + OSD_RDMA_STATUS_CLEAR_REJECT; + osd_reg_write(START_ADDR, table_paddr); + osd_reg_write(END_ADDR, table_paddr - 1); + item_count = 0; + spin_unlock_irqrestore(&rdma_lock, flags); + reset_rdma_table(); + start_osd_rdma(OSD_RDMA_CHANNEL_INDEX); + } else { + stop_rdma(OSD_RDMA_CHANNEL_INDEX); + } + + return 1; +} +EXPORT_SYMBOL(osd_rdma_enable); + +int osd_rdma_reset_and_flush(u32 reset_bit) +{ + int i, ret = 0; + unsigned long flags; + u32 reset_reg_mask; + u32 base; + u32 addr; + u32 value; + + spin_lock_irqsave(&rdma_lock, flags); + reset_reg_mask = reset_bit; + reset_reg_mask &= ~HW_RESET_OSD1_REGS; + if (disable_osd_rdma_reset != 0) { + reset_reg_mask = 0; + reset_bit = 0; + } + + if (reset_reg_mask) { + wrtie_reg_internal(VIU_SW_RESET, + reset_reg_mask); + wrtie_reg_internal(VIU_SW_RESET, 0); + } + + /* same bit, but gxm only reset hardware, not top reg*/ + if (get_cpu_type() == MESON_CPU_MAJOR_ID_GXM) + reset_bit &= ~HW_RESET_AFBCD_REGS; + + i = 0; + base = VIU_OSD1_CTRL_STAT; + while ((reset_bit & HW_RESET_OSD1_REGS) + && (i < OSD_REG_BACKUP_COUNT)) { + addr = osd_reg_backup[i]; + wrtie_reg_internal( + addr, osd_backup[addr - base]); + i++; + } + i = 0; + base = OSD1_AFBCD_ENABLE; + while ((reset_bit & HW_RESET_AFBCD_REGS) + && (i < OSD_AFBC_REG_BACKUP_COUNT)) { + addr = osd_afbc_reg_backup[i]; + value = osd_afbc_backup[addr - base]; + if (addr == OSD1_AFBCD_ENABLE) + value |= 0x100; + wrtie_reg_internal( + addr, value); + i++; + } + if (item_count < 500) + osd_reg_write(END_ADDR, (table_paddr + item_count * 8 - 1)); + else { + pr_info("osd_rdma_reset_and_flush item overflow %d\n", + item_count); + ret = -1; + } + if (dump_reg_trigger > 0) { + for (i = 0; i < item_count; i++) + pr_info("dump rdma reg[%d]:0x%x, data:0x%x\n", + i, rdma_table[i].addr, + rdma_table[i].val); + dump_reg_trigger--; + } + +#ifdef CONFIG_AMLOGIC_MEDIA_RDMA + if (osd_reset_rdma_handle != -1) + osd_reset_rdma_func( + reset_bit & HW_RESET_OSD1_REGS); +#endif + + spin_unlock_irqrestore(&rdma_lock, flags); + return ret; +} +EXPORT_SYMBOL(osd_rdma_reset_and_flush); + +static void osd_rdma_release(struct device *dev) +{ + dma_free_coherent(osd_rdma_dev, + PAGE_SIZE, + osd_rdma_table_virt, + (dma_addr_t)&osd_rdma_table_phy); +#ifdef CONFIG_AMLOGIC_MEDIA_RDMA + if (osd_reset_rdma_handle != -1) { + rdma_unregister(osd_reset_rdma_handle); + osd_reset_rdma_handle = -1; + } + if (osd_rdma_handle != -1) { + rdma_unregister(osd_rdma_handle); + osd_rdma_handle = -1; + } +#endif +} + +#ifdef OSD_RDMA_ISR +static irqreturn_t osd_rdma_isr(int irq, void *dev_id) +{ + u32 rdma_status; + + rdma_status = osd_reg_read(RDMA_STATUS); + debug_rdma_status = rdma_status; + if (rdma_status & (1 << (24 + OSD_RDMA_CHANNEL_INDEX))) { + OSD_RDMA_STATUS_CLEAR_REJECT; + reset_rdma_table(); + osd_update_scan_mode(); + osd_update_3d_mode(); + osd_update_vsync_hit(); + osd_hw_reset(); + rdma_irq_count++; + { + /*This is a memory barrier*/ + wmb(); + } + osd_reg_write(RDMA_CTRL, + 1 << (24 + OSD_RDMA_CHANNEL_INDEX)); + } else + rdma_lost_count++; + rdma_status = osd_reg_read(RDMA_STATUS); + if (rdma_status & 0xf7000000) { + if (!second_rdma_irq) + pr_info("osd rdma irq as first function call, status: 0x%x\n", + rdma_status); + pr_info("osd rdma miss done isr, status: 0x%x\n", rdma_status); + osd_reg_write(RDMA_CTRL, rdma_status & 0xf7000000); + } + return IRQ_HANDLED; +} +#endif + +static int osd_rdma_init(void) +{ + int ret = -1; + + if (osd_rdma_init_flag) + return 0; + + osd_rdma_dev = kzalloc(sizeof(struct device), GFP_KERNEL); + if (!osd_rdma_dev) { + /* osd_log_err("osd rdma init error!\n"); */ + return -1; + } + osd_rdma_dev->release = osd_rdma_release; + dev_set_name(osd_rdma_dev, "osd-rdma-dev"); + dev_set_drvdata(osd_rdma_dev, osd_rdma_dev); + ret = device_register(osd_rdma_dev); + if (ret) { + osd_log_err("register rdma dev error\n"); + goto error1; + } + of_dma_configure(osd_rdma_dev, osd_rdma_dev->of_node); + table_pages = dma_alloc_from_contiguous(osd_rdma_dev, 1, 4); + osd_rdma_table_virt = dma_alloc_coherent(osd_rdma_dev, PAGE_SIZE, + &osd_rdma_table_phy, GFP_KERNEL); + + if (!osd_rdma_table_virt) { + osd_log_err("osd rdma dma alloc failed!\n"); + goto error2; + } + +#ifdef OSD_RDMA_ISR + second_rdma_irq = 0; +#endif + dump_reg_trigger = 0; + table_vaddr = osd_rdma_table_virt; + table_paddr = osd_rdma_table_phy; + osd_log_info("%s: rdma_table p=0x%x,op=0x%lx , v=0x%p\n", __func__, + table_paddr, (unsigned long)osd_rdma_table_phy, + table_vaddr); + rdma_table = (struct rdma_table_item *)table_vaddr; + if (rdma_table == NULL) { + osd_log_err("%s: failed to remap rmda_table_addr\n", __func__); + goto error2; + } + +#ifdef OSD_RDMA_ISR + if (rdma_mgr_irq_request) { + second_rdma_irq = 1; + pr_info("osd rdma request irq as second interrput function!\n"); + } + if (request_irq(INT_RDMA, &osd_rdma_isr, + IRQF_SHARED, "osd_rdma", (void *)"osd_rdma")) { + osd_log_err("can't request irq for rdma\n"); + goto error2; + } +#endif + osd_rdma_init_flag = true; + osd_reg_write(OSD_RDMA_FLAG_REG, 0x0); + +#ifdef CONFIG_AMLOGIC_MEDIA_RDMA + if ((get_cpu_type() >= MESON_CPU_MAJOR_ID_GXL) + && (get_cpu_type() <= MESON_CPU_MAJOR_ID_TXL)) { + osd_reset_rdma_op.arg = osd_rdma_dev; + osd_reset_rdma_handle = + rdma_register(&osd_reset_rdma_op, + NULL, PAGE_SIZE); + pr_info("%s:osd reset rdma handle = %d.\n", __func__, + osd_reset_rdma_handle); + } + osd_rdma_op.arg = osd_rdma_dev; + osd_rdma_handle = + rdma_register(&osd_rdma_op, + NULL, PAGE_SIZE); + pr_info("%s:osd rdma handle = %d.\n", __func__, + osd_rdma_handle); +#else + osd_rdma_handle = 3; /* use channel 3 as default */ +#endif + + return 0; + +error2: + device_unregister(osd_rdma_dev); +error1: + kfree(osd_rdma_dev); + osd_rdma_dev = NULL; + return -1; +} + + +int osd_rdma_uninit(void) +{ + if (osd_rdma_init_flag) { + device_unregister(osd_rdma_dev); + kfree(osd_rdma_dev); + osd_rdma_dev = NULL; + osd_rdma_init_flag = false; + } + return 0; +} +EXPORT_SYMBOL(osd_rdma_uninit); + + +MODULE_PARM_DESC(item_count, "\n item_count\n"); +module_param(item_count, uint, 0664); + +MODULE_PARM_DESC(table_paddr, "\n table_paddr\n"); +module_param(table_paddr, uint, 0664); + +MODULE_PARM_DESC(rdma_debug, "\n rdma_debug\n"); +module_param(rdma_debug, uint, 0664); + +MODULE_PARM_DESC(debug_rdma_status, "\n debug_rdma_status\n"); +module_param(debug_rdma_status, uint, 0664); + +MODULE_PARM_DESC(rdma_irq_count, "\n rdma_irq_count\n"); +module_param(rdma_irq_count, uint, 0664); + +MODULE_PARM_DESC(rdma_lost_count, "\n rdma_lost_count\n"); +module_param(rdma_lost_count, uint, 0664); + +MODULE_PARM_DESC(dump_reg_trigger, "\n dump_reg_trigger\n"); +module_param(dump_reg_trigger, uint, 0664); + +MODULE_PARM_DESC(rdma_recovery_count, "\n rdma_recovery_count\n"); +module_param(rdma_recovery_count, uint, 0664); + diff --git a/drivers/amlogic/media/osd/osd_rdma.h b/drivers/amlogic/media/osd/osd_rdma.h new file mode 100644 index 000000000000..c061bd6e615e --- /dev/null +++ b/drivers/amlogic/media/osd/osd_rdma.h @@ -0,0 +1,75 @@ +/* + * drivers/amlogic/media/osd/osd_rdma.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 _OSD_RDMA_H_ +#define _OSD_RDMA_H_ + +#include +#include "osd_io.h" +#include "osd_reg.h" + +struct rdma_table_item { + u32 addr; + u32 val; +}; + +#define TABLE_SIZE PAGE_SIZE +#define MAX_TABLE_ITEM (TABLE_SIZE/sizeof(struct rdma_table_item_t)) +#define OSD_RDMA_CHANNEL_INDEX osd_rdma_handle +#define START_ADDR (RDMA_AHB_START_ADDR_MAN+(OSD_RDMA_CHANNEL_INDEX<<1)) +#define END_ADDR (RDMA_AHB_END_ADDR_MAN+(OSD_RDMA_CHANNEL_INDEX<<1)) + +#define OSD_RDMA_FLAG_REG VIU_OSD2_TCOLOR_AG3 + +#define OSD_RDMA_FLAG_REJECT (0x99 << 0) +/* hw rdma own this flag, change it to zero when start rdma, + * change it to 0 when complete + */ + +#define OSD_RDMA_STATUS_IS_REJECT \ + (osd_reg_read(OSD_RDMA_FLAG_REG) & OSD_RDMA_FLAG_REJECT) + +/* hw rdma op, set REJECT */ +#define OSD_RDMA_STATUS_MARK_TBL_RST \ + ((osd_reg_read(OSD_RDMA_FLAG_REG) \ + & ~OSD_RDMA_FLAG_REJECT) | \ + (OSD_RDMA_FLAG_REJECT)) + +#define OSD_RDMA_STATUS_MARK_TBL_DONE \ + ((osd_reg_read(OSD_RDMA_FLAG_REG) \ + & ~OSD_RDMA_FLAG_REJECT)) \ + +/* cpu op, clear REJECT */ +#define OSD_RDMA_STATUS_CLEAR_REJECT \ + (osd_reg_write(OSD_RDMA_FLAG_REG, \ + (osd_reg_read(OSD_RDMA_FLAG_REG) & \ + ~OSD_RDMA_FLAG_REJECT))) + +extern void osd_update_scan_mode(void); +extern void osd_update_3d_mode(void); +extern void osd_update_vsync_hit(void); +extern void osd_hw_reset(void); +extern int read_rdma_table(void); +extern int osd_rdma_enable(u32 enable); +extern int osd_rdma_reset_and_flush(u32 reset_bit); +extern int rdma_reset_tigger_flag; +extern int rdma_mgr_irq_request; +#ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD_VSYNC_RDMA +extern void osd_rdma_interrupt_done_clear(void); +#endif +extern int osd_rdma_uninit(void); +#endif diff --git a/drivers/amlogic/media/osd/osd_reg.h b/drivers/amlogic/media/osd/osd_reg.h new file mode 100644 index 000000000000..98f5bfa3a413 --- /dev/null +++ b/drivers/amlogic/media/osd/osd_reg.h @@ -0,0 +1,1379 @@ +/* + * drivers/amlogic/media/osd/osd_reg.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 _OSD_REG_H_ +#define _OSD_REG_H_ + +/* vpp2 */ +#define VPP2_DUMMY_DATA 0x1900 +#define VPP2_LINE_IN_LENGTH 0x1901 +#define VPP2_PIC_IN_HEIGHT 0x1902 +#define VPP2_SCALE_COEF_IDX 0x1903 +#define VPP2_SCALE_COEF 0x1904 +#define VPP2_VSC_REGION12_STARTP 0x1905 +#define VPP2_VSC_REGION34_STARTP 0x1906 +#define VPP2_VSC_REGION4_ENDP 0x1907 +#define VPP2_VSC_START_PHASE_STEP 0x1908 +#define VPP2_VSC_REGION0_PHASE_SLOPE 0x1909 +#define VPP2_VSC_REGION1_PHASE_SLOPE 0x190a +#define VPP2_VSC_REGION3_PHASE_SLOPE 0x190b +#define VPP2_VSC_REGION4_PHASE_SLOPE 0x190c +#define VPP2_VSC_PHASE_CTRL 0x190d +#define VPP2_VSC_INI_PHASE 0x190e +#define VPP2_HSC_REGION12_STARTP 0x1910 +#define VPP2_HSC_REGION34_STARTP 0x1911 +#define VPP2_HSC_REGION4_ENDP 0x1912 +#define VPP2_HSC_START_PHASE_STEP 0x1913 +#define VPP2_HSC_REGION0_PHASE_SLOPE 0x1914 +#define VPP2_HSC_REGION1_PHASE_SLOPE 0x1915 +#define VPP2_HSC_REGION3_PHASE_SLOPE 0x1916 +#define VPP2_HSC_REGION4_PHASE_SLOPE 0x1917 +#define VPP2_HSC_PHASE_CTRL 0x1918 +#define VPP2_SC_MISC 0x1919 +#define VPP2_PREBLEND_VD1_H_START_END 0x191a +#define VPP2_PREBLEND_VD1_V_START_END 0x191b +#define VPP2_POSTBLEND_VD1_H_START_END 0x191c +#define VPP2_POSTBLEND_VD1_V_START_END 0x191d +#define VPP2_PREBLEND_H_SIZE 0x1920 +#define VPP2_POSTBLEND_H_SIZE 0x1921 +#define VPP2_HOLD_LINES 0x1922 +#define VPP2_BLEND_ONECOLOR_CTRL 0x1923 +#define VPP2_PREBLEND_CURRENT_XY 0x1924 +#define VPP2_POSTBLEND_CURRENT_XY 0x1925 +#define VPP2_MISC 0x1926 +#define VPP2_OFIFO_SIZE 0x1927 +#define VPP2_FIFO_STATUS 0x1928 +#define VPP2_SMOKE_CTRL 0x1929 +#define VPP2_SMOKE1_VAL 0x192a +#define VPP2_SMOKE2_VAL 0x192b +#define VPP2_SMOKE1_H_START_END 0x192d +#define VPP2_SMOKE1_V_START_END 0x192e +#define VPP2_SMOKE2_H_START_END 0x192f +#define VPP2_SMOKE2_V_START_END 0x1930 +#define VPP2_SCO_FIFO_CTRL 0x1933 +#define VPP2_HSC_PHASE_CTRL1 0x1934 +#define VPP2_HSC_INI_PAT_CTRL 0x1935 +#define VPP2_VADJ_CTRL 0x1940 +#define VPP2_VADJ1_Y 0x1941 +#define VPP2_VADJ1_MA_MB 0x1942 +#define VPP2_VADJ1_MC_MD 0x1943 +#define VPP2_VADJ2_Y 0x1944 +#define VPP2_VADJ2_MA_MB 0x1945 +#define VPP2_VADJ2_MC_MD 0x1946 +#define VPP2_MATRIX_PROBE_COLOR 0x195c +#define VPP2_MATRIX_HL_COLOR 0x195d +#define VPP2_MATRIX_PROBE_POS 0x195e +#define VPP2_MATRIX_CTRL 0x195f +#define VPP2_MATRIX_COEF00_01 0x1960 +#define VPP2_MATRIX_COEF02_10 0x1961 +#define VPP2_MATRIX_COEF11_12 0x1962 +#define VPP2_MATRIX_COEF20_21 0x1963 +#define VPP2_MATRIX_COEF22 0x1964 +#define VPP2_MATRIX_OFFSET0_1 0x1965 +#define VPP2_MATRIX_OFFSET2 0x1966 +#define VPP2_MATRIX_PRE_OFFSET0_1 0x1967 +#define VPP2_MATRIX_PRE_OFFSET2 0x1968 +#define VPP2_DUMMY_DATA1 0x1969 +#define VPP2_GAINOFF_CTRL0 0x196a +#define VPP2_GAINOFF_CTRL1 0x196b +#define VPP2_GAINOFF_CTRL2 0x196c +#define VPP2_GAINOFF_CTRL3 0x196d +#define VPP2_GAINOFF_CTRL4 0x196e +#define VPP2_CHROMA_ADDR_PORT 0x1970 +#define VPP2_CHROMA_DATA_PORT 0x1971 +#define VPP2_GCLK_CTRL0 0x1972 +#define VPP2_GCLK_CTRL1 0x1973 +#define VPP2_SC_GCLK_CTRL 0x1974 +#define VPP2_MISC1 0x1976 +#define VPP2_DNLP_CTRL_00 0x1981 +#define VPP2_DNLP_CTRL_01 0x1982 +#define VPP2_DNLP_CTRL_02 0x1983 +#define VPP2_DNLP_CTRL_03 0x1984 +#define VPP2_DNLP_CTRL_04 0x1985 +#define VPP2_DNLP_CTRL_05 0x1986 +#define VPP2_DNLP_CTRL_06 0x1987 +#define VPP2_DNLP_CTRL_07 0x1988 +#define VPP2_DNLP_CTRL_08 0x1989 +#define VPP2_DNLP_CTRL_09 0x198a +#define VPP2_DNLP_CTRL_10 0x198b +#define VPP2_DNLP_CTRL_11 0x198c +#define VPP2_DNLP_CTRL_12 0x198d +#define VPP2_DNLP_CTRL_13 0x198e +#define VPP2_DNLP_CTRL_14 0x198f +#define VPP2_DNLP_CTRL_15 0x1990 +#define VPP2_VE_ENABLE_CTRL 0x19a1 +#define VPP2_VE_DEMO_LEFT_TOP_SCREEN_WIDTH 0x19a2 +#define VPP2_VE_DEMO_CENTER_BAR 0x19a3 +#define VPP2_VE_H_V_SIZE 0x19a4 +#define VPP2_VDO_MEAS_CTRL 0x19a8 +#define VPP2_VDO_MEAS_VS_COUNT_HI 0x19a9 +#define VPP2_VDO_MEAS_VS_COUNT_LO 0x19aa +#define VPP2_OSD_VSC_PHASE_STEP 0x19c0 +#define VPP2_OSD_VSC_INI_PHASE 0x19c1 +#define VPP2_OSD_VSC_CTRL0 0x19c2 +#define VPP2_OSD_HSC_PHASE_STEP 0x19c3 +#define VPP2_OSD_HSC_INI_PHASE 0x19c4 +#define VPP2_OSD_HSC_CTRL0 0x19c5 +#define VPP2_OSD_HSC_INI_PAT_CTRL 0x19c6 +#define VPP2_OSD_SC_DUMMY_DATA 0x19c7 +#define VPP2_OSD_SC_CTRL0 0x19c8 +#define VPP2_OSD_SCI_WH_M1 0x19c9 +#define VPP2_OSD_SCO_H_START_END 0x19ca +#define VPP2_OSD_SCO_V_START_END 0x19cb +#define VPP2_OSD_SCALE_COEF_IDX 0x19cc +#define VPP2_OSD_SCALE_COEF 0x19cd +#define VPP2_INT_LINE_NUM 0x19ce + +/* viu */ +#define VIU_ADDR_START 0x1a00 +#define VIU_ADDR_END 0x1aff +#define VIU_SW_RESET 0x1a01 +#define VIU_MISC_CTRL0 0x1a06 +#define D2D3_INTF_LENGTH 0x1a08 +#define D2D3_INTF_CTRL0 0x1a09 +#define VIU_OSD1_CTRL_STAT 0x1a10 +#define VIU_OSD1_CTRL_STAT2 0x1a2d +#define VIU_OSD1_COLOR_ADDR 0x1a11 +#define VIU_OSD1_COLOR 0x1a12 +#define VIU_OSD1_TCOLOR_AG0 0x1a17 +#define VIU_OSD1_TCOLOR_AG1 0x1a18 +#define VIU_OSD1_TCOLOR_AG2 0x1a19 +#define VIU_OSD1_TCOLOR_AG3 0x1a1a +#define VIU_OSD1_BLK0_CFG_W0 0x1a1b +#define VIU_OSD1_BLK1_CFG_W0 0x1a1f +#define VIU_OSD1_BLK2_CFG_W0 0x1a23 +#define VIU_OSD1_BLK3_CFG_W0 0x1a27 +#define VIU_OSD1_BLK0_CFG_W1 0x1a1c +#define VIU_OSD1_BLK1_CFG_W1 0x1a20 +#define VIU_OSD1_BLK2_CFG_W1 0x1a24 +#define VIU_OSD1_BLK3_CFG_W1 0x1a28 +#define VIU_OSD1_BLK0_CFG_W2 0x1a1d +#define VIU_OSD1_BLK1_CFG_W2 0x1a21 +#define VIU_OSD1_BLK2_CFG_W2 0x1a25 +#define VIU_OSD1_BLK3_CFG_W2 0x1a29 +#define VIU_OSD1_BLK0_CFG_W3 0x1a1e +#define VIU_OSD1_BLK1_CFG_W3 0x1a22 +#define VIU_OSD1_BLK2_CFG_W3 0x1a26 +#define VIU_OSD1_BLK3_CFG_W3 0x1a2a +#define VIU_OSD1_BLK0_CFG_W4 0x1a13 +#define VIU_OSD1_BLK1_CFG_W4 0x1a14 +#define VIU_OSD1_BLK2_CFG_W4 0x1a15 +#define VIU_OSD1_BLK3_CFG_W4 0x1a16 +#define VIU_OSD1_FIFO_CTRL_STAT 0x1a2b +#define VIU_OSD1_TEST_RDDATA 0x1a2c +#define VIU_OSD1_PROT_CTRL 0x1a2e +#define VIU_OSD2_CTRL_STAT 0x1a30 +#define VIU_OSD2_CTRL_STAT2 0x1a4d +#define VIU_OSD2_COLOR_ADDR 0x1a31 +#define VIU_OSD2_COLOR 0x1a32 +#define VIU_OSD2_HL1_H_START_END 0x1a33 +#define VIU_OSD2_HL1_V_START_END 0x1a34 +#define VIU_OSD2_HL2_H_START_END 0x1a35 +#define VIU_OSD2_HL2_V_START_END 0x1a36 +#define VIU_OSD2_TCOLOR_AG0 0x1a37 +#define VIU_OSD2_TCOLOR_AG1 0x1a38 +#define VIU_OSD2_TCOLOR_AG2 0x1a39 +#define VIU_OSD2_TCOLOR_AG3 0x1a3a +#define VIU_OSD2_BLK0_CFG_W0 0x1a3b +#define VIU_OSD2_BLK1_CFG_W0 0x1a3f +#define VIU_OSD2_BLK2_CFG_W0 0x1a43 +#define VIU_OSD2_BLK3_CFG_W0 0x1a47 +#define VIU_OSD2_BLK0_CFG_W1 0x1a3c +#define VIU_OSD2_BLK1_CFG_W1 0x1a40 +#define VIU_OSD2_BLK2_CFG_W1 0x1a44 +#define VIU_OSD2_BLK3_CFG_W1 0x1a48 +#define VIU_OSD2_BLK0_CFG_W2 0x1a3d +#define VIU_OSD2_BLK1_CFG_W2 0x1a41 +#define VIU_OSD2_BLK2_CFG_W2 0x1a45 +#define VIU_OSD2_BLK3_CFG_W2 0x1a49 +#define VIU_OSD2_BLK0_CFG_W3 0x1a3e +#define VIU_OSD2_BLK1_CFG_W3 0x1a42 +#define VIU_OSD2_BLK2_CFG_W3 0x1a46 +#define VIU_OSD2_BLK3_CFG_W3 0x1a4a +#define VIU_OSD2_BLK0_CFG_W4 0x1a64 +#define VIU_OSD2_BLK1_CFG_W4 0x1a65 +#define VIU_OSD2_BLK2_CFG_W4 0x1a66 +#define VIU_OSD2_BLK3_CFG_W4 0x1a67 +#define VIU_OSD2_FIFO_CTRL_STAT 0x1a4b +#define VIU_OSD2_TEST_RDDATA 0x1a4c +#define VIU_OSD2_PROT_CTRL 0x1a4e + +#define VD1_IF0_GEN_REG 0x1a50 +#define VD1_IF0_CANVAS0 0x1a51 +#define VD1_IF0_CANVAS1 0x1a52 +#define VD1_IF0_LUMA_X0 0x1a53 +#define VD1_IF0_LUMA_Y0 0x1a54 +#define VD1_IF0_CHROMA_X0 0x1a55 +#define VD1_IF0_CHROMA_Y0 0x1a56 +#define VD1_IF0_LUMA_X1 0x1a57 +#define VD1_IF0_LUMA_Y1 0x1a58 +#define VD1_IF0_CHROMA_X1 0x1a59 +#define VD1_IF0_CHROMA_Y1 0x1a5a +#define VD1_IF0_RPT_LOOP 0x1a5b +#define VD1_IF0_LUMA0_RPT_PAT 0x1a5c +#define VD1_IF0_CHROMA0_RPT_PAT 0x1a5d +#define VD1_IF0_LUMA1_RPT_PAT 0x1a5e +#define VD1_IF0_CHROMA1_RPT_PAT 0x1a5f +#define VD1_IF0_LUMA_PSEL 0x1a60 +#define VD1_IF0_CHROMA_PSEL 0x1a61 +#define VD1_IF0_DUMMY_PIXEL 0x1a62 +#define VD1_IF0_LUMA_FIFO_SIZE 0x1a63 +#define VD1_IF0_RANGE_MAP_Y 0x1a6a +#define VD1_IF0_RANGE_MAP_CB 0x1a6b +#define VD1_IF0_RANGE_MAP_CR 0x1a6c +#define VD1_IF0_GEN_REG2 0x1a6d +#define VD1_IF0_PROT_CNTL 0x1a6e +#define VIU_VD1_FMT_CTRL 0x1a68 +#define VIU_VD1_FMT_W 0x1a69 +#define VD2_IF0_GEN_REG 0x1a70 +#define VD2_IF0_CANVAS0 0x1a71 +#define VD2_IF0_CANVAS1 0x1a72 +#define VD2_IF0_LUMA_X0 0x1a73 +#define VD2_IF0_LUMA_Y0 0x1a74 +#define VD2_IF0_CHROMA_X0 0x1a75 +#define VD2_IF0_CHROMA_Y0 0x1a76 +#define VD2_IF0_LUMA_X1 0x1a77 +#define VD2_IF0_LUMA_Y1 0x1a78 +#define VD2_IF0_CHROMA_X1 0x1a79 +#define VD2_IF0_CHROMA_Y1 0x1a7a +#define VD2_IF0_RPT_LOOP 0x1a7b +#define VD2_IF0_LUMA0_RPT_PAT 0x1a7c +#define VD2_IF0_CHROMA0_RPT_PAT 0x1a7d +#define VD2_IF0_LUMA1_RPT_PAT 0x1a7e +#define VD2_IF0_CHROMA1_RPT_PAT 0x1a7f +#define VD2_IF0_LUMA_PSEL 0x1a80 +#define VD2_IF0_CHROMA_PSEL 0x1a81 +#define VD2_IF0_DUMMY_PIXEL 0x1a82 +#define VD2_IF0_LUMA_FIFO_SIZE 0x1a83 +#define VD2_IF0_RANGE_MAP_Y 0x1a8a +#define VD2_IF0_RANGE_MAP_CB 0x1a8b +#define VD2_IF0_RANGE_MAP_CR 0x1a8c +#define VD2_IF0_GEN_REG2 0x1a8d +#define VD2_IF0_PROT_CNTL 0x1a8e +#define VIU_VD2_FMT_CTRL 0x1a88 +#define VIU_VD2_FMT_W 0x1a89 + +#define VIU_OSD1_MATRIX_CTRL 0x1a90 +#define VIU_OSD1_MATRIX_COEF00_01 0x1a91 +#define VIU_OSD1_MATRIX_COEF02_10 0x1a92 +#define VIU_OSD1_MATRIX_COEF11_12 0x1a93 +#define VIU_OSD1_MATRIX_COEF20_21 0x1a94 +#define VIU_OSD1_MATRIX_COLMOD_COEF42 0x1a95 +#define VIU_OSD1_MATRIX_OFFSET0_1 0x1a96 +#define VIU_OSD1_MATRIX_OFFSET2 0x1a97 +#define VIU_OSD1_MATRIX_PRE_OFFSET0_1 0x1a98 +#define VIU_OSD1_MATRIX_PRE_OFFSET2 0x1a99 +#define VIU_OSD1_MATRIX_COEF22_30 0x1a9d +#define VIU_OSD1_MATRIX_COEF31_32 0x1a9e +#define VIU_OSD1_MATRIX_COEF40_41 0x1a9f +#define VIU_OSD1_EOTF_CTL 0x1ad4 +#define VIU_OSD1_EOTF_COEF00_01 0x1ad5 +#define VIU_OSD1_EOTF_COEF02_10 0x1ad6 +#define VIU_OSD1_EOTF_COEF11_12 0x1ad7 +#define VIU_OSD1_EOTF_COEF20_21 0x1ad8 +#define VIU_OSD1_EOTF_COEF22_RS 0x1ad9 +#define VIU_OSD1_EOTF_LUT_ADDR_PORT 0x1ada +#define VIU_OSD1_EOTF_LUT_DATA_PORT 0x1adb +#define VIU_OSD1_OETF_CTL 0x1adc +#define VIU_OSD1_OETF_LUT_ADDR_PORT 0x1add +#define VIU_OSD1_OETF_LUT_DATA_PORT 0x1ade + +/* vpp */ +#define VPP_DUMMY_DATA 0x1d00 +#define VPP_LINE_IN_LENGTH 0x1d01 +#define VPP_PIC_IN_HEIGHT 0x1d02 +#define VPP_SCALE_COEF_IDX 0x1d03 +#define VPP_SCALE_COEF 0x1d04 +#define VPP_VSC_REGION12_STARTP 0x1d05 +#define VPP_VSC_REGION34_STARTP 0x1d06 +#define VPP_VSC_REGION4_ENDP 0x1d07 +#define VPP_VSC_START_PHASE_STEP 0x1d08 +#define VPP_VSC_REGION0_PHASE_SLOPE 0x1d09 +#define VPP_VSC_REGION1_PHASE_SLOPE 0x1d0a +#define VPP_VSC_REGION3_PHASE_SLOPE 0x1d0b +#define VPP_VSC_REGION4_PHASE_SLOPE 0x1d0c +#define VPP_VSC_PHASE_CTRL 0x1d0d +#define VPP_VSC_INI_PHASE 0x1d0e +#define VPP_HSC_REGION12_STARTP 0x1d10 +#define VPP_HSC_REGION34_STARTP 0x1d11 +#define VPP_HSC_REGION4_ENDP 0x1d12 +#define VPP_HSC_START_PHASE_STEP 0x1d13 +#define VPP_HSC_REGION0_PHASE_SLOPE 0x1d14 +#define VPP_HSC_REGION1_PHASE_SLOPE 0x1d15 +#define VPP_HSC_REGION3_PHASE_SLOPE 0x1d16 +#define VPP_HSC_REGION4_PHASE_SLOPE 0x1d17 +#define VPP_HSC_PHASE_CTRL 0x1d18 +#define VPP_SC_MISC 0x1d19 +#define VPP_PREBLEND_VD1_H_START_END 0x1d1a +#define VPP_PREBLEND_VD1_V_START_END 0x1d1b +#define VPP_POSTBLEND_VD1_H_START_END 0x1d1c +#define VPP_POSTBLEND_VD1_V_START_END 0x1d1d +#define VPP_BLEND_VD2_H_START_END 0x1d1e +#define VPP_BLEND_VD2_V_START_END 0x1d1f +#define VPP_PREBLEND_H_SIZE 0x1d20 +#define VPP_POSTBLEND_H_SIZE 0x1d21 +#define VPP_HOLD_LINES 0x1d22 +#define VPP_BLEND_ONECOLOR_CTRL 0x1d23 +#define VPP_PREBLEND_CURRENT_XY 0x1d24 +#define VPP_POSTBLEND_CURRENT_XY 0x1d25 +#define VPP_MISC 0x1d26 +#define VPP_OFIFO_SIZE 0x1d27 +#define VPP_FIFO_STATUS 0x1d28 +#define VPP_SMOKE_CTRL 0x1d29 +#define VPP_SMOKE1_VAL 0x1d2a +#define VPP_SMOKE2_VAL 0x1d2b +#define VPP_SMOKE3_VAL 0x1d2c +#define VPP_SMOKE1_H_START_END 0x1d2d +#define VPP_SMOKE1_V_START_END 0x1d2e +#define VPP_SMOKE2_H_START_END 0x1d2f +#define VPP_SMOKE2_V_START_END 0x1d30 +#define VPP_SMOKE3_H_START_END 0x1d31 +#define VPP_SMOKE3_V_START_END 0x1d32 +#define VPP_SCO_FIFO_CTRL 0x1d33 +#define VPP_HSC_PHASE_CTRL1 0x1d34 +#define VPP_HSC_INI_PAT_CTRL 0x1d35 +#define VPP_VADJ_CTRL 0x1d40 +#define VPP_VADJ1_Y 0x1d41 +#define VPP_VADJ1_MA_MB 0x1d42 +#define VPP_VADJ1_MC_MD 0x1d43 +#define VPP_VADJ2_Y 0x1d44 +#define VPP_VADJ2_MA_MB 0x1d45 +#define VPP_VADJ2_MC_MD 0x1d46 +#define VPP_HSHARP_CTRL 0x1d50 +#define VPP_HSHARP_LUMA_THRESH01 0x1d51 +#define VPP_HSHARP_LUMA_THRESH23 0x1d52 +#define VPP_HSHARP_CHROMA_THRESH01 0x1d53 +#define VPP_HSHARP_CHROMA_THRESH23 0x1d54 +#define VPP_HSHARP_LUMA_GAIN 0x1d55 +#define VPP_HSHARP_CHROMA_GAIN 0x1d56 +#define VPP_MATRIX_PROBE_COLOR 0x1d5c +#define VPP_MATRIX_HL_COLOR 0x1d5d +#define VPP_MATRIX_PROBE_POS 0x1d5e +#define VPP_MATRIX_CTRL 0x1d5f +#define VPP_MATRIX_COEF00_01 0x1d60 +#define VPP_MATRIX_COEF02_10 0x1d61 +#define VPP_MATRIX_COEF11_12 0x1d62 +#define VPP_MATRIX_COEF20_21 0x1d63 +#define VPP_MATRIX_COEF22 0x1d64 +#define VPP_MATRIX_OFFSET0_1 0x1d65 +#define VPP_MATRIX_OFFSET2 0x1d66 +#define VPP_MATRIX_PRE_OFFSET0_1 0x1d67 +#define VPP_MATRIX_PRE_OFFSET2 0x1d68 +#define VPP_DUMMY_DATA1 0x1d69 +#define VPP_GAINOFF_CTRL0 0x1d6a +#define VPP_GAINOFF_CTRL1 0x1d6b +#define VPP_GAINOFF_CTRL2 0x1d6c +#define VPP_GAINOFF_CTRL3 0x1d6d +#define VPP_GAINOFF_CTRL4 0x1d6e +#define VPP_CHROMA_ADDR_PORT 0x1d70 +#define VPP_CHROMA_DATA_PORT 0x1d71 +#define VPP_GCLK_CTRL0 0x1d72 +#define VPP_GCLK_CTRL1 0x1d73 +#define VPP_SC_GCLK_CTRL 0x1d74 +#define VPP_MISC1 0x1d76 +#define VPP_BLACKEXT_CTRL 0x1d80 +#define VPP_DNLP_CTRL_00 0x1d81 +#define VPP_DNLP_CTRL_01 0x1d82 +#define VPP_DNLP_CTRL_02 0x1d83 +#define VPP_DNLP_CTRL_03 0x1d84 +#define VPP_DNLP_CTRL_04 0x1d85 +#define VPP_DNLP_CTRL_05 0x1d86 +#define VPP_DNLP_CTRL_06 0x1d87 +#define VPP_DNLP_CTRL_07 0x1d88 +#define VPP_DNLP_CTRL_08 0x1d89 +#define VPP_DNLP_CTRL_09 0x1d8a +#define VPP_DNLP_CTRL_10 0x1d8b +#define VPP_DNLP_CTRL_11 0x1d8c +#define VPP_DNLP_CTRL_12 0x1d8d +#define VPP_DNLP_CTRL_13 0x1d8e +#define VPP_DNLP_CTRL_14 0x1d8f +#define VPP_DNLP_CTRL_15 0x1d90 +#define VPP_PEAKING_HGAIN 0x1d91 +#define VPP_PEAKING_VGAIN 0x1d92 +#define VPP_PEAKING_NLP_1 0x1d93 +#define VPP_PEAKING_NLP_2 0x1d94 +#define VPP_PEAKING_NLP_3 0x1d95 +#define VPP_PEAKING_NLP_4 0x1d96 +#define VPP_PEAKING_NLP_5 0x1d97 +#define VPP_SHARP_LIMIT 0x1d98 +#define VPP_VLTI_CTRL 0x1d99 +#define VPP_HLTI_CTRL 0x1d9a +#define VPP_CTI_CTRL 0x1d9b +#define VPP_BLUE_STRETCH_1 0x1d9c +#define VPP_BLUE_STRETCH_2 0x1d9d +#define VPP_BLUE_STRETCH_3 0x1d9e +#define VPP_CCORING_CTRL 0x1da0 +#define VPP_VE_ENABLE_CTRL 0x1da1 +#define VPP_VE_DEMO_LEFT_TOP_SCREEN_WIDTH 0x1da2 +#define VPP_VE_DEMO_CENTER_BAR 0x1da3 +#define VPP_VE_H_V_SIZE 0x1da4 +#define VPP_VDO_MEAS_CTRL 0x1da8 +#define VPP_VDO_MEAS_VS_COUNT_HI 0x1da9 +#define VPP_VDO_MEAS_VS_COUNT_LO 0x1daa +#define VPP_INPUT_CTRL 0x1dab +#define VPP_CTI_CTRL2 0x1dac +#define VPP_PEAKING_SAT_THD1 0x1dad +#define VPP_PEAKING_SAT_THD2 0x1dae +#define VPP_PEAKING_SAT_THD3 0x1daf +#define VPP_PEAKING_SAT_THD4 0x1db0 +#define VPP_PEAKING_SAT_THD5 0x1db1 +#define VPP_PEAKING_SAT_THD6 0x1db2 +#define VPP_PEAKING_SAT_THD7 0x1db3 +#define VPP_PEAKING_SAT_THD8 0x1db4 +#define VPP_PEAKING_SAT_THD9 0x1db5 +#define VPP_PEAKING_GAIN_ADD1 0x1db6 +#define VPP_PEAKING_GAIN_ADD2 0x1db7 +#define VPP_PEAKING_DNLP 0x1db8 +#define VPP_SHARP_DEMO_WIN_CTRL1 0x1db9 +#define VPP_SHARP_DEMO_WIN_CTRL2 0x1dba +#define VPP_FRONT_HLTI_CTRL 0x1dbb +#define VPP_FRONT_CTI_CTRL 0x1dbc +#define VPP_FRONT_CTI_CTRL2 0x1dbd +#define VPP_OSD_VSC_PHASE_STEP 0x1dc0 +#define VPP_OSD_VSC_INI_PHASE 0x1dc1 +#define VPP_OSD_VSC_CTRL0 0x1dc2 +#define VPP_OSD_HSC_PHASE_STEP 0x1dc3 +#define VPP_OSD_HSC_INI_PHASE 0x1dc4 +#define VPP_OSD_HSC_CTRL0 0x1dc5 +#define VPP_OSD_HSC_INI_PAT_CTRL 0x1dc6 +#define VPP_OSD_SC_DUMMY_DATA 0x1dc7 +#define VPP_OSD_SC_CTRL0 0x1dc8 +#define VPP_OSD_SCI_WH_M1 0x1dc9 +#define VPP_OSD_SCO_H_START_END 0x1dca +#define VPP_OSD_SCO_V_START_END 0x1dcb +#define VPP_OSD_SCALE_COEF_IDX 0x1dcc +#define VPP_OSD_SCALE_COEF 0x1dcd +#define VPP_INT_LINE_NUM 0x1dce + +/* viu2 */ +#define VIU2_ADDR_START 0x1e00 +#define VIU2_ADDR_END 0x1eff +#define VIU2_SW_RESET 0x1e01 +#define VIU2_OSD1_CTRL_STAT 0x1e10 +#define VIU2_OSD1_CTRL_STAT2 0x1e2d +#define VIU2_OSD1_COLOR_ADDR 0x1e11 +#define VIU2_OSD1_COLOR 0x1e12 +#define VIU2_OSD1_TCOLOR_AG0 0x1e17 +#define VIU2_OSD1_TCOLOR_AG1 0x1e18 +#define VIU2_OSD1_TCOLOR_AG2 0x1e19 +#define VIU2_OSD1_TCOLOR_AG3 0x1e1a +#define VIU2_OSD1_BLK0_CFG_W0 0x1e1b +#define VIU2_OSD1_BLK1_CFG_W0 0x1e1f +#define VIU2_OSD1_BLK2_CFG_W0 0x1e23 +#define VIU2_OSD1_BLK3_CFG_W0 0x1e27 +#define VIU2_OSD1_BLK0_CFG_W1 0x1e1c +#define VIU2_OSD1_BLK1_CFG_W1 0x1e20 +#define VIU2_OSD1_BLK2_CFG_W1 0x1e24 +#define VIU2_OSD1_BLK3_CFG_W1 0x1e28 +#define VIU2_OSD1_BLK0_CFG_W2 0x1e1d +#define VIU2_OSD1_BLK1_CFG_W2 0x1e21 +#define VIU2_OSD1_BLK2_CFG_W2 0x1e25 +#define VIU2_OSD1_BLK3_CFG_W2 0x1e29 +#define VIU2_OSD1_BLK0_CFG_W3 0x1e1e +#define VIU2_OSD1_BLK1_CFG_W3 0x1e22 +#define VIU2_OSD1_BLK2_CFG_W3 0x1e26 +#define VIU2_OSD1_BLK3_CFG_W3 0x1e2a +#define VIU2_OSD1_BLK0_CFG_W4 0x1e13 +#define VIU2_OSD1_BLK1_CFG_W4 0x1e14 +#define VIU2_OSD1_BLK2_CFG_W4 0x1e15 +#define VIU2_OSD1_BLK3_CFG_W4 0x1e16 +#define VIU2_OSD1_FIFO_CTRL_STAT 0x1e2b +#define VIU2_OSD1_TEST_RDDATA 0x1e2c +#define VIU2_OSD1_PROT_CTRL 0x1e2e +#define VIU2_OSD2_CTRL_STAT 0x1e30 +#define VIU2_OSD2_CTRL_STAT2 0x1e4d +#define VIU2_OSD2_COLOR_ADDR 0x1e31 +#define VIU2_OSD2_COLOR 0x1e32 +#define VIU2_OSD2_HL1_H_START_END 0x1e33 +#define VIU2_OSD2_HL1_V_START_END 0x1e34 +#define VIU2_OSD2_HL2_H_START_END 0x1e35 +#define VIU2_OSD2_HL2_V_START_END 0x1e36 +#define VIU2_OSD2_TCOLOR_AG0 0x1e37 +#define VIU2_OSD2_TCOLOR_AG1 0x1e38 +#define VIU2_OSD2_TCOLOR_AG2 0x1e39 +#define VIU2_OSD2_TCOLOR_AG3 0x1e3a +#define VIU2_OSD2_BLK0_CFG_W0 0x1e3b +#define VIU2_OSD2_BLK1_CFG_W0 0x1e3f +#define VIU2_OSD2_BLK2_CFG_W0 0x1e43 +#define VIU2_OSD2_BLK3_CFG_W0 0x1e47 +#define VIU2_OSD2_BLK0_CFG_W1 0x1e3c +#define VIU2_OSD2_BLK1_CFG_W1 0x1e40 +#define VIU2_OSD2_BLK2_CFG_W1 0x1e44 +#define VIU2_OSD2_BLK3_CFG_W1 0x1e48 +#define VIU2_OSD2_BLK0_CFG_W2 0x1e3d +#define VIU2_OSD2_BLK1_CFG_W2 0x1e41 +#define VIU2_OSD2_BLK2_CFG_W2 0x1e45 +#define VIU2_OSD2_BLK3_CFG_W2 0x1e49 +#define VIU2_OSD2_BLK0_CFG_W3 0x1e3e +#define VIU2_OSD2_BLK1_CFG_W3 0x1e42 +#define VIU2_OSD2_BLK2_CFG_W3 0x1e46 +#define VIU2_OSD2_BLK3_CFG_W3 0x1e4a +#define VIU2_OSD2_BLK0_CFG_W4 0x1e64 +#define VIU2_OSD2_BLK1_CFG_W4 0x1e65 +#define VIU2_OSD2_BLK2_CFG_W4 0x1e66 +#define VIU2_OSD2_BLK3_CFG_W4 0x1e67 +#define VIU2_OSD2_FIFO_CTRL_STAT 0x1e4b +#define VIU2_OSD2_TEST_RDDATA 0x1e4c +#define VIU2_OSD2_PROT_CTRL 0x1e4e +#define VIU2_VD1_IF0_GEN_REG 0x1e50 +#define VIU2_VD1_IF0_CANVAS0 0x1e51 +#define VIU2_VD1_IF0_CANVAS1 0x1e52 +#define VIU2_VD1_IF0_LUMA_X0 0x1e53 +#define VIU2_VD1_IF0_LUMA_Y0 0x1e54 +#define VIU2_VD1_IF0_CHROMA_X0 0x1e55 +#define VIU2_VD1_IF0_CHROMA_Y0 0x1e56 +#define VIU2_VD1_IF0_LUMA_X1 0x1e57 +#define VIU2_VD1_IF0_LUMA_Y1 0x1e58 +#define VIU2_VD1_IF0_CHROMA_X1 0x1e59 +#define VIU2_VD1_IF0_CHROMA_Y1 0x1e5a +#define VIU2_VD1_IF0_RPT_LOOP 0x1e5b +#define VIU2_VD1_IF0_LUMA0_RPT_PAT 0x1e5c +#define VIU2_VD1_IF0_CHROMA0_RPT_PAT 0x1e5d +#define VIU2_VD1_IF0_LUMA1_RPT_PAT 0x1e5e +#define VIU2_VD1_IF0_CHROMA1_RPT_PAT 0x1e5f +#define VIU2_VD1_IF0_LUMA_PSEL 0x1e60 +#define VIU2_VD1_IF0_CHROMA_PSEL 0x1e61 +#define VIU2_VD1_IF0_DUMMY_PIXEL 0x1e62 +#define VIU2_VD1_IF0_LUMA_FIFO_SIZE 0x1e63 +#define VIU2_VD1_IF0_RANGE_MAP_Y 0x1e6a +#define VIU2_VD1_IF0_RANGE_MAP_CB 0x1e6b +#define VIU2_VD1_IF0_RANGE_MAP_CR 0x1e6c +#define VIU2_VD1_IF0_GEN_REG2 0x1e6d +#define VIU2_VD1_IF0_PROT_CNTL 0x1e6e +#define VIU2_VD1_FMT_CTRL 0x1e68 +#define VIU2_VD1_FMT_W 0x1e69 + +/* encode */ +#define ENCP_VFIFO2VD_CTL 0x1b58 +#define ENCP_VFIFO2VD_PIXEL_START 0x1b59 +#define ENCP_VFIFO2VD_PIXEL_END 0x1b5a +#define ENCP_VFIFO2VD_LINE_TOP_START 0x1b5b +#define ENCP_VFIFO2VD_LINE_TOP_END 0x1b5c +#define ENCP_VFIFO2VD_LINE_BOT_START 0x1b5d +#define ENCP_VFIFO2VD_LINE_BOT_END 0x1b5e +#define VENC_SYNC_ROUTE 0x1b60 +#define VENC_VIDEO_EXSRC 0x1b61 +#define VENC_DVI_SETTING 0x1b62 +#define VENC_C656_CTRL 0x1b63 +#define VENC_UPSAMPLE_CTRL0 0x1b64 +#define VENC_UPSAMPLE_CTRL1 0x1b65 +#define VENC_UPSAMPLE_CTRL2 0x1b66 +#define TCON_INVERT_CTL 0x1b67 +#define VENC_VIDEO_PROG_MODE 0x1b68 +#define VENC_ENCI_LINE 0x1b69 +#define VENC_ENCI_PIXEL 0x1b6a +#define VENC_ENCP_LINE 0x1b6b +#define VENC_ENCP_PIXEL 0x1b6c +#define VENC_STATA 0x1b6d +#define VENC_INTCTRL 0x1b6e +#define VENC_INTFLAG 0x1b6f +#define VENC_VIDEO_TST_EN 0x1b70 +#define VENC_VIDEO_TST_MDSEL 0x1b71 +#define VENC_VIDEO_TST_Y 0x1b72 +#define VENC_VIDEO_TST_CB 0x1b73 +#define VENC_VIDEO_TST_CR 0x1b74 +#define VENC_VIDEO_TST_CLRBAR_STRT 0x1b75 +#define VENC_VIDEO_TST_CLRBAR_WIDTH 0x1b76 +#define VENC_VIDEO_TST_VDCNT_STSET 0x1b77 +#define VENC_VDAC_DACSEL0 0x1b78 +#define VENC_VDAC_DACSEL1 0x1b79 +#define VENC_VDAC_DACSEL2 0x1b7a +#define VENC_VDAC_DACSEL3 0x1b7b +#define VENC_VDAC_DACSEL4 0x1b7c +#define VENC_VDAC_DACSEL5 0x1b7d +#define VENC_VDAC_SETTING 0x1b7e +#define VENC_VDAC_TST_VAL 0x1b7f +#define VENC_VDAC_DAC0_GAINCTRL 0x1bf0 +#define VENC_VDAC_DAC0_OFFSET 0x1bf1 +#define VENC_VDAC_DAC1_GAINCTRL 0x1bf2 +#define VENC_VDAC_DAC1_OFFSET 0x1bf3 +#define VENC_VDAC_DAC2_GAINCTRL 0x1bf4 +#define VENC_VDAC_DAC2_OFFSET 0x1bf5 +#define VENC_VDAC_DAC3_GAINCTRL 0x1bf6 +#define VENC_VDAC_DAC3_OFFSET 0x1bf7 +#define VENC_VDAC_DAC4_GAINCTRL 0x1bf8 +#define VENC_VDAC_DAC4_OFFSET 0x1bf9 +#define VENC_VDAC_DAC5_GAINCTRL 0x1bfa +#define VENC_VDAC_DAC5_OFFSET 0x1bfb +#define VENC_VDAC_FIFO_CTRL 0x1bfc +#define ENCL_TCON_INVERT_CTL 0x1bfd +#define ENCP_VIDEO_EN 0x1b80 +#define ENCP_VIDEO_SYNC_MODE 0x1b81 +#define ENCP_MACV_EN 0x1b82 +#define ENCP_VIDEO_Y_SCL 0x1b83 +#define ENCP_VIDEO_PB_SCL 0x1b84 +#define ENCP_VIDEO_PR_SCL 0x1b85 +#define ENCP_VIDEO_SYNC_SCL 0x1b86 +#define ENCP_VIDEO_MACV_SCL 0x1b87 +#define ENCP_VIDEO_Y_OFFST 0x1b88 +#define ENCP_VIDEO_PB_OFFST 0x1b89 +#define ENCP_VIDEO_PR_OFFST 0x1b8a +#define ENCP_VIDEO_SYNC_OFFST 0x1b8b +#define ENCP_VIDEO_MACV_OFFST 0x1b8c +#define ENCP_VIDEO_MODE 0x1b8d +#define ENCP_VIDEO_MODE_ADV 0x1b8e +#define ENCP_DBG_PX_RST 0x1b90 +#define ENCP_DBG_LN_RST 0x1b91 +#define ENCP_DBG_PX_INT 0x1b92 +#define ENCP_DBG_LN_INT 0x1b93 +#define ENCP_VIDEO_YFP1_HTIME 0x1b94 +#define ENCP_VIDEO_YFP2_HTIME 0x1b95 +#define ENCP_VIDEO_YC_DLY 0x1b96 +#define ENCP_VIDEO_MAX_PXCNT 0x1b97 +#define ENCP_VIDEO_HSPULS_BEGIN 0x1b98 +#define ENCP_VIDEO_HSPULS_END 0x1b99 +#define ENCP_VIDEO_HSPULS_SWITCH 0x1b9a +#define ENCP_VIDEO_VSPULS_BEGIN 0x1b9b +#define ENCP_VIDEO_VSPULS_END 0x1b9c +#define ENCP_VIDEO_VSPULS_BLINE 0x1b9d +#define ENCP_VIDEO_VSPULS_ELINE 0x1b9e +#define ENCP_VIDEO_EQPULS_BEGIN 0x1b9f +#define ENCP_VIDEO_EQPULS_END 0x1ba0 +#define ENCP_VIDEO_EQPULS_BLINE 0x1ba1 +#define ENCP_VIDEO_EQPULS_ELINE 0x1ba2 +#define ENCP_VIDEO_HAVON_END 0x1ba3 +#define ENCP_VIDEO_HAVON_BEGIN 0x1ba4 +#define ENCP_VIDEO_VAVON_ELINE 0x1baf +#define ENCP_VIDEO_VAVON_BLINE 0x1ba6 +#define ENCP_VIDEO_HSO_BEGIN 0x1ba7 +#define ENCP_VIDEO_HSO_END 0x1ba8 +#define ENCP_VIDEO_VSO_BEGIN 0x1ba9 +#define ENCP_VIDEO_VSO_END 0x1baa +#define ENCP_VIDEO_VSO_BLINE 0x1bab +#define ENCP_VIDEO_VSO_ELINE 0x1bac +#define ENCP_VIDEO_SYNC_WAVE_CURVE 0x1bad +#define ENCP_VIDEO_MAX_LNCNT 0x1bae +#define ENCP_VIDEO_SY_VAL 0x1bb0 +#define ENCP_VIDEO_SY2_VAL 0x1bb1 +#define ENCP_VIDEO_BLANKY_VAL 0x1bb2 +#define ENCP_VIDEO_BLANKPB_VAL 0x1bb3 +#define ENCP_VIDEO_BLANKPR_VAL 0x1bb4 +#define ENCP_VIDEO_HOFFST 0x1bb5 +#define ENCP_VIDEO_VOFFST 0x1bb6 +#define ENCP_VIDEO_RGB_CTRL 0x1bb7 +#define ENCP_VIDEO_FILT_CTRL 0x1bb8 +#define ENCP_VIDEO_OFLD_VPEQ_OFST 0x1bb9 +#define ENCP_VIDEO_OFLD_VOAV_OFST 0x1bba +#define ENCP_VIDEO_MATRIX_CB 0x1bbb +#define ENCP_VIDEO_MATRIX_CR 0x1bbc +#define ENCP_VIDEO_RGBIN_CTRL 0x1bbd +#define ENCP_MACV_BLANKY_VAL 0x1bc0 +#define ENCP_MACV_MAXY_VAL 0x1bc1 +#define ENCP_MACV_1ST_PSSYNC_STRT 0x1bc2 +#define ENCP_MACV_PSSYNC_STRT 0x1bc3 +#define ENCP_MACV_AGC_STRT 0x1bc4 +#define ENCP_MACV_AGC_END 0x1bc5 +#define ENCP_MACV_WAVE_END 0x1bc6 +#define ENCP_MACV_STRTLINE 0x1bc7 +#define ENCP_MACV_ENDLINE 0x1bc8 +#define ENCP_MACV_TS_CNT_MAX_L 0x1bc9 +#define ENCP_MACV_TS_CNT_MAX_H 0x1bca +#define ENCP_MACV_TIME_DOWN 0x1bcb +#define ENCP_MACV_TIME_LO 0x1bcc +#define ENCP_MACV_TIME_UP 0x1bcd +#define ENCP_MACV_TIME_RST 0x1bce +#define ENCP_VBI_CTRL 0x1bd0 +#define ENCP_VBI_SETTING 0x1bd1 +#define ENCP_VBI_BEGIN 0x1bd2 +#define ENCP_VBI_WIDTH 0x1bd3 +#define ENCP_VBI_HVAL 0x1bd4 +#define ENCP_VBI_DATA0 0x1bd5 +#define ENCP_VBI_DATA1 0x1bd6 +#define C656_HS_ST 0x1be0 +#define C656_HS_ED 0x1be1 +#define C656_VS_LNST_E 0x1be2 +#define C656_VS_LNST_O 0x1be3 +#define C656_VS_LNED_E 0x1be4 +#define C656_VS_LNED_O 0x1be5 +#define C656_FS_LNST 0x1be6 +#define C656_FS_LNED 0x1be7 +#define ENCI_VIDEO_MODE 0x1b00 +#define ENCI_VIDEO_MODE_ADV 0x1b01 +#define ENCI_VIDEO_FSC_ADJ 0x1b02 +#define ENCI_VIDEO_BRIGHT 0x1b03 +#define ENCI_VIDEO_CONT 0x1b04 +#define ENCI_VIDEO_SAT 0x1b05 +#define ENCI_VIDEO_HUE 0x1b06 +#define ENCI_VIDEO_SCH 0x1b07 +#define ENCI_SYNC_MODE 0x1b08 +#define ENCI_SYNC_CTRL 0x1b09 +#define ENCI_SYNC_HSO_BEGIN 0x1b0a +#define ENCI_SYNC_HSO_END 0x1b0b +#define ENCI_SYNC_VSO_EVN 0x1b0c +#define ENCI_SYNC_VSO_ODD 0x1b0d +#define ENCI_SYNC_VSO_EVNLN 0x1b0e +#define ENCI_SYNC_VSO_ODDLN 0x1b0f +#define ENCI_SYNC_HOFFST 0x1b10 +#define ENCI_SYNC_VOFFST 0x1b11 +#define ENCI_SYNC_ADJ 0x1b12 +#define ENCI_RGB_SETTING 0x1b13 +#define ENCI_DE_H_BEGIN 0x1b16 +#define ENCI_DE_H_END 0x1b17 +#define ENCI_DE_V_BEGIN_EVEN 0x1b18 +#define ENCI_DE_V_END_EVEN 0x1b19 +#define ENCI_DE_V_BEGIN_ODD 0x1b1a +#define ENCI_DE_V_END_ODD 0x1b1b +#define ENCI_VBI_SETTING 0x1b20 +#define ENCI_VBI_CCDT_EVN 0x1b21 +#define ENCI_VBI_CCDT_ODD 0x1b22 +#define ENCI_VBI_CC525_LN 0x1b23 +#define ENCI_VBI_CC625_LN 0x1b24 +#define ENCI_VBI_WSSDT 0x1b25 +#define ENCI_VBI_WSS_LN 0x1b26 +#define ENCI_VBI_CGMSDT_L 0x1b27 +#define ENCI_VBI_CGMSDT_H 0x1b28 +#define ENCI_VBI_CGMS_LN 0x1b29 +#define ENCI_VBI_TTX_HTIME 0x1b2a +#define ENCI_VBI_TTX_LN 0x1b2b +#define ENCI_VBI_TTXDT0 0x1b2c +#define ENCI_VBI_TTXDT1 0x1b2d +#define ENCI_VBI_TTXDT2 0x1b2e +#define ENCI_VBI_TTXDT3 0x1b2f +#define ENCI_MACV_N0 0x1b30 +#define ENCI_MACV_N1 0x1b31 +#define ENCI_MACV_N2 0x1b32 +#define ENCI_MACV_N3 0x1b33 +#define ENCI_MACV_N4 0x1b34 +#define ENCI_MACV_N5 0x1b35 +#define ENCI_MACV_N6 0x1b36 +#define ENCI_MACV_N7 0x1b37 +#define ENCI_MACV_N8 0x1b38 +#define ENCI_MACV_N9 0x1b39 +#define ENCI_MACV_N10 0x1b3a +#define ENCI_MACV_N11 0x1b3b +#define ENCI_MACV_N12 0x1b3c +#define ENCI_MACV_N13 0x1b3d +#define ENCI_MACV_N14 0x1b3e +#define ENCI_MACV_N15 0x1b3f +#define ENCI_MACV_N16 0x1b40 +#define ENCI_MACV_N17 0x1b41 +#define ENCI_MACV_N18 0x1b42 +#define ENCI_MACV_N19 0x1b43 +#define ENCI_MACV_N20 0x1b44 +#define ENCI_MACV_N21 0x1b45 +#define ENCI_MACV_N22 0x1b46 +#define ENCI_DBG_PX_RST 0x1b48 +#define ENCI_DBG_FLDLN_RST 0x1b49 +#define ENCI_DBG_PX_INT 0x1b4a +#define ENCI_DBG_FLDLN_INT 0x1b4b +#define ENCI_DBG_MAXPX 0x1b4c +#define ENCI_DBG_MAXLN 0x1b4d +#define ENCI_MACV_MAX_AMP 0x1b50 +#define ENCI_MACV_PULSE_LO 0x1b51 +#define ENCI_MACV_PULSE_HI 0x1b52 +#define ENCI_MACV_BKP_MAX 0x1b53 +#define ENCI_CFILT_CTRL 0x1b54 +#define ENCI_CFILT7 0x1b55 +#define ENCI_YC_DELAY 0x1b56 +#define ENCI_VIDEO_EN 0x1b57 +#define ENCI_DVI_HSO_BEGIN 0x1c00 +#define ENCI_DVI_HSO_END 0x1c01 +#define ENCI_DVI_VSO_BLINE_EVN 0x1c02 +#define ENCI_DVI_VSO_BLINE_ODD 0x1c03 +#define ENCI_DVI_VSO_ELINE_EVN 0x1c04 +#define ENCI_DVI_VSO_ELINE_ODD 0x1c05 +#define ENCI_DVI_VSO_BEGIN_EVN 0x1c06 +#define ENCI_DVI_VSO_BEGIN_ODD 0x1c07 +#define ENCI_DVI_VSO_END_EVN 0x1c08 +#define ENCI_DVI_VSO_END_ODD 0x1c09 +#define ENCI_CFILT_CTRL2 0x1c0a +#define ENCI_DACSEL_0 0x1c0b +#define ENCI_DACSEL_1 0x1c0c +#define ENCP_DACSEL_0 0x1c0d +#define ENCP_DACSEL_1 0x1c0e +#define ENCP_MAX_LINE_SWITCH_POINT 0x1c0f +#define ENCI_TST_EN 0x1c10 +#define ENCI_TST_MDSEL 0x1c11 +#define ENCI_TST_Y 0x1c12 +#define ENCI_TST_CB 0x1c13 +#define ENCI_TST_CR 0x1c14 +#define ENCI_TST_CLRBAR_STRT 0x1c15 +#define ENCI_TST_CLRBAR_WIDTH 0x1c16 +#define ENCI_TST_VDCNT_STSET 0x1c17 +#define ENCI_VFIFO2VD_CTL 0x1c18 +#define ENCI_VFIFO2VD_PIXEL_START 0x1c19 +#define ENCI_VFIFO2VD_PIXEL_END 0x1c1a +#define ENCI_VFIFO2VD_LINE_TOP_START 0x1c1b +#define ENCI_VFIFO2VD_LINE_TOP_END 0x1c1c +#define ENCI_VFIFO2VD_LINE_BOT_START 0x1c1d +#define ENCI_VFIFO2VD_LINE_BOT_END 0x1c1e +#define ENCI_VFIFO2VD_CTL2 0x1c1f +#define ENCT_VFIFO2VD_CTL 0x1c20 +#define ENCT_VFIFO2VD_PIXEL_START 0x1c21 +#define ENCT_VFIFO2VD_PIXEL_END 0x1c22 +#define ENCT_VFIFO2VD_LINE_TOP_START 0x1c23 +#define ENCT_VFIFO2VD_LINE_TOP_END 0x1c24 +#define ENCT_VFIFO2VD_LINE_BOT_START 0x1c25 +#define ENCT_VFIFO2VD_LINE_BOT_END 0x1c26 +#define ENCT_VFIFO2VD_CTL2 0x1c27 +#define ENCT_TST_EN 0x1c28 +#define ENCT_TST_MDSEL 0x1c29 +#define ENCT_TST_Y 0x1c2a +#define ENCT_TST_CB 0x1c2b +#define ENCT_TST_CR 0x1c2c +#define ENCT_TST_CLRBAR_STRT 0x1c2d +#define ENCT_TST_CLRBAR_WIDTH 0x1c2e +#define ENCT_TST_VDCNT_STSET 0x1c2f +#define ENCP_DVI_HSO_BEGIN 0x1c30 +#define ENCP_DVI_HSO_END 0x1c31 +#define ENCP_DVI_VSO_BLINE_EVN 0x1c32 +#define ENCP_DVI_VSO_BLINE_ODD 0x1c33 +#define ENCP_DVI_VSO_ELINE_EVN 0x1c34 +#define ENCP_DVI_VSO_ELINE_ODD 0x1c35 +#define ENCP_DVI_VSO_BEGIN_EVN 0x1c36 +#define ENCP_DVI_VSO_BEGIN_ODD 0x1c37 +#define ENCP_DVI_VSO_END_EVN 0x1c38 +#define ENCP_DVI_VSO_END_ODD 0x1c39 +#define ENCP_DE_H_BEGIN 0x1c3a +#define ENCP_DE_H_END 0x1c3b +#define ENCP_DE_V_BEGIN_EVEN 0x1c3c +#define ENCP_DE_V_END_EVEN 0x1c3d +#define ENCP_DE_V_BEGIN_ODD 0x1c3e +#define ENCP_DE_V_END_ODD 0x1c3f +#define ENCI_SYNC_LINE_LENGTH 0x1c40 +#define ENCI_SYNC_PIXEL_EN 0x1c41 +#define ENCI_SYNC_TO_LINE_EN 0x1c42 +#define ENCI_SYNC_TO_PIXEL 0x1c43 +#define ENCP_SYNC_LINE_LENGTH 0x1c44 +#define ENCP_SYNC_PIXEL_EN 0x1c45 +#define ENCP_SYNC_TO_LINE_EN 0x1c46 +#define ENCP_SYNC_TO_PIXEL 0x1c47 +#define ENCT_SYNC_LINE_LENGTH 0x1c48 +#define ENCT_SYNC_PIXEL_EN 0x1c49 +#define ENCT_SYNC_TO_LINE_EN 0x1c4a +#define ENCT_SYNC_TO_PIXEL 0x1c4b +#define ENCL_SYNC_LINE_LENGTH 0x1c4c +#define ENCL_SYNC_PIXEL_EN 0x1c4d +#define ENCL_SYNC_TO_LINE_EN 0x1c4e +#define ENCL_SYNC_TO_PIXEL 0x1c4f +#define ENCP_VFIFO2VD_CTL2 0x1c50 +#define VENC_DVI_SETTING_MORE 0x1c51 +#define VENC_VDAC_DAC4_FILT_CTRL0 0x1c54 +#define VENC_VDAC_DAC4_FILT_CTRL1 0x1c55 +#define VENC_VDAC_DAC5_FILT_CTRL0 0x1c56 +#define VENC_VDAC_DAC5_FILT_CTRL1 0x1c57 +#define VENC_VDAC_DAC0_FILT_CTRL0 0x1c58 +#define VENC_VDAC_DAC0_FILT_CTRL1 0x1c59 +#define VENC_VDAC_DAC1_FILT_CTRL0 0x1c5a +#define VENC_VDAC_DAC1_FILT_CTRL1 0x1c5b +#define VENC_VDAC_DAC2_FILT_CTRL0 0x1c5c +#define VENC_VDAC_DAC2_FILT_CTRL1 0x1c5d +#define VENC_VDAC_DAC3_FILT_CTRL0 0x1c5e +#define VENC_VDAC_DAC3_FILT_CTRL1 0x1c5f +#define ENCT_VIDEO_EN 0x1c60 +#define ENCT_VIDEO_Y_SCL 0x1c61 +#define ENCT_VIDEO_PB_SCL 0x1c62 +#define ENCT_VIDEO_PR_SCL 0x1c63 +#define ENCT_VIDEO_Y_OFFST 0x1c64 +#define ENCT_VIDEO_PB_OFFST 0x1c65 +#define ENCT_VIDEO_PR_OFFST 0x1c66 +#define ENCT_VIDEO_MODE 0x1c67 +#define ENCT_VIDEO_MODE_ADV 0x1c68 +#define ENCT_DBG_PX_RST 0x1c69 +#define ENCT_DBG_LN_RST 0x1c6a +#define ENCT_DBG_PX_INT 0x1c6b +#define ENCT_DBG_LN_INT 0x1c6c +#define ENCT_VIDEO_YFP1_HTIME 0x1c6d +#define ENCT_VIDEO_YFP2_HTIME 0x1c6e +#define ENCT_VIDEO_YC_DLY 0x1c6f +#define ENCT_VIDEO_MAX_PXCNT 0x1c70 +#define ENCT_VIDEO_HAVON_END 0x1c71 +#define ENCT_VIDEO_HAVON_BEGIN 0x1c72 +#define ENCT_VIDEO_VAVON_ELINE 0x1c73 +#define ENCT_VIDEO_VAVON_BLINE 0x1c74 +#define ENCT_VIDEO_HSO_BEGIN 0x1c75 +#define ENCT_VIDEO_HSO_END 0x1c76 +#define ENCT_VIDEO_VSO_BEGIN 0x1c77 +#define ENCT_VIDEO_VSO_END 0x1c78 +#define ENCT_VIDEO_VSO_BLINE 0x1c79 +#define ENCT_VIDEO_VSO_ELINE 0x1c7a +#define ENCT_VIDEO_MAX_LNCNT 0x1c7b +#define ENCT_VIDEO_BLANKY_VAL 0x1c7c +#define ENCT_VIDEO_BLANKPB_VAL 0x1c7d +#define ENCT_VIDEO_BLANKPR_VAL 0x1c7e +#define ENCT_VIDEO_HOFFST 0x1c7f +#define ENCT_VIDEO_VOFFST 0x1c80 +#define ENCT_VIDEO_RGB_CTRL 0x1c81 +#define ENCT_VIDEO_FILT_CTRL 0x1c82 +#define ENCT_VIDEO_OFLD_VPEQ_OFST 0x1c83 +#define ENCT_VIDEO_OFLD_VOAV_OFST 0x1c84 +#define ENCT_VIDEO_MATRIX_CB 0x1c85 +#define ENCT_VIDEO_MATRIX_CR 0x1c86 +#define ENCT_VIDEO_RGBIN_CTRL 0x1c87 +#define ENCT_MAX_LINE_SWITCH_POINT 0x1c88 +#define ENCT_DACSEL_0 0x1c89 +#define ENCT_DACSEL_1 0x1c8a +#define ENCL_VFIFO2VD_CTL 0x1c90 +#define ENCL_VFIFO2VD_PIXEL_START 0x1c91 +#define ENCL_VFIFO2VD_PIXEL_END 0x1c92 +#define ENCL_VFIFO2VD_LINE_TOP_START 0x1c93 +#define ENCL_VFIFO2VD_LINE_TOP_END 0x1c94 +#define ENCL_VFIFO2VD_LINE_BOT_START 0x1c95 +#define ENCL_VFIFO2VD_LINE_BOT_END 0x1c96 +#define ENCL_VFIFO2VD_CTL2 0x1c97 +#define ENCL_TST_EN 0x1c98 +#define ENCL_TST_MDSEL 0x1c99 +#define ENCL_TST_Y 0x1c9a +#define ENCL_TST_CB 0x1c9b +#define ENCL_TST_CR 0x1c9c +#define ENCL_TST_CLRBAR_STRT 0x1c9d +#define ENCL_TST_CLRBAR_WIDTH 0x1c9e +#define ENCL_TST_VDCNT_STSET 0x1c9f +#define ENCL_VIDEO_EN 0x1ca0 +#define ENCL_VIDEO_Y_SCL 0x1ca1 +#define ENCL_VIDEO_PB_SCL 0x1ca2 +#define ENCL_VIDEO_PR_SCL 0x1ca3 +#define ENCL_VIDEO_Y_OFFST 0x1ca4 +#define ENCL_VIDEO_PB_OFFST 0x1ca5 +#define ENCL_VIDEO_PR_OFFST 0x1ca6 +#define ENCL_VIDEO_MODE 0x1ca7 +#define ENCL_VIDEO_MODE_ADV 0x1ca8 +#define ENCL_DBG_PX_RST 0x1ca9 +#define ENCL_DBG_LN_RST 0x1caa +#define ENCL_DBG_PX_INT 0x1cab +#define ENCL_DBG_LN_INT 0x1cac +#define ENCL_VIDEO_YFP1_HTIME 0x1cad +#define ENCL_VIDEO_YFP2_HTIME 0x1cae +#define ENCL_VIDEO_YC_DLY 0x1caf +#define ENCL_VIDEO_MAX_PXCNT 0x1cb0 +#define ENCL_VIDEO_HAVON_END 0x1cb1 +#define ENCL_VIDEO_HAVON_BEGIN 0x1cb2 +#define ENCL_VIDEO_VAVON_ELINE 0x1cb3 +#define ENCL_VIDEO_VAVON_BLINE 0x1cb4 +#define ENCL_VIDEO_HSO_BEGIN 0x1cb5 +#define ENCL_VIDEO_HSO_END 0x1cb6 +#define ENCL_VIDEO_VSO_BEGIN 0x1cb7 +#define ENCL_VIDEO_VSO_END 0x1cb8 +#define ENCL_VIDEO_VSO_BLINE 0x1cb9 +#define ENCL_VIDEO_VSO_ELINE 0x1cba +#define ENCL_VIDEO_MAX_LNCNT 0x1cbb +#define ENCL_VIDEO_BLANKY_VAL 0x1cbc +#define ENCL_VIDEO_BLANKPB_VAL 0x1cbd +#define ENCL_VIDEO_BLANKPR_VAL 0x1cbe +#define ENCL_VIDEO_HOFFST 0x1cbf +#define ENCL_VIDEO_VOFFST 0x1cc0 +#define ENCL_VIDEO_RGB_CTRL 0x1cc1 +#define ENCL_VIDEO_FILT_CTRL 0x1cc2 +#define ENCL_VIDEO_OFLD_VPEQ_OFST 0x1cc3 +#define ENCL_VIDEO_OFLD_VOAV_OFST 0x1cc4 +#define ENCL_VIDEO_MATRIX_CB 0x1cc5 +#define ENCL_VIDEO_MATRIX_CR 0x1cc6 +#define ENCL_VIDEO_RGBIN_CTRL 0x1cc7 +#define ENCL_MAX_LINE_SWITCH_POINT 0x1cc8 +#define ENCL_DACSEL_0 0x1cc9 +#define ENCL_DACSEL_1 0x1cca +#define RDMA_AHB_START_ADDR_MAN 0x1100 +#define RDMA_AHB_END_ADDR_MAN 0x1101 +#define RDMA_AHB_START_ADDR_1 0x1102 +#define RDMA_AHB_END_ADDR_1 0x1103 +#define RDMA_AHB_START_ADDR_2 0x1104 +#define RDMA_AHB_END_ADDR_2 0x1105 +#define RDMA_AHB_START_ADDR_3 0x1106 +#define RDMA_AHB_END_ADDR_3 0x1107 +#define RDMA_AHB_START_ADDR_4 0x1108 +#define RDMA_AHB_END_ADDR_4 0x1109 +#define RDMA_AHB_START_ADDR_5 0x110a +#define RDMA_AHB_END_ADDR_5 0x110b +#define RDMA_AHB_START_ADDR_6 0x110c +#define RDMA_AHB_END_ADDR_6 0x110d +#define RDMA_AHB_START_ADDR_7 0x110e +#define RDMA_AHB_END_ADDR_7 0x110f +#define RDMA_ACCESS_AUTO 0x1110 +#define RDMA_ACCESS_AUTO2 0x1111 +#define RDMA_ACCESS_AUTO3 0x1112 +#define RDMA_ACCESS_MAN 0x1113 +#define RDMA_CTRL 0x1114 +#define RDMA_STATUS 0x1115 +#define RDMA_STATUS2 0x1116 +#define RDMA_STATUS3 0x1117 +#define L_GAMMA_CNTL_PORT 0x1400 +#define L_GAMMA_DATA_PORT 0x1401 +#define L_GAMMA_ADDR_PORT 0x1402 +#define L_GAMMA_VCOM_HSWITCH_ADDR 0x1403 +#define L_RGB_BASE_ADDR 0x1405 +#define L_RGB_COEFF_ADDR 0x1406 +#define L_POL_CNTL_ADDR 0x1407 +#define L_DITH_CNTL_ADDR 0x1408 +#define L_GAMMA_PROBE_CTRL 0x1409 +#define L_GAMMA_PROBE_COLOR_L 0x140a +#define L_GAMMA_PROBE_COLOR_H 0x140b +#define L_GAMMA_PROBE_HL_COLOR 0x140c +#define L_GAMMA_PROBE_POS_X 0x140d +#define L_GAMMA_PROBE_POS_Y 0x140e +#define L_STH1_HS_ADDR 0x1410 +#define L_STH1_HE_ADDR 0x1411 +#define L_STH1_VS_ADDR 0x1412 +#define L_STH1_VE_ADDR 0x1413 +#define L_STH2_HS_ADDR 0x1414 +#define L_STH2_HE_ADDR 0x1415 +#define L_STH2_VS_ADDR 0x1416 +#define L_STH2_VE_ADDR 0x1417 +#define L_OEH_HS_ADDR 0x1418 +#define L_OEH_HE_ADDR 0x1419 +#define L_OEH_VS_ADDR 0x141a +#define L_OEH_VE_ADDR 0x141b +#define L_VCOM_HSWITCH_ADDR 0x141c +#define L_VCOM_VS_ADDR 0x141d +#define L_VCOM_VE_ADDR 0x141e +#define L_CPV1_HS_ADDR 0x141f +#define L_CPV1_HE_ADDR 0x1420 +#define L_CPV1_VS_ADDR 0x1421 +#define L_CPV1_VE_ADDR 0x1422 +#define L_CPV2_HS_ADDR 0x1423 +#define L_CPV2_HE_ADDR 0x1424 +#define L_CPV2_VS_ADDR 0x1425 +#define L_CPV2_VE_ADDR 0x1426 +#define L_STV1_HS_ADDR 0x1427 +#define L_STV1_HE_ADDR 0x1428 +#define L_STV1_VS_ADDR 0x1429 +#define L_STV1_VE_ADDR 0x142a +#define L_STV2_HS_ADDR 0x142b +#define L_STV2_HE_ADDR 0x142c +#define L_STV2_VS_ADDR 0x142d +#define L_STV2_VE_ADDR 0x142e +#define L_OEV1_HS_ADDR 0x142f +#define L_OEV1_HE_ADDR 0x1430 +#define L_OEV1_VS_ADDR 0x1431 +#define L_OEV1_VE_ADDR 0x1432 +#define L_OEV2_HS_ADDR 0x1433 +#define L_OEV2_HE_ADDR 0x1434 +#define L_OEV2_VS_ADDR 0x1435 +#define L_OEV2_VE_ADDR 0x1436 +#define L_OEV3_HS_ADDR 0x1437 +#define L_OEV3_HE_ADDR 0x1438 +#define L_OEV3_VS_ADDR 0x1439 +#define L_OEV3_VE_ADDR 0x143a +#define L_LCD_PWR_ADDR 0x143b +#define L_LCD_PWM0_LO_ADDR 0x143c +#define L_LCD_PWM0_HI_ADDR 0x143d +#define L_LCD_PWM1_LO_ADDR 0x143e +#define L_LCD_PWM1_HI_ADDR 0x143f +#define L_INV_CNT_ADDR 0x1440 +#define L_TCON_MISC_SEL_ADDR 0x1441 +#define L_DUAL_PORT_CNTL_ADDR 0x1442 +#define MLVDS_CLK_CTL1_HI 0x1443 +#define MLVDS_CLK_CTL1_LO 0x1444 +#define L_TCON_DOUBLE_CTL 0x1449 +#define L_TCON_PATTERN_HI 0x144a +#define L_TCON_PATTERN_LO 0x144b +#define LDIM_BL_ADDR_PORT 0x144e +#define LDIM_BL_DATA_PORT 0x144f +#define L_DE_HS_ADDR 0x1451 +#define L_DE_HE_ADDR 0x1452 +#define L_DE_VS_ADDR 0x1453 +#define L_DE_VE_ADDR 0x1454 +#define L_HSYNC_HS_ADDR 0x1455 +#define L_HSYNC_HE_ADDR 0x1456 +#define L_HSYNC_VS_ADDR 0x1457 +#define L_HSYNC_VE_ADDR 0x1458 +#define L_VSYNC_HS_ADDR 0x1459 +#define L_VSYNC_HE_ADDR 0x145a +#define L_VSYNC_VS_ADDR 0x145b +#define L_VSYNC_VE_ADDR 0x145c +#define L_LCD_MCU_CTL 0x145d +#define DUAL_MLVDS_CTL 0x1460 +#define DUAL_MLVDS_LINE_START 0x1461 +#define DUAL_MLVDS_LINE_END 0x1462 +#define DUAL_MLVDS_PIXEL_W_START_L 0x1463 +#define DUAL_MLVDS_PIXEL_W_END_L 0x1464 +#define DUAL_MLVDS_PIXEL_W_START_R 0x1465 +#define DUAL_MLVDS_PIXEL_W_END_R 0x1466 +#define DUAL_MLVDS_PIXEL_R_START_L 0x1467 +#define DUAL_MLVDS_PIXEL_R_CNT_L 0x1468 +#define DUAL_MLVDS_PIXEL_R_START_R 0x1469 +#define DUAL_MLVDS_PIXEL_R_CNT_R 0x146a +#define V_INVERSION_PIXEL 0x1470 +#define V_INVERSION_LINE 0x1471 +#define V_INVERSION_CONTROL 0x1472 +#define MLVDS2_CONTROL 0x1474 +#define MLVDS2_CONFIG_HI 0x1475 +#define MLVDS2_CONFIG_LO 0x1476 +#define MLVDS2_DUAL_GATE_WR_START 0x1477 +#define MLVDS2_DUAL_GATE_WR_END 0x1478 +#define MLVDS2_DUAL_GATE_RD_START 0x1479 +#define MLVDS2_DUAL_GATE_RD_END 0x147a +#define MLVDS2_SECOND_RESET_CTL 0x147b +#define MLVDS2_DUAL_GATE_CTL_HI 0x147c +#define MLVDS2_DUAL_GATE_CTL_LO 0x147d +#define MLVDS2_RESET_CONFIG_HI 0x147e +#define MLVDS2_RESET_CONFIG_LO 0x147f +#define GAMMA_CNTL_PORT 0x1480 +#define GAMMA_DATA_PORT 0x1481 +#define GAMMA_ADDR_PORT 0x1482 +#define GAMMA_VCOM_HSWITCH_ADDR 0x1483 +#define RGB_BASE_ADDR 0x1485 +#define RGB_COEFF_ADDR 0x1486 +#define POL_CNTL_ADDR 0x1487 +#define DITH_CNTL_ADDR 0x1488 +#define GAMMA_PROBE_CTRL 0x1489 +#define GAMMA_PROBE_COLOR_L 0x148a +#define GAMMA_PROBE_COLOR_H 0x148b +#define GAMMA_PROBE_HL_COLOR 0x148c +#define GAMMA_PROBE_POS_X 0x148d +#define GAMMA_PROBE_POS_Y 0x148e +#define STH1_HS_ADDR 0x1490 +#define STH1_HE_ADDR 0x1491 +#define STH1_VS_ADDR 0x1492 +#define STH1_VE_ADDR 0x1493 +#define STH2_HS_ADDR 0x1494 +#define STH2_HE_ADDR 0x1495 +#define STH2_VS_ADDR 0x1496 +#define STH2_VE_ADDR 0x1497 +#define OEH_HS_ADDR 0x1498 +#define OEH_HE_ADDR 0x1499 +#define OEH_VS_ADDR 0x149a +#define OEH_VE_ADDR 0x149b +#define VCOM_HSWITCH_ADDR 0x149c +#define VCOM_VS_ADDR 0x149d +#define VCOM_VE_ADDR 0x149e +#define CPV1_HS_ADDR 0x149f +#define CPV1_HE_ADDR 0x14a0 +#define CPV1_VS_ADDR 0x14a1 +#define CPV1_VE_ADDR 0x14a2 +#define CPV2_HS_ADDR 0x14a3 +#define CPV2_HE_ADDR 0x14a4 +#define CPV2_VS_ADDR 0x14a5 +#define CPV2_VE_ADDR 0x14a6 +#define STV1_HS_ADDR 0x14a7 +#define STV1_HE_ADDR 0x14a8 +#define STV1_VS_ADDR 0x14a9 +#define STV1_VE_ADDR 0x14aa +#define STV2_HS_ADDR 0x14ab +#define STV2_HE_ADDR 0x14ac +#define STV2_VS_ADDR 0x14ad +#define STV2_VE_ADDR 0x14ae +#define OEV1_HS_ADDR 0x14af +#define OEV1_HE_ADDR 0x14b0 +#define OEV1_VS_ADDR 0x14b1 +#define OEV1_VE_ADDR 0x14b2 +#define OEV2_HS_ADDR 0x14b3 +#define OEV2_HE_ADDR 0x14b4 +#define OEV2_VS_ADDR 0x14b5 +#define OEV2_VE_ADDR 0x14b6 +#define OEV3_HS_ADDR 0x14b7 +#define OEV3_HE_ADDR 0x14b8 +#define OEV3_VS_ADDR 0x14b9 +#define OEV3_VE_ADDR 0x14ba +#define LCD_PWR_ADDR 0x14bb +#define LCD_PWM0_LO_ADDR 0x14bc +#define LCD_PWM0_HI_ADDR 0x14bd +#define LCD_PWM1_LO_ADDR 0x14be +#define LCD_PWM1_HI_ADDR 0x14bf +#define INV_CNT_ADDR 0x14c0 +#define TCON_MISC_SEL_ADDR 0x14c1 +#define DUAL_PORT_CNTL_ADDR 0x14c2 +#define MLVDS_CONTROL 0x14c3 +#define MLVDS_RESET_PATTERN_HI 0x14c4 +#define MLVDS_RESET_PATTERN_LO 0x14c5 +#define MLVDS_RESET_PATTERN_EXT 0x14c6 +#define MLVDS_CONFIG_HI 0x14c7 +#define MLVDS_CONFIG_LO 0x14c8 +#define TCON_DOUBLE_CTL 0x14c9 +#define TCON_PATTERN_HI 0x14ca +#define TCON_PATTERN_LO 0x14cb +#define TCON_CONTROL_HI 0x14cc +#define TCON_CONTROL_LO 0x14cd +#define LVDS_BLANK_DATA_HI 0x14ce +#define LVDS_BLANK_DATA_LO 0x14cf +#define LVDS_PACK_CNTL_ADDR 0x14d0 +#define DE_HS_ADDR 0x14d1 +#define DE_HE_ADDR 0x14d2 +#define DE_VS_ADDR 0x14d3 +#define DE_VE_ADDR 0x14d4 +#define HSYNC_HS_ADDR 0x14d5 +#define HSYNC_HE_ADDR 0x14d6 +#define HSYNC_VS_ADDR 0x14d7 +#define HSYNC_VE_ADDR 0x14d8 +#define VSYNC_HS_ADDR 0x14d9 +#define VSYNC_HE_ADDR 0x14da +#define VSYNC_VS_ADDR 0x14db +#define VSYNC_VE_ADDR 0x14dc +#define LCD_MCU_CTL 0x14dd +#define LCD_MCU_DATA_0 0x14de +#define LCD_MCU_DATA_1 0x14df +#define LVDS_GEN_CNTL 0x14e0 +#define LVDS_PHY_CNTL0 0x14e1 +#define LVDS_PHY_CNTL1 0x14e2 +#define LVDS_PHY_CNTL2 0x14e3 +#define LVDS_PHY_CNTL3 0x14e4 +#define LVDS_PHY_CNTL4 0x14e5 +#define LVDS_PHY_CNTL5 0x14e6 +#define LVDS_SRG_TEST 0x14e8 +#define LVDS_BIST_MUX0 0x14e9 +#define LVDS_BIST_MUX1 0x14ea +#define LVDS_BIST_FIXED0 0x14eb +#define LVDS_BIST_FIXED1 0x14ec +#define LVDS_BIST_CNTL0 0x14ed +#define LVDS_CLKB_CLKA 0x14ee +#define LVDS_PHY_CLK_CNTL 0x14ef +#define LVDS_SER_EN 0x14f0 +#define LVDS_PHY_CNTL6 0x14f1 +#define LVDS_PHY_CNTL7 0x14f2 +#define LVDS_PHY_CNTL8 0x14f3 +#define MLVDS_CLK_CTL0_HI 0x14f4 +#define MLVDS_CLK_CTL0_LO 0x14f5 +#define MLVDS_DUAL_GATE_WR_START 0x14f6 +#define MLVDS_DUAL_GATE_WR_END 0x14f7 +#define MLVDS_DUAL_GATE_RD_START 0x14f8 +#define MLVDS_DUAL_GATE_RD_END 0x14f9 +#define MLVDS_SECOND_RESET_CTL 0x14fa +#define MLVDS_DUAL_GATE_CTL_HI 0x14fb +#define MLVDS_DUAL_GATE_CTL_LO 0x14fc +#define MLVDS_RESET_CONFIG_HI 0x14fd +#define MLVDS_RESET_CONFIG_LO 0x14fe +#define VPU_OSD1_MMC_CTRL 0x2701 +#define VPU_OSD2_MMC_CTRL 0x2702 +#define VPU_VD1_MMC_CTRL 0x2703 +#define VPU_VD2_MMC_CTRL 0x2704 +#define VPU_DI_IF1_MMC_CTRL 0x2705 +#define VPU_DI_MEM_MMC_CTRL 0x2706 +#define VPU_DI_INP_MMC_CTRL 0x2707 +#define VPU_DI_MTNRD_MMC_CTRL 0x2708 +#define VPU_DI_CHAN2_MMC_CTRL 0x2709 +#define VPU_DI_MTNWR_MMC_CTRL 0x270a +#define VPU_DI_NRWR_MMC_CTRL 0x270b +#define VPU_DI_DIWR_MMC_CTRL 0x270c +#define VPU_VDIN0_MMC_CTRL 0x270d +#define VPU_VDIN1_MMC_CTRL 0x270e +#define VPU_BT656_MMC_CTRL 0x270f +#define VPU_TVD3D_MMC_CTRL 0x2710 +#define VPU_TVDVBI_MMC_CTRL 0x2711 +#define VPU_TVDVBI_VSLATCH_ADDR 0x2712 +#define VPU_TVDVBI_WRRSP_ADDR 0x2713 +#define VPU_VDIN_PRE_ARB_CTRL 0x2714 +#define VPU_VDISP_PRE_ARB_CTRL 0x2715 +#define VPU_VPUARB2_PRE_ARB_CTRL 0x2716 +#define VPU_OSD3_MMC_CTRL 0x2717 +#define VPU_OSD4_MMC_CTRL 0x2718 +#define VPU_VD3_MMC_CTRL 0x2719 +#define VPU_VIU_VENC_MUX_CTRL 0x271a +#define VPU_HDMI_SETTING 0x271b +#define ENCI_INFO_READ 0x271c +#define ENCP_INFO_READ 0x271d +#define ENCT_INFO_READ 0x271e +#define ENCL_INFO_READ 0x271f +#define VPU_SW_RESET 0x2720 +#define VPU_D2D3_MMC_CTRL 0x2721 +#define VPU_CONT_MMC_CTRL 0x2722 +#define VPU_CLK_GATE 0x2723 +#define VPU_RDMA_MMC_CTRL 0x2724 +#define VPU_MEM_PD_REG0 0x2725 +#define VPU_MEM_PD_REG1 0x2726 +#define VPU_HDMI_DATA_OVR 0x2727 +#define VPU_PROT1_MMC_CTRL 0x2728 +#define VPU_PROT2_MMC_CTRL 0x2729 +#define VPU_PROT3_MMC_CTRL 0x272a +#define VPU_ARB4_V1_MMC_CTRL 0x272b +#define VPU_ARB4_V2_MMC_CTRL 0x272c +#define VPU_VPU_PWM_V0 0x2730 +#define VPU_VPU_PWM_V1 0x2731 +#define VPU_VPU_PWM_V2 0x2732 +#define VPU_VPU_PWM_V3 0x2733 +#define VPU_VPU_PWM_H0 0x2734 +#define VPU_VPU_PWM_H1 0x2735 +#define VPU_VPU_PWM_H2 0x2736 +#define VPU_VPU_PWM_H3 0x2737 +#define VPU_MISC_CTRL 0x2740 +#define VPU_ISP_GCLK_CTRL0 0x2741 +#define VPU_ISP_GCLK_CTRL1 0x2742 +#define VPU_VDIN_ASYNC_HOLD_CTRL 0x2743 +#define VPU_VDISP_ASYNC_HOLD_CTRL 0x2744 +#define VPU_VPUARB2_ASYNC_HOLD_CTRL 0x2745 + +#define VPU_PROT1_CLK_GATE 0x2750 +#define VPU_PROT1_GEN_CNTL 0x2751 +#define VPU_PROT1_X_START_END 0x2752 +#define VPU_PROT1_Y_START_END 0x2753 +#define VPU_PROT1_Y_LEN_STEP 0x2754 +#define VPU_PROT1_RPT_LOOP 0x2755 +#define VPU_PROT1_RPT_PAT 0x2756 +#define VPU_PROT1_DDR 0x2757 +#define VPU_PROT1_RBUF_ROOM 0x2758 +#define VPU_PROT1_STAT_0 0x2759 +#define VPU_PROT1_STAT_1 0x275a +#define VPU_PROT1_STAT_2 0x275b +#define VPU_PROT1_REQ_ONOFF 0x275c +#define VPU_PROT2_CLK_GATE 0x2760 +#define VPU_PROT2_GEN_CNTL 0x2761 +#define VPU_PROT2_X_START_END 0x2762 +#define VPU_PROT2_Y_START_END 0x2763 +#define VPU_PROT2_Y_LEN_STEP 0x2764 +#define VPU_PROT2_RPT_LOOP 0x2765 +#define VPU_PROT2_RPT_PAT 0x2766 +#define VPU_PROT2_DDR 0x2767 +#define VPU_PROT2_RBUF_ROOM 0x2768 +#define VPU_PROT2_STAT_0 0x2769 +#define VPU_PROT2_STAT_1 0x276a +#define VPU_PROT2_STAT_2 0x276b +#define VPU_PROT2_REQ_ONOFF 0x276c +#define VPU_PROT3_CLK_GATE 0x2770 +#define VPU_PROT3_GEN_CNTL 0x2771 +#define VPU_PROT3_X_START_END 0x2772 +#define VPU_PROT3_Y_START_END 0x2773 +#define VPU_PROT3_Y_LEN_STEP 0x2774 +#define VPU_PROT3_RPT_LOOP 0x2775 +#define VPU_PROT3_RPT_PAT 0x2776 +#define VPU_PROT3_DDR 0x2777 +#define VPU_PROT3_RBUF_ROOM 0x2778 +#define VPU_PROT3_STAT_0 0x2779 +#define VPU_PROT3_STAT_1 0x277a +#define VPU_PROT3_STAT_2 0x277b +#define VPU_PROT3_REQ_ONOFF 0x277c +#define VPU_RDARB_MODE_L1C2 0x2799 +/* osd super scale */ +#define OSDSR_HV_SIZEIN 0x3130 +#define OSDSR_CTRL_MODE 0x3131 +#define OSDSR_ABIC_HCOEF 0x3132 +#define OSDSR_YBIC_HCOEF 0x3133 +#define OSDSR_CBIC_HCOEF 0x3134 +#define OSDSR_ABIC_VCOEF 0x3135 +#define OSDSR_YBIC_VCOEF 0x3136 +#define OSDSR_CBIC_VCOEF 0x3137 +#define OSDSR_VAR_PARA 0x3138 +#define OSDSR_CONST_PARA 0x3139 +#define OSDSR_RKE_EXTWIN 0x313a +#define OSDSR_UK_GRAD2DDIAG_TH_RATE 0x313b +#define OSDSR_UK_GRAD2DDIAG_LIMIT 0x313c +#define OSDSR_UK_GRAD2DADJA_TH_RATE 0x313d +#define OSDSR_UK_GRAD2DADJA_LIMIT 0x313e +#define OSDSR_UK_BST_GAIN 0x313f +#define OSDSR_HVBLEND_TH 0x3140 +#define OSDSR_DEMO_WIND_TB 0x3141 +#define OSDSR_DEMO_WIND_LR 0x3142 +#define OSDSR_INT_BLANK_NUM 0x3143 +#define OSDSR_FRM_END_STAT 0x3144 +#define OSDSR_ABIC_HCOEF0 0x3145 +#define OSDSR_YBIC_HCOEF0 0x3146 +#define OSDSR_CBIC_HCOEF0 0x3147 +#define OSDSR_ABIC_VCOEF0 0x3148 +#define OSDSR_YBIC_VCOEF0 0x3149 +#define OSDSR_CBIC_VCOEF0 0x314a + +/* osd afbcd on gxtvbb */ +#define OSD1_AFBCD_ENABLE 0x31a0 +#define OSD1_AFBCD_MODE 0x31a1 +#define OSD1_AFBCD_SIZE_IN 0x31a2 +#define OSD1_AFBCD_HDR_PTR 0x31a3 +#define OSD1_AFBCD_FRAME_PTR 0x31a4 +#define OSD1_AFBCD_CHROMA_PTR 0x31a5 +#define OSD1_AFBCD_CONV_CTRL 0x31a6 +#define OSD1_AFBCD_STATUS 0x31a8 +#define OSD1_AFBCD_PIXEL_HSCOPE 0x31a9 +#define OSD1_AFBCD_PIXEL_VSCOPE 0x31aa +#define VIU_MISC_CTRL1 0x1a07 + +#endif diff --git a/drivers/amlogic/media/osd/osd_sync.h b/drivers/amlogic/media/osd/osd_sync.h new file mode 100644 index 000000000000..4855f38c4265 --- /dev/null +++ b/drivers/amlogic/media/osd/osd_sync.h @@ -0,0 +1,30 @@ +/* + * drivers/amlogic/media/osd/osd_sync.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 _OSD_SYNC_H_ +#define _OSD_SYNC_H_ + + + +struct fb_sync_request_s { + unsigned int xoffset; + unsigned int yoffset; + int in_fen_fd; + int out_fen_fd; +}; + +#endif diff --git a/drivers/amlogic/media/osd_ext/Kconfig b/drivers/amlogic/media/osd_ext/Kconfig new file mode 100644 index 000000000000..dcde7b0672fe --- /dev/null +++ b/drivers/amlogic/media/osd_ext/Kconfig @@ -0,0 +1,17 @@ +# +# Frame buffer configuration +# +menu "Amlogic OSD_EXT Module" + +config AMLOGIC_MEDIA_FB_EXT + bool "Amlogic OSD_EXT Support" + default n + depends on AMLOGIC_MEDIA_FB + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + depends on AMLOGIC_MEDIA_CANVAS + depends on AMLOGIC_VOUT2 + help + This is the frame buffer device driver. +endmenu diff --git a/drivers/amlogic/media/osd_ext/Makefile b/drivers/amlogic/media/osd_ext/Makefile new file mode 100644 index 000000000000..455b316238cd --- /dev/null +++ b/drivers/amlogic/media/osd_ext/Makefile @@ -0,0 +1,5 @@ +obj-$(CONFIG_AMLOGIC_MEDIA_FB_EXT) += fb_ext.o +fb_ext-objs = osd_hw.o osd_fb.o osd_clone.o + +ccflags-y += -Idrivers/staging/android/ +ccflags-y += -Idrivers/amlogic/media/ \ No newline at end of file diff --git a/drivers/amlogic/media/osd_ext/osd_clone.c b/drivers/amlogic/media/osd_ext/osd_clone.c new file mode 100644 index 000000000000..9982875e7208 --- /dev/null +++ b/drivers/amlogic/media/osd_ext/osd_clone.c @@ -0,0 +1,193 @@ +/* + * drivers/amlogic/media/osd_ext/osd_clone.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. + * + */ + +/* Linux Headers */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Amlogic Headers */ +#include +#ifdef CONFIG_AMLOGIC_MEDIA_CANVAS +#include +#endif +#ifdef CONFIG_AMLOGIC_MEDIA_GE2D +#include +#endif + + +/* Local Headers */ +#include +#include +#include +#include "osd_clone.h" + + +#ifdef OSD_EXT_GE2D_CLONE_SUPPORT +struct osd_ext_clone_s { + bool inited; + int angle; + int pan; + struct config_para_ex_s ge2d_config; + struct ge2d_context_s *ge2d_context; +}; + +static DEFINE_MUTEX(osd_ext_clone_mutex); +static struct osd_ext_clone_s s_osd_ext_clone; + +static void osd_clone_process(void) +{ + struct canvas_s cs, cd; + u32 x0 = 0; + u32 y0 = 0; + u32 y1 = 0; + unsigned char x_rev = 0; + unsigned char y_rev = 0; + unsigned char xy_swap = 0; + struct config_para_ex_s *ge2d_config = &s_osd_ext_clone.ge2d_config; + struct ge2d_context_s *context = s_osd_ext_clone.ge2d_context; + + canvas_read(OSD1_CANVAS_INDEX, &cs); + canvas_read(OSD3_CANVAS_INDEX, &cd); + + if (s_osd_ext_clone.pan == 1) { + y0 = cs.height / 2; + y1 = cd.height / 2; + } + + if (s_osd_ext_clone.angle == 1) { + xy_swap = 1; + x_rev = 1; + } else if (s_osd_ext_clone.angle == 2) { + x_rev = 1; + y_rev = 1; + } else if (s_osd_ext_clone.angle == 3) { + xy_swap = 1; + y_rev = 1; + } + + memset(ge2d_config, 0, sizeof(struct config_para_ex_s)); + ge2d_config->alu_const_color = 0; + ge2d_config->bitmask_en = 0; + ge2d_config->src1_gb_alpha = 0; + ge2d_config->dst_xy_swap = 0; + + ge2d_config->src_planes[0].addr = cs.addr; + ge2d_config->src_planes[0].w = cs.width / 4; + ge2d_config->src_planes[0].h = cs.height; + + ge2d_config->dst_planes[0].addr = cd.addr; + ge2d_config->dst_planes[0].w = cd.width / 4; + ge2d_config->dst_planes[0].h = cd.height; + + ge2d_config->src_para.canvas_index = OSD1_CANVAS_INDEX; + ge2d_config->src_para.mem_type = CANVAS_OSD0; + ge2d_config->dst_para.mem_type = CANVAS_TYPE_INVALID; + ge2d_config->dst_para.format = GE2D_FORMAT_S32_ARGB; + ge2d_config->src_para.fill_color_en = 0; + ge2d_config->src_para.fill_mode = 0; + ge2d_config->src_para.x_rev = 0; + ge2d_config->src_para.y_rev = 0; + ge2d_config->src_para.color = 0xffffffff; + ge2d_config->src_para.top = 0; + ge2d_config->src_para.left = 0; + ge2d_config->src_para.width = cs.width / 4; + ge2d_config->src_para.height = cs.height; + + ge2d_config->dst_para.canvas_index = OSD3_CANVAS_INDEX; + ge2d_config->dst_para.mem_type = CANVAS_TYPE_INVALID; + ge2d_config->dst_para.format = GE2D_FORMAT_S32_ARGB; + ge2d_config->dst_para.top = 0; + ge2d_config->dst_para.left = 0; + ge2d_config->dst_para.width = cd.width / 4; + ge2d_config->dst_para.height = cd.height; + ge2d_config->dst_para.fill_color_en = 0; + ge2d_config->dst_para.fill_mode = 0; + ge2d_config->dst_para.color = 0; + ge2d_config->dst_para.x_rev = x_rev; + ge2d_config->dst_para.y_rev = y_rev; + ge2d_config->dst_xy_swap = xy_swap; + + if (ge2d_context_config_ex(context, ge2d_config) < 0) { + osd_log_err("++ osd clone ge2d config error.\n"); + return; + } + + stretchblt(context, x0, y0, cs.width / 4, cs.height / 2, + x0, y1, cd.width / 4, cd.height / 2); +} + +void osd_ext_clone_update_pan(int pan) +{ + if (!s_osd_ext_clone.inited) + return; + + mutex_lock(&osd_ext_clone_mutex); + s_osd_ext_clone.pan = pan; + mutex_unlock(&osd_ext_clone_mutex); + osd_clone_process(); +} + +void osd_ext_clone_set_angle(int angle) +{ + mutex_lock(&osd_ext_clone_mutex); + s_osd_ext_clone.angle = angle; + mutex_unlock(&osd_ext_clone_mutex); +} + +int osd_ext_clone_task_start(void) +{ + if (s_osd_ext_clone.inited) { + osd_log_info("osd_ext_clone_task already started.\n"); + return 0; + } + + osd_log_info("osd_ext_clone_task start.\n"); + + if (s_osd_ext_clone.ge2d_context == NULL) + s_osd_ext_clone.ge2d_context = create_ge2d_work_queue(); + + memset(&s_osd_ext_clone.ge2d_config, + 0, sizeof(struct config_para_ex_s)); + s_osd_ext_clone.inited = true; + + return 0; +} + +void osd_ext_clone_task_stop(void) +{ + if (!s_osd_ext_clone.inited) { + osd_log_info("osd_ext_clone_task already stopped.\n"); + return; + } + + osd_log_info("osd_ext_clone_task stop.\n"); + + if (s_osd_ext_clone.ge2d_context) { + destroy_ge2d_work_queue(s_osd_ext_clone.ge2d_context); + s_osd_ext_clone.ge2d_context = NULL; + } + + s_osd_ext_clone.inited = false; +} +#endif diff --git a/drivers/amlogic/media/osd_ext/osd_clone.h b/drivers/amlogic/media/osd_ext/osd_clone.h new file mode 100644 index 000000000000..540ba41308b6 --- /dev/null +++ b/drivers/amlogic/media/osd_ext/osd_clone.h @@ -0,0 +1,46 @@ +/* + * drivers/amlogic/media/osd_ext/osd_clone.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 _OSD_CLONE_H_ +#define _OSD_CLONE_H_ + +#include + +#ifdef CONFIG_AMLOGIC_MEDIA_GE2D +#define OSD_EXT_GE2D_CLONE_SUPPORT 1 +#endif + +#ifdef OSD_EXT_GE2D_CLONE_SUPPORT +extern void osd_ext_clone_set_angle(int angle); +extern void osd_ext_clone_update_pan(int pan); +extern int osd_ext_clone_task_start(void); +extern void osd_ext_clone_task_stop(void); +#else +static inline void osd_ext_clone_set_angle(int angle) {} +static inline void osd_ext_clone_update_pan(int pan) {} +static inline int osd_ext_clone_task_start(void) +{ + osd_log_info("++ osd_ext_clone depends on GE2D module!\n"); + return 0; +} +static inline void osd_ext_clone_task_stop(void) +{ + osd_log_info("-- osd_ext_clone depends on GE2D module!\n"); +} +#endif + +#endif diff --git a/drivers/amlogic/media/osd_ext/osd_fb.c b/drivers/amlogic/media/osd_ext/osd_fb.c new file mode 100644 index 000000000000..dae6e4558528 --- /dev/null +++ b/drivers/amlogic/media/osd_ext/osd_fb.c @@ -0,0 +1,1703 @@ +/* + * drivers/amlogic/media/osd_ext/osd_fb.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. + * + */ + +/* Linux Headers */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Amlogic Headers */ +#include + +/* Local Headers */ +#include +#include +#include +#include "osd_hw.h" +#include "osd_fb.h" + + +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +static struct early_suspend early_suspend; +static int early_suspend_flag; +#endif +#ifdef CONFIG_SCREEN_ON_EARLY +static int early_resume_flag; +#endif + +int int_viu2_vsync = -ENXIO; +static struct osd_fb_dev_s *gp_fbdev_list[OSD_COUNT] = {}; +static struct reserved_mem fb_rmem; +static phys_addr_t fb_rmem_paddr[2]; +static void __iomem *fb_rmem_vaddr[2]; +static u32 fb_rmem_size[2]; + +static DEFINE_MUTEX(dbg_mutex); + +static void osddev_ext_setup(struct osd_fb_dev_s *fbdev) +{ + mutex_lock(&fbdev->lock); + osd_ext_setup(&fbdev->osd_ctl, + fbdev->fb_info->var.xoffset, + fbdev->fb_info->var.yoffset, + fbdev->fb_info->var.xres, + fbdev->fb_info->var.yres, + fbdev->fb_info->var.xres_virtual, + fbdev->fb_info->var.yres_virtual, + fbdev->osd_ctl.disp_start_x, + fbdev->osd_ctl.disp_start_y, + fbdev->osd_ctl.disp_end_x, + fbdev->osd_ctl.disp_end_y, + fbdev->fb_mem_paddr, + fbdev->color, + fbdev->fb_info->node - 2); + mutex_unlock(&fbdev->lock); +} + +static void osddev_ext_update_disp_axis(struct osd_fb_dev_s *fbdev, + int mode_change) +{ + osd_ext_update_disp_axis_hw(fbdev->fb_info->node - 2, + fbdev->osd_ctl.disp_start_x, + fbdev->osd_ctl.disp_end_x, + fbdev->osd_ctl.disp_start_y, + fbdev->osd_ctl.disp_end_y, + fbdev->fb_info->var.xoffset, + fbdev->fb_info->var.yoffset, + mode_change); +} + +static int osddev_ext_setcolreg(unsigned int regno, u16 red, + u16 green, u16 blue, + u16 transp, struct osd_fb_dev_s *fbdev) +{ + struct fb_info *info = fbdev->fb_info; + + if ((fbdev->color->color_index == COLOR_INDEX_02_PAL4) || + (fbdev->color->color_index == COLOR_INDEX_04_PAL16) || + (fbdev->color->color_index == COLOR_INDEX_08_PAL256)) { + mutex_lock(&fbdev->lock); + osd_ext_setpal_hw(fbdev->fb_info->node - 2, + regno, red, green, blue, transp); + mutex_lock(&fbdev->lock); + } + if (info->fix.visual == FB_VISUAL_TRUECOLOR) { + u32 v, r, g, b, a; + + if (regno >= 16) + return 1; + r = red >> (16 - info->var.red.length); + g = green >> (16 - info->var.green.length); + b = blue >> (16 - info->var.blue.length); + a = transp >> (16 - info->var.transp.length); + v = (r << info->var.red.offset) | + (g << info->var.green.offset) | + (b << info->var.blue.offset) | + (a << info->var.transp.offset); + ((u32 *)(info->pseudo_palette))[regno] = v; + } + return 0; +} + +static const struct color_bit_define_s * +_find_color_format(struct fb_var_screeninfo *var) +{ + u32 upper_margin, lower_margin, i, level; + const struct color_bit_define_s *found = NULL; + const struct color_bit_define_s *color = NULL; + + level = (var->bits_per_pixel - 1) / 8; + switch (level) { + case 0: + upper_margin = COLOR_INDEX_08_PAL256; + lower_margin = COLOR_INDEX_02_PAL4; + break; + case 1: + upper_margin = COLOR_INDEX_16_565; + lower_margin = COLOR_INDEX_16_655; + break; + case 2: + upper_margin = COLOR_INDEX_24_RGB; + lower_margin = COLOR_INDEX_24_6666_A; + break; + case 3: + upper_margin = COLOR_INDEX_32_ARGB; + lower_margin = COLOR_INDEX_32_BGRA; + break; + case 4: + upper_margin = COLOR_INDEX_YUV_422; + lower_margin = COLOR_INDEX_YUV_422; + break; + default: + return NULL; + } + /* + * if not provide color component length + * then we find the first depth match. + */ + if ((var->red.length == 0) || (var->green.length == 0) + || (var->blue.length == 0) || + var->bits_per_pixel != (var->red.length + var->green.length + + var->blue.length + var->transp.length)) { + osd_log_dbg("not provide color length, use default color\n"); + found = &default_color_format_array[upper_margin]; + } else { + for (i = upper_margin; i >= lower_margin; i--) { + color = &default_color_format_array[i]; + if ((color->red_length == var->red.length) && + (color->green_length == var->green.length) && + (color->blue_length == var->blue.length) && + (color->transp_length == var->transp.length) && + (color->transp_offset == var->transp.offset) && + (color->green_offset == var->green.offset) && + (color->blue_offset == var->blue.offset) && + (color->red_offset == var->red.offset)) { + found = color; + break; + } + color--; + } + } + return found; +} + +static void __init _fbdev_set_default(struct osd_fb_dev_s *fbdev, int index) +{ + /* setup default value */ + fbdev->fb_info->var = fb_def_var[index]; + fbdev->fb_info->fix = fb_def_fix; + fbdev->color = _find_color_format(&fbdev->fb_info->var); +} + +static int osd_ext_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct fb_fix_screeninfo *fix; + struct osd_fb_dev_s *fbdev = (struct osd_fb_dev_s *)info->par; + const struct color_bit_define_s *color_format_pt; + + fix = &info->fix; + color_format_pt = _find_color_format(var); + if (color_format_pt == NULL || color_format_pt->color_index == 0) + return -EFAULT; + osd_log_dbg("select color format :index %d, bpp %d\n", + color_format_pt->color_index, + color_format_pt->bpp); + fbdev->color = color_format_pt; + var->red.offset = color_format_pt->red_offset; + var->red.length = color_format_pt->red_length; + var->red.msb_right = color_format_pt->red_msb_right; + var->green.offset = color_format_pt->green_offset; + var->green.length = color_format_pt->green_length; + var->green.msb_right = color_format_pt->green_msb_right; + var->blue.offset = color_format_pt->blue_offset; + var->blue.length = color_format_pt->blue_length; + var->blue.msb_right = color_format_pt->blue_msb_right; + var->transp.offset = color_format_pt->transp_offset; + var->transp.length = color_format_pt->transp_length; + var->transp.msb_right = color_format_pt->transp_msb_right; + var->bits_per_pixel = color_format_pt->bpp; + osd_log_dbg("rgba(L/O):%d/%d-%d/%d-%d/%d-%d/%d\n", + var->red.length, var->red.offset, + var->green.length, var->green.offset, + var->blue.length, var->blue.offset, + var->transp.length, var->transp.offset); + fix->visual = color_format_pt->color_type; + /* adjust memory length. */ + fix->line_length = var->xres_virtual * var->bits_per_pixel / 8; + if (var->xres_virtual * var->yres_virtual * var->bits_per_pixel / 8 > + fbdev->fb_len) { + osd_log_err("no enough memory for %d*%d*%d\n", var->xres, + var->yres, var->bits_per_pixel); + return -ENOMEM; + } + if (var->xres_virtual < var->xres) + var->xres_virtual = var->xres; + if (var->yres_virtual < var->yres) + var->yres_virtual = var->yres; + var->left_margin = var->right_margin = 0; + var->upper_margin = var->lower_margin = 0; + if (var->xres + var->xoffset > var->xres_virtual) + var->xoffset = var->xres_virtual - var->xres; + if (var->yres + var->yoffset > var->yres_virtual) + var->yoffset = var->yres_virtual - var->yres; + return 0; +} + +static int osd_ext_set_par(struct fb_info *info) +{ + const struct vinfo_s *vinfo = NULL; + struct osd_fb_dev_s *fbdev = (struct osd_fb_dev_s *)info->par; + struct osd_ctl_s *osd_ext_ctrl = &fbdev->osd_ctl; + u32 virt_end_x, virt_end_y; + +#ifdef CONFIG_AMLOGIC_VOUT2 + vinfo = get_current_vinfo2(); + if (!vinfo) { + osd_log_err("current vinfo NULL\n"); + return -1; + } +#endif + + if (vinfo == NULL) + return -1; + + virt_end_x = osd_ext_ctrl->disp_start_x + info->var.xres; + virt_end_y = osd_ext_ctrl->disp_start_y + info->var.yres; + + if (virt_end_x > vinfo->width) + osd_ext_ctrl->disp_end_x = vinfo->width - 1; + else + osd_ext_ctrl->disp_end_x = virt_end_x - 1; + if (virt_end_y > vinfo->height) + osd_ext_ctrl->disp_end_y = vinfo->height - 1; + else + osd_ext_ctrl->disp_end_y = virt_end_y - 1; + osddev_ext_setup((struct osd_fb_dev_s *)info->par); + return 0; +} + +static int osd_ext_setcolreg(unsigned int regno, unsigned int red, + unsigned int green, unsigned int blue, + unsigned int transp, struct fb_info *info) +{ + return osddev_ext_setcolreg(regno, red, green, blue, + transp, (struct osd_fb_dev_s *)info->par); +} + +static int osd_ext_setcmap(struct fb_cmap *cmap, struct fb_info *info) +{ + int count, index, r; + u16 *red, *green, *blue, *transp; + u16 trans = 0xffff; + + red = cmap->red; + green = cmap->green; + blue = cmap->blue; + transp = cmap->transp; + index = cmap->start; + + for (count = 0; count < cmap->len; count++) { + if (transp) + trans = *transp++; + r = osddev_ext_setcolreg(index++, *red++, *green++, *blue++, + trans, (struct osd_fb_dev_s *)info->par); + if (r != 0) + return r; + } + + return 0; +} + +static int osd_ext_ioctl(struct fb_info *info, unsigned int cmd, + unsigned long arg) +{ + struct osd_fb_dev_s *fbdev = (struct osd_fb_dev_s *)info->par; + void __user *argp = (void __user *)arg; + u32 src_colorkey;/* 16 bit or 24 bit */ + u32 srckey_enable; + u32 gbl_alpha; + u32 osd_ext_order; + s32 osd_ext_axis[4] = {0}; + s32 osd_ext_dst_axis[4] = {0}; + u32 block_windows[8] = {0}; + u32 block_mode; + unsigned long ret; + struct fb_sync_request_s sync_request; + + switch (cmd) { + case FBIOPUT_OSD_SRCKEY_ENABLE: + ret = copy_from_user(&srckey_enable, argp, sizeof(u32)); + break; + case FBIOPUT_OSD_SRCCOLORKEY: + ret = copy_from_user(&src_colorkey, argp, sizeof(u32)); + break; + case FBIOPUT_OSD_SET_GBL_ALPHA: + ret = copy_from_user(&gbl_alpha, argp, sizeof(u32)); + break; + case FBIOPUT_OSD_SCALE_AXIS: + ret = copy_from_user(&osd_ext_axis, argp, 4 * sizeof(s32)); + break; + case FBIOPUT_OSD_SYNC_ADD: + ret = copy_from_user(&sync_request, argp, + sizeof(struct fb_sync_request_s)); + break; + case FBIO_WAITFORVSYNC: + case FBIOGET_OSD_SCALE_AXIS: + case FBIOPUT_OSD_ORDER: + case FBIOGET_OSD_ORDER: + case FBIOGET_OSD_GET_GBL_ALPHA: + case FBIOPUT_OSD_2X_SCALE: + case FBIOPUT_OSD_ENABLE_3D_MODE: + case FBIOPUT_OSD_FREE_SCALE_ENABLE: + case FBIOPUT_OSD_FREE_SCALE_MODE: + case FBIOPUT_OSD_FREE_SCALE_WIDTH: + case FBIOPUT_OSD_FREE_SCALE_HEIGHT: + case FBIOGET_OSD_BLOCK_WINDOWS: + case FBIOGET_OSD_BLOCK_MODE: + case FBIOGET_OSD_FREE_SCALE_AXIS: + case FBIOGET_OSD_WINDOW_AXIS: + case FBIOPUT_OSD_ROTATE_ON: + case FBIOPUT_OSD_ROTATE_ANGLE: + break; + case FBIOPUT_OSD_BLOCK_MODE: + ret = copy_from_user(&block_mode, argp, sizeof(u32)); + break; + case FBIOPUT_OSD_BLOCK_WINDOWS: + ret = copy_from_user(&block_windows, argp, 8 * sizeof(u32)); + break; + case FBIOPUT_OSD_FREE_SCALE_AXIS: + ret = copy_from_user(&osd_ext_axis, argp, 4 * sizeof(s32)); + break; + case FBIOPUT_OSD_WINDOW_AXIS: + ret = copy_from_user(&osd_ext_dst_axis, argp, 4 * sizeof(s32)); + break; + default: + osd_log_err("command not supported\n "); + return -1; + } + mutex_lock(&fbdev->lock); + + switch (cmd) { + case FBIOPUT_OSD_ORDER: + osd_ext_set_order_hw(info->node - 2, arg); + break; + case FBIOGET_OSD_ORDER: + osd_ext_order = osd_ext_get_order_hw(info->node - 2); + ret = copy_to_user(argp, &osd_ext_order, sizeof(u32)); + break; + case FBIOPUT_OSD_FREE_SCALE_ENABLE: + osd_ext_set_free_scale_enable_hw(info->node - 2, arg); + break; + case FBIOPUT_OSD_FREE_SCALE_MODE: + osd_ext_set_free_scale_mode_hw(info->node - 2, arg); + break; + case FBIOPUT_OSD_ENABLE_3D_MODE: + osd_ext_enable_3d_mode_hw(info->node - 2, arg); + break; + case FBIOPUT_OSD_2X_SCALE: + /* + * higher 16 bit h_scale_enable, + * lower 16 bit v_scale_enable + */ + osd_ext_set_2x_scale_hw(info->node - 2, arg & 0xffff0000 ? + 1 : 0, arg & 0xffff ? 1 : 0); + break; + case FBIOPUT_OSD_ROTATE_ON: + break; + case FBIOPUT_OSD_ROTATE_ANGLE: + break; + case FBIOPUT_OSD_SRCCOLORKEY: + switch (fbdev->color->color_index) { + case COLOR_INDEX_16_655: + case COLOR_INDEX_16_844: + case COLOR_INDEX_16_565: + case COLOR_INDEX_24_888_B: + case COLOR_INDEX_24_RGB: + case COLOR_INDEX_YUV_422: + osd_log_dbg("set osd color key 0x%x\n", src_colorkey); + fbdev->color_key = src_colorkey; + osd_ext_set_color_key_hw(info->node - 2, + fbdev->color->color_index, src_colorkey); + break; + default: + break; + } + break; + case FBIOPUT_OSD_SRCKEY_ENABLE: + switch (fbdev->color->color_index) { + case COLOR_INDEX_16_655: + case COLOR_INDEX_16_844: + case COLOR_INDEX_16_565: + case COLOR_INDEX_24_888_B: + case COLOR_INDEX_24_RGB: + case COLOR_INDEX_YUV_422: + osd_log_dbg("set osd color key %s\n", + srckey_enable ? "enable" : "disable"); + if (srckey_enable != 0) { + fbdev->enable_key_flag |= KEYCOLOR_FLAG_TARGET; + if (!(fbdev->enable_key_flag & + KEYCOLOR_FLAG_ONHOLD)) { + fbdev->enable_key_flag |= + KEYCOLOR_FLAG_CURRENT; + osd_ext_srckey_enable_hw(info->node - 2, 1); + } + } else { + osd_ext_srckey_enable_hw(info->node - 2, 0); + fbdev->enable_key_flag &= + ~(KEYCOLOR_FLAG_TARGET | + KEYCOLOR_FLAG_CURRENT); + } + break; + default: + break; + } + break; + case FBIOPUT_OSD_SET_GBL_ALPHA: + osd_ext_set_gbl_alpha_hw(info->node - 2, gbl_alpha); + break; + case FBIOGET_OSD_GET_GBL_ALPHA: + gbl_alpha = osd_ext_get_gbl_alpha_hw(info->node - 2); + ret = copy_to_user(argp, &gbl_alpha, sizeof(u32)); + break; + + case FBIOGET_OSD_SCALE_AXIS: + osd_ext_get_scale_axis_hw(info->node - 2, + &osd_ext_axis[0], &osd_ext_axis[1], + &osd_ext_axis[2], &osd_ext_axis[3]); + ret = copy_to_user(argp, &osd_ext_axis, 4 * sizeof(s32)); + break; + case FBIOPUT_OSD_SCALE_AXIS: + osd_ext_set_scale_axis_hw(info->node - 2, + osd_ext_axis[0], osd_ext_axis[1], + osd_ext_axis[2], osd_ext_axis[3]); + break; + case FBIOGET_OSD_BLOCK_WINDOWS: + osd_ext_get_block_windows_hw(info->node - 2, block_windows); + ret = copy_to_user(argp, &block_windows, 8 * sizeof(u32)); + break; + case FBIOPUT_OSD_BLOCK_WINDOWS: + osd_ext_set_block_windows_hw(info->node - 2, block_windows); + break; + case FBIOPUT_OSD_BLOCK_MODE: + osd_ext_set_block_mode_hw(info->node - 2, block_mode); + break; + case FBIOGET_OSD_BLOCK_MODE: + osd_ext_get_block_mode_hw(info->node - 2, &block_mode); + ret = copy_to_user(argp, &block_mode, sizeof(u32)); + break; + case FBIOGET_OSD_FREE_SCALE_AXIS: + osd_ext_get_free_scale_axis_hw(info->node - 2, + &osd_ext_axis[0], &osd_ext_axis[1], + &osd_ext_axis[2], &osd_ext_axis[3]); + ret = copy_to_user(argp, &osd_ext_axis, 4 * sizeof(s32)); + break; + case FBIOGET_OSD_WINDOW_AXIS: + osd_ext_get_window_axis_hw(info->node - 2, + &osd_ext_dst_axis[0], &osd_ext_dst_axis[1], + &osd_ext_dst_axis[2], &osd_ext_dst_axis[3]); + ret = copy_to_user(argp, &osd_ext_dst_axis, 4 * sizeof(s32)); + break; + case FBIOPUT_OSD_FREE_SCALE_AXIS: + osd_ext_set_free_scale_axis_hw(info->node - 2, + osd_ext_axis[0], osd_ext_axis[1], + osd_ext_axis[2], osd_ext_axis[3]); + break; + case FBIOPUT_OSD_WINDOW_AXIS: + osd_ext_set_window_axis_hw(info->node - 2, + osd_ext_dst_axis[0], osd_ext_dst_axis[1], + osd_ext_dst_axis[2], osd_ext_dst_axis[3]); + break; + case FBIOPUT_OSD_SYNC_ADD: + sync_request.out_fen_fd = osd_ext_sync_request(info->node - 2, + info->var.yres, + sync_request.xoffset, + sync_request.yoffset, + sync_request.in_fen_fd); + ret = copy_to_user(argp, &sync_request, + sizeof(struct fb_sync_request_s)); + if (sync_request.out_fen_fd < 0) /* fence create fail. */ + ret = -1; + break; + case FBIO_WAITFORVSYNC: + osd_ext_wait_vsync_event(); + ret = copy_to_user(argp, &ret, sizeof(u32)); + break; + default: + break; + } + + mutex_unlock(&fbdev->lock); + + return 0; +} + +#ifdef CONFIG_COMPAT +static int osd_ext_compat_ioctl(struct fb_info *info, + unsigned int cmd, unsigned long arg) +{ + unsigned long ret; + + arg = (unsigned long)compat_ptr(arg); + ret = osd_ext_ioctl(info, cmd, arg); + + return ret; +} +#endif + +static int osd_ext_open(struct fb_info *info, int arg) +{ + return 0; +} + +static int +osd_ext_blank(int blank_mode, struct fb_info *info) +{ + osd_ext_enable_hw(info->node - 2, (blank_mode != 0) ? 0 : 1); + + return 0; +} + +static int osd_ext_pan_display(struct fb_var_screeninfo *var, + struct fb_info *fbi) +{ + + osd_ext_pan_display_hw(fbi->node - 2, var->xoffset, var->yoffset); + osd_log_info("osd_ext_pan_display:=>osd%d\n", fbi->node); + return 0; +} + +static int osd_ext_sync(struct fb_info *info) +{ + return 0; +} + +/* fb_ops structures */ +static struct fb_ops osd_ext_ops = { + .owner = THIS_MODULE, + .fb_check_var = osd_ext_check_var, + .fb_set_par = osd_ext_set_par, + .fb_setcolreg = osd_ext_setcolreg, + .fb_setcmap = osd_ext_setcmap, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, +#ifdef CONFIG_FB_SOFT_CURSOR + .fb_cursor = soft_cursor, +#elif defined(CONFIG_AMLOGIC_MEDIA_FB_OSD2_CURSOR) + .fb_cursor = NULL, +#endif + .fb_ioctl = osd_ext_ioctl, +#ifdef CONFIG_COMPAT + .fb_compat_ioctl = osd_ext_compat_ioctl, +#endif + .fb_open = osd_ext_open, + .fb_blank = osd_ext_blank, + .fb_pan_display = osd_ext_pan_display, + .fb_sync = osd_ext_sync, +}; + +static void set_default_display_axis(struct fb_var_screeninfo *var, + struct osd_ctl_s *osd_ext_ctrl, const struct vinfo_s *vinfo) +{ + u32 virt_end_x = osd_ext_ctrl->disp_start_x + var->xres; + u32 virt_end_y = osd_ext_ctrl->disp_start_y + var->yres; + + if (virt_end_x > vinfo->width) + osd_ext_ctrl->disp_end_x = vinfo->width - 1; /* screen axis */ + else + osd_ext_ctrl->disp_end_x = virt_end_x - 1; /* screen axis */ + if (virt_end_y > vinfo->height) + osd_ext_ctrl->disp_end_y = vinfo->height - 1; + else + osd_ext_ctrl->disp_end_y = virt_end_y - 1; /* screen axis */ +} + +int osd_ext_notify_callback(struct notifier_block *block, unsigned long cmd, + void *para) +{ + const struct vinfo_s *vinfo = NULL; + struct osd_fb_dev_s *fb_dev; + int i, blank; + struct disp_rect_s *disp_rect; + +#ifdef CONFIG_AMLOGIC_VOUT2 + vinfo = get_current_vinfo2(); + osd_log_info("tv_server:vmode=%s\n", vinfo->name); +#endif + if (vinfo == NULL) + return -1; + + if (vinfo->mode == VMODE_INIT_NULL) + return 1; + + switch (cmd) { + case VOUT_EVENT_MODE_CHANGE: + osd_log_info("recevie change mode message\n"); + for (i = 0; i < OSD_COUNT; i++) { + fb_dev = gp_fbdev_list[i]; + if (fb_dev == NULL) + continue; + set_default_display_axis(&fb_dev->fb_info->var, + &fb_dev->osd_ctl, vinfo); + console_lock(); + osddev_ext_update_disp_axis(fb_dev, 1); + console_unlock(); + } + break; + + case VOUT_EVENT_OSD_BLANK: + blank = *(int *)para; + for (i = 0; i < OSD_COUNT; i++) { + fb_dev = gp_fbdev_list[i]; + if (fb_dev == NULL) + continue; + console_lock(); + osd_ext_blank(blank, fb_dev->fb_info); + console_unlock(); + } + break; + case VOUT_EVENT_OSD_DISP_AXIS: + disp_rect = (struct disp_rect_s *)para; + + for (i = 0; i < OSD_COUNT; i++) { + if (!disp_rect) + break; + fb_dev = gp_fbdev_list[i]; + /* + * if (fb_dev->preblend_enable) + * break; + */ + fb_dev->osd_ctl.disp_start_x = disp_rect->x; + fb_dev->osd_ctl.disp_start_y = disp_rect->y; + osd_log_info("set disp axis: x:%d y:%d w:%d h:%d\n", + disp_rect->x, disp_rect->y, + disp_rect->w, disp_rect->h); + if (disp_rect->x + disp_rect->w > vinfo->width) + fb_dev->osd_ctl.disp_end_x = vinfo->width - 1; + else + fb_dev->osd_ctl.disp_end_x = + fb_dev->osd_ctl.disp_start_x + + disp_rect->w - 1; + if (disp_rect->y + disp_rect->h > vinfo->height) + fb_dev->osd_ctl.disp_end_y = vinfo->height - 1; + else + fb_dev->osd_ctl.disp_end_y = + fb_dev->osd_ctl.disp_start_y + + disp_rect->h - 1; + disp_rect++; + osd_log_info("new disp axis: x0:%d y0:%d x1:%d y1:%d\n", + fb_dev->osd_ctl.disp_start_x, + fb_dev->osd_ctl.disp_start_y, + fb_dev->osd_ctl.disp_end_x, + fb_dev->osd_ctl.disp_end_y); + console_lock(); + osddev_ext_update_disp_axis(fb_dev, 0); + console_unlock(); + } + + break; + } + return 0; +} + +static struct notifier_block osd_ext_notifier_nb = { + .notifier_call = osd_ext_notify_callback, +}; + +static ssize_t store_enable_3d(struct device *device, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + struct osd_fb_dev_s *fbdev = (struct osd_fb_dev_s *)fb_info->par; + int res = 0; + int ret = 0; + + ret = kstrtoint(buf, 0, &res); + fbdev->enable_3d = res; + osd_ext_enable_3d_mode_hw(fb_info->node - 2, fbdev->enable_3d); + + return count; +} + +static ssize_t show_enable_3d(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + struct osd_fb_dev_s *fbdev = (struct osd_fb_dev_s *)fb_info->par; + + return snprintf(buf, PAGE_SIZE, "3d_enable:[0x%x]\n", fbdev->enable_3d); +} + +static ssize_t store_color_key(struct device *device, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + struct osd_fb_dev_s *fbdev = (struct osd_fb_dev_s *)fb_info->par; + int res = 0; + int ret = 0; + + ret = kstrtoint(buf, 16, &res); + switch (fbdev->color->color_index) { + case COLOR_INDEX_16_655: + case COLOR_INDEX_16_844: + case COLOR_INDEX_16_565: + case COLOR_INDEX_24_888_B: + case COLOR_INDEX_24_RGB: + case COLOR_INDEX_YUV_422: + fbdev->color_key = res; + osd_ext_set_color_key_hw(fb_info->node - 2, + fbdev->color->color_index, fbdev->color_key); + break; + default: + break; + } + return count; +} + +static ssize_t show_color_key(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + struct osd_fb_dev_s *fbdev = (struct osd_fb_dev_s *)fb_info->par; + + return snprintf(buf, PAGE_SIZE, "0x%x\n", fbdev->color_key); +} + +static ssize_t store_enable_key(struct device *device, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + struct osd_fb_dev_s *fbdev = (struct osd_fb_dev_s *)fb_info->par; + int res = 0; + int ret = 0; + + ret = kstrtoint(buf, 0, &res); + mutex_lock(&fbdev->lock); + if (res != 0) { + fbdev->enable_key_flag |= KEYCOLOR_FLAG_TARGET; + if (!(fbdev->enable_key_flag & KEYCOLOR_FLAG_ONHOLD)) { + osd_ext_srckey_enable_hw(fb_info->node - 2, 1); + fbdev->enable_key_flag |= KEYCOLOR_FLAG_CURRENT; + } + } else { + fbdev->enable_key_flag &= + ~(KEYCOLOR_FLAG_TARGET | KEYCOLOR_FLAG_CURRENT); + osd_ext_srckey_enable_hw(fb_info->node - 2, 0); + } + mutex_unlock(&fbdev->lock); + + return count; +} + +static ssize_t show_enable_key(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + struct osd_fb_dev_s *fbdev = (struct osd_fb_dev_s *)fb_info->par; + + return snprintf(buf, PAGE_SIZE, + (fbdev->enable_key_flag & KEYCOLOR_FLAG_TARGET) ? + "1\n" : "0\n"); +} + +static ssize_t store_enable_key_onhold(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + struct osd_fb_dev_s *fbdev = (struct osd_fb_dev_s *)fb_info->par; + int res = 0; + int ret = 0; + + ret = kstrtoint(buf, 0, &res); + mutex_lock(&fbdev->lock); + if (res != 0) { + /* hold all the calls to enable color key */ + fbdev->enable_key_flag |= KEYCOLOR_FLAG_ONHOLD; + fbdev->enable_key_flag &= ~KEYCOLOR_FLAG_CURRENT; + osd_ext_srckey_enable_hw(fb_info->node - 2, 0); + + } else { + fbdev->enable_key_flag &= ~KEYCOLOR_FLAG_ONHOLD; + /* + * if target and current mistach + * then recover the pending key settings + */ + if (fbdev->enable_key_flag & KEYCOLOR_FLAG_TARGET) { + if ((fbdev->enable_key_flag & + KEYCOLOR_FLAG_CURRENT) == 0) { + fbdev->enable_key_flag |= KEYCOLOR_FLAG_CURRENT; + osd_ext_srckey_enable_hw(fb_info->node - 2, 1); + } + } else { + if (fbdev->enable_key_flag & KEYCOLOR_FLAG_CURRENT) { + fbdev->enable_key_flag &= + ~KEYCOLOR_FLAG_CURRENT; + osd_ext_srckey_enable_hw(fb_info->node - 2, 0); + } + } + } + mutex_unlock(&fbdev->lock); + + return count; +} + +static ssize_t show_enable_key_onhold(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + struct osd_fb_dev_s *fbdev = (struct osd_fb_dev_s *)fb_info->par; + + return snprintf(buf, PAGE_SIZE, + (fbdev->enable_key_flag & KEYCOLOR_FLAG_ONHOLD) ? + "1\n" : "0\n"); +} + +static int parse_para(const char *para, int para_num, int *result) +{ + char *token = NULL; + char *params, *params_base; + int *out = result; + int len = 0, count = 0; + int res = 0; + int ret = 0; + + if (!para) + return 0; + + params = kstrdup(para, GFP_KERNEL); + params_base = params; + token = params; + len = strlen(token); + do { + token = strsep(¶ms, " "); + while (token && (isspace(*token) + || !isgraph(*token)) && len) { + token++; + len--; + } + if (len == 0) + break; + ret = kstrtoint(token, 0, &res); + if (ret < 0) + break; + len = strlen(token); + *out++ = res; + count++; + } while ((token) && (count < para_num) && (len > 0)); + + kfree(params_base); + return count; +} + +static ssize_t show_free_scale_axis(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + int x, y, w, h; + + osd_ext_get_free_scale_axis_hw(fb_info->node - 2, &x, &y, &w, &h); + + return snprintf(buf, PAGE_SIZE, "%d %d %d %d\n", x, y, w, h); +} + +static ssize_t store_free_scale_axis(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + int parsed[4]; + + if (likely(parse_para(buf, 4, parsed) == 4)) + osd_ext_set_free_scale_axis_hw(fb_info->node - 2, + parsed[0], parsed[1], parsed[2], parsed[3]); + else + osd_log_err("set free scale axis error\n"); + + return count; +} + +static ssize_t show_scale_axis(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + int x0, y0, x1, y1; + + osd_ext_get_scale_axis_hw(fb_info->node - 2, &x0, &y0, &x1, &y1); + + return snprintf(buf, PAGE_SIZE, "%d %d %d %d\n", x0, y0, x1, y1); +} + +static ssize_t store_scale_axis(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + int parsed[4]; + + if (likely(parse_para(buf, 4, parsed) == 4)) + osd_ext_set_scale_axis_hw(fb_info->node - 2, + parsed[0], parsed[1], parsed[2], parsed[3]); + else + osd_log_err("set scale axis error\n"); + + return count; +} + + +static ssize_t show_scale_width(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + unsigned int free_scale_width = 0; + + osd_ext_get_free_scale_width_hw(fb_info->node - 2, &free_scale_width); + return snprintf(buf, PAGE_SIZE, "free_scale_width:[0x%x]\n", + free_scale_width); +} + +static ssize_t show_scale_height(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + unsigned int free_scale_height = 0; + + osd_ext_get_free_scale_height_hw(fb_info->node - 2, &free_scale_height); + return snprintf(buf, PAGE_SIZE, "free_scale_height:[0x%x]\n", + free_scale_height); +} + +static ssize_t store_free_scale(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + unsigned int free_scale_enable = 0; + int res = 0; + int ret = 0; + + ret = kstrtoint(buf, 0, &res); + free_scale_enable = res; + osd_ext_set_free_scale_enable_hw(fb_info->node - 2, free_scale_enable); + + return count; +} + +static ssize_t show_free_scale(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + unsigned int free_scale_enable = 0; + + osd_ext_get_free_scale_enable_hw(fb_info->node - 2, &free_scale_enable); + return snprintf(buf, PAGE_SIZE, "free_scale_enable:[0x%x]\n", + free_scale_enable); +} + +static ssize_t show_scale(struct device *device, struct device_attribute *attr, + char *buf) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + struct osd_fb_dev_s *fbdev = (struct osd_fb_dev_s *)fb_info->par; + + return snprintf(buf, PAGE_SIZE, "scale:[0x%x]\n", fbdev->scale); +} + +static ssize_t store_scale(struct device *device, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + struct osd_fb_dev_s *fbdev = (struct osd_fb_dev_s *)fb_info->par; + int res = 0; + int ret = 0; + + ret = kstrtoint(buf, 0, &res); + + fbdev->scale = res; + osd_ext_set_2x_scale_hw(fb_info->node - 2, + fbdev->scale & 0xffff0000 ? 1 : 0, + fbdev->scale & 0xffff ? 1 : 0); + + return count; +} + + +static ssize_t show_debug(struct device *device, struct device_attribute *attr, + char *buf) +{ + char help[] = "Usage:\n" + " echo val > debug ; show osd pan/display/scale value\n" + " echo reg > debug ; Show osd register value\n"; + + return snprintf(buf, sizeof(help), "%s", help); +} + +static ssize_t store_debug(struct device *device, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + int debug_flag = 0; + + if (!buf) + return count; + + if (strncmp(buf, "val", 3) == 0) + debug_flag = 1; + else if (strncmp(buf, "reg", 3) == 0) + debug_flag = 2; + osd_ext_set_debug_hw(fb_info->node - 2, debug_flag); + + + return count; +} + +static ssize_t store_order(struct device *device, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + struct osd_fb_dev_s *fbdev = (struct osd_fb_dev_s *)fb_info->par; + int res = 0; + int ret = 0; + + ret = kstrtoint(buf, 0, &res); + fbdev->order = res; + osd_ext_set_order_hw(fb_info->node - 2, fbdev->order); + + return count; +} + +static ssize_t show_order(struct device *device, struct device_attribute *attr, + char *buf) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + struct osd_fb_dev_s *fbdev = (struct osd_fb_dev_s *)fb_info->par; + + fbdev->order = osd_ext_get_order_hw(fb_info->node - 2); + + return snprintf(buf, PAGE_SIZE, "order:[0x%x]\n", fbdev->order); +} + +static ssize_t show_block_windows(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + u32 wins[8]; + + osd_ext_get_block_windows_hw(fb_info->node - 2, wins); + + return snprintf(buf, PAGE_SIZE, + "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", + wins[0], wins[1], wins[2], wins[3], + wins[4], wins[5], wins[6], wins[7]); +} + +static ssize_t store_block_windows(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + int parsed[8]; + + if (likely(parse_para(buf, 8, parsed) == 8)) + osd_ext_set_block_windows_hw(fb_info->node - 2, parsed); + else + osd_log_err("set block windows error\n"); + + return count; +} + +static ssize_t show_block_mode(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + u32 mode; + + osd_ext_get_block_mode_hw(fb_info->node - 2, &mode); + + return snprintf(buf, PAGE_SIZE, "0x%x\n", mode); +} + +static ssize_t store_block_mode(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + u32 mode; + int res = 0; + int ret = 0; + + ret = kstrtoint(buf, 0, &res); + mode = res; + osd_ext_set_block_mode_hw(fb_info->node - 2, mode); + + return count; +} + +static ssize_t store_freescale_mode(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + unsigned int free_scale_mode = 0; + int res = 0; + int ret = 0; + + ret = kstrtoint(buf, 0, &res); + free_scale_mode = res; + osd_ext_set_free_scale_mode_hw(fb_info->node - 2, free_scale_mode); + + return count; +} + +static ssize_t show_freescale_mode(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + unsigned int free_scale_mode = 0; + + osd_ext_get_free_scale_mode_hw(fb_info->node - 2, &free_scale_mode); + + return snprintf(buf, PAGE_SIZE, "free_scale_mode:%s\n", + free_scale_mode ? "new" : "default"); +} + +static ssize_t show_window_axis(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + int x0, y0, x1, y1; + + osd_ext_get_window_axis_hw(fb_info->node - 2, &x0, &y0, &x1, &y1); + + return snprintf(buf, PAGE_SIZE, + "window axis is [%d %d %d %d]\n", + x0, y0, x1, y1); +} + +static ssize_t store_window_axis(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + s32 parsed[4]; + + if (likely(parse_para(buf, 4, parsed) == 4)) + osd_ext_set_window_axis_hw(fb_info->node - 2, + parsed[0], parsed[1], parsed[2], parsed[3]); + else + osd_log_err("set window axis error\n"); + + return count; +} + +static ssize_t show_clone(struct device *device, struct device_attribute *attr, + char *buf) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + u32 clone; + + osd_ext_get_clone_hw(fb_info->node - 2, &clone); + + return snprintf(buf, PAGE_SIZE, "osd_ext->clone: [0x%x]\n", clone); +} + +static ssize_t store_clone(struct device *device, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + u32 clone; + int res = 0; + int ret = 0; + + ret = kstrtoint(buf, 0, &res); + clone = res; + osd_ext_set_clone_hw(fb_info->node - 2, clone); + + return count; +} + +static ssize_t show_angle(struct device *device, struct device_attribute *attr, + char *buf) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + u32 angle; + + osd_ext_get_angle_hw(fb_info->node - 2, &angle); + + return snprintf(buf, PAGE_SIZE, "osd_ext->angle: [0x%x]\n", angle); +} + +static ssize_t store_angle(struct device *device, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fb_info *fb_info = dev_get_drvdata(device); + u32 angle; + int res = 0; + int ret = 0; + + ret = kstrtoint(buf, 0, &res); + angle = res; + osd_ext_set_angle_hw(fb_info->node - 2, angle); + + return count; +} + +static struct device_attribute osd_ext_attrs[] = { + __ATTR(scale, 0664, + show_scale, store_scale), + __ATTR(order, 0664, + show_order, store_order), + __ATTR(enable_3d, 0644, + show_enable_3d, store_enable_3d), + __ATTR(free_scale, 0664, + show_free_scale, store_free_scale), + __ATTR(scale_axis, 0644, + show_scale_axis, store_scale_axis), + __ATTR(scale_width, 0644, + show_scale_width, NULL), + __ATTR(scale_height, 0644, + show_scale_height, NULL), + __ATTR(color_key, 0644, + show_color_key, store_color_key), + __ATTR(enable_key, 0644, + show_enable_key, store_enable_key), + __ATTR(enable_key_onhold, 0644, + show_enable_key_onhold, store_enable_key_onhold), + __ATTR(block_windows, 0644, + show_block_windows, store_block_windows), + __ATTR(block_mode, 0644, + show_block_mode, store_block_mode), + __ATTR(free_scale_axis, 0644, + show_free_scale_axis, store_free_scale_axis), + __ATTR(debug, 0644, + show_debug, store_debug), + __ATTR(window_axis, 0644, + show_window_axis, store_window_axis), + __ATTR(freescale_mode, 0644, + show_freescale_mode, store_freescale_mode), + __ATTR(clone, 0664, + show_clone, store_clone), + __ATTR(angle, 0644, + show_angle, store_angle), +}; + +#ifdef CONFIG_PM +static int osd_ext_suspend(struct platform_device *pdev, pm_message_t state) +{ +#ifdef CONFIG_HAS_EARLYSUSPEND + if (early_suspend_flag) + return 0; +#endif + osd_ext_suspend_hw(); + return 0; +} + +static int osd_ext_resume(struct platform_device *dev) +{ +#ifdef CONFIG_SCREEN_ON_EARLY + if (early_resume_flag) { + early_resume_flag = 0; + return 0; + } +#endif +#ifdef CONFIG_HAS_EARLYSUSPEND + if (early_suspend_flag) + return 0; +#endif + osd_ext_resume_hw(); + return 0; +} +#endif + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void osd_ext_early_suspend(struct early_suspend *h) +{ + if (early_suspend_flag) + return; + osd_ext_suspend_hw(); + early_suspend_flag = 1; +} + +static void osd_ext_late_resume(struct early_suspend *h) +{ + if (!early_suspend_flag) + return; + early_suspend_flag = 0; + osd_ext_resume_hw(); +} +#endif + +#ifdef CONFIG_SCREEN_ON_EARLY +void osd_ext_resume_early(void) +{ +#ifdef CONFIG_HAS_EARLYSUSPEND + osd_ext_resume_hw(); + early_suspend_flag = 0; +#endif + early_resume_flag = 1; +} +EXPORT_SYMBOL(osd_ext_resume_early); +#endif + +/* static struct resource memobj; */ +static int +osd_ext_probe(struct platform_device *pdev) +{ + int ret = 0; + struct fb_info *fbi = NULL; + const struct vinfo_s *vinfo = NULL; + struct fb_var_screeninfo *var; + struct fb_fix_screeninfo *fix; + /* struct resource *mem; */ + int index, Bpp; + int i; + struct osd_fb_dev_s *fbdev = NULL; + u32 memsize[2]; + int osd_ext_memory = 0; + /* 0:don't need osd_ext memory,1:need osd_ext memory */ + +#ifdef CONFIG_AMLOGIC_VOUT2 + /* register vout2 client */ + vout2_register_client(&osd_ext_notifier_nb); +#endif + + /* get interrupt resource */ + int_viu2_vsync = platform_get_irq_byname(pdev, "viu2-vsync"); + if (int_viu2_vsync == -ENXIO) { + osd_log_err("cannot get viu2 irq resource\n"); + goto failed1; + } else + osd_log_info("viu2 vysnc irq: %d\n", int_viu2_vsync); + + /* get buffer size from dt */ + ret = of_property_read_u32_array(pdev->dev.of_node, + "mem_size", memsize, 2); + if (ret) { + osd_log_err("not found mem_size from dt\n"); + osd_ext_memory = 0; + } else { + osd_log_dbg("mem_size: 0x%x, 0x%x\n", memsize[0], memsize[1]); + fb_rmem_size[0] = memsize[0]; + fb_rmem_paddr[0] = fb_rmem.base; + if ((OSD_COUNT == 2) && ((memsize[0] + memsize[1]) <= + fb_rmem.size)) { + fb_rmem_size[1] = memsize[1]; + fb_rmem_paddr[1] = fb_rmem.base + memsize[0]; + } + osd_ext_memory = 1; + } + + /* init reserved memory */ + ret = of_reserved_mem_device_init(&pdev->dev); + if (ret != 0) { + osd_log_info("not found reserved memory\n"); + osd_ext_memory = 0; + } +#ifdef CONFIG_AMLOGIC_VOUT2 + set_current_vmode2(VMODE_INIT_NULL); +#endif + osd_ext_init_hw(0); + +#ifdef CONFIG_AMLOGIC_VOUT2 + vinfo = get_current_vinfo2(); + osd_log_info("%s vinfo:%p\n", __func__, vinfo); +#endif + for (index = 0; index < OSD_COUNT; index++) { + fbi = framebuffer_alloc(sizeof(struct osd_fb_dev_s), + &pdev->dev); + if (!fbi) { + ret = -ENOMEM; + goto failed1; + } + + fbdev = (struct osd_fb_dev_s *)fbi->par; + fbdev->fb_info = fbi; + fbdev->dev = pdev; + + mutex_init(&fbdev->lock); + var = &fbi->var; + fix = &fbi->fix; + gp_fbdev_list[index] = fbdev; + if (osd_ext_memory) { + fbdev->fb_len = fb_rmem_size[index]; + fbdev->fb_mem_paddr = fb_rmem_paddr[index]; + fbdev->fb_mem_vaddr = fb_rmem_vaddr[index]; + if (!fbdev->fb_mem_vaddr) { + osd_log_err("failed to ioremap frame buffer\n"); + ret = -ENOMEM; + goto failed1; + } + } else + fbdev->fb_mem_paddr = 0; + osd_log_info("Frame buffer memory assigned at"); + osd_log_info(" phy:0x%08x, vir:0x%p, size=%dK\n", + fbdev->fb_mem_paddr, + fbdev->fb_mem_vaddr, + fbdev->fb_len >> 10); + if (index == DEV_OSD0) { + ret = of_property_read_u32_array(pdev->dev.of_node, + "display_size_default", + &var_screeninfo[0], 5); + if (ret) + osd_log_info("not found default size\n"); + else { + int bpp = var_screeninfo[4]; + + fb_def_var[index].xres = var_screeninfo[0]; + fb_def_var[index].yres = var_screeninfo[1]; + fb_def_var[index].xres_virtual = + var_screeninfo[2]; + fb_def_var[index].yres_virtual = + var_screeninfo[3]; + /* logo always use double buffer */ + fb_def_var[index].bits_per_pixel = bpp; + osd_log_info("init fbdev bpp is :%d\n", + fb_def_var[index].bits_per_pixel); + if (fb_def_var[index].bits_per_pixel > 32) + fb_def_var[index].bits_per_pixel = 32; + } + } + + _fbdev_set_default(fbdev, index); + if (fbdev->color == NULL) { + osd_log_err("fbdev->color NULL\n"); + ret = -ENOENT; + goto failed1; + } + + if (osd_ext_memory) { + Bpp = (fbdev->color->color_index > 8 ? + (fbdev->color->color_index > 16 ? + (fbdev->color->color_index > 24 ? + 4 : 3) : 2) : 1); + fix->line_length = var->xres_virtual * Bpp; + fix->smem_start = fbdev->fb_mem_paddr; + fix->smem_len = fbdev->fb_len; + } + + if (fb_alloc_cmap(&fbi->cmap, 16, 0) != 0) { + osd_log_err("unable to allocate color map memory\n"); + ret = -ENOMEM; + goto failed2; + } + + fbi->pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL); + if (!(fbi->pseudo_palette)) { + osd_log_err("unable to allocate pseudo palette mem\n"); + ret = -ENOMEM; + goto failed2; + } + memset(fbi->pseudo_palette, 0, sizeof(u32) * 16); + + fbi->fbops = &osd_ext_ops; + + if (osd_ext_memory) { + fbi->screen_base = (char __iomem *)fbdev->fb_mem_vaddr; + fbi->screen_size = fix->smem_len; + } + + if (vinfo) + set_default_display_axis(&fbdev->fb_info->var, + &fbdev->osd_ctl, vinfo); + osd_ext_check_var(var, fbi); + register_framebuffer(fbi); + + osddev_ext_setup(fbdev); + for (i = 0; i < ARRAY_SIZE(osd_ext_attrs); i++) + ret = device_create_file(fbi->dev, &osd_ext_attrs[i]); + } + + index = 0; +#ifdef CONFIG_HAS_EARLYSUSPEND + early_suspend.level = EARLY_SUSPEND_LEVEL_STOP_DRAWING; + early_suspend.suspend = osd_ext_early_suspend; + early_suspend.resume = osd_ext_late_resume; + register_early_suspend(&early_suspend); +#endif + + osd_log_info("osd-ext probe ok\n"); + return 0; + +failed2: + fb_dealloc_cmap(&fbi->cmap); +failed1: + osd_log_err("osd-ext module probe failed.\n"); + return ret; +} + +static int +osd_ext_remove(struct platform_device *pdev) +{ + struct fb_info *fbi; + int i = 0; + + osd_log_info("osd_ext_remove.\n"); + if (!pdev) + return -ENODEV; + +#ifdef CONFIG_HAS_EARLYSUSPEND + unregister_early_suspend(&early_suspend); +#endif + + vout_unregister_client(&osd_ext_notifier_nb); + + for (i = 0; i < OSD_COUNT; i++) { + int j; + + if (gp_fbdev_list[i]) { + struct osd_fb_dev_s *fbdev = gp_fbdev_list[i]; + + fbi = fbdev->fb_info; + for (j = 0; j < ARRAY_SIZE(osd_ext_attrs); j++) + device_remove_file(fbi->dev, &osd_ext_attrs[j]); + iounmap(fbdev->fb_mem_vaddr); + kfree(fbi->pseudo_palette); + fb_dealloc_cmap(&fbi->cmap); + unregister_framebuffer(fbi); + framebuffer_release(fbi); + } + } + return 0; +} + +/* Process kernel command line parameters */ +static int __init +osd_ext_setup_attribute(char *options) +{ + char *this_opt = NULL; + int r = 0; + unsigned long res; + + if (!options || !*options) + goto exit; + + while (!r && (this_opt = strsep(&options, ",")) != NULL) { + if (!strncmp(this_opt, "xres:", 5)) { + r = kstrtol(this_opt + 5, 0, &res); + fb_def_var[0].xres = fb_def_var[0].xres_virtual = res; + } else if (!strncmp(this_opt, "yres:", 5)) { + r = kstrtol(this_opt + 5, 0, &res); + fb_def_var[0].yres = fb_def_var[0].yres_virtual = res; + } else { + osd_log_err("invalid option\n"); + r = -1; + } + } +exit: + return r; +} + +static int rmem_fb_device_init(struct reserved_mem *rmem, struct device *dev) +{ + int i = 0; + + for (i = 0; i < OSD_COUNT; i++) { + if ((fb_rmem_paddr[i] > 0) && (fb_rmem_size[i] > 0)) { + fb_rmem_vaddr[i] = ioremap_wc(fb_rmem_paddr[i], + fb_rmem_size[i]); + if (!fb_rmem_vaddr[i]) + osd_log_err("fb [%d] ioremap error", i); + } + } + + return 0; +} + +static const struct reserved_mem_ops rmem_fb_ops = { + .device_init = rmem_fb_device_init, +}; + +static int __init rmem_fb_setup(struct reserved_mem *rmem) +{ + phys_addr_t align = PAGE_SIZE; + phys_addr_t mask = align - 1; + + if ((rmem->base & mask) || (rmem->size & mask)) { + pr_err("Reserved memory: incorrect alignment of region\n"); + return -EINVAL; + } + fb_rmem.base = rmem->base; + fb_rmem.size = rmem->size; + rmem->ops = &rmem_fb_ops; + + osd_log_info("Reserved memory: created fb at 0x%p, size %ld MiB\n", + (void *)rmem->base, (unsigned long)rmem->size / SZ_1M); + + return 0; +} +RESERVEDMEM_OF_DECLARE(fb, "amlogic, fb-ext-memory", rmem_fb_setup); + +/****************************************/ +static const struct of_device_id meson_fbext_dt_match[] = { + {.compatible = "amlogic, meson-fb-ext",}, + {}, +}; + +static struct platform_driver + osd_ext_driver = { + .probe = osd_ext_probe, + .remove = osd_ext_remove, +#ifdef CONFIG_PM + .suspend = osd_ext_suspend, + .resume = osd_ext_resume, +#endif + .driver = { + .name = "meson-fb-ext", + .of_match_table = meson_fbext_dt_match, + } +}; + +static int __init osd_ext_init_module(void) +{ + char *option; + + osd_log_info("%s\n", __func__); + if (fb_get_options("meson-fb-ext", &option)) + return -ENODEV; + osd_ext_setup_attribute(option); + if (platform_driver_register(&osd_ext_driver)) { + osd_log_err("failed to register osd ext driver\n"); + return -ENODEV; + } + + return 0; +} + +static void __exit osd_ext_exit_module(void) +{ + osd_log_info("%s\n", __func__); + + platform_driver_unregister(&osd_ext_driver); +} + +/****************************************/ +module_init(osd_ext_init_module); +module_exit(osd_ext_exit_module); + +MODULE_AUTHOR("Platform-BJ "); +MODULE_DESCRIPTION("OSD EXT Module"); +MODULE_LICENSE("GPL"); diff --git a/drivers/amlogic/media/osd_ext/osd_fb.h b/drivers/amlogic/media/osd_ext/osd_fb.h new file mode 100644 index 000000000000..f4969678f70f --- /dev/null +++ b/drivers/amlogic/media/osd_ext/osd_fb.h @@ -0,0 +1,274 @@ +/* + * drivers/amlogic/media/osd_ext/osd_fb.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 _OSD_FB_H_ +#define _OSD_FB_H_ + +/* Linux Headers */ +#include +#include + +/* Amlogic Headers */ +#include + +/* Local Headers */ +#include + +#define OSD_COUNT 2 /* enable two OSD layers */ + +#define INVALID_BPP_ITEM {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +static const struct color_bit_define_s default_color_format_array[] = { + INVALID_BPP_ITEM, + INVALID_BPP_ITEM, + { + COLOR_INDEX_02_PAL4, 0, 0, + 0, 2, 0, 0, 2, 0, 0, 2, 0, 0, 0, 0, + FB_VISUAL_PSEUDOCOLOR, 2, + }, + INVALID_BPP_ITEM, + { + COLOR_INDEX_04_PAL16, 0, 1, + 0, 4, 0, 0, 4, 0, 0, 4, 0, 0, 0, 0, + FB_VISUAL_PSEUDOCOLOR, 4, + }, + INVALID_BPP_ITEM, + INVALID_BPP_ITEM, + INVALID_BPP_ITEM, + { + COLOR_INDEX_08_PAL256, 0, 2, + 0, 8, 0, 0, 8, 0, 0, 8, 0, 0, 0, 0, + FB_VISUAL_PSEUDOCOLOR, 8, + }, + /*16 bit color*/ + { + COLOR_INDEX_16_655, 0, 4, + 10, 6, 0, 5, 5, 0, 0, 5, 0, 0, 0, 0, + FB_VISUAL_TRUECOLOR, 16 + }, + { + COLOR_INDEX_16_844, 1, 4, + 8, 8, 0, 4, 4, 0, 0, 4, 0, 0, 0, 0, + FB_VISUAL_TRUECOLOR, 16 + }, + { + COLOR_INDEX_16_6442, 2, 4, + 10, 6, 0, 6, 4, 0, 2, 4, 0, 0, 2, 0, + FB_VISUAL_TRUECOLOR, 16 + }, + { + COLOR_INDEX_16_4444_R, 3, 4, + 12, 4, 0, 8, 4, 0, 4, 4, 0, 0, 4, 0, + FB_VISUAL_TRUECOLOR, 16 + }, + { + COLOR_INDEX_16_4642_R, 7, 4, + 12, 4, 0, 6, 6, 0, 2, 4, 0, 0, 2, 0, + FB_VISUAL_TRUECOLOR, 16 + }, + { + COLOR_INDEX_16_1555_A, 6, 4, + 10, 5, 0, 5, 5, 0, 0, 5, 0, 15, 1, 0, + FB_VISUAL_TRUECOLOR, 16 + }, + { + COLOR_INDEX_16_4444_A, 5, 4, + 8, 4, 0, 4, 4, 0, 0, 4, 0, 12, 4, 0, + FB_VISUAL_TRUECOLOR, 16 + }, + { + COLOR_INDEX_16_565, 4, 4, + 11, 5, 0, 5, 6, 0, 0, 5, 0, 0, 0, 0, + FB_VISUAL_TRUECOLOR, 16 + }, + /*24 bit color*/ + INVALID_BPP_ITEM, + INVALID_BPP_ITEM, + { + COLOR_INDEX_24_6666_A, 4, 7, + 12, 6, 0, 6, 6, 0, 0, 6, 0, 18, 6, 0, + FB_VISUAL_TRUECOLOR, 24 + }, + { + COLOR_INDEX_24_6666_R, 3, 7, + 18, 6, 0, 12, 6, 0, 6, 6, 0, 0, 6, 0, + FB_VISUAL_TRUECOLOR, 24 + }, + { + COLOR_INDEX_24_8565, 2, 7, + 11, 5, 0, 5, 6, 0, 0, 5, 0, 16, 8, 0, + FB_VISUAL_TRUECOLOR, 24 + }, + { + COLOR_INDEX_24_5658, 1, 7, + 19, 5, 0, 13, 6, 0, 8, 5, 0, 0, 8, 0, + FB_VISUAL_TRUECOLOR, 24 + }, + { + COLOR_INDEX_24_888_B, 5, 7, + 0, 8, 0, 8, 8, 0, 16, 8, 0, 0, 0, 0, + FB_VISUAL_TRUECOLOR, 24 + }, + { + COLOR_INDEX_24_RGB, 0, 7, + 16, 8, 0, 8, 8, 0, 0, 8, 0, 0, 0, 0, + FB_VISUAL_TRUECOLOR, 24 + }, + /*32 bit color*/ + INVALID_BPP_ITEM, + INVALID_BPP_ITEM, + INVALID_BPP_ITEM, + INVALID_BPP_ITEM, + { + COLOR_INDEX_32_BGRA, 3, 5, + 8, 8, 0, 16, 8, 0, 24, 8, 0, 0, 8, 0, + FB_VISUAL_TRUECOLOR, 32 + }, + { + COLOR_INDEX_32_ABGR, 2, 5, + 0, 8, 0, 8, 8, 0, 16, 8, 0, 24, 8, 0, + FB_VISUAL_TRUECOLOR, 32 + }, + { + COLOR_INDEX_32_RGBA, 0, 5, + 24, 8, 0, 16, 8, 0, 8, 8, 0, 0, 8, 0, + FB_VISUAL_TRUECOLOR, 32 + }, + { + COLOR_INDEX_32_ARGB, 1, 5, + 16, 8, 0, 8, 8, 0, 0, 8, 0, 24, 8, 0, + FB_VISUAL_TRUECOLOR, 32 + }, + /*YUV color*/ + {COLOR_INDEX_YUV_422, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16}, +}; + +static __u32 var_screeninfo[5]; + +static struct fb_var_screeninfo fb_def_var[] = { + { + .xres = 768, + .yres = 1024, + .xres_virtual = 768, + .yres_virtual = 2048, + .xoffset = 0, + .yoffset = 0, + .bits_per_pixel = 32, + .grayscale = 0, + .red = {0, 0, 0}, + .green = {0, 0, 0}, + .blue = {0, 0, 0}, + .transp = {0, 0, 0}, + .nonstd = 0, + .activate = FB_ACTIVATE_NOW, + .height = -1, + .width = -1, + .accel_flags = 0, + .pixclock = 0, + .left_margin = 0, + .right_margin = 0, + .upper_margin = 0, + .lower_margin = 0, + .hsync_len = 0, + .vsync_len = 0, + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED, + .rotate = 0, + + } + +#ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD2_ENABLE + , + { +#if defined(CONFIG_FB_OSD2_DEFAULT_WIDTH) + .xres = CONFIG_FB_OSD2_DEFAULT_WIDTH, +#else + .xres = 32, +#endif +#if defined(CONFIG_FB_OSD2_DEFAULT_HEIGHT) + .yres = CONFIG_FB_OSD2_DEFAULT_HEIGHT, +#else + .yres = 32, +#endif +#if defined(CONFIG_FB_OSD2_DEFAULT_WIDTH_VIRTUAL) + .xres_virtual = CONFIG_FB_OSD2_DEFAULT_WIDTH_VIRTUAL, +#else + .xres_virtual = 32, +#endif +#if defined(CONFIG_FB_OSD2_DEFAULT_HEIGHT_VIRTUAL) + .yres_virtual = CONFIG_FB_OSD2_DEFAULT_HEIGHT_VIRTUAL, +#else + .yres_virtual = 32, +#endif + .xoffset = 0, + .yoffset = 0, +#if defined(CONFIG_FB_OSD2_DEFAULT_BITS_PER_PIXEL) + .bits_per_pixel = CONFIG_FB_OSD2_DEFAULT_BITS_PER_PIXEL, +#else + .bits_per_pixel = 32, +#endif + .grayscale = 0, + .red = {0, 0, 0}, + .green = {0, 0, 0}, + .blue = {0, 0, 0}, + .transp = {0, 0, 0}, + .nonstd = 0, + .activate = FB_ACTIVATE_NOW, + .height = -1, + .width = -1, + .accel_flags = 0, + .pixclock = 0, + .left_margin = 0, + .right_margin = 0, + .upper_margin = 0, + .lower_margin = 0, + .hsync_len = 0, + .vsync_len = 0, + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED, + .rotate = 0, + } +#endif +}; + +static struct fb_fix_screeninfo fb_def_fix = { + .id = "OSD FB EXT", + .xpanstep = 1, + .ypanstep = 1, + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_TRUECOLOR, + .accel = FB_ACCEL_NONE, +}; + +struct osd_fb_dev_s { + struct mutex lock; + struct fb_info *fb_info; + struct platform_device *dev; + u32 fb_mem_paddr; + void __iomem *fb_mem_vaddr; + u32 fb_len; + const struct color_bit_define_s *color; + enum vmode_e vmode; + struct osd_ctl_s osd_ctl; + u32 order; + u32 scale; + u32 enable_3d; + u32 preblend_enable; + u32 enable_key_flag; + u32 color_key; +}; + +#endif /* _OSD_FB_H_ */ diff --git a/drivers/amlogic/media/osd_ext/osd_hw.c b/drivers/amlogic/media/osd_ext/osd_hw.c new file mode 100644 index 000000000000..6c25a05c6706 --- /dev/null +++ b/drivers/amlogic/media/osd_ext/osd_hw.c @@ -0,0 +1,2520 @@ +/* + * drivers/amlogic/media/osd_ext/osd_hw.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. + * + */ + +/* Linux Headers */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Android Headers */ +#include +#include + +/* Amlogic Headers */ +#include +#include +#ifdef CONFIG_AMLOGIC_MEDIA_CANVAS +#include +#include +#endif +#ifdef CONFIG_AMLOGIC_VIDEO +#include +#endif + +/* Local Headers */ +#include +#include +#include +#include +#include + + +#include "osd_prot.h" +#include "osd_clone.h" +#include "osd_hw_def.h" + +#ifdef CONFIG_AML_VSYNC_FIQ_ENABLE +#define FIQ_VSYNC +#endif + +static DECLARE_WAIT_QUEUE_HEAD(osd_ext_vsync_wq); +static bool vsync_hit; +static bool osd_ext_vf_need_update; +static struct hw_para_s *osd_hw; + +#ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD_SYNC_FENCE +/* add sync fence relative varible here. */ +/* we will limit all fence relative code in this driver file. */ +static int ext_timeline_created; +static struct sw_sync_timeline *ext_timeline; +static u32 ext_cur_streamline_val; +/* thread control part */ +struct kthread_worker ext_buffer_toggle_worker; +struct task_struct *ext_buffer_toggle_thread; +struct kthread_work ext_buffer_toggle_work; +struct list_head ext_post_fence_list; +struct mutex ext_post_fence_list_lock; + +static void osd_ext_pan_display_fence(struct osd_fence_map_s *fence_map); +#endif + +#ifdef CONFIG_AMLOGIC_VIDEO +#define PROVIDER_NAME "osd_ext" +static struct vframe_s vf; +static struct vframe_provider_s osd_ext_vf_prov; +static unsigned char osd_ext_vf_prov_init; +#endif + +#ifdef CONFIG_AMLOGIC_VIDEO +static int g_vf_visual_width; +static int g_vf_width; +static int g_vf_height; +#endif +static unsigned int filt_coef0[] = { /* bicubic */ + 0x00800000, + 0x007f0100, + 0xff7f0200, + 0xfe7f0300, + 0xfd7e0500, + 0xfc7e0600, + 0xfb7d0800, + 0xfb7c0900, + 0xfa7b0b00, + 0xfa7a0dff, + 0xf9790fff, + 0xf97711ff, + 0xf87613ff, + 0xf87416fe, + 0xf87218fe, + 0xf8701afe, + 0xf76f1dfd, + 0xf76d1ffd, + 0xf76b21fd, + 0xf76824fd, + 0xf76627fc, + 0xf76429fc, + 0xf7612cfc, + 0xf75f2ffb, + 0xf75d31fb, + 0xf75a34fb, + 0xf75837fa, + 0xf7553afa, + 0xf8523cfa, + 0xf8503ff9, + 0xf84d42f9, + 0xf84a45f9, + 0xf84848f8 +}; + +static unsigned int filt_coef1[] = { /* 2 point bilinear */ + 0x00800000, + 0x007e0200, + 0x007c0400, + 0x007a0600, + 0x00780800, + 0x00760a00, + 0x00740c00, + 0x00720e00, + 0x00701000, + 0x006e1200, + 0x006c1400, + 0x006a1600, + 0x00681800, + 0x00661a00, + 0x00641c00, + 0x00621e00, + 0x00602000, + 0x005e2200, + 0x005c2400, + 0x005a2600, + 0x00582800, + 0x00562a00, + 0x00542c00, + 0x00522e00, + 0x00503000, + 0x004e3200, + 0x004c3400, + 0x004a3600, + 0x00483800, + 0x00463a00, + 0x00443c00, + 0x00423e00, + 0x00404000 +}; + +static unsigned int filt_coef2[] = { /* 2 point bilinear, bank_length == 2 */ + 0x80000000, + 0x7e020000, + 0x7c040000, + 0x7a060000, + 0x78080000, + 0x760a0000, + 0x740c0000, + 0x720e0000, + 0x70100000, + 0x6e120000, + 0x6c140000, + 0x6a160000, + 0x68180000, + 0x661a0000, + 0x641c0000, + 0x621e0000, + 0x60200000, + 0x5e220000, + 0x5c240000, + 0x5a260000, + 0x58280000, + 0x562a0000, + 0x542c0000, + 0x522e0000, + 0x50300000, + 0x4e320000, + 0x4c340000, + 0x4a360000, + 0x48380000, + 0x463a0000, + 0x443c0000, + 0x423e0000, + 0x40400000 +}; + +#ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD_SYNC_FENCE +static inline int find_ext_buf_num(u32 yres, u32 yoffset) +{ + int n = yres; + int i; + + for (i = 0; i < OSD_MAX_BUF_NUM; i++) { + /* find current addr position. */ + if (yoffset < (n)) + break; + n += yres; + } + + return i; +} + +static void osd_ext_toggle_buffer(struct kthread_work *work) +{ + struct osd_fence_map_s *data, *next; + struct list_head saved_list; + + mutex_lock(&ext_post_fence_list_lock); + saved_list = ext_post_fence_list; + list_replace_init(&ext_post_fence_list, &saved_list); + mutex_unlock(&ext_post_fence_list_lock); + + list_for_each_entry_safe(data, next, &saved_list, list) { + osd_ext_pan_display_fence(data); + + if ((data->in_fence) && (data->in_fd > 0)) { + __close_fd(data->files, data->in_fd); + sync_fence_put(data->in_fence); + } + + list_del(&data->list); + kfree(data); + } +} + +static int out_ext_fence_create(int *release_fence_fd, u32 *val, u32 buf_num) +{ + /* the first time create out_fence_fd==0 */ + /* sw_sync_timeline_inc will release fence and it's sync point */ + struct sync_pt *outer_sync_pt; + struct sync_fence *outer_fence; + int out_fence_fd = -1; + + out_fence_fd = get_unused_fd_flags(O_CLOEXEC); + + /* no file descriptor could be used. Error. */ + if (out_fence_fd < 0) + return -1; + + if (!ext_timeline_created) { /* timeline has not been created */ + ext_timeline = sw_sync_timeline_create("osd_ext_timeline"); + ext_cur_streamline_val = 1; + + if (ext_timeline == NULL) + return -1; + + init_kthread_worker(&ext_buffer_toggle_worker); + ext_buffer_toggle_thread = + kthread_run(kthread_worker_fn, + &ext_buffer_toggle_worker, + "aml_buf_ext_toggle"); + init_kthread_work(&ext_buffer_toggle_work, + osd_ext_toggle_buffer); + ext_timeline_created = 1; + } + + /* install fence map; first ,the simplest. */ + ext_cur_streamline_val++; + *val = ext_cur_streamline_val; + + outer_sync_pt = sw_sync_pt_create(ext_timeline, *val); + + if (outer_sync_pt == NULL) + goto error_ret; + + outer_fence = sync_fence_create("osd_ext_fence_out", outer_sync_pt); + if (outer_fence == NULL) { + sync_pt_free(outer_sync_pt); /* free sync point. */ + goto error_ret; + } + + sync_fence_install(outer_fence, out_fence_fd); + osd_log_dbg("---------------------------------------\n"); + osd_log_dbg("return out fence fd:%d\n", out_fence_fd); + *release_fence_fd = out_fence_fd; + return out_fence_fd; + +error_ret: + ext_cur_streamline_val--; + /* pt or fence fail,restore timeline value. */ + osd_log_err("fence obj create fail\n"); + put_unused_fd(out_fence_fd); + return -1; + +} + +int osd_ext_sync_request(u32 index, u32 yres, u32 xoffset, u32 yoffset, + s32 in_fence_fd) +{ + int out_fence_fd = -1; + int buf_num = 0; + struct osd_fence_map_s *fence_map = NULL; + + fence_map = kzalloc(sizeof(struct osd_fence_map_s), GFP_KERNEL); + if (!fence_map) + return -ENOMEM; + + buf_num = find_ext_buf_num(yres, yoffset); + + mutex_lock(&ext_post_fence_list_lock); + fence_map->fb_index = index; + fence_map->buf_num = buf_num; + fence_map->yoffset = yoffset; + fence_map->xoffset = xoffset; + fence_map->yres = yres; + fence_map->in_fd = in_fence_fd; + fence_map->in_fence = sync_fence_fdget(in_fence_fd); + fence_map->files = current->files; + + fence_map->out_fd = out_ext_fence_create(&out_fence_fd, &fence_map->val, + buf_num); + list_add_tail(&fence_map->list, &ext_post_fence_list); + mutex_unlock(&ext_post_fence_list_lock); + + queue_kthread_work(&ext_buffer_toggle_worker, &ext_buffer_toggle_work); + + return out_fence_fd; +} + +static int osd_ext_wait_buf_ready(struct osd_fence_map_s *fence_map) +{ + s32 ret = -1; + struct sync_fence *buf_ready_fence = NULL; + + if (fence_map->in_fd <= 0) { + ret = -1; + return ret; + } + + buf_ready_fence = fence_map->in_fence; + + if (buf_ready_fence == NULL) { + ret = -1;/* no fence ,output directly. */ + return ret; + } + + ret = sync_fence_wait(buf_ready_fence, -1); + if (ret < 0) + osd_log_err("Sync Fence wait error:%d\n", ret); + else + ret = 1; + + return ret; +} +#else +int osd_ext_sync_request(u32 index, u32 yres, u32 xoffset, u32 yoffset, + s32 in_fence_fd) +{ + osd_log_err("osd_ext_sync_request not supported\n"); + return -5566; +} +#endif + +#ifdef CONFIG_AMLOGIC_VIDEO +static struct vframe_s *osd_ext_vf_peek(void *arg) +{ + if ((osd_ext_vf_need_update && (vf.width > 0) && (vf.height > 0))) + return &vf; + else + return NULL; +} + +static struct vframe_s *osd_ext_vf_get(void *arg) +{ + if (osd_ext_vf_need_update) { + vf_ext_light_unreg_provider(&osd_ext_vf_prov); + osd_ext_vf_need_update = false; + return &vf; + } + + return NULL; +} + +static const struct vframe_operations_s osd_ext_vf_provider = { + .peek = osd_ext_vf_peek, + .get = osd_ext_vf_get, + .put = NULL, +}; +#endif + + +static inline void osd_ext_update_3d_mode(int enable_osd1, int enable_osd2) +{ + if (enable_osd1) + osd1_update_disp_3d_mode(); + + if (enable_osd2) + osd2_update_disp_3d_mode(); +} + +static inline void wait_ext_vsync_wakeup(void) +{ + vsync_hit = true; + wake_up_interruptible(&osd_ext_vsync_wq); +} + +static inline void walk_through_update_list(void) +{ + u32 i, j; + + for (i = 0; i < HW_OSD_COUNT; i++) { + j = 0; + while (osd_ext_hw.updated[i] && j < 32) { + if (osd_ext_hw.updated[i] & (1 << j)) { + osd_ext_hw.reg[i][j].update_func(); + remove_from_update_list(i, j); + } + j++; + } + } +} + +#ifdef FIQ_VSYNC +static irqreturn_t vsync_isr(int irq, void *dev_id) +{ + wait_ext_vsync_wakeup(); + + return IRQ_HANDLED; +} +#endif + +#ifdef FIQ_VSYNC +static void osd_ext_fiq_isr(void) +#else +static irqreturn_t vsync_isr(int irq, void *dev_id) +#endif +{ +#define VOUT_ENCI 1 +#define VOUT_ENCP 2 +#define VOUT_ENCT 3 + unsigned int fb0_cfg_w0, fb1_cfg_w0; + unsigned int odd_even; + unsigned int scan_line_number = 0; + unsigned char output_type = 0; + + output_type = osd_reg_read(VPU_VIU_VENC_MUX_CTRL) & 0xc; + osd_ext_hw.scan_mode = SCAN_MODE_PROGRESSIVE; + switch (output_type) { + case VOUT_ENCP: + if (osd_reg_read(ENCP_VIDEO_MODE) & (1 << 12)) /* 1080i */ + osd_ext_hw.scan_mode = SCAN_MODE_INTERLACE; + + break; + + case VOUT_ENCI: + if (osd_reg_read(ENCI_VIDEO_EN) & 1) + osd_ext_hw.scan_mode = SCAN_MODE_INTERLACE; + + break; + } + + + if (osd_ext_hw.free_scale_enable[OSD1]) + osd_ext_hw.scan_mode = SCAN_MODE_PROGRESSIVE; + + if (osd_ext_hw.scan_mode == SCAN_MODE_INTERLACE) { + fb0_cfg_w0 = osd_reg_read(VIU2_OSD1_BLK0_CFG_W0); + fb1_cfg_w0 = osd_reg_read(VIU2_OSD1_BLK0_CFG_W0 + REG_OFFSET); + + if (osd_reg_read(ENCP_VIDEO_MODE) & (1 << 12)) { + /* 1080I */ + scan_line_number = ((osd_reg_read(ENCP_INFO_READ)) + & 0x1fff0000) >> 16; + if ((osd_ext_hw.pandata[OSD1].y_start % 2) == 0) { + if (scan_line_number >= 562) { + /* bottom field, odd lines */ + odd_even = 1; + } else { + /* top field, even lines */ + odd_even = 0; + } + } else { + if (scan_line_number >= 562) { + /* top field, even lines */ + odd_even = 0; + } else { + /* bottom field, odd lines */ + odd_even = 1; + } + } + } else { + if ((osd_ext_hw.pandata[OSD1].y_start % 2) == 0) + odd_even = osd_reg_read(ENCI_INFO_READ) & 1; + else + odd_even = !(osd_reg_read(ENCI_INFO_READ) & 1); + } + + fb0_cfg_w0 &= ~1; + fb1_cfg_w0 &= ~1; + fb0_cfg_w0 |= odd_even; + fb1_cfg_w0 |= odd_even; + osd_reg_write(VIU2_OSD1_BLK0_CFG_W0, fb0_cfg_w0); + osd_reg_write(VIU2_OSD1_BLK1_CFG_W0, fb0_cfg_w0); + osd_reg_write(VIU2_OSD1_BLK2_CFG_W0, fb0_cfg_w0); + osd_reg_write(VIU2_OSD1_BLK3_CFG_W0, fb0_cfg_w0); + osd_reg_write(VIU2_OSD1_BLK0_CFG_W0 + REG_OFFSET, fb1_cfg_w0); + osd_reg_write(VIU2_OSD1_BLK1_CFG_W0 + REG_OFFSET, fb1_cfg_w0); + osd_reg_write(VIU2_OSD1_BLK2_CFG_W0 + REG_OFFSET, fb1_cfg_w0); + osd_reg_write(VIU2_OSD1_BLK3_CFG_W0 + REG_OFFSET, fb1_cfg_w0); + } + + /* go through update list */ + walk_through_update_list(); + osd_ext_update_3d_mode(osd_ext_hw.mode_3d[OSD1].enable, + osd_ext_hw.mode_3d[OSD2].enable); + + if (!vsync_hit) { +#ifdef FIQ_VSYNC + fiq_bridge_pulse_trigger(&osd_ext_hw.fiq_handle_item); +#else + wait_ext_vsync_wakeup(); +#endif + } + +#ifndef FIQ_VSYNC + return IRQ_HANDLED; +#endif +} + +void osd_ext_wait_vsync_hw(void) +{ + vsync_hit = false; + + wait_event_interruptible_timeout(osd_ext_vsync_wq, vsync_hit, HZ); +} + +s32 osd_ext_wait_vsync_event(void) +{ + vsync_hit = false; + wait_event_interruptible_timeout(osd_ext_vsync_wq, vsync_hit, 1); + return 0; +} + +void osd_ext_set_gbl_alpha_hw(u32 index, u32 gbl_alpha) +{ + if (osd_ext_hw.gbl_alpha[index] != gbl_alpha) { + + osd_ext_hw.gbl_alpha[index] = gbl_alpha; + add_to_update_list(index, OSD_GBL_ALPHA); + + osd_ext_wait_vsync_hw(); + } +} + +u32 osd_ext_get_gbl_alpha_hw(u32 index) +{ + return osd_ext_hw.gbl_alpha[index]; +} + +void osd_ext_set_color_key_hw(u32 index, u32 color_index, u32 colorkey) +{ + u8 r = 0, g = 0, b = 0, a = (colorkey & 0xff000000) >> 24; + u32 data32; + + colorkey &= 0x00ffffff; + + switch (color_index) { + case COLOR_INDEX_16_655: + r = (colorkey >> 10 & 0x3f) << 2; + g = (colorkey >> 5 & 0x1f) << 3; + b = (colorkey & 0x1f) << 3; + break; + + case COLOR_INDEX_16_844: + r = colorkey >> 8 & 0xff; + g = (colorkey >> 4 & 0xf) << 4; + b = (colorkey & 0xf) << 4; + break; + + case COLOR_INDEX_16_565: + r = (colorkey >> 11 & 0x1f) << 3; + g = (colorkey >> 5 & 0x3f) << 2; + b = (colorkey & 0x1f) << 3; + break; + + case COLOR_INDEX_24_888_B: + b = colorkey >> 16 & 0xff; + g = colorkey >> 8 & 0xff; + r = colorkey & 0xff; + break; + + case COLOR_INDEX_24_RGB: + case COLOR_INDEX_YUV_422: + r = colorkey >> 16 & 0xff; + g = colorkey >> 8 & 0xff; + b = colorkey & 0xff; + break; + } + + data32 = r << 24 | g << 16 | b << 8 | a; + + if (osd_ext_hw.color_key[index] != data32) { + osd_ext_hw.color_key[index] = data32; + osd_log_info("bpp:%d--r:0x%x g:0x%x b:0x%x ,a:0x%x\n", + color_index, r, g, b, a); + add_to_update_list(index, OSD_COLOR_KEY); + + osd_ext_wait_vsync_hw(); + } +} + +void osd_ext_srckey_enable_hw(u32 index, u8 enable) +{ + if (enable != osd_ext_hw.color_key_enable[index]) { + osd_ext_hw.color_key_enable[index] = enable; + add_to_update_list(index, OSD_COLOR_KEY_ENABLE); + + osd_ext_wait_vsync_hw(); + } + +} + +void osd_ext_update_disp_axis_hw( + u32 display_h_start, + u32 display_h_end, + u32 display_v_start, + u32 display_v_end, + u32 xoffset, + u32 yoffset, + u32 mode_change, + u32 index) +{ + struct pandata_s disp_data; + struct pandata_s pan_data; + + if (osd_ext_hw.color_info[index] == NULL) + return; + + if (mode_change) /* modify pandata . */ + add_to_update_list(index, OSD_COLOR_MODE); + + disp_data.x_start = display_h_start; + disp_data.y_start = display_v_start; + disp_data.x_end = display_h_end; + disp_data.y_end = display_v_end; + + pan_data.x_start = xoffset; + pan_data.x_end = xoffset + (display_h_end - display_h_start); + pan_data.y_start = yoffset; + pan_data.y_end = yoffset + (display_v_end - display_v_start); + + /* if output mode change then reset pan ofFfset. */ + memcpy(&osd_ext_hw.pandata[index], &pan_data, + sizeof(struct pandata_s)); + memcpy(&osd_ext_hw.dispdata[index], &disp_data, + sizeof(struct pandata_s)); + add_to_update_list(index, DISP_GEOMETRY); + osd_ext_wait_vsync_hw(); +} + +void osd_ext_setup(struct osd_ctl_s *osd_ext_ctl, + u32 xoffset, + u32 yoffset, + u32 xres, + u32 yres, + u32 xres_virtual, + u32 yres_virtual, + u32 disp_start_x, + u32 disp_start_y, + u32 disp_end_x, + u32 disp_end_y, + u32 fbmem, + const struct color_bit_define_s *color, + int index) +{ + u32 w = (color->bpp * xres_virtual + 7) >> 3; + struct pandata_s disp_data; + struct pandata_s pan_data; + + pan_data.x_start = xoffset; + pan_data.y_start = yoffset; + + disp_data.x_start = disp_start_x; + disp_data.y_start = disp_start_y; + + if (likely(osd_ext_hw.free_scale_enable[OSD1] && index == OSD1)) { + pan_data.x_end = xoffset + (disp_end_x - disp_start_x); + pan_data.y_end = yoffset + (disp_end_y - disp_start_y); + disp_data.x_end = disp_end_x; + disp_data.y_end = disp_end_y; + } else { + pan_data.x_end = xoffset + (disp_end_x - disp_start_x); + pan_data.y_end = yoffset + (disp_end_y - disp_start_y); + disp_data.x_end = disp_end_x; + disp_data.y_end = disp_end_y; + } + + if (osd_ext_hw.fb_gem[index].addr != fbmem || + osd_ext_hw.fb_gem[index].width != w + || osd_ext_hw.fb_gem[index].height != yres_virtual) { + osd_ext_hw.fb_gem[index].addr = fbmem; + osd_ext_hw.fb_gem[index].width = w; + osd_ext_hw.fb_gem[index].height = yres_virtual; + +#ifdef CONFIG_AMLOGIC_MEDIA_CANVAS + if (fbmem == 0) { + canvas_config(osd_ext_hw.fb_gem[index].canvas_idx, + osd_hw->fb_gem[index].addr, + osd_ext_hw.fb_gem[index].width, + osd_ext_hw.fb_gem[index].height, + CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR); + } else { + canvas_config(osd_ext_hw.fb_gem[index].canvas_idx, + osd_ext_hw.fb_gem[index].addr, + osd_ext_hw.fb_gem[index].width, + osd_ext_hw.fb_gem[index].height, + CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR); + } +#endif + } + + if (color != osd_ext_hw.color_info[index]) { + osd_ext_hw.color_info[index] = color; + add_to_update_list(index, OSD_COLOR_MODE); + } + + /* osd blank only control by /sys/class/graphcis/fbx/blank */ +#if 0 + if (osd_ext_hw.enable[index] == DISABLE) { + osd_ext_hw.enable[index] = ENABLE; + add_to_update_list(index, OSD_ENABLE); + } +#endif + if (memcmp(&pan_data, &osd_ext_hw.pandata[index], + sizeof(struct pandata_s)) != 0 || + memcmp(&disp_data, &osd_ext_hw.dispdata[index], + sizeof(struct pandata_s)) != 0) { + memcpy(&osd_ext_hw.pandata[index], &pan_data, + sizeof(struct pandata_s)); + memcpy(&osd_ext_hw.dispdata[index], &disp_data, + sizeof(struct pandata_s)); + add_to_update_list(index, DISP_GEOMETRY); + } + + osd_ext_wait_vsync_hw(); +} + +void osd_ext_setpal_hw(u32 index, + unsigned int regno, + unsigned int red, + unsigned int green, + unsigned int blue, + unsigned int transp) +{ + + if (regno < 256) { + u32 pal; + + pal = ((red & 0xff) << 24) | + ((green & 0xff) << 16) | + ((blue & 0xff) << 8) | + (transp & 0xff); + osd_reg_write(VIU2_OSD1_COLOR_ADDR + REG_OFFSET * index, regno); + osd_reg_write(VIU2_OSD1_COLOR + REG_OFFSET * index, pal); + } +} + +u32 osd_ext_get_order_hw(u32 index) +{ + return osd_ext_hw.order & 0x3; +} + +void osd_ext_set_order_hw(u32 index, u32 order) +{ + if ((order != OSD_ORDER_01) && (order != OSD_ORDER_10)) + return; + + osd_ext_hw.order = order; + add_to_update_list(index, OSD_CHANGE_ORDER); + osd_ext_wait_vsync_hw(); +} + +void osd_ext_enable_hw(u32 index, int enable) +{ + osd_ext_hw.enable[index] = enable; + add_to_update_list(index, OSD_ENABLE); + + osd_ext_wait_vsync_hw(); +} + +/* vpu free scale mode */ +static void osd_ext_set_free_scale_enable_mode0(u32 index, u32 enable) +{ + static struct pandata_s save_disp_data = { 0, 0, 0, 0 }; +#ifdef CONFIG_AMLOGIC_VIDEO +#ifdef CONFIG_POST_PROCESS_MANAGER + int mode_changed = 0; + + if ((index == OSD1) && + (osd_ext_hw.free_scale_enable[index] != enable)) + mode_changed = 1; +#endif +#endif + osd_log_info("osd%d free scale %s\n", + index, enable ? "ENABLE" : "DISABLE"); + osd_ext_hw.free_scale_enable[index] = enable; + + if (index == OSD1) { + if (enable) { + osd_ext_vf_need_update = true; +#ifdef CONFIG_AMLOGIC_VIDEO + if ((osd_ext_hw.free_src_data[OSD1].x_end > 0) + && (osd_ext_hw.free_src_data[OSD1].x_end > 0)) { + vf.width = + osd_ext_hw.free_src_data[index].x_end - + osd_ext_hw.free_src_data[index].x_start + + 1; + vf.height = + osd_ext_hw.free_src_data[index].y_end - + osd_ext_hw.free_src_data[index].y_start + + 1; + } else { + vf.width = osd_ext_hw.free_scale_width[OSD1]; + vf.height = osd_ext_hw.free_scale_height[OSD1]; + } + + vf.type = (VIDTYPE_NO_VIDEO_ENABLE | + VIDTYPE_PROGRESSIVE | + VIDTYPE_VIU_FIELD | + VIDTYPE_VSCALE_DISABLE); + vf.ratio_control = DISP_RATIO_FORCECONFIG | + DISP_RATIO_NO_KEEPRATIO; + + if (osd_ext_vf_prov_init == 0) { + vf_provider_init(&osd_ext_vf_prov, + PROVIDER_NAME, + &osd_ext_vf_provider, + NULL); + osd_ext_vf_prov_init = 1; + } + + vf_reg_provider(&osd_ext_vf_prov); + memcpy(&save_disp_data, &osd_ext_hw.dispdata[OSD1], + sizeof(struct pandata_s)); + + g_vf_visual_width = vf.width - 1 - + osd_hw->dispdata[OSD1].x_start; + g_vf_width = vf.width - 1; + g_vf_height = vf.height - 1; + osd_ext_hw.dispdata[OSD1].x_end = + osd_ext_hw.dispdata[OSD1].x_start + + vf.width - 1; + osd_ext_hw.dispdata[OSD1].y_end = + osd_ext_hw.dispdata[OSD1].y_start + + vf.height - 1; +#endif + add_to_update_list(OSD1, DISP_GEOMETRY); + add_to_update_list(OSD1, OSD_COLOR_MODE); + } else { + osd_ext_vf_need_update = false; + + if (save_disp_data.x_end <= save_disp_data.x_start || + save_disp_data.y_end <= save_disp_data.y_start) + return; + + memcpy(&osd_ext_hw.dispdata[OSD1], &save_disp_data, + sizeof(struct pandata_s)); + + add_to_update_list(OSD1, DISP_GEOMETRY); + add_to_update_list(OSD1, OSD_COLOR_MODE); +#ifdef CONFIG_AMLOGIC_VIDEO + vf_unreg_provider(&osd_ext_vf_prov); +#endif + + } + } else { + add_to_update_list(OSD2, DISP_GEOMETRY); + add_to_update_list(OSD2, OSD_COLOR_MODE); + } + + osd_ext_enable_hw(osd_ext_hw.enable[index], index); +#ifdef CONFIG_AMLOGIC_VIDEO +#ifdef CONFIG_POST_PROCESS_MANAGER + if (mode_changed) { + /* extern void vf_ppmgr_reset(int type); */ + vf_ppmgr_reset(1); + } +#endif +#endif +} + +/* osd free scale mode */ +static void osd_ext_set_free_scale_enable_mode1(u32 index, u32 enable) +{ + unsigned int h_enable = 0; + unsigned int v_enable = 0; + + h_enable = (enable & 0xffff0000 ? 1 : 0); + v_enable = (enable & 0xffff ? 1 : 0); + osd_ext_hw.free_scale[index].h_enable = h_enable; + osd_ext_hw.free_scale[index].v_enable = v_enable; + + if (h_enable || v_enable) + osd_ext_hw.free_scale_enable[index] = 1; + else if (!h_enable && !v_enable) + osd_ext_hw.free_scale_enable[index] = 0; + + if (index == OSD1) { + if (osd_ext_hw.free_scale_enable[index]) { + add_to_update_list(index, OSD_COLOR_MODE); + add_to_update_list(index, OSD_FREESCALE_COEF); + add_to_update_list(index, DISP_GEOMETRY); + add_to_update_list(index, DISP_FREESCALE_ENABLE); + } else { + add_to_update_list(index, OSD_COLOR_MODE); + add_to_update_list(index, DISP_GEOMETRY); + add_to_update_list(index, DISP_FREESCALE_ENABLE); + } + } else { + add_to_update_list(OSD2, DISP_GEOMETRY); + add_to_update_list(OSD2, OSD_COLOR_MODE); + } + osd_ext_enable_hw(osd_ext_hw.enable[index], index); +} + +void osd_ext_set_free_scale_enable_hw(u32 index, u32 enable) +{ + if (osd_ext_hw.free_scale_mode[index]) + osd_ext_set_free_scale_enable_mode1(index, enable); + else + osd_ext_set_free_scale_enable_mode0(index, enable); +} + +void osd_ext_get_free_scale_enable_hw(u32 index, u32 *free_scale_enable) +{ + *free_scale_enable = osd_ext_hw.free_scale_enable[index]; +} + +void osd_ext_get_free_scale_width_hw(u32 index, u32 *free_scale_width) +{ + *free_scale_width = osd_ext_hw.free_src_data[index].x_end - + osd_ext_hw.free_src_data[index].x_start + 1; +} + +void osd_ext_get_free_scale_height_hw(u32 index, u32 *free_scale_height) +{ + *free_scale_height = osd_ext_hw.free_src_data[index].y_end - + osd_ext_hw.free_src_data[index].y_start + 1; + +} + +void osd_ext_get_free_scale_axis_hw(u32 index, s32 *x0, s32 *y0, s32 *x1, + s32 *y1) +{ + *x0 = osd_ext_hw.free_src_data[index].x_start; + *y0 = osd_ext_hw.free_src_data[index].y_start; + *x1 = osd_ext_hw.free_src_data[index].x_end; + *y1 = osd_ext_hw.free_src_data[index].y_end; +} + +void osd_ext_set_free_scale_axis_hw(u32 index, s32 x0, s32 y0, s32 x1, s32 y1) +{ + osd_ext_hw.free_src_data[index].x_start = x0; + osd_ext_hw.free_src_data[index].y_start = y0; + osd_ext_hw.free_src_data[index].x_end = x1; + osd_ext_hw.free_src_data[index].y_end = y1; +} + +void osd_ext_get_scale_axis_hw(u32 index, s32 *x0, s32 *y0, s32 *x1, + s32 *y1) +{ + *x0 = osd_ext_hw.scaledata[index].x_start; + *x1 = osd_ext_hw.scaledata[index].x_end; + *y0 = osd_ext_hw.scaledata[index].y_start; + *y1 = osd_ext_hw.scaledata[index].y_end; +} + +void osd_ext_set_scale_axis_hw(u32 index, s32 x0, s32 y0, s32 x1, s32 y1) +{ + osd_ext_hw.scaledata[index].x_start = x0; + osd_ext_hw.scaledata[index].x_end = x1; + osd_ext_hw.scaledata[index].y_start = y0; + osd_ext_hw.scaledata[index].y_end = y1; +} + +void osd_ext_set_free_scale_mode_hw(u32 index, u32 freescale_mode) +{ + osd_ext_hw.free_scale_mode[index] = freescale_mode; +} + +void osd_ext_get_free_scale_mode_hw(u32 index, u32 *freescale_mode) +{ + *freescale_mode = osd_ext_hw.free_scale_mode[index]; +} + +void osd_ext_get_window_axis_hw(u32 index, s32 *x0, s32 *y0, s32 *x1, s32 *y1) +{ + *x0 = osd_ext_hw.free_dst_data[index].x_start; + *x1 = osd_ext_hw.free_dst_data[index].x_end; + *y0 = osd_ext_hw.free_dst_data[index].y_start; + *y1 = osd_ext_hw.free_dst_data[index].y_end; +} + +void osd_ext_set_window_axis_hw(u32 index, s32 x0, s32 y0, s32 x1, s32 y1) +{ + osd_ext_hw.free_dst_data[index].x_start = x0; + osd_ext_hw.free_dst_data[index].x_end = x1; + osd_ext_hw.free_dst_data[index].y_start = y0; + osd_ext_hw.free_dst_data[index].y_end = y1; +} + +void osd_ext_set_debug_hw(u32 index, u32 debug_flag) +{ + u32 reg = 0; + u32 offset = 0; + struct pandata_s *pdata = NULL; + + if (debug_flag == 1) { + pdata = &osd_ext_hw.pandata[index]; + osd_log_info("pandata[%d]:\n", index); + osd_log_info("\tx_start: 0x%08x, x_end: 0x%08x\n", + pdata->x_start, pdata->x_end); + osd_log_info("\ty_start: 0x%08x, y_end: 0x%08x\n", + pdata->y_start, pdata->y_end); + + pdata = &osd_ext_hw.dispdata[index]; + osd_log_info("dispdata[%d]\n", index); + osd_log_info("\tx_start: 0x%08x, x_end: 0x%08x\n", + pdata->x_start, pdata->x_end); + osd_log_info("\ty_start: 0x%08x, y_end: 0x%08x\n", + pdata->y_start, pdata->y_end); + + pdata = &osd_ext_hw.scaledata[index]; + osd_log_info("scaledata[%d]\n", index); + osd_log_info("\tx_start: 0x%08x, x_end: 0x%08x\n", + pdata->x_start, pdata->x_end); + osd_log_info("\ty_start: 0x%08x, y_end: 0x%08x\n", + pdata->y_start, pdata->y_end); + } else if (debug_flag == 2) { + reg = VPU_VIU_VENC_MUX_CTRL; + osd_log_info("reg[0x%x]: 0x%08x\n", reg, osd_reg_read(reg)); + reg = VPP_MISC; + osd_log_info("reg[0x%x]: 0x%08x\n", reg, osd_reg_read(reg)); + reg = VIU_OSD1_CTRL_STAT; + osd_log_info("reg[0x%x]: 0x%08x\n", reg, osd_reg_read(reg)); + if (index == 1) + offset = REG_OFFSET; + reg = offset + VIU2_OSD1_BLK0_CFG_W0; + osd_log_info("reg[0x%x]: 0x%08x\n", reg, osd_reg_read(reg)); + reg = offset + VIU2_OSD1_BLK0_CFG_W1; + osd_log_info("reg[0x%x]: 0x%08x\n", reg, osd_reg_read(reg)); + reg = offset + VIU2_OSD1_BLK0_CFG_W2; + osd_log_info("reg[0x%x]: 0x%08x\n", reg, osd_reg_read(reg)); + reg = offset + VIU2_OSD1_BLK0_CFG_W3; + osd_log_info("reg[0x%x]: 0x%08x\n", reg, osd_reg_read(reg)); + reg = offset + VIU2_OSD1_BLK0_CFG_W4; + osd_log_info("reg[0x%x]: 0x%08x\n", reg, osd_reg_read(reg)); + } else { + osd_log_err("argument error\n"); + } +} + +void osd_ext_get_block_windows_hw(u32 index, u32 *windows) +{ + /* memcpy(windows, osd_ext_hw.block_windows[index], + * sizeof(osd_ext_hw.block_windows[index])); + */ +} + +void osd_ext_set_block_windows_hw(u32 index, u32 *windows) +{ + /* memcpy(osd_ext_hw.block_windows[index], windows, + * sizeof(osd_ext_hw.block_windows[index])); + * add_to_update_list(index, DISP_GEOMETRY); + * osd_ext_wait_vsync_hw(); + */ +} + +void osd_ext_get_block_mode_hw(u32 index, u32 *mode) +{ + *mode = osd_ext_hw.block_mode[index]; +} + +void osd_ext_set_block_mode_hw(u32 index, u32 mode) +{ + osd_ext_hw.block_mode[index] = mode; + add_to_update_list(index, DISP_GEOMETRY); + osd_ext_wait_vsync_hw(); +} + +void osd_ext_set_2x_scale_hw(u32 index, u16 h_scale_enable, u16 v_scale_enable) +{ + osd_log_info("osd[%d] set scale, h_scale: %s, v_scale: %s\n", + index, h_scale_enable ? "ENABLE" : "DISABLE", + v_scale_enable ? "ENABLE" : "DISABLE"); + osd_log_info("osd[%d].scaledata: %d %d %d %d\n", + index, + osd_ext_hw.scaledata[index].x_start, + osd_ext_hw.scaledata[index].x_end, + osd_ext_hw.scaledata[index].y_start, + osd_ext_hw.scaledata[index].y_end); + osd_log_info("osd[%d].pandata: %d %d %d %d\n", + index, + osd_ext_hw.pandata[index].x_start, + osd_ext_hw.pandata[index].x_end, + osd_ext_hw.pandata[index].y_start, + osd_ext_hw.pandata[index].y_end); + + osd_ext_hw.scale[index].h_enable = h_scale_enable; + osd_ext_hw.scale[index].v_enable = v_scale_enable; + add_to_update_list(index, DISP_SCALE_ENABLE); + add_to_update_list(index, DISP_GEOMETRY); + + osd_ext_wait_vsync_hw(); +} + +void osd_ext_enable_3d_mode_hw(int index, int enable) +{ + spin_lock_irqsave(&osd_ext_lock, lock_flags); + osd_ext_hw.mode_3d[index].enable = enable; + spin_unlock_irqrestore(&osd_ext_lock, lock_flags); + + if (enable) { + /* when disable 3d mode ,we should return to stardard state. */ + osd_ext_hw.mode_3d[index].left_right = OSD_LEFT; + osd_ext_hw.mode_3d[index].l_start = + osd_ext_hw.pandata[index].x_start; + osd_ext_hw.mode_3d[index].l_end = + (osd_ext_hw.pandata[index].x_end + + osd_ext_hw.pandata[index].x_start) >> 1; + osd_ext_hw.mode_3d[index].r_start = + osd_ext_hw.mode_3d[index].l_end + 1; + osd_ext_hw.mode_3d[index].r_end = + osd_ext_hw.pandata[index].x_end; + osd_ext_hw.mode_3d[index].origin_scale.h_enable = + osd_ext_hw.scale[index].h_enable; + osd_ext_hw.mode_3d[index].origin_scale.v_enable = + osd_ext_hw.scale[index].v_enable; + osd_ext_set_2x_scale_hw(index, 1, 0); + } else { + osd_ext_set_2x_scale_hw(index, + osd_ext_hw.mode_3d[index].origin_scale.h_enable, + osd_ext_hw.mode_3d[index].origin_scale.v_enable); + } +} + +#ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD_SYNC_FENCE +void osd_ext_pan_display_fence(struct osd_fence_map_s *fence_map) +{ + s32 ret = 1; + long diff_x, diff_y; + u32 index = fence_map->fb_index; + u32 xoffset = fence_map->xoffset; + u32 yoffset = fence_map->yoffset; + + if (index >= 2) + return; + + if (ext_timeline_created) { /* out fence created success. */ + ret = osd_ext_wait_buf_ready(fence_map); + + if (ret < 0) + osd_log_dbg("fence wait ret %d\n", ret); + } + + if (ret) { + if (xoffset != osd_ext_hw.pandata[index].x_start || + yoffset != osd_ext_hw.pandata[index].y_start) { + diff_x = xoffset - osd_ext_hw.pandata[index].x_start; + diff_y = yoffset - osd_ext_hw.pandata[index].y_start; + + osd_ext_hw.pandata[index].x_start += diff_x; + osd_ext_hw.pandata[index].x_end += diff_x; + osd_ext_hw.pandata[index].y_start += diff_y; + osd_ext_hw.pandata[index].y_end += diff_y; + add_to_update_list(index, DISP_GEOMETRY); + osd_ext_wait_vsync_hw(); + } + } + + if (ext_timeline_created) { + if (ret) + sw_sync_timeline_inc(ext_timeline, 1); + else + osd_log_err("------NOT signal out_fence ERROR\n"); + } + + osd_log_dbg("offset[%d-%d]x[%d-%d]y[%d-%d]\n", + xoffset, yoffset, osd_ext_hw.pandata[index].x_start, + osd_ext_hw.pandata[index].x_end, + osd_ext_hw.pandata[index].y_start, + osd_ext_hw.pandata[index].y_end); +} +#endif + +void osd_ext_pan_display_hw(u32 index, unsigned int xoffset, + unsigned int yoffset) +{ + long diff_x, diff_y; + +#if defined(CONFIG_AMLOGIC_MEDIA_FB_OSD2_CURSOR) + if (index >= 1) +#else + if (index >= 2) +#endif + return; + + if (xoffset != osd_ext_hw.pandata[index].x_start || + yoffset != osd_ext_hw.pandata[index].y_start) { + diff_x = xoffset - osd_ext_hw.pandata[index].x_start; + diff_y = yoffset - osd_ext_hw.pandata[index].y_start; + + osd_ext_hw.pandata[index].x_start += diff_x; + osd_ext_hw.pandata[index].x_end += diff_x; + osd_ext_hw.pandata[index].y_start += diff_y; + osd_ext_hw.pandata[index].y_end += diff_y; + add_to_update_list(index, DISP_GEOMETRY); + + osd_ext_wait_vsync_hw(); + + osd_log_info("offset[%d-%d]x[%d-%d]y[%d-%d]\n", + xoffset, yoffset, + osd_ext_hw.pandata[index].x_start, + osd_ext_hw.pandata[index].x_end, + osd_ext_hw.pandata[index].y_start, + osd_ext_hw.pandata[index].y_end); + } +} + +static void osd1_update_disp_scale_enable(void) +{ + if (osd_ext_hw.scale[OSD1].h_enable) + osd_reg_set_mask(VIU2_OSD1_BLK0_CFG_W0, 3 << 12); + else + osd_reg_clr_mask(VIU2_OSD1_BLK0_CFG_W0, 3 << 12); + + if (osd_ext_hw.scan_mode != SCAN_MODE_INTERLACE) { + if (osd_ext_hw.scale[OSD1].v_enable) + osd_reg_set_mask(VIU2_OSD1_BLK0_CFG_W0, 1 << 14); + else + osd_reg_clr_mask(VIU2_OSD1_BLK0_CFG_W0, 1 << 14); + } +} + +static void osd2_update_disp_scale_enable(void) +{ + if (osd_ext_hw.scale[OSD2].h_enable) { +#if defined(CONFIG_AMLOGIC_MEDIA_FB_OSD2_CURSOR) + osd_reg_clr_mask(VIU2_OSD2_BLK0_CFG_W0, 3 << 12); +#else + osd_reg_set_mask(VIU2_OSD2_BLK0_CFG_W0, 3 << 12); +#endif + } else + osd_reg_clr_mask(VIU2_OSD2_BLK0_CFG_W0, 3 << 12); + + if (osd_ext_hw.scan_mode != SCAN_MODE_INTERLACE) { + if (osd_ext_hw.scale[OSD2].v_enable) { +#if defined(CONFIG_AMLOGIC_MEDIA_FB_OSD2_CURSOR) + osd_reg_clr_mask(VIU2_OSD2_BLK0_CFG_W0, 1 << 14); +#else + osd_reg_set_mask(VIU2_OSD2_BLK0_CFG_W0, 1 << 14); +#endif + } else + osd_reg_clr_mask(VIU2_OSD2_BLK0_CFG_W0, 1 << 14); + } + +} + +static void osd1_update_disp_freescale_enable(void) +{ + int hf_phase_step, vf_phase_step; + int src_w, src_h, dst_w, dst_h; + int vsc_ini_rcv_num, vsc_ini_rpt_p0_num; + int hsc_ini_rcv_num, hsc_ini_rpt_p0_num; + + int hf_bank_len = 4; + int vf_bank_len = 4; + + hsc_ini_rcv_num = hf_bank_len; + vsc_ini_rcv_num = vf_bank_len; + hsc_ini_rpt_p0_num = (hf_bank_len / 2 - 1) > 0 ? + (hf_bank_len / 2 - 1) : 0; + vsc_ini_rpt_p0_num = (vf_bank_len / 2 - 1) > 0 ? + (vf_bank_len / 2 - 1) : 0; + + src_w = osd_ext_hw.free_src_data[OSD1].x_end - + osd_ext_hw.free_src_data[OSD1].x_start + 1; + src_h = osd_ext_hw.free_src_data[OSD1].y_end - + osd_ext_hw.free_src_data[OSD1].y_start + 1; + dst_w = osd_ext_hw.free_dst_data[OSD1].x_end - + osd_ext_hw.free_dst_data[OSD1].x_start + 1; + hf_phase_step = ((src_w + 1) << 18) / dst_w; + hf_phase_step = (hf_phase_step << 6); + + dst_h = osd_ext_hw.free_dst_data[OSD1].y_end - + osd_ext_hw.free_dst_data[OSD1].y_start + 1; + vf_phase_step = ((src_h + 1) << 20) / + dst_h; + vf_phase_step = (vf_phase_step << 4); + + osd_reg_set_bits(VPP2_OSD_SC_DUMMY_DATA, 0x00808000, 0, 32); + + if (osd_ext_hw.free_scale_enable[OSD1]) { + osd_reg_set_bits(VPP2_OSD_SC_CTRL0, 1, 3, 1); + osd_reg_set_bits(VPP2_OSD_SC_CTRL0, OSD1, 0, 2); + osd_reg_set_bits(VPP2_OSD_SC_CTRL0, 0, 4, 8); + } else + osd_reg_clr_mask(VPP2_OSD_SC_CTRL0, 1 << 3); + + if (osd_ext_hw.free_scale_enable[OSD1]) { + osd_reg_set_bits(VPP2_OSD_SCI_WH_M1, + src_w, 16, 13); + osd_reg_set_bits(VPP2_OSD_SCI_WH_M1, + src_h, 0, 13); + + osd_reg_set_bits(VPP2_OSD_SCO_H_START_END, + osd_ext_hw.free_dst_data[OSD1].x_start, 16, 12); + osd_reg_set_bits(VPP2_OSD_SCO_H_START_END, + osd_ext_hw.free_dst_data[OSD1].x_end, 0, 12); + + osd_reg_set_bits(VPP2_OSD_SCO_V_START_END, + osd_ext_hw.free_dst_data[OSD1].y_start, + 16, 12); + osd_reg_set_bits(VPP2_OSD_SCO_V_START_END, + osd_ext_hw.free_dst_data[OSD1].y_end, 0, 12); + } + + if (osd_ext_hw.free_scale[OSD1].v_enable) { + osd_reg_set_bits(VPP2_OSD_VSC_CTRL0, vf_bank_len, 0, 3); + osd_reg_set_bits(VPP2_OSD_VSC_CTRL0, + vsc_ini_rcv_num, 3, 3); + osd_reg_set_bits(VPP2_OSD_VSC_CTRL0, + vsc_ini_rpt_p0_num, 8, 2); + osd_reg_set_bits(VPP2_OSD_VSC_CTRL0, 1, 24, 1); + } else + osd_reg_clr_mask(VPP2_OSD_VSC_CTRL0, 1 << 24); + + if (osd_ext_hw.free_scale[OSD1].h_enable) { + osd_reg_set_bits(VPP2_OSD_HSC_CTRL0, hf_bank_len, 0, 3); + osd_reg_set_bits(VPP2_OSD_HSC_CTRL0, + hsc_ini_rcv_num, 3, 3); + osd_reg_set_bits(VPP2_OSD_HSC_CTRL0, + hsc_ini_rpt_p0_num, 8, 2); + osd_reg_set_bits(VPP2_OSD_HSC_CTRL0, 1, 22, 1); + } else + osd_reg_clr_mask(VPP2_OSD_HSC_CTRL0, 1 << 22); + + if (osd_ext_hw.free_scale_enable[OSD1]) { + osd_reg_set_bits(VPP2_OSD_HSC_PHASE_STEP, + hf_phase_step, 0, 28); + osd_reg_set_bits(VPP2_OSD_HSC_INI_PHASE, 0, 0, 16); + osd_reg_set_bits(VPP2_OSD_VSC_PHASE_STEP, + vf_phase_step, 0, 28); + osd_reg_set_bits(VPP2_OSD_VSC_INI_PHASE, 0, 0, 16); + } + + remove_from_update_list(OSD1, DISP_FREESCALE_ENABLE); +} + +static void osd1_update_coef(void) +{ + int hf_coef_idx = 0; + int vf_coef_idx = 0; + int *hf_coef, *vf_coef; + int i = 0; + int hf_coef_wren = 1; + int vf_coef_wren = 1; + + if (vf_coef_idx == 0) + vf_coef = filt_coef0; + else if (vf_coef_idx == 1) + vf_coef = filt_coef1; + else if (vf_coef_idx == 2) + vf_coef = filt_coef2; + else + vf_coef = filt_coef0; + + if (hf_coef_idx == 0) + hf_coef = filt_coef0; + else if (hf_coef_idx == 1) + hf_coef = filt_coef1; + else if (hf_coef_idx == 2) + hf_coef = filt_coef2; + else + hf_coef = filt_coef0; + + + if (vf_coef_wren) { + osd_reg_set_bits(VPP2_OSD_SCALE_COEF_IDX, + 0x0000, 0, 9); + for (i = 0; i < 33; i++) + osd_reg_write(VPP2_OSD_SCALE_COEF, + vf_coef[i]); + } + if (hf_coef_wren) { + osd_reg_set_bits(VPP2_OSD_SCALE_COEF_IDX, + 0x0100, 0, 9); + + for (i = 0; i < 33; i++) + osd_reg_write(VPP2_OSD_SCALE_COEF, hf_coef[i]); + } + remove_from_update_list(OSD1, OSD_FREESCALE_COEF); +} + +static void osd2_update_disp_freescale_enable(void) +{ + int hf_phase_step, vf_phase_step; + int src_w, src_h, dst_w, dst_h; + int vsc_ini_rcv_num, vsc_ini_rpt_p0_num; + int hsc_ini_rcv_num, hsc_ini_rpt_p0_num; + + int hf_bank_len = 4; + int vf_bank_len = 4; + + hsc_ini_rcv_num = hf_bank_len; + vsc_ini_rcv_num = vf_bank_len; + hsc_ini_rpt_p0_num = (hf_bank_len / 2 - 1) > 0 ? + (hf_bank_len / 2 - 1) : 0; + vsc_ini_rpt_p0_num = (vf_bank_len / 2 - 1) > 0 ? + (vf_bank_len / 2 - 1) : 0; + + src_w = osd_ext_hw.free_src_data[OSD2].x_end - + osd_ext_hw.free_src_data[OSD2].x_start + 1; + src_h = osd_ext_hw.free_src_data[OSD2].y_end - + osd_ext_hw.free_src_data[OSD2].y_start + 1; + dst_w = osd_ext_hw.free_dst_data[OSD2].x_end - + osd_ext_hw.free_dst_data[OSD2].x_start + 1; + hf_phase_step = + ((src_w + 1) << 18) / dst_w; + hf_phase_step = (hf_phase_step << 6); + + dst_h = osd_ext_hw.free_dst_data[OSD2].y_end - + osd_ext_hw.free_dst_data[OSD2].y_start + 1; + vf_phase_step = + ((src_h + 1) << 20) / dst_h; + vf_phase_step = (vf_phase_step << 4); + + osd_reg_set_bits(VPP2_OSD_SC_DUMMY_DATA, 0x00808000, 0, 32); + + if (osd_ext_hw.free_scale_enable[OSD2]) { + osd_reg_set_bits(VPP2_OSD_SC_CTRL0, 1, 3, 1); + osd_reg_set_bits(VPP2_OSD_SC_CTRL0, OSD2, 0, 2); + osd_reg_set_bits(VPP2_OSD_SC_CTRL0, 0, 4, 8); + } else + osd_reg_clr_mask(VPP2_OSD_SC_CTRL0, 1 << 3); + + if (osd_ext_hw.free_scale_enable[OSD2]) { + osd_reg_set_bits(VPP2_OSD_SCI_WH_M1, + src_w, 16, 13); + osd_reg_set_bits(VPP2_OSD_SCI_WH_M1, + src_h, 0, 13); + + osd_reg_set_bits(VPP2_OSD_SCO_H_START_END, + osd_ext_hw.free_dst_data[OSD2].x_start, 16, 12); + osd_reg_set_bits(VPP2_OSD_SCO_H_START_END, + osd_ext_hw.free_dst_data[OSD2].x_end, 0, 12); + + osd_reg_set_bits(VPP2_OSD_SCO_V_START_END, + osd_ext_hw.free_dst_data[OSD2].y_start, 16, 12); + osd_reg_set_bits(VPP2_OSD_SCO_V_START_END, + osd_ext_hw.free_dst_data[OSD2].y_end, 0, 12); + } + + if (osd_ext_hw.free_scale[OSD2].h_enable) { + osd_reg_set_bits(VPP2_OSD_HSC_CTRL0, hf_bank_len, 0, 3); + osd_reg_set_bits(VPP2_OSD_HSC_CTRL0, + hsc_ini_rcv_num, 3, 3); + osd_reg_set_bits(VPP2_OSD_HSC_CTRL0, + hsc_ini_rpt_p0_num, 8, 2); + osd_reg_set_bits(VPP2_OSD_HSC_CTRL0, 1, 22, 1); + } else + osd_reg_clr_mask(VPP2_OSD_HSC_CTRL0, 1 << 22); + + if (osd_ext_hw.free_scale[OSD2].v_enable) { + osd_reg_set_bits(VPP2_OSD_VSC_CTRL0, vf_bank_len, 0, 3); + osd_reg_set_bits(VPP2_OSD_VSC_CTRL0, + vsc_ini_rcv_num, 3, 3); + osd_reg_set_bits(VPP2_OSD_VSC_CTRL0, + vsc_ini_rpt_p0_num, 8, 2); + osd_reg_set_bits(VPP2_OSD_VSC_CTRL0, 1, 24, 1); + } else + osd_reg_clr_mask(VPP2_OSD_VSC_CTRL0, 1 << 24); + + if (osd_ext_hw.free_scale_enable[OSD2]) { + osd_reg_set_bits(VPP2_OSD_HSC_PHASE_STEP, + hf_phase_step, 0, 28); + osd_reg_set_bits(VPP2_OSD_HSC_INI_PHASE, 0, 0, 16); + + osd_reg_set_bits(VPP2_OSD_VSC_PHASE_STEP, + vf_phase_step, 0, 28); + osd_reg_set_bits(VPP2_OSD_VSC_INI_PHASE, 0, 0, 16); + } + + remove_from_update_list(OSD2, DISP_FREESCALE_ENABLE); +} + +static void osd2_update_coef(void) +{ + int hf_coef_idx = 0; + int vf_coef_idx = 0; + int *hf_coef, *vf_coef; + int i = 0; + int hf_coef_wren = 1; + int vf_coef_wren = 1; + + if (vf_coef_idx == 0) + vf_coef = filt_coef0; + else if (vf_coef_idx == 1) + vf_coef = filt_coef1; + else if (vf_coef_idx == 2) + vf_coef = filt_coef2; + else + vf_coef = filt_coef0; + + if (hf_coef_idx == 0) + hf_coef = filt_coef0; + else if (hf_coef_idx == 1) + hf_coef = filt_coef1; + else if (hf_coef_idx == 2) + hf_coef = filt_coef2; + else + hf_coef = filt_coef0; + + if (vf_coef_wren) { + osd_reg_set_bits(VPP2_OSD_SCALE_COEF_IDX, 0x0000, 0, 9); + + for (i = 0; i < 33; i++) + osd_reg_write(VPP2_OSD_SCALE_COEF, vf_coef[i]); + } + + if (hf_coef_wren) { + osd_reg_set_bits(VPP2_OSD_SCALE_COEF_IDX, 0x0100, 0, 9); + + for (i = 0; i < 33; i++) + osd_reg_write(VPP2_OSD_SCALE_COEF, hf_coef[i]); + } + + remove_from_update_list(OSD2, OSD_FREESCALE_COEF); +} + +static void osd1_update_color_mode(void) +{ + u32 data32 = 0; + + if (osd_ext_hw.color_info[OSD1] != NULL) { + data32 = (osd_ext_hw.scan_mode == SCAN_MODE_INTERLACE) ? 2 : 0; + data32 |= osd_reg_read(VIU2_OSD1_BLK0_CFG_W0) & 0x30007040; + data32 |= osd_ext_hw.fb_gem[OSD1].canvas_idx << 16; + + /* if (!osd_ext_hw.rotate[OSD1].on_off) */ + data32 |= OSD_DATA_LITTLE_ENDIAN << 15; + data32 |= osd_ext_hw.color_info[OSD1]->hw_colormat << 2; + + if (osd_ext_hw.color_info[OSD1]->color_index < + COLOR_INDEX_YUV_422) + data32 |= 1 << 7; /* rgb enable */ + + /* osd_ext_blk_mode */ + data32 |= osd_ext_hw.color_info[OSD1]->hw_blkmode << 8; + osd_reg_write(VIU2_OSD1_BLK0_CFG_W0, data32); + osd_reg_write(VIU2_OSD1_BLK1_CFG_W0, data32); + osd_reg_write(VIU2_OSD1_BLK2_CFG_W0, data32); + osd_reg_write(VIU2_OSD1_BLK3_CFG_W0, data32); + } + + remove_from_update_list(OSD1, OSD_COLOR_MODE); +} + +static void osd2_update_color_mode(void) +{ + u32 data32 = 0; + + if (osd_ext_hw.color_info[OSD2] != NULL) { + data32 = (osd_ext_hw.scan_mode == SCAN_MODE_INTERLACE) ? 2 : 0; + data32 |= osd_reg_read(VIU2_OSD2_BLK0_CFG_W0) & 0x30007040; + data32 |= osd_ext_hw.fb_gem[OSD2].canvas_idx << 16; + + /* if (!osd_ext_hw.rotate[OSD1].on_off) */ + data32 |= OSD_DATA_LITTLE_ENDIAN << 15; + + data32 |= osd_ext_hw.color_info[OSD2]->hw_colormat << 2; + + if (osd_ext_hw.color_info[OSD2]->color_index < + COLOR_INDEX_YUV_422) + data32 |= 1 << 7; /* rgb enable */ + + /* osd_ext_blk_mode */ + data32 |= osd_ext_hw.color_info[OSD2]->hw_blkmode << 8; + osd_reg_write(VIU2_OSD2_BLK0_CFG_W0, data32); + } + remove_from_update_list(OSD2, OSD_COLOR_MODE); +} + +static void osd1_update_enable(void) +{ + if (osd_ext_hw.free_scale_mode[OSD1]) { + if (osd_ext_hw.enable[OSD1] == ENABLE) { + osd_reg_set_mask(VPP2_MISC, VPP_OSD1_POSTBLEND); + osd_reg_set_mask(VPP2_MISC, VPP_POSTBLEND_EN); + } else + osd_reg_clr_mask(VPP2_MISC, VPP_OSD1_POSTBLEND); + } else { + u32 video_enable = 0; + + video_enable |= osd_reg_read(VPP2_MISC) & VPP_VD1_PREBLEND; + + if (osd_ext_hw.enable[OSD1] == ENABLE) { + if (osd_ext_hw.free_scale_enable[OSD1]) { + osd_reg_clr_mask(VPP2_MISC, VPP_OSD1_POSTBLEND); + osd_reg_set_mask(VPP2_MISC, VPP_OSD1_PREBLEND); + osd_reg_set_mask(VPP2_MISC, VPP_VD1_POSTBLEND); + osd_reg_set_mask(VPP2_MISC, VPP_PREBLEND_EN); + } else { + osd_reg_clr_mask(VPP2_MISC, VPP_OSD1_PREBLEND); + + if (!video_enable) + osd_reg_clr_mask(VPP2_MISC, + VPP_VD1_POSTBLEND); + + osd_reg_set_mask(VPP2_MISC, VPP_OSD1_POSTBLEND); + } + + } else { + if (osd_ext_hw.free_scale_enable[OSD1]) + osd_reg_clr_mask(VPP2_MISC, VPP_OSD1_PREBLEND); + else + osd_reg_clr_mask(VPP2_MISC, VPP_OSD1_POSTBLEND); + } + } + + remove_from_update_list(OSD1, OSD_ENABLE); +} + +static void osd2_update_enable(void) +{ + if (osd_ext_hw.free_scale_mode[OSD2]) { + if (osd_ext_hw.enable[OSD1] == ENABLE) { + osd_reg_set_mask(VPP2_MISC, VPP_OSD2_POSTBLEND); + osd_reg_set_mask(VPP2_MISC, VPP_POSTBLEND_EN); + } else + osd_reg_clr_mask(VPP2_MISC, VPP_OSD2_POSTBLEND); + } else { + u32 video_enable = 0; + + video_enable |= osd_reg_read(VPP2_MISC) & VPP_VD1_PREBLEND; + + if (osd_ext_hw.enable[OSD2] == ENABLE) { + if (osd_ext_hw.free_scale_enable[OSD2]) { + osd_reg_clr_mask(VPP2_MISC, VPP_OSD2_POSTBLEND); + osd_reg_set_mask(VPP2_MISC, VPP_OSD2_PREBLEND); + osd_reg_set_mask(VPP2_MISC, VPP_VD1_POSTBLEND); + } else { + osd_reg_clr_mask(VPP2_MISC, VPP_OSD2_PREBLEND); + + if (!video_enable) + osd_reg_clr_mask(VPP2_MISC, + VPP_VD1_POSTBLEND); + + osd_reg_set_mask(VPP2_MISC, VPP_OSD2_POSTBLEND); + } + + } else { + if (osd_ext_hw.free_scale_enable[OSD2]) + osd_reg_clr_mask(VPP2_MISC, VPP_OSD2_PREBLEND); + else + osd_reg_clr_mask(VPP2_MISC, VPP_OSD2_POSTBLEND); + } + } + + remove_from_update_list(OSD2, OSD_ENABLE); +} + +static void osd1_update_disp_osd_rotate(void) +{ + remove_from_update_list(OSD1, DISP_OSD_ROTATE); +} + +static void osd2_update_disp_osd_rotate(void) +{ + remove_from_update_list(OSD2, DISP_OSD_ROTATE); +} + +static void osd1_update_color_key(void) +{ + osd_reg_write(VIU2_OSD1_TCOLOR_AG0, osd_ext_hw.color_key[OSD1]); + remove_from_update_list(OSD1, OSD_COLOR_KEY); +} + +static void osd2_update_color_key(void) +{ + osd_reg_write(VIU2_OSD2_TCOLOR_AG0, osd_ext_hw.color_key[OSD2]); + remove_from_update_list(OSD2, OSD_COLOR_KEY); +} + +static void osd1_update_color_key_enable(void) +{ + u32 data32; + + data32 = osd_reg_read(VIU2_OSD1_BLK0_CFG_W0); + data32 &= ~(1 << 6); + data32 |= (osd_ext_hw.color_key_enable[OSD1] << 6); + osd_reg_write(VIU2_OSD1_BLK0_CFG_W0, data32); + osd_reg_write(VIU2_OSD1_BLK1_CFG_W0, data32); + osd_reg_write(VIU2_OSD1_BLK2_CFG_W0, data32); + osd_reg_write(VIU2_OSD1_BLK3_CFG_W0, data32); + remove_from_update_list(OSD1, OSD_COLOR_KEY_ENABLE); +} + +static void osd2_update_color_key_enable(void) +{ + u32 data32; + + data32 = osd_reg_read(VIU2_OSD2_BLK0_CFG_W0); + data32 &= ~(1 << 6); + data32 |= (osd_ext_hw.color_key_enable[OSD2] << 6); + osd_reg_write(VIU2_OSD2_BLK0_CFG_W0, data32); + remove_from_update_list(OSD2, OSD_COLOR_KEY_ENABLE); +} + +static void osd1_update_gbl_alpha(void) +{ + u32 data32 = osd_reg_read(VIU2_OSD1_CTRL_STAT); + + data32 &= ~(0x1ff << 12); + data32 |= osd_ext_hw.gbl_alpha[OSD1] << 12; + osd_reg_write(VIU2_OSD1_CTRL_STAT, data32); + remove_from_update_list(OSD1, OSD_GBL_ALPHA); +} + +static void osd2_update_gbl_alpha(void) +{ + u32 data32 = osd_reg_read(VIU2_OSD2_CTRL_STAT); + + data32 &= ~(0x1ff << 12); + data32 |= osd_ext_hw.gbl_alpha[OSD2] << 12; + osd_reg_write(VIU2_OSD2_CTRL_STAT, data32); + remove_from_update_list(OSD2, OSD_GBL_ALPHA); +} + +static void osd2_update_order(void) +{ + switch (osd_ext_hw.order) { + case OSD_ORDER_01: + osd_reg_clr_mask(VPP2_MISC, + VPP_POST_FG_OSD2 | VPP_PRE_FG_OSD2); + break; + + case OSD_ORDER_10: + osd_reg_set_mask(VPP2_MISC, + VPP_POST_FG_OSD2 | VPP_PRE_FG_OSD2); + break; + + default: + break; + } + + remove_from_update_list(OSD2, OSD_CHANGE_ORDER); +} + +static void osd1_update_order(void) +{ + switch (osd_ext_hw.order) { + case OSD_ORDER_01: + osd_reg_clr_mask(VPP2_MISC, VPP_POST_FG_OSD2 | VPP_PRE_FG_OSD2); + break; + + case OSD_ORDER_10: + osd_reg_set_mask(VPP2_MISC, VPP_POST_FG_OSD2 | VPP_PRE_FG_OSD2); + break; + + default: + break; + } + + remove_from_update_list(OSD1, OSD_CHANGE_ORDER); +} + + +#if 0 +static void osd_ext_block_update_disp_geometry(u32 index) +{ + u32 data32; + u32 data_w1, data_w2, data_w3, data_w4; + u32 coef[4][2] = { {0, 0}, {1, 0}, {0, 1}, {1, 1} }; + u32 xoff, yoff; + u32 i; + + switch (osd_ext_hw.block_mode[index] & HW_OSD_BLOCK_LAYOUT_MASK) { + case HW_OSD_BLOCK_LAYOUT_HORIZONTAL: + yoff = ((osd_ext_hw.pandata[index].y_end & 0x1fff) - + (osd_ext_hw.pandata[index].y_start & 0x1fff) + 1) >> 2; + data_w1 = (osd_ext_hw.pandata[index].x_start & 0x1fff) | + (osd_ext_hw.pandata[index].x_end & 0x1fff) << 16; + data_w3 = (osd_ext_hw.dispdata[index].x_start & 0xfff) | + (osd_ext_hw.dispdata[index].x_end & 0xfff) << 16; + + for (i = 0; i < 4; i++) { + if (i == 3) { + data_w2 = ((osd_ext_hw.pandata[index].y_start + + yoff * i) & 0x1fff) + | (osd_ext_hw.pandata[index].y_end & + 0x1fff) << 16; + data_w4 = ((osd_ext_hw.dispdata[index].y_start + + yoff * i) & 0xfff) + | (osd_ext_hw.dispdata[index].y_end & + 0xfff) << 16; + } else { + data_w2 = ((osd_ext_hw.pandata[index].y_start + + yoff * i) & 0x1fff) + | ((osd_ext_hw.pandata[index].y_start + + yoff * (i + 1) - 1) & 0x1fff) << 16; + data_w4 = ((osd_ext_hw.dispdata[index].y_start + + yoff * i) & 0xfff) + | ((osd_ext_hw.dispdata[index].y_start + + yoff * (i + 1) - 1) & 0xfff) << 16; + } + + if (osd_ext_hw.scan_mode == SCAN_MODE_INTERLACE) { + data32 = data_w4; + data_w4 = ((data32 & 0xfff) >> 1) | + ((((((data32 >> 16) & 0xfff) + 1) >> + 1) - 1) << 16); + } + osd_reg_write(VIU2_OSD1_BLK0_CFG_W1 + (i << 4), + data_w1); + osd_reg_write(VIU2_OSD1_BLK0_CFG_W2 + (i << 4), + data_w2); + osd_reg_write(VIU2_OSD1_BLK0_CFG_W3 + (i << 4), + data_w3); + osd_reg_write(VIU2_OSD1_BLK0_CFG_W4 + (i << 2), + data_w4); + + osd_ext_hw.block_windows[index][i << 1] = data_w1; + osd_ext_hw.block_windows[index][(i << 1) + 1] = data_w2; + } + + break; + + case HW_OSD_BLOCK_LAYOUT_VERTICAL: + xoff = ((osd_ext_hw.pandata[index].x_end & 0x1fff) - + (osd_ext_hw.pandata[index].x_start & 0x1fff) + 1) >> 2; + data_w2 = (osd_ext_hw.pandata[index].y_start & 0x1fff) | + (osd_ext_hw.pandata[index].y_end & 0x1fff) << 16; + data_w4 = (osd_ext_hw.dispdata[index].y_start & 0xfff) | + (osd_ext_hw.dispdata[index].y_end & 0xfff) << 16; + + if (osd_ext_hw.scan_mode == SCAN_MODE_INTERLACE) { + data32 = data_w4; + data_w4 = ((data32 & 0xfff) >> 1) | + ((((((data32 >> 16) & 0xfff) + 1) >> 1) - 1) + << 16); + } + + for (i = 0; i < 4; i++) { + data_w1 = ((osd_ext_hw.pandata[index].x_start + + xoff * i) & 0x1fff) + | ((osd_ext_hw.pandata[index].x_start + + xoff * (i + 1) - 1) & 0x1fff) << 16; + data_w3 = ((osd_ext_hw.dispdata[index].x_start + + xoff * i) & 0xfff) + | ((osd_ext_hw.dispdata[index].x_start + + xoff * (i + 1) - 1) & 0xfff) << 16; + + osd_reg_write(VIU2_OSD1_BLK0_CFG_W1 + (i << 4), + data_w1); + osd_reg_write(VIU2_OSD1_BLK0_CFG_W2 + (i << 4), + data_w2); + osd_reg_write(VIU2_OSD1_BLK0_CFG_W3 + (i << 4), + data_w3); + osd_reg_write(VIU2_OSD1_BLK0_CFG_W4 + (i << 2), + data_w4); + + osd_ext_hw.block_windows[index][i << 1] = data_w1; + osd_ext_hw.block_windows[index][(i << 1) + 1] = data_w2; + } + + break; + + case HW_OSD_BLOCK_LAYOUT_GRID: + xoff = ((osd_ext_hw.pandata[index].x_end & 0x1fff) - + (osd_ext_hw.pandata[index].x_start & 0x1fff) + 1) >> 1; + yoff = ((osd_ext_hw.pandata[index].y_end & 0x1fff) - + (osd_ext_hw.pandata[index].y_start & 0x1fff) + 1) >> 1; + + for (i = 0; i < 4; i++) { + data_w1 = ((osd_ext_hw.pandata[index].x_start + + xoff * coef[i][0]) & 0x1fff) + | ((osd_ext_hw.pandata[index].x_start + + xoff * (coef[i][0] + 1) - 1) & 0x1fff) << 16; + data_w2 = ((osd_ext_hw.pandata[index].y_start + + yoff * coef[i][1]) & 0x1fff) + | ((osd_ext_hw.pandata[index].y_start + + yoff * (coef[i][1] + 1) - 1) & 0x1fff) << 16; + data_w3 = ((osd_ext_hw.dispdata[index].x_start + + xoff * coef[i][0]) & 0xfff) + | ((osd_ext_hw.dispdata[index].x_start + + xoff * (coef[i][0] + 1) - 1) & 0xfff) << 16; + data_w4 = ((osd_ext_hw.dispdata[index].y_start + + yoff * coef[i][1]) & 0xfff) + | ((osd_ext_hw.dispdata[index].y_start + + yoff * (coef[i][1] + 1) - 1) & 0xfff) << 16; + + if (osd_ext_hw.scan_mode == SCAN_MODE_INTERLACE) { + data32 = data_w4; + data_w4 = ((data32 & 0xfff) >> 1) | + ((((((data32 >> 16) & 0xfff) + + 1) >> 1) - 1) << 16); + } + + osd_reg_write(VIU2_OSD1_BLK0_CFG_W1 + (i << 4), + data_w1); + osd_reg_write(VIU2_OSD1_BLK0_CFG_W2 + (i << 4), + data_w2); + osd_reg_write(VIU2_OSD1_BLK0_CFG_W3 + (i << 4), + data_w3); + osd_reg_write(VIU2_OSD1_BLK0_CFG_W4 + (i << 2), + data_w4); + + osd_ext_hw.block_windows[index][i << 1] = data_w1; + osd_ext_hw.block_windows[index][(i << 1) + 1] = data_w2; + } + + break; + + case HW_OSD_BLOCK_LAYOUT_CUSTOMER: + for (i = 0; i < 4; i++) { + if (((osd_ext_hw.block_windows[index][i << 1] >> 16) & + 0x1fff) > osd_ext_hw.pandata[index].x_end) { + osd_ext_hw.block_windows[index][i << 1] = + (osd_ext_hw.block_windows[index][i << 1] & + 0x1fff) + | ((osd_ext_hw.pandata[index].x_end & + 0x1fff) << 16); + } + + data_w1 = osd_ext_hw.block_windows[index][i << 1] & + 0x1fff1fff; + data_w2 = ((osd_ext_hw.pandata[index].y_start & 0x1fff) + + (osd_ext_hw.block_windows[index][(i << 1) + 1] & + 0x1fff)) + | (((osd_ext_hw.pandata[index].y_start + & 0x1fff) << 16) + + (osd_ext_hw.block_windows[index][(i << 1) + 1] + & 0x1fff0000)); + data_w3 = (osd_ext_hw.dispdata[index].x_start + + (data_w1 & 0xfff)) + | (((osd_ext_hw.dispdata[index].x_start & + 0xfff) << 16) + (data_w1 & 0xfff0000)); + data_w4 = (osd_ext_hw.dispdata[index].y_start + + (osd_ext_hw.block_windows[index][(i << 1) + 1] + & 0xfff)) + | (((osd_ext_hw.dispdata[index].y_start + & 0xfff) << 16) + + (osd_ext_hw.block_windows[index][(i << 1) + 1] + & 0xfff0000)); + + if (osd_ext_hw.scan_mode == SCAN_MODE_INTERLACE) { + data32 = data_w4; + data_w4 = ((data32 & 0xfff) >> 1) | + ((((((data32 >> 16) & 0xfff) + 1) >> 1) + - 1) << 16); + } + + osd_reg_write(VIU2_OSD1_BLK0_CFG_W1 + (i << 4), + data_w1); + osd_reg_write(VIU2_OSD1_BLK0_CFG_W2 + (i << 4), + data_w2); + osd_reg_write(VIU2_OSD1_BLK0_CFG_W3 + (i << 4), + data_w3); + osd_reg_write(VIU2_OSD1_BLK0_CFG_W4 + (i << 2), + data_w4); + } + + break; + + default: + osd_log_err("ERROR block_mode: 0x%x\n", + osd_ext_hw.block_mode[index]); + break; + } +} +#endif + +static void osd1_update_disp_geometry(void) +{ + u32 dy0, sy0, sy1; + u32 data32; + + /* enable osd multi block */ + if (osd_ext_hw.block_mode[OSD1]) { + /* osd_ext_block_update_disp_geometry(OSD1); + * data32 = osd_reg_read(VIU2_OSD1_CTRL_STAT); + * data32 &= 0xfffffff0; + * data32 |= (osd_ext_hw.block_mode[OSD1] & + * HW_OSD_BLOCK_ENABLE_MASK); + * osd_reg_write(VIU2_OSD1_CTRL_STAT, data32); + */ + osd_log_info( + "osd1_update_disp_geometry: not support block mode\n"); + } else { + data32 = (osd_ext_hw.dispdata[OSD1].x_start & 0xfff) | + (osd_ext_hw.dispdata[OSD1].x_end & 0xfff) << 16; + osd_reg_write(VIU2_OSD1_BLK0_CFG_W3, data32); + if (osd_ext_hw.scan_mode == SCAN_MODE_INTERLACE) + data32 = ((osd_ext_hw.dispdata[OSD1].y_start >> + 1) & 0xfff) + | ((((osd_ext_hw.dispdata[OSD1].y_end + + 1) >> 1) - 1) & 0xfff) << 16; + else + data32 = (osd_ext_hw.dispdata[OSD1].y_start & + 0xfff) + | (osd_ext_hw.dispdata[OSD1].y_end & + 0xfff) << 16; + osd_reg_write(VIU2_OSD1_BLK0_CFG_W4, data32); + /* enable osd 2x scale */ + if (osd_ext_hw.scale[OSD1].h_enable || + osd_ext_hw.scale[OSD1].v_enable) { + data32 = (osd_ext_hw.scaledata[OSD1].x_start & 0x1fff) | + (osd_ext_hw.scaledata[OSD1].x_end & 0x1fff) << 16; + osd_reg_write(VIU2_OSD1_BLK0_CFG_W1, data32); + data32 = ((osd_ext_hw.scaledata[OSD1].y_start + + osd_ext_hw.pandata[OSD1].y_start) & 0x1fff) + | ((osd_ext_hw.scaledata[OSD1].y_end + + osd_ext_hw.pandata[OSD1].y_start) & 0x1fff) << 16; + osd_reg_write(VIU2_OSD1_BLK0_CFG_W2, data32); + + /* adjust display x-axis */ + if (osd_ext_hw.scale[OSD1].h_enable) { + data32 = (osd_ext_hw.dispdata[OSD1].x_start + & 0xfff) + | ((osd_ext_hw.dispdata[OSD1].x_start + + (osd_ext_hw.scaledata[OSD1].x_end - + osd_ext_hw.scaledata[OSD1].x_start) * + 2 + 1) & 0xfff) << 16; + osd_reg_write(VIU2_OSD1_BLK0_CFG_W3, data32); + } + + /* adjust display y-axis */ + dy0 = osd_ext_hw.dispdata[OSD1].y_start; + sy0 = osd_ext_hw.scaledata[OSD1].y_start; + sy1 = osd_ext_hw.scaledata[OSD1].y_end; + if (osd_ext_hw.scale[OSD1].v_enable) { + if (osd_ext_hw.scan_mode == + SCAN_MODE_INTERLACE) { + data32 = ((dy0 >> 1) & 0xfff) + | (((((dy0 + (sy1 - sy0) * 2) + + 1) >> 1) - 1) & 0xfff) << 16; + } else { + data32 = (dy0 & 0xfff) + | (((dy0 + (sy1 - sy0) * 2)) + & 0xfff) << 16; + } + + osd_reg_write(VIU2_OSD1_BLK0_CFG_W4, data32); + } + } else if (osd_ext_hw.free_scale_enable[OSD1] + && (osd_ext_hw.free_src_data[OSD1].x_end > 0) + && (osd_ext_hw.free_src_data[OSD1].y_end > 0)) { + /* enable osd free scale */ + data32 = (osd_ext_hw.free_src_data[OSD1].x_start + & 0x1fff) + | (osd_ext_hw.free_src_data[OSD1].x_end + & 0x1fff) << 16; + osd_reg_write(VIU2_OSD1_BLK0_CFG_W1, data32); + data32 = ((osd_ext_hw.free_src_data[OSD1].y_start + + osd_ext_hw.pandata[OSD1].y_start) & 0x1fff) + | ((osd_ext_hw.free_src_data[OSD1].y_end + + osd_ext_hw.pandata[OSD1].y_start) + & 0x1fff) << 16; + osd_reg_write(VIU2_OSD1_BLK0_CFG_W2, data32); + } else { + /* normal mode */ + data32 = + (osd_ext_hw.pandata[OSD1].x_start & 0x1fff) | + (osd_ext_hw.pandata[OSD1].x_end & 0x1fff) << 16; + osd_reg_write(VIU2_OSD1_BLK0_CFG_W1, data32); + data32 = + (osd_ext_hw.pandata[OSD1].y_start & 0x1fff) | + (osd_ext_hw.pandata[OSD1].y_end & 0x1fff) << 16; + osd_reg_write(VIU2_OSD1_BLK0_CFG_W2, data32); + } + + data32 = osd_reg_read(VIU2_OSD1_CTRL_STAT); + data32 &= 0xfffffff0; + data32 |= HW_OSD_BLOCK_ENABLE_0; + osd_reg_write(VIU2_OSD1_CTRL_STAT, data32); + } + + remove_from_update_list(OSD1, DISP_GEOMETRY); +} + +static void osd2_update_disp_geometry(void) +{ + u32 data32; + + data32 = (osd_ext_hw.dispdata[OSD2].x_start & 0xfff) | + (osd_ext_hw.dispdata[OSD2].x_end & 0xfff) << 16; + osd_reg_write(VIU2_OSD2_BLK0_CFG_W3, data32); + + if (osd_ext_hw.scan_mode == SCAN_MODE_INTERLACE) { + data32 = ((osd_ext_hw.dispdata[OSD2].y_start >> 1) & 0xfff) + | ((((osd_ext_hw.dispdata[OSD2].y_end + 1) >> 1) - 1) + & 0xfff) << 16; + } else + data32 = (osd_ext_hw.dispdata[OSD2].y_start & 0xfff) | + (osd_ext_hw.dispdata[OSD2].y_end & 0xfff) << 16; + + osd_reg_write(VIU2_OSD2_BLK0_CFG_W4, data32); + + if (osd_ext_hw.scale[OSD2].h_enable || + osd_ext_hw.scale[OSD2].v_enable) { +#if defined(CONFIG_AMLOGIC_MEDIA_FB_OSD2_CURSOR) + data32 = (osd_ext_hw.pandata[OSD2].x_start & 0x1fff) | + (osd_ext_hw.pandata[OSD2].x_end & 0x1fff) << 16; + osd_reg_write(VIU2_OSD2_BLK0_CFG_W1, data32); + data32 = (osd_ext_hw.pandata[OSD2].y_start & 0x1fff) | + (osd_ext_hw.pandata[OSD2].y_end & 0x1fff) << 16; + osd_reg_write(VIU2_OSD2_BLK0_CFG_W2, data32); +#else + data32 = + (osd_ext_hw.scaledata[OSD2].x_start & 0x1fff) | + (osd_ext_hw.scaledata[OSD2].x_end & 0x1fff) << 16; + osd_reg_write(VIU2_OSD2_BLK0_CFG_W1, data32); + data32 = ((osd_ext_hw.scaledata[OSD2].y_start + + osd_ext_hw.pandata[OSD2].y_start) & 0x1fff) + | ((osd_ext_hw.scaledata[OSD2].y_end + + osd_ext_hw.pandata[OSD2].y_start) + & 0x1fff) << 16; + osd_reg_write(VIU2_OSD2_BLK0_CFG_W2, data32); +#endif + } else { + data32 = (osd_ext_hw.pandata[OSD2].x_start & 0x1fff) | + (osd_ext_hw.pandata[OSD2].x_end & 0x1fff) << 16; + osd_reg_write(VIU2_OSD2_BLK0_CFG_W1, data32); + data32 = (osd_ext_hw.pandata[OSD2].y_start & 0x1fff) | + (osd_ext_hw.pandata[OSD2].y_end & 0x1fff) << 16; + osd_reg_write(VIU2_OSD2_BLK0_CFG_W2, data32); + } + + remove_from_update_list(OSD2, DISP_GEOMETRY); +} + +static void osd1_update_disp_3d_mode(void) +{ + /*step 1 . set pan data */ + u32 data32; + + if (osd_ext_hw.mode_3d[OSD1].left_right == OSD_LEFT) { + data32 = (osd_ext_hw.mode_3d[OSD1].l_start & 0x1fff) | + (osd_ext_hw.mode_3d[OSD1].l_end & 0x1fff) << 16; + osd_reg_write(VIU2_OSD1_BLK0_CFG_W1, data32); + } else { + data32 = (osd_ext_hw.mode_3d[OSD1].r_start & 0x1fff) | + (osd_ext_hw.mode_3d[OSD1].r_end & 0x1fff) << 16; + osd_reg_write(VIU2_OSD1_BLK0_CFG_W1, data32); + } + + osd_ext_hw.mode_3d[OSD1].left_right ^= 1; +} + +static void osd2_update_disp_3d_mode(void) +{ + u32 data32; + + if (osd_ext_hw.mode_3d[OSD2].left_right == OSD_LEFT) { + data32 = (osd_ext_hw.mode_3d[OSD2].l_start & 0x1fff) | + (osd_ext_hw.mode_3d[OSD2].l_end & 0x1fff) << 16; + osd_reg_write(VIU2_OSD2_BLK0_CFG_W1, data32); + } else { + data32 = (osd_ext_hw.mode_3d[OSD2].r_start & 0x1fff) | + (osd_ext_hw.mode_3d[OSD2].r_end & 0x1fff) << 16; + osd_reg_write(VIU2_OSD2_BLK0_CFG_W1, data32); + } + + osd_ext_hw.mode_3d[OSD2].left_right ^= 1; +} + +void osd_ext_init_hw(u32 logo_loaded) +{ + u32 group, idx, data32; + + for (group = 0; group < HW_OSD_COUNT; group++) + for (idx = 0; idx < HW_REG_INDEX_MAX; idx++) + osd_ext_hw.reg[group][idx].update_func = + hw_func_array[group][idx]; + + osd_ext_hw.updated[OSD1] = 0; + osd_ext_hw.updated[OSD2] = 0; + + /* here we will init default value ,these value only set once . */ + if (!logo_loaded) { + data32 = 1; /* Set DDR request priority to be urgent */ + data32 |= 4 << 5; /* hold_fifo_lines */ + data32 |= 3 << 10; /* burst_len_sel: 3=64 */ + data32 |= 32 << 12; /* fifo_depth_val: 32*8=256 */ + + osd_reg_write(VIU2_OSD1_FIFO_CTRL_STAT, data32); + osd_reg_write(VIU2_OSD2_FIFO_CTRL_STAT, data32); + + osd_reg_set_mask(VPP2_MISC, VPP_POSTBLEND_EN); + osd_reg_clr_mask(VPP2_MISC, VPP_PREBLEND_EN); + osd_reg_clr_mask(VPP2_MISC, + VPP_OSD1_POSTBLEND | VPP_OSD2_POSTBLEND); + data32 = 0x1 << 0; /* osd_ext_blk_enable */ + data32 |= OSD_GLOBAL_ALPHA_DEF << 12; + data32 |= (1 << 21); + osd_reg_write(VIU2_OSD1_CTRL_STAT, data32); + osd_reg_write(VIU2_OSD2_CTRL_STAT, data32); + } + +#if defined(CONFIG_AMLOGIC_MEDIA_FB_OSD2_CURSOR) + osd_reg_set_mask(VPP2_MISC, VPP_POST_FG_OSD2 | VPP_PRE_FG_OSD2); + osd_ext_hw.order = OSD_ORDER_10; +#else + osd_reg_clr_mask(VPP2_MISC, VPP_POST_FG_OSD2 | VPP_PRE_FG_OSD2); + osd_ext_hw.order = OSD_ORDER_01; +#endif + + osd_ext_hw.enable[OSD2] = osd_ext_hw.enable[OSD1] = DISABLE; + osd_ext_hw.fb_gem[OSD1].canvas_idx = OSD3_CANVAS_INDEX; + osd_ext_hw.fb_gem[OSD2].canvas_idx = OSD4_CANVAS_INDEX; + osd_ext_hw.gbl_alpha[OSD1] = OSD_GLOBAL_ALPHA_DEF; + osd_ext_hw.gbl_alpha[OSD2] = OSD_GLOBAL_ALPHA_DEF; + osd_ext_hw.color_info[OSD1] = NULL; + osd_ext_hw.color_info[OSD2] = NULL; + /* TODO */ + /* vf.width = vf.height = 0; */ + osd_ext_hw.color_key[OSD1] = osd_ext_hw.color_key[OSD2] = 0xffffffff; + osd_ext_hw.free_scale_enable[OSD1] = 0; + osd_ext_hw.free_scale_enable[OSD2] = 0; + osd_ext_hw.scale[OSD1].h_enable = osd_ext_hw.scale[OSD1].v_enable = 0; + osd_ext_hw.scale[OSD2].h_enable = osd_ext_hw.scale[OSD2].v_enable = 0; + osd_ext_hw.mode_3d[OSD2].enable = osd_ext_hw.mode_3d[OSD1].enable = 0; + osd_ext_hw.block_mode[OSD1] = osd_ext_hw.block_mode[OSD2] = 0; + /* + * osd_ext_hw.rotation_pandata[OSD1].x_start = + * osd_ext_hw.rotation_pandata[OSD1].y_start = 0; + * osd_ext_hw.rotation_pandata[OSD2].x_start = + * osd_ext_hw.rotation_pandata[OSD2].y_start = 0; + * memset(osd_ext_hw.rotate, 0, sizeof(struct osd_rotate_s)); + */ + osd_get_hw_para(&osd_hw); + +#ifdef CONFIG_AMLOGIC_MEDIA_FB_OSD_SYNC_FENCE + INIT_LIST_HEAD(&ext_post_fence_list); + mutex_init(&ext_post_fence_list_lock); +#endif + +#ifdef FIQ_VSYNC + osd_ext_hw.fiq_handle_item.handle = vsync_isr; + osd_ext_hw.fiq_handle_item.key = (u32) vsync_isr; + osd_ext_hw.fiq_handle_item.name = "osd_ext_vsync"; + + if (register_fiq_bridge_handle(&osd_ext_hw.fiq_handle_item)) +#else + if (request_irq(INT_VIU2_VSYNC, &vsync_isr, IRQF_SHARED, + "osd_ext_vsync", osd_ext_setup)) +#endif + osd_log_err("can't request irq for vsync\n"); + +#ifdef FIQ_VSYNC + request_fiq(INT_VIU2_VSYNC, &osd_ext_fiq_isr); +#endif +} + +#if defined(CONFIG_AMLOGIC_MEDIA_FB_OSD2_CURSOR) +void osd_ext_cursor_hw(s16 x, s16 y, s16 xstart, s16 ystart, u32 osd_ext_w, + u32 osd_ext_h, int index) +{ + struct pandata_s disp_tmp; + + if (index != 1) + return; + + memcpy(&disp_tmp, &osd_ext_hw.dispdata[OSD1], sizeof(struct pandata_s)); + + if (osd_ext_hw.scale[OSD2].h_enable && + (osd_ext_hw.scaledata[OSD2].x_start > 0) + && (osd_ext_hw.scaledata[OSD2].x_end > 0)) { + x = x * osd_ext_hw.scaledata[OSD2].x_end / + osd_ext_hw.scaledata[OSD2].x_start; + + if (osd_ext_hw.scaledata[OSD2].x_end > + osd_ext_hw.scaledata[OSD2].x_start) { + disp_tmp.x_start = + osd_ext_hw.dispdata[OSD1].x_start * + osd_ext_hw.scaledata[OSD2].x_end / + osd_ext_hw.scaledata[OSD2].x_start; + disp_tmp.x_end = + osd_ext_hw.dispdata[OSD1].x_end * + osd_ext_hw.scaledata[OSD2].x_end / + osd_ext_hw.scaledata[OSD2].x_start; + } + } + + if (osd_ext_hw.scale[OSD2].v_enable && + (osd_ext_hw.scaledata[OSD2].y_start > 0) + && (osd_ext_hw.scaledata[OSD2].y_end > 0)) { + y = y * osd_ext_hw.scaledata[OSD2].y_end / + osd_ext_hw.scaledata[OSD2].y_start; + + if (osd_ext_hw.scaledata[OSD2].y_end > + osd_ext_hw.scaledata[OSD2].y_start) { + disp_tmp.y_start = + osd_ext_hw.dispdata[OSD1].y_start * + osd_ext_hw.scaledata[OSD2].y_end / + osd_ext_hw.scaledata[OSD2].y_start; + disp_tmp.y_end = + osd_ext_hw.dispdata[OSD1].y_end * + osd_ext_hw.scaledata[OSD2].y_end / + osd_ext_hw.scaledata[OSD2].y_start; + } + } + + x += xstart; + y += ystart; + /** + * Use pandata to show a partial cursor when it is at the edge + * because the registers can't have negative values and because we + * need to manually clip the cursor when it is past the edge. + * The edge is hardcoded to the OSD0 area. + */ + osd_ext_hw.dispdata[OSD2].x_start = x; + osd_ext_hw.dispdata[OSD2].y_start = y; + + if (x < disp_tmp.x_start) { + /* if negative position, set osd to 0,y and pan. */ + if ((disp_tmp.x_start - x) < osd_ext_w) { + osd_ext_hw.pandata[OSD2].x_start = disp_tmp.x_start - x; + osd_ext_hw.pandata[OSD2].x_end = osd_ext_w - 1; + } + + osd_ext_hw.dispdata[OSD2].x_start = 0; + } else { + osd_ext_hw.pandata[OSD2].x_start = 0; + + if (x + osd_ext_w > disp_tmp.x_end) { + /* + * if past positive edge, + * set osd to inside of the edge and pan. + */ + if (x < osd_ext_hw.dispdata[OSD1].x_end) + osd_ext_hw.pandata[OSD2].x_end = + disp_tmp.x_end - x; + } else + osd_ext_hw.pandata[OSD2].x_end = osd_ext_w - 1; + } + + if (y < disp_tmp.y_start) { + if ((disp_tmp.y_start - y) < osd_ext_h) { + osd_ext_hw.pandata[OSD2].y_start = disp_tmp.y_start - y; + osd_ext_hw.pandata[OSD2].y_end = osd_ext_h - 1; + } + + osd_ext_hw.dispdata[OSD2].y_start = 0; + } else { + osd_ext_hw.pandata[OSD2].y_start = 0; + + if (y + osd_ext_h > disp_tmp.y_end) { + if (y < disp_tmp.y_end) + osd_ext_hw.pandata[OSD2].y_end = + disp_tmp.y_end - y; + } else + osd_ext_hw.pandata[OSD2].y_end = osd_ext_h - 1; + } + + osd_ext_hw.dispdata[OSD2].x_end = + osd_ext_hw.dispdata[OSD2].x_start + + osd_ext_hw.pandata[OSD2].x_end - + osd_ext_hw.pandata[OSD2].x_start; + osd_ext_hw.dispdata[OSD2].y_end = + osd_ext_hw.dispdata[OSD2].y_start + + osd_ext_hw.pandata[OSD2].y_end - + osd_ext_hw.pandata[OSD2].y_start; + add_to_update_list(OSD2, DISP_GEOMETRY); +} +#endif /* CONFIG_AMLOGIC_MEDIA_FB_OSD2_CURSOR */ + +void osd_ext_suspend_hw(void) +{ + osd_ext_hw.reg_status_save = + osd_reg_read(VPP2_MISC) & OSD_RELATIVE_BITS; + + osd_reg_clr_mask(VPP2_MISC, OSD_RELATIVE_BITS); + osd_log_info("osd_ext_suspended\n"); +} + +void osd_ext_resume_hw(void) +{ + osd_reg_set_mask(VPP2_MISC, osd_ext_hw.reg_status_save); + osd_log_info("osd_ext_resumed\n"); +} + +void osd_ext_clone_pan(u32 index) +{ + s32 offset = 0; + s32 height_osd0 = 0; + s32 height_osd2 = 0; + u32 py0, py1; + + height_osd0 = osd_hw->pandata[index].y_end - + osd_hw->pandata[index].y_start + 1; + height_osd2 = osd_ext_hw.pandata[index].y_end - + osd_ext_hw.pandata[index].y_start + 1; + + py0 = osd_ext_hw.pandata[index].y_start; + py1 = osd_ext_hw.pandata[index].y_end; + if (osd_ext_hw.clone[index]) { + if (py0 < height_osd0) { + if (py0 >= height_osd2) + offset -= py1 - py0 + 1; + else + offset = 0; + } else { + if (py0 < height_osd2) + offset += py1 - py0 + 1; + else + offset = 0; + } + + osd_ext_hw.pandata[index].y_start += offset; + osd_ext_hw.pandata[index].y_end += offset; + py0 = osd_ext_hw.pandata[index].y_start; + + if (osd_ext_hw.angle[index]) + osd_ext_clone_update_pan(py0 ? 1 : 0); + + add_to_update_list(index, DISP_GEOMETRY); + osd_ext_wait_vsync_hw(); + } +} + +void osd_ext_get_angle_hw(u32 index, u32 *angle) +{ + osd_log_info("get osd_ext[%d]->angle: %d\n", + index, osd_ext_hw.angle[index]); + *angle = osd_ext_hw.angle[index]; +} + +void osd_ext_set_angle_hw(u32 index, u32 angle) +{ +#ifndef OSD_EXT_GE2D_CLONE_SUPPORT + osd_log_info("++ osd_clone depends on GE2D module!\n"); + return; +#endif + + if (angle > 4) { + osd_log_err("++ invalid angle: %d\n", angle); + return; + } + + if (osd_ext_hw.clone[index] == 0) { + osd_log_info("++ set osd_ext[%d]->angle: %d->%d\n", index, + osd_ext_hw.angle[index], angle); + osd_ext_clone_set_angle(angle); + osd_ext_hw.angle[index] = angle; + } else if (!((osd_ext_hw.angle[index] == 0) || (angle == 0))) { + osd_log_info("++ set osd_ext[%d]->angle: %d->%d\n", index, + osd_ext_hw.angle[index], angle); + osd_ext_clone_set_angle(angle); + osd_ext_hw.angle[index] = angle; + osd_ext_clone_pan(index); + } +} + +void osd_ext_get_clone_hw(u32 index, u32 *clone) +{ + osd_log_info("get osd_ext[%d]->clone: %d\n", + index, osd_ext_hw.clone[index]); + *clone = osd_ext_hw.clone[index]; +} + +void osd_ext_set_clone_hw(u32 index, u32 clone) +{ + static const struct color_bit_define_s *color_info[HW_OSD_COUNT] = {}; + static struct pandata_s pandata[HW_OSD_COUNT] = {}; + + osd_log_info("++ set osd_ext[%d]->clone: %d->%d\n", index, + osd_ext_hw.clone[index], clone); + osd_ext_hw.clone[index] = clone; + + if (osd_ext_hw.clone[index]) { + if (osd_ext_hw.angle[index]) { + osd_ext_hw.color_info[index] = + osd_hw->color_info[index]; + osd_ext_clone_task_start(); + } else { + color_info[index] = osd_ext_hw.color_info[index]; + osd_ext_hw.color_info[index] = + osd_hw->color_info[index]; + memcpy(&pandata, &osd_ext_hw.pandata[index], + sizeof(struct pandata_s)); +#ifdef CONFIG_AMLOGIC_MEDIA_CANVAS + canvas_update_addr(osd_ext_hw.fb_gem[index].canvas_idx, + osd_hw->fb_gem[index].addr); +#endif + } + } else { + if (osd_ext_hw.angle[index]) + osd_ext_clone_task_stop(); + else { + color_info[index] = osd_ext_hw.color_info[index]; +#ifdef CONFIG_AMLOGIC_MEDIA_CANVAS + canvas_update_addr(osd_ext_hw.fb_gem[index].canvas_idx, + osd_ext_hw.fb_gem[index].addr); +#endif + osd_ext_hw.color_info[index] = color_info[index]; + memcpy(&osd_ext_hw.pandata[index], &pandata, + sizeof(struct pandata_s)); + } + } + add_to_update_list(index, OSD_COLOR_MODE); +} diff --git a/drivers/amlogic/media/osd_ext/osd_hw.h b/drivers/amlogic/media/osd_ext/osd_hw.h new file mode 100644 index 000000000000..c287f94c0289 --- /dev/null +++ b/drivers/amlogic/media/osd_ext/osd_hw.h @@ -0,0 +1,98 @@ +/* + * drivers/amlogic/media/osd_ext/osd_hw.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 _OSD_HW_H_ +#define _OSD_HW_H_ + +#include + +#define REG_OFFSET 0x20 +#define OSD_RELATIVE_BITS 0x333f0 +extern void osd_ext_set_color_key_hw(u32 index, u32 bpp, u32 colorkey); +extern void osd_ext_srckey_enable_hw(u32 index, u8 enable); +extern void osd_ext_set_gbl_alpha_hw(u32 index, u32 gbl_alpha); +extern u32 osd_ext_get_gbl_alpha_hw(u32 index); +extern void osd_ext_setup(struct osd_ctl_s *osd_ext_ctl, + u32 xoffset, + u32 yoffset, + u32 xres, + u32 yres, + u32 xres_virtual, + u32 yres_virtual, + u32 disp_start_x, + u32 disp_start_y, + u32 disp_end_x, + u32 disp_end_y, + u32 fbmem, + const struct color_bit_define_s *color, + int index); +extern void osd_ext_update_disp_axis_hw( + u32 index, + u32 display_h_start, + u32 display_h_end, + u32 display_v_start, + u32 display_v_end, + u32 xoffset, + u32 yoffset, + u32 mode_change); +extern void osd_ext_set_order_hw(u32 index, u32 order); +extern u32 osd_ext_get_order_hw(u32 index); +extern void osd_ext_set_free_scale_enable_hw(u32 index, u32 enable); +extern void osd_ext_get_free_scale_enable_hw(u32 index, + u32 *free_scale_enable); +extern void osd_ext_get_free_scale_width_hw(u32 index, u32 *free_scale_width); +extern void osd_ext_get_free_scale_height_hw(u32 index, + u32 *free_scale_height); +extern void osd_ext_get_free_scale_axis_hw(u32 index, s32 *x0, s32 *y0, s32 *x1, + s32 *y1); +extern void osd_ext_set_free_scale_axis_hw(u32 index, s32 x0, s32 y0, s32 x1, + s32 y1); +extern void osd_ext_get_scale_axis_hw(u32 index, s32 *x0, s32 *y0, s32 *x1, + s32 *y1); +extern void osd_ext_set_scale_axis_hw(u32 index, s32 x0, s32 y0, s32 x1, + s32 y1); +extern void osd_ext_get_window_axis_hw(u32 index, s32 *x0, s32 *y0, s32 *x1, + s32 *y1); +extern void osd_ext_set_window_axis_hw(u32 index, s32 x0, s32 y0, s32 x1, + s32 y1); +extern void osd_ext_get_free_scale_mode_hw(u32 index, u32 *freescale_mode); +extern void osd_ext_set_free_scale_mode_hw(u32 index, u32 freescale_mode); +extern void osd_ext_set_debug_hw(u32 index, u32 flag); +extern void osd_ext_get_block_windows_hw(u32 index, u32 *windows); +extern void osd_ext_set_block_windows_hw(u32 index, u32 *windows); +extern void osd_ext_get_block_mode_hw(u32 index, u32 *mode); +extern void osd_ext_set_block_mode_hw(u32 index, u32 mode); +extern void osd_ext_enable_3d_mode_hw(int index, int enable); +extern void osd_ext_set_2x_scale_hw(u32 index, u16 h_scale_enable, + u16 v_scale_enable); +extern void osd_ext_setpal_hw(u32 index, unsigned int regno, + unsigned int red, unsigned int green, + unsigned int blue, unsigned int transp); +extern void osd_ext_enable_hw(u32 index, int enable); +extern void osd_ext_pan_display_hw(u32 index, unsigned int xoffset, + unsigned int yoffset); +extern int osd_ext_sync_request(u32 index, u32 yres, u32 xoffset, u32 yoffset, + s32 in_fence_fd); +extern s32 osd_ext_wait_vsync_event(void); +extern void osd_ext_suspend_hw(void); +extern void osd_ext_resume_hw(void); +extern void osd_ext_init_hw(u32 logo_loaded); +extern void osd_ext_get_angle_hw(u32 index, u32 *angle); +extern void osd_ext_set_angle_hw(u32 index, u32 angle); +extern void osd_ext_get_clone_hw(u32 index, u32 *clone); +extern void osd_ext_set_clone_hw(u32 index, u32 clone); +#endif diff --git a/drivers/amlogic/media/osd_ext/osd_hw_def.h b/drivers/amlogic/media/osd_ext/osd_hw_def.h new file mode 100644 index 000000000000..695c9e771f4a --- /dev/null +++ b/drivers/amlogic/media/osd_ext/osd_hw_def.h @@ -0,0 +1,108 @@ +/* + * drivers/amlogic/media/osd_ext/osd_hw_def.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 _OSD_HW_DEF_H_ +#define _OSD_HW_DEF_H_ + +#include +#include "osd_hw.h" + +static void osd1_update_color_mode(void); +static void osd1_update_enable(void); +static void osd1_update_color_key(void); +static void osd1_update_color_key_enable(void); +static void osd1_update_gbl_alpha(void); +static void osd1_update_order(void); +static void osd1_update_coef(void); +static void osd1_update_disp_geometry(void); +static void osd1_update_disp_freescale_enable(void); +static void osd1_update_disp_osd_rotate(void); +static void osd1_update_disp_scale_enable(void); +static void osd1_update_disp_3d_mode(void); + +static void osd2_update_color_mode(void); +static void osd2_update_enable(void); +static void osd2_update_color_key(void); +static void osd2_update_color_key_enable(void); +static void osd2_update_gbl_alpha(void); +static void osd2_update_order(void); +static void osd2_update_coef(void); +static void osd2_update_disp_geometry(void); +static void osd2_update_disp_freescale_enable(void); +static void osd2_update_disp_osd_rotate(void); +static void osd2_update_disp_scale_enable(void); +static void osd2_update_disp_3d_mode(void); + +static DEFINE_SPINLOCK(osd_ext_lock); +static struct hw_para_s osd_ext_hw; +static unsigned long lock_flags; +#ifdef FIQ_VSYNC +static unsigned long fiq_flag; +#endif +static update_func_t hw_func_array[HW_OSD_COUNT][HW_REG_INDEX_MAX] = { + { + osd1_update_color_mode, + osd1_update_enable, + osd1_update_color_key, + osd1_update_color_key_enable, + osd1_update_gbl_alpha, + osd1_update_order, + osd1_update_coef, + osd1_update_disp_geometry, + osd1_update_disp_scale_enable, + osd1_update_disp_freescale_enable, + NULL, + osd1_update_disp_osd_rotate, + }, + { + osd2_update_color_mode, + osd2_update_enable, + osd2_update_color_key, + osd2_update_color_key_enable, + osd2_update_gbl_alpha, + osd2_update_order, + osd2_update_coef, + osd2_update_disp_geometry, + osd2_update_disp_scale_enable, + osd2_update_disp_freescale_enable, + NULL, + osd2_update_disp_osd_rotate, + }, +}; + +#ifdef FIQ_VSYNC +#define add_to_update_list(osd_ext_idx, cmd_idx) \ + do { \ + spin_lock_irqsave(&osd_ext_lock, lock_flags); \ + raw_local_save_flags(fiq_flag); \ + local_fiq_disable(); \ + osd_ext_hw.updated[osd_ext_idx] |= (1< +#include +#include +#include + +/* Amlogic Headers */ +#include + +/* Local Headers */ +#include +#include +#include "osd_hw.h" +#include "osd_prot.h" + +int osd_ext_set_prot(unsigned char x_rev, + unsigned char y_rev, + unsigned char bytes_per_pixel, + unsigned char conv_422to444, + unsigned char little_endian, + unsigned int hold_lines, + unsigned int x_start, + unsigned int x_end, + unsigned int y_start, + unsigned int y_end, + unsigned int y_len_m1, + unsigned char y_step, + unsigned char pat_start_ptr, + unsigned char pat_end_ptr, + unsigned long pat_val, + unsigned int canv_addr, + unsigned int cid_val, + unsigned char cid_mode, + unsigned char cugt, + unsigned char req_onoff_en, + unsigned int req_on_max, + unsigned int req_off_min, + unsigned char osd_index, + unsigned char on) +{ + unsigned long data32; + + if (!on) { + /* no one use prot1. */ + osd_reg_clr_mask(VPU_PROT1_MMC_CTRL, 0xf << 12); + osd_reg_clr_mask(VPU_PROT1_CLK_GATE, 1 << 0); + + if (osd_index == OSD1) { + /* switch back to little endian */ + osd_reg_set_bits(VIU2_OSD1_BLK0_CFG_W0, 1, 15, 1); + osd_reg_write(VIU2_OSD1_PROT_CTRL, 0); + } else if (osd_index == OSD2) { + /* switch back to little endian */ + osd_reg_set_bits(VIU2_OSD2_BLK0_CFG_W0, 1, 15, 1); + osd_reg_write(VIU2_OSD2_PROT_CTRL, 0); + } + + return 0; + } + + if (osd_index == OSD1) { + /* bit[12..15] OSD1 OSD2 OSD3 OSD4 */ + osd_reg_set_bits(VPU_PROT1_MMC_CTRL, 4, 12, 4); + osd_reg_write(VIU2_OSD1_PROT_CTRL, 1 << 15 | y_len_m1); + /* before rotate set big endian */ + osd_reg_clr_mask(VIU2_OSD1_BLK0_CFG_W0, 1 << 15); + } else if (osd_index == OSD2) { + /* bit[12..15] OSD1 OSD2 OSD3 OSD4 */ + osd_reg_set_bits(VPU_PROT1_MMC_CTRL, 8, 12, 4); + osd_reg_write(VIU2_OSD2_PROT_CTRL, 1 << 15 | y_len_m1); + /* before rotate set big endian */ + osd_reg_clr_mask(VIU2_OSD2_BLK0_CFG_W0, 1 << 15); + } + + data32 = (x_end << 16) | + (x_start << 0); + osd_reg_write(VPU_PROT1_X_START_END, data32); + + data32 = (y_end << 16) | + (y_start << 0); + osd_reg_write(VPU_PROT1_Y_START_END, data32); + + data32 = (y_step << 16) | + (y_len_m1 << 0); + osd_reg_write(VPU_PROT1_Y_LEN_STEP, data32); + + data32 = (pat_start_ptr << 4) | + (pat_end_ptr << 0); + osd_reg_write(VPU_PROT1_RPT_LOOP, data32); + + osd_reg_write(VPU_PROT1_RPT_PAT, pat_val); + + data32 = (cugt << 20) | + (cid_mode << 16) | + (cid_val << 8) | + (canv_addr << 0); + osd_reg_write(VPU_PROT1_DDR, data32); + + data32 = (hold_lines << 8) | + (little_endian << 7) | + (conv_422to444 << 6) | + (bytes_per_pixel << 4) | + (y_rev << 3) | + (x_rev << 2) | + (1 << 0); + /* [1:0] req_en: 0=Idle; 1=Rotate mode; 2=FIFO mode. */ + osd_reg_write(VPU_PROT1_GEN_CNTL, data32); + + data32 = (req_onoff_en << 31) | + (req_off_min << 16) | + (req_on_max << 0); + osd_reg_write(VPU_PROT1_REQ_ONOFF, data32); + osd_reg_write(VPU_PROT1_CLK_GATE, 1); /* Enable clock */ + return 0; +} diff --git a/drivers/amlogic/media/osd_ext/osd_prot.h b/drivers/amlogic/media/osd_ext/osd_prot.h new file mode 100644 index 000000000000..be9e05f85470 --- /dev/null +++ b/drivers/amlogic/media/osd_ext/osd_prot.h @@ -0,0 +1,57 @@ +/* + * drivers/amlogic/media/osd_ext/osd_prot.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 _OSD_PROT_H_ +#define _OSD_PROT_H_ + +#define CUGT 0 +#define CID_VALUE 161 +#define CID_MODE 6 +#define REQ_ONOFF_EN 0 +#define REQ_ON_MAX 0 +#define REQ_OFF_MIN 0 +#define PAT_VAL 0x00000000 +#define PAT_START_PTR 1 +#define PAT_END_PTR 1 +#define HOLD_LINES 28 +#define Y_STEP 0 + +extern int osd_ext_set_prot(unsigned char x_rev, + unsigned char y_rev, + unsigned char bytes_per_pixel, + unsigned char conv_422to444, + unsigned char little_endian, + unsigned int hold_lines, + unsigned int x_start, + unsigned int x_end, + unsigned int y_start, + unsigned int y_end, + unsigned int y_len_m1, + unsigned char y_step, + unsigned char pat_start_ptr, + unsigned char pat_end_ptr, + unsigned long pat_val, + unsigned int canv_addr, + unsigned int cid_val, + unsigned char cid_mode, + unsigned char cugt, + unsigned char req_onoff_en, + unsigned int req_on_max, + unsigned int req_off_min, + unsigned char osd_index, + unsigned char on_off); +#endif diff --git a/drivers/amlogic/media/video_sink/video_priv.h b/drivers/amlogic/media/video_sink/video_priv.h index 2bef2919fbea..77144c358b53 100644 --- a/drivers/amlogic/media/video_sink/video_priv.h +++ b/drivers/amlogic/media/video_sink/video_priv.h @@ -58,7 +58,9 @@ u32 get_video_enabled(void); int ext_frame_capture_poll(int endflags); #endif -/*extern u32 disp_canvas_index[2][6];*/ +#ifdef CONFIG_AMLOGIC_MEDIA_VSYNC_RDMA +extern u32 disp_canvas_index[2][6]; +#endif #endif /*VIDEO_PRIV_HEADER_HH*/ diff --git a/include/linux/amlogic/display/vinfo.h b/include/linux/amlogic/display/vinfo.h deleted file mode 100644 index ca7ff2a99e12..000000000000 --- a/include/linux/amlogic/display/vinfo.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * include/linux/amlogic/display/vinfo.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 _VINFO_H_ -#define _VINFO_H_ -#include - -/* the MSB is represent vmode set by vmode_init */ -#define VMODE_INIT_BIT_MASK 0x8000 -#define VMODE_MODE_BIT_MASK 0xff - -enum vmode_e { - VMODE_HDMI, - VMODE_CVBS, - VMODE_LCD, - VMODE_NULL, /* null mode is used as temporary witch mode state */ - VMODE_MAX, - VMODE_INIT_NULL, - VMODE_MASK = 0xFF, -}; - -#define SUPPORT_2020 0x01 - -/* master_display_info for display device */ -struct master_display_info_s { - u32 present_flag; - u32 features; /* feature bits bt2020/2084 */ - u32 primaries[3][2]; /* normalized 50000 in G,B,R order */ - u32 white_point[2]; /* normalized 50000 */ - u32 luminance[2]; /* max/min lumin, normalized 10000 */ -}; - -struct vinfo_s { - char *name; - enum vmode_e mode; - char ext_name[32]; - u32 width; - u32 height; - u32 field_height; - u32 aspect_ratio_num; - u32 aspect_ratio_den; - u32 screen_real_width; - u32 screen_real_height; - u32 sync_duration_num; - u32 sync_duration_den; - u32 video_clk; - enum color_fmt_e viu_color_fmt; - struct master_display_info_s master_display_info; - void *vout_device; -}; - -#endif /* _VINFO_H_ */ diff --git a/include/linux/amlogic/media/ge2d/ge2d.h b/include/linux/amlogic/media/ge2d/ge2d.h index 4d4de5a4c34f..72c43af45976 100644 --- a/include/linux/amlogic/media/ge2d/ge2d.h +++ b/include/linux/amlogic/media/ge2d/ge2d.h @@ -123,6 +123,7 @@ #define MATRIX_YCC_TO_RGB 1 #define MATRIX_RGB_TO_YCC 2 #define MATRIX_FULL_RANGE_YCC_TO_RGB 3 +#define MATRIX_RGB_TO_FULL_RANGE_YCC 4 #define GE2D_ENDIAN_SHIFT 24 @@ -815,6 +816,13 @@ struct compat_config_para_ex_s { _IOW(GE2D_IOC_MAGIC, 0x01, struct compat_config_para_ex_s) #endif +#define GE2D_SRCCOLORKEY _IOW(GE2D_IOC_MAGIC, 0x02, struct config_para_s) + +#ifdef CONFIG_COMPAT +#define GE2D_SRCCOLORKEY32 \ + _IOW(GE2D_IOC_MAGIC, 0x02, struct compat_config_para_s) +#endif + extern void ge2d_set_src1_data(struct ge2d_src1_data_s *cfg); extern void ge2d_set_src1_gen(struct ge2d_src1_gen_s *cfg); extern void ge2d_set_src2_dst_data(struct ge2d_src2_dst_data_s *cfg); diff --git a/include/linux/amlogic/media/ge2d/ge2d_cmd.h b/include/linux/amlogic/media/ge2d/ge2d_cmd.h index 4fdbc593c6b8..7e25cf4a3db8 100644 --- a/include/linux/amlogic/media/ge2d/ge2d_cmd.h +++ b/include/linux/amlogic/media/ge2d/ge2d_cmd.h @@ -18,6 +18,8 @@ #ifndef _GE2D_CMD_H_ #define _GE2D_CMD_H_ +#define GE2D_BLEND_NOALPHA_NOBLOCK 0x470a +#define GE2D_BLEND_NOALPHA 0x4709 #define GE2D_STRETCHBLIT_NOALPHA_NOBLOCK 0x4708 #define GE2D_BLIT_NOALPHA_NOBLOCK 0x4707 #define GE2D_BLEND_NOBLOCK 0x4706 @@ -32,10 +34,10 @@ #define GE2D_BLIT 0x46ff #define GE2D_STRETCHBLIT 0x46fe #define GE2D_FILLRECTANGLE 0x46fd -#define GE2D_SRCCOLORKEY 0x46fc +#define GE2D_SRCCOLORKEY_OLD 0x46fc #define GE2D_SET_COEF 0x46fb -/* #define GE2D_CONFIG_EX 0x46fa */ -/* #define GE2D_CONFIG 0x46f9 */ +#define GE2D_CONFIG_EX_OLD 0x46fa +#define GE2D_CONFIG_OLD 0x46f9 #define GE2D_ANTIFLICKER_ENABLE 0x46f8 #endif diff --git a/include/linux/amlogic/media/ge2d/ge2d_func.h b/include/linux/amlogic/media/ge2d/ge2d_func.h index c09240bb82dd..1ea8ec0a3488 100644 --- a/include/linux/amlogic/media/ge2d/ge2d_func.h +++ b/include/linux/amlogic/media/ge2d/ge2d_func.h @@ -110,4 +110,15 @@ void blend_noblk(struct ge2d_context_s *wq, int dst_x, int dst_y, int dst_w, int dst_h, int op); +void blend_noalpha(struct ge2d_context_s *wq, + int src_x, int src_y, int src_w, int src_h, + int src2_x, int src2_y, int src2_w, int src2_h, + int dst_x, int dst_y, int dst_w, int dst_h, + int op); + +void blend_noalpha_noblk(struct ge2d_context_s *wq, + int src_x, int src_y, int src_w, int src_h, + int src2_x, int src2_y, int src2_w, int src2_h, + int dst_x, int dst_y, int dst_w, int dst_h, + int op); #endif diff --git a/include/linux/amlogic/media/rdma/rdma_mgr.h b/include/linux/amlogic/media/rdma/rdma_mgr.h index 2367fd1b537f..a724a011f71d 100644 --- a/include/linux/amlogic/media/rdma/rdma_mgr.h +++ b/include/linux/amlogic/media/rdma/rdma_mgr.h @@ -23,9 +23,11 @@ struct rdma_op_s { void *arg; }; +#define RDMA_TRIGGER_VSYNC_INPUT 0x1 #define RDMA_TRIGGER_MANUAL 0x100 #define RDMA_TRIGGER_DEBUG1 0x101 #define RDMA_TRIGGER_DEBUG2 0x102 +#define RDMA_AUTO_START_MASK 0x80000 /* * rdma_read_reg(), rdma_write_reg(), rdma_clear() can only be called diff --git a/include/linux/amlogic/media/video_sink/video/video.h b/include/linux/amlogic/media/video_sink/video/video.h index c4d9146e3597..252a7e66307d 100644 --- a/include/linux/amlogic/media/video_sink/video/video.h +++ b/include/linux/amlogic/media/video_sink/video/video.h @@ -17,7 +17,7 @@ #ifndef VIDEO_HEADER_ #define VIDEO_HEADER_ -#ifdef CONFIG_VSYNC_RDMA +#ifdef CONFIG_AMLOGIC_MEDIA_VSYNC_RDMA int VSYNC_WR_MPEG_REG(u32 adr, u32 val); int VSYNC_WR_MPEG_REG_BITS(u32 adr, u32 val, u32 start, u32 len); diff --git a/include/linux/amlogic/media/vout/vout_notify.h b/include/linux/amlogic/media/vout/vout_notify.h index 8dd27abce3dc..3aa93ed94de3 100644 --- a/include/linux/amlogic/media/vout/vout_notify.h +++ b/include/linux/amlogic/media/vout/vout_notify.h @@ -13,7 +13,7 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * -*/ + */ #ifndef _VOUT_NOTIFY_H_ #define _VOUT_NOTIFY_H_