linux/drivers/gpu/drm/sprd/sprd_drm.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (C) 2020 Unisoc Inc.
   4 */
   5
   6#include <linux/component.h>
   7#include <linux/dma-mapping.h>
   8#include <linux/module.h>
   9#include <linux/mutex.h>
  10#include <linux/of_graph.h>
  11#include <linux/of_platform.h>
  12
  13#include <drm/drm_atomic_helper.h>
  14#include <drm/drm_crtc_helper.h>
  15#include <drm/drm_drv.h>
  16#include <drm/drm_gem_cma_helper.h>
  17#include <drm/drm_gem_framebuffer_helper.h>
  18#include <drm/drm_of.h>
  19#include <drm/drm_probe_helper.h>
  20#include <drm/drm_vblank.h>
  21
  22#include "sprd_drm.h"
  23
  24#define DRIVER_NAME     "sprd"
  25#define DRIVER_DESC     "Spreadtrum SoCs' DRM Driver"
  26#define DRIVER_DATE     "20200201"
  27#define DRIVER_MAJOR    1
  28#define DRIVER_MINOR    0
  29
  30static const struct drm_mode_config_helper_funcs sprd_drm_mode_config_helper = {
  31        .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm,
  32};
  33
  34static const struct drm_mode_config_funcs sprd_drm_mode_config_funcs = {
  35        .fb_create = drm_gem_fb_create,
  36        .atomic_check = drm_atomic_helper_check,
  37        .atomic_commit = drm_atomic_helper_commit,
  38};
  39
  40static void sprd_drm_mode_config_init(struct drm_device *drm)
  41{
  42        drm->mode_config.min_width = 0;
  43        drm->mode_config.min_height = 0;
  44        drm->mode_config.max_width = 8192;
  45        drm->mode_config.max_height = 8192;
  46        drm->mode_config.allow_fb_modifiers = true;
  47
  48        drm->mode_config.funcs = &sprd_drm_mode_config_funcs;
  49        drm->mode_config.helper_private = &sprd_drm_mode_config_helper;
  50}
  51
  52DEFINE_DRM_GEM_CMA_FOPS(sprd_drm_fops);
  53
  54static struct drm_driver sprd_drm_drv = {
  55        .driver_features        = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
  56        .fops                   = &sprd_drm_fops,
  57
  58        /* GEM Operations */
  59        DRM_GEM_CMA_DRIVER_OPS,
  60
  61        .name                   = DRIVER_NAME,
  62        .desc                   = DRIVER_DESC,
  63        .date                   = DRIVER_DATE,
  64        .major                  = DRIVER_MAJOR,
  65        .minor                  = DRIVER_MINOR,
  66};
  67
  68static int sprd_drm_bind(struct device *dev)
  69{
  70        struct platform_device *pdev = to_platform_device(dev);
  71        struct drm_device *drm;
  72        struct sprd_drm *sprd;
  73        int ret;
  74
  75        sprd = devm_drm_dev_alloc(dev, &sprd_drm_drv, struct sprd_drm, drm);
  76        if (IS_ERR(sprd))
  77                return PTR_ERR(sprd);
  78
  79        drm = &sprd->drm;
  80        platform_set_drvdata(pdev, drm);
  81
  82        ret = drmm_mode_config_init(drm);
  83        if (ret)
  84                return ret;
  85
  86        sprd_drm_mode_config_init(drm);
  87
  88        /* bind and init sub drivers */
  89        ret = component_bind_all(drm->dev, drm);
  90        if (ret) {
  91                drm_err(drm, "failed to bind all component.\n");
  92                return ret;
  93        }
  94
  95        /* vblank init */
  96        ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
  97        if (ret) {
  98                drm_err(drm, "failed to initialize vblank.\n");
  99                goto err_unbind_all;
 100        }
 101
 102        /* reset all the states of crtc/plane/encoder/connector */
 103        drm_mode_config_reset(drm);
 104
 105        /* init kms poll for handling hpd */
 106        drm_kms_helper_poll_init(drm);
 107
 108        ret = drm_dev_register(drm, 0);
 109        if (ret < 0)
 110                goto err_kms_helper_poll_fini;
 111
 112        return 0;
 113
 114err_kms_helper_poll_fini:
 115        drm_kms_helper_poll_fini(drm);
 116err_unbind_all:
 117        component_unbind_all(drm->dev, drm);
 118        return ret;
 119}
 120
 121static void sprd_drm_unbind(struct device *dev)
 122{
 123        struct drm_device *drm = dev_get_drvdata(dev);
 124
 125        drm_dev_unregister(drm);
 126
 127        drm_kms_helper_poll_fini(drm);
 128
 129        component_unbind_all(drm->dev, drm);
 130}
 131
 132static const struct component_master_ops drm_component_ops = {
 133        .bind = sprd_drm_bind,
 134        .unbind = sprd_drm_unbind,
 135};
 136
 137static int compare_of(struct device *dev, void *data)
 138{
 139        return dev->of_node == data;
 140}
 141
 142static int sprd_drm_probe(struct platform_device *pdev)
 143{
 144        return drm_of_component_probe(&pdev->dev, compare_of, &drm_component_ops);
 145}
 146
 147static int sprd_drm_remove(struct platform_device *pdev)
 148{
 149        component_master_del(&pdev->dev, &drm_component_ops);
 150        return 0;
 151}
 152
 153static void sprd_drm_shutdown(struct platform_device *pdev)
 154{
 155        struct drm_device *drm = platform_get_drvdata(pdev);
 156
 157        if (!drm) {
 158                drm_warn(drm, "drm device is not available, no shutdown\n");
 159                return;
 160        }
 161
 162        drm_atomic_helper_shutdown(drm);
 163}
 164
 165static const struct of_device_id drm_match_table[] = {
 166        { .compatible = "sprd,display-subsystem", },
 167        { /* sentinel */ },
 168};
 169MODULE_DEVICE_TABLE(of, drm_match_table);
 170
 171static struct platform_driver sprd_drm_driver = {
 172        .probe = sprd_drm_probe,
 173        .remove = sprd_drm_remove,
 174        .shutdown = sprd_drm_shutdown,
 175        .driver = {
 176                .name = "sprd-drm-drv",
 177                .of_match_table = drm_match_table,
 178        },
 179};
 180
 181static struct platform_driver *sprd_drm_drivers[]  = {
 182        &sprd_drm_driver,
 183        &sprd_dpu_driver,
 184        &sprd_dsi_driver,
 185};
 186
 187static int __init sprd_drm_init(void)
 188{
 189        return platform_register_drivers(sprd_drm_drivers,
 190                                        ARRAY_SIZE(sprd_drm_drivers));
 191}
 192
 193static void __exit sprd_drm_exit(void)
 194{
 195        platform_unregister_drivers(sprd_drm_drivers,
 196                                    ARRAY_SIZE(sprd_drm_drivers));
 197}
 198
 199module_init(sprd_drm_init);
 200module_exit(sprd_drm_exit);
 201
 202MODULE_AUTHOR("Leon He <leon.he@unisoc.com>");
 203MODULE_AUTHOR("Kevin Tang <kevin.tang@unisoc.com>");
 204MODULE_DESCRIPTION("Unisoc DRM KMS Master Driver");
 205MODULE_LICENSE("GPL v2");
 206