linux/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c
<<
>>
Prefs
   1/*
   2 * Hisilicon Kirin SoCs drm master driver
   3 *
   4 * Copyright (c) 2016 Linaro Limited.
   5 * Copyright (c) 2014-2016 Hisilicon Limited.
   6 *
   7 * Author:
   8 *      Xinliang Liu <z.liuxinliang@hisilicon.com>
   9 *      Xinliang Liu <xinliang.liu@linaro.org>
  10 *      Xinwei Kong <kong.kongxinwei@hisilicon.com>
  11 *
  12 * This program is free software; you can redistribute it and/or modify
  13 * it under the terms of the GNU General Public License version 2 as
  14 * published by the Free Software Foundation.
  15 *
  16 */
  17
  18#include <linux/of_platform.h>
  19#include <linux/component.h>
  20#include <linux/of_graph.h>
  21
  22#include <drm/drmP.h>
  23#include <drm/drm_gem_cma_helper.h>
  24#include <drm/drm_fb_cma_helper.h>
  25#include <drm/drm_gem_framebuffer_helper.h>
  26#include <drm/drm_atomic_helper.h>
  27#include <drm/drm_crtc_helper.h>
  28#include <drm/drm_of.h>
  29
  30#include "kirin_drm_drv.h"
  31
  32static struct kirin_dc_ops *dc_ops;
  33
  34static int kirin_drm_kms_cleanup(struct drm_device *dev)
  35{
  36        struct kirin_drm_private *priv = dev->dev_private;
  37
  38        if (priv->fbdev) {
  39                drm_fbdev_cma_fini(priv->fbdev);
  40                priv->fbdev = NULL;
  41        }
  42
  43        drm_kms_helper_poll_fini(dev);
  44        dc_ops->cleanup(to_platform_device(dev->dev));
  45        drm_mode_config_cleanup(dev);
  46        devm_kfree(dev->dev, priv);
  47        dev->dev_private = NULL;
  48
  49        return 0;
  50}
  51
  52static void kirin_fbdev_output_poll_changed(struct drm_device *dev)
  53{
  54        struct kirin_drm_private *priv = dev->dev_private;
  55
  56        drm_fbdev_cma_hotplug_event(priv->fbdev);
  57}
  58
  59static const struct drm_mode_config_funcs kirin_drm_mode_config_funcs = {
  60        .fb_create = drm_gem_fb_create,
  61        .output_poll_changed = kirin_fbdev_output_poll_changed,
  62        .atomic_check = drm_atomic_helper_check,
  63        .atomic_commit = drm_atomic_helper_commit,
  64};
  65
  66static void kirin_drm_mode_config_init(struct drm_device *dev)
  67{
  68        dev->mode_config.min_width = 0;
  69        dev->mode_config.min_height = 0;
  70
  71        dev->mode_config.max_width = 2048;
  72        dev->mode_config.max_height = 2048;
  73
  74        dev->mode_config.funcs = &kirin_drm_mode_config_funcs;
  75}
  76
  77static int kirin_drm_kms_init(struct drm_device *dev)
  78{
  79        struct kirin_drm_private *priv;
  80        int ret;
  81
  82        priv = devm_kzalloc(dev->dev, sizeof(*priv), GFP_KERNEL);
  83        if (!priv)
  84                return -ENOMEM;
  85
  86        dev->dev_private = priv;
  87        dev_set_drvdata(dev->dev, dev);
  88
  89        /* dev->mode_config initialization */
  90        drm_mode_config_init(dev);
  91        kirin_drm_mode_config_init(dev);
  92
  93        /* display controller init */
  94        ret = dc_ops->init(to_platform_device(dev->dev));
  95        if (ret)
  96                goto err_mode_config_cleanup;
  97
  98        /* bind and init sub drivers */
  99        ret = component_bind_all(dev->dev, dev);
 100        if (ret) {
 101                DRM_ERROR("failed to bind all component.\n");
 102                goto err_dc_cleanup;
 103        }
 104
 105        /* vblank init */
 106        ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
 107        if (ret) {
 108                DRM_ERROR("failed to initialize vblank.\n");
 109                goto err_unbind_all;
 110        }
 111        /* with irq_enabled = true, we can use the vblank feature. */
 112        dev->irq_enabled = true;
 113
 114        /* reset all the states of crtc/plane/encoder/connector */
 115        drm_mode_config_reset(dev);
 116
 117        /* init kms poll for handling hpd */
 118        drm_kms_helper_poll_init(dev);
 119
 120        priv->fbdev = drm_fbdev_cma_init(dev, 32,
 121                                         dev->mode_config.num_connector);
 122
 123        if (IS_ERR(priv->fbdev)) {
 124                DRM_ERROR("failed to initialize fbdev.\n");
 125                ret = PTR_ERR(priv->fbdev);
 126                goto err_cleanup_poll;
 127        }
 128        return 0;
 129
 130err_cleanup_poll:
 131        drm_kms_helper_poll_fini(dev);
 132err_unbind_all:
 133        component_unbind_all(dev->dev, dev);
 134err_dc_cleanup:
 135        dc_ops->cleanup(to_platform_device(dev->dev));
 136err_mode_config_cleanup:
 137        drm_mode_config_cleanup(dev);
 138        devm_kfree(dev->dev, priv);
 139        dev->dev_private = NULL;
 140
 141        return ret;
 142}
 143
 144DEFINE_DRM_GEM_CMA_FOPS(kirin_drm_fops);
 145
 146static int kirin_gem_cma_dumb_create(struct drm_file *file,
 147                                     struct drm_device *dev,
 148                                     struct drm_mode_create_dumb *args)
 149{
 150        return drm_gem_cma_dumb_create_internal(file, dev, args);
 151}
 152
 153static struct drm_driver kirin_drm_driver = {
 154        .driver_features        = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
 155                                  DRIVER_ATOMIC,
 156        .fops                   = &kirin_drm_fops,
 157
 158        .gem_free_object_unlocked = drm_gem_cma_free_object,
 159        .gem_vm_ops             = &drm_gem_cma_vm_ops,
 160        .dumb_create            = kirin_gem_cma_dumb_create,
 161
 162        .prime_handle_to_fd     = drm_gem_prime_handle_to_fd,
 163        .prime_fd_to_handle     = drm_gem_prime_fd_to_handle,
 164        .gem_prime_export       = drm_gem_prime_export,
 165        .gem_prime_import       = drm_gem_prime_import,
 166        .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
 167        .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
 168        .gem_prime_vmap         = drm_gem_cma_prime_vmap,
 169        .gem_prime_vunmap       = drm_gem_cma_prime_vunmap,
 170        .gem_prime_mmap         = drm_gem_cma_prime_mmap,
 171
 172        .name                   = "kirin",
 173        .desc                   = "Hisilicon Kirin SoCs' DRM Driver",
 174        .date                   = "20150718",
 175        .major                  = 1,
 176        .minor                  = 0,
 177};
 178
 179static int compare_of(struct device *dev, void *data)
 180{
 181        return dev->of_node == data;
 182}
 183
 184static int kirin_drm_bind(struct device *dev)
 185{
 186        struct drm_driver *driver = &kirin_drm_driver;
 187        struct drm_device *drm_dev;
 188        int ret;
 189
 190        drm_dev = drm_dev_alloc(driver, dev);
 191        if (IS_ERR(drm_dev))
 192                return PTR_ERR(drm_dev);
 193
 194        ret = kirin_drm_kms_init(drm_dev);
 195        if (ret)
 196                goto err_drm_dev_unref;
 197
 198        ret = drm_dev_register(drm_dev, 0);
 199        if (ret)
 200                goto err_kms_cleanup;
 201
 202        return 0;
 203
 204err_kms_cleanup:
 205        kirin_drm_kms_cleanup(drm_dev);
 206err_drm_dev_unref:
 207        drm_dev_unref(drm_dev);
 208
 209        return ret;
 210}
 211
 212static void kirin_drm_unbind(struct device *dev)
 213{
 214        struct drm_device *drm_dev = dev_get_drvdata(dev);
 215
 216        drm_dev_unregister(drm_dev);
 217        kirin_drm_kms_cleanup(drm_dev);
 218        drm_dev_unref(drm_dev);
 219}
 220
 221static const struct component_master_ops kirin_drm_ops = {
 222        .bind = kirin_drm_bind,
 223        .unbind = kirin_drm_unbind,
 224};
 225
 226static int kirin_drm_platform_probe(struct platform_device *pdev)
 227{
 228        struct device *dev = &pdev->dev;
 229        struct device_node *np = dev->of_node;
 230        struct component_match *match = NULL;
 231        struct device_node *remote;
 232
 233        dc_ops = (struct kirin_dc_ops *)of_device_get_match_data(dev);
 234        if (!dc_ops) {
 235                DRM_ERROR("failed to get dt id data\n");
 236                return -EINVAL;
 237        }
 238
 239        remote = of_graph_get_remote_node(np, 0, 0);
 240        if (!remote)
 241                return -ENODEV;
 242
 243        drm_of_component_match_add(dev, &match, compare_of, remote);
 244        of_node_put(remote);
 245
 246        return component_master_add_with_match(dev, &kirin_drm_ops, match);
 247
 248        return 0;
 249}
 250
 251static int kirin_drm_platform_remove(struct platform_device *pdev)
 252{
 253        component_master_del(&pdev->dev, &kirin_drm_ops);
 254        dc_ops = NULL;
 255        return 0;
 256}
 257
 258static const struct of_device_id kirin_drm_dt_ids[] = {
 259        { .compatible = "hisilicon,hi6220-ade",
 260          .data = &ade_dc_ops,
 261        },
 262        { /* end node */ },
 263};
 264MODULE_DEVICE_TABLE(of, kirin_drm_dt_ids);
 265
 266static struct platform_driver kirin_drm_platform_driver = {
 267        .probe = kirin_drm_platform_probe,
 268        .remove = kirin_drm_platform_remove,
 269        .driver = {
 270                .name = "kirin-drm",
 271                .of_match_table = kirin_drm_dt_ids,
 272        },
 273};
 274
 275module_platform_driver(kirin_drm_platform_driver);
 276
 277MODULE_AUTHOR("Xinliang Liu <xinliang.liu@linaro.org>");
 278MODULE_AUTHOR("Xinliang Liu <z.liuxinliang@hisilicon.com>");
 279MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>");
 280MODULE_DESCRIPTION("hisilicon Kirin SoCs' DRM master driver");
 281MODULE_LICENSE("GPL v2");
 282