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