// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2016 BayLibre, SAS
* Author: Neil Armstrong <narmstrong@baylibre.com>
* Copyright (C) 2015 Amlogic, Inc. All rights reserved.
*/
#include <linux/bitfield.h>
#include <linux/export.h>
#include <linux/iopoll.h>
#include <drm/drm_modes.h>
#include "meson_drv.h"
#include "meson_registers.h"
#include "meson_venc.h"
#include "meson_vpp.h"
/**
* DOC: Video Encoder
*
* VENC Handle the pixels encoding to the output formats.
* We handle the following encodings :
*
* - CVBS Encoding via the ENCI encoder and VDAC digital to analog converter
* - TMDS/HDMI Encoding via ENCI_DIV and ENCP
* - Setup of more clock rates for HDMI modes
*
* What is missing :
*
* - LCD Panel encoding via ENCL
* - TV Panel encoding via ENCT
*
* VENC paths :
*
* .. code::
*
* _____ _____ ____________________
* vd1---| |-| | | VENC /---------|----VDAC
* vd2---| VIU |-| VPP |-|-----ENCI/-ENCI_DVI-|-|
* osd1--| |-| | | \ | X--HDMI-TX
* osd2--|_____|-|_____| | |\-ENCP--ENCP_DVI-|-|
* | | |
* | \--ENCL-----------|----LVDS
* |____________________|
*
* The ENCI is designed for PAl or NTSC encoding and can go through the VDAC
* directly for CVBS encoding or through the ENCI_DVI encoder for HDMI.
* The ENCP is designed for Progressive encoding but can also generate
* 1080i interlaced pixels, and was initially designed to encode pixels for
* VDAC to output RGB ou YUV analog outputs.
* It's output is only used through the ENCP_DVI encoder for HDMI.
* The ENCL LVDS encoder is not implemented.
*
* The ENCI and ENCP encoders needs specially defined parameters for each
* supported mode and thus cannot be determined from standard video timings.
*
* The ENCI end ENCP DVI encoders are more generic and can generate any timings
* from the pixel data generated by ENCI or ENCP, so can use the standard video
* timings are source for HW parameters.
*/
/* HHI Registers */
#define HHI_GCLK_MPEG2 0 x148 /* 0x52 offset in data sheet */
#define HHI_VDAC_CNTL0 0 x2F4 /* 0xbd offset in data sheet */
#define HHI_VDAC_CNTL0_G12A 0 x2EC /* 0xbb offset in data sheet */
#define HHI_VDAC_CNTL1 0 x2F8 /* 0xbe offset in data sheet */
#define HHI_VDAC_CNTL1_G12A 0 x2F0 /* 0xbc offset in data sheet */
#define HHI_HDMI_PHY_CNTL0 0 x3a0 /* 0xe8 offset in data sheet */
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 = 0 xff,
.video_mode = 0 x13,
.sch_adjust = 0 x28,
.yc_delay = 0 x343,
.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 = 0 x8080,
};
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 = 0 xb,
.video_prog_mode = 0 xf0,
.video_mode = 0 x8,
.sch_adjust = 0 x20,
.yc_delay = 0 x333,
.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 = 0 x9c00,
};
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;
};
static 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 = 0 xb,
.video_prog_mode = 0 xf0,
.video_mode = 0 x8,
.sch_adjust = 0 x20,
.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 ,
},
};
static 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 = 0 x7,
.video_prog_mode = 0 xff,
.video_mode = 0 x13,
.sch_adjust = 0 x28,
.yc_delay = 0 x333,
.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 ,
},
};
static union meson_hdmi_venc_mode meson_hdmi_encp_mode_480p = {
.encp = {
.dvi_settings = 0 x21,
.video_mode = 0 x4000,
.video_mode_adv = 0 x9,
.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 = 0 x2052,
.video_filt_ctrl_present = true ,
/* video_ofld_voav_ofst */
.yfp1_htime = 244 ,
.yfp2_htime = 1630 ,
.max_pxcnt = 1715 ,
.hspuls_begin = 0 x22,
.hspuls_end = 0 xa0,
.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 = 0 x1d8,
.sy2_val_present = true ,
.max_lncnt = 524 ,
},
};
static union meson_hdmi_venc_mode meson_hdmi_encp_mode_576p = {
.encp = {
.dvi_settings = 0 x21,
.video_mode = 0 x4000,
.video_mode_adv = 0 x9,
.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 = 0 x52,
.video_filt_ctrl_present = true ,
/* video_ofld_voav_ofst */
.yfp1_htime = 235 ,
.yfp2_htime = 1674 ,
.max_pxcnt = 1727 ,
.hspuls_begin = 0 ,
.hspuls_end = 0 x80,
.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 = 0 x80,
.hso_end = 0 ,
.vso_begin = 0 ,
.vso_end = 5 ,
.vso_bline = 0 ,
/* vso_eline */
.sy_val = 8 ,
.sy_val_present = true ,
.sy2_val = 0 x1d8,
.sy2_val_present = true ,
.max_lncnt = 624 ,
},
};
static union meson_hdmi_venc_mode meson_hdmi_encp_mode_720p60 = {
.encp = {
.dvi_settings = 0 x2029,
.video_mode = 0 x4040,
.video_mode_adv = 0 x19,
/* 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 ,
},
};
static union meson_hdmi_venc_mode meson_hdmi_encp_mode_720p50 = {
.encp = {
.dvi_settings = 0 x202d,
.video_mode = 0 x4040,
.video_mode_adv = 0 x19,
.video_prog_mode = 0 x100,
.video_prog_mode_present = true ,
.video_sync_mode = 0 x407,
.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 ,
},
};
static union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080i60 = {
.encp = {
.dvi_settings = 0 x2029,
.video_mode = 0 x5ffc,
.video_mode_adv = 0 x19,
.video_prog_mode = 0 x100,
.video_prog_mode_present = true ,
.video_sync_mode = 0 x207,
.video_sync_mode_present = true ,
/* video_yc_dly */
/* video_rgb_ctrl */
/* video_filt_ctrl */
.video_ofld_voav_ofst = 0 x11,
.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 ,
},
};
static union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080i50 = {
.encp = {
.dvi_settings = 0 x202d,
.video_mode = 0 x5ffc,
.video_mode_adv = 0 x19,
.video_prog_mode = 0 x100,
.video_prog_mode_present = true ,
.video_sync_mode = 0 x7,
.video_sync_mode_present = true ,
/* video_yc_dly */
/* video_rgb_ctrl */
/* video_filt_ctrl */
.video_ofld_voav_ofst = 0 x11,
.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 ,
},
};
static union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p24 = {
.encp = {
.dvi_settings = 0 xd,
.video_mode = 0 x4040,
.video_mode_adv = 0 x18,
.video_prog_mode = 0 x100,
.video_prog_mode_present = true ,
.video_sync_mode = 0 x7,
.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 = 0 x1052,
.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 ,
},
};
static union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p30 = {
.encp = {
.dvi_settings = 0 x1,
.video_mode = 0 x4040,
.video_mode_adv = 0 x18,
.video_prog_mode = 0 x100,
.video_prog_mode_present = true ,
/* video_sync_mode */
/* video_yc_dly */
/* video_rgb_ctrl */
.video_filt_ctrl = 0 x1052,
.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 union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p50 = {
.encp = {
.dvi_settings = 0 xd,
.video_mode = 0 x4040,
.video_mode_adv = 0 x18,
.video_prog_mode = 0 x100,
.video_prog_mode_present = true ,
.video_sync_mode = 0 x7,
.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 ,
},
};
static union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p60 = {
.encp = {
.dvi_settings = 0 x1,
.video_mode = 0 x4040,
.video_mode_adv = 0 x18,
.video_prog_mode = 0 x100,
.video_prog_mode_present = true ,
/* video_sync_mode */
/* video_yc_dly */
/* video_rgb_ctrl */
.video_filt_ctrl = 0 x1052,
.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 union meson_hdmi_venc_mode meson_hdmi_encp_mode_2160p24 = {
.encp = {
.dvi_settings = 0 x1,
.video_mode = 0 x4040,
.video_mode_adv = 0 x8,
/* video_sync_mode */
/* video_yc_dly */
/* video_rgb_ctrl */
.video_filt_ctrl = 0 x1000,
.video_filt_ctrl_present = true ,
/* video_ofld_voav_ofst */
.yfp1_htime = 140 ,
.yfp2_htime = 140 +3840 ,
.max_pxcnt = 3840 +1660 -1 ,
.hspuls_begin = 2156 +1920 ,
.hspuls_end = 44 ,
.hspuls_switch = 44 ,
.vspuls_begin = 140 ,
.vspuls_end = 2059 +1920 ,
.vspuls_bline = 0 ,
.vspuls_eline = 4 ,
.havon_begin = 148 ,
.havon_end = 3987 ,
.vavon_bline = 89 ,
.vavon_eline = 2248 ,
/* eqpuls_begin */
/* eqpuls_end */
/* eqpuls_bline */
/* eqpuls_eline */
.hso_begin = 44 ,
.hso_end = 2156 +1920 ,
.vso_begin = 2100 +1920 ,
.vso_end = 2164 +1920 ,
.vso_bline = 51 ,
.vso_eline = 53 ,
.vso_eline_present = true ,
/* sy_val */
/* sy2_val */
.max_lncnt = 2249 ,
},
};
static union meson_hdmi_venc_mode meson_hdmi_encp_mode_2160p25 = {
.encp = {
.dvi_settings = 0 x1,
.video_mode = 0 x4040,
.video_mode_adv = 0 x8,
/* video_sync_mode */
/* video_yc_dly */
/* video_rgb_ctrl */
.video_filt_ctrl = 0 x1000,
.video_filt_ctrl_present = true ,
/* video_ofld_voav_ofst */
.yfp1_htime = 140 ,
.yfp2_htime = 140 +3840 ,
.max_pxcnt = 3840 +1440 -1 ,
.hspuls_begin = 2156 +1920 ,
.hspuls_end = 44 ,
.hspuls_switch = 44 ,
.vspuls_begin = 140 ,
.vspuls_end = 2059 +1920 ,
.vspuls_bline = 0 ,
.vspuls_eline = 4 ,
.havon_begin = 148 ,
.havon_end = 3987 ,
.vavon_bline = 89 ,
.vavon_eline = 2248 ,
/* eqpuls_begin */
/* eqpuls_end */
/* eqpuls_bline */
/* eqpuls_eline */
.hso_begin = 44 ,
.hso_end = 2156 +1920 ,
.vso_begin = 2100 +1920 ,
.vso_end = 2164 +1920 ,
.vso_bline = 51 ,
.vso_eline = 53 ,
.vso_eline_present = true ,
/* sy_val */
/* sy2_val */
.max_lncnt = 2249 ,
},
};
static union meson_hdmi_venc_mode meson_hdmi_encp_mode_2160p30 = {
.encp = {
.dvi_settings = 0 x1,
.video_mode = 0 x4040,
.video_mode_adv = 0 x8,
/* video_sync_mode */
/* video_yc_dly */
/* video_rgb_ctrl */
.video_filt_ctrl = 0 x1000,
.video_filt_ctrl_present = true ,
/* video_ofld_voav_ofst */
.yfp1_htime = 140 ,
.yfp2_htime = 140 +3840 ,
.max_pxcnt = 3840 +560 -1 ,
.hspuls_begin = 2156 +1920 ,
.hspuls_end = 44 ,
.hspuls_switch = 44 ,
.vspuls_begin = 140 ,
.vspuls_end = 2059 +1920 ,
.vspuls_bline = 0 ,
.vspuls_eline = 4 ,
.havon_begin = 148 ,
.havon_end = 3987 ,
.vavon_bline = 89 ,
.vavon_eline = 2248 ,
/* eqpuls_begin */
/* eqpuls_end */
/* eqpuls_bline */
/* eqpuls_eline */
.hso_begin = 44 ,
.hso_end = 2156 +1920 ,
.vso_begin = 2100 +1920 ,
.vso_end = 2164 +1920 ,
.vso_bline = 51 ,
.vso_eline = 53 ,
.vso_eline_present = true ,
/* sy_val */
/* sy2_val */
.max_lncnt = 2249 ,
},
};
static struct meson_hdmi_venc_vic_mode {
unsigned int vic;
union meson_hdmi_venc_mode *mode;
} meson_hdmi_venc_vic_modes[] = {
{ 6 , &meson_hdmi_enci_mode_480i },
{ 7 , &meson_hdmi_enci_mode_480i },
{ 21 , &meson_hdmi_enci_mode_576i },
{ 22 , &meson_hdmi_enci_mode_576i },
{ 2 , &meson_hdmi_encp_mode_480p },
{ 3 , &meson_hdmi_encp_mode_480p },
{ 17 , &meson_hdmi_encp_mode_576p },
{ 18 , &meson_hdmi_encp_mode_576p },
{ 4 , &meson_hdmi_encp_mode_720p60 },
{ 19 , &meson_hdmi_encp_mode_720p50 },
{ 5 , &meson_hdmi_encp_mode_1080i60 },
{ 20 , &meson_hdmi_encp_mode_1080i50 },
{ 32 , &meson_hdmi_encp_mode_1080p24 },
{ 33 , &meson_hdmi_encp_mode_1080p50 },
{ 34 , &meson_hdmi_encp_mode_1080p30 },
{ 31 , &meson_hdmi_encp_mode_1080p50 },
{ 16 , &meson_hdmi_encp_mode_1080p60 },
{ 93 , &meson_hdmi_encp_mode_2160p24 },
{ 94 , &meson_hdmi_encp_mode_2160p25 },
{ 95 , &meson_hdmi_encp_mode_2160p30 },
{ 96 , &meson_hdmi_encp_mode_2160p25 },
{ 97 , &meson_hdmi_encp_mode_2160p30 },
{ 0 , NULL}, /* sentinel */
};
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;
}
enum drm_mode_status
meson_venc_hdmi_supported_mode(const struct drm_display_mode *mode)
{
if (mode->flags & ~(DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NHSYNC |
DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_NVSYNC))
return MODE_BAD;
if (mode->hdisplay < 400 || mode->hdisplay > 1920 )
return MODE_BAD_HVALUE;
if (mode->vdisplay < 480 || mode->vdisplay > 1920 )
return MODE_BAD_VVALUE;
return MODE_OK;
}
EXPORT_SYMBOL_GPL(meson_venc_hdmi_supported_mode);
bool meson_venc_hdmi_supported_vic(int vic)
{
struct meson_hdmi_venc_vic_mode *vmode = meson_hdmi_venc_vic_modes;
while (vmode->vic && vmode->mode) {
if (vmode->vic == vic)
return true ;
vmode++;
}
return false ;
}
EXPORT_SYMBOL_GPL(meson_venc_hdmi_supported_vic);
static void meson_venc_hdmi_get_dmt_vmode(const struct drm_display_mode *mode,
union meson_hdmi_venc_mode *dmt_mode)
{
memset(dmt_mode, 0 , sizeof (*dmt_mode));
dmt_mode->encp.dvi_settings = 0 x21;
dmt_mode->encp.video_mode = 0 x4040;
dmt_mode->encp.video_mode_adv = 0 x18;
dmt_mode->encp.max_pxcnt = mode->htotal - 1 ;
dmt_mode->encp.havon_begin = mode->htotal - mode->hsync_start;
dmt_mode->encp.havon_end = dmt_mode->encp.havon_begin +
mode->hdisplay - 1 ;
dmt_mode->encp.vavon_bline = mode->vtotal - mode->vsync_start;
dmt_mode->encp.vavon_eline = dmt_mode->encp.vavon_bline +
mode->vdisplay - 1 ;
dmt_mode->encp.hso_begin = 0 ;
dmt_mode->encp.hso_end = mode->hsync_end - mode->hsync_start;
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_end - mode->vsync_start;
dmt_mode->encp.vso_eline_present = true ;
dmt_mode->encp.max_lncnt = mode->vtotal - 1 ;
}
static union meson_hdmi_venc_mode *meson_venc_hdmi_get_vic_vmode(int vic)
{
struct meson_hdmi_venc_vic_mode *vmode = meson_hdmi_venc_vic_modes;
while (vmode->vic && vmode->mode) {
if (vmode->vic == vic)
return vmode->mode;
vmode++;
}
return NULL;
}
bool meson_venc_hdmi_venc_repeat(int vic)
{
/* Repeat VENC pixels for 480/576i/p, 720p50/60 and 1080p50/60 */
if (vic == 6 || vic == 7 || /* 480i */
vic == 21 || vic == 22 || /* 576i */
vic == 17 || vic == 18 || /* 576p */
vic == 2 || vic == 3 || /* 480p */
vic == 4 || /* 720p60 */
vic == 19 || /* 720p50 */
vic == 5 || /* 1080i60 */
vic == 20 ) /* 1080i50 */
return true ;
return false ;
}
EXPORT_SYMBOL_GPL(meson_venc_hdmi_venc_repeat);
void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic,
unsigned int ycrcb_map,
bool yuv420_mode,
const struct drm_display_mode *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;
u32 reg;
/* Use VENCI for 480i and 576i and double HDMI pixels */
if (mode->flags & DRM_MODE_FLAG_DBLCLK) {
hdmi_repeat = true ;
use_enci = true ;
venc_hdmi_latency = 1 ;
}
if (meson_venc_hdmi_supported_vic(vic)) {
vmode = meson_venc_hdmi_get_vic_vmode(vic);
if (!vmode) {
dev_err(priv->dev, "%s: Fatal Error, unsupported mode "
DRM_MODE_FMT "\n" , __func__,
DRM_MODE_ARG(mode));
return ;
}
} else {
meson_venc_hdmi_get_dmt_vmode(mode, &vmode_dmt);
vmode = &vmode_dmt;
use_enci = false ;
}
/* Repeat VENC pixels for 480/576i/p, 720p50/60 and 1080p50/60 */
if (meson_venc_hdmi_venc_repeat(vic))
venc_repeat = true ;
eof_lines = mode->vsync_start - mode->vdisplay;
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
eof_lines /= 2 ;
sof_lines = mode->vtotal - mode->vsync_end;
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
sof_lines /= 2 ;
vsync_lines = mode->vsync_end - mode->vsync_start;
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
vsync_lines /= 2 ;
total_pixels_venc = mode->htotal;
if (hdmi_repeat)
total_pixels_venc /= 2 ;
if (venc_repeat)
total_pixels_venc *= 2 ;
active_pixels_venc = mode->hdisplay;
if (hdmi_repeat)
active_pixels_venc /= 2 ;
if (venc_repeat)
active_pixels_venc *= 2 ;
front_porch_venc = (mode->hsync_start - mode->hdisplay);
if (hdmi_repeat)
front_porch_venc /= 2 ;
if (venc_repeat)
front_porch_venc *= 2 ;
hsync_pixels_venc = (mode->hsync_end - mode->hsync_start);
if (hdmi_repeat)
hsync_pixels_venc /= 2 ;
if (venc_repeat)
hsync_pixels_venc *= 2 ;
/* Disable VDACs */
writel_bits_relaxed(0 xff, 0 xff,
priv->io_base + _REG(VENC_VDAC_SETTING));
writel_relaxed(0 , priv->io_base + _REG(ENCI_VIDEO_EN));
writel_relaxed(0 , priv->io_base + _REG(ENCP_VIDEO_EN));
if (use_enci) {
unsigned int lines_f0;
unsigned int lines_f1;
/* CVBS Filter settings */
writel_relaxed(ENCI_CFILT_CMPT_SEL_HIGH | 0 x10,
priv->io_base + _REG(ENCI_CFILT_CTRL));
writel_relaxed(ENCI_CFILT_CMPT_CR_DLY(2 ) |
ENCI_CFILT_CMPT_CB_DLY(1 ),
priv->io_base + _REG(ENCI_CFILT_CTRL2));
/* Digital Video Select : Interlace, clk27 clk, external */
writel_relaxed(0 , priv->io_base + _REG(VENC_DVI_SETTING));
/* Reset Video Mode */
writel_relaxed(0 , priv->io_base + _REG(ENCI_VIDEO_MODE));
writel_relaxed(0 , priv->io_base + _REG(ENCI_VIDEO_MODE_ADV));
/* Horizontal sync signal output */
writel_relaxed(vmode->enci.hso_begin,
priv->io_base + _REG(ENCI_SYNC_HSO_BEGIN));
writel_relaxed(vmode->enci.hso_end,
priv->io_base + _REG(ENCI_SYNC_HSO_END));
/* Vertical Sync lines */
writel_relaxed(vmode->enci.vso_even,
priv->io_base + _REG(ENCI_SYNC_VSO_EVNLN));
writel_relaxed(vmode->enci.vso_odd,
priv->io_base + _REG(ENCI_SYNC_VSO_ODDLN));
/* Macrovision max amplitude change */
writel_relaxed(ENCI_MACV_MAX_AMP_ENABLE_CHANGE |
ENCI_MACV_MAX_AMP_VAL(vmode->enci.macv_max_amp),
priv->io_base + _REG(ENCI_MACV_MAX_AMP));
/* Video mode */
writel_relaxed(vmode->enci.video_prog_mode,
priv->io_base + _REG(VENC_VIDEO_PROG_MODE));
writel_relaxed(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_relaxed(ENCI_VIDEO_MODE_ADV_DMXMD(2 ) |
ENCI_VIDEO_MODE_ADV_VBICTL_LINE_17_22 |
ENCI_VIDEO_MODE_ADV_YBW_HIGH,
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_relaxed(0 x07, priv->io_base + _REG(ENCI_SYNC_MODE));
if (vmode->enci.yc_delay)
writel_relaxed(vmode->enci.yc_delay,
priv->io_base + _REG(ENCI_YC_DELAY));
/* UNreset Interlaced TV Encoder */
writel_relaxed(0 , priv->io_base + _REG(ENCI_DBG_PX_RST));
/*
* Enable Vfifo2vd and set Y_Cb_Y_Cr:
* Corresponding value:
* Y => 00 or 10
* Cb => 01
* Cr => 11
* Ex: 0x4e => 01001110 would mean Cb/Y/Cr/Y
*/
writel_relaxed(ENCI_VFIFO2VD_CTL_ENABLE |
ENCI_VFIFO2VD_CTL_VD_SEL(0 x4e),
priv->io_base + _REG(ENCI_VFIFO2VD_CTL));
/* Timings */
writel_relaxed(vmode->enci.pixel_start,
priv->io_base + _REG(ENCI_VFIFO2VD_PIXEL_START));
writel_relaxed(vmode->enci.pixel_end,
priv->io_base + _REG(ENCI_VFIFO2VD_PIXEL_END));
writel_relaxed(vmode->enci.top_field_line_start,
priv->io_base + _REG(ENCI_VFIFO2VD_LINE_TOP_START));
writel_relaxed(vmode->enci.top_field_line_end,
priv->io_base + _REG(ENCI_VFIFO2VD_LINE_TOP_END));
writel_relaxed(vmode->enci.bottom_field_line_start,
priv->io_base + _REG(ENCI_VFIFO2VD_LINE_BOT_START));
writel_relaxed(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_relaxed(ENCI_VIDEO_EN_ENABLE,
priv->io_base + _REG(ENCI_VIDEO_EN));
lines_f0 = mode->vtotal >> 1 ;
lines_f1 = lines_f0 + 1 ;
de_h_begin = modulo(readl_relaxed(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_relaxed(de_h_begin,
priv->io_base + _REG(ENCI_DE_H_BEGIN));
writel_relaxed(de_h_end,
priv->io_base + _REG(ENCI_DE_H_END));
de_v_begin_even = readl_relaxed(priv->io_base +
_REG(ENCI_VFIFO2VD_LINE_TOP_START));
de_v_end_even = de_v_begin_even + mode->vdisplay;
de_v_begin_odd = readl_relaxed(priv->io_base +
_REG(ENCI_VFIFO2VD_LINE_BOT_START));
de_v_end_odd = de_v_begin_odd + mode->vdisplay;
writel_relaxed(de_v_begin_even,
priv->io_base + _REG(ENCI_DE_V_BEGIN_EVEN));
writel_relaxed(de_v_end_even,
priv->io_base + _REG(ENCI_DE_V_END_EVEN));
writel_relaxed(de_v_begin_odd,
priv->io_base + _REG(ENCI_DE_V_BEGIN_ODD));
writel_relaxed(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_relaxed(hs_begin,
priv->io_base + _REG(ENCI_DVI_HSO_BEGIN));
writel_relaxed(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_relaxed(vs_bline_evn,
priv->io_base + _REG(ENCI_DVI_VSO_BLINE_EVN));
writel_relaxed(vs_eline_evn,
priv->io_base + _REG(ENCI_DVI_VSO_ELINE_EVN));
writel_relaxed(hs_begin,
priv->io_base + _REG(ENCI_DVI_VSO_BEGIN_EVN));
writel_relaxed(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_relaxed(vs_bline_odd,
priv->io_base + _REG(ENCI_DVI_VSO_BLINE_ODD));
writel_relaxed(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_relaxed(vs_eline_evn, priv->io_base
+ _REG(ENCI_DVI_VSO_ELINE_EVN));
writel_relaxed(hs_begin, priv->io_base
+ _REG(ENCI_DVI_VSO_END_EVN));
} else {
vs_eline_odd = vs_bline_odd
+ vsync_lines;
writel_relaxed(vs_eline_odd, priv->io_base
+ _REG(ENCI_DVI_VSO_ELINE_ODD));
writel_relaxed(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_relaxed(vs_bline_odd,
priv->io_base + _REG(ENCI_DVI_VSO_BLINE_ODD));
writel_relaxed(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_relaxed(vso_begin_odd,
priv->io_base + _REG(ENCI_DVI_VSO_BEGIN_ODD));
writel_relaxed(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_relaxed(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_relaxed(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_relaxed(vs_eline_odd, priv->io_base
+ _REG(ENCI_DVI_VSO_ELINE_ODD));
writel_relaxed(vso_begin_evn, priv->io_base
+ _REG(ENCI_DVI_VSO_END_ODD));
} else {
vs_eline_evn = vs_bline_evn + vsync_lines;
writel_relaxed(vs_eline_evn, priv->io_base
+ _REG(ENCI_DVI_VSO_ELINE_EVN));
writel_relaxed(vso_begin_evn, priv->io_base
+ _REG(ENCI_DVI_VSO_END_EVN));
}
}
} else {
writel_relaxed(vmode->encp.dvi_settings,
priv->io_base + _REG(VENC_DVI_SETTING));
writel_relaxed(vmode->encp.video_mode,
priv->io_base + _REG(ENCP_VIDEO_MODE));
writel_relaxed(vmode->encp.video_mode_adv,
priv->io_base + _REG(ENCP_VIDEO_MODE_ADV));
if (vmode->encp.video_prog_mode_present)
writel_relaxed(vmode->encp.video_prog_mode,
priv->io_base + _REG(VENC_VIDEO_PROG_MODE));
if (vmode->encp.video_sync_mode_present)
writel_relaxed(vmode->encp.video_sync_mode,
priv->io_base + _REG(ENCP_VIDEO_SYNC_MODE));
if (vmode->encp.video_yc_dly_present)
writel_relaxed(vmode->encp.video_yc_dly,
priv->io_base + _REG(ENCP_VIDEO_YC_DLY));
if (vmode->encp.video_rgb_ctrl_present)
writel_relaxed(vmode->encp.video_rgb_ctrl,
priv->io_base + _REG(ENCP_VIDEO_RGB_CTRL));
if (vmode->encp.video_filt_ctrl_present)
writel_relaxed(vmode->encp.video_filt_ctrl,
priv->io_base + _REG(ENCP_VIDEO_FILT_CTRL));
if (vmode->encp.video_ofld_voav_ofst_present)
writel_relaxed(vmode->encp.video_ofld_voav_ofst,
priv->io_base
+ _REG(ENCP_VIDEO_OFLD_VOAV_OFST));
writel_relaxed(vmode->encp.yfp1_htime,
priv->io_base + _REG(ENCP_VIDEO_YFP1_HTIME));
writel_relaxed(vmode->encp.yfp2_htime,
priv->io_base + _REG(ENCP_VIDEO_YFP2_HTIME));
writel_relaxed(vmode->encp.max_pxcnt,
priv->io_base + _REG(ENCP_VIDEO_MAX_PXCNT));
writel_relaxed(vmode->encp.hspuls_begin,
priv->io_base + _REG(ENCP_VIDEO_HSPULS_BEGIN));
writel_relaxed(vmode->encp.hspuls_end,
priv->io_base + _REG(ENCP_VIDEO_HSPULS_END));
writel_relaxed(vmode->encp.hspuls_switch,
priv->io_base + _REG(ENCP_VIDEO_HSPULS_SWITCH));
writel_relaxed(vmode->encp.vspuls_begin,
priv->io_base + _REG(ENCP_VIDEO_VSPULS_BEGIN));
writel_relaxed(vmode->encp.vspuls_end,
priv->io_base + _REG(ENCP_VIDEO_VSPULS_END));
writel_relaxed(vmode->encp.vspuls_bline,
priv->io_base + _REG(ENCP_VIDEO_VSPULS_BLINE));
writel_relaxed(vmode->encp.vspuls_eline,
priv->io_base + _REG(ENCP_VIDEO_VSPULS_ELINE));
if (vmode->encp.eqpuls_begin_present)
writel_relaxed(vmode->encp.eqpuls_begin,
priv->io_base + _REG(ENCP_VIDEO_EQPULS_BEGIN));
if (vmode->encp.eqpuls_end_present)
writel_relaxed(vmode->encp.eqpuls_end,
priv->io_base + _REG(ENCP_VIDEO_EQPULS_END));
if (vmode->encp.eqpuls_bline_present)
writel_relaxed(vmode->encp.eqpuls_bline,
priv->io_base + _REG(ENCP_VIDEO_EQPULS_BLINE));
if (vmode->encp.eqpuls_eline_present)
writel_relaxed(vmode->encp.eqpuls_eline,
priv->io_base + _REG(ENCP_VIDEO_EQPULS_ELINE));
writel_relaxed(vmode->encp.havon_begin,
priv->io_base + _REG(ENCP_VIDEO_HAVON_BEGIN));
writel_relaxed(vmode->encp.havon_end,
priv->io_base + _REG(ENCP_VIDEO_HAVON_END));
writel_relaxed(vmode->encp.vavon_bline,
priv->io_base + _REG(ENCP_VIDEO_VAVON_BLINE));
writel_relaxed(vmode->encp.vavon_eline,
priv->io_base + _REG(ENCP_VIDEO_VAVON_ELINE));
writel_relaxed(vmode->encp.hso_begin,
priv->io_base + _REG(ENCP_VIDEO_HSO_BEGIN));
writel_relaxed(vmode->encp.hso_end,
priv->io_base + _REG(ENCP_VIDEO_HSO_END));
writel_relaxed(vmode->encp.vso_begin,
priv->io_base + _REG(ENCP_VIDEO_VSO_BEGIN));
writel_relaxed(vmode->encp.vso_end,
priv->io_base + _REG(ENCP_VIDEO_VSO_END));
writel_relaxed(vmode->encp.vso_bline,
priv->io_base + _REG(ENCP_VIDEO_VSO_BLINE));
if (vmode->encp.vso_eline_present)
writel_relaxed(vmode->encp.vso_eline,
priv->io_base + _REG(ENCP_VIDEO_VSO_ELINE));
if (vmode->encp.sy_val_present)
writel_relaxed(vmode->encp.sy_val,
priv->io_base + _REG(ENCP_VIDEO_SY_VAL));
if (vmode->encp.sy2_val_present)
writel_relaxed(vmode->encp.sy2_val,
priv->io_base + _REG(ENCP_VIDEO_SY2_VAL));
writel_relaxed(vmode->encp.max_lncnt,
priv->io_base + _REG(ENCP_VIDEO_MAX_LNCNT));
writel_relaxed(1 , priv->io_base + _REG(ENCP_VIDEO_EN));
/* Set DE signal’s polarity is active high */
writel_bits_relaxed(ENCP_VIDEO_MODE_DE_V_HIGH,
ENCP_VIDEO_MODE_DE_V_HIGH,
priv->io_base + _REG(ENCP_VIDEO_MODE));
/* Program DE timing */
de_h_begin = modulo(readl_relaxed(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_relaxed(de_h_begin,
priv->io_base + _REG(ENCP_DE_H_BEGIN));
writel_relaxed(de_h_end,
priv->io_base + _REG(ENCP_DE_H_END));
/* Program DE timing for even field */
de_v_begin_even = readl_relaxed(priv->io_base
+ _REG(ENCP_VIDEO_VAVON_BLINE));
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
de_v_end_even = de_v_begin_even +
(mode->vdisplay / 2 );
else
de_v_end_even = de_v_begin_even + mode->vdisplay;
writel_relaxed(de_v_begin_even,
priv->io_base + _REG(ENCP_DE_V_BEGIN_EVEN));
writel_relaxed(de_v_end_even,
priv->io_base + _REG(ENCP_DE_V_END_EVEN));
/* Program DE timing for odd field if needed */
if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
unsigned int ofld_voav_ofst =
readl_relaxed(priv->io_base +
_REG(ENCP_VIDEO_OFLD_VOAV_OFST));
de_v_begin_odd = to_signed((ofld_voav_ofst & 0 xf0) >> 4 )
+ de_v_begin_even
+ ((mode->vtotal - 1 ) / 2 );
de_v_end_odd = de_v_begin_odd + (mode->vdisplay / 2 );
writel_relaxed(de_v_begin_odd,
priv->io_base + _REG(ENCP_DE_V_BEGIN_ODD));
writel_relaxed(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_relaxed(hs_begin,
priv->io_base + _REG(ENCP_DVI_HSO_BEGIN));
writel_relaxed(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->vtotal
+ de_v_begin_even
- sof_lines
- vsync_lines
- (1 - vs_adjust);
vs_eline_evn = modulo(vs_bline_evn + vsync_lines,
mode->vtotal);
writel_relaxed(vs_bline_evn,
priv->io_base + _REG(ENCP_DVI_VSO_BLINE_EVN));
writel_relaxed(vs_eline_evn,
priv->io_base + _REG(ENCP_DVI_VSO_ELINE_EVN));
vso_begin_evn = hs_begin;
writel_relaxed(vso_begin_evn,
priv->io_base + _REG(ENCP_DVI_VSO_BEGIN_EVN));
writel_relaxed(vso_begin_evn,
priv->io_base + _REG(ENCP_DVI_VSO_END_EVN));
/* Program Vsync timing for odd field if needed */
if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
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_relaxed(vs_bline_odd,
priv->io_base + _REG(ENCP_DVI_VSO_BLINE_ODD));
writel_relaxed(vs_eline_odd,
priv->io_base + _REG(ENCP_DVI_VSO_ELINE_ODD));
writel_relaxed(vso_begin_odd,
priv->io_base + _REG(ENCP_DVI_VSO_BEGIN_ODD));
writel_relaxed(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);
}
/* Set VPU HDMI setting */
/* Select ENCP or ENCI data to HDMI */
if (use_enci)
reg = VPU_HDMI_ENCI_DATA_TO_HDMI;
else
reg = VPU_HDMI_ENCP_DATA_TO_HDMI;
/* Invert polarity of HSYNC from VENC */
if (mode->flags & DRM_MODE_FLAG_PHSYNC)
reg |= VPU_HDMI_INV_HSYNC;
/* Invert polarity of VSYNC from VENC */
if (mode->flags & DRM_MODE_FLAG_PVSYNC)
reg |= VPU_HDMI_INV_VSYNC;
/* Output data format */
reg |= ycrcb_map;
/*
* Write rate to the async FIFO between VENC and HDMI.
* One write every 2 wr_clk.
*/
if (venc_repeat || yuv420_mode)
reg |= VPU_HDMI_WR_RATE(2 );
/*
* Read rate to the async FIFO between VENC and HDMI.
* One read every 2 wr_clk.
*/
if (hdmi_repeat)
reg |= VPU_HDMI_RD_RATE(2 );
writel_relaxed(reg, priv->io_base + _REG(VPU_HDMI_SETTING));
priv->venc.hdmi_repeat = hdmi_repeat;
priv->venc.venc_repeat = venc_repeat;
priv->venc.hdmi_use_enci = use_enci;
priv->venc.current_mode = MESON_VENC_MODE_HDMI;
}
EXPORT_SYMBOL_GPL(meson_venc_hdmi_mode_set);
static unsigned short meson_encl_gamma_table[256 ] = {
0 , 4 , 8 , 12 , 16 , 20 , 24 , 28 , 32 , 36 , 40 , 44 , 48 , 52 , 56 , 60 ,
64 , 68 , 72 , 76 , 80 , 84 , 88 , 92 , 96 , 100 , 104 , 108 , 112 , 116 , 120 , 124 ,
128 , 132 , 136 , 140 , 144 , 148 , 152 , 156 , 160 , 164 , 168 , 172 , 176 , 180 , 184 , 188 ,
192 , 196 , 200 , 204 , 208 , 212 , 216 , 220 , 224 , 228 , 232 , 236 , 240 , 244 , 248 , 252 ,
256 , 260 , 264 , 268 , 272 , 276 , 280 , 284 , 288 , 292 , 296 , 300 , 304 , 308 , 312 , 316 ,
320 , 324 , 328 , 332 , 336 , 340 , 344 , 348 , 352 , 356 , 360 , 364 , 368 , 372 , 376 , 380 ,
384 , 388 , 392 , 396 , 400 , 404 , 408 , 412 , 416 , 420 , 424 , 428 , 432 , 436 , 440 , 444 ,
448 , 452 , 456 , 460 , 464 , 468 , 472 , 476 , 480 , 484 , 488 , 492 , 496 , 500 , 504 , 508 ,
512 , 516 , 520 , 524 , 528 , 532 , 536 , 540 , 544 , 548 , 552 , 556 , 560 , 564 , 568 , 572 ,
576 , 580 , 584 , 588 , 592 , 596 , 600 , 604 , 608 , 612 , 616 , 620 , 624 , 628 , 632 , 636 ,
640 , 644 , 648 , 652 , 656 , 660 , 664 , 668 , 672 , 676 , 680 , 684 , 688 , 692 , 696 , 700 ,
704 , 708 , 712 , 716 , 720 , 724 , 728 , 732 , 736 , 740 , 744 , 748 , 752 , 756 , 760 , 764 ,
768 , 772 , 776 , 780 , 784 , 788 , 792 , 796 , 800 , 804 , 808 , 812 , 816 , 820 , 824 , 828 ,
832 , 836 , 840 , 844 , 848 , 852 , 856 , 860 , 864 , 868 , 872 , 876 , 880 , 884 , 888 , 892 ,
896 , 900 , 904 , 908 , 912 , 916 , 920 , 924 , 928 , 932 , 936 , 940 , 944 , 948 , 952 , 956 ,
960 , 964 , 968 , 972 , 976 , 980 , 984 , 988 , 992 , 996 , 1000 , 1004 , 1008 , 1012 , 1016 , 1020 ,
};
static void meson_encl_set_gamma_table(struct meson_drm *priv, u16 *data,
u32 rgb_mask)
{
int i, ret;
u32 reg;
writel_bits_relaxed(L_GAMMA_CNTL_PORT_EN, 0 ,
priv->io_base + _REG(L_GAMMA_CNTL_PORT));
ret = readl_relaxed_poll_timeout(priv->io_base + _REG(L_GAMMA_CNTL_PORT),
reg, reg & L_GAMMA_CNTL_PORT_ADR_RDY, 10 , 10000 );
if (ret)
pr_warn("%s: GAMMA ADR_RDY timeout\n" , __func__);
writel_relaxed(L_GAMMA_ADDR_PORT_AUTO_INC | rgb_mask |
FIELD_PREP(L_GAMMA_ADDR_PORT_ADDR, 0 ),
priv->io_base + _REG(L_GAMMA_ADDR_PORT));
for (i = 0 ; i < 256 ; i++) {
ret = readl_relaxed_poll_timeout(priv->io_base + _REG(L_GAMMA_CNTL_PORT),
reg, reg & L_GAMMA_CNTL_PORT_WR_RDY,
10 , 10000 );
if (ret)
pr_warn_once("%s: GAMMA WR_RDY timeout\n" , __func__);
writel_relaxed(data[i], priv->io_base + _REG(L_GAMMA_DATA_PORT));
}
ret = readl_relaxed_poll_timeout(priv->io_base + _REG(L_GAMMA_CNTL_PORT),
reg, reg & L_GAMMA_CNTL_PORT_ADR_RDY, 10 , 10000 );
if (ret)
pr_warn("%s: GAMMA ADR_RDY timeout\n" , __func__);
writel_relaxed(L_GAMMA_ADDR_PORT_AUTO_INC | rgb_mask |
FIELD_PREP(L_GAMMA_ADDR_PORT_ADDR, 0 x23),
priv->io_base + _REG(L_GAMMA_ADDR_PORT));
}
void meson_encl_load_gamma(struct meson_drm *priv)
{
meson_encl_set_gamma_table(priv, meson_encl_gamma_table, L_GAMMA_ADDR_PORT_SEL_R);
meson_encl_set_gamma_table(priv, meson_encl_gamma_table, L_GAMMA_ADDR_PORT_SEL_G);
meson_encl_set_gamma_table(priv, meson_encl_gamma_table, L_GAMMA_ADDR_PORT_SEL_B);
writel_bits_relaxed(L_GAMMA_CNTL_PORT_EN, L_GAMMA_CNTL_PORT_EN,
priv->io_base + _REG(L_GAMMA_CNTL_PORT));
}
void meson_venc_mipi_dsi_mode_set(struct meson_drm *priv,
const struct drm_display_mode *mode)
{
unsigned int max_pxcnt;
unsigned int max_lncnt;
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;
max_pxcnt = mode->htotal - 1 ;
max_lncnt = mode->vtotal - 1 ;
havon_begin = mode->htotal - mode->hsync_start;
havon_end = havon_begin + mode->hdisplay - 1 ;
vavon_bline = mode->vtotal - mode->vsync_start;
vavon_eline = vavon_bline + mode->vdisplay - 1 ;
hso_begin = 0 ;
hso_end = mode->hsync_end - mode->hsync_start;
vso_begin = 0 ;
vso_end = 0 ;
vso_bline = 0 ;
vso_eline = mode->vsync_end - mode->vsync_start;
meson_vpp_setup_mux(priv, MESON_VIU_VPP_MUX_ENCL);
writel_relaxed(0 , priv->io_base + _REG(ENCL_VIDEO_EN));
writel_relaxed(ENCL_PX_LN_CNT_SHADOW_EN, priv->io_base + _REG(ENCL_VIDEO_MODE));
writel_relaxed(ENCL_VIDEO_MODE_ADV_VFIFO_EN |
ENCL_VIDEO_MODE_ADV_GAIN_HDTV |
ENCL_SEL_GAMMA_RGB_IN, priv->io_base + _REG(ENCL_VIDEO_MODE_ADV));
writel_relaxed(ENCL_VIDEO_FILT_CTRL_BYPASS_FILTER,
priv->io_base + _REG(ENCL_VIDEO_FILT_CTRL));
writel_relaxed(max_pxcnt, priv->io_base + _REG(ENCL_VIDEO_MAX_PXCNT));
writel_relaxed(max_lncnt, priv->io_base + _REG(ENCL_VIDEO_MAX_LNCNT));
writel_relaxed(havon_begin, priv->io_base + _REG(ENCL_VIDEO_HAVON_BEGIN));
writel_relaxed(havon_end, priv->io_base + _REG(ENCL_VIDEO_HAVON_END));
writel_relaxed(vavon_bline, priv->io_base + _REG(ENCL_VIDEO_VAVON_BLINE));
writel_relaxed(vavon_eline, priv->io_base + _REG(ENCL_VIDEO_VAVON_ELINE));
writel_relaxed(hso_begin, priv->io_base + _REG(ENCL_VIDEO_HSO_BEGIN));
writel_relaxed(hso_end, priv->io_base + _REG(ENCL_VIDEO_HSO_END));
writel_relaxed(vso_begin, priv->io_base + _REG(ENCL_VIDEO_VSO_BEGIN));
writel_relaxed(vso_end, priv->io_base + _REG(ENCL_VIDEO_VSO_END));
writel_relaxed(vso_bline, priv->io_base + _REG(ENCL_VIDEO_VSO_BLINE));
writel_relaxed(vso_eline, priv->io_base + _REG(ENCL_VIDEO_VSO_ELINE));
writel_relaxed(ENCL_VIDEO_RGBIN_RGB | ENCL_VIDEO_RGBIN_ZBLK,
priv->io_base + _REG(ENCL_VIDEO_RGBIN_CTRL));
/* default black pattern */
writel_relaxed(0 , priv->io_base + _REG(ENCL_TST_MDSEL));
writel_relaxed(0 , priv->io_base + _REG(ENCL_TST_Y));
writel_relaxed(0 , priv->io_base + _REG(ENCL_TST_CB));
writel_relaxed(0 , priv->io_base + _REG(ENCL_TST_CR));
writel_relaxed(1 , priv->io_base + _REG(ENCL_TST_EN));
writel_bits_relaxed(ENCL_VIDEO_MODE_ADV_VFIFO_EN, 0 ,
priv->io_base + _REG(ENCL_VIDEO_MODE_ADV));
writel_relaxed(1 , priv->io_base + _REG(ENCL_VIDEO_EN));
writel_relaxed(0 , priv->io_base + _REG(L_RGB_BASE_ADDR));
writel_relaxed(0 x400, priv->io_base + _REG(L_RGB_COEFF_ADDR)); /* Magic value */
writel_relaxed(L_DITH_CNTL_DITH10_EN, priv->io_base + _REG(L_DITH_CNTL_ADDR));
/* DE signal for TTL */
writel_relaxed(havon_begin, priv->io_base + _REG(L_OEH_HS_ADDR));
writel_relaxed(havon_end + 1 , priv->io_base + _REG(L_OEH_HE_ADDR));
writel_relaxed(vavon_bline, priv->io_base + _REG(L_OEH_VS_ADDR));
writel_relaxed(vavon_eline, priv->io_base + _REG(L_OEH_VE_ADDR));
/* DE signal for TTL */
writel_relaxed(havon_begin, priv->io_base + _REG(L_OEV1_HS_ADDR));
writel_relaxed(havon_end + 1 , priv->io_base + _REG(L_OEV1_HE_ADDR));
writel_relaxed(vavon_bline, priv->io_base + _REG(L_OEV1_VS_ADDR));
writel_relaxed(vavon_eline, priv->io_base + _REG(L_OEV1_VE_ADDR));
/* Hsync signal for TTL */
if (mode->flags & DRM_MODE_FLAG_PHSYNC) {
writel_relaxed(hso_begin, priv->io_base + _REG(L_STH1_HS_ADDR));
writel_relaxed(hso_end, priv->io_base + _REG(L_STH1_HE_ADDR));
} else {
writel_relaxed(hso_end, priv->io_base + _REG(L_STH1_HS_ADDR));
writel_relaxed(hso_begin, priv->io_base + _REG(L_STH1_HE_ADDR));
}
writel_relaxed(0 , priv->io_base + _REG(L_STH1_VS_ADDR));
writel_relaxed(max_lncnt, priv->io_base + _REG(L_STH1_VE_ADDR));
/* Vsync signal for TTL */
writel_relaxed(vso_begin, priv->io_base + _REG(L_STV1_HS_ADDR));
writel_relaxed(vso_end, priv->io_base + _REG(L_STV1_HE_ADDR));
if (mode->flags & DRM_MODE_FLAG_PVSYNC) {
writel_relaxed(vso_bline, priv->io_base + _REG(L_STV1_VS_ADDR));
writel_relaxed(vso_eline, priv->io_base + _REG(L_STV1_VE_ADDR));
} else {
writel_relaxed(vso_eline, priv->io_base + _REG(L_STV1_VS_ADDR));
writel_relaxed(vso_bline, priv->io_base + _REG(L_STV1_VE_ADDR));
}
/* DE signal */
writel_relaxed(havon_begin, priv->io_base + _REG(L_DE_HS_ADDR));
writel_relaxed(havon_end + 1 , priv->io_base + _REG(L_DE_HE_ADDR));
writel_relaxed(vavon_bline, priv->io_base + _REG(L_DE_VS_ADDR));
writel_relaxed(vavon_eline, priv->io_base + _REG(L_DE_VE_ADDR));
/* Hsync signal */
writel_relaxed(hso_begin, priv->io_base + _REG(L_HSYNC_HS_ADDR));
writel_relaxed(hso_end, priv->io_base + _REG(L_HSYNC_HE_ADDR));
writel_relaxed(0 , priv->io_base + _REG(L_HSYNC_VS_ADDR));
writel_relaxed(max_lncnt, priv->io_base + _REG(L_HSYNC_VE_ADDR));
/* Vsync signal */
writel_relaxed(vso_begin, priv->io_base + _REG(L_VSYNC_HS_ADDR));
writel_relaxed(vso_end, priv->io_base + _REG(L_VSYNC_HE_ADDR));
writel_relaxed(vso_bline, priv->io_base + _REG(L_VSYNC_VS_ADDR));
writel_relaxed(vso_eline, priv->io_base + _REG(L_VSYNC_VE_ADDR));
writel_relaxed(0 , priv->io_base + _REG(L_INV_CNT_ADDR));
writel_relaxed(L_TCON_MISC_SEL_STV1 | L_TCON_MISC_SEL_STV2,
priv->io_base + _REG(L_TCON_MISC_SEL_ADDR));
priv->venc.current_mode = MESON_VENC_MODE_MIPI_DSI;
}
EXPORT_SYMBOL_GPL(meson_venc_mipi_dsi_mode_set);
void meson_venci_cvbs_mode_set(struct meson_drm *priv,
struct meson_cvbs_enci_mode *mode)
{
u32 reg;
if (mode->mode_tag == priv->venc.current_mode)
return ;
/* CVBS Filter settings */
writel_relaxed(ENCI_CFILT_CMPT_SEL_HIGH | 0 x10,
priv->io_base + _REG(ENCI_CFILT_CTRL));
writel_relaxed(ENCI_CFILT_CMPT_CR_DLY(2 ) |
ENCI_CFILT_CMPT_CB_DLY(1 ),
priv->io_base + _REG(ENCI_CFILT_CTRL2));
/* Digital Video Select : Interlace, clk27 clk, external */
writel_relaxed(0 , priv->io_base + _REG(VENC_DVI_SETTING));
/* Reset Video Mode */
writel_relaxed(0 , priv->io_base + _REG(ENCI_VIDEO_MODE));
writel_relaxed(0 , priv->io_base + _REG(ENCI_VIDEO_MODE_ADV));
/* Horizontal sync signal output */
writel_relaxed(mode->hso_begin,
priv->io_base + _REG(ENCI_SYNC_HSO_BEGIN));
writel_relaxed(mode->hso_end,
priv->io_base + _REG(ENCI_SYNC_HSO_END));
/* Vertical Sync lines */
writel_relaxed(mode->vso_even,
priv->io_base + _REG(ENCI_SYNC_VSO_EVNLN));
writel_relaxed(mode->vso_odd,
priv->io_base + _REG(ENCI_SYNC_VSO_ODDLN));
/* Macrovision max amplitude change */
writel_relaxed(ENCI_MACV_MAX_AMP_ENABLE_CHANGE |
ENCI_MACV_MAX_AMP_VAL(mode->macv_max_amp),
priv->io_base + _REG(ENCI_MACV_MAX_AMP));
/* Video mode */
writel_relaxed(mode->video_prog_mode,
priv->io_base + _REG(VENC_VIDEO_PROG_MODE));
writel_relaxed(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_relaxed(ENCI_VIDEO_MODE_ADV_DMXMD(2 ) |
ENCI_VIDEO_MODE_ADV_VBICTL_LINE_17_22 |
ENCI_VIDEO_MODE_ADV_YBW_HIGH,
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_relaxed(0 x07, priv->io_base + _REG(ENCI_SYNC_MODE));
/* 0x3 Y, C, and Component Y delay */
writel_relaxed(mode->yc_delay, priv->io_base + _REG(ENCI_YC_DELAY));
/* Timings */
writel_relaxed(mode->pixel_start,
priv->io_base + _REG(ENCI_VFIFO2VD_PIXEL_START));
writel_relaxed(mode->pixel_end,
priv->io_base + _REG(ENCI_VFIFO2VD_PIXEL_END));
writel_relaxed(mode->top_field_line_start,
priv->io_base + _REG(ENCI_VFIFO2VD_LINE_TOP_START));
writel_relaxed(mode->top_field_line_end,
priv->io_base + _REG(ENCI_VFIFO2VD_LINE_TOP_END));
writel_relaxed(mode->bottom_field_line_start,
priv->io_base + _REG(ENCI_VFIFO2VD_LINE_BOT_START));
writel_relaxed(mode->bottom_field_line_end,
priv->io_base + _REG(ENCI_VFIFO2VD_LINE_BOT_END));
/* Internal Venc, Internal VIU Sync, Internal Vencoder */
writel_relaxed(0 , priv->io_base + _REG(VENC_SYNC_ROUTE));
/* UNreset Interlaced TV Encoder */
writel_relaxed(0 , priv->io_base + _REG(ENCI_DBG_PX_RST));
/*
* Enable Vfifo2vd and set Y_Cb_Y_Cr:
* Corresponding value:
* Y => 00 or 10
* Cb => 01
* Cr => 11
* Ex: 0x4e => 01001110 would mean Cb/Y/Cr/Y
*/
writel_relaxed(ENCI_VFIFO2VD_CTL_ENABLE |
ENCI_VFIFO2VD_CTL_VD_SEL(0 x4e),
priv->io_base + _REG(ENCI_VFIFO2VD_CTL));
/* Power UP Dacs */
writel_relaxed(0 , priv->io_base + _REG(VENC_VDAC_SETTING));
/* Video Upsampling */
/*
* CTRL0, CTRL1 and CTRL2:
* Filter0: input data sample every 2 cloks
* Filter1: filtering and upsample enable
*/
reg = VENC_UPSAMPLE_CTRL_F0_2_CLK_RATIO | VENC_UPSAMPLE_CTRL_F1_EN |
VENC_UPSAMPLE_CTRL_F1_UPSAMPLE_EN;
/*
* Upsample CTRL0:
* Interlace High Bandwidth Luma
*/
writel_relaxed(VENC_UPSAMPLE_CTRL_INTERLACE_HIGH_LUMA | reg,
priv->io_base + _REG(VENC_UPSAMPLE_CTRL0));
/*
* Upsample CTRL1:
* Interlace Pb
*/
writel_relaxed(VENC_UPSAMPLE_CTRL_INTERLACE_PB | reg,
priv->io_base + _REG(VENC_UPSAMPLE_CTRL1));
/*
* Upsample CTRL2:
* Interlace R
*/
writel_relaxed(VENC_UPSAMPLE_CTRL_INTERLACE_PR | reg,
priv->io_base + _REG(VENC_UPSAMPLE_CTRL2));
/* Select Interlace Y DACs */
writel_relaxed(0 , priv->io_base + _REG(VENC_VDAC_DACSEL0));
writel_relaxed(0 , priv->io_base + _REG(VENC_VDAC_DACSEL1));
writel_relaxed(0 , priv->io_base + _REG(VENC_VDAC_DACSEL2));
writel_relaxed(0 , priv->io_base + _REG(VENC_VDAC_DACSEL3));
writel_relaxed(0 , priv->io_base + _REG(VENC_VDAC_DACSEL4));
writel_relaxed(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_relaxed(VENC_VDAC_FIFO_EN_ENCI_ENABLE,
priv->io_base + _REG(VENC_VDAC_FIFO_CTRL));
/* Select ENCI DACs 0, 1, 4, and 5 */
writel_relaxed(0 x11, priv->io_base + _REG(ENCI_DACSEL_0));
writel_relaxed(0 x11, priv->io_base + _REG(ENCI_DACSEL_1));
/* Interlace video enable */
writel_relaxed(ENCI_VIDEO_EN_ENABLE,
priv->io_base + _REG(ENCI_VIDEO_EN));
/* Configure Video Saturation / Contrast / Brightness / Hue */
writel_relaxed(mode->video_saturation,
priv->io_base + _REG(ENCI_VIDEO_SAT));
writel_relaxed(mode->video_contrast,
priv->io_base + _REG(ENCI_VIDEO_CONT));
writel_relaxed(mode->video_brightness,
priv->io_base + _REG(ENCI_VIDEO_BRIGHT));
writel_relaxed(mode->video_hue,
priv->io_base + _REG(ENCI_VIDEO_HUE));
/* Enable DAC0 Filter */
writel_relaxed(VENC_VDAC_DAC0_FILT_CTRL0_EN,
priv->io_base + _REG(VENC_VDAC_DAC0_FILT_CTRL0));
writel_relaxed(0 xfc48, priv->io_base + _REG(VENC_VDAC_DAC0_FILT_CTRL1));
/* 0 in Macrovision register 0 */
writel_relaxed(0 , priv->io_base + _REG(ENCI_MACV_N0));
/* Analog Synchronization and color burst value adjust */
writel_relaxed(mode->analog_sync_adj,
priv->io_base + _REG(ENCI_SYNC_ADJ));
priv->venc.current_mode = mode->mode_tag;
}
/* Returns the current ENCI field polarity */
unsigned int meson_venci_get_field(struct meson_drm *priv)
{
return readl_relaxed(priv->io_base + _REG(ENCI_INFO_READ)) & BIT(29 );
}
void meson_venc_enable_vsync(struct meson_drm *priv)
{
switch (priv->venc.current_mode) {
case MESON_VENC_MODE_MIPI_DSI:
writel_relaxed(VENC_INTCTRL_ENCP_LNRST_INT_EN,
priv->io_base + _REG(VENC_INTCTRL));
break ;
default :
writel_relaxed(VENC_INTCTRL_ENCI_LNRST_INT_EN,
priv->io_base + _REG(VENC_INTCTRL));
}
regmap_update_bits(priv->hhi, HHI_GCLK_MPEG2, BIT(25 ), BIT(25 ));
}
void meson_venc_disable_vsync(struct meson_drm *priv)
{
regmap_update_bits(priv->hhi, HHI_GCLK_MPEG2, BIT(25 ), 0 );
writel_relaxed(0 , priv->io_base + _REG(VENC_INTCTRL));
}
void meson_venc_init(struct meson_drm *priv)
{
/* Disable CVBS VDAC */
if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
regmap_write(priv->hhi, HHI_VDAC_CNTL0_G12A, 0 );
regmap_write(priv->hhi, HHI_VDAC_CNTL1_G12A, 8 );
} else {
regmap_write(priv->hhi, HHI_VDAC_CNTL0, 0 );
regmap_write(priv->hhi, HHI_VDAC_CNTL1, 8 );
}
/* Power Down Dacs */
writel_relaxed(0 xff, priv->io_base + _REG(VENC_VDAC_SETTING));
/* Disable HDMI PHY */
regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0 );
/* Disable HDMI */
writel_bits_relaxed(VPU_HDMI_ENCI_DATA_TO_HDMI |
VPU_HDMI_ENCP_DATA_TO_HDMI, 0 ,
priv->io_base + _REG(VPU_HDMI_SETTING));
/* Disable all encoders */
writel_relaxed(0 , priv->io_base + _REG(ENCI_VIDEO_EN));
writel_relaxed(0 , priv->io_base + _REG(ENCP_VIDEO_EN));
writel_relaxed(0 , priv->io_base + _REG(ENCL_VIDEO_EN));
/* Disable VSync IRQ */
meson_venc_disable_vsync(priv);
priv->venc.current_mode = MESON_VENC_MODE_NONE;
}
Messung V0.5 in Prozent C=97 H=95 G=95
¤ Dauer der Verarbeitung: 0.19 Sekunden
(vorverarbeitet am 2026-06-07)
¤
*© Formatika GbR, Deutschland