1 From e84da235223d0209165183c430692dde5c69854c Mon Sep 17 00:00:00 2001
2 From: Maxime Ripard <maxime@cerno.tech>
3 Date: Fri, 17 Feb 2023 15:25:16 +0100
4 Subject: [PATCH] drm/vc4: hvs: Support BCM2712 HVS
6 The HVS found in the BCM2712, while having a similar role, is very
7 different from the one found in the previous SoCs. Indeed, the register
8 layout is fairly different, and the DLIST format is new as well.
10 Let's introduce the needed functions to support the new HVS.
12 Signed-off-by: Maxime Ripard <maxime@cerno.tech>
14 drivers/gpu/drm/vc4/vc4_crtc.c | 47 ++-
15 drivers/gpu/drm/vc4/vc4_drv.c | 8 +-
16 drivers/gpu/drm/vc4/vc4_drv.h | 18 +
17 drivers/gpu/drm/vc4/vc4_hvs.c | 626 ++++++++++++++++++++++++++++---
18 drivers/gpu/drm/vc4/vc4_kms.c | 102 ++++-
19 drivers/gpu/drm/vc4/vc4_plane.c | 641 +++++++++++++++++++++++++++++++-
20 drivers/gpu/drm/vc4/vc4_regs.h | 181 +++++++++
21 7 files changed, 1540 insertions(+), 83 deletions(-)
23 --- a/drivers/gpu/drm/vc4/vc4_crtc.c
24 +++ b/drivers/gpu/drm/vc4/vc4_crtc.c
25 @@ -82,13 +82,22 @@ static unsigned int
26 vc4_crtc_get_cob_allocation(struct vc4_dev *vc4, unsigned int channel)
28 struct vc4_hvs *hvs = vc4->hvs;
29 - u32 dispbase = HVS_READ(SCALER_DISPBASEX(channel));
30 + u32 dispbase, top, base;
32 /* Top/base are supposed to be 4-pixel aligned, but the
33 * Raspberry Pi firmware fills the low bits (which are
34 * presumably ignored).
36 - u32 top = VC4_GET_FIELD(dispbase, SCALER_DISPBASEX_TOP) & ~3;
37 - u32 base = VC4_GET_FIELD(dispbase, SCALER_DISPBASEX_BASE) & ~3;
39 + if (vc4->gen >= VC4_GEN_6) {
40 + dispbase = HVS_READ(SCALER6_DISPX_COB(channel));
41 + top = VC4_GET_FIELD(dispbase, SCALER6_DISPX_COB_TOP) & ~3;
42 + base = VC4_GET_FIELD(dispbase, SCALER6_DISPX_COB_BASE) & ~3;
44 + dispbase = HVS_READ(SCALER_DISPBASEX(channel));
45 + top = VC4_GET_FIELD(dispbase, SCALER_DISPBASEX_TOP) & ~3;
46 + base = VC4_GET_FIELD(dispbase, SCALER_DISPBASEX_BASE) & ~3;
49 return top - base + 4;
51 @@ -121,7 +130,10 @@ static bool vc4_crtc_get_scanout_positio
52 * Read vertical scanline which is currently composed for our
53 * pixelvalve by the HVS, and also the scaler status.
55 - val = HVS_READ(SCALER_DISPSTATX(channel));
56 + if (vc4->gen >= VC4_GEN_6)
57 + val = HVS_READ(SCALER6_DISPX_STATUS(channel));
59 + val = HVS_READ(SCALER_DISPSTATX(channel));
61 /* Get optional system timestamp after query. */
63 @@ -130,7 +142,12 @@ static bool vc4_crtc_get_scanout_positio
64 /* preempt_enable_rt() should go right here in PREEMPT_RT patchset. */
66 /* Vertical position of hvs composed scanline. */
67 - *vpos = VC4_GET_FIELD(val, SCALER_DISPSTATX_LINE);
69 + if (vc4->gen >= VC4_GEN_6)
70 + *vpos = VC4_GET_FIELD(val, SCALER6_DISPX_STATUS_YLINE);
72 + *vpos = VC4_GET_FIELD(val, SCALER_DISPSTATX_LINE);
76 if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
77 @@ -475,8 +492,10 @@ static void require_hvs_enabled(struct d
78 struct vc4_dev *vc4 = to_vc4_dev(dev);
79 struct vc4_hvs *hvs = vc4->hvs;
81 - WARN_ON_ONCE((HVS_READ(SCALER_DISPCTRL) & SCALER_DISPCTRL_ENABLE) !=
82 - SCALER_DISPCTRL_ENABLE);
83 + if (vc4->gen >= VC4_GEN_6)
84 + WARN_ON_ONCE(!(HVS_READ(SCALER6_CONTROL) & SCALER6_CONTROL_HVS_EN));
86 + WARN_ON_ONCE(!(HVS_READ(SCALER_DISPCTRL) & SCALER_DISPCTRL_ENABLE));
89 static int vc4_crtc_disable(struct drm_crtc *crtc,
90 @@ -804,14 +823,21 @@ static void vc4_crtc_handle_page_flip(st
91 struct drm_device *dev = crtc->dev;
92 struct vc4_dev *vc4 = to_vc4_dev(dev);
93 struct vc4_hvs *hvs = vc4->hvs;
94 + unsigned int current_dlist;
95 u32 chan = vc4_crtc->current_hvs_channel;
98 spin_lock_irqsave(&dev->event_lock, flags);
99 spin_lock(&vc4_crtc->irq_lock);
101 + if (vc4->gen >= VC4_GEN_6)
102 + current_dlist = VC4_GET_FIELD(HVS_READ(SCALER6_DISPX_DL(chan)),
103 + SCALER6_DISPX_DL_LACT);
105 + current_dlist = HVS_READ(SCALER_DISPLACTX(chan));
107 if (vc4_crtc->event &&
108 - (vc4_crtc->current_dlist == HVS_READ(SCALER_DISPLACTX(chan)) ||
109 - vc4_crtc->feeds_txp)) {
110 + (vc4_crtc->current_dlist == current_dlist || vc4_crtc->feeds_txp)) {
111 drm_crtc_send_vblank_event(crtc, vc4_crtc->event);
112 vc4_crtc->event = NULL;
113 drm_crtc_vblank_put(crtc);
114 @@ -822,7 +848,8 @@ static void vc4_crtc_handle_page_flip(st
115 * the CRTC and encoder already reconfigured, leading to
116 * underruns. This can be seen when reconfiguring the CRTC.
118 - vc4_hvs_unmask_underrun(hvs, chan);
119 + if (vc4->gen < VC4_GEN_6)
120 + vc4_hvs_unmask_underrun(hvs, chan);
122 spin_unlock(&vc4_crtc->irq_lock);
123 spin_unlock_irqrestore(&dev->event_lock, flags);
124 --- a/drivers/gpu/drm/vc4/vc4_drv.c
125 +++ b/drivers/gpu/drm/vc4/vc4_drv.c
126 @@ -277,6 +277,7 @@ static const struct of_device_id vc4_dma
127 { .compatible = "brcm,bcm2711-hvs" },
128 { .compatible = "brcm,bcm2835-hvs" },
129 { .compatible = "brcm,bcm2711-hvs" },
130 + { .compatible = "brcm,bcm2712-hvs" },
131 { .compatible = "raspberrypi,rpi-firmware-kms" },
132 { .compatible = "brcm,bcm2835-v3d" },
133 { .compatible = "brcm,cygnus-v3d" },
134 @@ -308,8 +309,6 @@ static int vc4_drm_bind(struct device *d
138 - dev->coherent_dma_mask = DMA_BIT_MASK(32);
140 if (of_device_is_compatible(dev->of_node, "brcm,bcm2712-vc6"))
142 else if (of_device_is_compatible(dev->of_node, "brcm,bcm2711-vc5"))
143 @@ -322,6 +321,11 @@ static int vc4_drm_bind(struct device *d
145 driver = &vc4_drm_driver;
147 + if (gen >= VC4_GEN_6)
148 + dma_set_mask_and_coherent(dev, DMA_BIT_MASK(36));
150 + dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
152 node = of_find_matching_node_and_match(NULL, vc4_dma_range_matches,
155 --- a/drivers/gpu/drm/vc4/vc4_drv.h
156 +++ b/drivers/gpu/drm/vc4/vc4_drv.h
157 @@ -345,8 +345,10 @@ struct vc4_hvs {
158 unsigned int dlist_mem_size;
160 struct clk *core_clk;
161 + struct clk *disp_clk;
165 unsigned int enabled: 1;
166 } eof_irq[HVS_NUM_CHANNELS];
168 @@ -358,6 +360,11 @@ struct vc4_hvs {
169 struct drm_mm dlist_mm;
170 /* Memory manager for the LBM memory used by HVS scaling. */
171 struct drm_mm lbm_mm;
173 + /* Memory manager for the UPM memory used for prefetching. */
174 + struct drm_mm upm_mm;
175 + struct ida upm_handles;
179 struct list_head stale_dlist_entries;
180 @@ -382,6 +389,8 @@ struct vc4_hvs {
181 bool vc5_hdmi_enable_4096by2160;
184 +#define HVS_UBM_WORD_SIZE 256
186 struct vc4_hvs_state {
187 struct drm_private_state base;
188 unsigned long core_clock_rate;
189 @@ -456,6 +465,15 @@ struct vc4_plane_state {
190 /* Our allocation in LBM for temporary storage during scaling. */
191 struct drm_mm_node lbm;
193 + /* Our allocation in UPM for prefetching. */
194 + struct drm_mm_node upm[DRM_FORMAT_MAX_PLANES];
196 + /* The Unified Pre-Fetcher Handle */
197 + unsigned int upm_handle[DRM_FORMAT_MAX_PLANES];
199 + /* Number of lines to pre-fetch */
200 + unsigned int upm_buffer_lines;
202 /* Set when the plane has per-pixel alpha content or does not cover
203 * the entire screen. This is a hint to the CRTC that it might need
204 * to enable background color fill.
205 --- a/drivers/gpu/drm/vc4/vc4_hvs.c
206 +++ b/drivers/gpu/drm/vc4/vc4_hvs.c
207 @@ -67,6 +67,80 @@ static const struct debugfs_reg32 vc4_hv
208 VC4_REG32(SCALER_OLEDCOEF2),
211 +static const struct debugfs_reg32 vc6_hvs_regs[] = {
212 + VC4_REG32(SCALER6_VERSION),
213 + VC4_REG32(SCALER6_CXM_SIZE),
214 + VC4_REG32(SCALER6_LBM_SIZE),
215 + VC4_REG32(SCALER6_UBM_SIZE),
216 + VC4_REG32(SCALER6_COBA_SIZE),
217 + VC4_REG32(SCALER6_COB_SIZE),
218 + VC4_REG32(SCALER6_CONTROL),
219 + VC4_REG32(SCALER6_FETCHER_STATUS),
220 + VC4_REG32(SCALER6_FETCH_STATUS),
221 + VC4_REG32(SCALER6_HANDLE_ERROR),
222 + VC4_REG32(SCALER6_DISP0_CTRL0),
223 + VC4_REG32(SCALER6_DISP0_CTRL1),
224 + VC4_REG32(SCALER6_DISP0_BGND),
225 + VC4_REG32(SCALER6_DISP0_LPTRS),
226 + VC4_REG32(SCALER6_DISP0_COB),
227 + VC4_REG32(SCALER6_DISP0_STATUS),
228 + VC4_REG32(SCALER6_DISP0_DL),
229 + VC4_REG32(SCALER6_DISP0_RUN),
230 + VC4_REG32(SCALER6_DISP1_CTRL0),
231 + VC4_REG32(SCALER6_DISP1_CTRL1),
232 + VC4_REG32(SCALER6_DISP1_BGND),
233 + VC4_REG32(SCALER6_DISP1_LPTRS),
234 + VC4_REG32(SCALER6_DISP1_COB),
235 + VC4_REG32(SCALER6_DISP1_STATUS),
236 + VC4_REG32(SCALER6_DISP1_DL),
237 + VC4_REG32(SCALER6_DISP1_RUN),
238 + VC4_REG32(SCALER6_DISP2_CTRL0),
239 + VC4_REG32(SCALER6_DISP2_CTRL1),
240 + VC4_REG32(SCALER6_DISP2_BGND),
241 + VC4_REG32(SCALER6_DISP2_LPTRS),
242 + VC4_REG32(SCALER6_DISP2_COB),
243 + VC4_REG32(SCALER6_DISP2_STATUS),
244 + VC4_REG32(SCALER6_DISP2_DL),
245 + VC4_REG32(SCALER6_DISP2_RUN),
246 + VC4_REG32(SCALER6_EOLN),
247 + VC4_REG32(SCALER6_DL_STATUS),
248 + VC4_REG32(SCALER6_BFG_MISC),
249 + VC4_REG32(SCALER6_QOS0),
250 + VC4_REG32(SCALER6_PROF0),
251 + VC4_REG32(SCALER6_QOS1),
252 + VC4_REG32(SCALER6_PROF1),
253 + VC4_REG32(SCALER6_QOS2),
254 + VC4_REG32(SCALER6_PROF2),
255 + VC4_REG32(SCALER6_PRI_MAP0),
256 + VC4_REG32(SCALER6_PRI_MAP1),
257 + VC4_REG32(SCALER6_HISTCTRL),
258 + VC4_REG32(SCALER6_HISTBIN0),
259 + VC4_REG32(SCALER6_HISTBIN1),
260 + VC4_REG32(SCALER6_HISTBIN2),
261 + VC4_REG32(SCALER6_HISTBIN3),
262 + VC4_REG32(SCALER6_HISTBIN4),
263 + VC4_REG32(SCALER6_HISTBIN5),
264 + VC4_REG32(SCALER6_HISTBIN6),
265 + VC4_REG32(SCALER6_HISTBIN7),
266 + VC4_REG32(SCALER6_HDR_CFG_REMAP),
267 + VC4_REG32(SCALER6_COL_SPACE),
268 + VC4_REG32(SCALER6_HVS_ID),
269 + VC4_REG32(SCALER6_CFC1),
270 + VC4_REG32(SCALER6_DISP_UPM_ISO0),
271 + VC4_REG32(SCALER6_DISP_UPM_ISO1),
272 + VC4_REG32(SCALER6_DISP_UPM_ISO2),
273 + VC4_REG32(SCALER6_DISP_LBM_ISO0),
274 + VC4_REG32(SCALER6_DISP_LBM_ISO1),
275 + VC4_REG32(SCALER6_DISP_LBM_ISO2),
276 + VC4_REG32(SCALER6_DISP_COB_ISO0),
277 + VC4_REG32(SCALER6_DISP_COB_ISO1),
278 + VC4_REG32(SCALER6_DISP_COB_ISO2),
279 + VC4_REG32(SCALER6_BAD_COB),
280 + VC4_REG32(SCALER6_BAD_LBM),
281 + VC4_REG32(SCALER6_BAD_UPM),
282 + VC4_REG32(SCALER6_BAD_AXI),
285 void vc4_hvs_dump_state(struct vc4_hvs *hvs)
287 struct drm_device *drm = &hvs->vc4->base;
288 @@ -145,6 +219,55 @@ static int vc4_hvs_debugfs_dlist(struct
292 +static int vc6_hvs_debugfs_dlist(struct seq_file *m, void *data)
294 + struct drm_info_node *node = m->private;
295 + struct drm_device *dev = node->minor->dev;
296 + struct vc4_dev *vc4 = to_vc4_dev(dev);
297 + struct vc4_hvs *hvs = vc4->hvs;
298 + struct drm_printer p = drm_seq_file_printer(m);
299 + unsigned int dlist_mem_size = hvs->dlist_mem_size;
300 + unsigned int next_entry_start;
303 + for (i = 0; i < SCALER_CHANNELS_COUNT; i++) {
304 + unsigned int active_dlist, dispstat;
307 + dispstat = VC4_GET_FIELD(HVS_READ(SCALER6_DISPX_STATUS(i)),
308 + SCALER6_DISPX_STATUS_MODE);
309 + if (dispstat == SCALER6_DISPX_STATUS_MODE_DISABLED ||
310 + dispstat == SCALER6_DISPX_STATUS_MODE_EOF) {
311 + drm_printf(&p, "HVS chan %u disabled\n", i);
315 + drm_printf(&p, "HVS chan %u:\n", i);
317 + active_dlist = VC4_GET_FIELD(HVS_READ(SCALER6_DISPX_DL(i)),
318 + SCALER6_DISPX_DL_LACT);
319 + next_entry_start = 0;
321 + for (j = active_dlist; j < dlist_mem_size; j++) {
324 + dlist_word = readl((u32 __iomem *)vc4->hvs->dlist + j);
325 + drm_printf(&p, "dlist: %02d: 0x%08x\n", j,
327 + if (!next_entry_start ||
328 + next_entry_start == j) {
329 + if (dlist_word & SCALER_CTL0_END)
331 + next_entry_start = j +
332 + VC4_GET_FIELD(dlist_word,
341 static int vc5_hvs_debugfs_gamma(struct seq_file *m, void *data)
343 struct drm_info_node *node = m->private;
344 @@ -435,6 +558,10 @@ static void vc4_hvs_irq_enable_eof(struc
345 SCALER5_DISPCTRL_DSPEIEOF(channel));
349 + enable_irq(hvs->eof_irq[channel].desc);
355 @@ -463,6 +590,10 @@ static void vc4_hvs_irq_clear_eof(struct
356 ~SCALER5_DISPCTRL_DSPEIEOF(channel));
360 + disable_irq_nosync(hvs->eof_irq[channel].desc);
366 @@ -622,26 +753,32 @@ static void vc4_hvs_dlist_free_work(stru
368 u8 vc4_hvs_get_fifo_frame_count(struct vc4_hvs *hvs, unsigned int fifo)
370 - struct drm_device *drm = &hvs->vc4->base;
371 + struct vc4_dev *vc4 = hvs->vc4;
372 + struct drm_device *drm = &vc4->base;
376 if (!drm_dev_enter(drm, &idx))
381 - field = VC4_GET_FIELD(HVS_READ(SCALER_DISPSTAT1),
382 - SCALER_DISPSTAT1_FRCNT0);
385 - field = VC4_GET_FIELD(HVS_READ(SCALER_DISPSTAT1),
386 - SCALER_DISPSTAT1_FRCNT1);
389 - field = VC4_GET_FIELD(HVS_READ(SCALER_DISPSTAT2),
390 - SCALER_DISPSTAT2_FRCNT2);
392 + if (vc4->gen >= VC4_GEN_6) {
393 + field = VC4_GET_FIELD(HVS_READ(SCALER6_DISPX_STATUS(fifo)),
394 + SCALER6_DISPX_STATUS_FRCNT);
398 + field = VC4_GET_FIELD(HVS_READ(SCALER_DISPSTAT1),
399 + SCALER_DISPSTAT1_FRCNT0);
402 + field = VC4_GET_FIELD(HVS_READ(SCALER_DISPSTAT1),
403 + SCALER_DISPSTAT1_FRCNT1);
406 + field = VC4_GET_FIELD(HVS_READ(SCALER_DISPSTAT2),
407 + SCALER_DISPSTAT2_FRCNT2);
413 @@ -708,6 +845,23 @@ int vc4_hvs_get_fifo_from_output(struct
437 @@ -782,7 +936,41 @@ static int vc4_hvs_init_channel(struct v
441 -void vc4_hvs_stop_channel(struct vc4_hvs *hvs, unsigned int chan)
442 +static int vc6_hvs_init_channel(struct vc4_hvs *hvs, struct drm_crtc *crtc,
443 + struct drm_display_mode *mode, bool oneshot)
445 + struct vc4_dev *vc4 = hvs->vc4;
446 + struct drm_device *drm = &vc4->base;
447 + struct vc4_crtc_state *vc4_crtc_state = to_vc4_crtc_state(crtc->state);
448 + unsigned int chan = vc4_crtc_state->assigned_channel;
449 + bool interlace = mode->flags & DRM_MODE_FLAG_INTERLACE;
453 + if (!drm_dev_enter(drm, &idx))
456 + HVS_WRITE(SCALER6_DISPX_CTRL0(chan), SCALER6_DISPX_CTRL0_RESET);
458 + disp_ctrl1 = HVS_READ(SCALER6_DISPX_CTRL1(chan));
459 + disp_ctrl1 &= ~SCALER6_DISPX_CTRL1_INTLACE;
460 + HVS_WRITE(SCALER6_DISPX_CTRL1(chan),
461 + disp_ctrl1 | (interlace ? SCALER6_DISPX_CTRL1_INTLACE : 0));
463 + HVS_WRITE(SCALER6_DISPX_CTRL0(chan),
464 + SCALER6_DISPX_CTRL0_ENB |
465 + VC4_SET_FIELD(mode->hdisplay - 1,
466 + SCALER6_DISPX_CTRL0_FWIDTH) |
467 + (oneshot ? SCALER6_DISPX_CTRL0_ONESHOT : 0) |
468 + VC4_SET_FIELD(mode->vdisplay - 1,
469 + SCALER6_DISPX_CTRL0_LINES));
476 +static void __vc4_hvs_stop_channel(struct vc4_hvs *hvs, unsigned int chan)
478 struct drm_device *drm = &hvs->vc4->base;
480 @@ -813,6 +1001,42 @@ out:
484 +static void __vc6_hvs_stop_channel(struct vc4_hvs *hvs, unsigned int chan)
486 + struct vc4_dev *vc4 = hvs->vc4;
487 + struct drm_device *drm = &vc4->base;
490 + if (!drm_dev_enter(drm, &idx))
493 + if (HVS_READ(SCALER6_DISPX_CTRL0(chan)) & SCALER6_DISPX_CTRL0_ENB)
496 + HVS_WRITE(SCALER6_DISPX_CTRL0(chan),
497 + HVS_READ(SCALER6_DISPX_CTRL0(chan)) | SCALER6_DISPX_CTRL0_RESET);
499 + HVS_WRITE(SCALER6_DISPX_CTRL0(chan),
500 + HVS_READ(SCALER6_DISPX_CTRL0(chan)) & ~SCALER6_DISPX_CTRL0_ENB);
502 + WARN_ON_ONCE(VC4_GET_FIELD(HVS_READ(SCALER6_DISPX_STATUS(chan)),
503 + SCALER6_DISPX_STATUS_MODE) !=
504 + SCALER6_DISPX_STATUS_MODE_DISABLED);
510 +void vc4_hvs_stop_channel(struct vc4_hvs *hvs, unsigned int chan)
512 + struct vc4_dev *vc4 = hvs->vc4;
514 + if (vc4->gen >= VC4_GEN_6)
515 + __vc6_hvs_stop_channel(hvs, chan);
517 + __vc4_hvs_stop_channel(hvs, chan);
520 static int vc4_hvs_gamma_check(struct drm_crtc *crtc,
521 struct drm_atomic_state *state)
523 @@ -907,8 +1131,14 @@ static void vc4_hvs_install_dlist(struct
526 WARN_ON(!vc4_state->mm);
527 - HVS_WRITE(SCALER_DISPLISTX(vc4_state->assigned_channel),
528 - vc4_state->mm->mm_node.start);
530 + if (vc4->gen >= VC4_GEN_6)
531 + HVS_WRITE(SCALER6_DISPX_LPTRS(vc4_state->assigned_channel),
532 + VC4_SET_FIELD(vc4_state->mm->mm_node.start,
533 + SCALER6_DISPX_LPTRS_HEADE));
535 + HVS_WRITE(SCALER_DISPLISTX(vc4_state->assigned_channel),
536 + vc4_state->mm->mm_node.start);
540 @@ -965,7 +1195,11 @@ void vc4_hvs_atomic_enable(struct drm_cr
542 vc4_hvs_install_dlist(crtc);
543 vc4_hvs_update_dlist(crtc);
544 - vc4_hvs_init_channel(vc4->hvs, crtc, mode, oneshot);
546 + if (vc4->gen >= VC4_GEN_6)
547 + vc6_hvs_init_channel(vc4->hvs, crtc, mode, oneshot);
549 + vc4_hvs_init_channel(vc4->hvs, crtc, mode, oneshot);
552 void vc4_hvs_atomic_disable(struct drm_crtc *crtc,
553 @@ -1052,13 +1286,28 @@ void vc4_hvs_atomic_flush(struct drm_crt
554 WARN_ON(!vc4_state->mm);
555 WARN_ON_ONCE(dlist_next - dlist_start != vc4_state->mm->mm_node.size);
557 - if (enable_bg_fill)
558 + if (enable_bg_fill) {
559 /* This sets a black background color fill, as is the case
560 * with other DRM drivers.
562 - HVS_WRITE(SCALER_DISPBKGNDX(channel),
563 - HVS_READ(SCALER_DISPBKGNDX(channel)) |
564 - SCALER_DISPBKGND_FILL);
565 + if (vc4->gen >= VC4_GEN_6)
566 + HVS_WRITE(SCALER6_DISPX_CTRL1(channel),
567 + HVS_READ(SCALER6_DISPX_CTRL1(channel)) |
568 + SCALER6_DISPX_CTRL1_BGENB);
570 + HVS_WRITE(SCALER_DISPBKGNDX(channel),
571 + HVS_READ(SCALER_DISPBKGNDX(channel)) |
572 + SCALER_DISPBKGND_FILL);
574 + if (vc4->gen >= VC4_GEN_6)
575 + HVS_WRITE(SCALER6_DISPX_CTRL1(channel),
576 + HVS_READ(SCALER6_DISPX_CTRL1(channel)) &
577 + ~SCALER6_DISPX_CTRL1_BGENB);
579 + HVS_WRITE(SCALER_DISPBKGNDX(channel),
580 + HVS_READ(SCALER_DISPBKGNDX(channel)) &
581 + ~SCALER_DISPBKGND_FILL);
584 /* Only update DISPLIST if the CRTC was already running and is not
586 @@ -1210,6 +1459,27 @@ static irqreturn_t vc4_hvs_irq_handler(i
590 +static irqreturn_t vc6_hvs_eof_irq_handler(int irq, void *data)
592 + struct drm_device *dev = data;
593 + struct vc4_dev *vc4 = to_vc4_dev(dev);
594 + struct vc4_hvs *hvs = vc4->hvs;
597 + for (i = 0; i < HVS_NUM_CHANNELS; i++) {
598 + if (!hvs->eof_irq[i].enabled)
601 + if (hvs->eof_irq[i].desc != irq)
604 + vc4_hvs_schedule_dlist_sweep(hvs, i);
605 + return IRQ_HANDLED;
611 int vc4_hvs_debugfs_init(struct drm_minor *minor)
613 struct drm_device *drm = minor->dev;
614 @@ -1232,8 +1502,10 @@ int vc4_hvs_debugfs_init(struct drm_mino
618 - ret = vc4_debugfs_add_file(minor, "hvs_dlists",
619 - vc4_hvs_debugfs_dlist, NULL);
620 + if (vc4->gen >= VC4_GEN_6)
621 + ret = vc4_debugfs_add_file(minor, "hvs_dlists", vc6_hvs_debugfs_dlist, NULL);
623 + ret = vc4_debugfs_add_file(minor, "hvs_dlists", vc4_hvs_debugfs_dlist, NULL);
627 @@ -1256,6 +1528,9 @@ struct vc4_hvs *__vc4_hvs_alloc(struct v
629 struct drm_device *drm = &vc4->base;
631 + unsigned int dlist_start;
635 hvs = drmm_kzalloc(drm, sizeof(*hvs), GFP_KERNEL);
637 @@ -1270,14 +1545,39 @@ struct vc4_hvs *__vc4_hvs_alloc(struct v
638 INIT_LIST_HEAD(&hvs->stale_dlist_entries);
639 INIT_WORK(&hvs->free_dlist_work, vc4_hvs_dlist_free_work);
641 - /* Set up the HVS display list memory manager. We never
642 - * overwrite the setup from the bootloader (just 128b out of
643 - * our 16K), since we don't want to scramble the screen when
644 - * transitioning from the firmware's boot setup to runtime.
646 - drm_mm_init(&hvs->dlist_mm,
647 - HVS_BOOTLOADER_DLIST_END,
648 - (SCALER_DLIST_SIZE >> 2) - HVS_BOOTLOADER_DLIST_END);
649 + switch (vc4->gen) {
652 + /* Set up the HVS display list memory manager. We never
653 + * overwrite the setup from the bootloader (just 128b
654 + * out of our 16K), since we don't want to scramble the
655 + * screen when transitioning from the firmware's boot
656 + * setup to runtime.
658 + dlist_start = HVS_BOOTLOADER_DLIST_END;
659 + dlist_size = (SCALER_DLIST_SIZE >> 2) - HVS_BOOTLOADER_DLIST_END;
663 + dlist_start = HVS_BOOTLOADER_DLIST_END;
666 + * If we are running a test, it means that we can't
667 + * access a register. Use a plausible size then.
669 + if (!kunit_get_current_test())
670 + dlist_size = HVS_READ(SCALER6_CXM_SIZE);
677 + drm_err(drm, "Unknown VC4 generation: %d", vc4->gen);
678 + return ERR_PTR(-ENODEV);
681 + drm_mm_init(&hvs->dlist_mm, dlist_start, dlist_size);
683 hvs->dlist_mem_size = dlist_size;
685 @@ -1286,12 +1586,46 @@ struct vc4_hvs *__vc4_hvs_alloc(struct v
686 * between planes when they don't overlap on the screen, but
687 * for now we just allocate globally.
689 - if (vc4->gen == VC4_GEN_4)
691 + switch (vc4->gen) {
693 /* 48k words of 2x12-bit pixels */
694 - drm_mm_init(&hvs->lbm_mm, 0, 48 * 1024);
696 + lbm_size = 48 * SZ_1K;
700 /* 60k words of 4x12-bit pixels */
701 - drm_mm_init(&hvs->lbm_mm, 0, 60 * 1024);
702 + lbm_size = 60 * SZ_1K;
707 + * If we are running a test, it means that we can't
708 + * access a register. Use a plausible size then.
714 + drm_err(drm, "Unknown VC4 generation: %d", vc4->gen);
715 + return ERR_PTR(-ENODEV);
718 + drm_mm_init(&hvs->lbm_mm, 0, lbm_size);
720 + if (vc4->gen >= VC4_GEN_6) {
721 + ida_init(&hvs->upm_handles);
724 + * NOTE: On BCM2712, the size can also be read through
725 + * the SCALER_UBM_SIZE register. We would need to do a
726 + * register access though, which we can't do with kunit
727 + * that also uses this function to create its mock
730 + drm_mm_init(&hvs->upm_mm, 0, 1024 * HVS_UBM_WORD_SIZE);
736 @@ -1388,10 +1722,124 @@ static int vc4_hvs_hw_init(struct vc4_hv
740 +#define CFC1_N_NL_CSC_CTRL(x) (0xa000 + ((x) * 0x3000))
741 +#define CFC1_N_MA_CSC_COEFF_C00(x) (0xa008 + ((x) * 0x3000))
742 +#define CFC1_N_MA_CSC_COEFF_C01(x) (0xa00c + ((x) * 0x3000))
743 +#define CFC1_N_MA_CSC_COEFF_C02(x) (0xa010 + ((x) * 0x3000))
744 +#define CFC1_N_MA_CSC_COEFF_C03(x) (0xa014 + ((x) * 0x3000))
745 +#define CFC1_N_MA_CSC_COEFF_C04(x) (0xa018 + ((x) * 0x3000))
746 +#define CFC1_N_MA_CSC_COEFF_C10(x) (0xa01c + ((x) * 0x3000))
747 +#define CFC1_N_MA_CSC_COEFF_C11(x) (0xa020 + ((x) * 0x3000))
748 +#define CFC1_N_MA_CSC_COEFF_C12(x) (0xa024 + ((x) * 0x3000))
749 +#define CFC1_N_MA_CSC_COEFF_C13(x) (0xa028 + ((x) * 0x3000))
750 +#define CFC1_N_MA_CSC_COEFF_C14(x) (0xa02c + ((x) * 0x3000))
751 +#define CFC1_N_MA_CSC_COEFF_C20(x) (0xa030 + ((x) * 0x3000))
752 +#define CFC1_N_MA_CSC_COEFF_C21(x) (0xa034 + ((x) * 0x3000))
753 +#define CFC1_N_MA_CSC_COEFF_C22(x) (0xa038 + ((x) * 0x3000))
754 +#define CFC1_N_MA_CSC_COEFF_C23(x) (0xa03c + ((x) * 0x3000))
755 +#define CFC1_N_MA_CSC_COEFF_C24(x) (0xa040 + ((x) * 0x3000))
757 +/* 4 S2.22 multiplication factors, and 1 S9.15 addititive element for each of 3
758 + * output components
760 +struct vc6_csc_coeff_entry {
764 +static const struct vc6_csc_coeff_entry csc_coeffs[2][3] = {
765 + [DRM_COLOR_YCBCR_LIMITED_RANGE] = {
766 + [DRM_COLOR_YCBCR_BT601] = {
768 + { 0x004A8542, 0x0, 0x0066254A, 0x0, 0xFF908A0D },
769 + { 0x004A8542, 0xFFE6ED5D, 0xFFCBF856, 0x0, 0x0043C9A3 },
770 + { 0x004A8542, 0x00811A54, 0x0, 0x0, 0xFF759502 }
773 + [DRM_COLOR_YCBCR_BT709] = {
775 + { 0x004A8542, 0x0, 0x0072BC44, 0x0, 0xFF83F312 },
776 + { 0x004A8542, 0xFFF25A22, 0xFFDDE4D0, 0x0, 0x00267064 },
777 + { 0x004A8542, 0x00873197, 0x0, 0x0, 0xFF6F7DC0 }
780 + [DRM_COLOR_YCBCR_BT2020] = {
782 + { 0x004A8542, 0x0, 0x006B4A17, 0x0, 0xFF8B653F },
783 + { 0x004A8542, 0xFFF402D9, 0xFFDDE4D0, 0x0, 0x0024C7AE },
784 + { 0x004A8542, 0x008912CC, 0x0, 0x0, 0xFF6D9C8B }
788 + [DRM_COLOR_YCBCR_FULL_RANGE] = {
789 + [DRM_COLOR_YCBCR_BT601] = {
791 + { 0x00400000, 0x0, 0x0059BA5E, 0x0, 0xFFA645A1 },
792 + { 0x00400000, 0xFFE9F9AC, 0xFFD24B97, 0x0, 0x0043BABB },
793 + { 0x00400000, 0x00716872, 0x0, 0x0, 0xFF8E978D }
796 + [DRM_COLOR_YCBCR_BT709] = {
798 + { 0x00400000, 0x0, 0x0064C985, 0x0, 0xFF9B367A },
799 + { 0x00400000, 0xFFF402E1, 0xFFE20A40, 0x0, 0x0029F2DE },
800 + { 0x00400000, 0x0076C226, 0x0, 0x0, 0xFF893DD9 }
803 + [DRM_COLOR_YCBCR_BT2020] = {
805 + { 0x00400000, 0x0, 0x005E3F14, 0x0, 0xFFA1C0EB },
806 + { 0x00400000, 0xFFF577F6, 0xFFDB580F, 0x0, 0x002F2FFA },
807 + { 0x00400000, 0x007868DB, 0x0, 0x0, 0xFF879724 }
813 +static int vc6_hvs_hw_init(struct vc4_hvs *hvs)
815 + const struct vc6_csc_coeff_entry *coeffs;
818 + HVS_WRITE(SCALER6_CONTROL,
819 + SCALER6_CONTROL_HVS_EN |
820 + VC4_SET_FIELD(8, SCALER6_CONTROL_PF_LINES) |
821 + VC4_SET_FIELD(15, SCALER6_CONTROL_MAX_REQS));
823 + /* Set HVS arbiter priority to max */
824 + HVS_WRITE(SCALER6_PRI_MAP0, 0xffffffff);
825 + HVS_WRITE(SCALER6_PRI_MAP1, 0xffffffff);
827 + for (i = 0; i < 6; i++) {
828 + coeffs = &csc_coeffs[i / 3][i % 3];
830 + HVS_WRITE(CFC1_N_MA_CSC_COEFF_C00(i), coeffs->csc[0][0]);
831 + HVS_WRITE(CFC1_N_MA_CSC_COEFF_C01(i), coeffs->csc[0][1]);
832 + HVS_WRITE(CFC1_N_MA_CSC_COEFF_C02(i), coeffs->csc[0][2]);
833 + HVS_WRITE(CFC1_N_MA_CSC_COEFF_C03(i), coeffs->csc[0][3]);
834 + HVS_WRITE(CFC1_N_MA_CSC_COEFF_C04(i), coeffs->csc[0][4]);
836 + HVS_WRITE(CFC1_N_MA_CSC_COEFF_C10(i), coeffs->csc[1][0]);
837 + HVS_WRITE(CFC1_N_MA_CSC_COEFF_C11(i), coeffs->csc[1][1]);
838 + HVS_WRITE(CFC1_N_MA_CSC_COEFF_C12(i), coeffs->csc[1][2]);
839 + HVS_WRITE(CFC1_N_MA_CSC_COEFF_C13(i), coeffs->csc[1][3]);
840 + HVS_WRITE(CFC1_N_MA_CSC_COEFF_C14(i), coeffs->csc[1][4]);
842 + HVS_WRITE(CFC1_N_MA_CSC_COEFF_C20(i), coeffs->csc[2][0]);
843 + HVS_WRITE(CFC1_N_MA_CSC_COEFF_C21(i), coeffs->csc[2][1]);
844 + HVS_WRITE(CFC1_N_MA_CSC_COEFF_C22(i), coeffs->csc[2][2]);
845 + HVS_WRITE(CFC1_N_MA_CSC_COEFF_C23(i), coeffs->csc[2][3]);
846 + HVS_WRITE(CFC1_N_MA_CSC_COEFF_C24(i), coeffs->csc[2][4]);
848 + HVS_WRITE(CFC1_N_NL_CSC_CTRL(i), BIT(15));
854 static int vc4_hvs_cob_init(struct vc4_hvs *hvs)
856 struct vc4_dev *vc4 = hvs->vc4;
858 + u32 reg, top, base;
861 * Recompute Composite Output Buffer (COB) allocations for the
862 @@ -1452,6 +1900,31 @@ static int vc4_hvs_cob_init(struct vc4_h
863 HVS_WRITE(SCALER_DISPBASE0, reg);
867 + #define VC6_COB_LINE_WIDTH 3840
868 + #define VC6_COB_NUM_LINES 4
872 + HVS_WRITE(SCALER6_DISP2_COB,
873 + VC4_SET_FIELD(top, SCALER6_DISPX_COB_TOP) |
874 + VC4_SET_FIELD(base, SCALER6_DISPX_COB_BASE));
877 + top += VC6_COB_LINE_WIDTH * VC6_COB_NUM_LINES;
879 + HVS_WRITE(SCALER6_DISP1_COB,
880 + VC4_SET_FIELD(top, SCALER6_DISPX_COB_TOP) |
881 + VC4_SET_FIELD(base, SCALER6_DISPX_COB_BASE));
884 + top += VC6_COB_LINE_WIDTH * VC6_COB_NUM_LINES;
886 + HVS_WRITE(SCALER6_DISP0_COB,
887 + VC4_SET_FIELD(top, SCALER6_DISPX_COB_TOP) |
888 + VC4_SET_FIELD(base, SCALER6_DISPX_COB_BASE));
894 @@ -1477,10 +1950,16 @@ static int vc4_hvs_bind(struct device *d
897 hvs->regset.base = hvs->regs;
898 - hvs->regset.regs = vc4_hvs_regs;
899 - hvs->regset.nregs = ARRAY_SIZE(vc4_hvs_regs);
901 - if (vc4->gen == VC4_GEN_5) {
902 + if (vc4->gen >= VC4_GEN_6) {
903 + hvs->regset.regs = vc6_hvs_regs;
904 + hvs->regset.nregs = ARRAY_SIZE(vc6_hvs_regs);
906 + hvs->regset.regs = vc4_hvs_regs;
907 + hvs->regset.nregs = ARRAY_SIZE(vc4_hvs_regs);
910 + if (vc4->gen >= VC4_GEN_5) {
911 struct rpi_firmware *firmware;
912 struct device_node *node;
913 unsigned int max_rate;
914 @@ -1494,12 +1973,20 @@ static int vc4_hvs_bind(struct device *d
916 return -EPROBE_DEFER;
918 - hvs->core_clk = devm_clk_get(&pdev->dev, NULL);
919 + hvs->core_clk = devm_clk_get(&pdev->dev,
920 + (vc4->gen >= VC4_GEN_6) ? "core" : NULL);
921 if (IS_ERR(hvs->core_clk)) {
922 dev_err(&pdev->dev, "Couldn't get core clock\n");
923 return PTR_ERR(hvs->core_clk);
926 + hvs->disp_clk = devm_clk_get(&pdev->dev,
927 + (vc4->gen >= VC4_GEN_6) ? "disp" : NULL);
928 + if (IS_ERR(hvs->disp_clk)) {
929 + dev_err(&pdev->dev, "Couldn't get disp clock\n");
930 + return PTR_ERR(hvs->disp_clk);
933 max_rate = rpi_firmware_clk_get_max_rate(firmware,
934 RPI_FIRMWARE_CORE_CLK_ID);
935 rpi_firmware_put(firmware);
936 @@ -1516,14 +2003,51 @@ static int vc4_hvs_bind(struct device *d
937 dev_err(&pdev->dev, "Couldn't enable the core clock\n");
941 + ret = clk_prepare_enable(hvs->disp_clk);
943 + dev_err(&pdev->dev, "Couldn't enable the disp clock\n");
948 - if (vc4->gen == VC4_GEN_4)
949 - hvs->dlist = hvs->regs + SCALER_DLIST_START;
951 + if (vc4->gen >= VC4_GEN_6) {
954 + for (i = 0; i < HVS_NUM_CHANNELS; i++) {
958 + snprintf(irq_name, sizeof(irq_name), "ch%u-eof", i);
960 + irq = platform_get_irq_byname(pdev, irq_name);
962 + dev_err(&pdev->dev,
963 + "Couldn't get %s interrupt: %d\n",
968 + ret = devm_request_irq(&pdev->dev,
970 + vc6_hvs_eof_irq_handler,
972 + dev_name(&pdev->dev),
975 + hvs->eof_irq[i].desc = irq;
979 + if (vc4->gen >= VC4_GEN_5)
980 hvs->dlist = hvs->regs + SCALER5_DLIST_START;
982 + hvs->dlist = hvs->regs + SCALER_DLIST_START;
984 - ret = vc4_hvs_hw_init(hvs);
985 + if (vc4->gen >= VC4_GEN_6)
986 + ret = vc6_hvs_hw_init(hvs);
988 + ret = vc4_hvs_hw_init(hvs);
992 @@ -1540,10 +2064,12 @@ static int vc4_hvs_bind(struct device *d
996 - ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
997 - vc4_hvs_irq_handler, 0, "vc4 hvs", drm);
1000 + if (vc4->gen < VC4_GEN_6) {
1001 + ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
1002 + vc4_hvs_irq_handler, 0, "vc4 hvs", drm);
1009 @@ -1568,6 +2094,7 @@ static void vc4_hvs_unbind(struct device
1010 drm_mm_remove_node(node);
1011 drm_mm_takedown(&vc4->hvs->lbm_mm);
1013 + clk_disable_unprepare(hvs->disp_clk);
1014 clk_disable_unprepare(hvs->core_clk);
1017 @@ -1591,6 +2118,7 @@ static int vc4_hvs_dev_remove(struct pla
1019 static const struct of_device_id vc4_hvs_dt_match[] = {
1020 { .compatible = "brcm,bcm2711-hvs" },
1021 + { .compatible = "brcm,bcm2712-hvs" },
1022 { .compatible = "brcm,bcm2835-hvs" },
1025 --- a/drivers/gpu/drm/vc4/vc4_kms.c
1026 +++ b/drivers/gpu/drm/vc4/vc4_kms.c
1027 @@ -329,17 +329,59 @@ static void vc5_hvs_pv_muxing_commit(str
1031 +static void vc6_hvs_pv_muxing_commit(struct vc4_dev *vc4,
1032 + struct drm_atomic_state *state)
1034 + struct vc4_hvs *hvs = vc4->hvs;
1035 + struct drm_crtc_state *crtc_state;
1036 + struct drm_crtc *crtc;
1039 + WARN_ON_ONCE(vc4->gen != VC4_GEN_6);
1041 + for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
1042 + struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc_state);
1043 + struct vc4_encoder *vc4_encoder;
1044 + struct drm_encoder *encoder;
1045 + unsigned char mux;
1048 + if (!vc4_state->update_muxing)
1051 + if (vc4_state->assigned_channel != 1)
1054 + encoder = vc4_get_crtc_encoder(crtc, crtc_state);
1055 + vc4_encoder = to_vc4_encoder(encoder);
1056 + switch (vc4_encoder->type) {
1057 + case VC4_ENCODER_TYPE_HDMI1:
1061 + case VC4_ENCODER_TYPE_TXP:
1069 + reg = HVS_READ(SCALER6_CONTROL);
1070 + HVS_WRITE(SCALER6_CONTROL,
1071 + (reg & ~SCALER6_CONTROL_DSP1_TARGET_MASK) |
1072 + VC4_SET_FIELD(mux, SCALER6_CONTROL_DSP1_TARGET));
1076 static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
1078 struct drm_device *dev = state->dev;
1079 struct vc4_dev *vc4 = to_vc4_dev(dev);
1080 struct vc4_hvs *hvs = vc4->hvs;
1081 - struct drm_crtc_state *new_crtc_state;
1082 struct vc4_hvs_state *new_hvs_state;
1083 - struct drm_crtc *crtc;
1084 struct vc4_hvs_state *old_hvs_state;
1085 unsigned int channel;
1088 old_hvs_state = vc4_hvs_get_old_global_state(state);
1089 if (WARN_ON(IS_ERR(old_hvs_state)))
1090 @@ -349,14 +391,23 @@ static void vc4_atomic_commit_tail(struc
1091 if (WARN_ON(IS_ERR(new_hvs_state)))
1094 - for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
1095 - struct vc4_crtc_state *vc4_crtc_state;
1096 + if (vc4->gen < VC4_GEN_6) {
1097 + struct drm_crtc_state *new_crtc_state;
1098 + struct drm_crtc *crtc;
1101 + for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
1102 + struct vc4_crtc_state *vc4_crtc_state;
1104 - if (!new_crtc_state->commit || vc4->firmware_kms)
1106 + if (vc4->firmware_kms)
1109 - vc4_crtc_state = to_vc4_crtc_state(new_crtc_state);
1110 - vc4_hvs_mask_underrun(hvs, vc4_crtc_state->assigned_channel);
1111 + if (!new_crtc_state->commit)
1114 + vc4_crtc_state = to_vc4_crtc_state(new_crtc_state);
1115 + vc4_hvs_mask_underrun(hvs, vc4_crtc_state->assigned_channel);
1119 for (channel = 0; channel < HVS_NUM_CHANNELS; channel++) {
1120 @@ -378,7 +429,7 @@ static void vc4_atomic_commit_tail(struc
1121 old_hvs_state->fifo_state[channel].pending_commit = NULL;
1124 - if (vc4->gen == VC4_GEN_5 && !vc4->firmware_kms) {
1125 + if (vc4->gen >= VC4_GEN_5 && !vc4->firmware_kms) {
1126 unsigned long state_rate = max(old_hvs_state->core_clock_rate,
1127 new_hvs_state->core_clock_rate);
1128 unsigned long core_rate = clamp_t(unsigned long, state_rate,
1129 @@ -391,17 +442,32 @@ static void vc4_atomic_commit_tail(struc
1132 WARN_ON(clk_set_min_rate(hvs->core_clk, core_rate));
1133 + WARN_ON(clk_set_min_rate(hvs->disp_clk, core_rate));
1136 drm_atomic_helper_commit_modeset_disables(dev, state);
1138 - vc4_ctm_commit(vc4, state);
1139 + if (vc4->gen <= VC4_GEN_5)
1140 + vc4_ctm_commit(vc4, state);
1142 if (!vc4->firmware_kms) {
1143 - if (vc4->gen == VC4_GEN_5)
1144 - vc5_hvs_pv_muxing_commit(vc4, state);
1146 + switch (vc4->gen) {
1148 vc4_hvs_pv_muxing_commit(vc4, state);
1152 + vc5_hvs_pv_muxing_commit(vc4, state);
1156 + vc6_hvs_pv_muxing_commit(vc4, state);
1160 + drm_err(dev, "Unknown VC4 generation: %d", vc4->gen);
1165 drm_atomic_helper_commit_planes(dev, state,
1166 @@ -417,7 +483,7 @@ static void vc4_atomic_commit_tail(struc
1168 drm_atomic_helper_cleanup_planes(dev, state);
1170 - if (vc4->gen == VC4_GEN_5 && !vc4->firmware_kms) {
1171 + if (vc4->gen >= VC4_GEN_5 && !vc4->firmware_kms) {
1172 unsigned long core_rate = min_t(unsigned long,
1174 new_hvs_state->core_clock_rate);
1175 @@ -429,6 +495,7 @@ static void vc4_atomic_commit_tail(struc
1178 WARN_ON(clk_set_min_rate(hvs->core_clk, core_rate));
1179 + WARN_ON(clk_set_min_rate(hvs->disp_clk, core_rate));
1181 drm_dbg(dev, "Core clock actual rate: %lu Hz\n",
1182 clk_get_rate(hvs->core_clk));
1183 @@ -1081,7 +1148,10 @@ int vc4_kms_load(struct drm_device *dev)
1187 - if (vc4->gen == VC4_GEN_5) {
1188 + if (vc4->gen >= VC4_GEN_6) {
1189 + dev->mode_config.max_width = 8192;
1190 + dev->mode_config.max_height = 8192;
1191 + } else if (vc4->gen >= VC4_GEN_5) {
1192 dev->mode_config.max_width = 7680;
1193 dev->mode_config.max_height = 7680;
1195 --- a/drivers/gpu/drm/vc4/vc4_plane.c
1196 +++ b/drivers/gpu/drm/vc4/vc4_plane.c
1197 @@ -279,6 +279,7 @@ static bool plane_enabled(struct drm_pla
1198 static struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane)
1200 struct vc4_plane_state *vc4_state;
1203 if (WARN_ON(!plane->state))
1205 @@ -288,6 +289,11 @@ static struct drm_plane_state *vc4_plane
1208 memset(&vc4_state->lbm, 0, sizeof(vc4_state->lbm));
1209 + memset(&vc4_state->upm, 0, sizeof(vc4_state->upm));
1211 + for (i = 0; i < DRM_FORMAT_MAX_PLANES; i++)
1212 + vc4_state->upm_handle[i] = 0;
1214 vc4_state->dlist_initialized = 0;
1216 __drm_atomic_helper_plane_duplicate_state(plane, &vc4_state->base);
1217 @@ -310,14 +316,30 @@ static void vc4_plane_destroy_state(stru
1218 struct drm_plane_state *state)
1220 struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
1221 + struct vc4_hvs *hvs = vc4->hvs;
1222 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
1225 if (drm_mm_node_allocated(&vc4_state->lbm)) {
1226 unsigned long irqflags;
1228 - spin_lock_irqsave(&vc4->hvs->mm_lock, irqflags);
1229 + spin_lock_irqsave(&hvs->mm_lock, irqflags);
1230 drm_mm_remove_node(&vc4_state->lbm);
1231 - spin_unlock_irqrestore(&vc4->hvs->mm_lock, irqflags);
1232 + spin_unlock_irqrestore(&hvs->mm_lock, irqflags);
1235 + for (i = 0; i < DRM_FORMAT_MAX_PLANES; i++) {
1236 + unsigned long irqflags;
1238 + if (!drm_mm_node_allocated(&vc4_state->upm[i]))
1241 + spin_lock_irqsave(&hvs->mm_lock, irqflags);
1242 + drm_mm_remove_node(&vc4_state->upm[i]);
1243 + spin_unlock_irqrestore(&hvs->mm_lock, irqflags);
1245 + if (vc4_state->upm_handle[i] > 0)
1246 + ida_free(&hvs->upm_handles, vc4_state->upm_handle[i]);
1249 kfree(vc4_state->dlist);
1250 @@ -543,6 +565,11 @@ static void vc4_write_tpz(struct vc4_pla
1253 vc4_dlist_write(vc4_state,
1255 + * The BCM2712 is lacking BIT(31) compared to
1256 + * the previous generations, but we don't use
1259 VC4_SET_FIELD(scale, SCALER_TPZ0_SCALE) |
1260 VC4_SET_FIELD(0, SCALER_TPZ0_IPHASE));
1261 vc4_dlist_write(vc4_state,
1262 @@ -590,10 +617,15 @@ static void vc4_write_ppf(struct vc4_pla
1263 vc4_dlist_write(vc4_state,
1265 VC4_SET_FIELD(scale, SCALER_PPF_SCALE) |
1267 + * The register layout documentation is slightly
1268 + * different to setup the phase in the BCM2712,
1269 + * but they seem equivalent.
1271 VC4_SET_FIELD(phase, SCALER_PPF_IPHASE));
1274 -static u32 vc4_lbm_size(struct drm_plane_state *state)
1275 +static u32 __vc4_lbm_size(struct drm_plane_state *state)
1277 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
1278 struct vc4_dev *vc4 = to_vc4_dev(state->plane->dev);
1279 @@ -641,6 +673,131 @@ static u32 vc4_lbm_size(struct drm_plane
1283 +static unsigned int vc4_lbm_words_per_component(const struct drm_plane_state *state,
1284 + unsigned int channel)
1286 + struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
1288 + switch (vc4_state->y_scaling[channel]) {
1289 + case VC4_SCALING_PPF:
1292 + case VC4_SCALING_TPZ:
1300 +static unsigned int vc4_lbm_components(const struct drm_plane_state *state,
1301 + unsigned int channel)
1303 + const struct drm_format_info *info = state->fb->format;
1304 + struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
1306 + if (vc4_state->y_scaling[channel] == VC4_SCALING_NONE)
1310 + return channel ? 2 : 1;
1312 + if (info->has_alpha)
1318 +static unsigned int vc4_lbm_channel_size(const struct drm_plane_state *state,
1319 + unsigned int channel)
1321 + const struct drm_format_info *info = state->fb->format;
1322 + struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
1323 + unsigned int channels_scaled = 0;
1324 + unsigned int components, words, wpc;
1325 + unsigned int width, lines;
1328 + /* LBM is meant to use the smaller of source or dest width, but there
1329 + * is a issue with UV scaling that the size required for the second
1330 + * channel is based on the source width only.
1332 + if (info->hsub > 1 && channel == 1)
1333 + width = state->src_w >> 16;
1335 + width = min(state->src_w >> 16, state->crtc_w);
1336 + width = round_up(width / info->hsub, 4);
1338 + wpc = vc4_lbm_words_per_component(state, channel);
1342 + components = vc4_lbm_components(state, channel);
1346 + if (state->alpha != DRM_BLEND_ALPHA_OPAQUE)
1349 + words = width * wpc * components;
1351 + lines = DIV_ROUND_UP(words, 128 / info->hsub);
1353 + for (i = 0; i < 2; i++)
1354 + if (vc4_state->y_scaling[channel] != VC4_SCALING_NONE)
1355 + channels_scaled++;
1357 + if (channels_scaled == 1)
1358 + lines = lines / 2;
1363 +static unsigned int __vc6_lbm_size(const struct drm_plane_state *state)
1365 + const struct drm_format_info *info = state->fb->format;
1367 + if (info->hsub > 1)
1368 + return max(vc4_lbm_channel_size(state, 0),
1369 + vc4_lbm_channel_size(state, 1));
1371 + return vc4_lbm_channel_size(state, 0);
1374 +u32 vc4_lbm_size(struct drm_plane_state *state)
1376 + struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
1377 + struct vc4_dev *vc4 = to_vc4_dev(state->plane->dev);
1379 + /* LBM is not needed when there's no vertical scaling. */
1380 + if (vc4_state->y_scaling[0] == VC4_SCALING_NONE &&
1381 + vc4_state->y_scaling[1] == VC4_SCALING_NONE)
1384 + if (vc4->gen >= VC4_GEN_6)
1385 + return __vc6_lbm_size(state);
1387 + return __vc4_lbm_size(state);
1390 +static size_t vc6_upm_size(const struct drm_plane_state *state,
1391 + unsigned int plane)
1393 + struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
1394 + unsigned int stride = state->fb->pitches[plane];
1397 + * TODO: This only works for raster formats, and is sub-optimal
1398 + * for buffers with a stride aligned on 32 bytes.
1400 + unsigned int words_per_line = (stride + 62) / 32;
1401 + unsigned int fetch_region_size = words_per_line * 32;
1402 + unsigned int buffer_lines = 2 << vc4_state->upm_buffer_lines;
1403 + unsigned int buffer_size = fetch_region_size * buffer_lines;
1405 + return ALIGN(buffer_size, HVS_UBM_WORD_SIZE);
1408 static void vc4_write_scaling_parameters(struct drm_plane_state *state,
1411 @@ -744,6 +901,10 @@ static int vc4_plane_allocate_lbm(struct
1416 + * NOTE: BCM2712 doesn't need to be aligned, since the size
1417 + * returned by vc4_lbm_size() is in words already.
1419 if (vc4->gen == VC4_GEN_5)
1420 lbm_size = ALIGN(lbm_size, 64);
1421 else if (vc4->gen == VC4_GEN_4)
1422 @@ -781,6 +942,57 @@ static int vc4_plane_allocate_lbm(struct
1426 +static int vc6_plane_allocate_upm(struct drm_plane_state *state)
1428 + const struct drm_format_info *info = state->fb->format;
1429 + struct drm_device *drm = state->plane->dev;
1430 + struct vc4_dev *vc4 = to_vc4_dev(drm);
1431 + struct vc4_hvs *hvs = vc4->hvs;
1432 + struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
1436 + WARN_ON_ONCE(vc4->gen < VC4_GEN_6);
1438 + vc4_state->upm_buffer_lines = SCALER6_PTR0_UPM_BUFF_SIZE_2_LINES;
1440 + for (i = 0; i < info->num_planes; i++) {
1441 + unsigned long irqflags;
1444 + upm_size = vc6_upm_size(state, i);
1448 + spin_lock_irqsave(&hvs->mm_lock, irqflags);
1449 + ret = drm_mm_insert_node_generic(&hvs->upm_mm,
1450 + &vc4_state->upm[i],
1451 + upm_size, HVS_UBM_WORD_SIZE,
1453 + spin_unlock_irqrestore(&hvs->mm_lock, irqflags);
1455 + drm_err(drm, "Failed to allocate UPM entry: %d\n", ret);
1459 + ret = ida_alloc_range(&hvs->upm_handles, 1, 32, GFP_KERNEL);
1463 + vc4_state->upm_handle[i] = ret;
1465 + vc4_state->dlist[vc4_state->ptr0_offset[i]] |=
1466 + VC4_SET_FIELD(vc4_state->upm[i].start / HVS_UBM_WORD_SIZE,
1467 + SCALER6_PTR0_UPM_BASE) |
1468 + VC4_SET_FIELD(vc4_state->upm_handle[i] - 1,
1469 + SCALER6_PTR0_UPM_HANDLE) |
1470 + VC4_SET_FIELD(vc4_state->upm_buffer_lines,
1471 + SCALER6_PTR0_UPM_BUFF_SIZE);
1478 * The colorspace conversion matrices are held in 3 entries in the dlist.
1479 * Create an array of them, with entries for each full and limited mode, and
1480 @@ -1355,6 +1567,413 @@ static int vc4_plane_mode_set(struct drm
1484 +static u32 vc6_plane_get_csc_mode(struct vc4_plane_state *vc4_state)
1486 + struct drm_plane_state *state = &vc4_state->base;
1489 + if (vc4_state->is_yuv) {
1490 + enum drm_color_encoding color_encoding = state->color_encoding;
1491 + enum drm_color_range color_range = state->color_range;
1493 + ret |= SCALER6_CTL2_CSC_ENABLE;
1495 + /* CSC pre-loaded with:
1496 + * 0 = BT601 limited range
1497 + * 1 = BT709 limited range
1498 + * 2 = BT2020 limited range
1499 + * 3 = BT601 full range
1500 + * 4 = BT709 full range
1501 + * 5 = BT2020 full range
1503 + if (color_encoding > DRM_COLOR_YCBCR_BT2020)
1504 + color_encoding = DRM_COLOR_YCBCR_BT601;
1505 + if (color_range > DRM_COLOR_YCBCR_FULL_RANGE)
1506 + color_range = DRM_COLOR_YCBCR_LIMITED_RANGE;
1508 + ret |= VC4_SET_FIELD(color_encoding + (color_range * 3),
1509 + SCALER6_CTL2_BRCM_CFC_CONTROL);
1515 +static int vc6_plane_mode_set(struct drm_plane *plane,
1516 + struct drm_plane_state *state)
1518 + struct drm_device *drm = plane->dev;
1519 + struct vc4_dev *vc4 = to_vc4_dev(drm);
1520 + struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
1521 + struct drm_framebuffer *fb = state->fb;
1522 + const struct hvs_format *format = vc4_get_hvs_format(fb->format->format);
1523 + u64 base_format_mod = fourcc_mod_broadcom_mod(fb->modifier);
1524 + int num_planes = fb->format->num_planes;
1525 + u32 h_subsample = fb->format->hsub;
1526 + u32 v_subsample = fb->format->vsub;
1527 + bool mix_plane_alpha;
1528 + bool covers_screen;
1529 + u32 scl0, scl1, pitch0;
1530 + u32 tiling, src_x, src_y;
1531 + u32 width, height;
1532 + u32 hvs_format = format->hvs;
1533 + u32 offsets[3] = { 0 };
1534 + unsigned int rotation;
1537 + if (vc4_state->dlist_initialized)
1540 + ret = vc4_plane_setup_clipping_and_scaling(state);
1544 + width = vc4_state->src_w[0] >> 16;
1545 + height = vc4_state->src_h[0] >> 16;
1547 + /* SCL1 is used for Cb/Cr scaling of planar formats. For RGB
1548 + * and 4:4:4, scl1 should be set to scl0 so both channels of
1549 + * the scaler do the same thing. For YUV, the Y plane needs
1550 + * to be put in channel 1 and Cb/Cr in channel 0, so we swap
1551 + * the scl fields here.
1553 + if (num_planes == 1) {
1554 + scl0 = vc4_get_scl_field(state, 0);
1557 + scl0 = vc4_get_scl_field(state, 1);
1558 + scl1 = vc4_get_scl_field(state, 0);
1561 + rotation = drm_rotation_simplify(state->rotation,
1562 + DRM_MODE_ROTATE_0 |
1563 + DRM_MODE_REFLECT_X |
1564 + DRM_MODE_REFLECT_Y);
1566 + /* We must point to the last line when Y reflection is enabled. */
1567 + src_y = vc4_state->src_y >> 16;
1568 + if (rotation & DRM_MODE_REFLECT_Y)
1569 + src_y += height - 1;
1571 + src_x = vc4_state->src_x >> 16;
1573 + switch (base_format_mod) {
1574 + case DRM_FORMAT_MOD_LINEAR:
1575 + tiling = SCALER6_CTL0_ADDR_MODE_LINEAR;
1577 + /* Adjust the base pointer to the first pixel to be scanned
1580 + for (i = 0; i < num_planes; i++) {
1581 + offsets[i] += src_y / (i ? v_subsample : 1) * fb->pitches[i];
1582 + offsets[i] += src_x / (i ? h_subsample : 1) * fb->format->cpp[i];
1587 + case DRM_FORMAT_MOD_BROADCOM_SAND128:
1588 + case DRM_FORMAT_MOD_BROADCOM_SAND256: {
1589 + uint32_t param = fourcc_mod_broadcom_param(fb->modifier);
1590 + u32 components_per_word;
1591 + u32 starting_offset;
1594 + if (param > SCALER_TILE_HEIGHT_MASK) {
1595 + DRM_DEBUG_KMS("SAND height too large (%d)\n",
1600 + if (fb->format->format == DRM_FORMAT_P030) {
1601 + hvs_format = HVS_PIXEL_FORMAT_YCBCR_10BIT;
1602 + tiling = SCALER6_CTL0_ADDR_MODE_128B;
1604 + hvs_format = HVS_PIXEL_FORMAT_YCBCR_YUV420_2PLANE;
1606 + switch (base_format_mod) {
1607 + case DRM_FORMAT_MOD_BROADCOM_SAND128:
1608 + tiling = SCALER6_CTL0_ADDR_MODE_128B;
1610 + case DRM_FORMAT_MOD_BROADCOM_SAND256:
1611 + tiling = SCALER6_CTL0_ADDR_MODE_256B;
1618 + /* Adjust the base pointer to the first pixel to be scanned
1621 + * For P030, y_ptr [31:4] is the 128bit word for the start pixel
1622 + * y_ptr [3:0] is the pixel (0-11) contained within that 128bit
1623 + * word that should be taken as the first pixel.
1624 + * Ditto uv_ptr [31:4] vs [3:0], however [3:0] contains the
1625 + * element within the 128bit word, eg for pixel 3 the value
1628 + for (i = 0; i < num_planes; i++) {
1629 + u32 tile_w, tile, x_off, pix_per_tile;
1631 + if (fb->format->format == DRM_FORMAT_P030) {
1633 + * Spec says: bits [31:4] of the given address
1634 + * should point to the 128-bit word containing
1635 + * the desired starting pixel, and bits[3:0]
1636 + * should be between 0 and 11, indicating which
1637 + * of the 12-pixels in that 128-bit word is the
1638 + * first pixel to be used
1640 + u32 remaining_pixels = src_x % 96;
1641 + u32 aligned = remaining_pixels / 12;
1642 + u32 last_bits = remaining_pixels % 12;
1644 + x_off = aligned * 16 + last_bits;
1646 + pix_per_tile = 96;
1648 + switch (base_format_mod) {
1649 + case DRM_FORMAT_MOD_BROADCOM_SAND128:
1652 + case DRM_FORMAT_MOD_BROADCOM_SAND256:
1658 + pix_per_tile = tile_w / fb->format->cpp[0];
1659 + x_off = (src_x % pix_per_tile) /
1660 + (i ? h_subsample : 1) *
1661 + fb->format->cpp[i];
1664 + tile = src_x / pix_per_tile;
1666 + offsets[i] += param * tile_w * tile;
1667 + offsets[i] += src_y / (i ? v_subsample : 1) * tile_w;
1668 + offsets[i] += x_off & ~(i ? 1 : 0);
1671 + components_per_word = fb->format->format == DRM_FORMAT_P030 ? 24 : 32;
1672 + starting_offset = src_x % components_per_word;
1673 + fetch_count = (width + starting_offset + components_per_word - 1) /
1674 + components_per_word;
1676 + pitch0 = VC4_SET_FIELD(param, SCALER6_PTR2_PITCH) |
1677 + VC4_SET_FIELD(fetch_count - 1, SCALER6_PTR2_FETCH_COUNT);
1682 + DRM_DEBUG_KMS("Unsupported FB tiling flag 0x%16llx",
1683 + (long long)fb->modifier);
1687 + /* fetch an extra pixel if we don't actually line up with the left edge. */
1688 + if ((vc4_state->src_x & 0xffff) && vc4_state->src_x < (state->fb->width << 16))
1691 + /* same for the right side */
1692 + if (((vc4_state->src_x + vc4_state->src_w[0]) & 0xffff) &&
1693 + vc4_state->src_x + vc4_state->src_w[0] < (state->fb->width << 16))
1696 + /* now for the top */
1697 + if ((vc4_state->src_y & 0xffff) && vc4_state->src_y < (state->fb->height << 16))
1700 + /* and the bottom */
1701 + if (((vc4_state->src_y + vc4_state->src_h[0]) & 0xffff) &&
1702 + vc4_state->src_y + vc4_state->src_h[0] < (state->fb->height << 16))
1705 + /* for YUV444 hardware wants double the width, otherwise it doesn't
1706 + * fetch full width of chroma
1708 + if (format->drm == DRM_FORMAT_YUV444 || format->drm == DRM_FORMAT_YVU444)
1711 + /* Don't waste cycles mixing with plane alpha if the set alpha
1712 + * is opaque or there is no per-pixel alpha information.
1713 + * In any case we use the alpha property value as the fixed alpha.
1715 + mix_plane_alpha = state->alpha != DRM_BLEND_ALPHA_OPAQUE &&
1716 + fb->format->has_alpha;
1718 + /* Control Word 0: Scaling Configuration & Element Validity*/
1719 + vc4_dlist_write(vc4_state,
1720 + SCALER6_CTL0_VALID |
1721 + VC4_SET_FIELD(tiling, SCALER6_CTL0_ADDR_MODE) |
1722 + VC4_SET_FIELD(0, SCALER6_CTL0_ALPHA_MASK) |
1723 + (vc4_state->is_unity ? SCALER6_CTL0_UNITY : 0) |
1724 + VC4_SET_FIELD(format->pixel_order_hvs5, SCALER6_CTL0_ORDERRGBA) |
1725 + VC4_SET_FIELD(scl1, SCALER6_CTL0_SCL1_MODE) |
1726 + VC4_SET_FIELD(scl0, SCALER6_CTL0_SCL0_MODE) |
1727 + VC4_SET_FIELD(hvs_format, SCALER6_CTL0_PIXEL_FORMAT));
1729 + /* Position Word 0: Image Position */
1730 + vc4_state->pos0_offset = vc4_state->dlist_count;
1731 + vc4_dlist_write(vc4_state,
1732 + VC4_SET_FIELD(vc4_state->crtc_y, SCALER6_POS0_START_Y) |
1733 + (rotation & DRM_MODE_REFLECT_X ? SCALER6_POS0_HFLIP : 0) |
1734 + VC4_SET_FIELD(vc4_state->crtc_x, SCALER6_POS0_START_X));
1736 + /* Control Word 2: Alpha Value & CSC */
1737 + vc4_dlist_write(vc4_state,
1738 + vc6_plane_get_csc_mode(vc4_state) |
1739 + vc4_hvs5_get_alpha_blend_mode(state) |
1740 + (mix_plane_alpha ? SCALER6_CTL2_ALPHA_MIX : 0) |
1741 + VC4_SET_FIELD(state->alpha >> 4, SCALER5_CTL2_ALPHA));
1743 + /* Position Word 1: Scaled Image Dimensions */
1744 + if (!vc4_state->is_unity)
1745 + vc4_dlist_write(vc4_state,
1746 + VC4_SET_FIELD(vc4_state->crtc_h - 1,
1747 + SCALER6_POS1_SCL_LINES) |
1748 + VC4_SET_FIELD(vc4_state->crtc_w - 1,
1749 + SCALER6_POS1_SCL_WIDTH));
1751 + /* Position Word 2: Source Image Size */
1752 + vc4_state->pos2_offset = vc4_state->dlist_count;
1753 + vc4_dlist_write(vc4_state,
1754 + VC4_SET_FIELD(height - 1,
1755 + SCALER6_POS2_SRC_LINES) |
1756 + VC4_SET_FIELD(width - 1,
1757 + SCALER6_POS2_SRC_WIDTH));
1759 + /* Position Word 3: Context */
1760 + vc4_dlist_write(vc4_state, 0xc0c0c0c0);
1763 + * TODO: This only covers Raster Scan Order planes
1765 + for (i = 0; i < num_planes; i++) {
1766 + dma_addr_t paddr = drm_fb_dma_get_gem_addr(fb, state, i);
1768 + paddr += offsets[i];
1770 + /* Pointer Word 0 */
1771 + vc4_state->ptr0_offset[i] = vc4_state->dlist_count;
1772 + vc4_dlist_write(vc4_state,
1773 + (rotation & DRM_MODE_REFLECT_Y ? SCALER6_PTR0_VFLIP : 0) |
1775 + * The UPM buffer will be allocated in
1776 + * vc6_plane_allocate_upm().
1778 + VC4_SET_FIELD(upper_32_bits(paddr) & 0xf,
1779 + SCALER6_PTR0_UPPER_ADDR));
1781 + /* Pointer Word 1 */
1782 + vc4_dlist_write(vc4_state, lower_32_bits(paddr));
1784 + /* Pointer Word 2 */
1785 + if (base_format_mod != DRM_FORMAT_MOD_BROADCOM_SAND128 &&
1786 + base_format_mod != DRM_FORMAT_MOD_BROADCOM_SAND256) {
1787 + vc4_dlist_write(vc4_state,
1788 + VC4_SET_FIELD(fb->pitches[i],
1789 + SCALER6_PTR2_PITCH));
1791 + vc4_dlist_write(vc4_state, pitch0);
1797 + * TODO: We're not using the palette mode
1802 + * TODO: It's only relevant if we set the trans_rgb bit in the
1803 + * control word 0, and we don't at the moment.
1806 + vc4_state->lbm_offset = 0;
1808 + if (!vc4_state->is_unity || fb->format->is_yuv) {
1810 + * Reserve a slot for the LBM Base Address. The real value will
1811 + * be set when calling vc4_plane_allocate_lbm().
1813 + if (vc4_state->y_scaling[0] != VC4_SCALING_NONE ||
1814 + vc4_state->y_scaling[1] != VC4_SCALING_NONE) {
1815 + vc4_state->lbm_offset = vc4_state->dlist_count;
1816 + vc4_dlist_counter_increment(vc4_state);
1819 + if (vc4_state->x_scaling[0] != VC4_SCALING_NONE ||
1820 + vc4_state->x_scaling[1] != VC4_SCALING_NONE ||
1821 + vc4_state->y_scaling[0] != VC4_SCALING_NONE ||
1822 + vc4_state->y_scaling[1] != VC4_SCALING_NONE) {
1823 + if (num_planes > 1)
1825 + * Emit Cb/Cr as channel 0 and Y as channel
1826 + * 1. This matches how we set up scl0/scl1
1829 + vc4_write_scaling_parameters(state, 1);
1831 + vc4_write_scaling_parameters(state, 0);
1835 + * If any PPF setup was done, then all the kernel
1836 + * pointers get uploaded.
1838 + if (vc4_state->x_scaling[0] == VC4_SCALING_PPF ||
1839 + vc4_state->y_scaling[0] == VC4_SCALING_PPF ||
1840 + vc4_state->x_scaling[1] == VC4_SCALING_PPF ||
1841 + vc4_state->y_scaling[1] == VC4_SCALING_PPF) {
1843 + VC4_SET_FIELD(vc4->hvs->mitchell_netravali_filter.start,
1844 + SCALER_PPF_KERNEL_OFFSET);
1846 + /* HPPF plane 0 */
1847 + vc4_dlist_write(vc4_state, kernel);
1848 + /* VPPF plane 0 */
1849 + vc4_dlist_write(vc4_state, kernel);
1850 + /* HPPF plane 1 */
1851 + vc4_dlist_write(vc4_state, kernel);
1852 + /* VPPF plane 1 */
1853 + vc4_dlist_write(vc4_state, kernel);
1857 + vc4_dlist_write(vc4_state, SCALER6_CTL0_END);
1859 + vc4_state->dlist[0] |=
1860 + VC4_SET_FIELD(vc4_state->dlist_count, SCALER6_CTL0_NEXT);
1862 + /* crtc_* are already clipped coordinates. */
1863 + covers_screen = vc4_state->crtc_x == 0 && vc4_state->crtc_y == 0 &&
1864 + vc4_state->crtc_w == state->crtc->mode.hdisplay &&
1865 + vc4_state->crtc_h == state->crtc->mode.vdisplay;
1868 + * Background fill might be necessary when the plane has per-pixel
1869 + * alpha content or a non-opaque plane alpha and could blend from the
1870 + * background or does not cover the entire screen.
1872 + vc4_state->needs_bg_fill = fb->format->has_alpha || !covers_screen ||
1873 + state->alpha != DRM_BLEND_ALPHA_OPAQUE;
1876 + * Flag the dlist as initialized to avoid checking it twice in case
1877 + * the async update check already called vc4_plane_mode_set() and
1878 + * decided to fallback to sync update because async update was not
1881 + vc4_state->dlist_initialized = 1;
1883 + vc4_plane_calc_load(state);
1885 + drm_dbg_driver(drm, "[PLANE:%d:%s] Computed DLIST size: %u\n",
1886 + plane->base.id, plane->name, vc4_state->dlist_count);
1891 /* If a modeset involves changing the setup of a plane, the atomic
1892 * infrastructure will call this to validate a proposed plane setup.
1893 * However, if a plane isn't getting updated, this (and the
1894 @@ -1365,6 +1984,7 @@ static int vc4_plane_mode_set(struct drm
1895 static int vc4_plane_atomic_check(struct drm_plane *plane,
1896 struct drm_atomic_state *state)
1898 + struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
1899 struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
1901 struct vc4_plane_state *vc4_state = to_vc4_plane_state(new_plane_state);
1902 @@ -1375,7 +1995,10 @@ static int vc4_plane_atomic_check(struct
1903 if (!plane_enabled(new_plane_state))
1906 - ret = vc4_plane_mode_set(plane, new_plane_state);
1907 + if (vc4->gen >= VC4_GEN_6)
1908 + ret = vc6_plane_mode_set(plane, new_plane_state);
1910 + ret = vc4_plane_mode_set(plane, new_plane_state);
1914 @@ -1383,6 +2006,12 @@ static int vc4_plane_atomic_check(struct
1918 + if (vc4->gen >= VC4_GEN_6) {
1919 + ret = vc6_plane_allocate_upm(new_plane_state);
1927 @@ -1716,7 +2345,7 @@ struct drm_plane *vc4_plane_init(struct
1930 for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) {
1931 - if (!hvs_formats[i].hvs5_only || vc4->gen == VC4_GEN_5) {
1932 + if (!hvs_formats[i].hvs5_only || vc4->gen >= VC4_GEN_5) {
1933 formats[num_formats] = hvs_formats[i].drm;
1936 @@ -1731,7 +2360,7 @@ struct drm_plane *vc4_plane_init(struct
1937 return ERR_CAST(vc4_plane);
1938 plane = &vc4_plane->base;
1940 - if (vc4->gen == VC4_GEN_5)
1941 + if (vc4->gen >= VC4_GEN_5)
1942 drm_plane_helper_add(plane, &vc5_plane_helper_funcs);
1944 drm_plane_helper_add(plane, &vc4_plane_helper_funcs);
1945 --- a/drivers/gpu/drm/vc4/vc4_regs.h
1946 +++ b/drivers/gpu/drm/vc4/vc4_regs.h
1947 @@ -536,6 +536,130 @@
1949 #define SCALER5_DLIST_START 0x00004000
1951 +#define SCALER6_VERSION 0x00000000
1952 +#define SCALER6_CXM_SIZE 0x00000004
1953 +#define SCALER6_LBM_SIZE 0x00000008
1954 +#define SCALER6_UBM_SIZE 0x0000000c
1955 +#define SCALER6_COBA_SIZE 0x00000010
1956 +#define SCALER6_COB_SIZE 0x00000014
1958 +#define SCALER6_CONTROL 0x00000020
1959 +# define SCALER6_CONTROL_HVS_EN BIT(31)
1960 +# define SCALER6_CONTROL_PF_LINES_MASK VC4_MASK(22, 18)
1961 +# define SCALER6_CONTROL_ABORT_ON_EMPTY BIT(16)
1962 +# define SCALER6_CONTROL_DSP1_TARGET_MASK VC4_MASK(13, 12)
1963 +# define SCALER6_CONTROL_MAX_REQS_MASK VC4_MASK(7, 4)
1965 +#define SCALER6_FETCHER_STATUS 0x00000024
1966 +#define SCALER6_FETCH_STATUS 0x00000028
1967 +#define SCALER6_HANDLE_ERROR 0x0000002c
1969 +#define SCALER6_DISP0_CTRL0 0x00000030
1970 +#define SCALER6_DISPX_CTRL0(x) \
1971 + (SCALER6_DISP0_CTRL0 + ((x) * (SCALER6_DISP1_CTRL0 - SCALER6_DISP0_CTRL0)))
1972 +# define SCALER6_DISPX_CTRL0_ENB BIT(31)
1973 +# define SCALER6_DISPX_CTRL0_RESET BIT(30)
1974 +# define SCALER6_DISPX_CTRL0_FWIDTH_MASK VC4_MASK(28, 16)
1975 +# define SCALER6_DISPX_CTRL0_ONESHOT BIT(15)
1976 +# define SCALER6_DISPX_CTRL0_ONECTX_MASK VC4_MASK(14, 13)
1977 +# define SCALER6_DISPX_CTRL0_LINES_MASK VC4_MASK(12, 0)
1979 +#define SCALER6_DISP0_CTRL1 0x00000034
1980 +#define SCALER6_DISPX_CTRL1(x) \
1981 + (SCALER6_DISP0_CTRL1 + ((x) * (SCALER6_DISP1_CTRL1 - SCALER6_DISP0_CTRL1)))
1982 +# define SCALER6_DISPX_CTRL1_BGENB BIT(8)
1983 +# define SCALER6_DISPX_CTRL1_INTLACE BIT(0)
1985 +#define SCALER6_DISP0_BGND 0x00000038
1986 +#define SCALER6_DISPX_BGND(x) \
1987 + (SCALER6_DISP0_BGND + ((x) * (SCALER6_DISP1_BGND - SCALER6_DISP0_BGND)))
1989 +#define SCALER6_DISP0_LPTRS 0x0000003c
1990 +#define SCALER6_DISPX_LPTRS(x) \
1991 + (SCALER6_DISP0_LPTRS + ((x) * (SCALER6_DISP1_LPTRS - SCALER6_DISP0_LPTRS)))
1992 +# define SCALER6_DISPX_LPTRS_HEADE_MASK VC4_MASK(11, 0)
1994 +#define SCALER6_DISP0_COB 0x00000040
1995 +#define SCALER6_DISPX_COB(x) \
1996 + (SCALER6_DISP0_COB + ((x) * (SCALER6_DISP1_COB - SCALER6_DISP0_COB)))
1997 +# define SCALER6_DISPX_COB_TOP_MASK VC4_MASK(31, 16)
1998 +# define SCALER6_DISPX_COB_BASE_MASK VC4_MASK(15, 0)
2000 +#define SCALER6_DISP0_STATUS 0x00000044
2002 +#define SCALER6_DISPX_STATUS(x) \
2003 + (SCALER6_DISP0_STATUS + ((x) * (SCALER6_DISP1_STATUS - SCALER6_DISP0_STATUS)))
2004 +# define SCALER6_DISPX_STATUS_EMPTY BIT(22)
2005 +# define SCALER6_DISPX_STATUS_FRCNT_MASK VC4_MASK(21, 16)
2006 +# define SCALER6_DISPX_STATUS_OFIELD BIT(15)
2007 +# define SCALER6_DISPX_STATUS_MODE_MASK VC4_MASK(14, 13)
2008 +# define SCALER6_DISPX_STATUS_MODE_DISABLED 0
2009 +# define SCALER6_DISPX_STATUS_MODE_INIT 1
2010 +# define SCALER6_DISPX_STATUS_MODE_RUN 2
2011 +# define SCALER6_DISPX_STATUS_MODE_EOF 3
2012 +# define SCALER6_DISPX_STATUS_YLINE_MASK VC4_MASK(12, 0)
2014 +#define SCALER6_DISP0_DL 0x00000048
2016 +#define SCALER6_DISPX_DL(x) \
2017 + (SCALER6_DISP0_DL + ((x) * (SCALER6_DISP1_DL - SCALER6_DISP0_DL)))
2018 +# define SCALER6_DISPX_DL_LACT_MASK VC4_MASK(11, 0)
2020 +#define SCALER6_DISP0_RUN 0x0000004c
2021 +#define SCALER6_DISP1_CTRL0 0x00000050
2022 +#define SCALER6_DISP1_CTRL1 0x00000054
2023 +#define SCALER6_DISP1_BGND 0x00000058
2024 +#define SCALER6_DISP1_LPTRS 0x0000005c
2025 +#define SCALER6_DISP1_COB 0x00000060
2026 +#define SCALER6_DISP1_STATUS 0x00000064
2027 +#define SCALER6_DISP1_DL 0x00000068
2028 +#define SCALER6_DISP1_RUN 0x0000006c
2029 +#define SCALER6_DISP2_CTRL0 0x00000070
2030 +#define SCALER6_DISP2_CTRL1 0x00000074
2031 +#define SCALER6_DISP2_BGND 0x00000078
2032 +#define SCALER6_DISP2_LPTRS 0x0000007c
2033 +#define SCALER6_DISP2_COB 0x00000080
2034 +#define SCALER6_DISP2_STATUS 0x00000084
2035 +#define SCALER6_DISP2_DL 0x00000088
2036 +#define SCALER6_DISP2_RUN 0x0000008c
2037 +#define SCALER6_EOLN 0x00000090
2038 +#define SCALER6_DL_STATUS 0x00000094
2039 +#define SCALER6_BFG_MISC 0x0000009c
2040 +#define SCALER6_QOS0 0x000000a0
2041 +#define SCALER6_PROF0 0x000000a4
2042 +#define SCALER6_QOS1 0x000000a8
2043 +#define SCALER6_PROF1 0x000000ac
2044 +#define SCALER6_QOS2 0x000000b0
2045 +#define SCALER6_PROF2 0x000000b4
2046 +#define SCALER6_PRI_MAP0 0x000000b8
2047 +#define SCALER6_PRI_MAP1 0x000000bc
2048 +#define SCALER6_HISTCTRL 0x000000c0
2049 +#define SCALER6_HISTBIN0 0x000000c4
2050 +#define SCALER6_HISTBIN1 0x000000c8
2051 +#define SCALER6_HISTBIN2 0x000000cc
2052 +#define SCALER6_HISTBIN3 0x000000d0
2053 +#define SCALER6_HISTBIN4 0x000000d4
2054 +#define SCALER6_HISTBIN5 0x000000d8
2055 +#define SCALER6_HISTBIN6 0x000000dc
2056 +#define SCALER6_HISTBIN7 0x000000e0
2057 +#define SCALER6_HDR_CFG_REMAP 0x000000f4
2058 +#define SCALER6_COL_SPACE 0x000000f8
2059 +#define SCALER6_HVS_ID 0x000000fc
2060 +#define SCALER6_CFC1 0x00000100
2061 +#define SCALER6_DISP_UPM_ISO0 0x00000200
2062 +#define SCALER6_DISP_UPM_ISO1 0x00000204
2063 +#define SCALER6_DISP_UPM_ISO2 0x00000208
2064 +#define SCALER6_DISP_LBM_ISO0 0x0000020c
2065 +#define SCALER6_DISP_LBM_ISO1 0x00000210
2066 +#define SCALER6_DISP_LBM_ISO2 0x00000214
2067 +#define SCALER6_DISP_COB_ISO0 0x00000218
2068 +#define SCALER6_DISP_COB_ISO1 0x0000021c
2069 +#define SCALER6_DISP_COB_ISO2 0x00000220
2070 +#define SCALER6_BAD_COB 0x00000224
2071 +#define SCALER6_BAD_LBM 0x00000228
2072 +#define SCALER6_BAD_UPM 0x0000022c
2073 +#define SCALER6_BAD_AXI 0x00000230
2075 # define VC4_HDMI_SW_RESET_FORMAT_DETECT BIT(1)
2076 # define VC4_HDMI_SW_RESET_HDMI BIT(0)
2078 @@ -1131,4 +1255,61 @@ enum hvs_pixel_format {
2079 #define SCALER_PITCH0_TILE_WIDTH_R_MASK VC4_MASK(6, 0)
2080 #define SCALER_PITCH0_TILE_WIDTH_R_SHIFT 0
2082 +#define SCALER6_CTL0_END BIT(31)
2083 +#define SCALER6_CTL0_VALID BIT(30)
2084 +#define SCALER6_CTL0_NEXT_MASK VC4_MASK(29, 24)
2085 +#define SCALER6_CTL0_RGB_TRANS BIT(23)
2086 +#define SCALER6_CTL0_ADDR_MODE_MASK VC4_MASK(22, 20)
2087 +#define SCALER6_CTL0_ADDR_MODE_LINEAR 0
2088 +#define SCALER6_CTL0_ADDR_MODE_128B 1
2089 +#define SCALER6_CTL0_ADDR_MODE_256B 2
2090 +#define SCALER6_CTL0_ADDR_MODE_MAP8 3
2091 +#define SCALER6_CTL0_ADDR_MODE_UIF 4
2093 +#define SCALER6_CTL0_ALPHA_MASK_MASK VC4_MASK(19, 18)
2094 +#define SCALER6_CTL0_UNITY BIT(15)
2095 +#define SCALER6_CTL0_ORDERRGBA_MASK VC4_MASK(14, 13)
2096 +#define SCALER6_CTL0_SCL1_MODE_MASK VC4_MASK(10, 8)
2097 +#define SCALER6_CTL0_SCL0_MODE_MASK VC4_MASK(7, 5)
2098 +#define SCALER6_CTL0_PIXEL_FORMAT_MASK VC4_MASK(4, 0)
2100 +#define SCALER6_POS0_START_Y_MASK VC4_MASK(28, 16)
2101 +#define SCALER6_POS0_HFLIP BIT(15)
2102 +#define SCALER6_POS0_START_X_MASK VC4_MASK(12, 0)
2104 +#define SCALER6_CTL2_ALPHA_MODE_MASK VC4_MASK(31, 30)
2105 +#define SCALER6_CTL2_ALPHA_PREMULT BIT(29)
2106 +#define SCALER6_CTL2_ALPHA_MIX BIT(28)
2107 +#define SCALER6_CTL2_BFG BIT(26)
2108 +#define SCALER6_CTL2_CSC_ENABLE BIT(25)
2109 +#define SCALER6_CTL2_BRCM_CFC_CONTROL_MASK VC4_MASK(18, 16)
2110 +#define SCALER6_CTL2_ALPHA_MASK VC4_MASK(15, 4)
2112 +#define SCALER6_POS1_SCL_LINES_MASK VC4_MASK(28, 16)
2113 +#define SCALER6_POS1_SCL_WIDTH_MASK VC4_MASK(12, 0)
2115 +#define SCALER6_POS2_SRC_LINES_MASK VC4_MASK(28, 16)
2116 +#define SCALER6_POS2_SRC_WIDTH_MASK VC4_MASK(12, 0)
2118 +#define SCALER6_PTR0_VFLIP BIT(31)
2119 +#define SCALER6_PTR0_UPM_BASE_MASK VC4_MASK(28, 16)
2120 +#define SCALER6_PTR0_UPM_HANDLE_MASK VC4_MASK(14, 10)
2121 +#define SCALER6_PTR0_UPM_BUFF_SIZE_MASK VC4_MASK(9, 8)
2122 +#define SCALER6_PTR0_UPM_BUFF_SIZE_16_LINES 3
2123 +#define SCALER6_PTR0_UPM_BUFF_SIZE_8_LINES 2
2124 +#define SCALER6_PTR0_UPM_BUFF_SIZE_4_LINES 1
2125 +#define SCALER6_PTR0_UPM_BUFF_SIZE_2_LINES 0
2126 +#define SCALER6_PTR0_UPPER_ADDR_MASK VC4_MASK(7, 0)
2128 +#define SCALER6_PTR2_ALPHA_BPP_MASK VC4_MASK(31, 31)
2129 +#define SCALER6_PTR2_ALPHA_BPP_1BPP 1
2130 +#define SCALER6_PTR2_ALPHA_BPP_8BPP 0
2131 +#define SCALER6_PTR2_ALPHA_ORDER_MASK VC4_MASK(30, 30)
2132 +#define SCALER6_PTR2_ALPHA_ORDER_MSB_TO_LSB 1
2133 +#define SCALER6_PTR2_ALPHA_ORDER_LSB_TO_MSB 0
2134 +#define SCALER6_PTR2_ALPHA_OFFS_MASK VC4_MASK(29, 27)
2135 +#define SCALER6_PTR2_LSKIP_MASK VC4_MASK(26, 24)
2136 +#define SCALER6_PTR2_PITCH_MASK VC4_MASK(16, 0)
2137 +#define SCALER6_PTR2_FETCH_COUNT_MASK VC4_MASK(26, 16)
2139 #endif /* VC4_REGS_H */