9659432294a947fd5f361fd533c8785403b96cb7
[openwrt/staging/pepe2k.git] / target / linux / bcm27xx / patches-6.1 / 950-0963-drm-vc4-hvs-Support-BCM2712-HVS.patch
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
5
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.
9
10 Let's introduce the needed functions to support the new HVS.
11
12 Signed-off-by: Maxime Ripard <maxime@cerno.tech>
13 ---
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(-)
22
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)
27 {
28 struct vc4_hvs *hvs = vc4->hvs;
29 - u32 dispbase = HVS_READ(SCALER_DISPBASEX(channel));
30 + u32 dispbase, top, base;
31 +
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).
35 */
36 - u32 top = VC4_GET_FIELD(dispbase, SCALER_DISPBASEX_TOP) & ~3;
37 - u32 base = VC4_GET_FIELD(dispbase, SCALER_DISPBASEX_BASE) & ~3;
38 +
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;
43 + } else {
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;
47 + }
48
49 return top - base + 4;
50 }
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.
54 */
55 - val = HVS_READ(SCALER_DISPSTATX(channel));
56 + if (vc4->gen >= VC4_GEN_6)
57 + val = HVS_READ(SCALER6_DISPX_STATUS(channel));
58 + else
59 + val = HVS_READ(SCALER_DISPSTATX(channel));
60
61 /* Get optional system timestamp after query. */
62 if (etime)
63 @@ -130,7 +142,12 @@ static bool vc4_crtc_get_scanout_positio
64 /* preempt_enable_rt() should go right here in PREEMPT_RT patchset. */
65
66 /* Vertical position of hvs composed scanline. */
67 - *vpos = VC4_GET_FIELD(val, SCALER_DISPSTATX_LINE);
68 +
69 + if (vc4->gen >= VC4_GEN_6)
70 + *vpos = VC4_GET_FIELD(val, SCALER6_DISPX_STATUS_YLINE);
71 + else
72 + *vpos = VC4_GET_FIELD(val, SCALER_DISPSTATX_LINE);
73 +
74 *hpos = 0;
75
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;
80
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));
85 + else
86 + WARN_ON_ONCE(!(HVS_READ(SCALER_DISPCTRL) & SCALER_DISPCTRL_ENABLE));
87 }
88
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;
96 unsigned long flags;
97
98 spin_lock_irqsave(&dev->event_lock, flags);
99 spin_lock(&vc4_crtc->irq_lock);
100 +
101 + if (vc4->gen >= VC4_GEN_6)
102 + current_dlist = VC4_GET_FIELD(HVS_READ(SCALER6_DISPX_DL(chan)),
103 + SCALER6_DISPX_DL_LACT);
104 + else
105 + current_dlist = HVS_READ(SCALER_DISPLACTX(chan));
106 +
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.
117 */
118 - vc4_hvs_unmask_underrun(hvs, chan);
119 + if (vc4->gen < VC4_GEN_6)
120 + vc4_hvs_unmask_underrun(hvs, chan);
121 }
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
135 enum vc4_gen gen;
136 int ret = 0;
137
138 - dev->coherent_dma_mask = DMA_BIT_MASK(32);
139 -
140 if (of_device_is_compatible(dev->of_node, "brcm,bcm2712-vc6"))
141 gen = VC4_GEN_6;
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
144 else
145 driver = &vc4_drm_driver;
146
147 + if (gen >= VC4_GEN_6)
148 + dma_set_mask_and_coherent(dev, DMA_BIT_MASK(36));
149 + else
150 + dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
151 +
152 node = of_find_matching_node_and_match(NULL, vc4_dma_range_matches,
153 NULL);
154 if (node) {
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;
159
160 struct clk *core_clk;
161 + struct clk *disp_clk;
162
163 struct {
164 + unsigned int desc;
165 unsigned int enabled: 1;
166 } eof_irq[HVS_NUM_CHANNELS];
167
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;
172 +
173 + /* Memory manager for the UPM memory used for prefetching. */
174 + struct drm_mm upm_mm;
175 + struct ida upm_handles;
176 +
177 spinlock_t mm_lock;
178
179 struct list_head stale_dlist_entries;
180 @@ -382,6 +389,8 @@ struct vc4_hvs {
181 bool vc5_hdmi_enable_4096by2160;
182 };
183
184 +#define HVS_UBM_WORD_SIZE 256
185 +
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;
192
193 + /* Our allocation in UPM for prefetching. */
194 + struct drm_mm_node upm[DRM_FORMAT_MAX_PLANES];
195 +
196 + /* The Unified Pre-Fetcher Handle */
197 + unsigned int upm_handle[DRM_FORMAT_MAX_PLANES];
198 +
199 + /* Number of lines to pre-fetch */
200 + unsigned int upm_buffer_lines;
201 +
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),
209 };
210
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),
283 +};
284 +
285 void vc4_hvs_dump_state(struct vc4_hvs *hvs)
286 {
287 struct drm_device *drm = &hvs->vc4->base;
288 @@ -145,6 +219,55 @@ static int vc4_hvs_debugfs_dlist(struct
289 return 0;
290 }
291
292 +static int vc6_hvs_debugfs_dlist(struct seq_file *m, void *data)
293 +{
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;
301 + unsigned int i;
302 +
303 + for (i = 0; i < SCALER_CHANNELS_COUNT; i++) {
304 + unsigned int active_dlist, dispstat;
305 + unsigned int j;
306 +
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);
312 + continue;
313 + }
314 +
315 + drm_printf(&p, "HVS chan %u:\n", i);
316 +
317 + active_dlist = VC4_GET_FIELD(HVS_READ(SCALER6_DISPX_DL(i)),
318 + SCALER6_DISPX_DL_LACT);
319 + next_entry_start = 0;
320 +
321 + for (j = active_dlist; j < dlist_mem_size; j++) {
322 + u32 dlist_word;
323 +
324 + dlist_word = readl((u32 __iomem *)vc4->hvs->dlist + j);
325 + drm_printf(&p, "dlist: %02d: 0x%08x\n", j,
326 + dlist_word);
327 + if (!next_entry_start ||
328 + next_entry_start == j) {
329 + if (dlist_word & SCALER_CTL0_END)
330 + break;
331 + next_entry_start = j +
332 + VC4_GET_FIELD(dlist_word,
333 + SCALER_CTL0_SIZE);
334 + }
335 + }
336 + }
337 +
338 + return 0;
339 +}
340 +
341 static int vc5_hvs_debugfs_gamma(struct seq_file *m, void *data)
342 {
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));
346 break;
347
348 + case VC4_GEN_6:
349 + enable_irq(hvs->eof_irq[channel].desc);
350 + break;
351 +
352 default:
353 break;
354 }
355 @@ -463,6 +590,10 @@ static void vc4_hvs_irq_clear_eof(struct
356 ~SCALER5_DISPCTRL_DSPEIEOF(channel));
357 break;
358
359 + case VC4_GEN_6:
360 + disable_irq_nosync(hvs->eof_irq[channel].desc);
361 + break;
362 +
363 default:
364 break;
365 }
366 @@ -622,26 +753,32 @@ static void vc4_hvs_dlist_free_work(stru
367
368 u8 vc4_hvs_get_fifo_frame_count(struct vc4_hvs *hvs, unsigned int fifo)
369 {
370 - struct drm_device *drm = &hvs->vc4->base;
371 + struct vc4_dev *vc4 = hvs->vc4;
372 + struct drm_device *drm = &vc4->base;
373 u8 field = 0;
374 int idx;
375
376 if (!drm_dev_enter(drm, &idx))
377 return 0;
378
379 - switch (fifo) {
380 - case 0:
381 - field = VC4_GET_FIELD(HVS_READ(SCALER_DISPSTAT1),
382 - SCALER_DISPSTAT1_FRCNT0);
383 - break;
384 - case 1:
385 - field = VC4_GET_FIELD(HVS_READ(SCALER_DISPSTAT1),
386 - SCALER_DISPSTAT1_FRCNT1);
387 - break;
388 - case 2:
389 - field = VC4_GET_FIELD(HVS_READ(SCALER_DISPSTAT2),
390 - SCALER_DISPSTAT2_FRCNT2);
391 - break;
392 + if (vc4->gen >= VC4_GEN_6) {
393 + field = VC4_GET_FIELD(HVS_READ(SCALER6_DISPX_STATUS(fifo)),
394 + SCALER6_DISPX_STATUS_FRCNT);
395 + } else {
396 + switch (fifo) {
397 + case 0:
398 + field = VC4_GET_FIELD(HVS_READ(SCALER_DISPSTAT1),
399 + SCALER_DISPSTAT1_FRCNT0);
400 + break;
401 + case 1:
402 + field = VC4_GET_FIELD(HVS_READ(SCALER_DISPSTAT1),
403 + SCALER_DISPSTAT1_FRCNT1);
404 + break;
405 + case 2:
406 + field = VC4_GET_FIELD(HVS_READ(SCALER_DISPSTAT2),
407 + SCALER_DISPSTAT2_FRCNT2);
408 + break;
409 + }
410 }
411
412 drm_dev_exit(idx);
413 @@ -708,6 +845,23 @@ int vc4_hvs_get_fifo_from_output(struct
414 default:
415 return -EPIPE;
416 }
417 +
418 + case VC4_GEN_6:
419 + switch (output) {
420 + case 0:
421 + return 0;
422 +
423 + case 2:
424 + return 2;
425 +
426 + case 1:
427 + case 3:
428 + case 4:
429 + return 1;
430 +
431 + default:
432 + return -EPIPE;
433 + }
434 }
435
436 return -EPIPE;
437 @@ -782,7 +936,41 @@ static int vc4_hvs_init_channel(struct v
438 return 0;
439 }
440
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)
444 +{
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;
450 + u32 disp_ctrl1;
451 + int idx;
452 +
453 + if (!drm_dev_enter(drm, &idx))
454 + return -ENODEV;
455 +
456 + HVS_WRITE(SCALER6_DISPX_CTRL0(chan), SCALER6_DISPX_CTRL0_RESET);
457 +
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));
462 +
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));
470 +
471 + drm_dev_exit(idx);
472 +
473 + return 0;
474 +}
475 +
476 +static void __vc4_hvs_stop_channel(struct vc4_hvs *hvs, unsigned int chan)
477 {
478 struct drm_device *drm = &hvs->vc4->base;
479 int idx;
480 @@ -813,6 +1001,42 @@ out:
481 drm_dev_exit(idx);
482 }
483
484 +static void __vc6_hvs_stop_channel(struct vc4_hvs *hvs, unsigned int chan)
485 +{
486 + struct vc4_dev *vc4 = hvs->vc4;
487 + struct drm_device *drm = &vc4->base;
488 + int idx;
489 +
490 + if (!drm_dev_enter(drm, &idx))
491 + return;
492 +
493 + if (HVS_READ(SCALER6_DISPX_CTRL0(chan)) & SCALER6_DISPX_CTRL0_ENB)
494 + goto out;
495 +
496 + HVS_WRITE(SCALER6_DISPX_CTRL0(chan),
497 + HVS_READ(SCALER6_DISPX_CTRL0(chan)) | SCALER6_DISPX_CTRL0_RESET);
498 +
499 + HVS_WRITE(SCALER6_DISPX_CTRL0(chan),
500 + HVS_READ(SCALER6_DISPX_CTRL0(chan)) & ~SCALER6_DISPX_CTRL0_ENB);
501 +
502 + WARN_ON_ONCE(VC4_GET_FIELD(HVS_READ(SCALER6_DISPX_STATUS(chan)),
503 + SCALER6_DISPX_STATUS_MODE) !=
504 + SCALER6_DISPX_STATUS_MODE_DISABLED);
505 +
506 +out:
507 + drm_dev_exit(idx);
508 +}
509 +
510 +void vc4_hvs_stop_channel(struct vc4_hvs *hvs, unsigned int chan)
511 +{
512 + struct vc4_dev *vc4 = hvs->vc4;
513 +
514 + if (vc4->gen >= VC4_GEN_6)
515 + __vc6_hvs_stop_channel(hvs, chan);
516 + else
517 + __vc4_hvs_stop_channel(hvs, chan);
518 +}
519 +
520 static int vc4_hvs_gamma_check(struct drm_crtc *crtc,
521 struct drm_atomic_state *state)
522 {
523 @@ -907,8 +1131,14 @@ static void vc4_hvs_install_dlist(struct
524 return;
525
526 WARN_ON(!vc4_state->mm);
527 - HVS_WRITE(SCALER_DISPLISTX(vc4_state->assigned_channel),
528 - vc4_state->mm->mm_node.start);
529 +
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));
534 + else
535 + HVS_WRITE(SCALER_DISPLISTX(vc4_state->assigned_channel),
536 + vc4_state->mm->mm_node.start);
537
538 drm_dev_exit(idx);
539 }
540 @@ -965,7 +1195,11 @@ void vc4_hvs_atomic_enable(struct drm_cr
541
542 vc4_hvs_install_dlist(crtc);
543 vc4_hvs_update_dlist(crtc);
544 - vc4_hvs_init_channel(vc4->hvs, crtc, mode, oneshot);
545 +
546 + if (vc4->gen >= VC4_GEN_6)
547 + vc6_hvs_init_channel(vc4->hvs, crtc, mode, oneshot);
548 + else
549 + vc4_hvs_init_channel(vc4->hvs, crtc, mode, oneshot);
550 }
551
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);
556
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.
561 */
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);
569 + else
570 + HVS_WRITE(SCALER_DISPBKGNDX(channel),
571 + HVS_READ(SCALER_DISPBKGNDX(channel)) |
572 + SCALER_DISPBKGND_FILL);
573 + } else {
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);
578 + else
579 + HVS_WRITE(SCALER_DISPBKGNDX(channel),
580 + HVS_READ(SCALER_DISPBKGNDX(channel)) &
581 + ~SCALER_DISPBKGND_FILL);
582 + }
583
584 /* Only update DISPLIST if the CRTC was already running and is not
585 * being disabled.
586 @@ -1210,6 +1459,27 @@ static irqreturn_t vc4_hvs_irq_handler(i
587 return irqret;
588 }
589
590 +static irqreturn_t vc6_hvs_eof_irq_handler(int irq, void *data)
591 +{
592 + struct drm_device *dev = data;
593 + struct vc4_dev *vc4 = to_vc4_dev(dev);
594 + struct vc4_hvs *hvs = vc4->hvs;
595 + unsigned int i;
596 +
597 + for (i = 0; i < HVS_NUM_CHANNELS; i++) {
598 + if (!hvs->eof_irq[i].enabled)
599 + continue;
600 +
601 + if (hvs->eof_irq[i].desc != irq)
602 + continue;
603 +
604 + vc4_hvs_schedule_dlist_sweep(hvs, i);
605 + return IRQ_HANDLED;
606 + }
607 +
608 + return IRQ_NONE;
609 +}
610 +
611 int vc4_hvs_debugfs_init(struct drm_minor *minor)
612 {
613 struct drm_device *drm = minor->dev;
614 @@ -1232,8 +1502,10 @@ int vc4_hvs_debugfs_init(struct drm_mino
615 NULL);
616 }
617
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);
622 + else
623 + ret = vc4_debugfs_add_file(minor, "hvs_dlists", vc4_hvs_debugfs_dlist, NULL);
624 if (ret)
625 return ret;
626
627 @@ -1256,6 +1528,9 @@ struct vc4_hvs *__vc4_hvs_alloc(struct v
628 {
629 struct drm_device *drm = &vc4->base;
630 struct vc4_hvs *hvs;
631 + unsigned int dlist_start;
632 + size_t dlist_size;
633 + size_t lbm_size;
634
635 hvs = drmm_kzalloc(drm, sizeof(*hvs), GFP_KERNEL);
636 if (!hvs)
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);
640
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.
645 - */
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) {
650 + case VC4_GEN_4:
651 + case VC4_GEN_5:
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.
657 + */
658 + dlist_start = HVS_BOOTLOADER_DLIST_END;
659 + dlist_size = (SCALER_DLIST_SIZE >> 2) - HVS_BOOTLOADER_DLIST_END;
660 + break;
661 +
662 + case VC4_GEN_6:
663 + dlist_start = HVS_BOOTLOADER_DLIST_END;
664 +
665 + /*
666 + * If we are running a test, it means that we can't
667 + * access a register. Use a plausible size then.
668 + */
669 + if (!kunit_get_current_test())
670 + dlist_size = HVS_READ(SCALER6_CXM_SIZE);
671 + else
672 + dlist_size = 4096;
673 +
674 + break;
675 +
676 + default:
677 + drm_err(drm, "Unknown VC4 generation: %d", vc4->gen);
678 + return ERR_PTR(-ENODEV);
679 + }
680 +
681 + drm_mm_init(&hvs->dlist_mm, dlist_start, dlist_size);
682
683 hvs->dlist_mem_size = dlist_size;
684
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.
688 */
689 - if (vc4->gen == VC4_GEN_4)
690 +
691 + switch (vc4->gen) {
692 + case VC4_GEN_4:
693 /* 48k words of 2x12-bit pixels */
694 - drm_mm_init(&hvs->lbm_mm, 0, 48 * 1024);
695 - else
696 + lbm_size = 48 * SZ_1K;
697 + break;
698 +
699 + case VC4_GEN_5:
700 /* 60k words of 4x12-bit pixels */
701 - drm_mm_init(&hvs->lbm_mm, 0, 60 * 1024);
702 + lbm_size = 60 * SZ_1K;
703 + break;
704 +
705 + case VC4_GEN_6:
706 + /*
707 + * If we are running a test, it means that we can't
708 + * access a register. Use a plausible size then.
709 + */
710 + lbm_size = 1024;
711 + break;
712 +
713 + default:
714 + drm_err(drm, "Unknown VC4 generation: %d", vc4->gen);
715 + return ERR_PTR(-ENODEV);
716 + }
717 +
718 + drm_mm_init(&hvs->lbm_mm, 0, lbm_size);
719 +
720 + if (vc4->gen >= VC4_GEN_6) {
721 + ida_init(&hvs->upm_handles);
722 +
723 + /*
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
728 + * device.
729 + */
730 + drm_mm_init(&hvs->upm_mm, 0, 1024 * HVS_UBM_WORD_SIZE);
731 + }
732 +
733
734 vc4->hvs = hvs;
735
736 @@ -1388,10 +1722,124 @@ static int vc4_hvs_hw_init(struct vc4_hv
737 return 0;
738 }
739
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))
756 +
757 +/* 4 S2.22 multiplication factors, and 1 S9.15 addititive element for each of 3
758 + * output components
759 + */
760 +struct vc6_csc_coeff_entry {
761 + u32 csc[3][5];
762 +};
763 +
764 +static const struct vc6_csc_coeff_entry csc_coeffs[2][3] = {
765 + [DRM_COLOR_YCBCR_LIMITED_RANGE] = {
766 + [DRM_COLOR_YCBCR_BT601] = {
767 + .csc = {
768 + { 0x004A8542, 0x0, 0x0066254A, 0x0, 0xFF908A0D },
769 + { 0x004A8542, 0xFFE6ED5D, 0xFFCBF856, 0x0, 0x0043C9A3 },
770 + { 0x004A8542, 0x00811A54, 0x0, 0x0, 0xFF759502 }
771 + }
772 + },
773 + [DRM_COLOR_YCBCR_BT709] = {
774 + .csc = {
775 + { 0x004A8542, 0x0, 0x0072BC44, 0x0, 0xFF83F312 },
776 + { 0x004A8542, 0xFFF25A22, 0xFFDDE4D0, 0x0, 0x00267064 },
777 + { 0x004A8542, 0x00873197, 0x0, 0x0, 0xFF6F7DC0 }
778 + }
779 + },
780 + [DRM_COLOR_YCBCR_BT2020] = {
781 + .csc = {
782 + { 0x004A8542, 0x0, 0x006B4A17, 0x0, 0xFF8B653F },
783 + { 0x004A8542, 0xFFF402D9, 0xFFDDE4D0, 0x0, 0x0024C7AE },
784 + { 0x004A8542, 0x008912CC, 0x0, 0x0, 0xFF6D9C8B }
785 + }
786 + }
787 + },
788 + [DRM_COLOR_YCBCR_FULL_RANGE] = {
789 + [DRM_COLOR_YCBCR_BT601] = {
790 + .csc = {
791 + { 0x00400000, 0x0, 0x0059BA5E, 0x0, 0xFFA645A1 },
792 + { 0x00400000, 0xFFE9F9AC, 0xFFD24B97, 0x0, 0x0043BABB },
793 + { 0x00400000, 0x00716872, 0x0, 0x0, 0xFF8E978D }
794 + }
795 + },
796 + [DRM_COLOR_YCBCR_BT709] = {
797 + .csc = {
798 + { 0x00400000, 0x0, 0x0064C985, 0x0, 0xFF9B367A },
799 + { 0x00400000, 0xFFF402E1, 0xFFE20A40, 0x0, 0x0029F2DE },
800 + { 0x00400000, 0x0076C226, 0x0, 0x0, 0xFF893DD9 }
801 + }
802 + },
803 + [DRM_COLOR_YCBCR_BT2020] = {
804 + .csc = {
805 + { 0x00400000, 0x0, 0x005E3F14, 0x0, 0xFFA1C0EB },
806 + { 0x00400000, 0xFFF577F6, 0xFFDB580F, 0x0, 0x002F2FFA },
807 + { 0x00400000, 0x007868DB, 0x0, 0x0, 0xFF879724 }
808 + }
809 + }
810 + }
811 +};
812 +
813 +static int vc6_hvs_hw_init(struct vc4_hvs *hvs)
814 +{
815 + const struct vc6_csc_coeff_entry *coeffs;
816 + unsigned int i;
817 +
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));
822 +
823 + /* Set HVS arbiter priority to max */
824 + HVS_WRITE(SCALER6_PRI_MAP0, 0xffffffff);
825 + HVS_WRITE(SCALER6_PRI_MAP1, 0xffffffff);
826 +
827 + for (i = 0; i < 6; i++) {
828 + coeffs = &csc_coeffs[i / 3][i % 3];
829 +
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]);
835 +
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]);
841 +
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]);
847 +
848 + HVS_WRITE(CFC1_N_NL_CSC_CTRL(i), BIT(15));
849 + }
850 +
851 + return 0;
852 +}
853 +
854 static int vc4_hvs_cob_init(struct vc4_hvs *hvs)
855 {
856 struct vc4_dev *vc4 = hvs->vc4;
857 - u32 reg, top;
858 + u32 reg, top, base;
859
860 /*
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);
864 break;
865
866 + case VC4_GEN_6:
867 + #define VC6_COB_LINE_WIDTH 3840
868 + #define VC6_COB_NUM_LINES 4
869 + reg = 0;
870 + top = 3840;
871 +
872 + HVS_WRITE(SCALER6_DISP2_COB,
873 + VC4_SET_FIELD(top, SCALER6_DISPX_COB_TOP) |
874 + VC4_SET_FIELD(base, SCALER6_DISPX_COB_BASE));
875 +
876 + base = top + 16;
877 + top += VC6_COB_LINE_WIDTH * VC6_COB_NUM_LINES;
878 +
879 + HVS_WRITE(SCALER6_DISP1_COB,
880 + VC4_SET_FIELD(top, SCALER6_DISPX_COB_TOP) |
881 + VC4_SET_FIELD(base, SCALER6_DISPX_COB_BASE));
882 +
883 + base = top + 16;
884 + top += VC6_COB_LINE_WIDTH * VC6_COB_NUM_LINES;
885 +
886 + HVS_WRITE(SCALER6_DISP0_COB,
887 + VC4_SET_FIELD(top, SCALER6_DISPX_COB_TOP) |
888 + VC4_SET_FIELD(base, SCALER6_DISPX_COB_BASE));
889 + break;
890 +
891 default:
892 return -EINVAL;
893 }
894 @@ -1477,10 +1950,16 @@ static int vc4_hvs_bind(struct device *d
895 return PTR_ERR(hvs);
896
897 hvs->regset.base = hvs->regs;
898 - hvs->regset.regs = vc4_hvs_regs;
899 - hvs->regset.nregs = ARRAY_SIZE(vc4_hvs_regs);
900
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);
905 + } else {
906 + hvs->regset.regs = vc4_hvs_regs;
907 + hvs->regset.nregs = ARRAY_SIZE(vc4_hvs_regs);
908 + }
909 +
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
915 if (!firmware)
916 return -EPROBE_DEFER;
917
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);
924 }
925
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);
931 + }
932 +
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");
938 return ret;
939 }
940 +
941 + ret = clk_prepare_enable(hvs->disp_clk);
942 + if (ret) {
943 + dev_err(&pdev->dev, "Couldn't enable the disp clock\n");
944 + return ret;
945 + }
946 }
947
948 - if (vc4->gen == VC4_GEN_4)
949 - hvs->dlist = hvs->regs + SCALER_DLIST_START;
950 - else
951 + if (vc4->gen >= VC4_GEN_6) {
952 + unsigned int i;
953 +
954 + for (i = 0; i < HVS_NUM_CHANNELS; i++) {
955 + char irq_name[16];
956 + int irq;
957 +
958 + snprintf(irq_name, sizeof(irq_name), "ch%u-eof", i);
959 +
960 + irq = platform_get_irq_byname(pdev, irq_name);
961 + if (irq < 0) {
962 + dev_err(&pdev->dev,
963 + "Couldn't get %s interrupt: %d\n",
964 + irq_name, irq);
965 + return irq;
966 + }
967 +
968 + ret = devm_request_irq(&pdev->dev,
969 + irq,
970 + vc6_hvs_eof_irq_handler,
971 + IRQF_NO_AUTOEN,
972 + dev_name(&pdev->dev),
973 + drm);
974 +
975 + hvs->eof_irq[i].desc = irq;
976 + }
977 + }
978 +
979 + if (vc4->gen >= VC4_GEN_5)
980 hvs->dlist = hvs->regs + SCALER5_DLIST_START;
981 + else
982 + hvs->dlist = hvs->regs + SCALER_DLIST_START;
983
984 - ret = vc4_hvs_hw_init(hvs);
985 + if (vc4->gen >= VC4_GEN_6)
986 + ret = vc6_hvs_hw_init(hvs);
987 + else
988 + ret = vc4_hvs_hw_init(hvs);
989 if (ret)
990 return ret;
991
992 @@ -1540,10 +2064,12 @@ static int vc4_hvs_bind(struct device *d
993 if (ret)
994 return ret;
995
996 - ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
997 - vc4_hvs_irq_handler, 0, "vc4 hvs", drm);
998 - if (ret)
999 - return ret;
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);
1003 + if (ret)
1004 + return ret;
1005 + }
1006
1007 return 0;
1008 }
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);
1012
1013 + clk_disable_unprepare(hvs->disp_clk);
1014 clk_disable_unprepare(hvs->core_clk);
1015
1016 vc4->hvs = NULL;
1017 @@ -1591,6 +2118,7 @@ static int vc4_hvs_dev_remove(struct pla
1018
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" },
1023 {}
1024 };
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
1028 }
1029 }
1030
1031 +static void vc6_hvs_pv_muxing_commit(struct vc4_dev *vc4,
1032 + struct drm_atomic_state *state)
1033 +{
1034 + struct vc4_hvs *hvs = vc4->hvs;
1035 + struct drm_crtc_state *crtc_state;
1036 + struct drm_crtc *crtc;
1037 + unsigned int i;
1038 +
1039 + WARN_ON_ONCE(vc4->gen != VC4_GEN_6);
1040 +
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;
1046 + u32 reg;
1047 +
1048 + if (!vc4_state->update_muxing)
1049 + continue;
1050 +
1051 + if (vc4_state->assigned_channel != 1)
1052 + continue;
1053 +
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:
1058 + mux = 0;
1059 + break;
1060 +
1061 + case VC4_ENCODER_TYPE_TXP:
1062 + mux = 2;
1063 + break;
1064 +
1065 + default:
1066 + break;
1067 + }
1068 +
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));
1073 + }
1074 +}
1075 +
1076 static void vc4_atomic_commit_tail(struct drm_atomic_state *state)
1077 {
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;
1086 - int i;
1087
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)))
1092 return;
1093
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;
1099 + int i;
1100 +
1101 + for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
1102 + struct vc4_crtc_state *vc4_crtc_state;
1103
1104 - if (!new_crtc_state->commit || vc4->firmware_kms)
1105 - continue;
1106 + if (vc4->firmware_kms)
1107 + continue;
1108
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)
1112 + continue;
1113 +
1114 + vc4_crtc_state = to_vc4_crtc_state(new_crtc_state);
1115 + vc4_hvs_mask_underrun(hvs, vc4_crtc_state->assigned_channel);
1116 + }
1117 }
1118
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;
1122 }
1123
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
1130 * modeset.
1131 */
1132 WARN_ON(clk_set_min_rate(hvs->core_clk, core_rate));
1133 + WARN_ON(clk_set_min_rate(hvs->disp_clk, core_rate));
1134 }
1135
1136 drm_atomic_helper_commit_modeset_disables(dev, state);
1137
1138 - vc4_ctm_commit(vc4, state);
1139 + if (vc4->gen <= VC4_GEN_5)
1140 + vc4_ctm_commit(vc4, state);
1141
1142 if (!vc4->firmware_kms) {
1143 - if (vc4->gen == VC4_GEN_5)
1144 - vc5_hvs_pv_muxing_commit(vc4, state);
1145 - else
1146 + switch (vc4->gen) {
1147 + case VC4_GEN_4:
1148 vc4_hvs_pv_muxing_commit(vc4, state);
1149 + break;
1150 +
1151 + case VC4_GEN_5:
1152 + vc5_hvs_pv_muxing_commit(vc4, state);
1153 + break;
1154 +
1155 + case VC4_GEN_6:
1156 + vc6_hvs_pv_muxing_commit(vc4, state);
1157 + break;
1158 +
1159 + default:
1160 + drm_err(dev, "Unknown VC4 generation: %d", vc4->gen);
1161 + break;
1162 + }
1163 }
1164
1165 drm_atomic_helper_commit_planes(dev, state,
1166 @@ -417,7 +483,7 @@ static void vc4_atomic_commit_tail(struc
1167
1168 drm_atomic_helper_cleanup_planes(dev, state);
1169
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,
1173 hvs->max_core_rate,
1174 new_hvs_state->core_clock_rate);
1175 @@ -429,6 +495,7 @@ static void vc4_atomic_commit_tail(struc
1176 * requirements.
1177 */
1178 WARN_ON(clk_set_min_rate(hvs->core_clk, core_rate));
1179 + WARN_ON(clk_set_min_rate(hvs->disp_clk, core_rate));
1180
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)
1184 return ret;
1185 }
1186
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;
1194 } else {
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)
1199 {
1200 struct vc4_plane_state *vc4_state;
1201 + unsigned int i;
1202
1203 if (WARN_ON(!plane->state))
1204 return NULL;
1205 @@ -288,6 +289,11 @@ static struct drm_plane_state *vc4_plane
1206 return NULL;
1207
1208 memset(&vc4_state->lbm, 0, sizeof(vc4_state->lbm));
1209 + memset(&vc4_state->upm, 0, sizeof(vc4_state->upm));
1210 +
1211 + for (i = 0; i < DRM_FORMAT_MAX_PLANES; i++)
1212 + vc4_state->upm_handle[i] = 0;
1213 +
1214 vc4_state->dlist_initialized = 0;
1215
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)
1219 {
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);
1223 + unsigned int i;
1224
1225 if (drm_mm_node_allocated(&vc4_state->lbm)) {
1226 unsigned long irqflags;
1227
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);
1233 + }
1234 +
1235 + for (i = 0; i < DRM_FORMAT_MAX_PLANES; i++) {
1236 + unsigned long irqflags;
1237 +
1238 + if (!drm_mm_node_allocated(&vc4_state->upm[i]))
1239 + continue;
1240 +
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);
1244 +
1245 + if (vc4_state->upm_handle[i] > 0)
1246 + ida_free(&hvs->upm_handles, vc4_state->upm_handle[i]);
1247 }
1248
1249 kfree(vc4_state->dlist);
1250 @@ -543,6 +565,11 @@ static void vc4_write_tpz(struct vc4_pla
1251 recip = ~0 / scale;
1252
1253 vc4_dlist_write(vc4_state,
1254 + /*
1255 + * The BCM2712 is lacking BIT(31) compared to
1256 + * the previous generations, but we don't use
1257 + * it.
1258 + */
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,
1264 SCALER_PPF_AGC |
1265 VC4_SET_FIELD(scale, SCALER_PPF_SCALE) |
1266 + /*
1267 + * The register layout documentation is slightly
1268 + * different to setup the phase in the BCM2712,
1269 + * but they seem equivalent.
1270 + */
1271 VC4_SET_FIELD(phase, SCALER_PPF_IPHASE));
1272 }
1273
1274 -static u32 vc4_lbm_size(struct drm_plane_state *state)
1275 +static u32 __vc4_lbm_size(struct drm_plane_state *state)
1276 {
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
1280 return lbm;
1281 }
1282
1283 +static unsigned int vc4_lbm_words_per_component(const struct drm_plane_state *state,
1284 + unsigned int channel)
1285 +{
1286 + struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
1287 +
1288 + switch (vc4_state->y_scaling[channel]) {
1289 + case VC4_SCALING_PPF:
1290 + return 4;
1291 +
1292 + case VC4_SCALING_TPZ:
1293 + return 2;
1294 +
1295 + default:
1296 + return 0;
1297 + }
1298 +}
1299 +
1300 +static unsigned int vc4_lbm_components(const struct drm_plane_state *state,
1301 + unsigned int channel)
1302 +{
1303 + const struct drm_format_info *info = state->fb->format;
1304 + struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
1305 +
1306 + if (vc4_state->y_scaling[channel] == VC4_SCALING_NONE)
1307 + return 0;
1308 +
1309 + if (info->is_yuv)
1310 + return channel ? 2 : 1;
1311 +
1312 + if (info->has_alpha)
1313 + return 4;
1314 +
1315 + return 3;
1316 +}
1317 +
1318 +static unsigned int vc4_lbm_channel_size(const struct drm_plane_state *state,
1319 + unsigned int channel)
1320 +{
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;
1326 + unsigned int i;
1327 +
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.
1331 + */
1332 + if (info->hsub > 1 && channel == 1)
1333 + width = state->src_w >> 16;
1334 + else
1335 + width = min(state->src_w >> 16, state->crtc_w);
1336 + width = round_up(width / info->hsub, 4);
1337 +
1338 + wpc = vc4_lbm_words_per_component(state, channel);
1339 + if (!wpc)
1340 + return 0;
1341 +
1342 + components = vc4_lbm_components(state, channel);
1343 + if (!components)
1344 + return 0;
1345 +
1346 + if (state->alpha != DRM_BLEND_ALPHA_OPAQUE)
1347 + components -= 1;
1348 +
1349 + words = width * wpc * components;
1350 +
1351 + lines = DIV_ROUND_UP(words, 128 / info->hsub);
1352 +
1353 + for (i = 0; i < 2; i++)
1354 + if (vc4_state->y_scaling[channel] != VC4_SCALING_NONE)
1355 + channels_scaled++;
1356 +
1357 + if (channels_scaled == 1)
1358 + lines = lines / 2;
1359 +
1360 + return lines;
1361 +}
1362 +
1363 +static unsigned int __vc6_lbm_size(const struct drm_plane_state *state)
1364 +{
1365 + const struct drm_format_info *info = state->fb->format;
1366 +
1367 + if (info->hsub > 1)
1368 + return max(vc4_lbm_channel_size(state, 0),
1369 + vc4_lbm_channel_size(state, 1));
1370 + else
1371 + return vc4_lbm_channel_size(state, 0);
1372 +}
1373 +
1374 +u32 vc4_lbm_size(struct drm_plane_state *state)
1375 +{
1376 + struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
1377 + struct vc4_dev *vc4 = to_vc4_dev(state->plane->dev);
1378 +
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)
1382 + return 0;
1383 +
1384 + if (vc4->gen >= VC4_GEN_6)
1385 + return __vc6_lbm_size(state);
1386 + else
1387 + return __vc4_lbm_size(state);
1388 +}
1389 +
1390 +static size_t vc6_upm_size(const struct drm_plane_state *state,
1391 + unsigned int plane)
1392 +{
1393 + struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
1394 + unsigned int stride = state->fb->pitches[plane];
1395 +
1396 + /*
1397 + * TODO: This only works for raster formats, and is sub-optimal
1398 + * for buffers with a stride aligned on 32 bytes.
1399 + */
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;
1404 +
1405 + return ALIGN(buffer_size, HVS_UBM_WORD_SIZE);
1406 +}
1407 +
1408 static void vc4_write_scaling_parameters(struct drm_plane_state *state,
1409 int channel)
1410 {
1411 @@ -744,6 +901,10 @@ static int vc4_plane_allocate_lbm(struct
1412 if (!lbm_size)
1413 return 0;
1414
1415 + /*
1416 + * NOTE: BCM2712 doesn't need to be aligned, since the size
1417 + * returned by vc4_lbm_size() is in words already.
1418 + */
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
1423 return 0;
1424 }
1425
1426 +static int vc6_plane_allocate_upm(struct drm_plane_state *state)
1427 +{
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);
1433 + unsigned int i;
1434 + int ret;
1435 +
1436 + WARN_ON_ONCE(vc4->gen < VC4_GEN_6);
1437 +
1438 + vc4_state->upm_buffer_lines = SCALER6_PTR0_UPM_BUFF_SIZE_2_LINES;
1439 +
1440 + for (i = 0; i < info->num_planes; i++) {
1441 + unsigned long irqflags;
1442 + size_t upm_size;
1443 +
1444 + upm_size = vc6_upm_size(state, i);
1445 + if (!upm_size)
1446 + return -EINVAL;
1447 +
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,
1452 + 0, 0);
1453 + spin_unlock_irqrestore(&hvs->mm_lock, irqflags);
1454 + if (ret) {
1455 + drm_err(drm, "Failed to allocate UPM entry: %d\n", ret);
1456 + return ret;
1457 + }
1458 +
1459 + ret = ida_alloc_range(&hvs->upm_handles, 1, 32, GFP_KERNEL);
1460 + if (ret < 0)
1461 + return ret;
1462 +
1463 + vc4_state->upm_handle[i] = ret;
1464 +
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);
1472 + }
1473 +
1474 + return 0;
1475 +}
1476 +
1477 /*
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
1481 return 0;
1482 }
1483
1484 +static u32 vc6_plane_get_csc_mode(struct vc4_plane_state *vc4_state)
1485 +{
1486 + struct drm_plane_state *state = &vc4_state->base;
1487 + u32 ret = 0;
1488 +
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;
1492 +
1493 + ret |= SCALER6_CTL2_CSC_ENABLE;
1494 +
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
1502 + */
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;
1507 +
1508 + ret |= VC4_SET_FIELD(color_encoding + (color_range * 3),
1509 + SCALER6_CTL2_BRCM_CFC_CONTROL);
1510 + }
1511 +
1512 + return ret;
1513 +}
1514 +
1515 +static int vc6_plane_mode_set(struct drm_plane *plane,
1516 + struct drm_plane_state *state)
1517 +{
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;
1535 + int ret, i;
1536 +
1537 + if (vc4_state->dlist_initialized)
1538 + return 0;
1539 +
1540 + ret = vc4_plane_setup_clipping_and_scaling(state);
1541 + if (ret)
1542 + return ret;
1543 +
1544 + width = vc4_state->src_w[0] >> 16;
1545 + height = vc4_state->src_h[0] >> 16;
1546 +
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.
1552 + */
1553 + if (num_planes == 1) {
1554 + scl0 = vc4_get_scl_field(state, 0);
1555 + scl1 = scl0;
1556 + } else {
1557 + scl0 = vc4_get_scl_field(state, 1);
1558 + scl1 = vc4_get_scl_field(state, 0);
1559 + }
1560 +
1561 + rotation = drm_rotation_simplify(state->rotation,
1562 + DRM_MODE_ROTATE_0 |
1563 + DRM_MODE_REFLECT_X |
1564 + DRM_MODE_REFLECT_Y);
1565 +
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;
1570 +
1571 + src_x = vc4_state->src_x >> 16;
1572 +
1573 + switch (base_format_mod) {
1574 + case DRM_FORMAT_MOD_LINEAR:
1575 + tiling = SCALER6_CTL0_ADDR_MODE_LINEAR;
1576 +
1577 + /* Adjust the base pointer to the first pixel to be scanned
1578 + * out.
1579 + */
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];
1583 + }
1584 +
1585 + break;
1586 +
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;
1592 + u32 fetch_count;
1593 +
1594 + if (param > SCALER_TILE_HEIGHT_MASK) {
1595 + DRM_DEBUG_KMS("SAND height too large (%d)\n",
1596 + param);
1597 + return -EINVAL;
1598 + }
1599 +
1600 + if (fb->format->format == DRM_FORMAT_P030) {
1601 + hvs_format = HVS_PIXEL_FORMAT_YCBCR_10BIT;
1602 + tiling = SCALER6_CTL0_ADDR_MODE_128B;
1603 + } else {
1604 + hvs_format = HVS_PIXEL_FORMAT_YCBCR_YUV420_2PLANE;
1605 +
1606 + switch (base_format_mod) {
1607 + case DRM_FORMAT_MOD_BROADCOM_SAND128:
1608 + tiling = SCALER6_CTL0_ADDR_MODE_128B;
1609 + break;
1610 + case DRM_FORMAT_MOD_BROADCOM_SAND256:
1611 + tiling = SCALER6_CTL0_ADDR_MODE_256B;
1612 + break;
1613 + default:
1614 + return -EINVAL;
1615 + }
1616 + }
1617 +
1618 + /* Adjust the base pointer to the first pixel to be scanned
1619 + * out.
1620 + *
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
1626 + * should be 6.
1627 + */
1628 + for (i = 0; i < num_planes; i++) {
1629 + u32 tile_w, tile, x_off, pix_per_tile;
1630 +
1631 + if (fb->format->format == DRM_FORMAT_P030) {
1632 + /*
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
1639 + */
1640 + u32 remaining_pixels = src_x % 96;
1641 + u32 aligned = remaining_pixels / 12;
1642 + u32 last_bits = remaining_pixels % 12;
1643 +
1644 + x_off = aligned * 16 + last_bits;
1645 + tile_w = 128;
1646 + pix_per_tile = 96;
1647 + } else {
1648 + switch (base_format_mod) {
1649 + case DRM_FORMAT_MOD_BROADCOM_SAND128:
1650 + tile_w = 128;
1651 + break;
1652 + case DRM_FORMAT_MOD_BROADCOM_SAND256:
1653 + tile_w = 256;
1654 + break;
1655 + default:
1656 + return -EINVAL;
1657 + }
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];
1662 + }
1663 +
1664 + tile = src_x / pix_per_tile;
1665 +
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);
1669 + }
1670 +
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;
1675 +
1676 + pitch0 = VC4_SET_FIELD(param, SCALER6_PTR2_PITCH) |
1677 + VC4_SET_FIELD(fetch_count - 1, SCALER6_PTR2_FETCH_COUNT);
1678 + break;
1679 + }
1680 +
1681 + default:
1682 + DRM_DEBUG_KMS("Unsupported FB tiling flag 0x%16llx",
1683 + (long long)fb->modifier);
1684 + return -EINVAL;
1685 + }
1686 +
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))
1689 + width++;
1690 +
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))
1694 + width++;
1695 +
1696 + /* now for the top */
1697 + if ((vc4_state->src_y & 0xffff) && vc4_state->src_y < (state->fb->height << 16))
1698 + height++;
1699 +
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))
1703 + height++;
1704 +
1705 + /* for YUV444 hardware wants double the width, otherwise it doesn't
1706 + * fetch full width of chroma
1707 + */
1708 + if (format->drm == DRM_FORMAT_YUV444 || format->drm == DRM_FORMAT_YVU444)
1709 + width <<= 1;
1710 +
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.
1714 + */
1715 + mix_plane_alpha = state->alpha != DRM_BLEND_ALPHA_OPAQUE &&
1716 + fb->format->has_alpha;
1717 +
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));
1728 +
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));
1735 +
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));
1742 +
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));
1750 +
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));
1758 +
1759 + /* Position Word 3: Context */
1760 + vc4_dlist_write(vc4_state, 0xc0c0c0c0);
1761 +
1762 + /*
1763 + * TODO: This only covers Raster Scan Order planes
1764 + */
1765 + for (i = 0; i < num_planes; i++) {
1766 + dma_addr_t paddr = drm_fb_dma_get_gem_addr(fb, state, i);
1767 +
1768 + paddr += offsets[i];
1769 +
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) |
1774 + /*
1775 + * The UPM buffer will be allocated in
1776 + * vc6_plane_allocate_upm().
1777 + */
1778 + VC4_SET_FIELD(upper_32_bits(paddr) & 0xf,
1779 + SCALER6_PTR0_UPPER_ADDR));
1780 +
1781 + /* Pointer Word 1 */
1782 + vc4_dlist_write(vc4_state, lower_32_bits(paddr));
1783 +
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));
1790 + } else {
1791 + vc4_dlist_write(vc4_state, pitch0);
1792 + }
1793 + }
1794 +
1795 + /*
1796 + * Palette Word 0
1797 + * TODO: We're not using the palette mode
1798 + */
1799 +
1800 + /*
1801 + * Trans Word 0
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.
1804 + */
1805 +
1806 + vc4_state->lbm_offset = 0;
1807 +
1808 + if (!vc4_state->is_unity || fb->format->is_yuv) {
1809 + /*
1810 + * Reserve a slot for the LBM Base Address. The real value will
1811 + * be set when calling vc4_plane_allocate_lbm().
1812 + */
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);
1817 + }
1818 +
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)
1824 + /*
1825 + * Emit Cb/Cr as channel 0 and Y as channel
1826 + * 1. This matches how we set up scl0/scl1
1827 + * above.
1828 + */
1829 + vc4_write_scaling_parameters(state, 1);
1830 +
1831 + vc4_write_scaling_parameters(state, 0);
1832 + }
1833 +
1834 + /*
1835 + * If any PPF setup was done, then all the kernel
1836 + * pointers get uploaded.
1837 + */
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) {
1842 + u32 kernel =
1843 + VC4_SET_FIELD(vc4->hvs->mitchell_netravali_filter.start,
1844 + SCALER_PPF_KERNEL_OFFSET);
1845 +
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);
1854 + }
1855 + }
1856 +
1857 + vc4_dlist_write(vc4_state, SCALER6_CTL0_END);
1858 +
1859 + vc4_state->dlist[0] |=
1860 + VC4_SET_FIELD(vc4_state->dlist_count, SCALER6_CTL0_NEXT);
1861 +
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;
1866 +
1867 + /*
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.
1871 + */
1872 + vc4_state->needs_bg_fill = fb->format->has_alpha || !covers_screen ||
1873 + state->alpha != DRM_BLEND_ALPHA_OPAQUE;
1874 +
1875 + /*
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
1879 + * possible.
1880 + */
1881 + vc4_state->dlist_initialized = 1;
1882 +
1883 + vc4_plane_calc_load(state);
1884 +
1885 + drm_dbg_driver(drm, "[PLANE:%d:%s] Computed DLIST size: %u\n",
1886 + plane->base.id, plane->name, vc4_state->dlist_count);
1887 +
1888 + return 0;
1889 +}
1890 +
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)
1897 {
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,
1900 plane);
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))
1904 return 0;
1905
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);
1909 + else
1910 + ret = vc4_plane_mode_set(plane, new_plane_state);
1911 if (ret)
1912 return ret;
1913
1914 @@ -1383,6 +2006,12 @@ static int vc4_plane_atomic_check(struct
1915 if (ret)
1916 return ret;
1917
1918 + if (vc4->gen >= VC4_GEN_6) {
1919 + ret = vc6_plane_allocate_upm(new_plane_state);
1920 + if (ret)
1921 + return ret;
1922 + }
1923 +
1924 return 0;
1925 }
1926
1927 @@ -1716,7 +2345,7 @@ struct drm_plane *vc4_plane_init(struct
1928 };
1929
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;
1934 num_formats++;
1935 }
1936 @@ -1731,7 +2360,7 @@ struct drm_plane *vc4_plane_init(struct
1937 return ERR_CAST(vc4_plane);
1938 plane = &vc4_plane->base;
1939
1940 - if (vc4->gen == VC4_GEN_5)
1941 + if (vc4->gen >= VC4_GEN_5)
1942 drm_plane_helper_add(plane, &vc5_plane_helper_funcs);
1943 else
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 @@
1948
1949 #define SCALER5_DLIST_START 0x00004000
1950
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
1957 +
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)
1964 +
1965 +#define SCALER6_FETCHER_STATUS 0x00000024
1966 +#define SCALER6_FETCH_STATUS 0x00000028
1967 +#define SCALER6_HANDLE_ERROR 0x0000002c
1968 +
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)
1978 +
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)
1984 +
1985 +#define SCALER6_DISP0_BGND 0x00000038
1986 +#define SCALER6_DISPX_BGND(x) \
1987 + (SCALER6_DISP0_BGND + ((x) * (SCALER6_DISP1_BGND - SCALER6_DISP0_BGND)))
1988 +
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)
1993 +
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)
1999 +
2000 +#define SCALER6_DISP0_STATUS 0x00000044
2001 +
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)
2013 +
2014 +#define SCALER6_DISP0_DL 0x00000048
2015 +
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)
2019 +
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
2074 +
2075 # define VC4_HDMI_SW_RESET_FORMAT_DETECT BIT(1)
2076 # define VC4_HDMI_SW_RESET_HDMI BIT(0)
2077
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
2081
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
2092 +
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)
2099 +
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)
2103 +
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)
2111 +
2112 +#define SCALER6_POS1_SCL_LINES_MASK VC4_MASK(28, 16)
2113 +#define SCALER6_POS1_SCL_WIDTH_MASK VC4_MASK(12, 0)
2114 +
2115 +#define SCALER6_POS2_SRC_LINES_MASK VC4_MASK(28, 16)
2116 +#define SCALER6_POS2_SRC_WIDTH_MASK VC4_MASK(12, 0)
2117 +
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)
2127 +
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)
2138 +
2139 #endif /* VC4_REGS_H */