1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Copyright (C) 2016 BayLibre, SAS |
4 | * Author: Neil Armstrong <narmstrong@baylibre.com> |
5 | * Copyright (C) 2015 Amlogic, Inc. All rights reserved. |
6 | * Copyright (C) 2014 Endless Mobile |
7 | * |
8 | * Written by: |
9 | * Jasper St. Pierre <jstpierre@mecheye.net> |
10 | */ |
11 | |
12 | #include <linux/bitfield.h> |
13 | #include <linux/soc/amlogic/meson-canvas.h> |
14 | |
15 | #include <drm/drm_atomic_helper.h> |
16 | #include <drm/drm_device.h> |
17 | #include <drm/drm_print.h> |
18 | #include <drm/drm_probe_helper.h> |
19 | #include <drm/drm_vblank.h> |
20 | |
21 | #include "meson_crtc.h" |
22 | #include "meson_plane.h" |
23 | #include "meson_registers.h" |
24 | #include "meson_venc.h" |
25 | #include "meson_viu.h" |
26 | #include "meson_rdma.h" |
27 | #include "meson_vpp.h" |
28 | #include "meson_osd_afbcd.h" |
29 | |
30 | #define MESON_G12A_VIU_OFFSET 0x5ec0 |
31 | |
32 | /* CRTC definition */ |
33 | |
34 | struct meson_crtc { |
35 | struct drm_crtc base; |
36 | struct drm_pending_vblank_event *event; |
37 | struct meson_drm *priv; |
38 | void (*enable_osd1)(struct meson_drm *priv); |
39 | void (*enable_vd1)(struct meson_drm *priv); |
40 | void (*enable_osd1_afbc)(struct meson_drm *priv); |
41 | void (*disable_osd1_afbc)(struct meson_drm *priv); |
42 | unsigned int viu_offset; |
43 | bool vsync_forced; |
44 | bool vsync_disabled; |
45 | }; |
46 | #define to_meson_crtc(x) container_of(x, struct meson_crtc, base) |
47 | |
48 | /* CRTC */ |
49 | |
50 | static int meson_crtc_enable_vblank(struct drm_crtc *crtc) |
51 | { |
52 | struct meson_crtc *meson_crtc = to_meson_crtc(crtc); |
53 | struct meson_drm *priv = meson_crtc->priv; |
54 | |
55 | meson_crtc->vsync_disabled = false; |
56 | meson_venc_enable_vsync(priv); |
57 | |
58 | return 0; |
59 | } |
60 | |
61 | static void meson_crtc_disable_vblank(struct drm_crtc *crtc) |
62 | { |
63 | struct meson_crtc *meson_crtc = to_meson_crtc(crtc); |
64 | struct meson_drm *priv = meson_crtc->priv; |
65 | |
66 | if (!meson_crtc->vsync_forced) { |
67 | meson_crtc->vsync_disabled = true; |
68 | meson_venc_disable_vsync(priv); |
69 | } |
70 | } |
71 | |
72 | static const struct drm_crtc_funcs meson_crtc_funcs = { |
73 | .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, |
74 | .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, |
75 | .destroy = drm_crtc_cleanup, |
76 | .page_flip = drm_atomic_helper_page_flip, |
77 | .reset = drm_atomic_helper_crtc_reset, |
78 | .set_config = drm_atomic_helper_set_config, |
79 | .enable_vblank = meson_crtc_enable_vblank, |
80 | .disable_vblank = meson_crtc_disable_vblank, |
81 | |
82 | }; |
83 | |
84 | static void meson_g12a_crtc_atomic_enable(struct drm_crtc *crtc, |
85 | struct drm_atomic_state *state) |
86 | { |
87 | struct meson_crtc *meson_crtc = to_meson_crtc(crtc); |
88 | struct drm_crtc_state *crtc_state = crtc->state; |
89 | struct meson_drm *priv = meson_crtc->priv; |
90 | |
91 | DRM_DEBUG_DRIVER("\n" ); |
92 | |
93 | if (!crtc_state) { |
94 | DRM_ERROR("Invalid crtc_state\n" ); |
95 | return; |
96 | } |
97 | |
98 | /* VD1 Preblend vertical start/end */ |
99 | writel(FIELD_PREP(GENMASK(11, 0), 2303), |
100 | addr: priv->io_base + _REG(VPP_PREBLEND_VD1_V_START_END)); |
101 | |
102 | /* Setup Blender */ |
103 | writel(val: crtc_state->mode.hdisplay | |
104 | crtc_state->mode.vdisplay << 16, |
105 | addr: priv->io_base + _REG(VPP_POSTBLEND_H_SIZE)); |
106 | |
107 | writel_relaxed(0 << 16 | |
108 | (crtc_state->mode.hdisplay - 1), |
109 | priv->io_base + _REG(VPP_OSD1_BLD_H_SCOPE)); |
110 | writel_relaxed(0 << 16 | |
111 | (crtc_state->mode.vdisplay - 1), |
112 | priv->io_base + _REG(VPP_OSD1_BLD_V_SCOPE)); |
113 | writel_relaxed(crtc_state->mode.hdisplay << 16 | |
114 | crtc_state->mode.vdisplay, |
115 | priv->io_base + _REG(VPP_OUT_H_V_SIZE)); |
116 | |
117 | drm_crtc_vblank_on(crtc); |
118 | } |
119 | |
120 | static void meson_crtc_atomic_enable(struct drm_crtc *crtc, |
121 | struct drm_atomic_state *state) |
122 | { |
123 | struct meson_crtc *meson_crtc = to_meson_crtc(crtc); |
124 | struct drm_crtc_state *crtc_state = crtc->state; |
125 | struct meson_drm *priv = meson_crtc->priv; |
126 | |
127 | DRM_DEBUG_DRIVER("\n" ); |
128 | |
129 | if (!crtc_state) { |
130 | DRM_ERROR("Invalid crtc_state\n" ); |
131 | return; |
132 | } |
133 | |
134 | /* Enable VPP Postblend */ |
135 | writel(val: crtc_state->mode.hdisplay, |
136 | addr: priv->io_base + _REG(VPP_POSTBLEND_H_SIZE)); |
137 | |
138 | /* VD1 Preblend vertical start/end */ |
139 | writel(FIELD_PREP(GENMASK(11, 0), 2303), |
140 | addr: priv->io_base + _REG(VPP_PREBLEND_VD1_V_START_END)); |
141 | |
142 | writel_bits_relaxed(VPP_POSTBLEND_ENABLE, VPP_POSTBLEND_ENABLE, |
143 | priv->io_base + _REG(VPP_MISC)); |
144 | |
145 | drm_crtc_vblank_on(crtc); |
146 | } |
147 | |
148 | static void meson_g12a_crtc_atomic_disable(struct drm_crtc *crtc, |
149 | struct drm_atomic_state *state) |
150 | { |
151 | struct meson_crtc *meson_crtc = to_meson_crtc(crtc); |
152 | struct meson_drm *priv = meson_crtc->priv; |
153 | |
154 | DRM_DEBUG_DRIVER("\n" ); |
155 | |
156 | drm_crtc_vblank_off(crtc); |
157 | |
158 | priv->viu.osd1_enabled = false; |
159 | priv->viu.osd1_commit = false; |
160 | |
161 | priv->viu.vd1_enabled = false; |
162 | priv->viu.vd1_commit = false; |
163 | |
164 | if (crtc->state->event && !crtc->state->active) { |
165 | spin_lock_irq(lock: &crtc->dev->event_lock); |
166 | drm_crtc_send_vblank_event(crtc, e: crtc->state->event); |
167 | spin_unlock_irq(lock: &crtc->dev->event_lock); |
168 | |
169 | crtc->state->event = NULL; |
170 | } |
171 | } |
172 | |
173 | static void meson_crtc_atomic_disable(struct drm_crtc *crtc, |
174 | struct drm_atomic_state *state) |
175 | { |
176 | struct meson_crtc *meson_crtc = to_meson_crtc(crtc); |
177 | struct meson_drm *priv = meson_crtc->priv; |
178 | |
179 | DRM_DEBUG_DRIVER("\n" ); |
180 | |
181 | drm_crtc_vblank_off(crtc); |
182 | |
183 | priv->viu.osd1_enabled = false; |
184 | priv->viu.osd1_commit = false; |
185 | |
186 | priv->viu.vd1_enabled = false; |
187 | priv->viu.vd1_commit = false; |
188 | |
189 | /* Disable VPP Postblend */ |
190 | writel_bits_relaxed(VPP_OSD1_POSTBLEND | VPP_VD1_POSTBLEND | |
191 | VPP_VD1_PREBLEND | VPP_POSTBLEND_ENABLE, 0, |
192 | priv->io_base + _REG(VPP_MISC)); |
193 | |
194 | if (crtc->state->event && !crtc->state->active) { |
195 | spin_lock_irq(lock: &crtc->dev->event_lock); |
196 | drm_crtc_send_vblank_event(crtc, e: crtc->state->event); |
197 | spin_unlock_irq(lock: &crtc->dev->event_lock); |
198 | |
199 | crtc->state->event = NULL; |
200 | } |
201 | } |
202 | |
203 | static void meson_crtc_atomic_begin(struct drm_crtc *crtc, |
204 | struct drm_atomic_state *state) |
205 | { |
206 | struct meson_crtc *meson_crtc = to_meson_crtc(crtc); |
207 | unsigned long flags; |
208 | |
209 | if (crtc->state->event) { |
210 | WARN_ON(drm_crtc_vblank_get(crtc) != 0); |
211 | |
212 | spin_lock_irqsave(&crtc->dev->event_lock, flags); |
213 | meson_crtc->event = crtc->state->event; |
214 | spin_unlock_irqrestore(lock: &crtc->dev->event_lock, flags); |
215 | crtc->state->event = NULL; |
216 | } |
217 | } |
218 | |
219 | static void meson_crtc_atomic_flush(struct drm_crtc *crtc, |
220 | struct drm_atomic_state *state) |
221 | { |
222 | struct meson_crtc *meson_crtc = to_meson_crtc(crtc); |
223 | struct meson_drm *priv = meson_crtc->priv; |
224 | |
225 | priv->viu.osd1_commit = true; |
226 | priv->viu.vd1_commit = true; |
227 | } |
228 | |
229 | static const struct drm_crtc_helper_funcs meson_crtc_helper_funcs = { |
230 | .atomic_begin = meson_crtc_atomic_begin, |
231 | .atomic_flush = meson_crtc_atomic_flush, |
232 | .atomic_enable = meson_crtc_atomic_enable, |
233 | .atomic_disable = meson_crtc_atomic_disable, |
234 | }; |
235 | |
236 | static const struct drm_crtc_helper_funcs meson_g12a_crtc_helper_funcs = { |
237 | .atomic_begin = meson_crtc_atomic_begin, |
238 | .atomic_flush = meson_crtc_atomic_flush, |
239 | .atomic_enable = meson_g12a_crtc_atomic_enable, |
240 | .atomic_disable = meson_g12a_crtc_atomic_disable, |
241 | }; |
242 | |
243 | static void meson_crtc_enable_osd1(struct meson_drm *priv) |
244 | { |
245 | writel_bits_relaxed(VPP_OSD1_POSTBLEND, VPP_OSD1_POSTBLEND, |
246 | priv->io_base + _REG(VPP_MISC)); |
247 | } |
248 | |
249 | static void meson_crtc_g12a_enable_osd1_afbc(struct meson_drm *priv) |
250 | { |
251 | writel_relaxed(priv->viu.osd1_blk2_cfg4, |
252 | priv->io_base + _REG(VIU_OSD1_BLK2_CFG_W4)); |
253 | |
254 | writel_bits_relaxed(OSD_MEM_LINEAR_ADDR, OSD_MEM_LINEAR_ADDR, |
255 | priv->io_base + _REG(VIU_OSD1_CTRL_STAT)); |
256 | |
257 | writel_relaxed(priv->viu.osd1_blk1_cfg4, |
258 | priv->io_base + _REG(VIU_OSD1_BLK1_CFG_W4)); |
259 | |
260 | meson_viu_g12a_enable_osd1_afbc(priv); |
261 | |
262 | writel_bits_relaxed(OSD_MEM_LINEAR_ADDR, OSD_MEM_LINEAR_ADDR, |
263 | priv->io_base + _REG(VIU_OSD1_CTRL_STAT)); |
264 | |
265 | writel_bits_relaxed(OSD_MALI_SRC_EN, OSD_MALI_SRC_EN, |
266 | priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W0)); |
267 | } |
268 | |
269 | static void meson_g12a_crtc_enable_osd1(struct meson_drm *priv) |
270 | { |
271 | writel_relaxed(priv->viu.osd_blend_din0_scope_h, |
272 | priv->io_base + |
273 | _REG(VIU_OSD_BLEND_DIN0_SCOPE_H)); |
274 | writel_relaxed(priv->viu.osd_blend_din0_scope_v, |
275 | priv->io_base + |
276 | _REG(VIU_OSD_BLEND_DIN0_SCOPE_V)); |
277 | writel_relaxed(priv->viu.osb_blend0_size, |
278 | priv->io_base + |
279 | _REG(VIU_OSD_BLEND_BLEND0_SIZE)); |
280 | writel_relaxed(priv->viu.osb_blend1_size, |
281 | priv->io_base + |
282 | _REG(VIU_OSD_BLEND_BLEND1_SIZE)); |
283 | writel_bits_relaxed(3 << 8, 3 << 8, |
284 | priv->io_base + _REG(OSD1_BLEND_SRC_CTRL)); |
285 | } |
286 | |
287 | static void meson_crtc_enable_vd1(struct meson_drm *priv) |
288 | { |
289 | writel_bits_relaxed(VPP_VD1_PREBLEND | VPP_VD1_POSTBLEND | |
290 | VPP_COLOR_MNG_ENABLE, |
291 | VPP_VD1_PREBLEND | VPP_VD1_POSTBLEND | |
292 | VPP_COLOR_MNG_ENABLE, |
293 | priv->io_base + _REG(VPP_MISC)); |
294 | |
295 | writel_bits_relaxed(VIU_CTRL0_AFBC_TO_VD1, |
296 | priv->viu.vd1_afbc ? VIU_CTRL0_AFBC_TO_VD1 : 0, |
297 | priv->io_base + _REG(VIU_MISC_CTRL0)); |
298 | } |
299 | |
300 | static void meson_g12a_crtc_enable_vd1(struct meson_drm *priv) |
301 | { |
302 | writel_relaxed(VD_BLEND_PREBLD_SRC_VD1 | |
303 | VD_BLEND_PREBLD_PREMULT_EN | |
304 | VD_BLEND_POSTBLD_SRC_VD1 | |
305 | VD_BLEND_POSTBLD_PREMULT_EN, |
306 | priv->io_base + _REG(VD1_BLEND_SRC_CTRL)); |
307 | |
308 | writel_relaxed(priv->viu.vd1_afbc ? |
309 | (VD1_AXI_SEL_AFBC | AFBC_VD1_SEL) : 0, |
310 | priv->io_base + _REG(VD1_AFBCD0_MISC_CTRL)); |
311 | } |
312 | |
313 | void meson_crtc_irq(struct meson_drm *priv) |
314 | { |
315 | struct meson_crtc *meson_crtc = to_meson_crtc(priv->crtc); |
316 | unsigned long flags; |
317 | |
318 | /* Update the OSD registers */ |
319 | if (priv->viu.osd1_enabled && priv->viu.osd1_commit) { |
320 | writel_relaxed(priv->viu.osd1_ctrl_stat, |
321 | priv->io_base + _REG(VIU_OSD1_CTRL_STAT)); |
322 | writel_relaxed(priv->viu.osd1_ctrl_stat2, |
323 | priv->io_base + _REG(VIU_OSD1_CTRL_STAT2)); |
324 | writel_relaxed(priv->viu.osd1_blk0_cfg[0], |
325 | priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W0)); |
326 | writel_relaxed(priv->viu.osd1_blk0_cfg[1], |
327 | priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W1)); |
328 | writel_relaxed(priv->viu.osd1_blk0_cfg[2], |
329 | priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W2)); |
330 | writel_relaxed(priv->viu.osd1_blk0_cfg[3], |
331 | priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W3)); |
332 | writel_relaxed(priv->viu.osd1_blk0_cfg[4], |
333 | priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W4)); |
334 | |
335 | if (priv->viu.osd1_afbcd) { |
336 | if (meson_crtc->enable_osd1_afbc) |
337 | meson_crtc->enable_osd1_afbc(priv); |
338 | } else { |
339 | if (meson_crtc->disable_osd1_afbc) |
340 | meson_crtc->disable_osd1_afbc(priv); |
341 | if (priv->afbcd.ops) { |
342 | priv->afbcd.ops->reset(priv); |
343 | priv->afbcd.ops->disable(priv); |
344 | } |
345 | meson_crtc->vsync_forced = false; |
346 | } |
347 | |
348 | writel_relaxed(priv->viu.osd_sc_ctrl0, |
349 | priv->io_base + _REG(VPP_OSD_SC_CTRL0)); |
350 | writel_relaxed(priv->viu.osd_sc_i_wh_m1, |
351 | priv->io_base + _REG(VPP_OSD_SCI_WH_M1)); |
352 | writel_relaxed(priv->viu.osd_sc_o_h_start_end, |
353 | priv->io_base + _REG(VPP_OSD_SCO_H_START_END)); |
354 | writel_relaxed(priv->viu.osd_sc_o_v_start_end, |
355 | priv->io_base + _REG(VPP_OSD_SCO_V_START_END)); |
356 | writel_relaxed(priv->viu.osd_sc_v_ini_phase, |
357 | priv->io_base + _REG(VPP_OSD_VSC_INI_PHASE)); |
358 | writel_relaxed(priv->viu.osd_sc_v_phase_step, |
359 | priv->io_base + _REG(VPP_OSD_VSC_PHASE_STEP)); |
360 | writel_relaxed(priv->viu.osd_sc_h_ini_phase, |
361 | priv->io_base + _REG(VPP_OSD_HSC_INI_PHASE)); |
362 | writel_relaxed(priv->viu.osd_sc_h_phase_step, |
363 | priv->io_base + _REG(VPP_OSD_HSC_PHASE_STEP)); |
364 | writel_relaxed(priv->viu.osd_sc_h_ctrl0, |
365 | priv->io_base + _REG(VPP_OSD_HSC_CTRL0)); |
366 | writel_relaxed(priv->viu.osd_sc_v_ctrl0, |
367 | priv->io_base + _REG(VPP_OSD_VSC_CTRL0)); |
368 | |
369 | if (!priv->viu.osd1_afbcd) |
370 | meson_canvas_config(canvas: priv->canvas, canvas_index: priv->canvas_id_osd1, |
371 | addr: priv->viu.osd1_addr, |
372 | stride: priv->viu.osd1_stride, |
373 | height: priv->viu.osd1_height, |
374 | MESON_CANVAS_WRAP_NONE, |
375 | MESON_CANVAS_BLKMODE_LINEAR, endian: 0); |
376 | |
377 | /* Enable OSD1 */ |
378 | if (meson_crtc->enable_osd1) |
379 | meson_crtc->enable_osd1(priv); |
380 | |
381 | if (priv->viu.osd1_afbcd) { |
382 | priv->afbcd.ops->reset(priv); |
383 | priv->afbcd.ops->setup(priv); |
384 | priv->afbcd.ops->enable(priv); |
385 | meson_crtc->vsync_forced = true; |
386 | } |
387 | |
388 | priv->viu.osd1_commit = false; |
389 | } |
390 | |
391 | /* Update the VD1 registers */ |
392 | if (priv->viu.vd1_enabled && priv->viu.vd1_commit) { |
393 | |
394 | if (priv->viu.vd1_afbc) { |
395 | writel_relaxed(priv->viu.vd1_afbc_head_addr, |
396 | priv->io_base + |
397 | _REG(AFBC_HEAD_BADDR)); |
398 | writel_relaxed(priv->viu.vd1_afbc_body_addr, |
399 | priv->io_base + |
400 | _REG(AFBC_BODY_BADDR)); |
401 | writel_relaxed(priv->viu.vd1_afbc_en, |
402 | priv->io_base + |
403 | _REG(AFBC_ENABLE)); |
404 | writel_relaxed(priv->viu.vd1_afbc_mode, |
405 | priv->io_base + |
406 | _REG(AFBC_MODE)); |
407 | writel_relaxed(priv->viu.vd1_afbc_size_in, |
408 | priv->io_base + |
409 | _REG(AFBC_SIZE_IN)); |
410 | writel_relaxed(priv->viu.vd1_afbc_dec_def_color, |
411 | priv->io_base + |
412 | _REG(AFBC_DEC_DEF_COLOR)); |
413 | writel_relaxed(priv->viu.vd1_afbc_conv_ctrl, |
414 | priv->io_base + |
415 | _REG(AFBC_CONV_CTRL)); |
416 | writel_relaxed(priv->viu.vd1_afbc_size_out, |
417 | priv->io_base + |
418 | _REG(AFBC_SIZE_OUT)); |
419 | writel_relaxed(priv->viu.vd1_afbc_vd_cfmt_ctrl, |
420 | priv->io_base + |
421 | _REG(AFBC_VD_CFMT_CTRL)); |
422 | writel_relaxed(priv->viu.vd1_afbc_vd_cfmt_w, |
423 | priv->io_base + |
424 | _REG(AFBC_VD_CFMT_W)); |
425 | writel_relaxed(priv->viu.vd1_afbc_mif_hor_scope, |
426 | priv->io_base + |
427 | _REG(AFBC_MIF_HOR_SCOPE)); |
428 | writel_relaxed(priv->viu.vd1_afbc_mif_ver_scope, |
429 | priv->io_base + |
430 | _REG(AFBC_MIF_VER_SCOPE)); |
431 | writel_relaxed(priv->viu.vd1_afbc_pixel_hor_scope, |
432 | priv->io_base+ |
433 | _REG(AFBC_PIXEL_HOR_SCOPE)); |
434 | writel_relaxed(priv->viu.vd1_afbc_pixel_ver_scope, |
435 | priv->io_base + |
436 | _REG(AFBC_PIXEL_VER_SCOPE)); |
437 | writel_relaxed(priv->viu.vd1_afbc_vd_cfmt_h, |
438 | priv->io_base + |
439 | _REG(AFBC_VD_CFMT_H)); |
440 | } else { |
441 | switch (priv->viu.vd1_planes) { |
442 | case 3: |
443 | meson_canvas_config(canvas: priv->canvas, |
444 | canvas_index: priv->canvas_id_vd1_2, |
445 | addr: priv->viu.vd1_addr2, |
446 | stride: priv->viu.vd1_stride2, |
447 | height: priv->viu.vd1_height2, |
448 | MESON_CANVAS_WRAP_NONE, |
449 | MESON_CANVAS_BLKMODE_LINEAR, |
450 | MESON_CANVAS_ENDIAN_SWAP64); |
451 | fallthrough; |
452 | case 2: |
453 | meson_canvas_config(canvas: priv->canvas, |
454 | canvas_index: priv->canvas_id_vd1_1, |
455 | addr: priv->viu.vd1_addr1, |
456 | stride: priv->viu.vd1_stride1, |
457 | height: priv->viu.vd1_height1, |
458 | MESON_CANVAS_WRAP_NONE, |
459 | MESON_CANVAS_BLKMODE_LINEAR, |
460 | MESON_CANVAS_ENDIAN_SWAP64); |
461 | fallthrough; |
462 | case 1: |
463 | meson_canvas_config(canvas: priv->canvas, |
464 | canvas_index: priv->canvas_id_vd1_0, |
465 | addr: priv->viu.vd1_addr0, |
466 | stride: priv->viu.vd1_stride0, |
467 | height: priv->viu.vd1_height0, |
468 | MESON_CANVAS_WRAP_NONE, |
469 | MESON_CANVAS_BLKMODE_LINEAR, |
470 | MESON_CANVAS_ENDIAN_SWAP64); |
471 | } |
472 | |
473 | writel_relaxed(0, priv->io_base + _REG(AFBC_ENABLE)); |
474 | } |
475 | |
476 | writel_relaxed(priv->viu.vd1_if0_gen_reg, |
477 | priv->io_base + meson_crtc->viu_offset + |
478 | _REG(VD1_IF0_GEN_REG)); |
479 | writel_relaxed(priv->viu.vd1_if0_gen_reg, |
480 | priv->io_base + meson_crtc->viu_offset + |
481 | _REG(VD2_IF0_GEN_REG)); |
482 | writel_relaxed(priv->viu.vd1_if0_gen_reg2, |
483 | priv->io_base + meson_crtc->viu_offset + |
484 | _REG(VD1_IF0_GEN_REG2)); |
485 | writel_relaxed(priv->viu.viu_vd1_fmt_ctrl, |
486 | priv->io_base + meson_crtc->viu_offset + |
487 | _REG(VIU_VD1_FMT_CTRL)); |
488 | writel_relaxed(priv->viu.viu_vd1_fmt_ctrl, |
489 | priv->io_base + meson_crtc->viu_offset + |
490 | _REG(VIU_VD2_FMT_CTRL)); |
491 | writel_relaxed(priv->viu.viu_vd1_fmt_w, |
492 | priv->io_base + meson_crtc->viu_offset + |
493 | _REG(VIU_VD1_FMT_W)); |
494 | writel_relaxed(priv->viu.viu_vd1_fmt_w, |
495 | priv->io_base + meson_crtc->viu_offset + |
496 | _REG(VIU_VD2_FMT_W)); |
497 | writel_relaxed(priv->viu.vd1_if0_canvas0, |
498 | priv->io_base + meson_crtc->viu_offset + |
499 | _REG(VD1_IF0_CANVAS0)); |
500 | writel_relaxed(priv->viu.vd1_if0_canvas0, |
501 | priv->io_base + meson_crtc->viu_offset + |
502 | _REG(VD1_IF0_CANVAS1)); |
503 | writel_relaxed(priv->viu.vd1_if0_canvas0, |
504 | priv->io_base + meson_crtc->viu_offset + |
505 | _REG(VD2_IF0_CANVAS0)); |
506 | writel_relaxed(priv->viu.vd1_if0_canvas0, |
507 | priv->io_base + meson_crtc->viu_offset + |
508 | _REG(VD2_IF0_CANVAS1)); |
509 | writel_relaxed(priv->viu.vd1_if0_luma_x0, |
510 | priv->io_base + meson_crtc->viu_offset + |
511 | _REG(VD1_IF0_LUMA_X0)); |
512 | writel_relaxed(priv->viu.vd1_if0_luma_x0, |
513 | priv->io_base + meson_crtc->viu_offset + |
514 | _REG(VD1_IF0_LUMA_X1)); |
515 | writel_relaxed(priv->viu.vd1_if0_luma_x0, |
516 | priv->io_base + meson_crtc->viu_offset + |
517 | _REG(VD2_IF0_LUMA_X0)); |
518 | writel_relaxed(priv->viu.vd1_if0_luma_x0, |
519 | priv->io_base + meson_crtc->viu_offset + |
520 | _REG(VD2_IF0_LUMA_X1)); |
521 | writel_relaxed(priv->viu.vd1_if0_luma_y0, |
522 | priv->io_base + meson_crtc->viu_offset + |
523 | _REG(VD1_IF0_LUMA_Y0)); |
524 | writel_relaxed(priv->viu.vd1_if0_luma_y0, |
525 | priv->io_base + meson_crtc->viu_offset + |
526 | _REG(VD1_IF0_LUMA_Y1)); |
527 | writel_relaxed(priv->viu.vd1_if0_luma_y0, |
528 | priv->io_base + meson_crtc->viu_offset + |
529 | _REG(VD2_IF0_LUMA_Y0)); |
530 | writel_relaxed(priv->viu.vd1_if0_luma_y0, |
531 | priv->io_base + meson_crtc->viu_offset + |
532 | _REG(VD2_IF0_LUMA_Y1)); |
533 | writel_relaxed(priv->viu.vd1_if0_chroma_x0, |
534 | priv->io_base + meson_crtc->viu_offset + |
535 | _REG(VD1_IF0_CHROMA_X0)); |
536 | writel_relaxed(priv->viu.vd1_if0_chroma_x0, |
537 | priv->io_base + meson_crtc->viu_offset + |
538 | _REG(VD1_IF0_CHROMA_X1)); |
539 | writel_relaxed(priv->viu.vd1_if0_chroma_x0, |
540 | priv->io_base + meson_crtc->viu_offset + |
541 | _REG(VD2_IF0_CHROMA_X0)); |
542 | writel_relaxed(priv->viu.vd1_if0_chroma_x0, |
543 | priv->io_base + meson_crtc->viu_offset + |
544 | _REG(VD2_IF0_CHROMA_X1)); |
545 | writel_relaxed(priv->viu.vd1_if0_chroma_y0, |
546 | priv->io_base + meson_crtc->viu_offset + |
547 | _REG(VD1_IF0_CHROMA_Y0)); |
548 | writel_relaxed(priv->viu.vd1_if0_chroma_y0, |
549 | priv->io_base + meson_crtc->viu_offset + |
550 | _REG(VD1_IF0_CHROMA_Y1)); |
551 | writel_relaxed(priv->viu.vd1_if0_chroma_y0, |
552 | priv->io_base + meson_crtc->viu_offset + |
553 | _REG(VD2_IF0_CHROMA_Y0)); |
554 | writel_relaxed(priv->viu.vd1_if0_chroma_y0, |
555 | priv->io_base + meson_crtc->viu_offset + |
556 | _REG(VD2_IF0_CHROMA_Y1)); |
557 | writel_relaxed(priv->viu.vd1_if0_repeat_loop, |
558 | priv->io_base + meson_crtc->viu_offset + |
559 | _REG(VD1_IF0_RPT_LOOP)); |
560 | writel_relaxed(priv->viu.vd1_if0_repeat_loop, |
561 | priv->io_base + meson_crtc->viu_offset + |
562 | _REG(VD2_IF0_RPT_LOOP)); |
563 | writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat, |
564 | priv->io_base + meson_crtc->viu_offset + |
565 | _REG(VD1_IF0_LUMA0_RPT_PAT)); |
566 | writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat, |
567 | priv->io_base + meson_crtc->viu_offset + |
568 | _REG(VD2_IF0_LUMA0_RPT_PAT)); |
569 | writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat, |
570 | priv->io_base + meson_crtc->viu_offset + |
571 | _REG(VD1_IF0_LUMA1_RPT_PAT)); |
572 | writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat, |
573 | priv->io_base + meson_crtc->viu_offset + |
574 | _REG(VD2_IF0_LUMA1_RPT_PAT)); |
575 | writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat, |
576 | priv->io_base + meson_crtc->viu_offset + |
577 | _REG(VD1_IF0_CHROMA0_RPT_PAT)); |
578 | writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat, |
579 | priv->io_base + meson_crtc->viu_offset + |
580 | _REG(VD2_IF0_CHROMA0_RPT_PAT)); |
581 | writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat, |
582 | priv->io_base + meson_crtc->viu_offset + |
583 | _REG(VD1_IF0_CHROMA1_RPT_PAT)); |
584 | writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat, |
585 | priv->io_base + meson_crtc->viu_offset + |
586 | _REG(VD2_IF0_CHROMA1_RPT_PAT)); |
587 | writel_relaxed(0, priv->io_base + meson_crtc->viu_offset + |
588 | _REG(VD1_IF0_LUMA_PSEL)); |
589 | writel_relaxed(0, priv->io_base + meson_crtc->viu_offset + |
590 | _REG(VD1_IF0_CHROMA_PSEL)); |
591 | writel_relaxed(0, priv->io_base + meson_crtc->viu_offset + |
592 | _REG(VD2_IF0_LUMA_PSEL)); |
593 | writel_relaxed(0, priv->io_base + meson_crtc->viu_offset + |
594 | _REG(VD2_IF0_CHROMA_PSEL)); |
595 | writel_relaxed(priv->viu.vd1_range_map_y, |
596 | priv->io_base + meson_crtc->viu_offset + |
597 | _REG(VD1_IF0_RANGE_MAP_Y)); |
598 | writel_relaxed(priv->viu.vd1_range_map_cb, |
599 | priv->io_base + meson_crtc->viu_offset + |
600 | _REG(VD1_IF0_RANGE_MAP_CB)); |
601 | writel_relaxed(priv->viu.vd1_range_map_cr, |
602 | priv->io_base + meson_crtc->viu_offset + |
603 | _REG(VD1_IF0_RANGE_MAP_CR)); |
604 | writel_relaxed(VPP_VSC_BANK_LENGTH(4) | |
605 | VPP_HSC_BANK_LENGTH(4) | |
606 | VPP_SC_VD_EN_ENABLE | |
607 | VPP_SC_TOP_EN_ENABLE | |
608 | VPP_SC_HSC_EN_ENABLE | |
609 | VPP_SC_VSC_EN_ENABLE, |
610 | priv->io_base + _REG(VPP_SC_MISC)); |
611 | writel_relaxed(priv->viu.vpp_pic_in_height, |
612 | priv->io_base + _REG(VPP_PIC_IN_HEIGHT)); |
613 | writel_relaxed(priv->viu.vpp_postblend_vd1_h_start_end, |
614 | priv->io_base + _REG(VPP_POSTBLEND_VD1_H_START_END)); |
615 | writel_relaxed(priv->viu.vpp_blend_vd2_h_start_end, |
616 | priv->io_base + _REG(VPP_BLEND_VD2_H_START_END)); |
617 | writel_relaxed(priv->viu.vpp_postblend_vd1_v_start_end, |
618 | priv->io_base + _REG(VPP_POSTBLEND_VD1_V_START_END)); |
619 | writel_relaxed(priv->viu.vpp_blend_vd2_v_start_end, |
620 | priv->io_base + _REG(VPP_BLEND_VD2_V_START_END)); |
621 | writel_relaxed(priv->viu.vpp_hsc_region12_startp, |
622 | priv->io_base + _REG(VPP_HSC_REGION12_STARTP)); |
623 | writel_relaxed(priv->viu.vpp_hsc_region34_startp, |
624 | priv->io_base + _REG(VPP_HSC_REGION34_STARTP)); |
625 | writel_relaxed(priv->viu.vpp_hsc_region4_endp, |
626 | priv->io_base + _REG(VPP_HSC_REGION4_ENDP)); |
627 | writel_relaxed(priv->viu.vpp_hsc_start_phase_step, |
628 | priv->io_base + _REG(VPP_HSC_START_PHASE_STEP)); |
629 | writel_relaxed(priv->viu.vpp_hsc_region1_phase_slope, |
630 | priv->io_base + _REG(VPP_HSC_REGION1_PHASE_SLOPE)); |
631 | writel_relaxed(priv->viu.vpp_hsc_region3_phase_slope, |
632 | priv->io_base + _REG(VPP_HSC_REGION3_PHASE_SLOPE)); |
633 | writel_relaxed(priv->viu.vpp_line_in_length, |
634 | priv->io_base + _REG(VPP_LINE_IN_LENGTH)); |
635 | writel_relaxed(priv->viu.vpp_preblend_h_size, |
636 | priv->io_base + _REG(VPP_PREBLEND_H_SIZE)); |
637 | writel_relaxed(priv->viu.vpp_vsc_region12_startp, |
638 | priv->io_base + _REG(VPP_VSC_REGION12_STARTP)); |
639 | writel_relaxed(priv->viu.vpp_vsc_region34_startp, |
640 | priv->io_base + _REG(VPP_VSC_REGION34_STARTP)); |
641 | writel_relaxed(priv->viu.vpp_vsc_region4_endp, |
642 | priv->io_base + _REG(VPP_VSC_REGION4_ENDP)); |
643 | writel_relaxed(priv->viu.vpp_vsc_start_phase_step, |
644 | priv->io_base + _REG(VPP_VSC_START_PHASE_STEP)); |
645 | writel_relaxed(priv->viu.vpp_vsc_ini_phase, |
646 | priv->io_base + _REG(VPP_VSC_INI_PHASE)); |
647 | writel_relaxed(priv->viu.vpp_vsc_phase_ctrl, |
648 | priv->io_base + _REG(VPP_VSC_PHASE_CTRL)); |
649 | writel_relaxed(priv->viu.vpp_hsc_phase_ctrl, |
650 | priv->io_base + _REG(VPP_HSC_PHASE_CTRL)); |
651 | writel_relaxed(0x42, priv->io_base + _REG(VPP_SCALE_COEF_IDX)); |
652 | |
653 | /* Enable VD1 */ |
654 | if (meson_crtc->enable_vd1) |
655 | meson_crtc->enable_vd1(priv); |
656 | |
657 | priv->viu.vd1_commit = false; |
658 | } |
659 | |
660 | if (meson_crtc->vsync_disabled) |
661 | return; |
662 | |
663 | drm_crtc_handle_vblank(crtc: priv->crtc); |
664 | |
665 | spin_lock_irqsave(&priv->drm->event_lock, flags); |
666 | if (meson_crtc->event) { |
667 | drm_crtc_send_vblank_event(crtc: priv->crtc, e: meson_crtc->event); |
668 | drm_crtc_vblank_put(crtc: priv->crtc); |
669 | meson_crtc->event = NULL; |
670 | } |
671 | spin_unlock_irqrestore(lock: &priv->drm->event_lock, flags); |
672 | } |
673 | |
674 | int meson_crtc_create(struct meson_drm *priv) |
675 | { |
676 | struct meson_crtc *meson_crtc; |
677 | struct drm_crtc *crtc; |
678 | int ret; |
679 | |
680 | meson_crtc = devm_kzalloc(dev: priv->drm->dev, size: sizeof(*meson_crtc), |
681 | GFP_KERNEL); |
682 | if (!meson_crtc) |
683 | return -ENOMEM; |
684 | |
685 | meson_crtc->priv = priv; |
686 | crtc = &meson_crtc->base; |
687 | ret = drm_crtc_init_with_planes(dev: priv->drm, crtc, |
688 | primary: priv->primary_plane, NULL, |
689 | funcs: &meson_crtc_funcs, name: "meson_crtc" ); |
690 | if (ret) { |
691 | dev_err(priv->drm->dev, "Failed to init CRTC\n" ); |
692 | return ret; |
693 | } |
694 | |
695 | if (meson_vpu_is_compatible(priv, family: VPU_COMPATIBLE_G12A)) { |
696 | meson_crtc->enable_osd1 = meson_g12a_crtc_enable_osd1; |
697 | meson_crtc->enable_vd1 = meson_g12a_crtc_enable_vd1; |
698 | meson_crtc->viu_offset = MESON_G12A_VIU_OFFSET; |
699 | meson_crtc->enable_osd1_afbc = |
700 | meson_crtc_g12a_enable_osd1_afbc; |
701 | meson_crtc->disable_osd1_afbc = |
702 | meson_viu_g12a_disable_osd1_afbc; |
703 | drm_crtc_helper_add(crtc, funcs: &meson_g12a_crtc_helper_funcs); |
704 | } else { |
705 | meson_crtc->enable_osd1 = meson_crtc_enable_osd1; |
706 | meson_crtc->enable_vd1 = meson_crtc_enable_vd1; |
707 | if (meson_vpu_is_compatible(priv, family: VPU_COMPATIBLE_GXM)) { |
708 | meson_crtc->enable_osd1_afbc = |
709 | meson_viu_gxm_enable_osd1_afbc; |
710 | meson_crtc->disable_osd1_afbc = |
711 | meson_viu_gxm_disable_osd1_afbc; |
712 | } |
713 | drm_crtc_helper_add(crtc, funcs: &meson_crtc_helper_funcs); |
714 | } |
715 | |
716 | priv->crtc = crtc; |
717 | |
718 | return 0; |
719 | } |
720 | |