2 * Copyright (C) 2016 BayLibre, SAS
3 * Author: Neil Armstrong <narmstrong@baylibre.com>
4 * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
20 #include <linux/kernel.h>
21 #include <linux/module.h>
23 #include "meson_drv.h"
24 #include "meson_venc.h"
25 #include "meson_vpp.h"
26 #include "meson_vclk.h"
27 #include "meson_registers.h"
30 * VENC Handle the pixels encoding to the output formats.
31 * We handle the following encodings :
32 * - CVBS Encoding via the ENCI encoder and VDAC digital to analog converter
35 * - TMDS/HDMI Encoding via ENCI_DIV and ENCP
36 * - Setup of more clock rates for HDMI modes
37 * - LCD Panel encoding via ENCL
38 * - TV Panel encoding via ENCT
41 struct meson_cvbs_enci_mode meson_cvbs_enci_pal
= {
42 .mode_tag
= MESON_VENC_MODE_CVBS_PAL
,
48 .video_prog_mode
= 0xff,
54 .top_field_line_start
= 22,
55 .top_field_line_end
= 310,
56 .bottom_field_line_start
= 23,
57 .bottom_field_line_end
= 311,
58 .video_saturation
= 9,
60 .video_brightness
= 0,
62 .analog_sync_adj
= 0x8080,
65 struct meson_cvbs_enci_mode meson_cvbs_enci_ntsc
= {
66 .mode_tag
= MESON_VENC_MODE_CVBS_NTSC
,
72 .video_prog_mode
= 0xf0,
78 .top_field_line_start
= 18,
79 .top_field_line_end
= 258,
80 .bottom_field_line_start
= 19,
81 .bottom_field_line_end
= 259,
82 .video_saturation
= 18,
84 .video_brightness
= 0,
86 .analog_sync_adj
= 0x9c00,
89 void meson_venci_cvbs_mode_set(struct meson_drm
*priv
,
90 struct meson_cvbs_enci_mode
*mode
)
92 if (mode
->mode_tag
== priv
->venc
.current_mode
)
95 /* CVBS Filter settings */
96 writel_relaxed(0x12, priv
->io_base
+ _REG(ENCI_CFILT_CTRL
));
97 writel_relaxed(0x12, priv
->io_base
+ _REG(ENCI_CFILT_CTRL2
));
99 /* Digital Video Select : Interlace, clk27 clk, external */
100 writel_relaxed(0, priv
->io_base
+ _REG(VENC_DVI_SETTING
));
102 /* Reset Video Mode */
103 writel_relaxed(0, priv
->io_base
+ _REG(ENCI_VIDEO_MODE
));
104 writel_relaxed(0, priv
->io_base
+ _REG(ENCI_VIDEO_MODE_ADV
));
106 /* Horizontal sync signal output */
107 writel_relaxed(mode
->hso_begin
,
108 priv
->io_base
+ _REG(ENCI_SYNC_HSO_BEGIN
));
109 writel_relaxed(mode
->hso_end
,
110 priv
->io_base
+ _REG(ENCI_SYNC_HSO_END
));
112 /* Vertical Sync lines */
113 writel_relaxed(mode
->vso_even
,
114 priv
->io_base
+ _REG(ENCI_SYNC_VSO_EVNLN
));
115 writel_relaxed(mode
->vso_odd
,
116 priv
->io_base
+ _REG(ENCI_SYNC_VSO_ODDLN
));
118 /* Macrovision max amplitude change */
119 writel_relaxed(0x8100 + mode
->macv_max_amp
,
120 priv
->io_base
+ _REG(ENCI_MACV_MAX_AMP
));
123 writel_relaxed(mode
->video_prog_mode
,
124 priv
->io_base
+ _REG(VENC_VIDEO_PROG_MODE
));
125 writel_relaxed(mode
->video_mode
,
126 priv
->io_base
+ _REG(ENCI_VIDEO_MODE
));
128 /* Advanced Video Mode :
130 * Blank line end at line17/22
131 * High bandwidth Luma Filter
132 * Low bandwidth Chroma Filter
133 * Bypass luma low pass filter
134 * No macrovision on CSYNC
136 writel_relaxed(0x26, priv
->io_base
+ _REG(ENCI_VIDEO_MODE_ADV
));
138 writel(mode
->sch_adjust
, priv
->io_base
+ _REG(ENCI_VIDEO_SCH
));
140 /* Sync mode : MASTER Master mode, free run, send HSO/VSO out */
141 writel_relaxed(0x07, priv
->io_base
+ _REG(ENCI_SYNC_MODE
));
143 /* 0x3 Y, C, and Component Y delay */
144 writel_relaxed(mode
->yc_delay
, priv
->io_base
+ _REG(ENCI_YC_DELAY
));
147 writel_relaxed(mode
->pixel_start
,
148 priv
->io_base
+ _REG(ENCI_VFIFO2VD_PIXEL_START
));
149 writel_relaxed(mode
->pixel_end
,
150 priv
->io_base
+ _REG(ENCI_VFIFO2VD_PIXEL_END
));
152 writel_relaxed(mode
->top_field_line_start
,
153 priv
->io_base
+ _REG(ENCI_VFIFO2VD_LINE_TOP_START
));
154 writel_relaxed(mode
->top_field_line_end
,
155 priv
->io_base
+ _REG(ENCI_VFIFO2VD_LINE_TOP_END
));
157 writel_relaxed(mode
->bottom_field_line_start
,
158 priv
->io_base
+ _REG(ENCI_VFIFO2VD_LINE_BOT_START
));
159 writel_relaxed(mode
->bottom_field_line_end
,
160 priv
->io_base
+ _REG(ENCI_VFIFO2VD_LINE_BOT_END
));
162 /* Internal Venc, Internal VIU Sync, Internal Vencoder */
163 writel_relaxed(0, priv
->io_base
+ _REG(VENC_SYNC_ROUTE
));
165 /* UNreset Interlaced TV Encoder */
166 writel_relaxed(0, priv
->io_base
+ _REG(ENCI_DBG_PX_RST
));
168 /* Enable Vfifo2vd, Y_Cb_Y_Cr select */
169 writel_relaxed(0x4e01, priv
->io_base
+ _REG(ENCI_VFIFO2VD_CTL
));
172 writel_relaxed(0, priv
->io_base
+ _REG(VENC_VDAC_SETTING
));
174 /* Video Upsampling */
175 writel_relaxed(0x0061, priv
->io_base
+ _REG(VENC_UPSAMPLE_CTRL0
));
176 writel_relaxed(0x4061, priv
->io_base
+ _REG(VENC_UPSAMPLE_CTRL1
));
177 writel_relaxed(0x5061, priv
->io_base
+ _REG(VENC_UPSAMPLE_CTRL2
));
179 /* Select Interlace Y DACs */
180 writel_relaxed(0, priv
->io_base
+ _REG(VENC_VDAC_DACSEL0
));
181 writel_relaxed(0, priv
->io_base
+ _REG(VENC_VDAC_DACSEL1
));
182 writel_relaxed(0, priv
->io_base
+ _REG(VENC_VDAC_DACSEL2
));
183 writel_relaxed(0, priv
->io_base
+ _REG(VENC_VDAC_DACSEL3
));
184 writel_relaxed(0, priv
->io_base
+ _REG(VENC_VDAC_DACSEL4
));
185 writel_relaxed(0, priv
->io_base
+ _REG(VENC_VDAC_DACSEL5
));
187 /* Select ENCI for VIU */
188 meson_vpp_setup_mux(priv
, MESON_VIU_VPP_MUX_ENCI
);
190 /* Enable ENCI FIFO */
191 writel_relaxed(0x2000, priv
->io_base
+ _REG(VENC_VDAC_FIFO_CTRL
));
193 /* Select ENCI DACs 0, 1, 4, and 5 */
194 writel_relaxed(0x11, priv
->io_base
+ _REG(ENCI_DACSEL_0
));
195 writel_relaxed(0x11, priv
->io_base
+ _REG(ENCI_DACSEL_1
));
197 /* Interlace video enable */
198 writel_relaxed(1, priv
->io_base
+ _REG(ENCI_VIDEO_EN
));
200 /* Configure Video Saturation / Contrast / Brightness / Hue */
201 writel_relaxed(mode
->video_saturation
,
202 priv
->io_base
+ _REG(ENCI_VIDEO_SAT
));
203 writel_relaxed(mode
->video_contrast
,
204 priv
->io_base
+ _REG(ENCI_VIDEO_CONT
));
205 writel_relaxed(mode
->video_brightness
,
206 priv
->io_base
+ _REG(ENCI_VIDEO_BRIGHT
));
207 writel_relaxed(mode
->video_hue
,
208 priv
->io_base
+ _REG(ENCI_VIDEO_HUE
));
210 /* Enable DAC0 Filter */
211 writel_relaxed(0x1, priv
->io_base
+ _REG(VENC_VDAC_DAC0_FILT_CTRL0
));
212 writel_relaxed(0xfc48, priv
->io_base
+ _REG(VENC_VDAC_DAC0_FILT_CTRL1
));
214 /* 0 in Macrovision register 0 */
215 writel_relaxed(0, priv
->io_base
+ _REG(ENCI_MACV_N0
));
217 /* Analog Synchronization and color burst value adjust */
218 writel_relaxed(mode
->analog_sync_adj
,
219 priv
->io_base
+ _REG(ENCI_SYNC_ADJ
));
221 /* Setup 27MHz vclk2 for ENCI and VDAC */
222 meson_vclk_setup(priv
, MESON_VCLK_TARGET_CVBS
, MESON_VCLK_CVBS
);
224 priv
->venc
.current_mode
= mode
->mode_tag
;
227 /* Returns the current ENCI field polarity */
228 unsigned int meson_venci_get_field(struct meson_drm
*priv
)
230 return readl_relaxed(priv
->io_base
+ _REG(ENCI_INFO_READ
)) & BIT(29);
233 void meson_venc_enable_vsync(struct meson_drm
*priv
)
235 writel_relaxed(2, priv
->io_base
+ _REG(VENC_INTCTRL
));
238 void meson_venc_disable_vsync(struct meson_drm
*priv
)
240 writel_relaxed(0, priv
->io_base
+ _REG(VENC_INTCTRL
));
243 void meson_venc_init(struct meson_drm
*priv
)
245 /* Disable all encoders */
246 writel_relaxed(0, priv
->io_base
+ _REG(ENCI_VIDEO_EN
));
247 writel_relaxed(0, priv
->io_base
+ _REG(ENCP_VIDEO_EN
));
248 writel_relaxed(0, priv
->io_base
+ _REG(ENCL_VIDEO_EN
));
250 /* Disable VSync IRQ */
251 meson_venc_disable_vsync(priv
);
253 priv
->venc
.current_mode
= MESON_VENC_MODE_NONE
;