Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/gpu/drm/armada/armada_drv.c
26482 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* Copyright (C) 2012 Russell King
4
*/
5
6
#include <linux/aperture.h>
7
#include <linux/clk.h>
8
#include <linux/component.h>
9
#include <linux/module.h>
10
#include <linux/of.h>
11
#include <linux/of_graph.h>
12
#include <linux/platform_device.h>
13
14
#include <drm/clients/drm_client_setup.h>
15
#include <drm/drm_atomic_helper.h>
16
#include <drm/drm_drv.h>
17
#include <drm/drm_ioctl.h>
18
#include <drm/drm_managed.h>
19
#include <drm/drm_prime.h>
20
#include <drm/drm_probe_helper.h>
21
#include <drm/drm_of.h>
22
#include <drm/drm_vblank.h>
23
24
#include "armada_crtc.h"
25
#include "armada_drm.h"
26
#include "armada_gem.h"
27
#include "armada_fb.h"
28
#include "armada_hw.h"
29
#include <drm/armada_drm.h>
30
#include "armada_ioctlP.h"
31
32
static const struct drm_ioctl_desc armada_ioctls[] = {
33
DRM_IOCTL_DEF_DRV(ARMADA_GEM_CREATE, armada_gem_create_ioctl,0),
34
DRM_IOCTL_DEF_DRV(ARMADA_GEM_MMAP, armada_gem_mmap_ioctl, 0),
35
DRM_IOCTL_DEF_DRV(ARMADA_GEM_PWRITE, armada_gem_pwrite_ioctl, 0),
36
};
37
38
DEFINE_DRM_GEM_FOPS(armada_drm_fops);
39
40
static const struct drm_driver armada_drm_driver = {
41
.gem_prime_import = armada_gem_prime_import,
42
.dumb_create = armada_gem_dumb_create,
43
ARMADA_FBDEV_DRIVER_OPS,
44
.major = 1,
45
.minor = 0,
46
.name = "armada-drm",
47
.desc = "Armada SoC DRM",
48
.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
49
.ioctls = armada_ioctls,
50
.num_ioctls = ARRAY_SIZE(armada_ioctls),
51
.fops = &armada_drm_fops,
52
};
53
54
static const struct drm_mode_config_funcs armada_drm_mode_config_funcs = {
55
.fb_create = armada_fb_create,
56
.atomic_check = drm_atomic_helper_check,
57
.atomic_commit = drm_atomic_helper_commit,
58
};
59
60
static int armada_drm_bind(struct device *dev)
61
{
62
struct armada_private *priv;
63
struct resource *mem = NULL;
64
int ret, n;
65
66
for (n = 0; ; n++) {
67
struct resource *r = platform_get_resource(to_platform_device(dev),
68
IORESOURCE_MEM, n);
69
if (!r)
70
break;
71
72
/* Resources above 64K are graphics memory */
73
if (resource_size(r) > SZ_64K)
74
mem = r;
75
else
76
return -EINVAL;
77
}
78
79
if (!mem)
80
return -ENXIO;
81
82
if (!devm_request_mem_region(dev, mem->start, resource_size(mem),
83
"armada-drm"))
84
return -EBUSY;
85
86
priv = devm_drm_dev_alloc(dev, &armada_drm_driver,
87
struct armada_private, drm);
88
if (IS_ERR(priv)) {
89
dev_err(dev, "[" DRM_NAME ":%s] devm_drm_dev_alloc failed: %li\n",
90
__func__, PTR_ERR(priv));
91
return PTR_ERR(priv);
92
}
93
94
/* Remove early framebuffers */
95
ret = aperture_remove_all_conflicting_devices(armada_drm_driver.name);
96
if (ret) {
97
dev_err(dev, "[" DRM_NAME ":%s] can't kick out simple-fb: %d\n",
98
__func__, ret);
99
return ret;
100
}
101
102
dev_set_drvdata(dev, &priv->drm);
103
104
/* Mode setting support */
105
drm_mode_config_init(&priv->drm);
106
priv->drm.mode_config.min_width = 320;
107
priv->drm.mode_config.min_height = 200;
108
109
/*
110
* With vscale enabled, the maximum width is 1920 due to the
111
* 1920 by 3 lines RAM
112
*/
113
priv->drm.mode_config.max_width = 1920;
114
priv->drm.mode_config.max_height = 2048;
115
116
priv->drm.mode_config.preferred_depth = 24;
117
priv->drm.mode_config.funcs = &armada_drm_mode_config_funcs;
118
drm_mm_init(&priv->linear, mem->start, resource_size(mem));
119
mutex_init(&priv->linear_lock);
120
121
ret = component_bind_all(dev, &priv->drm);
122
if (ret)
123
goto err_kms;
124
125
ret = drm_vblank_init(&priv->drm, priv->drm.mode_config.num_crtc);
126
if (ret)
127
goto err_comp;
128
129
drm_mode_config_reset(&priv->drm);
130
131
drm_kms_helper_poll_init(&priv->drm);
132
133
ret = drm_dev_register(&priv->drm, 0);
134
if (ret)
135
goto err_poll;
136
137
#ifdef CONFIG_DEBUG_FS
138
armada_drm_debugfs_init(priv->drm.primary);
139
#endif
140
141
drm_client_setup(&priv->drm, NULL);
142
143
return 0;
144
145
err_poll:
146
drm_kms_helper_poll_fini(&priv->drm);
147
err_comp:
148
component_unbind_all(dev, &priv->drm);
149
err_kms:
150
drm_mode_config_cleanup(&priv->drm);
151
drm_mm_takedown(&priv->linear);
152
dev_set_drvdata(dev, NULL);
153
return ret;
154
}
155
156
static void armada_drm_unbind(struct device *dev)
157
{
158
struct drm_device *drm = dev_get_drvdata(dev);
159
struct armada_private *priv = drm_to_armada_dev(drm);
160
161
drm_kms_helper_poll_fini(&priv->drm);
162
163
drm_dev_unregister(&priv->drm);
164
165
drm_atomic_helper_shutdown(&priv->drm);
166
167
component_unbind_all(dev, &priv->drm);
168
169
drm_mode_config_cleanup(&priv->drm);
170
drm_mm_takedown(&priv->linear);
171
dev_set_drvdata(dev, NULL);
172
}
173
174
static void armada_add_endpoints(struct device *dev,
175
struct component_match **match, struct device_node *dev_node)
176
{
177
struct device_node *ep, *remote;
178
179
for_each_endpoint_of_node(dev_node, ep) {
180
remote = of_graph_get_remote_port_parent(ep);
181
if (remote && of_device_is_available(remote))
182
drm_of_component_match_add(dev, match, component_compare_of,
183
remote);
184
of_node_put(remote);
185
}
186
}
187
188
static const struct component_master_ops armada_master_ops = {
189
.bind = armada_drm_bind,
190
.unbind = armada_drm_unbind,
191
};
192
193
static int armada_drm_probe(struct platform_device *pdev)
194
{
195
struct component_match *match = NULL;
196
struct device *dev = &pdev->dev;
197
int ret;
198
199
ret = drm_of_component_probe(dev, component_compare_dev_name, &armada_master_ops);
200
if (ret != -EINVAL)
201
return ret;
202
203
if (dev->platform_data) {
204
char **devices = dev->platform_data;
205
struct device *d;
206
int i;
207
208
for (i = 0; devices[i]; i++)
209
component_match_add(dev, &match, component_compare_dev_name,
210
devices[i]);
211
212
if (i == 0) {
213
dev_err(dev, "missing 'ports' property\n");
214
return -ENODEV;
215
}
216
217
for (i = 0; devices[i]; i++) {
218
d = bus_find_device_by_name(&platform_bus_type, NULL,
219
devices[i]);
220
if (d && d->of_node)
221
armada_add_endpoints(dev, &match, d->of_node);
222
put_device(d);
223
}
224
}
225
226
return component_master_add_with_match(&pdev->dev, &armada_master_ops,
227
match);
228
}
229
230
static void armada_drm_remove(struct platform_device *pdev)
231
{
232
component_master_del(&pdev->dev, &armada_master_ops);
233
}
234
235
static void armada_drm_shutdown(struct platform_device *pdev)
236
{
237
drm_atomic_helper_shutdown(platform_get_drvdata(pdev));
238
}
239
240
static const struct platform_device_id armada_drm_platform_ids[] = {
241
{
242
.name = "armada-drm",
243
}, {
244
.name = "armada-510-drm",
245
},
246
{ },
247
};
248
MODULE_DEVICE_TABLE(platform, armada_drm_platform_ids);
249
250
static struct platform_driver armada_drm_platform_driver = {
251
.probe = armada_drm_probe,
252
.remove = armada_drm_remove,
253
.shutdown = armada_drm_shutdown,
254
.driver = {
255
.name = "armada-drm",
256
},
257
.id_table = armada_drm_platform_ids,
258
};
259
260
static int __init armada_drm_init(void)
261
{
262
int ret;
263
264
if (drm_firmware_drivers_only())
265
return -ENODEV;
266
267
ret = platform_driver_register(&armada_lcd_platform_driver);
268
if (ret)
269
return ret;
270
ret = platform_driver_register(&armada_drm_platform_driver);
271
if (ret)
272
platform_driver_unregister(&armada_lcd_platform_driver);
273
return ret;
274
}
275
module_init(armada_drm_init);
276
277
static void __exit armada_drm_exit(void)
278
{
279
platform_driver_unregister(&armada_drm_platform_driver);
280
platform_driver_unregister(&armada_lcd_platform_driver);
281
}
282
module_exit(armada_drm_exit);
283
284
MODULE_AUTHOR("Russell King <[email protected]>");
285
MODULE_DESCRIPTION("Armada DRM Driver");
286
MODULE_LICENSE("GPL");
287
MODULE_ALIAS("platform:armada-drm");
288
289