1
2
3
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
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
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
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
103 drm_mode_config_reset(drm);
104
105
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 { },
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