linux/drivers/gpu/drm/xylon/xylon_drv.c
<<
>>
Prefs
   1/*
   2 * Xylon DRM driver functions
   3 *
   4 * Copyright (C) 2014 Xylon d.o.o.
   5 * Author: Davor Joja <davor.joja@logicbricks.com>
   6 *
   7 * Based on Xilinx DRM driver.
   8 * Copyright (C) 2013 Xilinx, Inc.
   9 *
  10 * This software is licensed under the terms of the GNU General Public
  11 * License version 2, as published by the Free Software Foundation, and
  12 * may be copied, distributed, and modified under those terms.
  13 *
  14 * This program is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17 * GNU General Public License for more details.
  18 */
  19
  20#include <drm/drmP.h>
  21#include <drm/drm_crtc_helper.h>
  22#include <drm/drm_gem_cma_helper.h>
  23
  24#include <linux/device.h>
  25#include <linux/module.h>
  26#include <linux/platform_device.h>
  27
  28#include "xylon_connector.h"
  29#include "xylon_crtc.h"
  30#include "xylon_drv.h"
  31#include "xylon_encoder.h"
  32#include "xylon_fb.h"
  33#include "xylon_fbdev.h"
  34#include "xylon_irq.h"
  35
  36#define DEVICE_NAME "logicvc"
  37
  38#define DRIVER_NAME "xylon-drm"
  39#define DRIVER_DESCRIPTION "Xylon DRM driver for logiCVC IP core"
  40#define DRIVER_VERSION "1.1"
  41#define DRIVER_DATE "20140701"
  42
  43#define DRIVER_MAJOR 1
  44#define DRIVER_MINOR 0
  45
  46static int xylon_drm_load(struct drm_device *dev, unsigned long flags)
  47{
  48        struct platform_device *pdev = dev->platformdev;
  49        struct xylon_drm_device *xdev;
  50        unsigned int bpp;
  51        int ret;
  52
  53        xdev = devm_kzalloc(dev->dev, sizeof(*xdev), GFP_KERNEL);
  54        if (!xdev)
  55                return -ENOMEM;
  56        xdev->dev = dev;
  57
  58        dev->dev_private = xdev;
  59
  60        drm_mode_config_init(dev);
  61
  62        drm_kms_helper_poll_init(dev);
  63
  64        xdev->crtc = xylon_drm_crtc_create(dev);
  65        if (IS_ERR(xdev->crtc)) {
  66                DRM_ERROR("failed create xylon crtc\n");
  67                ret = PTR_ERR(xdev->crtc);
  68                goto err_out;
  69        }
  70
  71        xylon_drm_mode_config_init(dev);
  72
  73        xdev->encoder = xylon_drm_encoder_create(dev);
  74        if (IS_ERR(xdev->encoder)) {
  75                DRM_ERROR("failed create xylon encoder\n");
  76                ret = PTR_ERR(xdev->encoder);
  77                goto err_out;
  78        }
  79
  80        xdev->connector = xylon_drm_connector_create(dev, xdev->encoder);
  81        if (IS_ERR(xdev->connector)) {
  82                DRM_ERROR("failed create xylon connector\n");
  83                ret = PTR_ERR(xdev->connector);
  84                goto err_out;
  85        }
  86
  87        ret = drm_vblank_init(dev, 1);
  88        if (ret) {
  89                DRM_ERROR("failed initialize vblank\n");
  90                goto err_out;
  91        }
  92        dev->vblank_disable_allowed = 1;
  93
  94        ret = xylon_drm_irq_install(dev);
  95        if (ret < 0) {
  96                DRM_ERROR("failed install irq\n");
  97                goto err_irq;
  98        }
  99
 100        ret = xylon_drm_crtc_get_param(xdev->crtc, &bpp,
 101                                       XYLON_DRM_CRTC_BUFF_BPP);
 102        if (ret) {
 103                DRM_ERROR("failed get bpp\n");
 104                goto err_fbdev;
 105        }
 106        xdev->fbdev = xylon_drm_fbdev_init(dev, bpp, 1, 1);
 107        if (IS_ERR(xdev->fbdev)) {
 108                DRM_ERROR("failed initialize fbdev\n");
 109                ret = PTR_ERR(xdev->fbdev);
 110                goto err_fbdev;
 111        }
 112
 113        drm_helper_disable_unused_functions(dev);
 114
 115        platform_set_drvdata(pdev, xdev);
 116
 117        return 0;
 118
 119err_fbdev:
 120        xylon_drm_irq_uninstall(dev);
 121err_irq:
 122        drm_vblank_cleanup(dev);
 123err_out:
 124        drm_mode_config_cleanup(dev);
 125
 126        if (ret == -EPROBE_DEFER)
 127                DRM_INFO("driver load deferred, will be called again\n");
 128
 129        return ret;
 130}
 131
 132static int xylon_drm_unload(struct drm_device *dev)
 133{
 134        struct xylon_drm_device *xdev = dev->dev_private;
 135
 136        xylon_drm_irq_uninstall(dev);
 137
 138        drm_vblank_cleanup(dev);
 139
 140        drm_kms_helper_poll_fini(dev);
 141
 142        xylon_drm_fbdev_fini(xdev->fbdev);
 143
 144        drm_mode_config_cleanup(dev);
 145
 146        return 0;
 147}
 148
 149static void xylon_drm_preclose(struct drm_device *dev, struct drm_file *file)
 150{
 151        struct xylon_drm_device *xdev = dev->dev_private;
 152
 153        xylon_drm_crtc_cancel_page_flip(xdev->crtc, file);
 154}
 155
 156static void xylon_drm_postclose(struct drm_device *dev, struct drm_file *file)
 157{
 158}
 159
 160static void xylon_drm_lastclose(struct drm_device *dev)
 161{
 162        struct xylon_drm_device *xdev = dev->dev_private;
 163
 164        xylon_drm_crtc_properties_restore(xdev->crtc);
 165
 166        xylon_drm_fbdev_restore_mode(xdev->fbdev);
 167}
 168
 169static int xylon_drm_vblank_enable(struct drm_device *dev, int crtc)
 170{
 171        struct xylon_drm_device *xdev = dev->dev_private;
 172
 173        xylon_drm_crtc_vblank(xdev->crtc, true);
 174
 175        return 0;
 176}
 177
 178static void xylon_drm_vblank_disable(struct drm_device *dev, int crtc)
 179{
 180        struct xylon_drm_device *xdev = dev->dev_private;
 181
 182        xylon_drm_crtc_vblank(xdev->crtc, false);
 183}
 184
 185static int xylon_drm_gem_dumb_create(struct drm_file *file_priv,
 186                                     struct drm_device *dev,
 187                                     struct drm_mode_create_dumb *args)
 188{
 189        struct drm_gem_cma_object *cma_obj;
 190        struct drm_gem_object *gem_obj;
 191        struct xylon_drm_device *xdev = dev->dev_private;
 192        unsigned int buff_width;
 193        int ret;
 194
 195        ret = xylon_drm_crtc_get_param(xdev->crtc, &buff_width,
 196                                       XYLON_DRM_CRTC_BUFF_WIDTH);
 197        if (ret)
 198                return ret;
 199
 200        args->pitch = buff_width * DIV_ROUND_UP(args->bpp, 8);
 201        args->size = (u64)(buff_width * DIV_ROUND_UP(args->bpp, 8) *
 202                           args->height);
 203
 204        cma_obj = drm_gem_cma_create(dev, (unsigned int)args->size);
 205        if (IS_ERR(cma_obj))
 206                return PTR_ERR(cma_obj);
 207
 208        gem_obj = &cma_obj->base;
 209
 210        ret = drm_gem_handle_create(file_priv, gem_obj, &args->handle);
 211        if (ret)
 212                goto err_handle_create;
 213
 214        drm_gem_object_unreference_unlocked(gem_obj);
 215
 216        return PTR_ERR_OR_ZERO(cma_obj);
 217
 218err_handle_create:
 219        drm_gem_cma_free_object(gem_obj);
 220
 221        return ret;
 222}
 223
 224static const struct file_operations xylon_drm_fops = {
 225        .owner = THIS_MODULE,
 226        .open = drm_open,
 227        .release = drm_release,
 228        .unlocked_ioctl = drm_ioctl,
 229        .mmap = drm_gem_cma_mmap,
 230        .poll = drm_poll,
 231        .read = drm_read,
 232#ifdef CONFIG_COMPAT
 233        .compat_ioctl = drm_compat_ioctl,
 234#endif
 235        .llseek = noop_llseek,
 236};
 237
 238static struct drm_driver xylon_drm_driver = {
 239        .driver_features = DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED |
 240                           DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME,
 241        .load = xylon_drm_load,
 242        .unload = xylon_drm_unload,
 243        .preclose = xylon_drm_preclose,
 244        .postclose = xylon_drm_postclose,
 245        .lastclose = xylon_drm_lastclose,
 246
 247        .get_vblank_counter = drm_vblank_count,
 248        .enable_vblank = xylon_drm_vblank_enable,
 249        .disable_vblank = xylon_drm_vblank_disable,
 250
 251        .irq_preinstall = xylon_drm_irq_preinst,
 252        .irq_postinstall = xylon_drm_irq_postinst,
 253        .irq_uninstall = xylon_drm_irq_uninst,
 254        .irq_handler = xylon_drm_irq_handler,
 255
 256        .gem_free_object = drm_gem_cma_free_object,
 257
 258        .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
 259        .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
 260        .gem_prime_export = drm_gem_prime_export,
 261        .gem_prime_import = drm_gem_prime_import,
 262        .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
 263        .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
 264        .gem_prime_vmap = drm_gem_cma_prime_vmap,
 265        .gem_prime_vunmap = drm_gem_cma_prime_vunmap,
 266        .gem_prime_mmap = drm_gem_cma_prime_mmap,
 267
 268        .dumb_create = xylon_drm_gem_dumb_create,
 269        .dumb_map_offset = drm_gem_cma_dumb_map_offset,
 270        .dumb_destroy = drm_gem_dumb_destroy,
 271
 272        .gem_vm_ops = &drm_gem_cma_vm_ops,
 273
 274        .fops = &xylon_drm_fops,
 275
 276        .name = DRIVER_NAME,
 277        .desc = DRIVER_DESCRIPTION,
 278        .date = DRIVER_DATE,
 279        .major = DRIVER_MAJOR,
 280        .minor = DRIVER_MINOR,
 281};
 282
 283static int __maybe_unused xylon_drm_pm_suspend(struct device *dev)
 284{
 285        struct xylon_drm_device *xdev = dev_get_drvdata(dev);
 286
 287        drm_kms_helper_poll_disable(xdev->dev);
 288        drm_helper_connector_dpms(xdev->connector, DRM_MODE_DPMS_SUSPEND);
 289
 290        return 0;
 291}
 292
 293static int __maybe_unused xylon_drm_pm_resume(struct device *dev)
 294{
 295        struct xylon_drm_device *xdev = dev_get_drvdata(dev);
 296
 297        drm_helper_connector_dpms(xdev->connector, DRM_MODE_DPMS_ON);
 298        drm_kms_helper_poll_enable(xdev->dev);
 299
 300        return 0;
 301}
 302
 303static const struct dev_pm_ops xylon_drm_pm_ops = {
 304        SET_SYSTEM_SLEEP_PM_OPS(xylon_drm_pm_suspend, xylon_drm_pm_resume)
 305        SET_RUNTIME_PM_OPS(xylon_drm_pm_suspend, xylon_drm_pm_resume, NULL)
 306};
 307
 308static int xylon_drm_platform_probe(struct platform_device *pdev)
 309{
 310        return drm_platform_init(&xylon_drm_driver, pdev);
 311}
 312
 313static int xylon_drm_platform_remove(struct platform_device *pdev)
 314{
 315        struct xylon_drm_device *xdev = platform_get_drvdata(pdev);
 316
 317        drm_put_dev(xdev->dev);
 318
 319        return 0;
 320}
 321
 322static const struct of_device_id xylon_drm_of_match[] = {
 323        { .compatible = "xylon,drm-1.00.a", },
 324        { /* end of table */ },
 325};
 326MODULE_DEVICE_TABLE(of, xylon_drm_of_match);
 327
 328static struct platform_driver xylon_drm_platform_driver = {
 329        .probe = xylon_drm_platform_probe,
 330        .remove = xylon_drm_platform_remove,
 331        .driver = {
 332                .name = DRIVER_NAME,
 333                .pm = &xylon_drm_pm_ops,
 334                .of_match_table = xylon_drm_of_match,
 335        },
 336};
 337
 338module_platform_driver(xylon_drm_platform_driver);
 339
 340MODULE_AUTHOR("Xylon d.o.o.");
 341MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
 342MODULE_LICENSE("GPL v2");
 343