linux/drivers/gpu/drm/xilinx/xilinx_drm_drv.c
<<
>>
Prefs
   1/*
   2 * Xilinx DRM KMS support for Xilinx
   3 *
   4 *  Copyright (C) 2013 Xilinx, Inc.
   5 *
   6 *  Author: Hyun Woo Kwon <hyunk@xilinx.com>
   7 *
   8 * This software is licensed under the terms of the GNU General Public
   9 * License version 2, as published by the Free Software Foundation, and
  10 * may be copied, distributed, and modified under those terms.
  11 *
  12 * This program is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 * GNU General Public License for more details.
  16 */
  17
  18#include <drm/drmP.h>
  19#include <drm/drm_crtc_helper.h>
  20#include <drm/drm_gem_cma_helper.h>
  21
  22#include <linux/component.h>
  23#include <linux/console.h>
  24#include <linux/device.h>
  25#include <linux/module.h>
  26#include <linux/of_graph.h>
  27#include <linux/platform_device.h>
  28
  29#include "xilinx_drm_connector.h"
  30#include "xilinx_drm_crtc.h"
  31#include "xilinx_drm_drv.h"
  32#include "xilinx_drm_encoder.h"
  33#include "xilinx_drm_fb.h"
  34#include "xilinx_drm_gem.h"
  35
  36#define DRIVER_NAME     "xilinx_drm"
  37#define DRIVER_DESC     "Xilinx DRM KMS support for Xilinx"
  38#define DRIVER_DATE     "20130509"
  39#define DRIVER_MAJOR    1
  40#define DRIVER_MINOR    0
  41
  42static uint xilinx_drm_fbdev_vres = 2;
  43module_param_named(fbdev_vres, xilinx_drm_fbdev_vres, uint, 0444);
  44MODULE_PARM_DESC(fbdev_vres,
  45                 "fbdev virtual resolution multiplier for fb (default: 2)");
  46
  47/*
  48 * TODO: The possible pipeline configurations are numerous with Xilinx soft IPs.
  49 * It's not too bad for now, but the more proper way(Common Display Framework,
  50 * or some internal abstraction) should be considered, when it reaches a point
  51 * that such thing is required.
  52 */
  53
  54struct xilinx_drm_private {
  55        struct drm_device *drm;
  56        struct drm_crtc *crtc;
  57        struct drm_fb_helper *fb;
  58        struct platform_device *pdev;
  59        bool is_master;
  60};
  61
  62/**
  63 * struct xilinx_video_format_desc - Xilinx Video IP video format description
  64 * @name: Xilinx video format name
  65 * @depth: color depth
  66 * @bpp: bits per pixel
  67 * @xilinx_format: xilinx format code
  68 * @drm_format: drm format code
  69 */
  70struct xilinx_video_format_desc {
  71        const char *name;
  72        unsigned int depth;
  73        unsigned int bpp;
  74        unsigned int xilinx_format;
  75        uint32_t drm_format;
  76};
  77
  78static const struct xilinx_video_format_desc xilinx_video_formats[] = {
  79        { "yuv420", 16, 16, XILINX_VIDEO_FORMAT_YUV420, DRM_FORMAT_YUV420 },
  80        { "uvy422", 16, 16, XILINX_VIDEO_FORMAT_NONE, DRM_FORMAT_UYVY },
  81        { "vuy422", 16, 16, XILINX_VIDEO_FORMAT_YUV422, DRM_FORMAT_VYUY },
  82        { "yuv422", 16, 16, XILINX_VIDEO_FORMAT_YUV422, DRM_FORMAT_YUYV },
  83        { "yvu422", 16, 16, XILINX_VIDEO_FORMAT_NONE, DRM_FORMAT_YVYU },
  84        { "yuv444", 24, 24, XILINX_VIDEO_FORMAT_YUV444, DRM_FORMAT_YUV444 },
  85        { "nv12", 16, 16, XILINX_VIDEO_FORMAT_NONE, DRM_FORMAT_NV12 },
  86        { "nv21", 16, 16, XILINX_VIDEO_FORMAT_NONE, DRM_FORMAT_NV21 },
  87        { "nv16", 16, 16, XILINX_VIDEO_FORMAT_NONE, DRM_FORMAT_NV16 },
  88        { "nv61", 16, 16, XILINX_VIDEO_FORMAT_NONE, DRM_FORMAT_NV61 },
  89        { "abgr1555", 16, 16, XILINX_VIDEO_FORMAT_NONE, DRM_FORMAT_ABGR1555 },
  90        { "argb1555", 16, 16, XILINX_VIDEO_FORMAT_NONE, DRM_FORMAT_ARGB1555 },
  91        { "rgba4444", 16, 16, XILINX_VIDEO_FORMAT_NONE, DRM_FORMAT_RGBA4444 },
  92        { "bgra4444", 16, 16, XILINX_VIDEO_FORMAT_NONE, DRM_FORMAT_BGRA4444 },
  93        { "bgr565", 16, 16, XILINX_VIDEO_FORMAT_NONE, DRM_FORMAT_BGR565 },
  94        { "rgb565", 16, 16, XILINX_VIDEO_FORMAT_NONE, DRM_FORMAT_RGB565 },
  95        { "bgr888", 24, 24, XILINX_VIDEO_FORMAT_RGB, DRM_FORMAT_BGR888 },
  96        { "rgb888", 24, 24, XILINX_VIDEO_FORMAT_RGB, DRM_FORMAT_RGB888 },
  97        { "xbgr8888", 24, 32, XILINX_VIDEO_FORMAT_NONE, DRM_FORMAT_XBGR8888 },
  98        { "xrgb8888", 24, 32, XILINX_VIDEO_FORMAT_XRGB, DRM_FORMAT_XRGB8888 },
  99        { "abgr8888", 32, 32, XILINX_VIDEO_FORMAT_NONE, DRM_FORMAT_ABGR8888 },
 100        { "argb8888", 32, 32, XILINX_VIDEO_FORMAT_NONE, DRM_FORMAT_ARGB8888 },
 101        { "bgra8888", 32, 32, XILINX_VIDEO_FORMAT_NONE, DRM_FORMAT_BGRA8888 },
 102        { "rgba8888", 32, 32, XILINX_VIDEO_FORMAT_NONE, DRM_FORMAT_RGBA8888 },
 103};
 104
 105/**
 106 * xilinx_drm_check_format - Check if the given format is supported
 107 * @drm: DRM device
 108 * @fourcc: format fourcc
 109 *
 110 * Check if the given format @fourcc is supported by the current pipeline
 111 *
 112 * Return: true if the format is supported, or false
 113 */
 114bool xilinx_drm_check_format(struct drm_device *drm, uint32_t fourcc)
 115{
 116        struct xilinx_drm_private *private = drm->dev_private;
 117
 118        return xilinx_drm_crtc_check_format(private->crtc, fourcc);
 119}
 120
 121/**
 122 * xilinx_drm_get_format - Get the current device format
 123 * @drm: DRM device
 124 *
 125 * Get the current format of pipeline
 126 *
 127 * Return: the corresponding DRM_FORMAT_XXX
 128 */
 129uint32_t xilinx_drm_get_format(struct drm_device *drm)
 130{
 131        struct xilinx_drm_private *private = drm->dev_private;
 132
 133        return xilinx_drm_crtc_get_format(private->crtc);
 134}
 135
 136/**
 137 * xilinx_drm_get_align - Get the alignment value for pitch
 138 * @drm: DRM object
 139 *
 140 * Get the alignment value for pitch from the plane
 141 *
 142 * Return: The alignment value if successful, or the error code.
 143 */
 144unsigned int xilinx_drm_get_align(struct drm_device *drm)
 145{
 146        struct xilinx_drm_private *private = drm->dev_private;
 147
 148        return xilinx_drm_crtc_get_align(private->crtc);
 149}
 150
 151void xilinx_drm_set_config(struct drm_device *drm, struct drm_mode_set *set)
 152{
 153        struct xilinx_drm_private *private = drm->dev_private;
 154
 155        if (private && private->fb)
 156                xilinx_drm_fb_set_config(private->fb, set);
 157}
 158
 159/* poll changed handler */
 160static void xilinx_drm_output_poll_changed(struct drm_device *drm)
 161{
 162        struct xilinx_drm_private *private = drm->dev_private;
 163
 164        xilinx_drm_fb_hotplug_event(private->fb);
 165}
 166
 167static const struct drm_mode_config_funcs xilinx_drm_mode_config_funcs = {
 168        .fb_create              = xilinx_drm_fb_create,
 169        .output_poll_changed    = xilinx_drm_output_poll_changed,
 170};
 171
 172/* enable vblank */
 173static int xilinx_drm_enable_vblank(struct drm_device *drm, unsigned int crtc)
 174{
 175        struct xilinx_drm_private *private = drm->dev_private;
 176
 177        xilinx_drm_crtc_enable_vblank(private->crtc);
 178
 179        return 0;
 180}
 181
 182/* disable vblank */
 183static void xilinx_drm_disable_vblank(struct drm_device *drm, unsigned int crtc)
 184{
 185        struct xilinx_drm_private *private = drm->dev_private;
 186
 187        xilinx_drm_crtc_disable_vblank(private->crtc);
 188}
 189
 190/* initialize mode config */
 191static void xilinx_drm_mode_config_init(struct drm_device *drm)
 192{
 193        struct xilinx_drm_private *private = drm->dev_private;
 194
 195        drm->mode_config.min_width = 0;
 196        drm->mode_config.min_height = 0;
 197
 198        drm->mode_config.max_width =
 199                xilinx_drm_crtc_get_max_width(private->crtc);
 200        drm->mode_config.max_height = 4096;
 201
 202        drm->mode_config.funcs = &xilinx_drm_mode_config_funcs;
 203}
 204
 205/* convert xilinx format to drm format by code */
 206int xilinx_drm_format_by_code(unsigned int xilinx_format, uint32_t *drm_format)
 207{
 208        const struct xilinx_video_format_desc *format;
 209        unsigned int i;
 210
 211        for (i = 0; i < ARRAY_SIZE(xilinx_video_formats); i++) {
 212                format = &xilinx_video_formats[i];
 213                if (format->xilinx_format == xilinx_format) {
 214                        *drm_format = format->drm_format;
 215                        return 0;
 216                }
 217        }
 218
 219        DRM_ERROR("Unknown Xilinx video format: %d\n", xilinx_format);
 220
 221        return -EINVAL;
 222}
 223
 224/* convert xilinx format to drm format by name */
 225int xilinx_drm_format_by_name(const char *name, uint32_t *drm_format)
 226{
 227        const struct xilinx_video_format_desc *format;
 228        unsigned int i;
 229
 230        for (i = 0; i < ARRAY_SIZE(xilinx_video_formats); i++) {
 231                format = &xilinx_video_formats[i];
 232                if (strcmp(format->name, name) == 0) {
 233                        *drm_format = format->drm_format;
 234                        return 0;
 235                }
 236        }
 237
 238        DRM_ERROR("Unknown Xilinx video format: %s\n", name);
 239
 240        return -EINVAL;
 241}
 242
 243/* get bpp of given format */
 244unsigned int xilinx_drm_format_bpp(uint32_t drm_format)
 245{
 246        const struct xilinx_video_format_desc *format;
 247        unsigned int i;
 248
 249        for (i = 0; i < ARRAY_SIZE(xilinx_video_formats); i++) {
 250                format = &xilinx_video_formats[i];
 251                if (format->drm_format == drm_format)
 252                        return format->bpp;
 253        }
 254
 255        return 0;
 256}
 257
 258/* get color depth of given format */
 259unsigned int xilinx_drm_format_depth(uint32_t drm_format)
 260{
 261        const struct xilinx_video_format_desc *format;
 262        unsigned int i;
 263
 264        for (i = 0; i < ARRAY_SIZE(xilinx_video_formats); i++) {
 265                format = &xilinx_video_formats[i];
 266                if (format->drm_format == drm_format)
 267                        return format->depth;
 268        }
 269
 270        return 0;
 271}
 272
 273static int xilinx_drm_bind(struct device *dev)
 274{
 275        struct xilinx_drm_private *private = dev_get_drvdata(dev);
 276        struct drm_device *drm = private->drm;
 277
 278        return component_bind_all(dev, drm);
 279}
 280
 281static void xilinx_drm_unbind(struct device *dev)
 282{
 283        dev_set_drvdata(dev, NULL);
 284}
 285
 286static const struct component_master_ops xilinx_drm_ops = {
 287        .bind   = xilinx_drm_bind,
 288        .unbind = xilinx_drm_unbind,
 289};
 290
 291static int compare_of(struct device *dev, void *data)
 292{
 293        struct device_node *np = data;
 294
 295        return dev->of_node == np;
 296}
 297
 298/* load xilinx drm */
 299static int xilinx_drm_load(struct drm_device *drm, unsigned long flags)
 300{
 301        struct xilinx_drm_private *private;
 302        struct drm_encoder *encoder;
 303        struct drm_connector *connector;
 304        struct device_node *encoder_node, *ep = NULL, *remote;
 305        struct platform_device *pdev = drm->platformdev;
 306        struct component_match *match = NULL;
 307        unsigned int bpp, align, i = 0;
 308        int ret;
 309
 310        private = devm_kzalloc(drm->dev, sizeof(*private), GFP_KERNEL);
 311        if (!private)
 312                return -ENOMEM;
 313
 314        drm_mode_config_init(drm);
 315
 316        /* create a xilinx crtc */
 317        private->crtc = xilinx_drm_crtc_create(drm);
 318        if (IS_ERR(private->crtc)) {
 319                DRM_DEBUG_DRIVER("failed to create xilinx crtc\n");
 320                ret = PTR_ERR(private->crtc);
 321                goto err_out;
 322        }
 323
 324        while ((encoder_node = of_parse_phandle(drm->dev->of_node,
 325                                                "xlnx,encoder-slave", i))) {
 326                encoder = xilinx_drm_encoder_create(drm, encoder_node);
 327                of_node_put(encoder_node);
 328                if (IS_ERR(encoder)) {
 329                        DRM_DEBUG_DRIVER("failed to create xilinx encoder\n");
 330                        ret = PTR_ERR(encoder);
 331                        goto err_out;
 332                }
 333
 334                connector = xilinx_drm_connector_create(drm, encoder, i);
 335                if (IS_ERR(connector)) {
 336                        DRM_DEBUG_DRIVER("failed to create xilinx connector\n");
 337                        ret = PTR_ERR(connector);
 338                        goto err_out;
 339                }
 340
 341                i++;
 342        }
 343
 344        while (1) {
 345                ep = of_graph_get_next_endpoint(drm->dev->of_node, ep);
 346                if (!ep)
 347                        break;
 348
 349                of_node_put(ep);
 350                remote = of_graph_get_remote_port_parent(ep);
 351                if (!remote || !of_device_is_available(remote)) {
 352                        of_node_put(remote);
 353                        continue;
 354                }
 355
 356                component_match_add(drm->dev, &match, compare_of, remote);
 357                of_node_put(remote);
 358                i++;
 359        }
 360
 361        if (i == 0) {
 362                DRM_ERROR("failed to get an encoder slave node\n");
 363                return -ENODEV;
 364        }
 365
 366        ret = drm_vblank_init(drm, 1);
 367        if (ret) {
 368                dev_err(&pdev->dev, "failed to initialize vblank\n");
 369                goto err_master;
 370        }
 371
 372        /* enable irq to enable vblank feature */
 373        drm->irq_enabled = 1;
 374
 375        drm->dev_private = private;
 376        private->drm = drm;
 377        xilinx_drm_mode_config_init(drm);
 378
 379        /* initialize xilinx framebuffer */
 380        bpp = xilinx_drm_format_bpp(xilinx_drm_crtc_get_format(private->crtc));
 381        align = xilinx_drm_crtc_get_align(private->crtc);
 382        private->fb = xilinx_drm_fb_init(drm, bpp, 1, 1, align,
 383                                         xilinx_drm_fbdev_vres);
 384        if (IS_ERR(private->fb)) {
 385                DRM_ERROR("failed to initialize drm cma fb\n");
 386                ret = PTR_ERR(private->fb);
 387                goto err_fb;
 388        }
 389
 390        drm_kms_helper_poll_init(drm);
 391
 392        drm_helper_disable_unused_functions(drm);
 393
 394        platform_set_drvdata(pdev, private);
 395
 396        if (match) {
 397                ret = component_master_add_with_match(drm->dev,
 398                                                      &xilinx_drm_ops, match);
 399                if (ret)
 400                        goto err_fb;
 401        }
 402
 403        return 0;
 404
 405err_fb:
 406        drm_vblank_cleanup(drm);
 407err_master:
 408        component_master_del(drm->dev, &xilinx_drm_ops);
 409err_out:
 410        drm_mode_config_cleanup(drm);
 411        if (ret == -EPROBE_DEFER)
 412                DRM_INFO("load() is defered & will be called again\n");
 413        return ret;
 414}
 415
 416/* unload xilinx drm */
 417static int xilinx_drm_unload(struct drm_device *drm)
 418{
 419        struct xilinx_drm_private *private = drm->dev_private;
 420
 421        drm_vblank_cleanup(drm);
 422        component_master_del(drm->dev, &xilinx_drm_ops);
 423        drm_kms_helper_poll_fini(drm);
 424        xilinx_drm_fb_fini(private->fb);
 425        drm_mode_config_cleanup(drm);
 426
 427        return 0;
 428}
 429
 430int xilinx_drm_open(struct drm_device *dev, struct drm_file *file)
 431{
 432        struct xilinx_drm_private *private = dev->dev_private;
 433
 434        if (!(drm_is_primary_client(file) && !dev->master) &&
 435                        capable(CAP_SYS_ADMIN)) {
 436                file->is_master = 1;
 437                private->is_master = true;
 438        }
 439
 440        return 0;
 441}
 442
 443/* preclose */
 444static void xilinx_drm_preclose(struct drm_device *drm, struct drm_file *file)
 445{
 446        struct xilinx_drm_private *private = drm->dev_private;
 447
 448        /* cancel pending page flip request */
 449        xilinx_drm_crtc_cancel_page_flip(private->crtc, file);
 450
 451        if (private->is_master) {
 452                private->is_master = false;
 453                file->is_master = 0;
 454        }
 455}
 456
 457/* restore the default mode when xilinx drm is released */
 458static void xilinx_drm_lastclose(struct drm_device *drm)
 459{
 460        struct xilinx_drm_private *private = drm->dev_private;
 461
 462        xilinx_drm_crtc_restore(private->crtc);
 463
 464        xilinx_drm_fb_restore_mode(private->fb);
 465}
 466
 467static const struct file_operations xilinx_drm_fops = {
 468        .owner          = THIS_MODULE,
 469        .open           = drm_open,
 470        .release        = drm_release,
 471        .unlocked_ioctl = drm_ioctl,
 472        .mmap           = drm_gem_cma_mmap,
 473        .poll           = drm_poll,
 474        .read           = drm_read,
 475#ifdef CONFIG_COMPAT
 476        .compat_ioctl   = drm_compat_ioctl,
 477#endif
 478        .llseek         = noop_llseek,
 479};
 480
 481static struct drm_driver xilinx_drm_driver = {
 482        .driver_features                = DRIVER_MODESET | DRIVER_GEM |
 483                                          DRIVER_PRIME,
 484        .load                           = xilinx_drm_load,
 485        .unload                         = xilinx_drm_unload,
 486        .open                           = xilinx_drm_open,
 487        .preclose                       = xilinx_drm_preclose,
 488        .lastclose                      = xilinx_drm_lastclose,
 489
 490        .get_vblank_counter             = drm_vblank_no_hw_counter,
 491        .enable_vblank                  = xilinx_drm_enable_vblank,
 492        .disable_vblank                 = xilinx_drm_disable_vblank,
 493
 494        .prime_handle_to_fd             = drm_gem_prime_handle_to_fd,
 495        .prime_fd_to_handle             = drm_gem_prime_fd_to_handle,
 496        .gem_prime_export               = drm_gem_prime_export,
 497        .gem_prime_import               = drm_gem_prime_import,
 498        .gem_prime_get_sg_table         = drm_gem_cma_prime_get_sg_table,
 499        .gem_prime_import_sg_table      = drm_gem_cma_prime_import_sg_table,
 500        .gem_prime_vmap                 = drm_gem_cma_prime_vmap,
 501        .gem_prime_vunmap               = drm_gem_cma_prime_vunmap,
 502        .gem_prime_mmap                 = drm_gem_cma_prime_mmap,
 503        .gem_free_object                = drm_gem_cma_free_object,
 504        .gem_vm_ops                     = &drm_gem_cma_vm_ops,
 505        .dumb_create                    = xilinx_drm_gem_cma_dumb_create,
 506        .dumb_map_offset                = drm_gem_cma_dumb_map_offset,
 507        .dumb_destroy                   = drm_gem_dumb_destroy,
 508
 509        .fops                           = &xilinx_drm_fops,
 510
 511        .name                           = DRIVER_NAME,
 512        .desc                           = DRIVER_DESC,
 513        .date                           = DRIVER_DATE,
 514        .major                          = DRIVER_MAJOR,
 515        .minor                          = DRIVER_MINOR,
 516};
 517
 518#if defined(CONFIG_PM_SLEEP)
 519/* suspend xilinx drm */
 520static int xilinx_drm_pm_suspend(struct device *dev)
 521{
 522        struct xilinx_drm_private *private = dev_get_drvdata(dev);
 523        struct drm_device *drm = private->drm;
 524        struct drm_connector *connector;
 525
 526        drm_kms_helper_poll_disable(drm);
 527
 528        if (!console_suspend_enabled)
 529                return 0;
 530
 531        drm_modeset_lock_all(drm);
 532        list_for_each_entry(connector, &drm->mode_config.connector_list, head) {
 533                int old_dpms = connector->dpms;
 534
 535                if (connector->funcs->dpms)
 536                        connector->funcs->dpms(connector,
 537                                               DRM_MODE_DPMS_SUSPEND);
 538
 539                connector->dpms = old_dpms;
 540        }
 541        drm_modeset_unlock_all(drm);
 542
 543        return 0;
 544}
 545
 546/* resume xilinx drm */
 547static int xilinx_drm_pm_resume(struct device *dev)
 548{
 549        struct xilinx_drm_private *private = dev_get_drvdata(dev);
 550        struct drm_device *drm = private->drm;
 551        struct drm_connector *connector;
 552
 553        if (!console_suspend_enabled)
 554                return 0;
 555
 556        drm_modeset_lock_all(drm);
 557        list_for_each_entry(connector, &drm->mode_config.connector_list, head) {
 558                if (connector->funcs->dpms) {
 559                        int dpms = connector->dpms;
 560
 561                        connector->dpms = DRM_MODE_DPMS_OFF;
 562                        connector->funcs->dpms(connector, dpms);
 563                }
 564        }
 565        drm_modeset_unlock_all(drm);
 566
 567        drm_helper_resume_force_mode(drm);
 568
 569        drm_modeset_lock_all(drm);
 570        drm_kms_helper_poll_enable_locked(drm);
 571        drm_modeset_unlock_all(drm);
 572
 573        return 0;
 574}
 575#endif
 576
 577static const struct dev_pm_ops xilinx_drm_pm_ops = {
 578        SET_SYSTEM_SLEEP_PM_OPS(xilinx_drm_pm_suspend, xilinx_drm_pm_resume)
 579};
 580
 581/* init xilinx drm platform */
 582static int xilinx_drm_platform_probe(struct platform_device *pdev)
 583{
 584        return drm_platform_init(&xilinx_drm_driver, pdev);
 585}
 586
 587/* exit xilinx drm platform */
 588static int xilinx_drm_platform_remove(struct platform_device *pdev)
 589{
 590        struct xilinx_drm_private *private = platform_get_drvdata(pdev);
 591
 592        drm_put_dev(private->drm);
 593
 594        return 0;
 595}
 596
 597static void xilinx_drm_platform_shutdown(struct platform_device *pdev)
 598{
 599        struct xilinx_drm_private *private = platform_get_drvdata(pdev);
 600
 601        drm_put_dev(private->drm);
 602}
 603
 604static const struct of_device_id xilinx_drm_of_match[] = {
 605        { .compatible = "xlnx,drm", },
 606        { /* end of table */ },
 607};
 608MODULE_DEVICE_TABLE(of, xilinx_drm_of_match);
 609
 610static struct platform_driver xilinx_drm_private_driver = {
 611        .probe                  = xilinx_drm_platform_probe,
 612        .remove                 = xilinx_drm_platform_remove,
 613        .shutdown               = xilinx_drm_platform_shutdown,
 614        .driver                 = {
 615                .name           = "xilinx-drm",
 616                .pm             = &xilinx_drm_pm_ops,
 617                .of_match_table = xilinx_drm_of_match,
 618        },
 619};
 620
 621module_platform_driver(xilinx_drm_private_driver);
 622
 623MODULE_AUTHOR("Xilinx, Inc.");
 624MODULE_DESCRIPTION("Xilinx DRM KMS Driver");
 625MODULE_LICENSE("GPL v2");
 626