]> Git Repo - J-linux.git/blob - drivers/gpu/drm/rcar-du/rcar_du_drv.c
Merge branch 'asoc-5.3' into asoc-5.4
[J-linux.git] / drivers / gpu / drm / rcar-du / rcar_du_drv.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * rcar_du_drv.c  --  R-Car Display Unit DRM driver
4  *
5  * Copyright (C) 2013-2015 Renesas Electronics Corporation
6  *
7  * Contact: Laurent Pinchart ([email protected])
8  */
9
10 #include <linux/clk.h>
11 #include <linux/io.h>
12 #include <linux/mm.h>
13 #include <linux/module.h>
14 #include <linux/of_device.h>
15 #include <linux/platform_device.h>
16 #include <linux/pm.h>
17 #include <linux/slab.h>
18 #include <linux/wait.h>
19
20 #include <drm/drm_atomic_helper.h>
21 #include <drm/drm_fb_cma_helper.h>
22 #include <drm/drm_fb_helper.h>
23 #include <drm/drm_drv.h>
24 #include <drm/drm_gem_cma_helper.h>
25 #include <drm/drm_probe_helper.h>
26
27 #include "rcar_du_drv.h"
28 #include "rcar_du_kms.h"
29 #include "rcar_du_of.h"
30 #include "rcar_du_regs.h"
31
32 /* -----------------------------------------------------------------------------
33  * Device Information
34  */
35
36 static const struct rcar_du_device_info rzg1_du_r8a7743_info = {
37         .gen = 2,
38         .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
39                   | RCAR_DU_FEATURE_INTERLACED
40                   | RCAR_DU_FEATURE_TVM_SYNC,
41         .channels_mask = BIT(1) | BIT(0),
42         .routes = {
43                 /*
44                  * R8A774[34] has one RGB output and one LVDS output
45                  */
46                 [RCAR_DU_OUTPUT_DPAD0] = {
47                         .possible_crtcs = BIT(1) | BIT(0),
48                         .port = 0,
49                 },
50                 [RCAR_DU_OUTPUT_LVDS0] = {
51                         .possible_crtcs = BIT(0),
52                         .port = 1,
53                 },
54         },
55         .num_lvds = 1,
56 };
57
58 static const struct rcar_du_device_info rzg1_du_r8a7745_info = {
59         .gen = 2,
60         .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
61                   | RCAR_DU_FEATURE_INTERLACED
62                   | RCAR_DU_FEATURE_TVM_SYNC,
63         .channels_mask = BIT(1) | BIT(0),
64         .routes = {
65                 /*
66                  * R8A7745 has two RGB outputs
67                  */
68                 [RCAR_DU_OUTPUT_DPAD0] = {
69                         .possible_crtcs = BIT(0),
70                         .port = 0,
71                 },
72                 [RCAR_DU_OUTPUT_DPAD1] = {
73                         .possible_crtcs = BIT(1),
74                         .port = 1,
75                 },
76         },
77 };
78
79 static const struct rcar_du_device_info rzg1_du_r8a77470_info = {
80         .gen = 2,
81         .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
82                   | RCAR_DU_FEATURE_INTERLACED
83                   | RCAR_DU_FEATURE_TVM_SYNC,
84         .channels_mask = BIT(1) | BIT(0),
85         .routes = {
86                 /*
87                  * R8A77470 has two RGB outputs, one LVDS output, and
88                  * one (currently unsupported) analog video output
89                  */
90                 [RCAR_DU_OUTPUT_DPAD0] = {
91                         .possible_crtcs = BIT(0),
92                         .port = 0,
93                 },
94                 [RCAR_DU_OUTPUT_DPAD1] = {
95                         .possible_crtcs = BIT(1),
96                         .port = 1,
97                 },
98                 [RCAR_DU_OUTPUT_LVDS0] = {
99                         .possible_crtcs = BIT(0) | BIT(1),
100                         .port = 2,
101                 },
102         },
103 };
104
105 static const struct rcar_du_device_info rcar_du_r8a774a1_info = {
106         .gen = 3,
107         .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
108                   | RCAR_DU_FEATURE_VSP1_SOURCE
109                   | RCAR_DU_FEATURE_INTERLACED
110                   | RCAR_DU_FEATURE_TVM_SYNC,
111         .channels_mask = BIT(2) | BIT(1) | BIT(0),
112         .routes = {
113                 /*
114                  * R8A774A1 has one RGB output, one LVDS output and one HDMI
115                  * output.
116                  */
117                 [RCAR_DU_OUTPUT_DPAD0] = {
118                         .possible_crtcs = BIT(2),
119                         .port = 0,
120                 },
121                 [RCAR_DU_OUTPUT_HDMI0] = {
122                         .possible_crtcs = BIT(1),
123                         .port = 1,
124                 },
125                 [RCAR_DU_OUTPUT_LVDS0] = {
126                         .possible_crtcs = BIT(0),
127                         .port = 2,
128                 },
129         },
130         .num_lvds = 1,
131         .dpll_mask =  BIT(1),
132 };
133
134 static const struct rcar_du_device_info rcar_du_r8a774c0_info = {
135         .gen = 3,
136         .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
137                   | RCAR_DU_FEATURE_VSP1_SOURCE,
138         .channels_mask = BIT(1) | BIT(0),
139         .routes = {
140                 /*
141                  * R8A774C0 has one RGB output and two LVDS outputs
142                  */
143                 [RCAR_DU_OUTPUT_DPAD0] = {
144                         .possible_crtcs = BIT(0) | BIT(1),
145                         .port = 0,
146                 },
147                 [RCAR_DU_OUTPUT_LVDS0] = {
148                         .possible_crtcs = BIT(0),
149                         .port = 1,
150                 },
151                 [RCAR_DU_OUTPUT_LVDS1] = {
152                         .possible_crtcs = BIT(1),
153                         .port = 2,
154                 },
155         },
156         .num_lvds = 2,
157         .lvds_clk_mask =  BIT(1) | BIT(0),
158 };
159
160 static const struct rcar_du_device_info rcar_du_r8a7779_info = {
161         .gen = 1,
162         .features = RCAR_DU_FEATURE_INTERLACED
163                   | RCAR_DU_FEATURE_TVM_SYNC,
164         .channels_mask = BIT(1) | BIT(0),
165         .routes = {
166                 /*
167                  * R8A7779 has two RGB outputs and one (currently unsupported)
168                  * TCON output.
169                  */
170                 [RCAR_DU_OUTPUT_DPAD0] = {
171                         .possible_crtcs = BIT(0),
172                         .port = 0,
173                 },
174                 [RCAR_DU_OUTPUT_DPAD1] = {
175                         .possible_crtcs = BIT(1) | BIT(0),
176                         .port = 1,
177                 },
178         },
179 };
180
181 static const struct rcar_du_device_info rcar_du_r8a7790_info = {
182         .gen = 2,
183         .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
184                   | RCAR_DU_FEATURE_INTERLACED
185                   | RCAR_DU_FEATURE_TVM_SYNC,
186         .quirks = RCAR_DU_QUIRK_ALIGN_128B,
187         .channels_mask = BIT(2) | BIT(1) | BIT(0),
188         .routes = {
189                 /*
190                  * R8A7790 has one RGB output, two LVDS outputs and one
191                  * (currently unsupported) TCON output.
192                  */
193                 [RCAR_DU_OUTPUT_DPAD0] = {
194                         .possible_crtcs = BIT(2) | BIT(1) | BIT(0),
195                         .port = 0,
196                 },
197                 [RCAR_DU_OUTPUT_LVDS0] = {
198                         .possible_crtcs = BIT(0),
199                         .port = 1,
200                 },
201                 [RCAR_DU_OUTPUT_LVDS1] = {
202                         .possible_crtcs = BIT(2) | BIT(1),
203                         .port = 2,
204                 },
205         },
206         .num_lvds = 2,
207 };
208
209 /* M2-W (r8a7791) and M2-N (r8a7793) are identical */
210 static const struct rcar_du_device_info rcar_du_r8a7791_info = {
211         .gen = 2,
212         .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
213                   | RCAR_DU_FEATURE_INTERLACED
214                   | RCAR_DU_FEATURE_TVM_SYNC,
215         .channels_mask = BIT(1) | BIT(0),
216         .routes = {
217                 /*
218                  * R8A779[13] has one RGB output, one LVDS output and one
219                  * (currently unsupported) TCON output.
220                  */
221                 [RCAR_DU_OUTPUT_DPAD0] = {
222                         .possible_crtcs = BIT(1) | BIT(0),
223                         .port = 0,
224                 },
225                 [RCAR_DU_OUTPUT_LVDS0] = {
226                         .possible_crtcs = BIT(0),
227                         .port = 1,
228                 },
229         },
230         .num_lvds = 1,
231 };
232
233 static const struct rcar_du_device_info rcar_du_r8a7792_info = {
234         .gen = 2,
235         .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
236                   | RCAR_DU_FEATURE_INTERLACED
237                   | RCAR_DU_FEATURE_TVM_SYNC,
238         .channels_mask = BIT(1) | BIT(0),
239         .routes = {
240                 /* R8A7792 has two RGB outputs. */
241                 [RCAR_DU_OUTPUT_DPAD0] = {
242                         .possible_crtcs = BIT(0),
243                         .port = 0,
244                 },
245                 [RCAR_DU_OUTPUT_DPAD1] = {
246                         .possible_crtcs = BIT(1),
247                         .port = 1,
248                 },
249         },
250 };
251
252 static const struct rcar_du_device_info rcar_du_r8a7794_info = {
253         .gen = 2,
254         .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
255                   | RCAR_DU_FEATURE_INTERLACED
256                   | RCAR_DU_FEATURE_TVM_SYNC,
257         .channels_mask = BIT(1) | BIT(0),
258         .routes = {
259                 /*
260                  * R8A7794 has two RGB outputs and one (currently unsupported)
261                  * TCON output.
262                  */
263                 [RCAR_DU_OUTPUT_DPAD0] = {
264                         .possible_crtcs = BIT(0),
265                         .port = 0,
266                 },
267                 [RCAR_DU_OUTPUT_DPAD1] = {
268                         .possible_crtcs = BIT(1),
269                         .port = 1,
270                 },
271         },
272 };
273
274 static const struct rcar_du_device_info rcar_du_r8a7795_info = {
275         .gen = 3,
276         .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
277                   | RCAR_DU_FEATURE_VSP1_SOURCE
278                   | RCAR_DU_FEATURE_INTERLACED
279                   | RCAR_DU_FEATURE_TVM_SYNC,
280         .channels_mask = BIT(3) | BIT(2) | BIT(1) | BIT(0),
281         .routes = {
282                 /*
283                  * R8A7795 has one RGB output, two HDMI outputs and one
284                  * LVDS output.
285                  */
286                 [RCAR_DU_OUTPUT_DPAD0] = {
287                         .possible_crtcs = BIT(3),
288                         .port = 0,
289                 },
290                 [RCAR_DU_OUTPUT_HDMI0] = {
291                         .possible_crtcs = BIT(1),
292                         .port = 1,
293                 },
294                 [RCAR_DU_OUTPUT_HDMI1] = {
295                         .possible_crtcs = BIT(2),
296                         .port = 2,
297                 },
298                 [RCAR_DU_OUTPUT_LVDS0] = {
299                         .possible_crtcs = BIT(0),
300                         .port = 3,
301                 },
302         },
303         .num_lvds = 1,
304         .dpll_mask =  BIT(2) | BIT(1),
305 };
306
307 static const struct rcar_du_device_info rcar_du_r8a7796_info = {
308         .gen = 3,
309         .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
310                   | RCAR_DU_FEATURE_VSP1_SOURCE
311                   | RCAR_DU_FEATURE_INTERLACED
312                   | RCAR_DU_FEATURE_TVM_SYNC,
313         .channels_mask = BIT(2) | BIT(1) | BIT(0),
314         .routes = {
315                 /*
316                  * R8A7796 has one RGB output, one LVDS output and one HDMI
317                  * output.
318                  */
319                 [RCAR_DU_OUTPUT_DPAD0] = {
320                         .possible_crtcs = BIT(2),
321                         .port = 0,
322                 },
323                 [RCAR_DU_OUTPUT_HDMI0] = {
324                         .possible_crtcs = BIT(1),
325                         .port = 1,
326                 },
327                 [RCAR_DU_OUTPUT_LVDS0] = {
328                         .possible_crtcs = BIT(0),
329                         .port = 2,
330                 },
331         },
332         .num_lvds = 1,
333         .dpll_mask =  BIT(1),
334 };
335
336 static const struct rcar_du_device_info rcar_du_r8a77965_info = {
337         .gen = 3,
338         .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
339                   | RCAR_DU_FEATURE_VSP1_SOURCE
340                   | RCAR_DU_FEATURE_INTERLACED
341                   | RCAR_DU_FEATURE_TVM_SYNC,
342         .channels_mask = BIT(3) | BIT(1) | BIT(0),
343         .routes = {
344                 /*
345                  * R8A77965 has one RGB output, one LVDS output and one HDMI
346                  * output.
347                  */
348                 [RCAR_DU_OUTPUT_DPAD0] = {
349                         .possible_crtcs = BIT(2),
350                         .port = 0,
351                 },
352                 [RCAR_DU_OUTPUT_HDMI0] = {
353                         .possible_crtcs = BIT(1),
354                         .port = 1,
355                 },
356                 [RCAR_DU_OUTPUT_LVDS0] = {
357                         .possible_crtcs = BIT(0),
358                         .port = 2,
359                 },
360         },
361         .num_lvds = 1,
362         .dpll_mask =  BIT(1),
363 };
364
365 static const struct rcar_du_device_info rcar_du_r8a77970_info = {
366         .gen = 3,
367         .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
368                   | RCAR_DU_FEATURE_VSP1_SOURCE
369                   | RCAR_DU_FEATURE_INTERLACED
370                   | RCAR_DU_FEATURE_TVM_SYNC,
371         .channels_mask = BIT(0),
372         .routes = {
373                 /* R8A77970 has one RGB output and one LVDS output. */
374                 [RCAR_DU_OUTPUT_DPAD0] = {
375                         .possible_crtcs = BIT(0),
376                         .port = 0,
377                 },
378                 [RCAR_DU_OUTPUT_LVDS0] = {
379                         .possible_crtcs = BIT(0),
380                         .port = 1,
381                 },
382         },
383         .num_lvds = 1,
384 };
385
386 static const struct rcar_du_device_info rcar_du_r8a7799x_info = {
387         .gen = 3,
388         .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
389                   | RCAR_DU_FEATURE_VSP1_SOURCE,
390         .channels_mask = BIT(1) | BIT(0),
391         .routes = {
392                 /*
393                  * R8A77990 and R8A77995 have one RGB output and two LVDS
394                  * outputs.
395                  */
396                 [RCAR_DU_OUTPUT_DPAD0] = {
397                         .possible_crtcs = BIT(0) | BIT(1),
398                         .port = 0,
399                 },
400                 [RCAR_DU_OUTPUT_LVDS0] = {
401                         .possible_crtcs = BIT(0),
402                         .port = 1,
403                 },
404                 [RCAR_DU_OUTPUT_LVDS1] = {
405                         .possible_crtcs = BIT(1),
406                         .port = 2,
407                 },
408         },
409         .num_lvds = 2,
410         .lvds_clk_mask =  BIT(1) | BIT(0),
411 };
412
413 static const struct of_device_id rcar_du_of_table[] = {
414         { .compatible = "renesas,du-r8a7743", .data = &rzg1_du_r8a7743_info },
415         { .compatible = "renesas,du-r8a7744", .data = &rzg1_du_r8a7743_info },
416         { .compatible = "renesas,du-r8a7745", .data = &rzg1_du_r8a7745_info },
417         { .compatible = "renesas,du-r8a77470", .data = &rzg1_du_r8a77470_info },
418         { .compatible = "renesas,du-r8a774a1", .data = &rcar_du_r8a774a1_info },
419         { .compatible = "renesas,du-r8a774c0", .data = &rcar_du_r8a774c0_info },
420         { .compatible = "renesas,du-r8a7779", .data = &rcar_du_r8a7779_info },
421         { .compatible = "renesas,du-r8a7790", .data = &rcar_du_r8a7790_info },
422         { .compatible = "renesas,du-r8a7791", .data = &rcar_du_r8a7791_info },
423         { .compatible = "renesas,du-r8a7792", .data = &rcar_du_r8a7792_info },
424         { .compatible = "renesas,du-r8a7793", .data = &rcar_du_r8a7791_info },
425         { .compatible = "renesas,du-r8a7794", .data = &rcar_du_r8a7794_info },
426         { .compatible = "renesas,du-r8a7795", .data = &rcar_du_r8a7795_info },
427         { .compatible = "renesas,du-r8a7796", .data = &rcar_du_r8a7796_info },
428         { .compatible = "renesas,du-r8a77965", .data = &rcar_du_r8a77965_info },
429         { .compatible = "renesas,du-r8a77970", .data = &rcar_du_r8a77970_info },
430         { .compatible = "renesas,du-r8a77990", .data = &rcar_du_r8a7799x_info },
431         { .compatible = "renesas,du-r8a77995", .data = &rcar_du_r8a7799x_info },
432         { }
433 };
434
435 MODULE_DEVICE_TABLE(of, rcar_du_of_table);
436
437 /* -----------------------------------------------------------------------------
438  * DRM operations
439  */
440
441 DEFINE_DRM_GEM_CMA_FOPS(rcar_du_fops);
442
443 static struct drm_driver rcar_du_driver = {
444         .driver_features        = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME
445                                 | DRIVER_ATOMIC,
446         .gem_free_object_unlocked = drm_gem_cma_free_object,
447         .gem_vm_ops             = &drm_gem_cma_vm_ops,
448         .prime_handle_to_fd     = drm_gem_prime_handle_to_fd,
449         .prime_fd_to_handle     = drm_gem_prime_fd_to_handle,
450         .gem_prime_import       = drm_gem_prime_import,
451         .gem_prime_export       = drm_gem_prime_export,
452         .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
453         .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
454         .gem_prime_vmap         = drm_gem_cma_prime_vmap,
455         .gem_prime_vunmap       = drm_gem_cma_prime_vunmap,
456         .gem_prime_mmap         = drm_gem_cma_prime_mmap,
457         .dumb_create            = rcar_du_dumb_create,
458         .fops                   = &rcar_du_fops,
459         .name                   = "rcar-du",
460         .desc                   = "Renesas R-Car Display Unit",
461         .date                   = "20130110",
462         .major                  = 1,
463         .minor                  = 0,
464 };
465
466 /* -----------------------------------------------------------------------------
467  * Power management
468  */
469
470 #ifdef CONFIG_PM_SLEEP
471 static int rcar_du_pm_suspend(struct device *dev)
472 {
473         struct rcar_du_device *rcdu = dev_get_drvdata(dev);
474
475         return drm_mode_config_helper_suspend(rcdu->ddev);
476 }
477
478 static int rcar_du_pm_resume(struct device *dev)
479 {
480         struct rcar_du_device *rcdu = dev_get_drvdata(dev);
481
482         return drm_mode_config_helper_resume(rcdu->ddev);
483 }
484 #endif
485
486 static const struct dev_pm_ops rcar_du_pm_ops = {
487         SET_SYSTEM_SLEEP_PM_OPS(rcar_du_pm_suspend, rcar_du_pm_resume)
488 };
489
490 /* -----------------------------------------------------------------------------
491  * Platform driver
492  */
493
494 static int rcar_du_remove(struct platform_device *pdev)
495 {
496         struct rcar_du_device *rcdu = platform_get_drvdata(pdev);
497         struct drm_device *ddev = rcdu->ddev;
498
499         drm_dev_unregister(ddev);
500
501         drm_kms_helper_poll_fini(ddev);
502         drm_mode_config_cleanup(ddev);
503
504         drm_dev_put(ddev);
505
506         return 0;
507 }
508
509 static int rcar_du_probe(struct platform_device *pdev)
510 {
511         struct rcar_du_device *rcdu;
512         struct drm_device *ddev;
513         struct resource *mem;
514         int ret;
515
516         /* Allocate and initialize the R-Car device structure. */
517         rcdu = devm_kzalloc(&pdev->dev, sizeof(*rcdu), GFP_KERNEL);
518         if (rcdu == NULL)
519                 return -ENOMEM;
520
521         rcdu->dev = &pdev->dev;
522         rcdu->info = of_device_get_match_data(rcdu->dev);
523
524         platform_set_drvdata(pdev, rcdu);
525
526         /* I/O resources */
527         mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
528         rcdu->mmio = devm_ioremap_resource(&pdev->dev, mem);
529         if (IS_ERR(rcdu->mmio))
530                 return PTR_ERR(rcdu->mmio);
531
532         /* DRM/KMS objects */
533         ddev = drm_dev_alloc(&rcar_du_driver, &pdev->dev);
534         if (IS_ERR(ddev))
535                 return PTR_ERR(ddev);
536
537         rcdu->ddev = ddev;
538         ddev->dev_private = rcdu;
539
540         ret = rcar_du_modeset_init(rcdu);
541         if (ret < 0) {
542                 if (ret != -EPROBE_DEFER)
543                         dev_err(&pdev->dev,
544                                 "failed to initialize DRM/KMS (%d)\n", ret);
545                 goto error;
546         }
547
548         ddev->irq_enabled = 1;
549
550         /*
551          * Register the DRM device with the core and the connectors with
552          * sysfs.
553          */
554         ret = drm_dev_register(ddev, 0);
555         if (ret)
556                 goto error;
557
558         DRM_INFO("Device %s probed\n", dev_name(&pdev->dev));
559
560         drm_fbdev_generic_setup(ddev, 32);
561
562         return 0;
563
564 error:
565         rcar_du_remove(pdev);
566
567         return ret;
568 }
569
570 static struct platform_driver rcar_du_platform_driver = {
571         .probe          = rcar_du_probe,
572         .remove         = rcar_du_remove,
573         .driver         = {
574                 .name   = "rcar-du",
575                 .pm     = &rcar_du_pm_ops,
576                 .of_match_table = rcar_du_of_table,
577         },
578 };
579
580 static int __init rcar_du_init(void)
581 {
582         rcar_du_of_init(rcar_du_of_table);
583
584         return platform_driver_register(&rcar_du_platform_driver);
585 }
586 module_init(rcar_du_init);
587
588 static void __exit rcar_du_exit(void)
589 {
590         platform_driver_unregister(&rcar_du_platform_driver);
591 }
592 module_exit(rcar_du_exit);
593
594 MODULE_AUTHOR("Laurent Pinchart <[email protected]>");
595 MODULE_DESCRIPTION("Renesas R-Car Display Unit DRM Driver");
596 MODULE_LICENSE("GPL");
This page took 0.062169 seconds and 4 git commands to generate.