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