linux/drivers/gpu/drm/exynos/exynos_drm_vidi.c
<<
>>
Prefs
   1/* exynos_drm_vidi.c
   2 *
   3 * Copyright (C) 2012 Samsung Electronics Co.Ltd
   4 * Authors:
   5 *      Inki Dae <inki.dae@samsung.com>
   6 *
   7 * This program is free software; you can redistribute  it and/or modify it
   8 * under  the terms of  the GNU General  Public License as published by the
   9 * Free Software Foundation;  either version 2 of the  License, or (at your
  10 * option) any later version.
  11 *
  12 */
  13#include <drm/drmP.h>
  14
  15#include <linux/kernel.h>
  16#include <linux/platform_device.h>
  17
  18#include <drm/exynos_drm.h>
  19
  20#include <drm/drm_edid.h>
  21#include <drm/drm_crtc_helper.h>
  22
  23#include "exynos_drm_drv.h"
  24#include "exynos_drm_crtc.h"
  25#include "exynos_drm_encoder.h"
  26#include "exynos_drm_vidi.h"
  27
  28/* vidi has totally three virtual windows. */
  29#define WINDOWS_NR              3
  30
  31#define get_vidi_mgr(dev)       platform_get_drvdata(to_platform_device(dev))
  32#define ctx_from_connector(c)   container_of(c, struct vidi_context, \
  33                                        connector)
  34
  35struct vidi_win_data {
  36        unsigned int            offset_x;
  37        unsigned int            offset_y;
  38        unsigned int            ovl_width;
  39        unsigned int            ovl_height;
  40        unsigned int            fb_width;
  41        unsigned int            fb_height;
  42        unsigned int            bpp;
  43        dma_addr_t              dma_addr;
  44        unsigned int            buf_offsize;
  45        unsigned int            line_size;      /* bytes */
  46        bool                    enabled;
  47};
  48
  49struct vidi_context {
  50        struct drm_device               *drm_dev;
  51        struct drm_crtc                 *crtc;
  52        struct drm_encoder              *encoder;
  53        struct drm_connector            connector;
  54        struct exynos_drm_subdrv        subdrv;
  55        struct vidi_win_data            win_data[WINDOWS_NR];
  56        struct edid                     *raw_edid;
  57        unsigned int                    clkdiv;
  58        unsigned int                    default_win;
  59        unsigned long                   irq_flags;
  60        unsigned int                    connected;
  61        bool                            vblank_on;
  62        bool                            suspended;
  63        bool                            direct_vblank;
  64        struct work_struct              work;
  65        struct mutex                    lock;
  66        int                             pipe;
  67};
  68
  69static const char fake_edid_info[] = {
  70        0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x4c, 0x2d, 0x05, 0x05,
  71        0x00, 0x00, 0x00, 0x00, 0x30, 0x12, 0x01, 0x03, 0x80, 0x10, 0x09, 0x78,
  72        0x0a, 0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26, 0x0f, 0x50, 0x54, 0xbd,
  73        0xee, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
  74        0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x66, 0x21, 0x50, 0xb0, 0x51, 0x00,
  75        0x1b, 0x30, 0x40, 0x70, 0x36, 0x00, 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x1e,
  76        0x01, 0x1d, 0x00, 0x72, 0x51, 0xd0, 0x1e, 0x20, 0x6e, 0x28, 0x55, 0x00,
  77        0xa0, 0x5a, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x18,
  78        0x4b, 0x1a, 0x44, 0x17, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
  79        0x00, 0x00, 0x00, 0xfc, 0x00, 0x53, 0x41, 0x4d, 0x53, 0x55, 0x4e, 0x47,
  80        0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0xbc, 0x02, 0x03, 0x1e, 0xf1,
  81        0x46, 0x84, 0x05, 0x03, 0x10, 0x20, 0x22, 0x23, 0x09, 0x07, 0x07, 0x83,
  82        0x01, 0x00, 0x00, 0xe2, 0x00, 0x0f, 0x67, 0x03, 0x0c, 0x00, 0x10, 0x00,
  83        0xb8, 0x2d, 0x01, 0x1d, 0x80, 0x18, 0x71, 0x1c, 0x16, 0x20, 0x58, 0x2c,
  84        0x25, 0x00, 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x9e, 0x8c, 0x0a, 0xd0, 0x8a,
  85        0x20, 0xe0, 0x2d, 0x10, 0x10, 0x3e, 0x96, 0x00, 0xa0, 0x5a, 0x00, 0x00,
  86        0x00, 0x18, 0x02, 0x3a, 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
  87        0x45, 0x00, 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00,
  88        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  89        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  90        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  91        0x00, 0x00, 0x00, 0x06
  92};
  93
  94static void vidi_apply(struct exynos_drm_manager *mgr)
  95{
  96        struct vidi_context *ctx = mgr->ctx;
  97        struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
  98        struct vidi_win_data *win_data;
  99        int i;
 100
 101        for (i = 0; i < WINDOWS_NR; i++) {
 102                win_data = &ctx->win_data[i];
 103                if (win_data->enabled && (mgr_ops && mgr_ops->win_commit))
 104                        mgr_ops->win_commit(mgr, i);
 105        }
 106
 107        if (mgr_ops && mgr_ops->commit)
 108                mgr_ops->commit(mgr);
 109}
 110
 111static void vidi_commit(struct exynos_drm_manager *mgr)
 112{
 113        struct vidi_context *ctx = mgr->ctx;
 114
 115        if (ctx->suspended)
 116                return;
 117}
 118
 119static int vidi_enable_vblank(struct exynos_drm_manager *mgr)
 120{
 121        struct vidi_context *ctx = mgr->ctx;
 122
 123        if (ctx->suspended)
 124                return -EPERM;
 125
 126        if (!test_and_set_bit(0, &ctx->irq_flags))
 127                ctx->vblank_on = true;
 128
 129        ctx->direct_vblank = true;
 130
 131        /*
 132         * in case of page flip request, vidi_finish_pageflip function
 133         * will not be called because direct_vblank is true and then
 134         * that function will be called by manager_ops->win_commit callback
 135         */
 136        schedule_work(&ctx->work);
 137
 138        return 0;
 139}
 140
 141static void vidi_disable_vblank(struct exynos_drm_manager *mgr)
 142{
 143        struct vidi_context *ctx = mgr->ctx;
 144
 145        if (ctx->suspended)
 146                return;
 147
 148        if (test_and_clear_bit(0, &ctx->irq_flags))
 149                ctx->vblank_on = false;
 150}
 151
 152static void vidi_win_mode_set(struct exynos_drm_manager *mgr,
 153                        struct exynos_drm_overlay *overlay)
 154{
 155        struct vidi_context *ctx = mgr->ctx;
 156        struct vidi_win_data *win_data;
 157        int win;
 158        unsigned long offset;
 159
 160        if (!overlay) {
 161                DRM_ERROR("overlay is NULL\n");
 162                return;
 163        }
 164
 165        win = overlay->zpos;
 166        if (win == DEFAULT_ZPOS)
 167                win = ctx->default_win;
 168
 169        if (win < 0 || win >= WINDOWS_NR)
 170                return;
 171
 172        offset = overlay->fb_x * (overlay->bpp >> 3);
 173        offset += overlay->fb_y * overlay->pitch;
 174
 175        DRM_DEBUG_KMS("offset = 0x%lx, pitch = %x\n", offset, overlay->pitch);
 176
 177        win_data = &ctx->win_data[win];
 178
 179        win_data->offset_x = overlay->crtc_x;
 180        win_data->offset_y = overlay->crtc_y;
 181        win_data->ovl_width = overlay->crtc_width;
 182        win_data->ovl_height = overlay->crtc_height;
 183        win_data->fb_width = overlay->fb_width;
 184        win_data->fb_height = overlay->fb_height;
 185        win_data->dma_addr = overlay->dma_addr[0] + offset;
 186        win_data->bpp = overlay->bpp;
 187        win_data->buf_offsize = (overlay->fb_width - overlay->crtc_width) *
 188                                (overlay->bpp >> 3);
 189        win_data->line_size = overlay->crtc_width * (overlay->bpp >> 3);
 190
 191        /*
 192         * some parts of win_data should be transferred to user side
 193         * through specific ioctl.
 194         */
 195
 196        DRM_DEBUG_KMS("offset_x = %d, offset_y = %d\n",
 197                        win_data->offset_x, win_data->offset_y);
 198        DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
 199                        win_data->ovl_width, win_data->ovl_height);
 200        DRM_DEBUG_KMS("paddr = 0x%lx\n", (unsigned long)win_data->dma_addr);
 201        DRM_DEBUG_KMS("fb_width = %d, crtc_width = %d\n",
 202                        overlay->fb_width, overlay->crtc_width);
 203}
 204
 205static void vidi_win_commit(struct exynos_drm_manager *mgr, int zpos)
 206{
 207        struct vidi_context *ctx = mgr->ctx;
 208        struct vidi_win_data *win_data;
 209        int win = zpos;
 210
 211        if (ctx->suspended)
 212                return;
 213
 214        if (win == DEFAULT_ZPOS)
 215                win = ctx->default_win;
 216
 217        if (win < 0 || win >= WINDOWS_NR)
 218                return;
 219
 220        win_data = &ctx->win_data[win];
 221
 222        win_data->enabled = true;
 223
 224        DRM_DEBUG_KMS("dma_addr = %pad\n", &win_data->dma_addr);
 225
 226        if (ctx->vblank_on)
 227                schedule_work(&ctx->work);
 228}
 229
 230static void vidi_win_disable(struct exynos_drm_manager *mgr, int zpos)
 231{
 232        struct vidi_context *ctx = mgr->ctx;
 233        struct vidi_win_data *win_data;
 234        int win = zpos;
 235
 236        if (win == DEFAULT_ZPOS)
 237                win = ctx->default_win;
 238
 239        if (win < 0 || win >= WINDOWS_NR)
 240                return;
 241
 242        win_data = &ctx->win_data[win];
 243        win_data->enabled = false;
 244
 245        /* TODO. */
 246}
 247
 248static int vidi_power_on(struct exynos_drm_manager *mgr, bool enable)
 249{
 250        struct vidi_context *ctx = mgr->ctx;
 251
 252        DRM_DEBUG_KMS("%s\n", __FILE__);
 253
 254        if (enable != false && enable != true)
 255                return -EINVAL;
 256
 257        if (enable) {
 258                ctx->suspended = false;
 259
 260                /* if vblank was enabled status, enable it again. */
 261                if (test_and_clear_bit(0, &ctx->irq_flags))
 262                        vidi_enable_vblank(mgr);
 263
 264                vidi_apply(mgr);
 265        } else {
 266                ctx->suspended = true;
 267        }
 268
 269        return 0;
 270}
 271
 272static void vidi_dpms(struct exynos_drm_manager *mgr, int mode)
 273{
 274        struct vidi_context *ctx = mgr->ctx;
 275
 276        DRM_DEBUG_KMS("%d\n", mode);
 277
 278        mutex_lock(&ctx->lock);
 279
 280        switch (mode) {
 281        case DRM_MODE_DPMS_ON:
 282                vidi_power_on(mgr, true);
 283                break;
 284        case DRM_MODE_DPMS_STANDBY:
 285        case DRM_MODE_DPMS_SUSPEND:
 286        case DRM_MODE_DPMS_OFF:
 287                vidi_power_on(mgr, false);
 288                break;
 289        default:
 290                DRM_DEBUG_KMS("unspecified mode %d\n", mode);
 291                break;
 292        }
 293
 294        mutex_unlock(&ctx->lock);
 295}
 296
 297static int vidi_mgr_initialize(struct exynos_drm_manager *mgr,
 298                        struct drm_device *drm_dev)
 299{
 300        struct vidi_context *ctx = mgr->ctx;
 301        struct exynos_drm_private *priv = drm_dev->dev_private;
 302
 303        mgr->drm_dev = ctx->drm_dev = drm_dev;
 304        mgr->pipe = ctx->pipe = priv->pipe++;
 305
 306        return 0;
 307}
 308
 309static struct exynos_drm_manager_ops vidi_manager_ops = {
 310        .dpms = vidi_dpms,
 311        .commit = vidi_commit,
 312        .enable_vblank = vidi_enable_vblank,
 313        .disable_vblank = vidi_disable_vblank,
 314        .win_mode_set = vidi_win_mode_set,
 315        .win_commit = vidi_win_commit,
 316        .win_disable = vidi_win_disable,
 317};
 318
 319static struct exynos_drm_manager vidi_manager = {
 320        .type = EXYNOS_DISPLAY_TYPE_VIDI,
 321        .ops = &vidi_manager_ops,
 322};
 323
 324static void vidi_fake_vblank_handler(struct work_struct *work)
 325{
 326        struct vidi_context *ctx = container_of(work, struct vidi_context,
 327                                        work);
 328
 329        if (ctx->pipe < 0)
 330                return;
 331
 332        /* refresh rate is about 50Hz. */
 333        usleep_range(16000, 20000);
 334
 335        mutex_lock(&ctx->lock);
 336
 337        if (ctx->direct_vblank) {
 338                drm_handle_vblank(ctx->drm_dev, ctx->pipe);
 339                ctx->direct_vblank = false;
 340                mutex_unlock(&ctx->lock);
 341                return;
 342        }
 343
 344        mutex_unlock(&ctx->lock);
 345
 346        exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
 347}
 348
 349static int vidi_show_connection(struct device *dev,
 350                                struct device_attribute *attr, char *buf)
 351{
 352        int rc;
 353        struct exynos_drm_manager *mgr = get_vidi_mgr(dev);
 354        struct vidi_context *ctx = mgr->ctx;
 355
 356        mutex_lock(&ctx->lock);
 357
 358        rc = sprintf(buf, "%d\n", ctx->connected);
 359
 360        mutex_unlock(&ctx->lock);
 361
 362        return rc;
 363}
 364
 365static int vidi_store_connection(struct device *dev,
 366                                struct device_attribute *attr,
 367                                const char *buf, size_t len)
 368{
 369        struct exynos_drm_manager *mgr = get_vidi_mgr(dev);
 370        struct vidi_context *ctx = mgr->ctx;
 371        int ret;
 372
 373        ret = kstrtoint(buf, 0, &ctx->connected);
 374        if (ret)
 375                return ret;
 376
 377        if (ctx->connected > 1)
 378                return -EINVAL;
 379
 380        /* use fake edid data for test. */
 381        if (!ctx->raw_edid)
 382                ctx->raw_edid = (struct edid *)fake_edid_info;
 383
 384        /* if raw_edid isn't same as fake data then it can't be tested. */
 385        if (ctx->raw_edid != (struct edid *)fake_edid_info) {
 386                DRM_DEBUG_KMS("edid data is not fake data.\n");
 387                return -EINVAL;
 388        }
 389
 390        DRM_DEBUG_KMS("requested connection.\n");
 391
 392        drm_helper_hpd_irq_event(ctx->drm_dev);
 393
 394        return len;
 395}
 396
 397static DEVICE_ATTR(connection, 0644, vidi_show_connection,
 398                        vidi_store_connection);
 399
 400int vidi_connection_ioctl(struct drm_device *drm_dev, void *data,
 401                                struct drm_file *file_priv)
 402{
 403        struct vidi_context *ctx = NULL;
 404        struct drm_encoder *encoder;
 405        struct exynos_drm_display *display;
 406        struct drm_exynos_vidi_connection *vidi = data;
 407
 408        if (!vidi) {
 409                DRM_DEBUG_KMS("user data for vidi is null.\n");
 410                return -EINVAL;
 411        }
 412
 413        if (vidi->connection > 1) {
 414                DRM_DEBUG_KMS("connection should be 0 or 1.\n");
 415                return -EINVAL;
 416        }
 417
 418        list_for_each_entry(encoder, &drm_dev->mode_config.encoder_list,
 419                                                                head) {
 420                display = exynos_drm_get_display(encoder);
 421
 422                if (display->type == EXYNOS_DISPLAY_TYPE_VIDI) {
 423                        ctx = display->ctx;
 424                        break;
 425                }
 426        }
 427
 428        if (!ctx) {
 429                DRM_DEBUG_KMS("not found virtual device type encoder.\n");
 430                return -EINVAL;
 431        }
 432
 433        if (ctx->connected == vidi->connection) {
 434                DRM_DEBUG_KMS("same connection request.\n");
 435                return -EINVAL;
 436        }
 437
 438        if (vidi->connection) {
 439                struct edid *raw_edid  = (struct edid *)(uint32_t)vidi->edid;
 440                if (!drm_edid_is_valid(raw_edid)) {
 441                        DRM_DEBUG_KMS("edid data is invalid.\n");
 442                        return -EINVAL;
 443                }
 444                ctx->raw_edid = drm_edid_duplicate(raw_edid);
 445                if (!ctx->raw_edid) {
 446                        DRM_DEBUG_KMS("failed to allocate raw_edid.\n");
 447                        return -ENOMEM;
 448                }
 449        } else {
 450                /*
 451                 * with connection = 0, free raw_edid
 452                 * only if raw edid data isn't same as fake data.
 453                 */
 454                if (ctx->raw_edid && ctx->raw_edid !=
 455                                (struct edid *)fake_edid_info) {
 456                        kfree(ctx->raw_edid);
 457                        ctx->raw_edid = NULL;
 458                }
 459        }
 460
 461        ctx->connected = vidi->connection;
 462        drm_helper_hpd_irq_event(ctx->drm_dev);
 463
 464        return 0;
 465}
 466
 467static enum drm_connector_status vidi_detect(struct drm_connector *connector,
 468                        bool force)
 469{
 470        struct vidi_context *ctx = ctx_from_connector(connector);
 471
 472        /*
 473         * connection request would come from user side
 474         * to do hotplug through specific ioctl.
 475         */
 476        return ctx->connected ? connector_status_connected :
 477                        connector_status_disconnected;
 478}
 479
 480static void vidi_connector_destroy(struct drm_connector *connector)
 481{
 482}
 483
 484static struct drm_connector_funcs vidi_connector_funcs = {
 485        .dpms = drm_helper_connector_dpms,
 486        .fill_modes = drm_helper_probe_single_connector_modes,
 487        .detect = vidi_detect,
 488        .destroy = vidi_connector_destroy,
 489};
 490
 491static int vidi_get_modes(struct drm_connector *connector)
 492{
 493        struct vidi_context *ctx = ctx_from_connector(connector);
 494        struct edid *edid;
 495        int edid_len;
 496
 497        /*
 498         * the edid data comes from user side and it would be set
 499         * to ctx->raw_edid through specific ioctl.
 500         */
 501        if (!ctx->raw_edid) {
 502                DRM_DEBUG_KMS("raw_edid is null.\n");
 503                return -EFAULT;
 504        }
 505
 506        edid_len = (1 + ctx->raw_edid->extensions) * EDID_LENGTH;
 507        edid = kmemdup(ctx->raw_edid, edid_len, GFP_KERNEL);
 508        if (!edid) {
 509                DRM_DEBUG_KMS("failed to allocate edid\n");
 510                return -ENOMEM;
 511        }
 512
 513        drm_mode_connector_update_edid_property(connector, edid);
 514
 515        return drm_add_edid_modes(connector, edid);
 516}
 517
 518static struct drm_encoder *vidi_best_encoder(struct drm_connector *connector)
 519{
 520        struct vidi_context *ctx = ctx_from_connector(connector);
 521
 522        return ctx->encoder;
 523}
 524
 525static struct drm_connector_helper_funcs vidi_connector_helper_funcs = {
 526        .get_modes = vidi_get_modes,
 527        .best_encoder = vidi_best_encoder,
 528};
 529
 530static int vidi_create_connector(struct exynos_drm_display *display,
 531                                struct drm_encoder *encoder)
 532{
 533        struct vidi_context *ctx = display->ctx;
 534        struct drm_connector *connector = &ctx->connector;
 535        int ret;
 536
 537        ctx->encoder = encoder;
 538        connector->polled = DRM_CONNECTOR_POLL_HPD;
 539
 540        ret = drm_connector_init(ctx->drm_dev, connector,
 541                        &vidi_connector_funcs, DRM_MODE_CONNECTOR_VIRTUAL);
 542        if (ret) {
 543                DRM_ERROR("Failed to initialize connector with drm\n");
 544                return ret;
 545        }
 546
 547        drm_connector_helper_add(connector, &vidi_connector_helper_funcs);
 548        drm_connector_register(connector);
 549        drm_mode_connector_attach_encoder(connector, encoder);
 550
 551        return 0;
 552}
 553
 554
 555static struct exynos_drm_display_ops vidi_display_ops = {
 556        .create_connector = vidi_create_connector,
 557};
 558
 559static struct exynos_drm_display vidi_display = {
 560        .type = EXYNOS_DISPLAY_TYPE_VIDI,
 561        .ops = &vidi_display_ops,
 562};
 563
 564static int vidi_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
 565{
 566        struct exynos_drm_manager *mgr = get_vidi_mgr(dev);
 567        struct vidi_context *ctx = mgr->ctx;
 568        struct drm_crtc *crtc = ctx->crtc;
 569        int ret;
 570
 571        vidi_mgr_initialize(mgr, drm_dev);
 572
 573        ret = exynos_drm_crtc_create(&vidi_manager);
 574        if (ret) {
 575                DRM_ERROR("failed to create crtc.\n");
 576                return ret;
 577        }
 578
 579        ret = exynos_drm_create_enc_conn(drm_dev, &vidi_display);
 580        if (ret) {
 581                crtc->funcs->destroy(crtc);
 582                DRM_ERROR("failed to create encoder and connector.\n");
 583                return ret;
 584        }
 585
 586        return 0;
 587}
 588
 589static int vidi_probe(struct platform_device *pdev)
 590{
 591        struct exynos_drm_subdrv *subdrv;
 592        struct vidi_context *ctx;
 593        int ret;
 594
 595        ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
 596        if (!ctx)
 597                return -ENOMEM;
 598
 599        ctx->default_win = 0;
 600
 601        INIT_WORK(&ctx->work, vidi_fake_vblank_handler);
 602
 603        vidi_manager.ctx = ctx;
 604        vidi_display.ctx = ctx;
 605
 606        mutex_init(&ctx->lock);
 607
 608        platform_set_drvdata(pdev, &vidi_manager);
 609
 610        subdrv = &ctx->subdrv;
 611        subdrv->dev = &pdev->dev;
 612        subdrv->probe = vidi_subdrv_probe;
 613
 614        ret = exynos_drm_subdrv_register(subdrv);
 615        if (ret < 0) {
 616                dev_err(&pdev->dev, "failed to register drm vidi device\n");
 617                return ret;
 618        }
 619
 620        ret = device_create_file(&pdev->dev, &dev_attr_connection);
 621        if (ret < 0) {
 622                exynos_drm_subdrv_unregister(subdrv);
 623                DRM_INFO("failed to create connection sysfs.\n");
 624        }
 625
 626        return 0;
 627}
 628
 629static int vidi_remove(struct platform_device *pdev)
 630{
 631        struct exynos_drm_manager *mgr = platform_get_drvdata(pdev);
 632        struct vidi_context *ctx = mgr->ctx;
 633
 634        if (ctx->raw_edid != (struct edid *)fake_edid_info) {
 635                kfree(ctx->raw_edid);
 636                ctx->raw_edid = NULL;
 637
 638                return -EINVAL;
 639        }
 640
 641        return 0;
 642}
 643
 644struct platform_driver vidi_driver = {
 645        .probe          = vidi_probe,
 646        .remove         = vidi_remove,
 647        .driver         = {
 648                .name   = "exynos-drm-vidi",
 649                .owner  = THIS_MODULE,
 650        },
 651};
 652
 653int exynos_drm_probe_vidi(void)
 654{
 655        struct platform_device *pdev;
 656        int ret;
 657
 658        pdev = platform_device_register_simple("exynos-drm-vidi", -1, NULL, 0);
 659        if (IS_ERR(pdev))
 660                return PTR_ERR(pdev);
 661
 662        ret = platform_driver_register(&vidi_driver);
 663        if (ret) {
 664                platform_device_unregister(pdev);
 665                return ret;
 666        }
 667
 668        return ret;
 669}
 670
 671void exynos_drm_remove_vidi(void)
 672{
 673        struct vidi_context *ctx = vidi_manager.ctx;
 674        struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
 675        struct platform_device *pdev = to_platform_device(subdrv->dev);
 676
 677        platform_driver_unregister(&vidi_driver);
 678        platform_device_unregister(pdev);
 679}
 680