video: Add Meson Video Processing Unit Driver
This adds video output support for Amlogic GXBB/GXL/GXM chips.
The supported ports are CVBS and HDMI (based on DW_HDMI).
When using HDMI, only DMT modes are supported.
There is support for simple-framebuffer (CONFIG_VIDEO_DT_SIMPLEFB)
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
Signed-off-by: Jorge Ramire-Ortiz <jramirez@baylibre.com>
Signed-off-by: Maxime Jourdan <mjourdan@baylibre.com>
[narmstrong: fixed defines alignment in meson_canvas.c]
Reviewed-by: Anatolij Gustschin <agust@denx.de>
diff --git a/drivers/video/meson/meson_venc.c b/drivers/video/meson/meson_venc.c
new file mode 100644
index 0000000..d137dde
--- /dev/null
+++ b/drivers/video/meson/meson_venc.c
@@ -0,0 +1,1464 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Amlogic Meson Video Processing Unit driver
+ *
+ * Copyright (c) 2018 BayLibre, SAS.
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ */
+
+#include <edid.h>
+#include "meson_vpu.h"
+
+enum {
+ MESON_VENC_MODE_NONE = 0,
+ MESON_VENC_MODE_CVBS_PAL,
+ MESON_VENC_MODE_CVBS_NTSC,
+ MESON_VENC_MODE_HDMI,
+};
+
+enum meson_venc_source {
+ MESON_VENC_SOURCE_NONE = 0,
+ MESON_VENC_SOURCE_ENCI = 1,
+ MESON_VENC_SOURCE_ENCP = 2,
+};
+
+#define HHI_VDAC_CNTL0 0x2F4 /* 0xbd offset in data sheet */
+#define HHI_VDAC_CNTL1 0x2F8 /* 0xbe offset in data sheet */
+
+struct meson_cvbs_enci_mode {
+ unsigned int mode_tag;
+ unsigned int hso_begin; /* HSO begin position */
+ unsigned int hso_end; /* HSO end position */
+ unsigned int vso_even; /* VSO even line */
+ unsigned int vso_odd; /* VSO odd line */
+ unsigned int macv_max_amp; /* Macrovision max amplitude */
+ unsigned int video_prog_mode;
+ unsigned int video_mode;
+ unsigned int sch_adjust;
+ unsigned int yc_delay;
+ unsigned int pixel_start;
+ unsigned int pixel_end;
+ unsigned int top_field_line_start;
+ unsigned int top_field_line_end;
+ unsigned int bottom_field_line_start;
+ unsigned int bottom_field_line_end;
+ unsigned int video_saturation;
+ unsigned int video_contrast;
+ unsigned int video_brightness;
+ unsigned int video_hue;
+ unsigned int analog_sync_adj;
+};
+
+struct meson_cvbs_enci_mode meson_cvbs_enci_pal = {
+ .mode_tag = MESON_VENC_MODE_CVBS_PAL,
+ .hso_begin = 3,
+ .hso_end = 129,
+ .vso_even = 3,
+ .vso_odd = 260,
+ .macv_max_amp = 7,
+ .video_prog_mode = 0xff,
+ .video_mode = 0x13,
+ .sch_adjust = 0x28,
+ .yc_delay = 0x343,
+ .pixel_start = 251,
+ .pixel_end = 1691,
+ .top_field_line_start = 22,
+ .top_field_line_end = 310,
+ .bottom_field_line_start = 23,
+ .bottom_field_line_end = 311,
+ .video_saturation = 9,
+ .video_contrast = 0,
+ .video_brightness = 0,
+ .video_hue = 0,
+ .analog_sync_adj = 0x8080,
+};
+
+struct meson_cvbs_enci_mode meson_cvbs_enci_ntsc = {
+ .mode_tag = MESON_VENC_MODE_CVBS_NTSC,
+ .hso_begin = 5,
+ .hso_end = 129,
+ .vso_even = 3,
+ .vso_odd = 260,
+ .macv_max_amp = 0xb,
+ .video_prog_mode = 0xf0,
+ .video_mode = 0x8,
+ .sch_adjust = 0x20,
+ .yc_delay = 0x333,
+ .pixel_start = 227,
+ .pixel_end = 1667,
+ .top_field_line_start = 18,
+ .top_field_line_end = 258,
+ .bottom_field_line_start = 19,
+ .bottom_field_line_end = 259,
+ .video_saturation = 18,
+ .video_contrast = 3,
+ .video_brightness = 0,
+ .video_hue = 0,
+ .analog_sync_adj = 0x9c00,
+};
+
+union meson_hdmi_venc_mode {
+ struct {
+ unsigned int mode_tag;
+ unsigned int hso_begin;
+ unsigned int hso_end;
+ unsigned int vso_even;
+ unsigned int vso_odd;
+ unsigned int macv_max_amp;
+ unsigned int video_prog_mode;
+ unsigned int video_mode;
+ unsigned int sch_adjust;
+ unsigned int yc_delay;
+ unsigned int pixel_start;
+ unsigned int pixel_end;
+ unsigned int top_field_line_start;
+ unsigned int top_field_line_end;
+ unsigned int bottom_field_line_start;
+ unsigned int bottom_field_line_end;
+ } enci;
+ struct {
+ unsigned int dvi_settings;
+ unsigned int video_mode;
+ unsigned int video_mode_adv;
+ unsigned int video_prog_mode;
+ bool video_prog_mode_present;
+ unsigned int video_sync_mode;
+ bool video_sync_mode_present;
+ unsigned int video_yc_dly;
+ bool video_yc_dly_present;
+ unsigned int video_rgb_ctrl;
+ bool video_rgb_ctrl_present;
+ unsigned int video_filt_ctrl;
+ bool video_filt_ctrl_present;
+ unsigned int video_ofld_voav_ofst;
+ bool video_ofld_voav_ofst_present;
+ unsigned int yfp1_htime;
+ unsigned int yfp2_htime;
+ unsigned int max_pxcnt;
+ unsigned int hspuls_begin;
+ unsigned int hspuls_end;
+ unsigned int hspuls_switch;
+ unsigned int vspuls_begin;
+ unsigned int vspuls_end;
+ unsigned int vspuls_bline;
+ unsigned int vspuls_eline;
+ unsigned int eqpuls_begin;
+ bool eqpuls_begin_present;
+ unsigned int eqpuls_end;
+ bool eqpuls_end_present;
+ unsigned int eqpuls_bline;
+ bool eqpuls_bline_present;
+ unsigned int eqpuls_eline;
+ bool eqpuls_eline_present;
+ unsigned int havon_begin;
+ unsigned int havon_end;
+ unsigned int vavon_bline;
+ unsigned int vavon_eline;
+ unsigned int hso_begin;
+ unsigned int hso_end;
+ unsigned int vso_begin;
+ unsigned int vso_end;
+ unsigned int vso_bline;
+ unsigned int vso_eline;
+ bool vso_eline_present;
+ unsigned int sy_val;
+ bool sy_val_present;
+ unsigned int sy2_val;
+ bool sy2_val_present;
+ unsigned int max_lncnt;
+ } encp;
+};
+
+union meson_hdmi_venc_mode meson_hdmi_enci_mode_480i = {
+ .enci = {
+ .hso_begin = 5,
+ .hso_end = 129,
+ .vso_even = 3,
+ .vso_odd = 260,
+ .macv_max_amp = 0x810b,
+ .video_prog_mode = 0xf0,
+ .video_mode = 0x8,
+ .sch_adjust = 0x20,
+ .yc_delay = 0,
+ .pixel_start = 227,
+ .pixel_end = 1667,
+ .top_field_line_start = 18,
+ .top_field_line_end = 258,
+ .bottom_field_line_start = 19,
+ .bottom_field_line_end = 259,
+ },
+};
+
+union meson_hdmi_venc_mode meson_hdmi_enci_mode_576i = {
+ .enci = {
+ .hso_begin = 3,
+ .hso_end = 129,
+ .vso_even = 3,
+ .vso_odd = 260,
+ .macv_max_amp = 8107,
+ .video_prog_mode = 0xff,
+ .video_mode = 0x13,
+ .sch_adjust = 0x28,
+ .yc_delay = 0x333,
+ .pixel_start = 251,
+ .pixel_end = 1691,
+ .top_field_line_start = 22,
+ .top_field_line_end = 310,
+ .bottom_field_line_start = 23,
+ .bottom_field_line_end = 311,
+ },
+};
+
+union meson_hdmi_venc_mode meson_hdmi_encp_mode_480p = {
+ .encp = {
+ .dvi_settings = 0x21,
+ .video_mode = 0x4000,
+ .video_mode_adv = 0x9,
+ .video_prog_mode = 0,
+ .video_prog_mode_present = true,
+ .video_sync_mode = 7,
+ .video_sync_mode_present = true,
+ /* video_yc_dly */
+ /* video_rgb_ctrl */
+ .video_filt_ctrl = 0x2052,
+ .video_filt_ctrl_present = true,
+ /* video_ofld_voav_ofst */
+ .yfp1_htime = 244,
+ .yfp2_htime = 1630,
+ .max_pxcnt = 1715,
+ .hspuls_begin = 0x22,
+ .hspuls_end = 0xa0,
+ .hspuls_switch = 88,
+ .vspuls_begin = 0,
+ .vspuls_end = 1589,
+ .vspuls_bline = 0,
+ .vspuls_eline = 5,
+ .havon_begin = 249,
+ .havon_end = 1689,
+ .vavon_bline = 42,
+ .vavon_eline = 521,
+ /* eqpuls_begin */
+ /* eqpuls_end */
+ /* eqpuls_bline */
+ /* eqpuls_eline */
+ .hso_begin = 3,
+ .hso_end = 5,
+ .vso_begin = 3,
+ .vso_end = 5,
+ .vso_bline = 0,
+ /* vso_eline */
+ .sy_val = 8,
+ .sy_val_present = true,
+ .sy2_val = 0x1d8,
+ .sy2_val_present = true,
+ .max_lncnt = 524,
+ },
+};
+
+union meson_hdmi_venc_mode meson_hdmi_encp_mode_576p = {
+ .encp = {
+ .dvi_settings = 0x21,
+ .video_mode = 0x4000,
+ .video_mode_adv = 0x9,
+ .video_prog_mode = 0,
+ .video_prog_mode_present = true,
+ .video_sync_mode = 7,
+ .video_sync_mode_present = true,
+ /* video_yc_dly */
+ /* video_rgb_ctrl */
+ .video_filt_ctrl = 0x52,
+ .video_filt_ctrl_present = true,
+ /* video_ofld_voav_ofst */
+ .yfp1_htime = 235,
+ .yfp2_htime = 1674,
+ .max_pxcnt = 1727,
+ .hspuls_begin = 0,
+ .hspuls_end = 0x80,
+ .hspuls_switch = 88,
+ .vspuls_begin = 0,
+ .vspuls_end = 1599,
+ .vspuls_bline = 0,
+ .vspuls_eline = 4,
+ .havon_begin = 235,
+ .havon_end = 1674,
+ .vavon_bline = 44,
+ .vavon_eline = 619,
+ /* eqpuls_begin */
+ /* eqpuls_end */
+ /* eqpuls_bline */
+ /* eqpuls_eline */
+ .hso_begin = 0x80,
+ .hso_end = 0,
+ .vso_begin = 0,
+ .vso_end = 5,
+ .vso_bline = 0,
+ /* vso_eline */
+ .sy_val = 8,
+ .sy_val_present = true,
+ .sy2_val = 0x1d8,
+ .sy2_val_present = true,
+ .max_lncnt = 624,
+ },
+};
+
+union meson_hdmi_venc_mode meson_hdmi_encp_mode_720p60 = {
+ .encp = {
+ .dvi_settings = 0x2029,
+ .video_mode = 0x4040,
+ .video_mode_adv = 0x19,
+ /* video_prog_mode */
+ /* video_sync_mode */
+ /* video_yc_dly */
+ /* video_rgb_ctrl */
+ /* video_filt_ctrl */
+ /* video_ofld_voav_ofst */
+ .yfp1_htime = 648,
+ .yfp2_htime = 3207,
+ .max_pxcnt = 3299,
+ .hspuls_begin = 80,
+ .hspuls_end = 240,
+ .hspuls_switch = 80,
+ .vspuls_begin = 688,
+ .vspuls_end = 3248,
+ .vspuls_bline = 4,
+ .vspuls_eline = 8,
+ .havon_begin = 648,
+ .havon_end = 3207,
+ .vavon_bline = 29,
+ .vavon_eline = 748,
+ /* eqpuls_begin */
+ /* eqpuls_end */
+ /* eqpuls_bline */
+ /* eqpuls_eline */
+ .hso_begin = 256,
+ .hso_end = 168,
+ .vso_begin = 168,
+ .vso_end = 256,
+ .vso_bline = 0,
+ .vso_eline = 5,
+ .vso_eline_present = true,
+ /* sy_val */
+ /* sy2_val */
+ .max_lncnt = 749,
+ },
+};
+
+union meson_hdmi_venc_mode meson_hdmi_encp_mode_720p50 = {
+ .encp = {
+ .dvi_settings = 0x202d,
+ .video_mode = 0x4040,
+ .video_mode_adv = 0x19,
+ .video_prog_mode = 0x100,
+ .video_prog_mode_present = true,
+ .video_sync_mode = 0x407,
+ .video_sync_mode_present = true,
+ .video_yc_dly = 0,
+ .video_yc_dly_present = true,
+ /* video_rgb_ctrl */
+ /* video_filt_ctrl */
+ /* video_ofld_voav_ofst */
+ .yfp1_htime = 648,
+ .yfp2_htime = 3207,
+ .max_pxcnt = 3959,
+ .hspuls_begin = 80,
+ .hspuls_end = 240,
+ .hspuls_switch = 80,
+ .vspuls_begin = 688,
+ .vspuls_end = 3248,
+ .vspuls_bline = 4,
+ .vspuls_eline = 8,
+ .havon_begin = 648,
+ .havon_end = 3207,
+ .vavon_bline = 29,
+ .vavon_eline = 748,
+ /* eqpuls_begin */
+ /* eqpuls_end */
+ /* eqpuls_bline */
+ /* eqpuls_eline */
+ .hso_begin = 128,
+ .hso_end = 208,
+ .vso_begin = 128,
+ .vso_end = 128,
+ .vso_bline = 0,
+ .vso_eline = 5,
+ .vso_eline_present = true,
+ /* sy_val */
+ /* sy2_val */
+ .max_lncnt = 749,
+ },
+};
+
+union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080i60 = {
+ .encp = {
+ .dvi_settings = 0x2029,
+ .video_mode = 0x5ffc,
+ .video_mode_adv = 0x19,
+ .video_prog_mode = 0x100,
+ .video_prog_mode_present = true,
+ .video_sync_mode = 0x207,
+ .video_sync_mode_present = true,
+ /* video_yc_dly */
+ /* video_rgb_ctrl */
+ /* video_filt_ctrl */
+ .video_ofld_voav_ofst = 0x11,
+ .video_ofld_voav_ofst_present = true,
+ .yfp1_htime = 516,
+ .yfp2_htime = 4355,
+ .max_pxcnt = 4399,
+ .hspuls_begin = 88,
+ .hspuls_end = 264,
+ .hspuls_switch = 88,
+ .vspuls_begin = 440,
+ .vspuls_end = 2200,
+ .vspuls_bline = 0,
+ .vspuls_eline = 4,
+ .havon_begin = 516,
+ .havon_end = 4355,
+ .vavon_bline = 20,
+ .vavon_eline = 559,
+ .eqpuls_begin = 2288,
+ .eqpuls_begin_present = true,
+ .eqpuls_end = 2464,
+ .eqpuls_end_present = true,
+ .eqpuls_bline = 0,
+ .eqpuls_bline_present = true,
+ .eqpuls_eline = 4,
+ .eqpuls_eline_present = true,
+ .hso_begin = 264,
+ .hso_end = 176,
+ .vso_begin = 88,
+ .vso_end = 88,
+ .vso_bline = 0,
+ .vso_eline = 5,
+ .vso_eline_present = true,
+ /* sy_val */
+ /* sy2_val */
+ .max_lncnt = 1124,
+ },
+};
+
+union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080i50 = {
+ .encp = {
+ .dvi_settings = 0x202d,
+ .video_mode = 0x5ffc,
+ .video_mode_adv = 0x19,
+ .video_prog_mode = 0x100,
+ .video_prog_mode_present = true,
+ .video_sync_mode = 0x7,
+ .video_sync_mode_present = true,
+ /* video_yc_dly */
+ /* video_rgb_ctrl */
+ /* video_filt_ctrl */
+ .video_ofld_voav_ofst = 0x11,
+ .video_ofld_voav_ofst_present = true,
+ .yfp1_htime = 526,
+ .yfp2_htime = 4365,
+ .max_pxcnt = 5279,
+ .hspuls_begin = 88,
+ .hspuls_end = 264,
+ .hspuls_switch = 88,
+ .vspuls_begin = 440,
+ .vspuls_end = 2200,
+ .vspuls_bline = 0,
+ .vspuls_eline = 4,
+ .havon_begin = 526,
+ .havon_end = 4365,
+ .vavon_bline = 20,
+ .vavon_eline = 559,
+ .eqpuls_begin = 2288,
+ .eqpuls_begin_present = true,
+ .eqpuls_end = 2464,
+ .eqpuls_end_present = true,
+ .eqpuls_bline = 0,
+ .eqpuls_bline_present = true,
+ .eqpuls_eline = 4,
+ .eqpuls_eline_present = true,
+ .hso_begin = 142,
+ .hso_end = 230,
+ .vso_begin = 142,
+ .vso_end = 142,
+ .vso_bline = 0,
+ .vso_eline = 5,
+ .vso_eline_present = true,
+ /* sy_val */
+ /* sy2_val */
+ .max_lncnt = 1124,
+ },
+};
+
+union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p24 = {
+ .encp = {
+ .dvi_settings = 0xd,
+ .video_mode = 0x4040,
+ .video_mode_adv = 0x18,
+ .video_prog_mode = 0x100,
+ .video_prog_mode_present = true,
+ .video_sync_mode = 0x7,
+ .video_sync_mode_present = true,
+ .video_yc_dly = 0,
+ .video_yc_dly_present = true,
+ .video_rgb_ctrl = 2,
+ .video_rgb_ctrl_present = true,
+ .video_filt_ctrl = 0x1052,
+ .video_filt_ctrl_present = true,
+ /* video_ofld_voav_ofst */
+ .yfp1_htime = 271,
+ .yfp2_htime = 2190,
+ .max_pxcnt = 2749,
+ .hspuls_begin = 44,
+ .hspuls_end = 132,
+ .hspuls_switch = 44,
+ .vspuls_begin = 220,
+ .vspuls_end = 2140,
+ .vspuls_bline = 0,
+ .vspuls_eline = 4,
+ .havon_begin = 271,
+ .havon_end = 2190,
+ .vavon_bline = 41,
+ .vavon_eline = 1120,
+ /* eqpuls_begin */
+ /* eqpuls_end */
+ .eqpuls_bline = 0,
+ .eqpuls_bline_present = true,
+ .eqpuls_eline = 4,
+ .eqpuls_eline_present = true,
+ .hso_begin = 79,
+ .hso_end = 123,
+ .vso_begin = 79,
+ .vso_end = 79,
+ .vso_bline = 0,
+ .vso_eline = 5,
+ .vso_eline_present = true,
+ /* sy_val */
+ /* sy2_val */
+ .max_lncnt = 1124,
+ },
+};
+
+union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p30 = {
+ .encp = {
+ .dvi_settings = 0x1,
+ .video_mode = 0x4040,
+ .video_mode_adv = 0x18,
+ .video_prog_mode = 0x100,
+ .video_prog_mode_present = true,
+ /* video_sync_mode */
+ /* video_yc_dly */
+ /* video_rgb_ctrl */
+ .video_filt_ctrl = 0x1052,
+ .video_filt_ctrl_present = true,
+ /* video_ofld_voav_ofst */
+ .yfp1_htime = 140,
+ .yfp2_htime = 2060,
+ .max_pxcnt = 2199,
+ .hspuls_begin = 2156,
+ .hspuls_end = 44,
+ .hspuls_switch = 44,
+ .vspuls_begin = 140,
+ .vspuls_end = 2059,
+ .vspuls_bline = 0,
+ .vspuls_eline = 4,
+ .havon_begin = 148,
+ .havon_end = 2067,
+ .vavon_bline = 41,
+ .vavon_eline = 1120,
+ /* eqpuls_begin */
+ /* eqpuls_end */
+ /* eqpuls_bline */
+ /* eqpuls_eline */
+ .hso_begin = 44,
+ .hso_end = 2156,
+ .vso_begin = 2100,
+ .vso_end = 2164,
+ .vso_bline = 0,
+ .vso_eline = 5,
+ .vso_eline_present = true,
+ /* sy_val */
+ /* sy2_val */
+ .max_lncnt = 1124,
+ },
+};
+
+union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p50 = {
+ .encp = {
+ .dvi_settings = 0xd,
+ .video_mode = 0x4040,
+ .video_mode_adv = 0x18,
+ .video_prog_mode = 0x100,
+ .video_prog_mode_present = true,
+ .video_sync_mode = 0x7,
+ .video_sync_mode_present = true,
+ .video_yc_dly = 0,
+ .video_yc_dly_present = true,
+ .video_rgb_ctrl = 2,
+ .video_rgb_ctrl_present = true,
+ /* video_filt_ctrl */
+ /* video_ofld_voav_ofst */
+ .yfp1_htime = 271,
+ .yfp2_htime = 2190,
+ .max_pxcnt = 2639,
+ .hspuls_begin = 44,
+ .hspuls_end = 132,
+ .hspuls_switch = 44,
+ .vspuls_begin = 220,
+ .vspuls_end = 2140,
+ .vspuls_bline = 0,
+ .vspuls_eline = 4,
+ .havon_begin = 271,
+ .havon_end = 2190,
+ .vavon_bline = 41,
+ .vavon_eline = 1120,
+ /* eqpuls_begin */
+ /* eqpuls_end */
+ .eqpuls_bline = 0,
+ .eqpuls_bline_present = true,
+ .eqpuls_eline = 4,
+ .eqpuls_eline_present = true,
+ .hso_begin = 79,
+ .hso_end = 123,
+ .vso_begin = 79,
+ .vso_end = 79,
+ .vso_bline = 0,
+ .vso_eline = 5,
+ .vso_eline_present = true,
+ /* sy_val */
+ /* sy2_val */
+ .max_lncnt = 1124,
+ },
+};
+
+union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p60 = {
+ .encp = {
+ .dvi_settings = 0x1,
+ .video_mode = 0x4040,
+ .video_mode_adv = 0x18,
+ .video_prog_mode = 0x100,
+ .video_prog_mode_present = true,
+ /* video_sync_mode */
+ /* video_yc_dly */
+ /* video_rgb_ctrl */
+ .video_filt_ctrl = 0x1052,
+ .video_filt_ctrl_present = true,
+ /* video_ofld_voav_ofst */
+ .yfp1_htime = 140,
+ .yfp2_htime = 2060,
+ .max_pxcnt = 2199,
+ .hspuls_begin = 2156,
+ .hspuls_end = 44,
+ .hspuls_switch = 44,
+ .vspuls_begin = 140,
+ .vspuls_end = 2059,
+ .vspuls_bline = 0,
+ .vspuls_eline = 4,
+ .havon_begin = 148,
+ .havon_end = 2067,
+ .vavon_bline = 41,
+ .vavon_eline = 1120,
+ /* eqpuls_begin */
+ /* eqpuls_end */
+ /* eqpuls_bline */
+ /* eqpuls_eline */
+ .hso_begin = 44,
+ .hso_end = 2156,
+ .vso_begin = 2100,
+ .vso_end = 2164,
+ .vso_bline = 0,
+ .vso_eline = 5,
+ .vso_eline_present = true,
+ /* sy_val */
+ /* sy2_val */
+ .max_lncnt = 1124,
+ },
+};
+
+static signed int to_signed(unsigned int a)
+{
+ if (a <= 7)
+ return a;
+ else
+ return a - 16;
+}
+
+static unsigned long modulo(unsigned long a, unsigned long b)
+{
+ if (a >= b)
+ return a - b;
+ else
+ return a;
+}
+
+bool meson_venc_hdmi_supported_mode(const struct display_timing *mode)
+{
+ if (mode->flags & ~(DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_HSYNC_HIGH |
+ DISPLAY_FLAGS_VSYNC_LOW | DISPLAY_FLAGS_VSYNC_HIGH))
+ return false;
+
+ if (mode->hactive.typ < 640 || mode->hactive.typ > 1920)
+ return false;
+
+ if (mode->vactive.typ < 480 || mode->vactive.typ > 1200)
+ return false;
+
+ return true;
+}
+
+static void meson_venc_hdmi_get_dmt_vmode(const struct display_timing *mode,
+ union meson_hdmi_venc_mode *dmt_mode)
+{
+ memset(dmt_mode, 0, sizeof(*dmt_mode));
+
+ dmt_mode->encp.dvi_settings = 0x21;
+ dmt_mode->encp.video_mode = 0x4040;
+ dmt_mode->encp.video_mode_adv = 0x18;
+
+ dmt_mode->encp.max_pxcnt = mode->hactive.typ +
+ mode->hfront_porch.typ +
+ mode->hback_porch.typ +
+ mode->hsync_len.typ - 1;
+
+ dmt_mode->encp.havon_begin = mode->hback_porch.typ +
+ mode->hsync_len.typ;
+
+ dmt_mode->encp.havon_end = dmt_mode->encp.havon_begin +
+ mode->hactive.typ - 1;
+
+ dmt_mode->encp.vavon_bline = mode->vback_porch.typ +
+ mode->vsync_len.typ;
+ dmt_mode->encp.vavon_eline = dmt_mode->encp.vavon_bline +
+ mode->vactive.typ - 1;
+
+ /* to investigate */
+ dmt_mode->encp.hso_begin = 0;
+ dmt_mode->encp.hso_end = mode->hsync_len.typ;
+ dmt_mode->encp.vso_begin = 30;
+ dmt_mode->encp.vso_end = 50;
+
+ dmt_mode->encp.vso_bline = 0;
+ dmt_mode->encp.vso_eline = mode->vsync_len.typ;
+ dmt_mode->encp.vso_eline_present = true;
+
+ dmt_mode->encp.max_lncnt = mode->vactive.typ +
+ mode->vfront_porch.typ +
+ mode->vback_porch.typ +
+ mode->vsync_len.typ - 1;
+}
+
+static void meson_venc_hdmi_mode_set(struct meson_vpu_priv *priv,
+ const struct display_timing *mode)
+{
+ union meson_hdmi_venc_mode *vmode = NULL;
+ union meson_hdmi_venc_mode vmode_dmt;
+ bool use_enci = false;
+ bool venc_repeat = false;
+ bool hdmi_repeat = false;
+ unsigned int venc_hdmi_latency = 2;
+ unsigned long total_pixels_venc = 0;
+ unsigned long active_pixels_venc = 0;
+ unsigned long front_porch_venc = 0;
+ unsigned long hsync_pixels_venc = 0;
+ unsigned long de_h_begin = 0;
+ unsigned long de_h_end = 0;
+ unsigned long de_v_begin_even = 0;
+ unsigned long de_v_end_even = 0;
+ unsigned long de_v_begin_odd = 0;
+ unsigned long de_v_end_odd = 0;
+ unsigned long hs_begin = 0;
+ unsigned long hs_end = 0;
+ unsigned long vs_adjust = 0;
+ unsigned long vs_bline_evn = 0;
+ unsigned long vs_eline_evn = 0;
+ unsigned long vs_bline_odd = 0;
+ unsigned long vs_eline_odd = 0;
+ unsigned long vso_begin_evn = 0;
+ unsigned long vso_begin_odd = 0;
+ unsigned int eof_lines;
+ unsigned int sof_lines;
+ unsigned int vsync_lines;
+
+ /* Use VENCI for 480i and 576i and double HDMI pixels */
+ if (mode->flags & DISPLAY_FLAGS_DOUBLECLK) {
+ venc_hdmi_latency = 1;
+ hdmi_repeat = true;
+ use_enci = true;
+ }
+
+ meson_venc_hdmi_get_dmt_vmode(mode, &vmode_dmt);
+ vmode = &vmode_dmt;
+ use_enci = false;
+
+ debug(" max_pxcnt %04d, max_lncnt %04d\n"
+ " havon_begin %04d, havon_end %04d\n"
+ " vavon_bline %04d, vavon_eline %04d\n"
+ " hso_begin %04d, hso_end %04d\n"
+ " vso_begin %04d, vso_end %04d\n"
+ " vso_bline %04d, vso_eline %04d\n",
+ vmode->encp.max_pxcnt, vmode->encp.max_lncnt,
+ vmode->encp.havon_begin, vmode->encp.havon_end,
+ vmode->encp.vavon_bline, vmode->encp.vavon_eline,
+ vmode->encp.hso_begin, vmode->encp.hso_end,
+ vmode->encp.vso_begin, vmode->encp.vso_end,
+ vmode->encp.vso_bline, vmode->encp.vso_eline);
+
+ eof_lines = mode->vfront_porch.typ;
+ if (mode->flags & DISPLAY_FLAGS_INTERLACED)
+ eof_lines /= 2;
+
+ sof_lines = mode->vback_porch.typ;
+ if (mode->flags & DISPLAY_FLAGS_INTERLACED)
+ sof_lines /= 2;
+
+ vsync_lines = mode->vsync_len.typ;
+ if (mode->flags & DISPLAY_FLAGS_INTERLACED)
+ vsync_lines /= 2;
+
+ total_pixels_venc = mode->hback_porch.typ + mode->hactive.typ +
+ mode->hfront_porch.typ + mode->hsync_len.typ;
+ if (hdmi_repeat)
+ total_pixels_venc /= 2;
+ if (venc_repeat)
+ total_pixels_venc *= 2;
+
+ active_pixels_venc = mode->hactive.typ;
+ if (hdmi_repeat)
+ active_pixels_venc /= 2;
+ if (venc_repeat)
+ active_pixels_venc *= 2;
+
+ front_porch_venc = mode->hfront_porch.typ;
+ if (hdmi_repeat)
+ front_porch_venc /= 2;
+ if (venc_repeat)
+ front_porch_venc *= 2;
+
+ hsync_pixels_venc = mode->hsync_len.typ;
+ if (hdmi_repeat)
+ hsync_pixels_venc /= 2;
+ if (venc_repeat)
+ hsync_pixels_venc *= 2;
+
+ /* Disable VDACs */
+ writel_bits(0xff, 0xff,
+ priv->io_base + _REG(VENC_VDAC_SETTING));
+
+ writel(0, priv->io_base + _REG(ENCI_VIDEO_EN));
+ writel(0, priv->io_base + _REG(ENCP_VIDEO_EN));
+
+ debug("use_enci: %d, hdmi_repeat: %d\n", use_enci, hdmi_repeat);
+
+ if (use_enci) {
+ unsigned int lines_f0;
+ unsigned int lines_f1;
+
+ /* CVBS Filter settings */
+ writel(0x12, priv->io_base + _REG(ENCI_CFILT_CTRL));
+ writel(0x12, priv->io_base + _REG(ENCI_CFILT_CTRL2));
+
+ /* Digital Video Select : Interlace, clk27 clk, external */
+ writel(0, priv->io_base + _REG(VENC_DVI_SETTING));
+
+ /* Reset Video Mode */
+ writel(0, priv->io_base + _REG(ENCI_VIDEO_MODE));
+ writel(0, priv->io_base + _REG(ENCI_VIDEO_MODE_ADV));
+
+ /* Horizontal sync signal output */
+ writel(vmode->enci.hso_begin,
+ priv->io_base + _REG(ENCI_SYNC_HSO_BEGIN));
+ writel(vmode->enci.hso_end,
+ priv->io_base + _REG(ENCI_SYNC_HSO_END));
+
+ /* Vertical Sync lines */
+ writel(vmode->enci.vso_even,
+ priv->io_base + _REG(ENCI_SYNC_VSO_EVNLN));
+ writel(vmode->enci.vso_odd,
+ priv->io_base + _REG(ENCI_SYNC_VSO_ODDLN));
+
+ /* Macrovision max amplitude change */
+ writel(vmode->enci.macv_max_amp,
+ priv->io_base + _REG(ENCI_MACV_MAX_AMP));
+
+ /* Video mode */
+ writel(vmode->enci.video_prog_mode,
+ priv->io_base + _REG(VENC_VIDEO_PROG_MODE));
+ writel(vmode->enci.video_mode,
+ priv->io_base + _REG(ENCI_VIDEO_MODE));
+
+ /* Advanced Video Mode :
+ * Demux shifting 0x2
+ * Blank line end at line17/22
+ * High bandwidth Luma Filter
+ * Low bandwidth Chroma Filter
+ * Bypass luma low pass filter
+ * No macrovision on CSYNC
+ */
+ writel(0x26, priv->io_base + _REG(ENCI_VIDEO_MODE_ADV));
+
+ writel(vmode->enci.sch_adjust,
+ priv->io_base + _REG(ENCI_VIDEO_SCH));
+
+ /* Sync mode : MASTER Master mode, free run, send HSO/VSO out */
+ writel(0x07, priv->io_base + _REG(ENCI_SYNC_MODE));
+
+ if (vmode->enci.yc_delay)
+ writel(vmode->enci.yc_delay,
+ priv->io_base + _REG(ENCI_YC_DELAY));
+
+ /* UNreset Interlaced TV Encoder */
+ writel(0, priv->io_base + _REG(ENCI_DBG_PX_RST));
+
+ /* Enable Vfifo2vd, Y_Cb_Y_Cr select */
+ writel(0x4e01, priv->io_base + _REG(ENCI_VFIFO2VD_CTL));
+
+ /* Timings */
+ writel(vmode->enci.pixel_start,
+ priv->io_base + _REG(ENCI_VFIFO2VD_PIXEL_START));
+ writel(vmode->enci.pixel_end,
+ priv->io_base + _REG(ENCI_VFIFO2VD_PIXEL_END));
+
+ writel(vmode->enci.top_field_line_start,
+ priv->io_base + _REG(ENCI_VFIFO2VD_LINE_TOP_START));
+ writel(vmode->enci.top_field_line_end,
+ priv->io_base + _REG(ENCI_VFIFO2VD_LINE_TOP_END));
+
+ writel(vmode->enci.bottom_field_line_start,
+ priv->io_base + _REG(ENCI_VFIFO2VD_LINE_BOT_START));
+ writel(vmode->enci.bottom_field_line_end,
+ priv->io_base + _REG(ENCI_VFIFO2VD_LINE_BOT_END));
+
+ /* Select ENCI for VIU */
+ meson_vpp_setup_mux(priv, MESON_VIU_VPP_MUX_ENCI);
+
+ /* Interlace video enable */
+ writel(1, priv->io_base + _REG(ENCI_VIDEO_EN));
+
+ lines_f0 = mode->vback_porch.typ + mode->vactive.typ +
+ mode->vback_porch.typ + mode->vsync_len.typ;
+ lines_f0 = lines_f0 >> 1;
+ lines_f1 = lines_f0 + 1;
+
+ de_h_begin = modulo(readl(priv->io_base +
+ _REG(ENCI_VFIFO2VD_PIXEL_START))
+ + venc_hdmi_latency,
+ total_pixels_venc);
+ de_h_end = modulo(de_h_begin + active_pixels_venc,
+ total_pixels_venc);
+
+ writel(de_h_begin,
+ priv->io_base + _REG(ENCI_DE_H_BEGIN));
+ writel(de_h_end,
+ priv->io_base + _REG(ENCI_DE_H_END));
+
+ de_v_begin_even = readl(priv->io_base +
+ _REG(ENCI_VFIFO2VD_LINE_TOP_START));
+ de_v_end_even = de_v_begin_even + mode->vactive.typ;
+ de_v_begin_odd = readl(priv->io_base +
+ _REG(ENCI_VFIFO2VD_LINE_BOT_START));
+ de_v_end_odd = de_v_begin_odd + mode->vactive.typ;
+
+ writel(de_v_begin_even,
+ priv->io_base + _REG(ENCI_DE_V_BEGIN_EVEN));
+ writel(de_v_end_even,
+ priv->io_base + _REG(ENCI_DE_V_END_EVEN));
+ writel(de_v_begin_odd,
+ priv->io_base + _REG(ENCI_DE_V_BEGIN_ODD));
+ writel(de_v_end_odd,
+ priv->io_base + _REG(ENCI_DE_V_END_ODD));
+
+ /* Program Hsync timing */
+ hs_begin = de_h_end + front_porch_venc;
+ if (de_h_end + front_porch_venc >= total_pixels_venc) {
+ hs_begin -= total_pixels_venc;
+ vs_adjust = 1;
+ } else {
+ hs_begin = de_h_end + front_porch_venc;
+ vs_adjust = 0;
+ }
+
+ hs_end = modulo(hs_begin + hsync_pixels_venc,
+ total_pixels_venc);
+ writel(hs_begin,
+ priv->io_base + _REG(ENCI_DVI_HSO_BEGIN));
+ writel(hs_end,
+ priv->io_base + _REG(ENCI_DVI_HSO_END));
+
+ /* Program Vsync timing for even field */
+ if (((de_v_end_odd - 1) + eof_lines + vs_adjust) >= lines_f1) {
+ vs_bline_evn = (de_v_end_odd - 1)
+ + eof_lines
+ + vs_adjust
+ - lines_f1;
+ vs_eline_evn = vs_bline_evn + vsync_lines;
+
+ writel(vs_bline_evn,
+ priv->io_base + _REG(ENCI_DVI_VSO_BLINE_EVN));
+
+ writel(vs_eline_evn,
+ priv->io_base + _REG(ENCI_DVI_VSO_ELINE_EVN));
+
+ writel(hs_begin,
+ priv->io_base + _REG(ENCI_DVI_VSO_BEGIN_EVN));
+ writel(hs_begin,
+ priv->io_base + _REG(ENCI_DVI_VSO_END_EVN));
+ } else {
+ vs_bline_odd = (de_v_end_odd - 1)
+ + eof_lines
+ + vs_adjust;
+
+ writel(vs_bline_odd,
+ priv->io_base + _REG(ENCI_DVI_VSO_BLINE_ODD));
+
+ writel(hs_begin,
+ priv->io_base + _REG(ENCI_DVI_VSO_BEGIN_ODD));
+
+ if ((vs_bline_odd + vsync_lines) >= lines_f1) {
+ vs_eline_evn = vs_bline_odd
+ + vsync_lines
+ - lines_f1;
+
+ writel(vs_eline_evn, priv->io_base
+ + _REG(ENCI_DVI_VSO_ELINE_EVN));
+
+ writel(hs_begin, priv->io_base
+ + _REG(ENCI_DVI_VSO_END_EVN));
+ } else {
+ vs_eline_odd = vs_bline_odd
+ + vsync_lines;
+
+ writel(vs_eline_odd, priv->io_base
+ + _REG(ENCI_DVI_VSO_ELINE_ODD));
+
+ writel(hs_begin, priv->io_base
+ + _REG(ENCI_DVI_VSO_END_ODD));
+ }
+ }
+
+ /* Program Vsync timing for odd field */
+ if (((de_v_end_even - 1) + (eof_lines + 1)) >= lines_f0) {
+ vs_bline_odd = (de_v_end_even - 1)
+ + (eof_lines + 1)
+ - lines_f0;
+ vs_eline_odd = vs_bline_odd + vsync_lines;
+
+ writel(vs_bline_odd,
+ priv->io_base + _REG(ENCI_DVI_VSO_BLINE_ODD));
+
+ writel(vs_eline_odd,
+ priv->io_base + _REG(ENCI_DVI_VSO_ELINE_ODD));
+
+ vso_begin_odd = modulo(hs_begin
+ + (total_pixels_venc >> 1),
+ total_pixels_venc);
+
+ writel(vso_begin_odd,
+ priv->io_base + _REG(ENCI_DVI_VSO_BEGIN_ODD));
+ writel(vso_begin_odd,
+ priv->io_base + _REG(ENCI_DVI_VSO_END_ODD));
+ } else {
+ vs_bline_evn = (de_v_end_even - 1)
+ + (eof_lines + 1);
+
+ writel(vs_bline_evn,
+ priv->io_base + _REG(ENCI_DVI_VSO_BLINE_EVN));
+
+ vso_begin_evn = modulo(hs_begin
+ + (total_pixels_venc >> 1),
+ total_pixels_venc);
+
+ writel(vso_begin_evn, priv->io_base
+ + _REG(ENCI_DVI_VSO_BEGIN_EVN));
+
+ if (vs_bline_evn + vsync_lines >= lines_f0) {
+ vs_eline_odd = vs_bline_evn
+ + vsync_lines
+ - lines_f0;
+
+ writel(vs_eline_odd, priv->io_base
+ + _REG(ENCI_DVI_VSO_ELINE_ODD));
+
+ writel(vso_begin_evn, priv->io_base
+ + _REG(ENCI_DVI_VSO_END_ODD));
+ } else {
+ vs_eline_evn = vs_bline_evn + vsync_lines;
+
+ writel(vs_eline_evn, priv->io_base
+ + _REG(ENCI_DVI_VSO_ELINE_EVN));
+
+ writel(vso_begin_evn, priv->io_base
+ + _REG(ENCI_DVI_VSO_END_EVN));
+ }
+ }
+ } else {
+ writel(vmode->encp.dvi_settings,
+ priv->io_base + _REG(VENC_DVI_SETTING));
+ writel(vmode->encp.video_mode,
+ priv->io_base + _REG(ENCP_VIDEO_MODE));
+ writel(vmode->encp.video_mode_adv,
+ priv->io_base + _REG(ENCP_VIDEO_MODE_ADV));
+ if (vmode->encp.video_prog_mode_present)
+ writel(vmode->encp.video_prog_mode,
+ priv->io_base + _REG(VENC_VIDEO_PROG_MODE));
+ if (vmode->encp.video_sync_mode_present)
+ writel(vmode->encp.video_sync_mode,
+ priv->io_base + _REG(ENCP_VIDEO_SYNC_MODE));
+ if (vmode->encp.video_yc_dly_present)
+ writel(vmode->encp.video_yc_dly,
+ priv->io_base + _REG(ENCP_VIDEO_YC_DLY));
+ if (vmode->encp.video_rgb_ctrl_present)
+ writel(vmode->encp.video_rgb_ctrl,
+ priv->io_base + _REG(ENCP_VIDEO_RGB_CTRL));
+ if (vmode->encp.video_filt_ctrl_present)
+ writel(vmode->encp.video_filt_ctrl,
+ priv->io_base + _REG(ENCP_VIDEO_FILT_CTRL));
+ if (vmode->encp.video_ofld_voav_ofst_present)
+ writel(vmode->encp.video_ofld_voav_ofst,
+ priv->io_base
+ + _REG(ENCP_VIDEO_OFLD_VOAV_OFST));
+ writel(vmode->encp.yfp1_htime,
+ priv->io_base + _REG(ENCP_VIDEO_YFP1_HTIME));
+ writel(vmode->encp.yfp2_htime,
+ priv->io_base + _REG(ENCP_VIDEO_YFP2_HTIME));
+ writel(vmode->encp.max_pxcnt,
+ priv->io_base + _REG(ENCP_VIDEO_MAX_PXCNT));
+ writel(vmode->encp.hspuls_begin,
+ priv->io_base + _REG(ENCP_VIDEO_HSPULS_BEGIN));
+ writel(vmode->encp.hspuls_end,
+ priv->io_base + _REG(ENCP_VIDEO_HSPULS_END));
+ writel(vmode->encp.hspuls_switch,
+ priv->io_base + _REG(ENCP_VIDEO_HSPULS_SWITCH));
+ writel(vmode->encp.vspuls_begin,
+ priv->io_base + _REG(ENCP_VIDEO_VSPULS_BEGIN));
+ writel(vmode->encp.vspuls_end,
+ priv->io_base + _REG(ENCP_VIDEO_VSPULS_END));
+ writel(vmode->encp.vspuls_bline,
+ priv->io_base + _REG(ENCP_VIDEO_VSPULS_BLINE));
+ writel(vmode->encp.vspuls_eline,
+ priv->io_base + _REG(ENCP_VIDEO_VSPULS_ELINE));
+ if (vmode->encp.eqpuls_begin_present)
+ writel(vmode->encp.eqpuls_begin,
+ priv->io_base + _REG(ENCP_VIDEO_EQPULS_BEGIN));
+ if (vmode->encp.eqpuls_end_present)
+ writel(vmode->encp.eqpuls_end,
+ priv->io_base + _REG(ENCP_VIDEO_EQPULS_END));
+ if (vmode->encp.eqpuls_bline_present)
+ writel(vmode->encp.eqpuls_bline,
+ priv->io_base + _REG(ENCP_VIDEO_EQPULS_BLINE));
+ if (vmode->encp.eqpuls_eline_present)
+ writel(vmode->encp.eqpuls_eline,
+ priv->io_base + _REG(ENCP_VIDEO_EQPULS_ELINE));
+ writel(vmode->encp.havon_begin,
+ priv->io_base + _REG(ENCP_VIDEO_HAVON_BEGIN));
+ writel(vmode->encp.havon_end,
+ priv->io_base + _REG(ENCP_VIDEO_HAVON_END));
+ writel(vmode->encp.vavon_bline,
+ priv->io_base + _REG(ENCP_VIDEO_VAVON_BLINE));
+ writel(vmode->encp.vavon_eline,
+ priv->io_base + _REG(ENCP_VIDEO_VAVON_ELINE));
+ writel(vmode->encp.hso_begin,
+ priv->io_base + _REG(ENCP_VIDEO_HSO_BEGIN));
+ writel(vmode->encp.hso_end,
+ priv->io_base + _REG(ENCP_VIDEO_HSO_END));
+ writel(vmode->encp.vso_begin,
+ priv->io_base + _REG(ENCP_VIDEO_VSO_BEGIN));
+ writel(vmode->encp.vso_end,
+ priv->io_base + _REG(ENCP_VIDEO_VSO_END));
+ writel(vmode->encp.vso_bline,
+ priv->io_base + _REG(ENCP_VIDEO_VSO_BLINE));
+ if (vmode->encp.vso_eline_present)
+ writel(vmode->encp.vso_eline,
+ priv->io_base + _REG(ENCP_VIDEO_VSO_ELINE));
+ if (vmode->encp.sy_val_present)
+ writel(vmode->encp.sy_val,
+ priv->io_base + _REG(ENCP_VIDEO_SY_VAL));
+ if (vmode->encp.sy2_val_present)
+ writel(vmode->encp.sy2_val,
+ priv->io_base + _REG(ENCP_VIDEO_SY2_VAL));
+ writel(vmode->encp.max_lncnt,
+ priv->io_base + _REG(ENCP_VIDEO_MAX_LNCNT));
+
+ writel(1, priv->io_base + _REG(ENCP_VIDEO_EN));
+
+ /* Set DE signal's polarity is active high */
+ writel_bits(BIT(14), BIT(14),
+ priv->io_base + _REG(ENCP_VIDEO_MODE));
+
+ /* Program DE timing */
+ de_h_begin = modulo(readl(priv->io_base +
+ _REG(ENCP_VIDEO_HAVON_BEGIN))
+ + venc_hdmi_latency,
+ total_pixels_venc);
+ de_h_end = modulo(de_h_begin + active_pixels_venc,
+ total_pixels_venc);
+
+ writel(de_h_begin,
+ priv->io_base + _REG(ENCP_DE_H_BEGIN));
+ writel(de_h_end,
+ priv->io_base + _REG(ENCP_DE_H_END));
+
+ /* Program DE timing for even field */
+ de_v_begin_even = readl(priv->io_base
+ + _REG(ENCP_VIDEO_VAVON_BLINE));
+ if (mode->flags & DISPLAY_FLAGS_INTERLACED)
+ de_v_end_even = de_v_begin_even +
+ (mode->vactive.typ / 2);
+ else
+ de_v_end_even = de_v_begin_even + mode->vactive.typ;
+
+ writel(de_v_begin_even,
+ priv->io_base + _REG(ENCP_DE_V_BEGIN_EVEN));
+ writel(de_v_end_even,
+ priv->io_base + _REG(ENCP_DE_V_END_EVEN));
+
+ /* Program DE timing for odd field if needed */
+ if (mode->flags & DISPLAY_FLAGS_INTERLACED) {
+ unsigned int ofld_voav_ofst =
+ readl(priv->io_base +
+ _REG(ENCP_VIDEO_OFLD_VOAV_OFST));
+ de_v_begin_odd = to_signed((ofld_voav_ofst & 0xf0) >> 4)
+ + de_v_begin_even
+ + ((mode->vfront_porch.typ +
+ mode->vactive.typ +
+ mode->vsync_len.typ - 1) / 2);
+ de_v_end_odd = de_v_begin_odd + (mode->vactive.typ / 2);
+
+ writel(de_v_begin_odd,
+ priv->io_base + _REG(ENCP_DE_V_BEGIN_ODD));
+ writel(de_v_end_odd,
+ priv->io_base + _REG(ENCP_DE_V_END_ODD));
+ }
+
+ /* Program Hsync timing */
+ if ((de_h_end + front_porch_venc) >= total_pixels_venc) {
+ hs_begin = de_h_end
+ + front_porch_venc
+ - total_pixels_venc;
+ vs_adjust = 1;
+ } else {
+ hs_begin = de_h_end
+ + front_porch_venc;
+ vs_adjust = 0;
+ }
+
+ hs_end = modulo(hs_begin + hsync_pixels_venc,
+ total_pixels_venc);
+
+ writel(hs_begin,
+ priv->io_base + _REG(ENCP_DVI_HSO_BEGIN));
+ writel(hs_end,
+ priv->io_base + _REG(ENCP_DVI_HSO_END));
+
+ /* Program Vsync timing for even field */
+ if (de_v_begin_even >=
+ (sof_lines + vsync_lines + (1 - vs_adjust)))
+ vs_bline_evn = de_v_begin_even
+ - sof_lines
+ - vsync_lines
+ - (1 - vs_adjust);
+ else
+ vs_bline_evn = (mode->vfront_porch.typ +
+ mode->vactive.typ +
+ mode->vsync_len.typ) +
+ + de_v_begin_even
+ - sof_lines
+ - vsync_lines
+ - (1 - vs_adjust);
+
+ vs_eline_evn = modulo(vs_bline_evn + vsync_lines,
+ mode->hfront_porch.typ +
+ mode->hactive.typ +
+ mode->hsync_len.typ);
+
+ writel(vs_bline_evn,
+ priv->io_base + _REG(ENCP_DVI_VSO_BLINE_EVN));
+ writel(vs_eline_evn,
+ priv->io_base + _REG(ENCP_DVI_VSO_ELINE_EVN));
+
+ vso_begin_evn = hs_begin;
+ writel(vso_begin_evn,
+ priv->io_base + _REG(ENCP_DVI_VSO_BEGIN_EVN));
+ writel(vso_begin_evn,
+ priv->io_base + _REG(ENCP_DVI_VSO_END_EVN));
+
+ /* Program Vsync timing for odd field if needed */
+ if (mode->flags & DISPLAY_FLAGS_INTERLACED) {
+ vs_bline_odd = (de_v_begin_odd - 1)
+ - sof_lines
+ - vsync_lines;
+ vs_eline_odd = (de_v_begin_odd - 1)
+ - vsync_lines;
+ vso_begin_odd = modulo(hs_begin
+ + (total_pixels_venc >> 1),
+ total_pixels_venc);
+
+ writel(vs_bline_odd,
+ priv->io_base + _REG(ENCP_DVI_VSO_BLINE_ODD));
+ writel(vs_eline_odd,
+ priv->io_base + _REG(ENCP_DVI_VSO_ELINE_ODD));
+ writel(vso_begin_odd,
+ priv->io_base + _REG(ENCP_DVI_VSO_BEGIN_ODD));
+ writel(vso_begin_odd,
+ priv->io_base + _REG(ENCP_DVI_VSO_END_ODD));
+ }
+
+ /* Select ENCP for VIU */
+ meson_vpp_setup_mux(priv, MESON_VIU_VPP_MUX_ENCP);
+ }
+
+ writel((use_enci ? 1 : 2) |
+ (mode->flags & DISPLAY_FLAGS_HSYNC_HIGH ? 1 << 2 : 0) |
+ (mode->flags & DISPLAY_FLAGS_VSYNC_HIGH ? 1 << 3 : 0) |
+ 4 << 5 |
+ (venc_repeat ? 1 << 8 : 0) |
+ (hdmi_repeat ? 1 << 12 : 0),
+ priv->io_base + _REG(VPU_HDMI_SETTING));
+}
+
+static void meson_venci_cvbs_mode_set(struct meson_vpu_priv *priv,
+ struct meson_cvbs_enci_mode *mode)
+{
+ /* CVBS Filter settings */
+ writel(0x12, priv->io_base + _REG(ENCI_CFILT_CTRL));
+ writel(0x12, priv->io_base + _REG(ENCI_CFILT_CTRL2));
+
+ /* Digital Video Select : Interlace, clk27 clk, external */
+ writel(0, priv->io_base + _REG(VENC_DVI_SETTING));
+
+ /* Reset Video Mode */
+ writel(0, priv->io_base + _REG(ENCI_VIDEO_MODE));
+ writel(0, priv->io_base + _REG(ENCI_VIDEO_MODE_ADV));
+
+ /* Horizontal sync signal output */
+ writel(mode->hso_begin,
+ priv->io_base + _REG(ENCI_SYNC_HSO_BEGIN));
+ writel(mode->hso_end,
+ priv->io_base + _REG(ENCI_SYNC_HSO_END));
+
+ /* Vertical Sync lines */
+ writel(mode->vso_even,
+ priv->io_base + _REG(ENCI_SYNC_VSO_EVNLN));
+ writel(mode->vso_odd,
+ priv->io_base + _REG(ENCI_SYNC_VSO_ODDLN));
+
+ /* Macrovision max amplitude change */
+ writel(0x8100 + mode->macv_max_amp,
+ priv->io_base + _REG(ENCI_MACV_MAX_AMP));
+
+ /* Video mode */
+ writel(mode->video_prog_mode,
+ priv->io_base + _REG(VENC_VIDEO_PROG_MODE));
+ writel(mode->video_mode,
+ priv->io_base + _REG(ENCI_VIDEO_MODE));
+
+ /* Advanced Video Mode :
+ * Demux shifting 0x2
+ * Blank line end at line17/22
+ * High bandwidth Luma Filter
+ * Low bandwidth Chroma Filter
+ * Bypass luma low pass filter
+ * No macrovision on CSYNC
+ */
+ writel(0x26, priv->io_base + _REG(ENCI_VIDEO_MODE_ADV));
+
+ writel(mode->sch_adjust, priv->io_base + _REG(ENCI_VIDEO_SCH));
+
+ /* Sync mode : MASTER Master mode, free run, send HSO/VSO out */
+ writel(0x07, priv->io_base + _REG(ENCI_SYNC_MODE));
+
+ /* 0x3 Y, C, and Component Y delay */
+ writel(mode->yc_delay, priv->io_base + _REG(ENCI_YC_DELAY));
+
+ /* Timings */
+ writel(mode->pixel_start,
+ priv->io_base + _REG(ENCI_VFIFO2VD_PIXEL_START));
+ writel(mode->pixel_end,
+ priv->io_base + _REG(ENCI_VFIFO2VD_PIXEL_END));
+
+ writel(mode->top_field_line_start,
+ priv->io_base + _REG(ENCI_VFIFO2VD_LINE_TOP_START));
+ writel(mode->top_field_line_end,
+ priv->io_base + _REG(ENCI_VFIFO2VD_LINE_TOP_END));
+
+ writel(mode->bottom_field_line_start,
+ priv->io_base + _REG(ENCI_VFIFO2VD_LINE_BOT_START));
+ writel(mode->bottom_field_line_end,
+ priv->io_base + _REG(ENCI_VFIFO2VD_LINE_BOT_END));
+
+ /* Internal Venc, Internal VIU Sync, Internal Vencoder */
+ writel(0, priv->io_base + _REG(VENC_SYNC_ROUTE));
+
+ /* UNreset Interlaced TV Encoder */
+ writel(0, priv->io_base + _REG(ENCI_DBG_PX_RST));
+
+ /* Enable Vfifo2vd, Y_Cb_Y_Cr select */
+ writel(0x4e01, priv->io_base + _REG(ENCI_VFIFO2VD_CTL));
+
+ /* Power UP Dacs */
+ writel(0, priv->io_base + _REG(VENC_VDAC_SETTING));
+
+ /* Video Upsampling */
+ writel(0x0061, priv->io_base + _REG(VENC_UPSAMPLE_CTRL0));
+ writel(0x4061, priv->io_base + _REG(VENC_UPSAMPLE_CTRL1));
+ writel(0x5061, priv->io_base + _REG(VENC_UPSAMPLE_CTRL2));
+
+ /* Select Interlace Y DACs */
+ writel(0, priv->io_base + _REG(VENC_VDAC_DACSEL0));
+ writel(0, priv->io_base + _REG(VENC_VDAC_DACSEL1));
+ writel(0, priv->io_base + _REG(VENC_VDAC_DACSEL2));
+ writel(0, priv->io_base + _REG(VENC_VDAC_DACSEL3));
+ writel(0, priv->io_base + _REG(VENC_VDAC_DACSEL4));
+ writel(0, priv->io_base + _REG(VENC_VDAC_DACSEL5));
+
+ /* Select ENCI for VIU */
+ meson_vpp_setup_mux(priv, MESON_VIU_VPP_MUX_ENCI);
+
+ /* Enable ENCI FIFO */
+ writel(0x2000, priv->io_base + _REG(VENC_VDAC_FIFO_CTRL));
+
+ /* Select ENCI DACs 0, 1, 4, and 5 */
+ writel(0x11, priv->io_base + _REG(ENCI_DACSEL_0));
+ writel(0x11, priv->io_base + _REG(ENCI_DACSEL_1));
+
+ /* Interlace video enable */
+ writel(1, priv->io_base + _REG(ENCI_VIDEO_EN));
+
+ /* Configure Video Saturation / Contrast / Brightness / Hue */
+ writel(mode->video_saturation,
+ priv->io_base + _REG(ENCI_VIDEO_SAT));
+ writel(mode->video_contrast,
+ priv->io_base + _REG(ENCI_VIDEO_CONT));
+ writel(mode->video_brightness,
+ priv->io_base + _REG(ENCI_VIDEO_BRIGHT));
+ writel(mode->video_hue,
+ priv->io_base + _REG(ENCI_VIDEO_HUE));
+
+ /* Enable DAC0 Filter */
+ writel(0x1, priv->io_base + _REG(VENC_VDAC_DAC0_FILT_CTRL0));
+ writel(0xfc48, priv->io_base + _REG(VENC_VDAC_DAC0_FILT_CTRL1));
+
+ /* 0 in Macrovision register 0 */
+ writel(0, priv->io_base + _REG(ENCI_MACV_N0));
+
+ /* Analog Synchronization and color burst value adjust */
+ writel(mode->analog_sync_adj,
+ priv->io_base + _REG(ENCI_SYNC_ADJ));
+
+ /* enable VDAC */
+ writel_bits(BIT(5), 0, priv->io_base + _REG(VENC_VDAC_DACSEL0));
+
+ if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB))
+ hhi_write(HHI_VDAC_CNTL0, 1);
+ else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL) ||
+ meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM))
+ hhi_write(HHI_VDAC_CNTL0, 0xf0001);
+
+ hhi_write(HHI_VDAC_CNTL1, 0);
+}
+
+void meson_vpu_setup_venc(struct udevice *dev,
+ const struct display_timing *mode, bool is_cvbs)
+{
+ struct meson_vpu_priv *priv = dev_get_priv(dev);
+
+ if (is_cvbs)
+ return meson_venci_cvbs_mode_set(priv, &meson_cvbs_enci_pal);
+
+ meson_venc_hdmi_mode_set(priv, mode);
+}