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