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