0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/clk.h>
0011 #include <linux/dma-mapping.h>
0012 #include <linux/io.h>
0013 #include <linux/mm.h>
0014 #include <linux/module.h>
0015 #include <linux/of_device.h>
0016 #include <linux/platform_device.h>
0017 #include <linux/pm.h>
0018 #include <linux/slab.h>
0019 #include <linux/wait.h>
0020
0021 #include <drm/drm_atomic_helper.h>
0022 #include <drm/drm_drv.h>
0023 #include <drm/drm_fb_cma_helper.h>
0024 #include <drm/drm_fb_helper.h>
0025 #include <drm/drm_gem_cma_helper.h>
0026 #include <drm/drm_managed.h>
0027 #include <drm/drm_probe_helper.h>
0028
0029 #include "rcar_du_drv.h"
0030 #include "rcar_du_kms.h"
0031 #include "rcar_du_regs.h"
0032
0033
0034
0035
0036
0037 static const struct rcar_du_device_info rzg1_du_r8a7743_info = {
0038 .gen = 2,
0039 .features = RCAR_DU_FEATURE_CRTC_IRQ
0040 | RCAR_DU_FEATURE_CRTC_CLOCK
0041 | RCAR_DU_FEATURE_INTERLACED
0042 | RCAR_DU_FEATURE_TVM_SYNC,
0043 .channels_mask = BIT(1) | BIT(0),
0044 .routes = {
0045
0046
0047
0048 [RCAR_DU_OUTPUT_DPAD0] = {
0049 .possible_crtcs = BIT(1) | BIT(0),
0050 .port = 0,
0051 },
0052 [RCAR_DU_OUTPUT_LVDS0] = {
0053 .possible_crtcs = BIT(0),
0054 .port = 1,
0055 },
0056 },
0057 .num_lvds = 1,
0058 .num_rpf = 4,
0059 };
0060
0061 static const struct rcar_du_device_info rzg1_du_r8a7745_info = {
0062 .gen = 2,
0063 .features = RCAR_DU_FEATURE_CRTC_IRQ
0064 | RCAR_DU_FEATURE_CRTC_CLOCK
0065 | RCAR_DU_FEATURE_INTERLACED
0066 | RCAR_DU_FEATURE_TVM_SYNC,
0067 .channels_mask = BIT(1) | BIT(0),
0068 .routes = {
0069
0070
0071
0072 [RCAR_DU_OUTPUT_DPAD0] = {
0073 .possible_crtcs = BIT(0),
0074 .port = 0,
0075 },
0076 [RCAR_DU_OUTPUT_DPAD1] = {
0077 .possible_crtcs = BIT(1),
0078 .port = 1,
0079 },
0080 },
0081 .num_rpf = 4,
0082 };
0083
0084 static const struct rcar_du_device_info rzg1_du_r8a77470_info = {
0085 .gen = 2,
0086 .features = RCAR_DU_FEATURE_CRTC_IRQ
0087 | RCAR_DU_FEATURE_CRTC_CLOCK
0088 | RCAR_DU_FEATURE_INTERLACED
0089 | RCAR_DU_FEATURE_TVM_SYNC,
0090 .channels_mask = BIT(1) | BIT(0),
0091 .routes = {
0092
0093
0094
0095
0096 [RCAR_DU_OUTPUT_DPAD0] = {
0097 .possible_crtcs = BIT(0),
0098 .port = 0,
0099 },
0100 [RCAR_DU_OUTPUT_DPAD1] = {
0101 .possible_crtcs = BIT(1),
0102 .port = 1,
0103 },
0104 [RCAR_DU_OUTPUT_LVDS0] = {
0105 .possible_crtcs = BIT(0) | BIT(1),
0106 .port = 2,
0107 },
0108 },
0109 .num_rpf = 4,
0110 };
0111
0112 static const struct rcar_du_device_info rcar_du_r8a774a1_info = {
0113 .gen = 3,
0114 .features = RCAR_DU_FEATURE_CRTC_IRQ
0115 | RCAR_DU_FEATURE_CRTC_CLOCK
0116 | RCAR_DU_FEATURE_VSP1_SOURCE
0117 | RCAR_DU_FEATURE_INTERLACED
0118 | RCAR_DU_FEATURE_TVM_SYNC,
0119 .channels_mask = BIT(2) | BIT(1) | BIT(0),
0120 .routes = {
0121
0122
0123
0124
0125 [RCAR_DU_OUTPUT_DPAD0] = {
0126 .possible_crtcs = BIT(2),
0127 .port = 0,
0128 },
0129 [RCAR_DU_OUTPUT_HDMI0] = {
0130 .possible_crtcs = BIT(1),
0131 .port = 1,
0132 },
0133 [RCAR_DU_OUTPUT_LVDS0] = {
0134 .possible_crtcs = BIT(0),
0135 .port = 2,
0136 },
0137 },
0138 .num_lvds = 1,
0139 .num_rpf = 5,
0140 .dpll_mask = BIT(1),
0141 };
0142
0143 static const struct rcar_du_device_info rcar_du_r8a774b1_info = {
0144 .gen = 3,
0145 .features = RCAR_DU_FEATURE_CRTC_IRQ
0146 | RCAR_DU_FEATURE_CRTC_CLOCK
0147 | RCAR_DU_FEATURE_VSP1_SOURCE
0148 | RCAR_DU_FEATURE_INTERLACED
0149 | RCAR_DU_FEATURE_TVM_SYNC,
0150 .channels_mask = BIT(3) | BIT(1) | BIT(0),
0151 .routes = {
0152
0153
0154
0155
0156 [RCAR_DU_OUTPUT_DPAD0] = {
0157 .possible_crtcs = BIT(2),
0158 .port = 0,
0159 },
0160 [RCAR_DU_OUTPUT_HDMI0] = {
0161 .possible_crtcs = BIT(1),
0162 .port = 1,
0163 },
0164 [RCAR_DU_OUTPUT_LVDS0] = {
0165 .possible_crtcs = BIT(0),
0166 .port = 2,
0167 },
0168 },
0169 .num_lvds = 1,
0170 .num_rpf = 5,
0171 .dpll_mask = BIT(1),
0172 };
0173
0174 static const struct rcar_du_device_info rcar_du_r8a774c0_info = {
0175 .gen = 3,
0176 .features = RCAR_DU_FEATURE_CRTC_IRQ
0177 | RCAR_DU_FEATURE_CRTC_CLOCK
0178 | RCAR_DU_FEATURE_VSP1_SOURCE,
0179 .channels_mask = BIT(1) | BIT(0),
0180 .routes = {
0181
0182
0183
0184 [RCAR_DU_OUTPUT_DPAD0] = {
0185 .possible_crtcs = BIT(0) | BIT(1),
0186 .port = 0,
0187 },
0188 [RCAR_DU_OUTPUT_LVDS0] = {
0189 .possible_crtcs = BIT(0),
0190 .port = 1,
0191 },
0192 [RCAR_DU_OUTPUT_LVDS1] = {
0193 .possible_crtcs = BIT(1),
0194 .port = 2,
0195 },
0196 },
0197 .num_lvds = 2,
0198 .num_rpf = 4,
0199 .lvds_clk_mask = BIT(1) | BIT(0),
0200 };
0201
0202 static const struct rcar_du_device_info rcar_du_r8a774e1_info = {
0203 .gen = 3,
0204 .features = RCAR_DU_FEATURE_CRTC_IRQ
0205 | RCAR_DU_FEATURE_CRTC_CLOCK
0206 | RCAR_DU_FEATURE_VSP1_SOURCE
0207 | RCAR_DU_FEATURE_INTERLACED
0208 | RCAR_DU_FEATURE_TVM_SYNC,
0209 .channels_mask = BIT(3) | BIT(1) | BIT(0),
0210 .routes = {
0211
0212
0213
0214
0215 [RCAR_DU_OUTPUT_DPAD0] = {
0216 .possible_crtcs = BIT(2),
0217 .port = 0,
0218 },
0219 [RCAR_DU_OUTPUT_HDMI0] = {
0220 .possible_crtcs = BIT(1),
0221 .port = 1,
0222 },
0223 [RCAR_DU_OUTPUT_LVDS0] = {
0224 .possible_crtcs = BIT(0),
0225 .port = 2,
0226 },
0227 },
0228 .num_lvds = 1,
0229 .num_rpf = 5,
0230 .dpll_mask = BIT(1),
0231 };
0232
0233 static const struct rcar_du_device_info rcar_du_r8a7779_info = {
0234 .gen = 1,
0235 .features = RCAR_DU_FEATURE_INTERLACED
0236 | RCAR_DU_FEATURE_TVM_SYNC,
0237 .channels_mask = BIT(1) | BIT(0),
0238 .routes = {
0239
0240
0241
0242
0243 [RCAR_DU_OUTPUT_DPAD0] = {
0244 .possible_crtcs = BIT(0),
0245 .port = 0,
0246 },
0247 [RCAR_DU_OUTPUT_DPAD1] = {
0248 .possible_crtcs = BIT(1) | BIT(0),
0249 .port = 1,
0250 },
0251 },
0252 };
0253
0254 static const struct rcar_du_device_info rcar_du_r8a7790_info = {
0255 .gen = 2,
0256 .features = RCAR_DU_FEATURE_CRTC_IRQ
0257 | RCAR_DU_FEATURE_CRTC_CLOCK
0258 | RCAR_DU_FEATURE_INTERLACED
0259 | RCAR_DU_FEATURE_TVM_SYNC,
0260 .quirks = RCAR_DU_QUIRK_ALIGN_128B,
0261 .channels_mask = BIT(2) | BIT(1) | BIT(0),
0262 .routes = {
0263
0264
0265
0266
0267
0268 [RCAR_DU_OUTPUT_DPAD0] = {
0269 .possible_crtcs = BIT(2) | BIT(1) | BIT(0),
0270 .port = 0,
0271 },
0272 [RCAR_DU_OUTPUT_LVDS0] = {
0273 .possible_crtcs = BIT(0),
0274 .port = 1,
0275 },
0276 [RCAR_DU_OUTPUT_LVDS1] = {
0277 .possible_crtcs = BIT(2) | BIT(1),
0278 .port = 2,
0279 },
0280 },
0281 .num_lvds = 2,
0282 .num_rpf = 4,
0283 };
0284
0285
0286 static const struct rcar_du_device_info rcar_du_r8a7791_info = {
0287 .gen = 2,
0288 .features = RCAR_DU_FEATURE_CRTC_IRQ
0289 | RCAR_DU_FEATURE_CRTC_CLOCK
0290 | RCAR_DU_FEATURE_INTERLACED
0291 | RCAR_DU_FEATURE_TVM_SYNC,
0292 .channels_mask = BIT(1) | BIT(0),
0293 .routes = {
0294
0295
0296
0297
0298 [RCAR_DU_OUTPUT_DPAD0] = {
0299 .possible_crtcs = BIT(1) | BIT(0),
0300 .port = 0,
0301 },
0302 [RCAR_DU_OUTPUT_LVDS0] = {
0303 .possible_crtcs = BIT(0),
0304 .port = 1,
0305 },
0306 },
0307 .num_lvds = 1,
0308 .num_rpf = 4,
0309 };
0310
0311 static const struct rcar_du_device_info rcar_du_r8a7792_info = {
0312 .gen = 2,
0313 .features = RCAR_DU_FEATURE_CRTC_IRQ
0314 | RCAR_DU_FEATURE_CRTC_CLOCK
0315 | RCAR_DU_FEATURE_INTERLACED
0316 | RCAR_DU_FEATURE_TVM_SYNC,
0317 .channels_mask = BIT(1) | BIT(0),
0318 .routes = {
0319
0320 [RCAR_DU_OUTPUT_DPAD0] = {
0321 .possible_crtcs = BIT(0),
0322 .port = 0,
0323 },
0324 [RCAR_DU_OUTPUT_DPAD1] = {
0325 .possible_crtcs = BIT(1),
0326 .port = 1,
0327 },
0328 },
0329 .num_rpf = 4,
0330 };
0331
0332 static const struct rcar_du_device_info rcar_du_r8a7794_info = {
0333 .gen = 2,
0334 .features = RCAR_DU_FEATURE_CRTC_IRQ
0335 | RCAR_DU_FEATURE_CRTC_CLOCK
0336 | RCAR_DU_FEATURE_INTERLACED
0337 | RCAR_DU_FEATURE_TVM_SYNC,
0338 .channels_mask = BIT(1) | BIT(0),
0339 .routes = {
0340
0341
0342
0343
0344 [RCAR_DU_OUTPUT_DPAD0] = {
0345 .possible_crtcs = BIT(0),
0346 .port = 0,
0347 },
0348 [RCAR_DU_OUTPUT_DPAD1] = {
0349 .possible_crtcs = BIT(1),
0350 .port = 1,
0351 },
0352 },
0353 .num_rpf = 4,
0354 };
0355
0356 static const struct rcar_du_device_info rcar_du_r8a7795_info = {
0357 .gen = 3,
0358 .features = RCAR_DU_FEATURE_CRTC_IRQ
0359 | RCAR_DU_FEATURE_CRTC_CLOCK
0360 | RCAR_DU_FEATURE_VSP1_SOURCE
0361 | RCAR_DU_FEATURE_INTERLACED
0362 | RCAR_DU_FEATURE_TVM_SYNC,
0363 .channels_mask = BIT(3) | BIT(2) | BIT(1) | BIT(0),
0364 .routes = {
0365
0366
0367
0368
0369 [RCAR_DU_OUTPUT_DPAD0] = {
0370 .possible_crtcs = BIT(3),
0371 .port = 0,
0372 },
0373 [RCAR_DU_OUTPUT_HDMI0] = {
0374 .possible_crtcs = BIT(1),
0375 .port = 1,
0376 },
0377 [RCAR_DU_OUTPUT_HDMI1] = {
0378 .possible_crtcs = BIT(2),
0379 .port = 2,
0380 },
0381 [RCAR_DU_OUTPUT_LVDS0] = {
0382 .possible_crtcs = BIT(0),
0383 .port = 3,
0384 },
0385 },
0386 .num_lvds = 1,
0387 .num_rpf = 5,
0388 .dpll_mask = BIT(2) | BIT(1),
0389 };
0390
0391 static const struct rcar_du_device_info rcar_du_r8a7796_info = {
0392 .gen = 3,
0393 .features = RCAR_DU_FEATURE_CRTC_IRQ
0394 | RCAR_DU_FEATURE_CRTC_CLOCK
0395 | RCAR_DU_FEATURE_VSP1_SOURCE
0396 | RCAR_DU_FEATURE_INTERLACED
0397 | RCAR_DU_FEATURE_TVM_SYNC,
0398 .channels_mask = BIT(2) | BIT(1) | BIT(0),
0399 .routes = {
0400
0401
0402
0403
0404 [RCAR_DU_OUTPUT_DPAD0] = {
0405 .possible_crtcs = BIT(2),
0406 .port = 0,
0407 },
0408 [RCAR_DU_OUTPUT_HDMI0] = {
0409 .possible_crtcs = BIT(1),
0410 .port = 1,
0411 },
0412 [RCAR_DU_OUTPUT_LVDS0] = {
0413 .possible_crtcs = BIT(0),
0414 .port = 2,
0415 },
0416 },
0417 .num_lvds = 1,
0418 .num_rpf = 5,
0419 .dpll_mask = BIT(1),
0420 };
0421
0422 static const struct rcar_du_device_info rcar_du_r8a77965_info = {
0423 .gen = 3,
0424 .features = RCAR_DU_FEATURE_CRTC_IRQ
0425 | RCAR_DU_FEATURE_CRTC_CLOCK
0426 | RCAR_DU_FEATURE_VSP1_SOURCE
0427 | RCAR_DU_FEATURE_INTERLACED
0428 | RCAR_DU_FEATURE_TVM_SYNC,
0429 .channels_mask = BIT(3) | BIT(1) | BIT(0),
0430 .routes = {
0431
0432
0433
0434
0435 [RCAR_DU_OUTPUT_DPAD0] = {
0436 .possible_crtcs = BIT(2),
0437 .port = 0,
0438 },
0439 [RCAR_DU_OUTPUT_HDMI0] = {
0440 .possible_crtcs = BIT(1),
0441 .port = 1,
0442 },
0443 [RCAR_DU_OUTPUT_LVDS0] = {
0444 .possible_crtcs = BIT(0),
0445 .port = 2,
0446 },
0447 },
0448 .num_lvds = 1,
0449 .num_rpf = 5,
0450 .dpll_mask = BIT(1),
0451 };
0452
0453 static const struct rcar_du_device_info rcar_du_r8a77970_info = {
0454 .gen = 3,
0455 .features = RCAR_DU_FEATURE_CRTC_IRQ
0456 | RCAR_DU_FEATURE_CRTC_CLOCK
0457 | RCAR_DU_FEATURE_VSP1_SOURCE
0458 | RCAR_DU_FEATURE_INTERLACED
0459 | RCAR_DU_FEATURE_TVM_SYNC,
0460 .channels_mask = BIT(0),
0461 .routes = {
0462
0463
0464
0465
0466 [RCAR_DU_OUTPUT_DPAD0] = {
0467 .possible_crtcs = BIT(0),
0468 .port = 0,
0469 },
0470 [RCAR_DU_OUTPUT_LVDS0] = {
0471 .possible_crtcs = BIT(0),
0472 .port = 1,
0473 },
0474 },
0475 .num_lvds = 1,
0476 .num_rpf = 5,
0477 };
0478
0479 static const struct rcar_du_device_info rcar_du_r8a7799x_info = {
0480 .gen = 3,
0481 .features = RCAR_DU_FEATURE_CRTC_IRQ
0482 | RCAR_DU_FEATURE_CRTC_CLOCK
0483 | RCAR_DU_FEATURE_VSP1_SOURCE,
0484 .channels_mask = BIT(1) | BIT(0),
0485 .routes = {
0486
0487
0488
0489
0490 [RCAR_DU_OUTPUT_DPAD0] = {
0491 .possible_crtcs = BIT(0) | BIT(1),
0492 .port = 0,
0493 },
0494 [RCAR_DU_OUTPUT_LVDS0] = {
0495 .possible_crtcs = BIT(0),
0496 .port = 1,
0497 },
0498 [RCAR_DU_OUTPUT_LVDS1] = {
0499 .possible_crtcs = BIT(1),
0500 .port = 2,
0501 },
0502 },
0503 .num_lvds = 2,
0504 .num_rpf = 5,
0505 .lvds_clk_mask = BIT(1) | BIT(0),
0506 };
0507
0508 static const struct rcar_du_device_info rcar_du_r8a779a0_info = {
0509 .gen = 3,
0510 .features = RCAR_DU_FEATURE_CRTC_IRQ
0511 | RCAR_DU_FEATURE_VSP1_SOURCE,
0512 .channels_mask = BIT(1) | BIT(0),
0513 .routes = {
0514
0515 [RCAR_DU_OUTPUT_DSI0] = {
0516 .possible_crtcs = BIT(0),
0517 .port = 0,
0518 },
0519 [RCAR_DU_OUTPUT_DSI1] = {
0520 .possible_crtcs = BIT(1),
0521 .port = 1,
0522 },
0523 },
0524 .num_rpf = 5,
0525 .dsi_clk_mask = BIT(1) | BIT(0),
0526 };
0527
0528 static const struct of_device_id rcar_du_of_table[] = {
0529 { .compatible = "renesas,du-r8a7742", .data = &rcar_du_r8a7790_info },
0530 { .compatible = "renesas,du-r8a7743", .data = &rzg1_du_r8a7743_info },
0531 { .compatible = "renesas,du-r8a7744", .data = &rzg1_du_r8a7743_info },
0532 { .compatible = "renesas,du-r8a7745", .data = &rzg1_du_r8a7745_info },
0533 { .compatible = "renesas,du-r8a77470", .data = &rzg1_du_r8a77470_info },
0534 { .compatible = "renesas,du-r8a774a1", .data = &rcar_du_r8a774a1_info },
0535 { .compatible = "renesas,du-r8a774b1", .data = &rcar_du_r8a774b1_info },
0536 { .compatible = "renesas,du-r8a774c0", .data = &rcar_du_r8a774c0_info },
0537 { .compatible = "renesas,du-r8a774e1", .data = &rcar_du_r8a774e1_info },
0538 { .compatible = "renesas,du-r8a7779", .data = &rcar_du_r8a7779_info },
0539 { .compatible = "renesas,du-r8a7790", .data = &rcar_du_r8a7790_info },
0540 { .compatible = "renesas,du-r8a7791", .data = &rcar_du_r8a7791_info },
0541 { .compatible = "renesas,du-r8a7792", .data = &rcar_du_r8a7792_info },
0542 { .compatible = "renesas,du-r8a7793", .data = &rcar_du_r8a7791_info },
0543 { .compatible = "renesas,du-r8a7794", .data = &rcar_du_r8a7794_info },
0544 { .compatible = "renesas,du-r8a7795", .data = &rcar_du_r8a7795_info },
0545 { .compatible = "renesas,du-r8a7796", .data = &rcar_du_r8a7796_info },
0546 { .compatible = "renesas,du-r8a77961", .data = &rcar_du_r8a7796_info },
0547 { .compatible = "renesas,du-r8a77965", .data = &rcar_du_r8a77965_info },
0548 { .compatible = "renesas,du-r8a77970", .data = &rcar_du_r8a77970_info },
0549 { .compatible = "renesas,du-r8a77980", .data = &rcar_du_r8a77970_info },
0550 { .compatible = "renesas,du-r8a77990", .data = &rcar_du_r8a7799x_info },
0551 { .compatible = "renesas,du-r8a77995", .data = &rcar_du_r8a7799x_info },
0552 { .compatible = "renesas,du-r8a779a0", .data = &rcar_du_r8a779a0_info },
0553 { }
0554 };
0555
0556 MODULE_DEVICE_TABLE(of, rcar_du_of_table);
0557
0558 const char *rcar_du_output_name(enum rcar_du_output output)
0559 {
0560 static const char * const names[] = {
0561 [RCAR_DU_OUTPUT_DPAD0] = "DPAD0",
0562 [RCAR_DU_OUTPUT_DPAD1] = "DPAD1",
0563 [RCAR_DU_OUTPUT_DSI0] = "DSI0",
0564 [RCAR_DU_OUTPUT_DSI1] = "DSI1",
0565 [RCAR_DU_OUTPUT_HDMI0] = "HDMI0",
0566 [RCAR_DU_OUTPUT_HDMI1] = "HDMI1",
0567 [RCAR_DU_OUTPUT_LVDS0] = "LVDS0",
0568 [RCAR_DU_OUTPUT_LVDS1] = "LVDS1",
0569 [RCAR_DU_OUTPUT_TCON] = "TCON",
0570 };
0571
0572 if (output >= ARRAY_SIZE(names) || !names[output])
0573 return "UNKNOWN";
0574
0575 return names[output];
0576 }
0577
0578
0579
0580
0581
0582 DEFINE_DRM_GEM_CMA_FOPS(rcar_du_fops);
0583
0584 static const struct drm_driver rcar_du_driver = {
0585 .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
0586 .dumb_create = rcar_du_dumb_create,
0587 .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
0588 .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
0589 .gem_prime_import_sg_table = rcar_du_gem_prime_import_sg_table,
0590 .gem_prime_mmap = drm_gem_prime_mmap,
0591 .fops = &rcar_du_fops,
0592 .name = "rcar-du",
0593 .desc = "Renesas R-Car Display Unit",
0594 .date = "20130110",
0595 .major = 1,
0596 .minor = 0,
0597 };
0598
0599
0600
0601
0602
0603 #ifdef CONFIG_PM_SLEEP
0604 static int rcar_du_pm_suspend(struct device *dev)
0605 {
0606 struct rcar_du_device *rcdu = dev_get_drvdata(dev);
0607
0608 return drm_mode_config_helper_suspend(&rcdu->ddev);
0609 }
0610
0611 static int rcar_du_pm_resume(struct device *dev)
0612 {
0613 struct rcar_du_device *rcdu = dev_get_drvdata(dev);
0614
0615 return drm_mode_config_helper_resume(&rcdu->ddev);
0616 }
0617 #endif
0618
0619 static const struct dev_pm_ops rcar_du_pm_ops = {
0620 SET_SYSTEM_SLEEP_PM_OPS(rcar_du_pm_suspend, rcar_du_pm_resume)
0621 };
0622
0623
0624
0625
0626
0627 static int rcar_du_remove(struct platform_device *pdev)
0628 {
0629 struct rcar_du_device *rcdu = platform_get_drvdata(pdev);
0630 struct drm_device *ddev = &rcdu->ddev;
0631
0632 drm_dev_unregister(ddev);
0633 drm_atomic_helper_shutdown(ddev);
0634
0635 drm_kms_helper_poll_fini(ddev);
0636
0637 return 0;
0638 }
0639
0640 static void rcar_du_shutdown(struct platform_device *pdev)
0641 {
0642 struct rcar_du_device *rcdu = platform_get_drvdata(pdev);
0643
0644 drm_atomic_helper_shutdown(&rcdu->ddev);
0645 }
0646
0647 static int rcar_du_probe(struct platform_device *pdev)
0648 {
0649 struct rcar_du_device *rcdu;
0650 unsigned int mask;
0651 int ret;
0652
0653 if (drm_firmware_drivers_only())
0654 return -ENODEV;
0655
0656
0657 rcdu = devm_drm_dev_alloc(&pdev->dev, &rcar_du_driver,
0658 struct rcar_du_device, ddev);
0659 if (IS_ERR(rcdu))
0660 return PTR_ERR(rcdu);
0661
0662 rcdu->dev = &pdev->dev;
0663 rcdu->info = of_device_get_match_data(rcdu->dev);
0664
0665 platform_set_drvdata(pdev, rcdu);
0666
0667
0668 rcdu->mmio = devm_platform_ioremap_resource(pdev, 0);
0669 if (IS_ERR(rcdu->mmio))
0670 return PTR_ERR(rcdu->mmio);
0671
0672
0673
0674
0675
0676
0677 mask = rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE) ? 40 : 32;
0678 ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(mask));
0679 if (ret)
0680 return ret;
0681
0682
0683 ret = rcar_du_modeset_init(rcdu);
0684 if (ret < 0) {
0685 if (ret != -EPROBE_DEFER)
0686 dev_err(&pdev->dev,
0687 "failed to initialize DRM/KMS (%d)\n", ret);
0688 goto error;
0689 }
0690
0691
0692
0693
0694
0695 ret = drm_dev_register(&rcdu->ddev, 0);
0696 if (ret)
0697 goto error;
0698
0699 DRM_INFO("Device %s probed\n", dev_name(&pdev->dev));
0700
0701 drm_fbdev_generic_setup(&rcdu->ddev, 32);
0702
0703 return 0;
0704
0705 error:
0706 drm_kms_helper_poll_fini(&rcdu->ddev);
0707 return ret;
0708 }
0709
0710 static struct platform_driver rcar_du_platform_driver = {
0711 .probe = rcar_du_probe,
0712 .remove = rcar_du_remove,
0713 .shutdown = rcar_du_shutdown,
0714 .driver = {
0715 .name = "rcar-du",
0716 .pm = &rcar_du_pm_ops,
0717 .of_match_table = rcar_du_of_table,
0718 },
0719 };
0720
0721 module_platform_driver(rcar_du_platform_driver);
0722
0723 MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
0724 MODULE_DESCRIPTION("Renesas R-Car Display Unit DRM Driver");
0725 MODULE_LICENSE("GPL");