forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-10-09 244b2c5ca8b14627e4a17755e5922221e121c771
kernel/drivers/gpu/drm/vc4/vc4_hvs.c
....@@ -1,9 +1,6 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * Copyright (C) 2015 Broadcom
3
- *
4
- * This program is free software; you can redistribute it and/or modify
5
- * it under the terms of the GNU General Public License version 2 as
6
- * published by the Free Software Foundation.
74 */
85
96 /**
....@@ -22,58 +19,58 @@
2219 * each CRTC.
2320 */
2421
22
+#include <linux/bitfield.h>
23
+#include <linux/clk.h>
2524 #include <linux/component.h>
25
+#include <linux/platform_device.h>
26
+
27
+#include <drm/drm_atomic_helper.h>
28
+#include <drm/drm_vblank.h>
29
+
2630 #include "vc4_drv.h"
2731 #include "vc4_regs.h"
2832
29
-#define HVS_REG(reg) { reg, #reg }
30
-static const struct {
31
- u32 reg;
32
- const char *name;
33
-} hvs_regs[] = {
34
- HVS_REG(SCALER_DISPCTRL),
35
- HVS_REG(SCALER_DISPSTAT),
36
- HVS_REG(SCALER_DISPID),
37
- HVS_REG(SCALER_DISPECTRL),
38
- HVS_REG(SCALER_DISPPROF),
39
- HVS_REG(SCALER_DISPDITHER),
40
- HVS_REG(SCALER_DISPEOLN),
41
- HVS_REG(SCALER_DISPLIST0),
42
- HVS_REG(SCALER_DISPLIST1),
43
- HVS_REG(SCALER_DISPLIST2),
44
- HVS_REG(SCALER_DISPLSTAT),
45
- HVS_REG(SCALER_DISPLACT0),
46
- HVS_REG(SCALER_DISPLACT1),
47
- HVS_REG(SCALER_DISPLACT2),
48
- HVS_REG(SCALER_DISPCTRL0),
49
- HVS_REG(SCALER_DISPBKGND0),
50
- HVS_REG(SCALER_DISPSTAT0),
51
- HVS_REG(SCALER_DISPBASE0),
52
- HVS_REG(SCALER_DISPCTRL1),
53
- HVS_REG(SCALER_DISPBKGND1),
54
- HVS_REG(SCALER_DISPSTAT1),
55
- HVS_REG(SCALER_DISPBASE1),
56
- HVS_REG(SCALER_DISPCTRL2),
57
- HVS_REG(SCALER_DISPBKGND2),
58
- HVS_REG(SCALER_DISPSTAT2),
59
- HVS_REG(SCALER_DISPBASE2),
60
- HVS_REG(SCALER_DISPALPHA2),
61
- HVS_REG(SCALER_OLEDOFFS),
62
- HVS_REG(SCALER_OLEDCOEF0),
63
- HVS_REG(SCALER_OLEDCOEF1),
64
- HVS_REG(SCALER_OLEDCOEF2),
33
+static const struct debugfs_reg32 hvs_regs[] = {
34
+ VC4_REG32(SCALER_DISPCTRL),
35
+ VC4_REG32(SCALER_DISPSTAT),
36
+ VC4_REG32(SCALER_DISPID),
37
+ VC4_REG32(SCALER_DISPECTRL),
38
+ VC4_REG32(SCALER_DISPPROF),
39
+ VC4_REG32(SCALER_DISPDITHER),
40
+ VC4_REG32(SCALER_DISPEOLN),
41
+ VC4_REG32(SCALER_DISPLIST0),
42
+ VC4_REG32(SCALER_DISPLIST1),
43
+ VC4_REG32(SCALER_DISPLIST2),
44
+ VC4_REG32(SCALER_DISPLSTAT),
45
+ VC4_REG32(SCALER_DISPLACT0),
46
+ VC4_REG32(SCALER_DISPLACT1),
47
+ VC4_REG32(SCALER_DISPLACT2),
48
+ VC4_REG32(SCALER_DISPCTRL0),
49
+ VC4_REG32(SCALER_DISPBKGND0),
50
+ VC4_REG32(SCALER_DISPSTAT0),
51
+ VC4_REG32(SCALER_DISPBASE0),
52
+ VC4_REG32(SCALER_DISPCTRL1),
53
+ VC4_REG32(SCALER_DISPBKGND1),
54
+ VC4_REG32(SCALER_DISPSTAT1),
55
+ VC4_REG32(SCALER_DISPBASE1),
56
+ VC4_REG32(SCALER_DISPCTRL2),
57
+ VC4_REG32(SCALER_DISPBKGND2),
58
+ VC4_REG32(SCALER_DISPSTAT2),
59
+ VC4_REG32(SCALER_DISPBASE2),
60
+ VC4_REG32(SCALER_DISPALPHA2),
61
+ VC4_REG32(SCALER_OLEDOFFS),
62
+ VC4_REG32(SCALER_OLEDCOEF0),
63
+ VC4_REG32(SCALER_OLEDCOEF1),
64
+ VC4_REG32(SCALER_OLEDCOEF2),
6565 };
6666
6767 void vc4_hvs_dump_state(struct drm_device *dev)
6868 {
6969 struct vc4_dev *vc4 = to_vc4_dev(dev);
70
+ struct drm_printer p = drm_info_printer(&vc4->hvs->pdev->dev);
7071 int i;
7172
72
- for (i = 0; i < ARRAY_SIZE(hvs_regs); i++) {
73
- DRM_INFO("0x%04x (%s): 0x%08x\n",
74
- hvs_regs[i].reg, hvs_regs[i].name,
75
- HVS_READ(hvs_regs[i].reg));
76
- }
73
+ drm_print_regset32(&p, &vc4->hvs->regset);
7774
7875 DRM_INFO("HVS ctx:\n");
7976 for (i = 0; i < 64; i += 4) {
....@@ -86,23 +83,17 @@
8683 }
8784 }
8885
89
-#ifdef CONFIG_DEBUG_FS
90
-int vc4_hvs_debugfs_regs(struct seq_file *m, void *unused)
86
+static int vc4_hvs_debugfs_underrun(struct seq_file *m, void *data)
9187 {
92
- struct drm_info_node *node = (struct drm_info_node *)m->private;
88
+ struct drm_info_node *node = m->private;
9389 struct drm_device *dev = node->minor->dev;
9490 struct vc4_dev *vc4 = to_vc4_dev(dev);
95
- int i;
91
+ struct drm_printer p = drm_seq_file_printer(m);
9692
97
- for (i = 0; i < ARRAY_SIZE(hvs_regs); i++) {
98
- seq_printf(m, "%s (0x%04x): 0x%08x\n",
99
- hvs_regs[i].name, hvs_regs[i].reg,
100
- HVS_READ(hvs_regs[i].reg));
101
- }
93
+ drm_printf(&p, "%d\n", atomic_read(&vc4->underrun));
10294
10395 return 0;
10496 }
105
-#endif
10697
10798 /* The filter kernel is composed of dwords each containing 3 9-bit
10899 * signed integers packed next to each other.
....@@ -166,14 +157,414 @@
166157 return 0;
167158 }
168159
160
+static void vc4_hvs_lut_load(struct drm_crtc *crtc)
161
+{
162
+ struct drm_device *dev = crtc->dev;
163
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
164
+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
165
+ struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state);
166
+ u32 i;
167
+
168
+ /* The LUT memory is laid out with each HVS channel in order,
169
+ * each of which takes 256 writes for R, 256 for G, then 256
170
+ * for B.
171
+ */
172
+ HVS_WRITE(SCALER_GAMADDR,
173
+ SCALER_GAMADDR_AUTOINC |
174
+ (vc4_state->assigned_channel * 3 * crtc->gamma_size));
175
+
176
+ for (i = 0; i < crtc->gamma_size; i++)
177
+ HVS_WRITE(SCALER_GAMDATA, vc4_crtc->lut_r[i]);
178
+ for (i = 0; i < crtc->gamma_size; i++)
179
+ HVS_WRITE(SCALER_GAMDATA, vc4_crtc->lut_g[i]);
180
+ for (i = 0; i < crtc->gamma_size; i++)
181
+ HVS_WRITE(SCALER_GAMDATA, vc4_crtc->lut_b[i]);
182
+}
183
+
184
+static void vc4_hvs_update_gamma_lut(struct drm_crtc *crtc)
185
+{
186
+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
187
+ struct drm_color_lut *lut = crtc->state->gamma_lut->data;
188
+ u32 length = drm_color_lut_size(crtc->state->gamma_lut);
189
+ u32 i;
190
+
191
+ for (i = 0; i < length; i++) {
192
+ vc4_crtc->lut_r[i] = drm_color_lut_extract(lut[i].red, 8);
193
+ vc4_crtc->lut_g[i] = drm_color_lut_extract(lut[i].green, 8);
194
+ vc4_crtc->lut_b[i] = drm_color_lut_extract(lut[i].blue, 8);
195
+ }
196
+
197
+ vc4_hvs_lut_load(crtc);
198
+}
199
+
200
+int vc4_hvs_get_fifo_from_output(struct drm_device *dev, unsigned int output)
201
+{
202
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
203
+ u32 reg;
204
+ int ret;
205
+
206
+ if (!vc4->hvs->hvs5)
207
+ return output;
208
+
209
+ switch (output) {
210
+ case 0:
211
+ return 0;
212
+
213
+ case 1:
214
+ return 1;
215
+
216
+ case 2:
217
+ reg = HVS_READ(SCALER_DISPECTRL);
218
+ ret = FIELD_GET(SCALER_DISPECTRL_DSP2_MUX_MASK, reg);
219
+ if (ret == 0)
220
+ return 2;
221
+
222
+ return 0;
223
+
224
+ case 3:
225
+ reg = HVS_READ(SCALER_DISPCTRL);
226
+ ret = FIELD_GET(SCALER_DISPCTRL_DSP3_MUX_MASK, reg);
227
+ if (ret == 3)
228
+ return -EPIPE;
229
+
230
+ return ret;
231
+
232
+ case 4:
233
+ reg = HVS_READ(SCALER_DISPEOLN);
234
+ ret = FIELD_GET(SCALER_DISPEOLN_DSP4_MUX_MASK, reg);
235
+ if (ret == 3)
236
+ return -EPIPE;
237
+
238
+ return ret;
239
+
240
+ case 5:
241
+ reg = HVS_READ(SCALER_DISPDITHER);
242
+ ret = FIELD_GET(SCALER_DISPDITHER_DSP5_MUX_MASK, reg);
243
+ if (ret == 3)
244
+ return -EPIPE;
245
+
246
+ return ret;
247
+
248
+ default:
249
+ return -EPIPE;
250
+ }
251
+}
252
+
253
+static int vc4_hvs_init_channel(struct vc4_dev *vc4, struct drm_crtc *crtc,
254
+ struct drm_display_mode *mode, bool oneshot)
255
+{
256
+ struct vc4_crtc_state *vc4_crtc_state = to_vc4_crtc_state(crtc->state);
257
+ unsigned int chan = vc4_crtc_state->assigned_channel;
258
+ bool interlace = mode->flags & DRM_MODE_FLAG_INTERLACE;
259
+ u32 dispbkgndx;
260
+ u32 dispctrl;
261
+
262
+ HVS_WRITE(SCALER_DISPCTRLX(chan), 0);
263
+ HVS_WRITE(SCALER_DISPCTRLX(chan), SCALER_DISPCTRLX_RESET);
264
+ HVS_WRITE(SCALER_DISPCTRLX(chan), 0);
265
+
266
+ /* Turn on the scaler, which will wait for vstart to start
267
+ * compositing.
268
+ * When feeding the transposer, we should operate in oneshot
269
+ * mode.
270
+ */
271
+ dispctrl = SCALER_DISPCTRLX_ENABLE;
272
+
273
+ if (!vc4->hvs->hvs5)
274
+ dispctrl |= VC4_SET_FIELD(mode->hdisplay,
275
+ SCALER_DISPCTRLX_WIDTH) |
276
+ VC4_SET_FIELD(mode->vdisplay,
277
+ SCALER_DISPCTRLX_HEIGHT) |
278
+ (oneshot ? SCALER_DISPCTRLX_ONESHOT : 0);
279
+ else
280
+ dispctrl |= VC4_SET_FIELD(mode->hdisplay,
281
+ SCALER5_DISPCTRLX_WIDTH) |
282
+ VC4_SET_FIELD(mode->vdisplay,
283
+ SCALER5_DISPCTRLX_HEIGHT) |
284
+ (oneshot ? SCALER5_DISPCTRLX_ONESHOT : 0);
285
+
286
+ HVS_WRITE(SCALER_DISPCTRLX(chan), dispctrl);
287
+
288
+ dispbkgndx = HVS_READ(SCALER_DISPBKGNDX(chan));
289
+ dispbkgndx &= ~SCALER_DISPBKGND_GAMMA;
290
+ dispbkgndx &= ~SCALER_DISPBKGND_INTERLACE;
291
+
292
+ HVS_WRITE(SCALER_DISPBKGNDX(chan), dispbkgndx |
293
+ SCALER_DISPBKGND_AUTOHS |
294
+ ((!vc4->hvs->hvs5) ? SCALER_DISPBKGND_GAMMA : 0) |
295
+ (interlace ? SCALER_DISPBKGND_INTERLACE : 0));
296
+
297
+ /* Reload the LUT, since the SRAMs would have been disabled if
298
+ * all CRTCs had SCALER_DISPBKGND_GAMMA unset at once.
299
+ */
300
+ vc4_hvs_lut_load(crtc);
301
+
302
+ return 0;
303
+}
304
+
305
+void vc4_hvs_stop_channel(struct drm_device *dev, unsigned int chan)
306
+{
307
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
308
+
309
+ if (HVS_READ(SCALER_DISPCTRLX(chan)) & SCALER_DISPCTRLX_ENABLE)
310
+ return;
311
+
312
+ HVS_WRITE(SCALER_DISPCTRLX(chan),
313
+ HVS_READ(SCALER_DISPCTRLX(chan)) | SCALER_DISPCTRLX_RESET);
314
+ HVS_WRITE(SCALER_DISPCTRLX(chan),
315
+ HVS_READ(SCALER_DISPCTRLX(chan)) & ~SCALER_DISPCTRLX_ENABLE);
316
+
317
+ /* Once we leave, the scaler should be disabled and its fifo empty. */
318
+ WARN_ON_ONCE(HVS_READ(SCALER_DISPCTRLX(chan)) & SCALER_DISPCTRLX_RESET);
319
+
320
+ WARN_ON_ONCE(VC4_GET_FIELD(HVS_READ(SCALER_DISPSTATX(chan)),
321
+ SCALER_DISPSTATX_MODE) !=
322
+ SCALER_DISPSTATX_MODE_DISABLED);
323
+
324
+ WARN_ON_ONCE((HVS_READ(SCALER_DISPSTATX(chan)) &
325
+ (SCALER_DISPSTATX_FULL | SCALER_DISPSTATX_EMPTY)) !=
326
+ SCALER_DISPSTATX_EMPTY);
327
+}
328
+
329
+int vc4_hvs_atomic_check(struct drm_crtc *crtc,
330
+ struct drm_crtc_state *state)
331
+{
332
+ struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(state);
333
+ struct drm_device *dev = crtc->dev;
334
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
335
+ struct drm_plane *plane;
336
+ unsigned long flags;
337
+ const struct drm_plane_state *plane_state;
338
+ u32 dlist_count = 0;
339
+ int ret;
340
+
341
+ /* The pixelvalve can only feed one encoder (and encoders are
342
+ * 1:1 with connectors.)
343
+ */
344
+ if (hweight32(state->connector_mask) > 1)
345
+ return -EINVAL;
346
+
347
+ drm_atomic_crtc_state_for_each_plane_state(plane, plane_state, state)
348
+ dlist_count += vc4_plane_dlist_size(plane_state);
349
+
350
+ dlist_count++; /* Account for SCALER_CTL0_END. */
351
+
352
+ spin_lock_irqsave(&vc4->hvs->mm_lock, flags);
353
+ ret = drm_mm_insert_node(&vc4->hvs->dlist_mm, &vc4_state->mm,
354
+ dlist_count);
355
+ spin_unlock_irqrestore(&vc4->hvs->mm_lock, flags);
356
+ if (ret)
357
+ return ret;
358
+
359
+ return 0;
360
+}
361
+
362
+static void vc4_hvs_update_dlist(struct drm_crtc *crtc)
363
+{
364
+ struct drm_device *dev = crtc->dev;
365
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
366
+ struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
367
+ struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state);
368
+
369
+ if (crtc->state->event) {
370
+ unsigned long flags;
371
+
372
+ crtc->state->event->pipe = drm_crtc_index(crtc);
373
+
374
+ WARN_ON(drm_crtc_vblank_get(crtc) != 0);
375
+
376
+ spin_lock_irqsave(&dev->event_lock, flags);
377
+
378
+ if (!vc4_state->feed_txp || vc4_state->txp_armed) {
379
+ vc4_crtc->event = crtc->state->event;
380
+ crtc->state->event = NULL;
381
+ }
382
+
383
+ HVS_WRITE(SCALER_DISPLISTX(vc4_state->assigned_channel),
384
+ vc4_state->mm.start);
385
+
386
+ spin_unlock_irqrestore(&dev->event_lock, flags);
387
+ } else {
388
+ HVS_WRITE(SCALER_DISPLISTX(vc4_state->assigned_channel),
389
+ vc4_state->mm.start);
390
+ }
391
+}
392
+
393
+void vc4_hvs_atomic_enable(struct drm_crtc *crtc,
394
+ struct drm_crtc_state *old_state)
395
+{
396
+ struct drm_device *dev = crtc->dev;
397
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
398
+ struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state);
399
+ struct drm_display_mode *mode = &crtc->state->adjusted_mode;
400
+ bool oneshot = vc4_state->feed_txp;
401
+
402
+ vc4_hvs_update_dlist(crtc);
403
+ vc4_hvs_init_channel(vc4, crtc, mode, oneshot);
404
+}
405
+
406
+void vc4_hvs_atomic_disable(struct drm_crtc *crtc,
407
+ struct drm_crtc_state *old_state)
408
+{
409
+ struct drm_device *dev = crtc->dev;
410
+ struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(old_state);
411
+ unsigned int chan = vc4_state->assigned_channel;
412
+
413
+ vc4_hvs_stop_channel(dev, chan);
414
+}
415
+
416
+void vc4_hvs_atomic_flush(struct drm_crtc *crtc,
417
+ struct drm_crtc_state *old_state)
418
+{
419
+ struct drm_device *dev = crtc->dev;
420
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
421
+ struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc->state);
422
+ struct drm_plane *plane;
423
+ struct vc4_plane_state *vc4_plane_state;
424
+ bool debug_dump_regs = false;
425
+ bool enable_bg_fill = false;
426
+ u32 __iomem *dlist_start = vc4->hvs->dlist + vc4_state->mm.start;
427
+ u32 __iomem *dlist_next = dlist_start;
428
+
429
+ if (debug_dump_regs) {
430
+ DRM_INFO("CRTC %d HVS before:\n", drm_crtc_index(crtc));
431
+ vc4_hvs_dump_state(dev);
432
+ }
433
+
434
+ /* Copy all the active planes' dlist contents to the hardware dlist. */
435
+ drm_atomic_crtc_for_each_plane(plane, crtc) {
436
+ /* Is this the first active plane? */
437
+ if (dlist_next == dlist_start) {
438
+ /* We need to enable background fill when a plane
439
+ * could be alpha blending from the background, i.e.
440
+ * where no other plane is underneath. It suffices to
441
+ * consider the first active plane here since we set
442
+ * needs_bg_fill such that either the first plane
443
+ * already needs it or all planes on top blend from
444
+ * the first or a lower plane.
445
+ */
446
+ vc4_plane_state = to_vc4_plane_state(plane->state);
447
+ enable_bg_fill = vc4_plane_state->needs_bg_fill;
448
+ }
449
+
450
+ dlist_next += vc4_plane_write_dlist(plane, dlist_next);
451
+ }
452
+
453
+ writel(SCALER_CTL0_END, dlist_next);
454
+ dlist_next++;
455
+
456
+ WARN_ON_ONCE(dlist_next - dlist_start != vc4_state->mm.size);
457
+
458
+ if (enable_bg_fill)
459
+ /* This sets a black background color fill, as is the case
460
+ * with other DRM drivers.
461
+ */
462
+ HVS_WRITE(SCALER_DISPBKGNDX(vc4_state->assigned_channel),
463
+ HVS_READ(SCALER_DISPBKGNDX(vc4_state->assigned_channel)) |
464
+ SCALER_DISPBKGND_FILL);
465
+
466
+ /* Only update DISPLIST if the CRTC was already running and is not
467
+ * being disabled.
468
+ * vc4_crtc_enable() takes care of updating the dlist just after
469
+ * re-enabling VBLANK interrupts and before enabling the engine.
470
+ * If the CRTC is being disabled, there's no point in updating this
471
+ * information.
472
+ */
473
+ if (crtc->state->active && old_state->active)
474
+ vc4_hvs_update_dlist(crtc);
475
+
476
+ if (crtc->state->color_mgmt_changed) {
477
+ u32 dispbkgndx = HVS_READ(SCALER_DISPBKGNDX(vc4_state->assigned_channel));
478
+
479
+ if (crtc->state->gamma_lut) {
480
+ vc4_hvs_update_gamma_lut(crtc);
481
+ dispbkgndx |= SCALER_DISPBKGND_GAMMA;
482
+ } else {
483
+ /* Unsetting DISPBKGND_GAMMA skips the gamma lut step
484
+ * in hardware, which is the same as a linear lut that
485
+ * DRM expects us to use in absence of a user lut.
486
+ */
487
+ dispbkgndx &= ~SCALER_DISPBKGND_GAMMA;
488
+ }
489
+ HVS_WRITE(SCALER_DISPBKGNDX(vc4_state->assigned_channel), dispbkgndx);
490
+ }
491
+
492
+ if (debug_dump_regs) {
493
+ DRM_INFO("CRTC %d HVS after:\n", drm_crtc_index(crtc));
494
+ vc4_hvs_dump_state(dev);
495
+ }
496
+}
497
+
498
+void vc4_hvs_mask_underrun(struct drm_device *dev, int channel)
499
+{
500
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
501
+ u32 dispctrl = HVS_READ(SCALER_DISPCTRL);
502
+
503
+ dispctrl &= ~SCALER_DISPCTRL_DSPEISLUR(channel);
504
+
505
+ HVS_WRITE(SCALER_DISPCTRL, dispctrl);
506
+}
507
+
508
+void vc4_hvs_unmask_underrun(struct drm_device *dev, int channel)
509
+{
510
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
511
+ u32 dispctrl = HVS_READ(SCALER_DISPCTRL);
512
+
513
+ dispctrl |= SCALER_DISPCTRL_DSPEISLUR(channel);
514
+
515
+ HVS_WRITE(SCALER_DISPSTAT,
516
+ SCALER_DISPSTAT_EUFLOW(channel));
517
+ HVS_WRITE(SCALER_DISPCTRL, dispctrl);
518
+}
519
+
520
+static void vc4_hvs_report_underrun(struct drm_device *dev)
521
+{
522
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
523
+
524
+ atomic_inc(&vc4->underrun);
525
+ DRM_DEV_ERROR(dev->dev, "HVS underrun\n");
526
+}
527
+
528
+static irqreturn_t vc4_hvs_irq_handler(int irq, void *data)
529
+{
530
+ struct drm_device *dev = data;
531
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
532
+ irqreturn_t irqret = IRQ_NONE;
533
+ int channel;
534
+ u32 control;
535
+ u32 status;
536
+
537
+ status = HVS_READ(SCALER_DISPSTAT);
538
+ control = HVS_READ(SCALER_DISPCTRL);
539
+
540
+ for (channel = 0; channel < SCALER_CHANNELS_COUNT; channel++) {
541
+ /* Interrupt masking is not always honored, so check it here. */
542
+ if (status & SCALER_DISPSTAT_EUFLOW(channel) &&
543
+ control & SCALER_DISPCTRL_DSPEISLUR(channel)) {
544
+ vc4_hvs_mask_underrun(dev, channel);
545
+ vc4_hvs_report_underrun(dev);
546
+
547
+ irqret = IRQ_HANDLED;
548
+ }
549
+ }
550
+
551
+ /* Clear every per-channel interrupt flag. */
552
+ HVS_WRITE(SCALER_DISPSTAT, SCALER_DISPSTAT_IRQMASK(0) |
553
+ SCALER_DISPSTAT_IRQMASK(1) |
554
+ SCALER_DISPSTAT_IRQMASK(2));
555
+
556
+ return irqret;
557
+}
558
+
169559 static int vc4_hvs_bind(struct device *dev, struct device *master, void *data)
170560 {
171561 struct platform_device *pdev = to_platform_device(dev);
172562 struct drm_device *drm = dev_get_drvdata(master);
173
- struct vc4_dev *vc4 = drm->dev_private;
563
+ struct vc4_dev *vc4 = to_vc4_dev(drm);
174564 struct vc4_hvs *hvs = NULL;
175565 int ret;
176566 u32 dispctrl;
567
+ u32 reg;
177568
178569 hvs = devm_kzalloc(&pdev->dev, sizeof(*hvs), GFP_KERNEL);
179570 if (!hvs)
....@@ -181,11 +572,35 @@
181572
182573 hvs->pdev = pdev;
183574
575
+ if (of_device_is_compatible(pdev->dev.of_node, "brcm,bcm2711-hvs"))
576
+ hvs->hvs5 = true;
577
+
184578 hvs->regs = vc4_ioremap_regs(pdev, 0);
185579 if (IS_ERR(hvs->regs))
186580 return PTR_ERR(hvs->regs);
187581
188
- hvs->dlist = hvs->regs + SCALER_DLIST_START;
582
+ hvs->regset.base = hvs->regs;
583
+ hvs->regset.regs = hvs_regs;
584
+ hvs->regset.nregs = ARRAY_SIZE(hvs_regs);
585
+
586
+ if (hvs->hvs5) {
587
+ hvs->core_clk = devm_clk_get(&pdev->dev, NULL);
588
+ if (IS_ERR(hvs->core_clk)) {
589
+ dev_err(&pdev->dev, "Couldn't get core clock\n");
590
+ return PTR_ERR(hvs->core_clk);
591
+ }
592
+
593
+ ret = clk_prepare_enable(hvs->core_clk);
594
+ if (ret) {
595
+ dev_err(&pdev->dev, "Couldn't enable the core clock\n");
596
+ return ret;
597
+ }
598
+ }
599
+
600
+ if (!hvs->hvs5)
601
+ hvs->dlist = hvs->regs + SCALER_DLIST_START;
602
+ else
603
+ hvs->dlist = hvs->regs + SCALER5_DLIST_START;
189604
190605 spin_lock_init(&hvs->mm_lock);
191606
....@@ -203,7 +618,12 @@
203618 * between planes when they don't overlap on the screen, but
204619 * for now we just allocate globally.
205620 */
206
- drm_mm_init(&hvs->lbm_mm, 0, 96 * 1024);
621
+ if (!hvs->hvs5)
622
+ /* 48k words of 2x12-bit pixels */
623
+ drm_mm_init(&hvs->lbm_mm, 0, 48 * 1024);
624
+ else
625
+ /* 60k words of 4x12-bit pixels */
626
+ drm_mm_init(&hvs->lbm_mm, 0, 60 * 1024);
207627
208628 /* Upload filter kernels. We only have the one for now, so we
209629 * keep it around for the lifetime of the driver.
....@@ -216,17 +636,68 @@
216636
217637 vc4->hvs = hvs;
218638
639
+ reg = HVS_READ(SCALER_DISPECTRL);
640
+ reg &= ~SCALER_DISPECTRL_DSP2_MUX_MASK;
641
+ HVS_WRITE(SCALER_DISPECTRL,
642
+ reg | VC4_SET_FIELD(0, SCALER_DISPECTRL_DSP2_MUX));
643
+
644
+ reg = HVS_READ(SCALER_DISPCTRL);
645
+ reg &= ~SCALER_DISPCTRL_DSP3_MUX_MASK;
646
+ HVS_WRITE(SCALER_DISPCTRL,
647
+ reg | VC4_SET_FIELD(3, SCALER_DISPCTRL_DSP3_MUX));
648
+
649
+ reg = HVS_READ(SCALER_DISPEOLN);
650
+ reg &= ~SCALER_DISPEOLN_DSP4_MUX_MASK;
651
+ HVS_WRITE(SCALER_DISPEOLN,
652
+ reg | VC4_SET_FIELD(3, SCALER_DISPEOLN_DSP4_MUX));
653
+
654
+ reg = HVS_READ(SCALER_DISPDITHER);
655
+ reg &= ~SCALER_DISPDITHER_DSP5_MUX_MASK;
656
+ HVS_WRITE(SCALER_DISPDITHER,
657
+ reg | VC4_SET_FIELD(3, SCALER_DISPDITHER_DSP5_MUX));
658
+
219659 dispctrl = HVS_READ(SCALER_DISPCTRL);
220660
221661 dispctrl |= SCALER_DISPCTRL_ENABLE;
662
+ dispctrl |= SCALER_DISPCTRL_DISPEIRQ(0) |
663
+ SCALER_DISPCTRL_DISPEIRQ(1) |
664
+ SCALER_DISPCTRL_DISPEIRQ(2);
222665
223
- /* Set DSP3 (PV1) to use HVS channel 2, which would otherwise
224
- * be unused.
666
+ dispctrl &= ~(SCALER_DISPCTRL_DMAEIRQ |
667
+ SCALER_DISPCTRL_SLVWREIRQ |
668
+ SCALER_DISPCTRL_SLVRDEIRQ |
669
+ SCALER_DISPCTRL_DSPEIEOF(0) |
670
+ SCALER_DISPCTRL_DSPEIEOF(1) |
671
+ SCALER_DISPCTRL_DSPEIEOF(2) |
672
+ SCALER_DISPCTRL_DSPEIEOLN(0) |
673
+ SCALER_DISPCTRL_DSPEIEOLN(1) |
674
+ SCALER_DISPCTRL_DSPEIEOLN(2) |
675
+ SCALER_DISPCTRL_DSPEISLUR(0) |
676
+ SCALER_DISPCTRL_DSPEISLUR(1) |
677
+ SCALER_DISPCTRL_DSPEISLUR(2) |
678
+ SCALER_DISPCTRL_SCLEIRQ);
679
+
680
+ /* Set AXI panic mode.
681
+ * VC4 panics when < 2 lines in FIFO.
682
+ * VC5 panics when less than 1 line in the FIFO.
225683 */
226
- dispctrl &= ~SCALER_DISPCTRL_DSP3_MUX_MASK;
227
- dispctrl |= VC4_SET_FIELD(2, SCALER_DISPCTRL_DSP3_MUX);
684
+ dispctrl &= ~(SCALER_DISPCTRL_PANIC0_MASK |
685
+ SCALER_DISPCTRL_PANIC1_MASK |
686
+ SCALER_DISPCTRL_PANIC2_MASK);
687
+ dispctrl |= VC4_SET_FIELD(2, SCALER_DISPCTRL_PANIC0);
688
+ dispctrl |= VC4_SET_FIELD(2, SCALER_DISPCTRL_PANIC1);
689
+ dispctrl |= VC4_SET_FIELD(2, SCALER_DISPCTRL_PANIC2);
228690
229691 HVS_WRITE(SCALER_DISPCTRL, dispctrl);
692
+
693
+ ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
694
+ vc4_hvs_irq_handler, 0, "vc4 hvs", drm);
695
+ if (ret)
696
+ return ret;
697
+
698
+ vc4_debugfs_add_regset32(drm, "hvs_regs", &hvs->regset);
699
+ vc4_debugfs_add_file(drm, "hvs_underrun", vc4_hvs_debugfs_underrun,
700
+ NULL);
230701
231702 return 0;
232703 }
....@@ -235,13 +706,16 @@
235706 void *data)
236707 {
237708 struct drm_device *drm = dev_get_drvdata(master);
238
- struct vc4_dev *vc4 = drm->dev_private;
709
+ struct vc4_dev *vc4 = to_vc4_dev(drm);
710
+ struct vc4_hvs *hvs = vc4->hvs;
239711
240
- if (vc4->hvs->mitchell_netravali_filter.allocated)
712
+ if (drm_mm_node_allocated(&vc4->hvs->mitchell_netravali_filter))
241713 drm_mm_remove_node(&vc4->hvs->mitchell_netravali_filter);
242714
243715 drm_mm_takedown(&vc4->hvs->dlist_mm);
244716 drm_mm_takedown(&vc4->hvs->lbm_mm);
717
+
718
+ clk_disable_unprepare(hvs->core_clk);
245719
246720 vc4->hvs = NULL;
247721 }
....@@ -263,6 +737,7 @@
263737 }
264738
265739 static const struct of_device_id vc4_hvs_dt_match[] = {
740
+ { .compatible = "brcm,bcm2711-hvs" },
266741 { .compatible = "brcm,bcm2835-hvs" },
267742 {}
268743 };