1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#include <drm/drmP.h>
19#include <drm/drm_crtc_helper.h>
20#include <drm/drm_gem_cma_helper.h>
21
22#include <linux/device.h>
23#include <linux/module.h>
24#include <linux/platform_device.h>
25
26#include "xilinx_drm_connector.h"
27#include "xilinx_drm_crtc.h"
28#include "xilinx_drm_drv.h"
29#include "xilinx_drm_encoder.h"
30#include "xilinx_drm_fb.h"
31#include "xilinx_drm_gem.h"
32
33#define DRIVER_NAME "xilinx_drm"
34#define DRIVER_DESC "Xilinx DRM KMS support for Xilinx"
35#define DRIVER_DATE "20130509"
36#define DRIVER_MAJOR 1
37#define DRIVER_MINOR 0
38
39static uint xilinx_drm_fbdev_vres = 2;
40module_param_named(fbdev_vres, xilinx_drm_fbdev_vres, uint, 0444);
41MODULE_PARM_DESC(fbdev_vres,
42 "fbdev virtual resolution multiplier for fb (default: 2)");
43
44
45
46
47
48
49
50
51struct xilinx_drm_private {
52 struct drm_device *drm;
53 struct drm_crtc *crtc;
54 struct drm_fb_helper *fb;
55 struct platform_device *pdev;
56 bool is_master;
57};
58
59
60
61
62
63
64
65
66
67struct xilinx_video_format_desc {
68 const char *name;
69 unsigned int depth;
70 unsigned int bpp;
71 unsigned int xilinx_format;
72 uint32_t drm_format;
73};
74
75static const struct xilinx_video_format_desc xilinx_video_formats[] = {
76 { "yuv420", 16, 16, XILINX_VIDEO_FORMAT_YUV420, DRM_FORMAT_YUV420 },
77 { "uvy422", 16, 16, XILINX_VIDEO_FORMAT_NONE, DRM_FORMAT_UYVY },
78 { "vuy422", 16, 16, XILINX_VIDEO_FORMAT_YUV422, DRM_FORMAT_VYUY },
79 { "yuv422", 16, 16, XILINX_VIDEO_FORMAT_YUV422, DRM_FORMAT_YUYV },
80 { "yvu422", 16, 16, XILINX_VIDEO_FORMAT_NONE, DRM_FORMAT_YVYU },
81 { "yuv444", 24, 24, XILINX_VIDEO_FORMAT_YUV444, DRM_FORMAT_YUV444 },
82 { "nv12", 16, 16, XILINX_VIDEO_FORMAT_NONE, DRM_FORMAT_NV12 },
83 { "nv21", 16, 16, XILINX_VIDEO_FORMAT_NONE, DRM_FORMAT_NV21 },
84 { "nv16", 16, 16, XILINX_VIDEO_FORMAT_NONE, DRM_FORMAT_NV16 },
85 { "nv61", 16, 16, XILINX_VIDEO_FORMAT_NONE, DRM_FORMAT_NV61 },
86 { "abgr1555", 16, 16, XILINX_VIDEO_FORMAT_NONE, DRM_FORMAT_ABGR1555 },
87 { "argb1555", 16, 16, XILINX_VIDEO_FORMAT_NONE, DRM_FORMAT_ARGB1555 },
88 { "rgba4444", 16, 16, XILINX_VIDEO_FORMAT_NONE, DRM_FORMAT_RGBA4444 },
89 { "bgra4444", 16, 16, XILINX_VIDEO_FORMAT_NONE, DRM_FORMAT_BGRA4444 },
90 { "bgr565", 16, 16, XILINX_VIDEO_FORMAT_NONE, DRM_FORMAT_BGR565 },
91 { "rgb565", 16, 16, XILINX_VIDEO_FORMAT_NONE, DRM_FORMAT_RGB565 },
92 { "bgr888", 24, 24, XILINX_VIDEO_FORMAT_RGB, DRM_FORMAT_BGR888 },
93 { "rgb888", 24, 24, XILINX_VIDEO_FORMAT_RGB, DRM_FORMAT_RGB888 },
94 { "xbgr8888", 24, 32, XILINX_VIDEO_FORMAT_NONE, DRM_FORMAT_XBGR8888 },
95 { "xrgb8888", 24, 32, XILINX_VIDEO_FORMAT_XRGB, DRM_FORMAT_XRGB8888 },
96 { "abgr8888", 32, 32, XILINX_VIDEO_FORMAT_NONE, DRM_FORMAT_ABGR8888 },
97 { "argb8888", 32, 32, XILINX_VIDEO_FORMAT_NONE, DRM_FORMAT_ARGB8888 },
98 { "bgra8888", 32, 32, XILINX_VIDEO_FORMAT_NONE, DRM_FORMAT_BGRA8888 },
99 { "rgba8888", 32, 32, XILINX_VIDEO_FORMAT_NONE, DRM_FORMAT_RGBA8888 },
100};
101
102
103
104
105
106
107
108
109
110
111bool xilinx_drm_check_format(struct drm_device *drm, uint32_t fourcc)
112{
113 struct xilinx_drm_private *private = drm->dev_private;
114
115 return xilinx_drm_crtc_check_format(private->crtc, fourcc);
116}
117
118
119
120
121
122
123
124
125
126uint32_t xilinx_drm_get_format(struct drm_device *drm)
127{
128 struct xilinx_drm_private *private = drm->dev_private;
129
130 return xilinx_drm_crtc_get_format(private->crtc);
131}
132
133
134
135
136
137
138
139
140
141unsigned int xilinx_drm_get_align(struct drm_device *drm)
142{
143 struct xilinx_drm_private *private = drm->dev_private;
144
145 return xilinx_drm_crtc_get_align(private->crtc);
146}
147
148void xilinx_drm_set_config(struct drm_device *drm, struct drm_mode_set *set)
149{
150 struct xilinx_drm_private *private = drm->dev_private;
151
152 if (private && private->fb)
153 xilinx_drm_fb_set_config(private->fb, set);
154}
155
156
157static void xilinx_drm_output_poll_changed(struct drm_device *drm)
158{
159 struct xilinx_drm_private *private = drm->dev_private;
160
161 xilinx_drm_fb_hotplug_event(private->fb);
162}
163
164static const struct drm_mode_config_funcs xilinx_drm_mode_config_funcs = {
165 .fb_create = xilinx_drm_fb_create,
166 .output_poll_changed = xilinx_drm_output_poll_changed,
167};
168
169
170static int xilinx_drm_enable_vblank(struct drm_device *drm, unsigned int crtc)
171{
172 struct xilinx_drm_private *private = drm->dev_private;
173
174 xilinx_drm_crtc_enable_vblank(private->crtc);
175
176 return 0;
177}
178
179
180static void xilinx_drm_disable_vblank(struct drm_device *drm, unsigned int crtc)
181{
182 struct xilinx_drm_private *private = drm->dev_private;
183
184 xilinx_drm_crtc_disable_vblank(private->crtc);
185}
186
187
188static void xilinx_drm_mode_config_init(struct drm_device *drm)
189{
190 struct xilinx_drm_private *private = drm->dev_private;
191
192 drm->mode_config.min_width = 0;
193 drm->mode_config.min_height = 0;
194
195 drm->mode_config.max_width =
196 xilinx_drm_crtc_get_max_width(private->crtc);
197 drm->mode_config.max_height = 4096;
198
199 drm->mode_config.funcs = &xilinx_drm_mode_config_funcs;
200}
201
202
203int xilinx_drm_format_by_code(unsigned int xilinx_format, uint32_t *drm_format)
204{
205 const struct xilinx_video_format_desc *format;
206 unsigned int i;
207
208 for (i = 0; i < ARRAY_SIZE(xilinx_video_formats); i++) {
209 format = &xilinx_video_formats[i];
210 if (format->xilinx_format == xilinx_format) {
211 *drm_format = format->drm_format;
212 return 0;
213 }
214 }
215
216 DRM_ERROR("Unknown Xilinx video format: %d\n", xilinx_format);
217
218 return -EINVAL;
219}
220
221
222int xilinx_drm_format_by_name(const char *name, uint32_t *drm_format)
223{
224 const struct xilinx_video_format_desc *format;
225 unsigned int i;
226
227 for (i = 0; i < ARRAY_SIZE(xilinx_video_formats); i++) {
228 format = &xilinx_video_formats[i];
229 if (strcmp(format->name, name) == 0) {
230 *drm_format = format->drm_format;
231 return 0;
232 }
233 }
234
235 DRM_ERROR("Unknown Xilinx video format: %s\n", name);
236
237 return -EINVAL;
238}
239
240
241unsigned int xilinx_drm_format_bpp(uint32_t drm_format)
242{
243 const struct xilinx_video_format_desc *format;
244 unsigned int i;
245
246 for (i = 0; i < ARRAY_SIZE(xilinx_video_formats); i++) {
247 format = &xilinx_video_formats[i];
248 if (format->drm_format == drm_format)
249 return format->bpp;
250 }
251
252 return 0;
253}
254
255
256unsigned int xilinx_drm_format_depth(uint32_t drm_format)
257{
258 const struct xilinx_video_format_desc *format;
259 unsigned int i;
260
261 for (i = 0; i < ARRAY_SIZE(xilinx_video_formats); i++) {
262 format = &xilinx_video_formats[i];
263 if (format->drm_format == drm_format)
264 return format->depth;
265 }
266
267 return 0;
268}
269
270
271static int xilinx_drm_load(struct drm_device *drm, unsigned long flags)
272{
273 struct xilinx_drm_private *private;
274 struct drm_encoder *encoder;
275 struct drm_connector *connector;
276 struct device_node *encoder_node;
277 struct platform_device *pdev = drm->platformdev;
278 unsigned int bpp, align, i = 0;
279 int ret;
280
281 private = devm_kzalloc(drm->dev, sizeof(*private), GFP_KERNEL);
282 if (!private)
283 return -ENOMEM;
284
285 drm_mode_config_init(drm);
286
287
288 private->crtc = xilinx_drm_crtc_create(drm);
289 if (IS_ERR(private->crtc)) {
290 DRM_DEBUG_DRIVER("failed to create xilinx crtc\n");
291 ret = PTR_ERR(private->crtc);
292 goto err_out;
293 }
294
295 while ((encoder_node = of_parse_phandle(drm->dev->of_node,
296 "xlnx,encoder-slave", i))) {
297 encoder = xilinx_drm_encoder_create(drm, encoder_node);
298 of_node_put(encoder_node);
299 if (IS_ERR(encoder)) {
300 DRM_DEBUG_DRIVER("failed to create xilinx encoder\n");
301 ret = PTR_ERR(encoder);
302 goto err_out;
303 }
304
305 connector = xilinx_drm_connector_create(drm, encoder, i);
306 if (IS_ERR(connector)) {
307 DRM_DEBUG_DRIVER("failed to create xilinx connector\n");
308 ret = PTR_ERR(connector);
309 goto err_out;
310 }
311
312 i++;
313 }
314
315 if (i == 0) {
316 DRM_ERROR("failed to get an encoder slave node\n");
317 return -ENODEV;
318 }
319
320 ret = drm_vblank_init(drm, 1);
321 if (ret) {
322 dev_err(&pdev->dev, "failed to initialize vblank\n");
323 goto err_out;
324 }
325
326
327 drm->irq_enabled = 1;
328
329
330 drm->vblank_disable_allowed = 1;
331
332 drm->dev_private = private;
333 private->drm = drm;
334
335
336 bpp = xilinx_drm_format_bpp(xilinx_drm_crtc_get_format(private->crtc));
337 align = xilinx_drm_crtc_get_align(private->crtc);
338 private->fb = xilinx_drm_fb_init(drm, bpp, 1, 1, align,
339 xilinx_drm_fbdev_vres);
340 if (IS_ERR(private->fb)) {
341 DRM_ERROR("failed to initialize drm cma fb\n");
342 ret = PTR_ERR(private->fb);
343 goto err_fb;
344 }
345
346 drm_kms_helper_poll_init(drm);
347
348
349 xilinx_drm_mode_config_init(drm);
350
351 drm_helper_disable_unused_functions(drm);
352
353 platform_set_drvdata(pdev, private);
354
355 return 0;
356
357err_fb:
358 drm_vblank_cleanup(drm);
359err_out:
360 drm_mode_config_cleanup(drm);
361 if (ret == -EPROBE_DEFER)
362 DRM_INFO("load() is defered & will be called again\n");
363 return ret;
364}
365
366
367static int xilinx_drm_unload(struct drm_device *drm)
368{
369 struct xilinx_drm_private *private = drm->dev_private;
370
371 drm_vblank_cleanup(drm);
372
373 drm_kms_helper_poll_fini(drm);
374
375 xilinx_drm_fb_fini(private->fb);
376
377 drm_mode_config_cleanup(drm);
378
379 return 0;
380}
381
382int xilinx_drm_open(struct drm_device *dev, struct drm_file *file)
383{
384 struct xilinx_drm_private *private = dev->dev_private;
385
386 if (!(drm_is_primary_client(file) && !file->minor->master) &&
387 capable(CAP_SYS_ADMIN)) {
388 file->is_master = 1;
389 private->is_master = true;
390 }
391
392 return 0;
393}
394
395
396static void xilinx_drm_preclose(struct drm_device *drm, struct drm_file *file)
397{
398 struct xilinx_drm_private *private = drm->dev_private;
399
400
401 xilinx_drm_crtc_cancel_page_flip(private->crtc, file);
402
403 if (private->is_master) {
404 private->is_master = false;
405 file->is_master = 0;
406 }
407}
408
409
410static void xilinx_drm_lastclose(struct drm_device *drm)
411{
412 struct xilinx_drm_private *private = drm->dev_private;
413
414 xilinx_drm_crtc_restore(private->crtc);
415
416 xilinx_drm_fb_restore_mode(private->fb);
417}
418
419static int xilinx_drm_set_busid(struct drm_device *dev, struct drm_master *master)
420{
421 return 0;
422}
423
424static const struct file_operations xilinx_drm_fops = {
425 .owner = THIS_MODULE,
426 .open = drm_open,
427 .release = drm_release,
428 .unlocked_ioctl = drm_ioctl,
429 .mmap = drm_gem_cma_mmap,
430 .poll = drm_poll,
431 .read = drm_read,
432#ifdef CONFIG_COMPAT
433 .compat_ioctl = drm_compat_ioctl,
434#endif
435 .llseek = noop_llseek,
436};
437
438static struct drm_driver xilinx_drm_driver = {
439 .driver_features = DRIVER_MODESET | DRIVER_GEM |
440 DRIVER_PRIME,
441 .load = xilinx_drm_load,
442 .unload = xilinx_drm_unload,
443 .open = xilinx_drm_open,
444 .preclose = xilinx_drm_preclose,
445 .lastclose = xilinx_drm_lastclose,
446 .set_busid = xilinx_drm_set_busid,
447
448 .get_vblank_counter = drm_vblank_no_hw_counter,
449 .enable_vblank = xilinx_drm_enable_vblank,
450 .disable_vblank = xilinx_drm_disable_vblank,
451
452 .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
453 .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
454 .gem_prime_export = drm_gem_prime_export,
455 .gem_prime_import = drm_gem_prime_import,
456 .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
457 .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
458 .gem_prime_vmap = drm_gem_cma_prime_vmap,
459 .gem_prime_vunmap = drm_gem_cma_prime_vunmap,
460 .gem_prime_mmap = drm_gem_cma_prime_mmap,
461 .gem_free_object = drm_gem_cma_free_object,
462 .gem_vm_ops = &drm_gem_cma_vm_ops,
463 .dumb_create = xilinx_drm_gem_cma_dumb_create,
464 .dumb_map_offset = drm_gem_cma_dumb_map_offset,
465 .dumb_destroy = drm_gem_dumb_destroy,
466
467 .fops = &xilinx_drm_fops,
468
469 .name = DRIVER_NAME,
470 .desc = DRIVER_DESC,
471 .date = DRIVER_DATE,
472 .major = DRIVER_MAJOR,
473 .minor = DRIVER_MINOR,
474};
475
476#if defined(CONFIG_PM_SLEEP)
477
478static int xilinx_drm_pm_suspend(struct device *dev)
479{
480 struct xilinx_drm_private *private = dev_get_drvdata(dev);
481 struct drm_device *drm = private->drm;
482 struct drm_connector *connector;
483
484 drm_kms_helper_poll_disable(drm);
485 drm_modeset_lock_all(drm);
486 list_for_each_entry(connector, &drm->mode_config.connector_list, head) {
487 int old_dpms = connector->dpms;
488
489 if (connector->funcs->dpms)
490 connector->funcs->dpms(connector,
491 DRM_MODE_DPMS_SUSPEND);
492
493 connector->dpms = old_dpms;
494 }
495 drm_modeset_unlock_all(drm);
496
497 return 0;
498}
499
500
501static int xilinx_drm_pm_resume(struct device *dev)
502{
503 struct xilinx_drm_private *private = dev_get_drvdata(dev);
504 struct drm_device *drm = private->drm;
505 struct drm_connector *connector;
506
507 drm_modeset_lock_all(drm);
508 list_for_each_entry(connector, &drm->mode_config.connector_list, head) {
509 if (connector->funcs->dpms) {
510 int dpms = connector->dpms;
511
512 connector->dpms = DRM_MODE_DPMS_OFF;
513 connector->funcs->dpms(connector, dpms);
514 }
515 }
516 drm_kms_helper_poll_enable_locked(drm);
517 drm_modeset_unlock_all(drm);
518
519 return 0;
520}
521#endif
522
523static const struct dev_pm_ops xilinx_drm_pm_ops = {
524 SET_SYSTEM_SLEEP_PM_OPS(xilinx_drm_pm_suspend, xilinx_drm_pm_resume)
525};
526
527
528static int xilinx_drm_platform_probe(struct platform_device *pdev)
529{
530 return drm_platform_init(&xilinx_drm_driver, pdev);
531}
532
533
534static int xilinx_drm_platform_remove(struct platform_device *pdev)
535{
536 struct xilinx_drm_private *private = platform_get_drvdata(pdev);
537
538 drm_put_dev(private->drm);
539
540 return 0;
541}
542
543static const struct of_device_id xilinx_drm_of_match[] = {
544 { .compatible = "xlnx,drm", },
545 { },
546};
547MODULE_DEVICE_TABLE(of, xilinx_drm_of_match);
548
549static struct platform_driver xilinx_drm_private_driver = {
550 .probe = xilinx_drm_platform_probe,
551 .remove = xilinx_drm_platform_remove,
552 .driver = {
553 .name = "xilinx-drm",
554 .pm = &xilinx_drm_pm_ops,
555 .of_match_table = xilinx_drm_of_match,
556 },
557};
558
559module_platform_driver(xilinx_drm_private_driver);
560
561MODULE_AUTHOR("Xilinx, Inc.");
562MODULE_DESCRIPTION("Xilinx DRM KMS Driver");
563MODULE_LICENSE("GPL v2");
564