/*
* Copyright (C) 2016 BayLibre, SAS
* Author: Neil Armstrong <narmstrong@baylibre.com>
* Copyright (C) 2015 Amlogic, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <drm/drmP.h>
#include "meson_drv.h"
#include "meson_venc.h"
#include "meson_vpp.h"
#include "meson_vclk.h"
#include "meson_registers.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 initialy desined 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_VDAC_CNTL0 0x2F4 /* 0xbd offset in data sheet */
#define HHI_VDAC_CNTL1 0x2F8 /* 0xbe offset in data sheet */
#define HHI_HDMI_PHY_CNTL0 0x3a0 /* 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 = 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,
|