2 * Copyright (C) 2016 BayLibre, SAS
3 * Author: Neil Armstrong <narmstrong@baylibre.com>
4 * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
5 * Copyright (C) 2014 Endless Mobile
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <http://www.gnu.org/licenses/>.
21 * Jasper St. Pierre <jstpierre@mecheye.net>
24 #include <linux/kernel.h>
25 #include <linux/module.h>
26 #include <linux/mutex.h>
27 #include <linux/platform_device.h>
28 #include <linux/bitfield.h>
30 #include <drm/drm_atomic.h>
31 #include <drm/drm_atomic_helper.h>
32 #include <drm/drm_flip_work.h>
33 #include <drm/drm_probe_helper.h>
35 #include "meson_crtc.h"
36 #include "meson_plane.h"
37 #include "meson_venc.h"
38 #include "meson_vpp.h"
39 #include "meson_viu.h"
40 #include "meson_registers.h"
46 struct drm_pending_vblank_event *event;
47 struct meson_drm *priv;
49 #define to_meson_crtc(x) container_of(x, struct meson_crtc, base)
53 static int meson_crtc_enable_vblank(struct drm_crtc *crtc)
55 struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
56 struct meson_drm *priv = meson_crtc->priv;
58 meson_venc_enable_vsync(priv);
63 static void meson_crtc_disable_vblank(struct drm_crtc *crtc)
65 struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
66 struct meson_drm *priv = meson_crtc->priv;
68 meson_venc_disable_vsync(priv);
71 static const struct drm_crtc_funcs meson_crtc_funcs = {
72 .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
73 .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
74 .destroy = drm_crtc_cleanup,
75 .page_flip = drm_atomic_helper_page_flip,
76 .reset = drm_atomic_helper_crtc_reset,
77 .set_config = drm_atomic_helper_set_config,
78 .enable_vblank = meson_crtc_enable_vblank,
79 .disable_vblank = meson_crtc_disable_vblank,
83 static void meson_crtc_atomic_enable(struct drm_crtc *crtc,
84 struct drm_crtc_state *old_state)
86 struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
87 struct drm_crtc_state *crtc_state = crtc->state;
88 struct meson_drm *priv = meson_crtc->priv;
90 DRM_DEBUG_DRIVER("\n");
93 DRM_ERROR("Invalid crtc_state\n");
97 /* Enable VPP Postblend */
98 writel(crtc_state->mode.hdisplay,
99 priv->io_base + _REG(VPP_POSTBLEND_H_SIZE));
101 /* VD1 Preblend vertical start/end */
102 writel(FIELD_PREP(GENMASK(11, 0), 2303),
103 priv->io_base + _REG(VPP_PREBLEND_VD1_V_START_END));
105 writel_bits_relaxed(VPP_POSTBLEND_ENABLE, VPP_POSTBLEND_ENABLE,
106 priv->io_base + _REG(VPP_MISC));
108 drm_crtc_vblank_on(crtc);
110 priv->viu.osd1_enabled = true;
113 static void meson_crtc_atomic_disable(struct drm_crtc *crtc,
114 struct drm_crtc_state *old_state)
116 struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
117 struct meson_drm *priv = meson_crtc->priv;
119 DRM_DEBUG_DRIVER("\n");
121 drm_crtc_vblank_off(crtc);
123 priv->viu.osd1_enabled = false;
124 priv->viu.osd1_commit = false;
126 priv->viu.vd1_enabled = false;
127 priv->viu.vd1_commit = false;
129 /* Disable VPP Postblend */
130 writel_bits_relaxed(VPP_OSD1_POSTBLEND | VPP_VD1_POSTBLEND |
131 VPP_VD1_PREBLEND | VPP_POSTBLEND_ENABLE, 0,
132 priv->io_base + _REG(VPP_MISC));
134 if (crtc->state->event && !crtc->state->active) {
135 spin_lock_irq(&crtc->dev->event_lock);
136 drm_crtc_send_vblank_event(crtc, crtc->state->event);
137 spin_unlock_irq(&crtc->dev->event_lock);
139 crtc->state->event = NULL;
143 static void meson_crtc_atomic_begin(struct drm_crtc *crtc,
144 struct drm_crtc_state *state)
146 struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
149 if (crtc->state->event) {
150 WARN_ON(drm_crtc_vblank_get(crtc) != 0);
152 spin_lock_irqsave(&crtc->dev->event_lock, flags);
153 meson_crtc->event = crtc->state->event;
154 spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
155 crtc->state->event = NULL;
159 static void meson_crtc_atomic_flush(struct drm_crtc *crtc,
160 struct drm_crtc_state *old_crtc_state)
162 struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
163 struct meson_drm *priv = meson_crtc->priv;
165 priv->viu.osd1_commit = true;
166 priv->viu.vd1_commit = true;
169 static const struct drm_crtc_helper_funcs meson_crtc_helper_funcs = {
170 .atomic_begin = meson_crtc_atomic_begin,
171 .atomic_flush = meson_crtc_atomic_flush,
172 .atomic_enable = meson_crtc_atomic_enable,
173 .atomic_disable = meson_crtc_atomic_disable,
176 void meson_crtc_irq(struct meson_drm *priv)
178 struct meson_crtc *meson_crtc = to_meson_crtc(priv->crtc);
181 /* Update the OSD registers */
182 if (priv->viu.osd1_enabled && priv->viu.osd1_commit) {
183 writel_relaxed(priv->viu.osd1_ctrl_stat,
184 priv->io_base + _REG(VIU_OSD1_CTRL_STAT));
185 writel_relaxed(priv->viu.osd1_blk0_cfg[0],
186 priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W0));
187 writel_relaxed(priv->viu.osd1_blk0_cfg[1],
188 priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W1));
189 writel_relaxed(priv->viu.osd1_blk0_cfg[2],
190 priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W2));
191 writel_relaxed(priv->viu.osd1_blk0_cfg[3],
192 priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W3));
193 writel_relaxed(priv->viu.osd1_blk0_cfg[4],
194 priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W4));
195 writel_relaxed(priv->viu.osd_sc_ctrl0,
196 priv->io_base + _REG(VPP_OSD_SC_CTRL0));
197 writel_relaxed(priv->viu.osd_sc_i_wh_m1,
198 priv->io_base + _REG(VPP_OSD_SCI_WH_M1));
199 writel_relaxed(priv->viu.osd_sc_o_h_start_end,
200 priv->io_base + _REG(VPP_OSD_SCO_H_START_END));
201 writel_relaxed(priv->viu.osd_sc_o_v_start_end,
202 priv->io_base + _REG(VPP_OSD_SCO_V_START_END));
203 writel_relaxed(priv->viu.osd_sc_v_ini_phase,
204 priv->io_base + _REG(VPP_OSD_VSC_INI_PHASE));
205 writel_relaxed(priv->viu.osd_sc_v_phase_step,
206 priv->io_base + _REG(VPP_OSD_VSC_PHASE_STEP));
207 writel_relaxed(priv->viu.osd_sc_h_ini_phase,
208 priv->io_base + _REG(VPP_OSD_HSC_INI_PHASE));
209 writel_relaxed(priv->viu.osd_sc_h_phase_step,
210 priv->io_base + _REG(VPP_OSD_HSC_PHASE_STEP));
211 writel_relaxed(priv->viu.osd_sc_h_ctrl0,
212 priv->io_base + _REG(VPP_OSD_HSC_CTRL0));
213 writel_relaxed(priv->viu.osd_sc_v_ctrl0,
214 priv->io_base + _REG(VPP_OSD_VSC_CTRL0));
216 meson_canvas_config(priv->canvas, priv->canvas_id_osd1,
217 priv->viu.osd1_addr, priv->viu.osd1_stride,
218 priv->viu.osd1_height, MESON_CANVAS_WRAP_NONE,
219 MESON_CANVAS_BLKMODE_LINEAR, 0);
222 writel_bits_relaxed(VPP_OSD1_POSTBLEND, VPP_OSD1_POSTBLEND,
223 priv->io_base + _REG(VPP_MISC));
225 priv->viu.osd1_commit = false;
228 /* Update the VD1 registers */
229 if (priv->viu.vd1_enabled && priv->viu.vd1_commit) {
231 switch (priv->viu.vd1_planes) {
233 meson_canvas_config(priv->canvas,
234 priv->canvas_id_vd1_2,
236 priv->viu.vd1_stride2,
237 priv->viu.vd1_height2,
238 MESON_CANVAS_WRAP_NONE,
239 MESON_CANVAS_BLKMODE_LINEAR,
240 MESON_CANVAS_ENDIAN_SWAP64);
243 meson_canvas_config(priv->canvas,
244 priv->canvas_id_vd1_1,
246 priv->viu.vd1_stride1,
247 priv->viu.vd1_height1,
248 MESON_CANVAS_WRAP_NONE,
249 MESON_CANVAS_BLKMODE_LINEAR,
250 MESON_CANVAS_ENDIAN_SWAP64);
253 meson_canvas_config(priv->canvas,
254 priv->canvas_id_vd1_0,
256 priv->viu.vd1_stride0,
257 priv->viu.vd1_height0,
258 MESON_CANVAS_WRAP_NONE,
259 MESON_CANVAS_BLKMODE_LINEAR,
260 MESON_CANVAS_ENDIAN_SWAP64);
263 writel_relaxed(priv->viu.vd1_if0_gen_reg,
264 priv->io_base + _REG(VD1_IF0_GEN_REG));
265 writel_relaxed(priv->viu.vd1_if0_gen_reg,
266 priv->io_base + _REG(VD2_IF0_GEN_REG));
267 writel_relaxed(priv->viu.vd1_if0_gen_reg2,
268 priv->io_base + _REG(VD1_IF0_GEN_REG2));
269 writel_relaxed(priv->viu.viu_vd1_fmt_ctrl,
270 priv->io_base + _REG(VIU_VD1_FMT_CTRL));
271 writel_relaxed(priv->viu.viu_vd1_fmt_ctrl,
272 priv->io_base + _REG(VIU_VD2_FMT_CTRL));
273 writel_relaxed(priv->viu.viu_vd1_fmt_w,
274 priv->io_base + _REG(VIU_VD1_FMT_W));
275 writel_relaxed(priv->viu.viu_vd1_fmt_w,
276 priv->io_base + _REG(VIU_VD2_FMT_W));
277 writel_relaxed(priv->viu.vd1_if0_canvas0,
278 priv->io_base + _REG(VD1_IF0_CANVAS0));
279 writel_relaxed(priv->viu.vd1_if0_canvas0,
280 priv->io_base + _REG(VD1_IF0_CANVAS1));
281 writel_relaxed(priv->viu.vd1_if0_canvas0,
282 priv->io_base + _REG(VD2_IF0_CANVAS0));
283 writel_relaxed(priv->viu.vd1_if0_canvas0,
284 priv->io_base + _REG(VD2_IF0_CANVAS1));
285 writel_relaxed(priv->viu.vd1_if0_luma_x0,
286 priv->io_base + _REG(VD1_IF0_LUMA_X0));
287 writel_relaxed(priv->viu.vd1_if0_luma_x0,
288 priv->io_base + _REG(VD1_IF0_LUMA_X1));
289 writel_relaxed(priv->viu.vd1_if0_luma_x0,
290 priv->io_base + _REG(VD2_IF0_LUMA_X0));
291 writel_relaxed(priv->viu.vd1_if0_luma_x0,
292 priv->io_base + _REG(VD2_IF0_LUMA_X1));
293 writel_relaxed(priv->viu.vd1_if0_luma_y0,
294 priv->io_base + _REG(VD1_IF0_LUMA_Y0));
295 writel_relaxed(priv->viu.vd1_if0_luma_y0,
296 priv->io_base + _REG(VD1_IF0_LUMA_Y1));
297 writel_relaxed(priv->viu.vd1_if0_luma_y0,
298 priv->io_base + _REG(VD2_IF0_LUMA_Y0));
299 writel_relaxed(priv->viu.vd1_if0_luma_y0,
300 priv->io_base + _REG(VD2_IF0_LUMA_Y1));
301 writel_relaxed(priv->viu.vd1_if0_chroma_x0,
302 priv->io_base + _REG(VD1_IF0_CHROMA_X0));
303 writel_relaxed(priv->viu.vd1_if0_chroma_x0,
304 priv->io_base + _REG(VD1_IF0_CHROMA_X1));
305 writel_relaxed(priv->viu.vd1_if0_chroma_x0,
306 priv->io_base + _REG(VD2_IF0_CHROMA_X0));
307 writel_relaxed(priv->viu.vd1_if0_chroma_x0,
308 priv->io_base + _REG(VD2_IF0_CHROMA_X1));
309 writel_relaxed(priv->viu.vd1_if0_chroma_y0,
310 priv->io_base + _REG(VD1_IF0_CHROMA_Y0));
311 writel_relaxed(priv->viu.vd1_if0_chroma_y0,
312 priv->io_base + _REG(VD1_IF0_CHROMA_Y1));
313 writel_relaxed(priv->viu.vd1_if0_chroma_y0,
314 priv->io_base + _REG(VD2_IF0_CHROMA_Y0));
315 writel_relaxed(priv->viu.vd1_if0_chroma_y0,
316 priv->io_base + _REG(VD2_IF0_CHROMA_Y1));
317 writel_relaxed(priv->viu.vd1_if0_repeat_loop,
318 priv->io_base + _REG(VD1_IF0_RPT_LOOP));
319 writel_relaxed(priv->viu.vd1_if0_repeat_loop,
320 priv->io_base + _REG(VD2_IF0_RPT_LOOP));
321 writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat,
322 priv->io_base + _REG(VD1_IF0_LUMA0_RPT_PAT));
323 writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat,
324 priv->io_base + _REG(VD2_IF0_LUMA0_RPT_PAT));
325 writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat,
326 priv->io_base + _REG(VD1_IF0_LUMA1_RPT_PAT));
327 writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat,
328 priv->io_base + _REG(VD2_IF0_LUMA1_RPT_PAT));
329 writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat,
330 priv->io_base + _REG(VD1_IF0_CHROMA0_RPT_PAT));
331 writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat,
332 priv->io_base + _REG(VD2_IF0_CHROMA0_RPT_PAT));
333 writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat,
334 priv->io_base + _REG(VD1_IF0_CHROMA1_RPT_PAT));
335 writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat,
336 priv->io_base + _REG(VD2_IF0_CHROMA1_RPT_PAT));
337 writel_relaxed(0, priv->io_base + _REG(VD1_IF0_LUMA_PSEL));
338 writel_relaxed(0, priv->io_base + _REG(VD1_IF0_CHROMA_PSEL));
339 writel_relaxed(0, priv->io_base + _REG(VD2_IF0_LUMA_PSEL));
340 writel_relaxed(0, priv->io_base + _REG(VD2_IF0_CHROMA_PSEL));
341 writel_relaxed(priv->viu.vd1_range_map_y,
342 priv->io_base + _REG(VD1_IF0_RANGE_MAP_Y));
343 writel_relaxed(priv->viu.vd1_range_map_cb,
344 priv->io_base + _REG(VD1_IF0_RANGE_MAP_CB));
345 writel_relaxed(priv->viu.vd1_range_map_cr,
346 priv->io_base + _REG(VD1_IF0_RANGE_MAP_CR));
347 writel_relaxed(0x78404,
348 priv->io_base + _REG(VPP_SC_MISC));
349 writel_relaxed(priv->viu.vpp_pic_in_height,
350 priv->io_base + _REG(VPP_PIC_IN_HEIGHT));
351 writel_relaxed(priv->viu.vpp_postblend_vd1_h_start_end,
352 priv->io_base + _REG(VPP_POSTBLEND_VD1_H_START_END));
353 writel_relaxed(priv->viu.vpp_blend_vd2_h_start_end,
354 priv->io_base + _REG(VPP_BLEND_VD2_H_START_END));
355 writel_relaxed(priv->viu.vpp_postblend_vd1_v_start_end,
356 priv->io_base + _REG(VPP_POSTBLEND_VD1_V_START_END));
357 writel_relaxed(priv->viu.vpp_blend_vd2_v_start_end,
358 priv->io_base + _REG(VPP_BLEND_VD2_V_START_END));
359 writel_relaxed(priv->viu.vpp_hsc_region12_startp,
360 priv->io_base + _REG(VPP_HSC_REGION12_STARTP));
361 writel_relaxed(priv->viu.vpp_hsc_region34_startp,
362 priv->io_base + _REG(VPP_HSC_REGION34_STARTP));
363 writel_relaxed(priv->viu.vpp_hsc_region4_endp,
364 priv->io_base + _REG(VPP_HSC_REGION4_ENDP));
365 writel_relaxed(priv->viu.vpp_hsc_start_phase_step,
366 priv->io_base + _REG(VPP_HSC_START_PHASE_STEP));
367 writel_relaxed(priv->viu.vpp_hsc_region1_phase_slope,
368 priv->io_base + _REG(VPP_HSC_REGION1_PHASE_SLOPE));
369 writel_relaxed(priv->viu.vpp_hsc_region3_phase_slope,
370 priv->io_base + _REG(VPP_HSC_REGION3_PHASE_SLOPE));
371 writel_relaxed(priv->viu.vpp_line_in_length,
372 priv->io_base + _REG(VPP_LINE_IN_LENGTH));
373 writel_relaxed(priv->viu.vpp_preblend_h_size,
374 priv->io_base + _REG(VPP_PREBLEND_H_SIZE));
375 writel_relaxed(priv->viu.vpp_vsc_region12_startp,
376 priv->io_base + _REG(VPP_VSC_REGION12_STARTP));
377 writel_relaxed(priv->viu.vpp_vsc_region34_startp,
378 priv->io_base + _REG(VPP_VSC_REGION34_STARTP));
379 writel_relaxed(priv->viu.vpp_vsc_region4_endp,
380 priv->io_base + _REG(VPP_VSC_REGION4_ENDP));
381 writel_relaxed(priv->viu.vpp_vsc_start_phase_step,
382 priv->io_base + _REG(VPP_VSC_START_PHASE_STEP));
383 writel_relaxed(priv->viu.vpp_vsc_ini_phase,
384 priv->io_base + _REG(VPP_VSC_INI_PHASE));
385 writel_relaxed(priv->viu.vpp_vsc_phase_ctrl,
386 priv->io_base + _REG(VPP_VSC_PHASE_CTRL));
387 writel_relaxed(priv->viu.vpp_hsc_phase_ctrl,
388 priv->io_base + _REG(VPP_HSC_PHASE_CTRL));
389 writel_relaxed(0x42, priv->io_base + _REG(VPP_SCALE_COEF_IDX));
392 writel_bits_relaxed(VPP_VD1_PREBLEND | VPP_VD1_POSTBLEND |
393 VPP_COLOR_MNG_ENABLE,
394 VPP_VD1_PREBLEND | VPP_VD1_POSTBLEND |
395 VPP_COLOR_MNG_ENABLE,
396 priv->io_base + _REG(VPP_MISC));
398 priv->viu.vd1_commit = false;
401 drm_crtc_handle_vblank(priv->crtc);
403 spin_lock_irqsave(&priv->drm->event_lock, flags);
404 if (meson_crtc->event) {
405 drm_crtc_send_vblank_event(priv->crtc, meson_crtc->event);
406 drm_crtc_vblank_put(priv->crtc);
407 meson_crtc->event = NULL;
409 spin_unlock_irqrestore(&priv->drm->event_lock, flags);
412 int meson_crtc_create(struct meson_drm *priv)
414 struct meson_crtc *meson_crtc;
415 struct drm_crtc *crtc;
418 meson_crtc = devm_kzalloc(priv->drm->dev, sizeof(*meson_crtc),
423 meson_crtc->priv = priv;
424 crtc = &meson_crtc->base;
425 ret = drm_crtc_init_with_planes(priv->drm, crtc,
426 priv->primary_plane, NULL,
427 &meson_crtc_funcs, "meson_crtc");
429 dev_err(priv->drm->dev, "Failed to init CRTC\n");
433 drm_crtc_helper_add(crtc, &meson_crtc_helper_funcs);