linux/drivers/gpu/drm/rcar-du/rcar_du_kms.c
<<
>>
Prefs
   1/*
   2 * rcar_du_kms.c  --  R-Car Display Unit Mode Setting
   3 *
   4 * Copyright (C) 2013-2015 Renesas Electronics Corporation
   5 *
   6 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License as published by
  10 * the Free Software Foundation; either version 2 of the License, or
  11 * (at your option) any later version.
  12 */
  13
  14#include <drm/drmP.h>
  15#include <drm/drm_atomic.h>
  16#include <drm/drm_atomic_helper.h>
  17#include <drm/drm_crtc.h>
  18#include <drm/drm_crtc_helper.h>
  19#include <drm/drm_fb_cma_helper.h>
  20#include <drm/drm_gem_cma_helper.h>
  21
  22#include <linux/of_graph.h>
  23#include <linux/wait.h>
  24
  25#include "rcar_du_crtc.h"
  26#include "rcar_du_drv.h"
  27#include "rcar_du_encoder.h"
  28#include "rcar_du_kms.h"
  29#include "rcar_du_lvdsenc.h"
  30#include "rcar_du_regs.h"
  31#include "rcar_du_vsp.h"
  32
  33/* -----------------------------------------------------------------------------
  34 * Format helpers
  35 */
  36
  37static const struct rcar_du_format_info rcar_du_format_infos[] = {
  38        {
  39                .fourcc = DRM_FORMAT_RGB565,
  40                .bpp = 16,
  41                .planes = 1,
  42                .pnmr = PnMR_SPIM_TP | PnMR_DDDF_16BPP,
  43                .edf = PnDDCR4_EDF_NONE,
  44        }, {
  45                .fourcc = DRM_FORMAT_ARGB1555,
  46                .bpp = 16,
  47                .planes = 1,
  48                .pnmr = PnMR_SPIM_ALP | PnMR_DDDF_ARGB,
  49                .edf = PnDDCR4_EDF_NONE,
  50        }, {
  51                .fourcc = DRM_FORMAT_XRGB1555,
  52                .bpp = 16,
  53                .planes = 1,
  54                .pnmr = PnMR_SPIM_ALP | PnMR_DDDF_ARGB,
  55                .edf = PnDDCR4_EDF_NONE,
  56        }, {
  57                .fourcc = DRM_FORMAT_XRGB8888,
  58                .bpp = 32,
  59                .planes = 1,
  60                .pnmr = PnMR_SPIM_TP | PnMR_DDDF_16BPP,
  61                .edf = PnDDCR4_EDF_RGB888,
  62        }, {
  63                .fourcc = DRM_FORMAT_ARGB8888,
  64                .bpp = 32,
  65                .planes = 1,
  66                .pnmr = PnMR_SPIM_ALP | PnMR_DDDF_16BPP,
  67                .edf = PnDDCR4_EDF_ARGB8888,
  68        }, {
  69                .fourcc = DRM_FORMAT_UYVY,
  70                .bpp = 16,
  71                .planes = 1,
  72                .pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC,
  73                .edf = PnDDCR4_EDF_NONE,
  74        }, {
  75                .fourcc = DRM_FORMAT_YUYV,
  76                .bpp = 16,
  77                .planes = 1,
  78                .pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC,
  79                .edf = PnDDCR4_EDF_NONE,
  80        }, {
  81                .fourcc = DRM_FORMAT_NV12,
  82                .bpp = 12,
  83                .planes = 2,
  84                .pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC,
  85                .edf = PnDDCR4_EDF_NONE,
  86        }, {
  87                .fourcc = DRM_FORMAT_NV21,
  88                .bpp = 12,
  89                .planes = 2,
  90                .pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC,
  91                .edf = PnDDCR4_EDF_NONE,
  92        }, {
  93                .fourcc = DRM_FORMAT_NV16,
  94                .bpp = 16,
  95                .planes = 2,
  96                .pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC,
  97                .edf = PnDDCR4_EDF_NONE,
  98        },
  99        /* The following formats are not supported on Gen2 and thus have no
 100         * associated .pnmr or .edf settings.
 101         */
 102        {
 103                .fourcc = DRM_FORMAT_NV61,
 104                .bpp = 16,
 105                .planes = 2,
 106        }, {
 107                .fourcc = DRM_FORMAT_YUV420,
 108                .bpp = 12,
 109                .planes = 3,
 110        }, {
 111                .fourcc = DRM_FORMAT_YVU420,
 112                .bpp = 12,
 113                .planes = 3,
 114        }, {
 115                .fourcc = DRM_FORMAT_YUV422,
 116                .bpp = 16,
 117                .planes = 3,
 118        }, {
 119                .fourcc = DRM_FORMAT_YVU422,
 120                .bpp = 16,
 121                .planes = 3,
 122        }, {
 123                .fourcc = DRM_FORMAT_YUV444,
 124                .bpp = 24,
 125                .planes = 3,
 126        }, {
 127                .fourcc = DRM_FORMAT_YVU444,
 128                .bpp = 24,
 129                .planes = 3,
 130        },
 131};
 132
 133const struct rcar_du_format_info *rcar_du_format_info(u32 fourcc)
 134{
 135        unsigned int i;
 136
 137        for (i = 0; i < ARRAY_SIZE(rcar_du_format_infos); ++i) {
 138                if (rcar_du_format_infos[i].fourcc == fourcc)
 139                        return &rcar_du_format_infos[i];
 140        }
 141
 142        return NULL;
 143}
 144
 145/* -----------------------------------------------------------------------------
 146 * Frame buffer
 147 */
 148
 149int rcar_du_dumb_create(struct drm_file *file, struct drm_device *dev,
 150                        struct drm_mode_create_dumb *args)
 151{
 152        struct rcar_du_device *rcdu = dev->dev_private;
 153        unsigned int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
 154        unsigned int align;
 155
 156        /* The R8A7779 DU requires a 16 pixels pitch alignment as documented,
 157         * but the R8A7790 DU seems to require a 128 bytes pitch alignment.
 158         */
 159        if (rcar_du_needs(rcdu, RCAR_DU_QUIRK_ALIGN_128B))
 160                align = 128;
 161        else
 162                align = 16 * args->bpp / 8;
 163
 164        args->pitch = roundup(min_pitch, align);
 165
 166        return drm_gem_cma_dumb_create_internal(file, dev, args);
 167}
 168
 169static struct drm_framebuffer *
 170rcar_du_fb_create(struct drm_device *dev, struct drm_file *file_priv,
 171                  const struct drm_mode_fb_cmd2 *mode_cmd)
 172{
 173        struct rcar_du_device *rcdu = dev->dev_private;
 174        const struct rcar_du_format_info *format;
 175        unsigned int max_pitch;
 176        unsigned int align;
 177        unsigned int bpp;
 178        unsigned int i;
 179
 180        format = rcar_du_format_info(mode_cmd->pixel_format);
 181        if (format == NULL) {
 182                dev_dbg(dev->dev, "unsupported pixel format %08x\n",
 183                        mode_cmd->pixel_format);
 184                return ERR_PTR(-EINVAL);
 185        }
 186
 187        /*
 188         * The pitch and alignment constraints are expressed in pixels on the
 189         * hardware side and in bytes in the DRM API.
 190         */
 191        bpp = format->planes == 1 ? format->bpp / 8 : 1;
 192        max_pitch =  4096 * bpp;
 193
 194        if (rcar_du_needs(rcdu, RCAR_DU_QUIRK_ALIGN_128B))
 195                align = 128;
 196        else
 197                align = 16 * bpp;
 198
 199        if (mode_cmd->pitches[0] & (align - 1) ||
 200            mode_cmd->pitches[0] >= max_pitch) {
 201                dev_dbg(dev->dev, "invalid pitch value %u\n",
 202                        mode_cmd->pitches[0]);
 203                return ERR_PTR(-EINVAL);
 204        }
 205
 206        for (i = 1; i < format->planes; ++i) {
 207                if (mode_cmd->pitches[i] != mode_cmd->pitches[0]) {
 208                        dev_dbg(dev->dev,
 209                                "luma and chroma pitches do not match\n");
 210                        return ERR_PTR(-EINVAL);
 211                }
 212        }
 213
 214        return drm_fb_cma_create(dev, file_priv, mode_cmd);
 215}
 216
 217static void rcar_du_output_poll_changed(struct drm_device *dev)
 218{
 219        struct rcar_du_device *rcdu = dev->dev_private;
 220
 221        drm_fbdev_cma_hotplug_event(rcdu->fbdev);
 222}
 223
 224/* -----------------------------------------------------------------------------
 225 * Atomic Check and Update
 226 */
 227
 228static int rcar_du_atomic_check(struct drm_device *dev,
 229                                struct drm_atomic_state *state)
 230{
 231        struct rcar_du_device *rcdu = dev->dev_private;
 232        int ret;
 233
 234        ret = drm_atomic_helper_check_modeset(dev, state);
 235        if (ret)
 236                return ret;
 237
 238        ret = drm_atomic_normalize_zpos(dev, state);
 239        if (ret)
 240                return ret;
 241
 242        ret = drm_atomic_helper_check_planes(dev, state);
 243        if (ret)
 244                return ret;
 245
 246        if (rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE))
 247                return 0;
 248
 249        return rcar_du_atomic_check_planes(dev, state);
 250}
 251
 252struct rcar_du_commit {
 253        struct work_struct work;
 254        struct drm_device *dev;
 255        struct drm_atomic_state *state;
 256        u32 crtcs;
 257};
 258
 259static void rcar_du_atomic_complete(struct rcar_du_commit *commit)
 260{
 261        struct drm_device *dev = commit->dev;
 262        struct rcar_du_device *rcdu = dev->dev_private;
 263        struct drm_atomic_state *old_state = commit->state;
 264
 265        /* Apply the atomic update. */
 266        drm_atomic_helper_commit_modeset_disables(dev, old_state);
 267        drm_atomic_helper_commit_modeset_enables(dev, old_state);
 268        drm_atomic_helper_commit_planes(dev, old_state,
 269                                        DRM_PLANE_COMMIT_ACTIVE_ONLY);
 270
 271        drm_atomic_helper_wait_for_vblanks(dev, old_state);
 272
 273        drm_atomic_helper_cleanup_planes(dev, old_state);
 274
 275        drm_atomic_state_put(old_state);
 276
 277        /* Complete the commit, wake up any waiter. */
 278        spin_lock(&rcdu->commit.wait.lock);
 279        rcdu->commit.pending &= ~commit->crtcs;
 280        wake_up_all_locked(&rcdu->commit.wait);
 281        spin_unlock(&rcdu->commit.wait.lock);
 282
 283        kfree(commit);
 284}
 285
 286static void rcar_du_atomic_work(struct work_struct *work)
 287{
 288        struct rcar_du_commit *commit =
 289                container_of(work, struct rcar_du_commit, work);
 290
 291        rcar_du_atomic_complete(commit);
 292}
 293
 294static int rcar_du_atomic_commit(struct drm_device *dev,
 295                                 struct drm_atomic_state *state,
 296                                 bool nonblock)
 297{
 298        struct rcar_du_device *rcdu = dev->dev_private;
 299        struct rcar_du_commit *commit;
 300        struct drm_crtc *crtc;
 301        struct drm_crtc_state *crtc_state;
 302        unsigned int i;
 303        int ret;
 304
 305        ret = drm_atomic_helper_prepare_planes(dev, state);
 306        if (ret)
 307                return ret;
 308
 309        /* Allocate the commit object. */
 310        commit = kzalloc(sizeof(*commit), GFP_KERNEL);
 311        if (commit == NULL) {
 312                ret = -ENOMEM;
 313                goto error;
 314        }
 315
 316        INIT_WORK(&commit->work, rcar_du_atomic_work);
 317        commit->dev = dev;
 318        commit->state = state;
 319
 320        /* Wait until all affected CRTCs have completed previous commits and
 321         * mark them as pending.
 322         */
 323        for_each_crtc_in_state(state, crtc, crtc_state, i)
 324                commit->crtcs |= drm_crtc_mask(crtc);
 325
 326        spin_lock(&rcdu->commit.wait.lock);
 327        ret = wait_event_interruptible_locked(rcdu->commit.wait,
 328                        !(rcdu->commit.pending & commit->crtcs));
 329        if (ret == 0)
 330                rcdu->commit.pending |= commit->crtcs;
 331        spin_unlock(&rcdu->commit.wait.lock);
 332
 333        if (ret) {
 334                kfree(commit);
 335                goto error;
 336        }
 337
 338        /* Swap the state, this is the point of no return. */
 339        drm_atomic_helper_swap_state(state, true);
 340
 341        drm_atomic_state_get(state);
 342        if (nonblock)
 343                schedule_work(&commit->work);
 344        else
 345                rcar_du_atomic_complete(commit);
 346
 347        return 0;
 348
 349error:
 350        drm_atomic_helper_cleanup_planes(dev, state);
 351        return ret;
 352}
 353
 354/* -----------------------------------------------------------------------------
 355 * Initialization
 356 */
 357
 358static const struct drm_mode_config_funcs rcar_du_mode_config_funcs = {
 359        .fb_create = rcar_du_fb_create,
 360        .output_poll_changed = rcar_du_output_poll_changed,
 361        .atomic_check = rcar_du_atomic_check,
 362        .atomic_commit = rcar_du_atomic_commit,
 363};
 364
 365static int rcar_du_encoders_init_one(struct rcar_du_device *rcdu,
 366                                     enum rcar_du_output output,
 367                                     struct of_endpoint *ep)
 368{
 369        static const struct {
 370                const char *compatible;
 371                enum rcar_du_encoder_type type;
 372        } encoders[] = {
 373                { "adi,adv7123", RCAR_DU_ENCODER_VGA },
 374                { "adi,adv7511w", RCAR_DU_ENCODER_HDMI },
 375                { "thine,thc63lvdm83d", RCAR_DU_ENCODER_LVDS },
 376        };
 377
 378        enum rcar_du_encoder_type enc_type = RCAR_DU_ENCODER_NONE;
 379        struct device_node *connector = NULL;
 380        struct device_node *encoder = NULL;
 381        struct device_node *ep_node = NULL;
 382        struct device_node *entity_ep_node;
 383        struct device_node *entity;
 384        int ret;
 385
 386        /*
 387         * Locate the connected entity and infer its type from the number of
 388         * endpoints.
 389         */
 390        entity = of_graph_get_remote_port_parent(ep->local_node);
 391        if (!entity) {
 392                dev_dbg(rcdu->dev, "unconnected endpoint %s, skipping\n",
 393                        ep->local_node->full_name);
 394                return -ENODEV;
 395        }
 396
 397        entity_ep_node = of_parse_phandle(ep->local_node, "remote-endpoint", 0);
 398
 399        for_each_endpoint_of_node(entity, ep_node) {
 400                if (ep_node == entity_ep_node)
 401                        continue;
 402
 403                /*
 404                 * We've found one endpoint other than the input, this must
 405                 * be an encoder. Locate the connector.
 406                 */
 407                encoder = entity;
 408                connector = of_graph_get_remote_port_parent(ep_node);
 409                of_node_put(ep_node);
 410
 411                if (!connector) {
 412                        dev_warn(rcdu->dev,
 413                                 "no connector for encoder %s, skipping\n",
 414                                 encoder->full_name);
 415                        of_node_put(entity_ep_node);
 416                        of_node_put(encoder);
 417                        return -ENODEV;
 418                }
 419
 420                break;
 421        }
 422
 423        of_node_put(entity_ep_node);
 424
 425        if (encoder) {
 426                /*
 427                 * If an encoder has been found, get its type based on its
 428                 * compatible string.
 429                 */
 430                unsigned int i;
 431
 432                for (i = 0; i < ARRAY_SIZE(encoders); ++i) {
 433                        if (of_device_is_compatible(encoder,
 434                                                    encoders[i].compatible)) {
 435                                enc_type = encoders[i].type;
 436                                break;
 437                        }
 438                }
 439
 440                if (i == ARRAY_SIZE(encoders)) {
 441                        dev_warn(rcdu->dev,
 442                                 "unknown encoder type for %s, skipping\n",
 443                                 encoder->full_name);
 444                        of_node_put(encoder);
 445                        of_node_put(connector);
 446                        return -EINVAL;
 447                }
 448        } else {
 449                /*
 450                 * If no encoder has been found the entity must be the
 451                 * connector.
 452                 */
 453                connector = entity;
 454        }
 455
 456        ret = rcar_du_encoder_init(rcdu, enc_type, output, encoder, connector);
 457        if (ret && ret != -EPROBE_DEFER)
 458                dev_warn(rcdu->dev,
 459                         "failed to initialize encoder %s on output %u (%d), skipping\n",
 460                         of_node_full_name(encoder), output, ret);
 461
 462        of_node_put(encoder);
 463        of_node_put(connector);
 464
 465        return ret;
 466}
 467
 468static int rcar_du_encoders_init(struct rcar_du_device *rcdu)
 469{
 470        struct device_node *np = rcdu->dev->of_node;
 471        struct device_node *ep_node;
 472        unsigned int num_encoders = 0;
 473
 474        /*
 475         * Iterate over the endpoints and create one encoder for each output
 476         * pipeline.
 477         */
 478        for_each_endpoint_of_node(np, ep_node) {
 479                enum rcar_du_output output;
 480                struct of_endpoint ep;
 481                unsigned int i;
 482                int ret;
 483
 484                ret = of_graph_parse_endpoint(ep_node, &ep);
 485                if (ret < 0) {
 486                        of_node_put(ep_node);
 487                        return ret;
 488                }
 489
 490                /* Find the output route corresponding to the port number. */
 491                for (i = 0; i < RCAR_DU_OUTPUT_MAX; ++i) {
 492                        if (rcdu->info->routes[i].possible_crtcs &&
 493                            rcdu->info->routes[i].port == ep.port) {
 494                                output = i;
 495                                break;
 496                        }
 497                }
 498
 499                if (i == RCAR_DU_OUTPUT_MAX) {
 500                        dev_warn(rcdu->dev,
 501                                 "port %u references unexisting output, skipping\n",
 502                                 ep.port);
 503                        continue;
 504                }
 505
 506                /* Process the output pipeline. */
 507                ret = rcar_du_encoders_init_one(rcdu, output, &ep);
 508                if (ret < 0) {
 509                        if (ret == -EPROBE_DEFER) {
 510                                of_node_put(ep_node);
 511                                return ret;
 512                        }
 513
 514                        continue;
 515                }
 516
 517                num_encoders++;
 518        }
 519
 520        return num_encoders;
 521}
 522
 523static int rcar_du_properties_init(struct rcar_du_device *rcdu)
 524{
 525        rcdu->props.alpha =
 526                drm_property_create_range(rcdu->ddev, 0, "alpha", 0, 255);
 527        if (rcdu->props.alpha == NULL)
 528                return -ENOMEM;
 529
 530        /* The color key is expressed as an RGB888 triplet stored in a 32-bit
 531         * integer in XRGB8888 format. Bit 24 is used as a flag to disable (0)
 532         * or enable source color keying (1).
 533         */
 534        rcdu->props.colorkey =
 535                drm_property_create_range(rcdu->ddev, 0, "colorkey",
 536                                          0, 0x01ffffff);
 537        if (rcdu->props.colorkey == NULL)
 538                return -ENOMEM;
 539
 540        return 0;
 541}
 542
 543int rcar_du_modeset_init(struct rcar_du_device *rcdu)
 544{
 545        static const unsigned int mmio_offsets[] = {
 546                DU0_REG_OFFSET, DU2_REG_OFFSET
 547        };
 548
 549        struct drm_device *dev = rcdu->ddev;
 550        struct drm_encoder *encoder;
 551        struct drm_fbdev_cma *fbdev;
 552        unsigned int num_encoders;
 553        unsigned int num_groups;
 554        unsigned int i;
 555        int ret;
 556
 557        drm_mode_config_init(dev);
 558
 559        dev->mode_config.min_width = 0;
 560        dev->mode_config.min_height = 0;
 561        dev->mode_config.max_width = 4095;
 562        dev->mode_config.max_height = 2047;
 563        dev->mode_config.funcs = &rcar_du_mode_config_funcs;
 564
 565        rcdu->num_crtcs = rcdu->info->num_crtcs;
 566
 567        ret = rcar_du_properties_init(rcdu);
 568        if (ret < 0)
 569                return ret;
 570
 571        /* Initialize vertical blanking interrupts handling. Start with vblank
 572         * disabled for all CRTCs.
 573         */
 574        ret = drm_vblank_init(dev, (1 << rcdu->info->num_crtcs) - 1);
 575        if (ret < 0)
 576                return ret;
 577
 578        /* Initialize the groups. */
 579        num_groups = DIV_ROUND_UP(rcdu->num_crtcs, 2);
 580
 581        for (i = 0; i < num_groups; ++i) {
 582                struct rcar_du_group *rgrp = &rcdu->groups[i];
 583
 584                mutex_init(&rgrp->lock);
 585
 586                rgrp->dev = rcdu;
 587                rgrp->mmio_offset = mmio_offsets[i];
 588                rgrp->index = i;
 589                rgrp->num_crtcs = min(rcdu->num_crtcs - 2 * i, 2U);
 590
 591                /* If we have more than one CRTCs in this group pre-associate
 592                 * the low-order planes with CRTC 0 and the high-order planes
 593                 * with CRTC 1 to minimize flicker occurring when the
 594                 * association is changed.
 595                 */
 596                rgrp->dptsr_planes = rgrp->num_crtcs > 1
 597                                   ? (rcdu->info->gen >= 3 ? 0x04 : 0xf0)
 598                                   : 0;
 599
 600                if (!rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE)) {
 601                        ret = rcar_du_planes_init(rgrp);
 602                        if (ret < 0)
 603                                return ret;
 604                }
 605        }
 606
 607        /* Initialize the compositors. */
 608        if (rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE)) {
 609                for (i = 0; i < rcdu->num_crtcs; ++i) {
 610                        struct rcar_du_vsp *vsp = &rcdu->vsps[i];
 611
 612                        vsp->index = i;
 613                        vsp->dev = rcdu;
 614                        rcdu->crtcs[i].vsp = vsp;
 615
 616                        ret = rcar_du_vsp_init(vsp);
 617                        if (ret < 0)
 618                                return ret;
 619                }
 620        }
 621
 622        /* Create the CRTCs. */
 623        for (i = 0; i < rcdu->num_crtcs; ++i) {
 624                struct rcar_du_group *rgrp = &rcdu->groups[i / 2];
 625
 626                ret = rcar_du_crtc_create(rgrp, i);
 627                if (ret < 0)
 628                        return ret;
 629        }
 630
 631        /* Initialize the encoders. */
 632        ret = rcar_du_lvdsenc_init(rcdu);
 633        if (ret < 0)
 634                return ret;
 635
 636        ret = rcar_du_encoders_init(rcdu);
 637        if (ret < 0)
 638                return ret;
 639
 640        if (ret == 0) {
 641                dev_err(rcdu->dev, "error: no encoder could be initialized\n");
 642                return -EINVAL;
 643        }
 644
 645        num_encoders = ret;
 646
 647        /* Set the possible CRTCs and possible clones. There's always at least
 648         * one way for all encoders to clone each other, set all bits in the
 649         * possible clones field.
 650         */
 651        list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
 652                struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
 653                const struct rcar_du_output_routing *route =
 654                        &rcdu->info->routes[renc->output];
 655
 656                encoder->possible_crtcs = route->possible_crtcs;
 657                encoder->possible_clones = (1 << num_encoders) - 1;
 658        }
 659
 660        drm_mode_config_reset(dev);
 661
 662        drm_kms_helper_poll_init(dev);
 663
 664        if (dev->mode_config.num_connector) {
 665                fbdev = drm_fbdev_cma_init(dev, 32,
 666                                           dev->mode_config.num_connector);
 667                if (IS_ERR(fbdev))
 668                        return PTR_ERR(fbdev);
 669
 670                rcdu->fbdev = fbdev;
 671        } else {
 672                dev_info(rcdu->dev,
 673                         "no connector found, disabling fbdev emulation\n");
 674        }
 675
 676        return 0;
 677}
 678