]> rtime.felk.cvut.cz Git - zynq/linux.git/blob - drivers/gpu/drm/xilinx/xilinx_drm_drv.c
drm: xilinx: crtc: Add crtc set config helper
[zynq/linux.git] / drivers / gpu / drm / xilinx / xilinx_drm_drv.c
1 /*
2  * Xilinx DRM KMS support for Xilinx
3  *
4  *  Copyright (C) 2013 Xilinx, Inc.
5  *
6  *  Author: Hyun Woo Kwon <hyunk@xilinx.com>
7  *
8  * This software is licensed under the terms of the GNU General Public
9  * License version 2, as published by the Free Software Foundation, and
10  * may be copied, distributed, and modified under those terms.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
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
39 static uint xilinx_drm_fbdev_vres = 2;
40 module_param_named(fbdev_vres, xilinx_drm_fbdev_vres, uint, 0444);
41 MODULE_PARM_DESC(fbdev_vres,
42                  "fbdev virtual resolution multiplier for fb (default: 2)");
43
44 /*
45  * TODO: The possible pipeline configurations are numerous with Xilinx soft IPs.
46  * It's not too bad for now, but the more proper way(Common Display Framework,
47  * or some internal abstraction) should be considered, when it reaches a point
48  * that such thing is required.
49  */
50
51 struct 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 };
57
58 /**
59  * struct xilinx_video_format_desc - Xilinx Video IP video format description
60  * @name: Xilinx video format name
61  * @depth: color depth
62  * @bpp: bits per pixel
63  * @xilinx_format: xilinx format code
64  * @drm_format: drm format code
65  */
66 struct xilinx_video_format_desc {
67         const char *name;
68         unsigned int depth;
69         unsigned int bpp;
70         unsigned int xilinx_format;
71         uint32_t drm_format;
72 };
73
74 static const struct xilinx_video_format_desc xilinx_video_formats[] = {
75         { "yuv422", 16, 16, XILINX_VIDEO_FORMAT_YUV422, DRM_FORMAT_YUYV },
76         { "yuv444", 24, 24, XILINX_VIDEO_FORMAT_YUV444, DRM_FORMAT_YUV444 },
77         { "rgb888", 24, 24, XILINX_VIDEO_FORMAT_RGB, DRM_FORMAT_RGB888 },
78         { "yuv420", 16, 16, XILINX_VIDEO_FORMAT_YUV420, DRM_FORMAT_YUV420 },
79         { "xrgb8888", 24, 32, XILINX_VIDEO_FORMAT_XRGB, DRM_FORMAT_XRGB8888 },
80         { "rgba8888", 32, 32, XILINX_VIDEO_FORMAT_NONE, DRM_FORMAT_RGBA8888 },
81         { "rgb565", 16, 16, XILINX_VIDEO_FORMAT_NONE, DRM_FORMAT_RGB565 },
82         { "xbgr8888", 24, 32, XILINX_VIDEO_FORMAT_NONE, DRM_FORMAT_XBGR8888 },
83         { "abgr8888", 32, 32, XILINX_VIDEO_FORMAT_NONE, DRM_FORMAT_ABGR8888 },
84 };
85
86 /**
87  * xilinx_drm_check_format - Check if the given format is supported
88  * @drm: DRM device
89  * @fourcc: format fourcc
90  *
91  * Check if the given format @fourcc is supported by the current pipeline
92  *
93  * Return: true if the format is supported, or false
94  */
95 bool xilinx_drm_check_format(struct drm_device *drm, uint32_t fourcc)
96 {
97         struct xilinx_drm_private *private = drm->dev_private;
98
99         return xilinx_drm_crtc_check_format(private->crtc, fourcc);
100 }
101
102 /**
103  * xilinx_drm_get_format - Get the current device format
104  * @drm: DRM device
105  *
106  * Get the current format of pipeline
107  *
108  * Return: the corresponding DRM_FORMAT_XXX
109  */
110 uint32_t xilinx_drm_get_format(struct drm_device *drm)
111 {
112         struct xilinx_drm_private *private = drm->dev_private;
113
114         return xilinx_drm_crtc_get_format(private->crtc);
115 }
116
117 /**
118  * xilinx_drm_get_align - Get the alignment value for pitch
119  * @drm: DRM object
120  *
121  * Get the alignment value for pitch from the plane
122  *
123  * Return: The alignment value if successful, or the error code.
124  */
125 unsigned int xilinx_drm_get_align(struct drm_device *drm)
126 {
127         struct xilinx_drm_private *private = drm->dev_private;
128
129         return xilinx_drm_crtc_get_align(private->crtc);
130 }
131
132 void xilinx_drm_set_config(struct drm_device *drm, struct drm_mode_set *set)
133 {
134         struct xilinx_drm_private *private = drm->dev_private;
135
136         if (private && private->fb)
137                 xilinx_drm_fb_set_config(private->fb, set);
138 }
139
140 /* poll changed handler */
141 static void xilinx_drm_output_poll_changed(struct drm_device *drm)
142 {
143         struct xilinx_drm_private *private = drm->dev_private;
144
145         xilinx_drm_fb_hotplug_event(private->fb);
146 }
147
148 static const struct drm_mode_config_funcs xilinx_drm_mode_config_funcs = {
149         .fb_create              = xilinx_drm_fb_create,
150         .output_poll_changed    = xilinx_drm_output_poll_changed,
151 };
152
153 /* enable vblank */
154 static int xilinx_drm_enable_vblank(struct drm_device *drm, unsigned int crtc)
155 {
156         struct xilinx_drm_private *private = drm->dev_private;
157
158         xilinx_drm_crtc_enable_vblank(private->crtc);
159
160         return 0;
161 }
162
163 /* disable vblank */
164 static void xilinx_drm_disable_vblank(struct drm_device *drm, unsigned int crtc)
165 {
166         struct xilinx_drm_private *private = drm->dev_private;
167
168         xilinx_drm_crtc_disable_vblank(private->crtc);
169 }
170
171 /* initialize mode config */
172 static void xilinx_drm_mode_config_init(struct drm_device *drm)
173 {
174         struct xilinx_drm_private *private = drm->dev_private;
175
176         drm->mode_config.min_width = 0;
177         drm->mode_config.min_height = 0;
178
179         drm->mode_config.max_width =
180                 xilinx_drm_crtc_get_max_width(private->crtc);
181         drm->mode_config.max_height = 4096;
182
183         drm->mode_config.funcs = &xilinx_drm_mode_config_funcs;
184 }
185
186 /* convert xilinx format to drm format by code */
187 int xilinx_drm_format_by_code(unsigned int xilinx_format, uint32_t *drm_format)
188 {
189         const struct xilinx_video_format_desc *format;
190         unsigned int i;
191
192         for (i = 0; i < ARRAY_SIZE(xilinx_video_formats); i++) {
193                 format = &xilinx_video_formats[i];
194                 if (format->xilinx_format == xilinx_format) {
195                         *drm_format = format->drm_format;
196                         return 0;
197                 }
198         }
199
200         DRM_ERROR("Unknown Xilinx video format: %d\n", xilinx_format);
201
202         return -EINVAL;
203 }
204
205 /* convert xilinx format to drm format by name */
206 int xilinx_drm_format_by_name(const char *name, uint32_t *drm_format)
207 {
208         const struct xilinx_video_format_desc *format;
209         unsigned int i;
210
211         for (i = 0; i < ARRAY_SIZE(xilinx_video_formats); i++) {
212                 format = &xilinx_video_formats[i];
213                 if (strcmp(format->name, name) == 0) {
214                         *drm_format = format->drm_format;
215                         return 0;
216                 }
217         }
218
219         DRM_ERROR("Unknown Xilinx video format: %s\n", name);
220
221         return -EINVAL;
222 }
223
224 /* get bpp of given format */
225 unsigned int xilinx_drm_format_bpp(uint32_t drm_format)
226 {
227         const struct xilinx_video_format_desc *format;
228         unsigned int i;
229
230         for (i = 0; i < ARRAY_SIZE(xilinx_video_formats); i++) {
231                 format = &xilinx_video_formats[i];
232                 if (format->drm_format == drm_format)
233                         return format->bpp;
234         }
235
236         return 0;
237 }
238
239 /* get color depth of given format */
240 unsigned int xilinx_drm_format_depth(uint32_t drm_format)
241 {
242         const struct xilinx_video_format_desc *format;
243         unsigned int i;
244
245         for (i = 0; i < ARRAY_SIZE(xilinx_video_formats); i++) {
246                 format = &xilinx_video_formats[i];
247                 if (format->drm_format == drm_format)
248                         return format->depth;
249         }
250
251         return 0;
252 }
253
254 /* load xilinx drm */
255 static int xilinx_drm_load(struct drm_device *drm, unsigned long flags)
256 {
257         struct xilinx_drm_private *private;
258         struct drm_encoder *encoder;
259         struct drm_connector *connector;
260         struct device_node *encoder_node;
261         struct platform_device *pdev = drm->platformdev;
262         unsigned int bpp, align, i = 0;
263         int ret;
264
265         private = devm_kzalloc(drm->dev, sizeof(*private), GFP_KERNEL);
266         if (!private)
267                 return -ENOMEM;
268
269         drm_mode_config_init(drm);
270
271         /* create a xilinx crtc */
272         private->crtc = xilinx_drm_crtc_create(drm);
273         if (IS_ERR(private->crtc)) {
274                 DRM_DEBUG_DRIVER("failed to create xilinx crtc\n");
275                 ret = PTR_ERR(private->crtc);
276                 goto err_out;
277         }
278
279         while ((encoder_node = of_parse_phandle(drm->dev->of_node,
280                                                 "xlnx,encoder-slave", i))) {
281                 encoder = xilinx_drm_encoder_create(drm, encoder_node);
282                 of_node_put(encoder_node);
283                 if (IS_ERR(encoder)) {
284                         DRM_DEBUG_DRIVER("failed to create xilinx encoder\n");
285                         ret = PTR_ERR(encoder);
286                         goto err_out;
287                 }
288
289                 connector = xilinx_drm_connector_create(drm, encoder, i);
290                 if (IS_ERR(connector)) {
291                         DRM_DEBUG_DRIVER("failed to create xilinx connector\n");
292                         ret = PTR_ERR(connector);
293                         goto err_out;
294                 }
295
296                 i++;
297         }
298
299         if (i == 0) {
300                 DRM_ERROR("failed to get an encoder slave node\n");
301                 return -ENODEV;
302         }
303
304         ret = drm_vblank_init(drm, 1);
305         if (ret) {
306                 dev_err(&pdev->dev, "failed to initialize vblank\n");
307                 goto err_out;
308         }
309
310         /* enable irq to enable vblank feature */
311         drm->irq_enabled = 1;
312
313         /* allow disable vblank */
314         drm->vblank_disable_allowed = 1;
315
316         drm->dev_private = private;
317         private->drm = drm;
318
319         /* initialize xilinx framebuffer */
320         bpp = xilinx_drm_format_bpp(xilinx_drm_crtc_get_format(private->crtc));
321         align = xilinx_drm_crtc_get_align(private->crtc);
322         private->fb = xilinx_drm_fb_init(drm, bpp, 1, 1, align,
323                                          xilinx_drm_fbdev_vres);
324         if (IS_ERR(private->fb)) {
325                 DRM_ERROR("failed to initialize drm cma fb\n");
326                 ret = PTR_ERR(private->fb);
327                 goto err_fb;
328         }
329
330         drm_kms_helper_poll_init(drm);
331
332         /* set up mode config for xilinx */
333         xilinx_drm_mode_config_init(drm);
334
335         drm_helper_disable_unused_functions(drm);
336
337         platform_set_drvdata(pdev, private);
338
339         return 0;
340
341 err_fb:
342         drm_vblank_cleanup(drm);
343 err_out:
344         drm_mode_config_cleanup(drm);
345         if (ret == -EPROBE_DEFER)
346                 DRM_INFO("load() is defered & will be called again\n");
347         return ret;
348 }
349
350 /* unload xilinx drm */
351 static int xilinx_drm_unload(struct drm_device *drm)
352 {
353         struct xilinx_drm_private *private = drm->dev_private;
354
355         drm_vblank_cleanup(drm);
356
357         drm_kms_helper_poll_fini(drm);
358
359         xilinx_drm_fb_fini(private->fb);
360
361         drm_mode_config_cleanup(drm);
362
363         return 0;
364 }
365
366 /* preclose */
367 static void xilinx_drm_preclose(struct drm_device *drm, struct drm_file *file)
368 {
369         struct xilinx_drm_private *private = drm->dev_private;
370
371         /* cancel pending page flip request */
372         xilinx_drm_crtc_cancel_page_flip(private->crtc, file);
373 }
374
375 /* restore the default mode when xilinx drm is released */
376 static void xilinx_drm_lastclose(struct drm_device *drm)
377 {
378         struct xilinx_drm_private *private = drm->dev_private;
379
380         xilinx_drm_crtc_restore(private->crtc);
381
382         xilinx_drm_fb_restore_mode(private->fb);
383 }
384
385 static const struct file_operations xilinx_drm_fops = {
386         .owner          = THIS_MODULE,
387         .open           = drm_open,
388         .release        = drm_release,
389         .unlocked_ioctl = drm_ioctl,
390         .mmap           = drm_gem_cma_mmap,
391         .poll           = drm_poll,
392         .read           = drm_read,
393 #ifdef CONFIG_COMPAT
394         .compat_ioctl   = drm_compat_ioctl,
395 #endif
396         .llseek         = noop_llseek,
397 };
398
399 static struct drm_driver xilinx_drm_driver = {
400         .driver_features                = DRIVER_MODESET | DRIVER_GEM |
401                                           DRIVER_PRIME,
402         .load                           = xilinx_drm_load,
403         .unload                         = xilinx_drm_unload,
404         .preclose                       = xilinx_drm_preclose,
405         .lastclose                      = xilinx_drm_lastclose,
406         .set_busid                      = drm_platform_set_busid,
407
408         .get_vblank_counter             = drm_vblank_no_hw_counter,
409         .enable_vblank                  = xilinx_drm_enable_vblank,
410         .disable_vblank                 = xilinx_drm_disable_vblank,
411
412         .prime_handle_to_fd             = drm_gem_prime_handle_to_fd,
413         .prime_fd_to_handle             = drm_gem_prime_fd_to_handle,
414         .gem_prime_export               = drm_gem_prime_export,
415         .gem_prime_import               = drm_gem_prime_import,
416         .gem_prime_get_sg_table         = drm_gem_cma_prime_get_sg_table,
417         .gem_prime_import_sg_table      = drm_gem_cma_prime_import_sg_table,
418         .gem_prime_vmap                 = drm_gem_cma_prime_vmap,
419         .gem_prime_vunmap               = drm_gem_cma_prime_vunmap,
420         .gem_prime_mmap                 = drm_gem_cma_prime_mmap,
421         .gem_free_object                = drm_gem_cma_free_object,
422         .gem_vm_ops                     = &drm_gem_cma_vm_ops,
423         .dumb_create                    = xilinx_drm_gem_cma_dumb_create,
424         .dumb_map_offset                = drm_gem_cma_dumb_map_offset,
425         .dumb_destroy                   = drm_gem_dumb_destroy,
426
427         .fops                           = &xilinx_drm_fops,
428
429         .name                           = DRIVER_NAME,
430         .desc                           = DRIVER_DESC,
431         .date                           = DRIVER_DATE,
432         .major                          = DRIVER_MAJOR,
433         .minor                          = DRIVER_MINOR,
434 };
435
436 #if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM_RUNTIME)
437 /* suspend xilinx drm */
438 static int xilinx_drm_pm_suspend(struct device *dev)
439 {
440         struct xilinx_drm_private *private = dev_get_drvdata(dev);
441         struct drm_device *drm = private->drm;
442         struct drm_connector *connector;
443
444         drm_kms_helper_poll_disable(drm);
445         drm_modeset_lock_all(drm);
446         list_for_each_entry(connector, &drm->mode_config.connector_list, head) {
447                 int old_dpms = connector->dpms;
448
449                 if (connector->funcs->dpms)
450                         connector->funcs->dpms(connector,
451                                                DRM_MODE_DPMS_SUSPEND);
452
453                 connector->dpms = old_dpms;
454         }
455         drm_modeset_unlock_all(drm);
456
457         return 0;
458 }
459
460 /* resume xilinx drm */
461 static int xilinx_drm_pm_resume(struct device *dev)
462 {
463         struct xilinx_drm_private *private = dev_get_drvdata(dev);
464         struct drm_device *drm = private->drm;
465         struct drm_connector *connector;
466
467         drm_modeset_lock_all(drm);
468         list_for_each_entry(connector, &drm->mode_config.connector_list, head) {
469                 if (connector->funcs->dpms) {
470                         int dpms = connector->dpms;
471
472                         connector->dpms = DRM_MODE_DPMS_OFF;
473                         connector->funcs->dpms(connector, dpms);
474                 }
475         }
476         drm_kms_helper_poll_enable_locked(drm);
477         drm_modeset_unlock_all(drm);
478
479         return 0;
480 }
481 #endif
482
483 static const struct dev_pm_ops xilinx_drm_pm_ops = {
484         SET_SYSTEM_SLEEP_PM_OPS(xilinx_drm_pm_suspend, xilinx_drm_pm_resume)
485         SET_RUNTIME_PM_OPS(xilinx_drm_pm_suspend, xilinx_drm_pm_resume, NULL)
486 };
487
488 /* init xilinx drm platform */
489 static int xilinx_drm_platform_probe(struct platform_device *pdev)
490 {
491         return drm_platform_init(&xilinx_drm_driver, pdev);
492 }
493
494 /* exit xilinx drm platform */
495 static int xilinx_drm_platform_remove(struct platform_device *pdev)
496 {
497         struct xilinx_drm_private *private = platform_get_drvdata(pdev);
498
499         drm_put_dev(private->drm);
500
501         return 0;
502 }
503
504 static const struct of_device_id xilinx_drm_of_match[] = {
505         { .compatible = "xlnx,drm", },
506         { /* end of table */ },
507 };
508 MODULE_DEVICE_TABLE(of, xilinx_drm_of_match);
509
510 static struct platform_driver xilinx_drm_private_driver = {
511         .probe                  = xilinx_drm_platform_probe,
512         .remove                 = xilinx_drm_platform_remove,
513         .driver                 = {
514                 .name           = "xilinx-drm",
515                 .pm             = &xilinx_drm_pm_ops,
516                 .of_match_table = xilinx_drm_of_match,
517         },
518 };
519
520 module_platform_driver(xilinx_drm_private_driver);
521
522 MODULE_AUTHOR("Xilinx, Inc.");
523 MODULE_DESCRIPTION("Xilinx DRM KMS Driver");
524 MODULE_LICENSE("GPL v2");