Commit | Line | Data |
---|---|---|
bbbe775e NA |
1 | /* |
2 | * Copyright (C) 2016 BayLibre, SAS | |
3 | * Author: Neil Armstrong <narmstrong@baylibre.com> | |
4 | * Copyright (C) 2015 Amlogic, Inc. All rights reserved. | |
5 | * | |
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. | |
10 | * | |
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. | |
15 | * | |
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/>. | |
18 | */ | |
19 | ||
20 | #include <linux/kernel.h> | |
21 | #include <linux/module.h> | |
22 | #include <drm/drmP.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" | |
28 | ||
29 | /* | |
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 | |
33 | * | |
34 | * What is missing : | |
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 | |
39 | */ | |
40 | ||
0c931a29 NA |
41 | /* HHI Registers */ |
42 | #define HHI_VDAC_CNTL0 0x2F4 /* 0xbd offset in data sheet */ | |
43 | #define HHI_VDAC_CNTL1 0x2F8 /* 0xbe offset in data sheet */ | |
44 | #define HHI_HDMI_PHY_CNTL0 0x3a0 /* 0xe8 offset in data sheet */ | |
45 | ||
bbbe775e NA |
46 | struct meson_cvbs_enci_mode meson_cvbs_enci_pal = { |
47 | .mode_tag = MESON_VENC_MODE_CVBS_PAL, | |
48 | .hso_begin = 3, | |
49 | .hso_end = 129, | |
50 | .vso_even = 3, | |
51 | .vso_odd = 260, | |
52 | .macv_max_amp = 7, | |
53 | .video_prog_mode = 0xff, | |
54 | .video_mode = 0x13, | |
55 | .sch_adjust = 0x28, | |
56 | .yc_delay = 0x343, | |
57 | .pixel_start = 251, | |
58 | .pixel_end = 1691, | |
59 | .top_field_line_start = 22, | |
60 | .top_field_line_end = 310, | |
61 | .bottom_field_line_start = 23, | |
62 | .bottom_field_line_end = 311, | |
63 | .video_saturation = 9, | |
64 | .video_contrast = 0, | |
65 | .video_brightness = 0, | |
66 | .video_hue = 0, | |
67 | .analog_sync_adj = 0x8080, | |
68 | }; | |
69 | ||
70 | struct meson_cvbs_enci_mode meson_cvbs_enci_ntsc = { | |
71 | .mode_tag = MESON_VENC_MODE_CVBS_NTSC, | |
72 | .hso_begin = 5, | |
73 | .hso_end = 129, | |
74 | .vso_even = 3, | |
75 | .vso_odd = 260, | |
76 | .macv_max_amp = 0xb, | |
77 | .video_prog_mode = 0xf0, | |
78 | .video_mode = 0x8, | |
79 | .sch_adjust = 0x20, | |
80 | .yc_delay = 0x333, | |
81 | .pixel_start = 227, | |
82 | .pixel_end = 1667, | |
83 | .top_field_line_start = 18, | |
84 | .top_field_line_end = 258, | |
85 | .bottom_field_line_start = 19, | |
86 | .bottom_field_line_end = 259, | |
87 | .video_saturation = 18, | |
88 | .video_contrast = 3, | |
89 | .video_brightness = 0, | |
90 | .video_hue = 0, | |
91 | .analog_sync_adj = 0x9c00, | |
92 | }; | |
93 | ||
94 | void meson_venci_cvbs_mode_set(struct meson_drm *priv, | |
95 | struct meson_cvbs_enci_mode *mode) | |
96 | { | |
97 | if (mode->mode_tag == priv->venc.current_mode) | |
98 | return; | |
99 | ||
100 | /* CVBS Filter settings */ | |
101 | writel_relaxed(0x12, priv->io_base + _REG(ENCI_CFILT_CTRL)); | |
102 | writel_relaxed(0x12, priv->io_base + _REG(ENCI_CFILT_CTRL2)); | |
103 | ||
104 | /* Digital Video Select : Interlace, clk27 clk, external */ | |
105 | writel_relaxed(0, priv->io_base + _REG(VENC_DVI_SETTING)); | |
106 | ||
107 | /* Reset Video Mode */ | |
108 | writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_MODE)); | |
109 | writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_MODE_ADV)); | |
110 | ||
111 | /* Horizontal sync signal output */ | |
112 | writel_relaxed(mode->hso_begin, | |
113 | priv->io_base + _REG(ENCI_SYNC_HSO_BEGIN)); | |
114 | writel_relaxed(mode->hso_end, | |
115 | priv->io_base + _REG(ENCI_SYNC_HSO_END)); | |
116 | ||
117 | /* Vertical Sync lines */ | |
118 | writel_relaxed(mode->vso_even, | |
119 | priv->io_base + _REG(ENCI_SYNC_VSO_EVNLN)); | |
120 | writel_relaxed(mode->vso_odd, | |
121 | priv->io_base + _REG(ENCI_SYNC_VSO_ODDLN)); | |
122 | ||
123 | /* Macrovision max amplitude change */ | |
124 | writel_relaxed(0x8100 + mode->macv_max_amp, | |
125 | priv->io_base + _REG(ENCI_MACV_MAX_AMP)); | |
126 | ||
127 | /* Video mode */ | |
128 | writel_relaxed(mode->video_prog_mode, | |
129 | priv->io_base + _REG(VENC_VIDEO_PROG_MODE)); | |
130 | writel_relaxed(mode->video_mode, | |
131 | priv->io_base + _REG(ENCI_VIDEO_MODE)); | |
132 | ||
133 | /* Advanced Video Mode : | |
134 | * Demux shifting 0x2 | |
135 | * Blank line end at line17/22 | |
136 | * High bandwidth Luma Filter | |
137 | * Low bandwidth Chroma Filter | |
138 | * Bypass luma low pass filter | |
139 | * No macrovision on CSYNC | |
140 | */ | |
141 | writel_relaxed(0x26, priv->io_base + _REG(ENCI_VIDEO_MODE_ADV)); | |
142 | ||
143 | writel(mode->sch_adjust, priv->io_base + _REG(ENCI_VIDEO_SCH)); | |
144 | ||
145 | /* Sync mode : MASTER Master mode, free run, send HSO/VSO out */ | |
146 | writel_relaxed(0x07, priv->io_base + _REG(ENCI_SYNC_MODE)); | |
147 | ||
148 | /* 0x3 Y, C, and Component Y delay */ | |
149 | writel_relaxed(mode->yc_delay, priv->io_base + _REG(ENCI_YC_DELAY)); | |
150 | ||
151 | /* Timings */ | |
152 | writel_relaxed(mode->pixel_start, | |
153 | priv->io_base + _REG(ENCI_VFIFO2VD_PIXEL_START)); | |
154 | writel_relaxed(mode->pixel_end, | |
155 | priv->io_base + _REG(ENCI_VFIFO2VD_PIXEL_END)); | |
156 | ||
157 | writel_relaxed(mode->top_field_line_start, | |
158 | priv->io_base + _REG(ENCI_VFIFO2VD_LINE_TOP_START)); | |
159 | writel_relaxed(mode->top_field_line_end, | |
160 | priv->io_base + _REG(ENCI_VFIFO2VD_LINE_TOP_END)); | |
161 | ||
162 | writel_relaxed(mode->bottom_field_line_start, | |
163 | priv->io_base + _REG(ENCI_VFIFO2VD_LINE_BOT_START)); | |
164 | writel_relaxed(mode->bottom_field_line_end, | |
165 | priv->io_base + _REG(ENCI_VFIFO2VD_LINE_BOT_END)); | |
166 | ||
167 | /* Internal Venc, Internal VIU Sync, Internal Vencoder */ | |
168 | writel_relaxed(0, priv->io_base + _REG(VENC_SYNC_ROUTE)); | |
169 | ||
170 | /* UNreset Interlaced TV Encoder */ | |
171 | writel_relaxed(0, priv->io_base + _REG(ENCI_DBG_PX_RST)); | |
172 | ||
173 | /* Enable Vfifo2vd, Y_Cb_Y_Cr select */ | |
174 | writel_relaxed(0x4e01, priv->io_base + _REG(ENCI_VFIFO2VD_CTL)); | |
175 | ||
176 | /* Power UP Dacs */ | |
177 | writel_relaxed(0, priv->io_base + _REG(VENC_VDAC_SETTING)); | |
178 | ||
179 | /* Video Upsampling */ | |
180 | writel_relaxed(0x0061, priv->io_base + _REG(VENC_UPSAMPLE_CTRL0)); | |
181 | writel_relaxed(0x4061, priv->io_base + _REG(VENC_UPSAMPLE_CTRL1)); | |
182 | writel_relaxed(0x5061, priv->io_base + _REG(VENC_UPSAMPLE_CTRL2)); | |
183 | ||
184 | /* Select Interlace Y DACs */ | |
185 | writel_relaxed(0, priv->io_base + _REG(VENC_VDAC_DACSEL0)); | |
186 | writel_relaxed(0, priv->io_base + _REG(VENC_VDAC_DACSEL1)); | |
187 | writel_relaxed(0, priv->io_base + _REG(VENC_VDAC_DACSEL2)); | |
188 | writel_relaxed(0, priv->io_base + _REG(VENC_VDAC_DACSEL3)); | |
189 | writel_relaxed(0, priv->io_base + _REG(VENC_VDAC_DACSEL4)); | |
190 | writel_relaxed(0, priv->io_base + _REG(VENC_VDAC_DACSEL5)); | |
191 | ||
192 | /* Select ENCI for VIU */ | |
193 | meson_vpp_setup_mux(priv, MESON_VIU_VPP_MUX_ENCI); | |
194 | ||
195 | /* Enable ENCI FIFO */ | |
196 | writel_relaxed(0x2000, priv->io_base + _REG(VENC_VDAC_FIFO_CTRL)); | |
197 | ||
198 | /* Select ENCI DACs 0, 1, 4, and 5 */ | |
199 | writel_relaxed(0x11, priv->io_base + _REG(ENCI_DACSEL_0)); | |
200 | writel_relaxed(0x11, priv->io_base + _REG(ENCI_DACSEL_1)); | |
201 | ||
202 | /* Interlace video enable */ | |
203 | writel_relaxed(1, priv->io_base + _REG(ENCI_VIDEO_EN)); | |
204 | ||
205 | /* Configure Video Saturation / Contrast / Brightness / Hue */ | |
206 | writel_relaxed(mode->video_saturation, | |
207 | priv->io_base + _REG(ENCI_VIDEO_SAT)); | |
208 | writel_relaxed(mode->video_contrast, | |
209 | priv->io_base + _REG(ENCI_VIDEO_CONT)); | |
210 | writel_relaxed(mode->video_brightness, | |
211 | priv->io_base + _REG(ENCI_VIDEO_BRIGHT)); | |
212 | writel_relaxed(mode->video_hue, | |
213 | priv->io_base + _REG(ENCI_VIDEO_HUE)); | |
214 | ||
215 | /* Enable DAC0 Filter */ | |
216 | writel_relaxed(0x1, priv->io_base + _REG(VENC_VDAC_DAC0_FILT_CTRL0)); | |
217 | writel_relaxed(0xfc48, priv->io_base + _REG(VENC_VDAC_DAC0_FILT_CTRL1)); | |
218 | ||
219 | /* 0 in Macrovision register 0 */ | |
220 | writel_relaxed(0, priv->io_base + _REG(ENCI_MACV_N0)); | |
221 | ||
222 | /* Analog Synchronization and color burst value adjust */ | |
223 | writel_relaxed(mode->analog_sync_adj, | |
224 | priv->io_base + _REG(ENCI_SYNC_ADJ)); | |
225 | ||
226 | /* Setup 27MHz vclk2 for ENCI and VDAC */ | |
227 | meson_vclk_setup(priv, MESON_VCLK_TARGET_CVBS, MESON_VCLK_CVBS); | |
228 | ||
229 | priv->venc.current_mode = mode->mode_tag; | |
230 | } | |
231 | ||
232 | /* Returns the current ENCI field polarity */ | |
233 | unsigned int meson_venci_get_field(struct meson_drm *priv) | |
234 | { | |
235 | return readl_relaxed(priv->io_base + _REG(ENCI_INFO_READ)) & BIT(29); | |
236 | } | |
237 | ||
238 | void meson_venc_enable_vsync(struct meson_drm *priv) | |
239 | { | |
240 | writel_relaxed(2, priv->io_base + _REG(VENC_INTCTRL)); | |
241 | } | |
242 | ||
243 | void meson_venc_disable_vsync(struct meson_drm *priv) | |
244 | { | |
245 | writel_relaxed(0, priv->io_base + _REG(VENC_INTCTRL)); | |
246 | } | |
247 | ||
248 | void meson_venc_init(struct meson_drm *priv) | |
249 | { | |
0c931a29 NA |
250 | /* Disable CVBS VDAC */ |
251 | regmap_write(priv->hhi, HHI_VDAC_CNTL0, 0); | |
252 | regmap_write(priv->hhi, HHI_VDAC_CNTL1, 8); | |
253 | ||
254 | /* Power Down Dacs */ | |
255 | writel_relaxed(0xff, priv->io_base + _REG(VENC_VDAC_SETTING)); | |
256 | ||
257 | /* Disable HDMI PHY */ | |
258 | regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0); | |
259 | ||
260 | /* Disable HDMI */ | |
261 | writel_bits_relaxed(0x3, 0, | |
262 | priv->io_base + _REG(VPU_HDMI_SETTING)); | |
263 | ||
bbbe775e NA |
264 | /* Disable all encoders */ |
265 | writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_EN)); | |
266 | writel_relaxed(0, priv->io_base + _REG(ENCP_VIDEO_EN)); | |
267 | writel_relaxed(0, priv->io_base + _REG(ENCL_VIDEO_EN)); | |
268 | ||
269 | /* Disable VSync IRQ */ | |
270 | meson_venc_disable_vsync(priv); | |
271 | ||
272 | priv->venc.current_mode = MESON_VENC_MODE_NONE; | |
273 | } |