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