forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-05-13 9d77db3c730780c8ef5ccd4b66403ff5675cfe4e
kernel/drivers/gpu/drm/vc4/vc4_txp.c
....@@ -7,17 +7,20 @@
77 * Boris Brezillon <boris.brezillon@bootlin.com>
88 */
99
10
-#include <drm/drm_atomic_helper.h>
11
-#include <drm/drm_fb_cma_helper.h>
12
-#include <drm/drm_crtc_helper.h>
13
-#include <drm/drm_edid.h>
14
-#include <drm/drm_panel.h>
15
-#include <drm/drm_writeback.h>
1610 #include <linux/clk.h>
1711 #include <linux/component.h>
1812 #include <linux/of_graph.h>
1913 #include <linux/of_platform.h>
2014 #include <linux/pm_runtime.h>
15
+
16
+#include <drm/drm_atomic_helper.h>
17
+#include <drm/drm_edid.h>
18
+#include <drm/drm_fb_cma_helper.h>
19
+#include <drm/drm_fourcc.h>
20
+#include <drm/drm_panel.h>
21
+#include <drm/drm_probe_helper.h>
22
+#include <drm/drm_vblank.h>
23
+#include <drm/drm_writeback.h>
2124
2225 #include "vc4_drv.h"
2326 #include "vc4_regs.h"
....@@ -143,11 +146,14 @@
143146 #define TXP_WRITE(offset, val) writel(val, txp->regs + (offset))
144147
145148 struct vc4_txp {
149
+ struct vc4_crtc base;
150
+
146151 struct platform_device *pdev;
147152
148153 struct drm_writeback_connector connector;
149154
150155 void __iomem *regs;
156
+ struct debugfs_regset32 regset;
151157 };
152158
153159 static inline struct vc4_txp *encoder_to_vc4_txp(struct drm_encoder *encoder)
....@@ -160,39 +166,13 @@
160166 return container_of(conn, struct vc4_txp, connector.base);
161167 }
162168
163
-#define TXP_REG(reg) { reg, #reg }
164
-static const struct {
165
- u32 reg;
166
- const char *name;
167
-} txp_regs[] = {
168
- TXP_REG(TXP_DST_PTR),
169
- TXP_REG(TXP_DST_PITCH),
170
- TXP_REG(TXP_DIM),
171
- TXP_REG(TXP_DST_CTRL),
172
- TXP_REG(TXP_PROGRESS),
169
+static const struct debugfs_reg32 txp_regs[] = {
170
+ VC4_REG32(TXP_DST_PTR),
171
+ VC4_REG32(TXP_DST_PITCH),
172
+ VC4_REG32(TXP_DIM),
173
+ VC4_REG32(TXP_DST_CTRL),
174
+ VC4_REG32(TXP_PROGRESS),
173175 };
174
-
175
-#ifdef CONFIG_DEBUG_FS
176
-int vc4_txp_debugfs_regs(struct seq_file *m, void *unused)
177
-{
178
- struct drm_info_node *node = (struct drm_info_node *)m->private;
179
- struct drm_device *dev = node->minor->dev;
180
- struct vc4_dev *vc4 = to_vc4_dev(dev);
181
- struct vc4_txp *txp = vc4->txp;
182
- int i;
183
-
184
- if (!txp)
185
- return 0;
186
-
187
- for (i = 0; i < ARRAY_SIZE(txp_regs); i++) {
188
- seq_printf(m, "%s (0x%04x): 0x%08x\n",
189
- txp_regs[i].name, txp_regs[i].reg,
190
- TXP_READ(txp_regs[i].reg));
191
- }
192
-
193
- return 0;
194
-}
195
-#endif
196176
197177 static int vc4_txp_connector_get_modes(struct drm_connector *connector)
198178 {
....@@ -245,17 +225,23 @@
245225 TXP_FORMAT_BGRA8888,
246226 };
247227
228
+static void vc4_txp_armed(struct drm_crtc_state *state)
229
+{
230
+ struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(state);
231
+
232
+ vc4_state->txp_armed = true;
233
+}
234
+
248235 static int vc4_txp_connector_atomic_check(struct drm_connector *conn,
249236 struct drm_atomic_state *state)
250237 {
251238 struct drm_connector_state *conn_state;
252239 struct drm_crtc_state *crtc_state;
253
- struct drm_gem_cma_object *gem;
254240 struct drm_framebuffer *fb;
255241 int i;
256242
257243 conn_state = drm_atomic_get_new_connector_state(state, conn);
258
- if (!conn_state->writeback_job || !conn_state->writeback_job->fb)
244
+ if (!conn_state->writeback_job)
259245 return 0;
260246
261247 crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
....@@ -276,13 +262,11 @@
276262 if (i == ARRAY_SIZE(drm_fmts))
277263 return -EINVAL;
278264
279
- gem = drm_fb_cma_get_gem_obj(fb, 0);
280
-
281265 /* Pitch must be aligned on 16 bytes. */
282266 if (fb->pitches[0] & GENMASK(3, 0))
283267 return -EINVAL;
284268
285
- vc4_crtc_txp_armed(crtc_state);
269
+ vc4_txp_armed(crtc_state);
286270
287271 return 0;
288272 }
....@@ -297,8 +281,7 @@
297281 u32 ctrl;
298282 int i;
299283
300
- if (WARN_ON(!conn_state->writeback_job ||
301
- !conn_state->writeback_job->fb))
284
+ if (WARN_ON(!conn_state->writeback_job))
302285 return;
303286
304287 mode = &conn_state->crtc->state->adjusted_mode;
....@@ -312,12 +295,18 @@
312295 if (WARN_ON(i == ARRAY_SIZE(drm_fmts)))
313296 return;
314297
315
- ctrl = TXP_GO | TXP_VSTART_AT_EOF | TXP_EI |
298
+ ctrl = TXP_GO | TXP_EI |
316299 VC4_SET_FIELD(0xf, TXP_BYTE_ENABLE) |
317300 VC4_SET_FIELD(txp_fmts[i], TXP_FORMAT);
318301
319302 if (fb->format->has_alpha)
320303 ctrl |= TXP_ALPHA_ENABLE;
304
+ else
305
+ /*
306
+ * If TXP_ALPHA_ENABLE isn't set and TXP_ALPHA_INVERT is, the
307
+ * hardware will force the output padding to be 0xff.
308
+ */
309
+ ctrl |= TXP_ALPHA_INVERT;
321310
322311 gem = drm_fb_cma_get_gem_obj(fb, 0);
323312 TXP_WRITE(TXP_DST_PTR, gem->paddr + fb->offsets[0]);
....@@ -328,7 +317,7 @@
328317
329318 TXP_WRITE(TXP_DST_CTRL, ctrl);
330319
331
- drm_writeback_queue_job(&txp->connector, conn_state->writeback_job);
320
+ drm_writeback_queue_job(&txp->connector, conn_state);
332321 }
333322
334323 static const struct drm_connector_helper_funcs vc4_txp_connector_helper_funcs = {
....@@ -382,23 +371,105 @@
382371 .disable = vc4_txp_encoder_disable,
383372 };
384373
374
+static int vc4_txp_enable_vblank(struct drm_crtc *crtc)
375
+{
376
+ return 0;
377
+}
378
+
379
+static void vc4_txp_disable_vblank(struct drm_crtc *crtc) {}
380
+
381
+static const struct drm_crtc_funcs vc4_txp_crtc_funcs = {
382
+ .set_config = drm_atomic_helper_set_config,
383
+ .destroy = vc4_crtc_destroy,
384
+ .page_flip = vc4_page_flip,
385
+ .reset = vc4_crtc_reset,
386
+ .atomic_duplicate_state = vc4_crtc_duplicate_state,
387
+ .atomic_destroy_state = vc4_crtc_destroy_state,
388
+ .gamma_set = drm_atomic_helper_legacy_gamma_set,
389
+ .enable_vblank = vc4_txp_enable_vblank,
390
+ .disable_vblank = vc4_txp_disable_vblank,
391
+};
392
+
393
+static int vc4_txp_atomic_check(struct drm_crtc *crtc,
394
+ struct drm_crtc_state *state)
395
+{
396
+ struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(state);
397
+ int ret;
398
+
399
+ ret = vc4_hvs_atomic_check(crtc, state);
400
+ if (ret)
401
+ return ret;
402
+
403
+ state->no_vblank = true;
404
+ vc4_state->feed_txp = true;
405
+
406
+ return 0;
407
+}
408
+
409
+static void vc4_txp_atomic_enable(struct drm_crtc *crtc,
410
+ struct drm_crtc_state *old_state)
411
+{
412
+ drm_crtc_vblank_on(crtc);
413
+ vc4_hvs_atomic_enable(crtc, old_state);
414
+}
415
+
416
+static void vc4_txp_atomic_disable(struct drm_crtc *crtc,
417
+ struct drm_crtc_state *old_state)
418
+{
419
+ struct drm_device *dev = crtc->dev;
420
+
421
+ /* Disable vblank irq handling before crtc is disabled. */
422
+ drm_crtc_vblank_off(crtc);
423
+
424
+ vc4_hvs_atomic_disable(crtc, old_state);
425
+
426
+ /*
427
+ * Make sure we issue a vblank event after disabling the CRTC if
428
+ * someone was waiting it.
429
+ */
430
+ if (crtc->state->event) {
431
+ unsigned long flags;
432
+
433
+ spin_lock_irqsave(&dev->event_lock, flags);
434
+ drm_crtc_send_vblank_event(crtc, crtc->state->event);
435
+ crtc->state->event = NULL;
436
+ spin_unlock_irqrestore(&dev->event_lock, flags);
437
+ }
438
+}
439
+
440
+static const struct drm_crtc_helper_funcs vc4_txp_crtc_helper_funcs = {
441
+ .atomic_check = vc4_txp_atomic_check,
442
+ .atomic_flush = vc4_hvs_atomic_flush,
443
+ .atomic_enable = vc4_txp_atomic_enable,
444
+ .atomic_disable = vc4_txp_atomic_disable,
445
+};
446
+
385447 static irqreturn_t vc4_txp_interrupt(int irq, void *data)
386448 {
387449 struct vc4_txp *txp = data;
450
+ struct vc4_crtc *vc4_crtc = &txp->base;
388451
389452 TXP_WRITE(TXP_DST_CTRL, TXP_READ(TXP_DST_CTRL) & ~TXP_EI);
390
- vc4_crtc_handle_vblank(to_vc4_crtc(txp->connector.base.state->crtc));
453
+ vc4_crtc_handle_vblank(vc4_crtc);
391454 drm_writeback_signal_completion(&txp->connector, 0);
392455
393456 return IRQ_HANDLED;
394457 }
458
+
459
+static const struct vc4_crtc_data vc4_txp_crtc_data = {
460
+ .hvs_available_channels = BIT(2),
461
+ .hvs_output = 2,
462
+};
395463
396464 static int vc4_txp_bind(struct device *dev, struct device *master, void *data)
397465 {
398466 struct platform_device *pdev = to_platform_device(dev);
399467 struct drm_device *drm = dev_get_drvdata(master);
400468 struct vc4_dev *vc4 = to_vc4_dev(drm);
469
+ struct vc4_crtc *vc4_crtc;
401470 struct vc4_txp *txp;
471
+ struct drm_crtc *crtc;
472
+ struct drm_encoder *encoder;
402473 int ret, irq;
403474
404475 irq = platform_get_irq(pdev, 0);
....@@ -408,12 +479,20 @@
408479 txp = devm_kzalloc(dev, sizeof(*txp), GFP_KERNEL);
409480 if (!txp)
410481 return -ENOMEM;
482
+ vc4_crtc = &txp->base;
483
+ crtc = &vc4_crtc->base;
484
+
485
+ vc4_crtc->pdev = pdev;
486
+ vc4_crtc->data = &vc4_txp_crtc_data;
411487
412488 txp->pdev = pdev;
413489
414490 txp->regs = vc4_ioremap_regs(pdev, 0);
415491 if (IS_ERR(txp->regs))
416492 return PTR_ERR(txp->regs);
493
+ txp->regset.base = txp->regs;
494
+ txp->regset.regs = txp_regs;
495
+ txp->regset.nregs = ARRAY_SIZE(txp_regs);
417496
418497 drm_connector_helper_add(&txp->connector.base,
419498 &vc4_txp_connector_helper_funcs);
....@@ -424,6 +503,14 @@
424503 if (ret)
425504 return ret;
426505
506
+ ret = vc4_crtc_init(drm, vc4_crtc,
507
+ &vc4_txp_crtc_funcs, &vc4_txp_crtc_helper_funcs);
508
+ if (ret)
509
+ return ret;
510
+
511
+ encoder = &txp->connector.encoder;
512
+ encoder->possible_crtcs = drm_crtc_mask(crtc);
513
+
427514 ret = devm_request_irq(dev, irq, vc4_txp_interrupt, 0,
428515 dev_name(dev), txp);
429516 if (ret)
....@@ -432,6 +519,8 @@
432519 dev_set_drvdata(dev, txp);
433520 vc4->txp = txp;
434521
522
+ vc4_debugfs_add_regset32(drm, "txp_regs", &txp->regset);
523
+
435524 return 0;
436525 }
437526