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.h>
20#include <drm/drm_crtc_helper.h>
21#include <drm/drm_fb_cma_helper.h>
22#include <drm/drm_gem_cma_helper.h>
23
24#include <linux/clk.h>
25#include <linux/delay.h>
26#include <linux/device.h>
27#include <linux/i2c.h>
28
29#include <video/videomode.h>
30
31#include "xilinx_drm_crtc.h"
32#include "xilinx_drm_dp_sub.h"
33#include "xilinx_drm_drv.h"
34#include "xilinx_drm_plane.h"
35
36#include "xilinx_cresample.h"
37#include "xilinx_rgb2yuv.h"
38#include "xilinx_vtc.h"
39
40struct xilinx_drm_crtc {
41 struct drm_crtc base;
42 struct xilinx_cresample *cresample;
43 struct xilinx_rgb2yuv *rgb2yuv;
44 struct clk *pixel_clock;
45 bool pixel_clock_enabled;
46 struct xilinx_vtc *vtc;
47 struct xilinx_drm_plane_manager *plane_manager;
48 int dpms;
49 unsigned int alpha;
50 struct drm_pending_vblank_event *event;
51 struct xilinx_drm_dp_sub *dp_sub;
52};
53
54#define to_xilinx_crtc(x) container_of(x, struct xilinx_drm_crtc, base)
55
56
57static void xilinx_drm_crtc_dpms(struct drm_crtc *base_crtc, int dpms)
58{
59 struct xilinx_drm_crtc *crtc = to_xilinx_crtc(base_crtc);
60 int ret;
61
62 DRM_DEBUG_KMS("dpms: %d -> %d\n", crtc->dpms, dpms);
63
64 if (crtc->dpms == dpms)
65 return;
66
67 crtc->dpms = dpms;
68
69 switch (dpms) {
70 case DRM_MODE_DPMS_ON:
71 if (!crtc->pixel_clock_enabled) {
72 ret = clk_prepare_enable(crtc->pixel_clock);
73 if (ret) {
74 DRM_ERROR("failed to enable a pixel clock\n");
75 crtc->pixel_clock_enabled = false;
76 }
77 }
78 crtc->pixel_clock_enabled = true;
79
80 xilinx_drm_plane_manager_dpms(crtc->plane_manager, dpms);
81 xilinx_drm_plane_dpms(base_crtc->primary, dpms);
82 if (crtc->rgb2yuv)
83 xilinx_rgb2yuv_enable(crtc->rgb2yuv);
84 if (crtc->cresample)
85 xilinx_cresample_enable(crtc->cresample);
86 if (crtc->vtc)
87 xilinx_vtc_enable(crtc->vtc);
88 break;
89 default:
90 if (crtc->vtc) {
91 xilinx_vtc_disable(crtc->vtc);
92 xilinx_vtc_reset(crtc->vtc);
93 }
94 if (crtc->cresample) {
95 xilinx_cresample_disable(crtc->cresample);
96 xilinx_cresample_reset(crtc->cresample);
97 }
98 if (crtc->rgb2yuv) {
99 xilinx_rgb2yuv_disable(crtc->rgb2yuv);
100 xilinx_rgb2yuv_reset(crtc->rgb2yuv);
101 }
102 xilinx_drm_plane_dpms(base_crtc->primary, dpms);
103 xilinx_drm_plane_manager_dpms(crtc->plane_manager, dpms);
104 if (crtc->pixel_clock_enabled) {
105 clk_disable_unprepare(crtc->pixel_clock);
106 crtc->pixel_clock_enabled = false;
107 }
108 break;
109 }
110}
111
112
113static void xilinx_drm_crtc_prepare(struct drm_crtc *base_crtc)
114{
115 xilinx_drm_crtc_dpms(base_crtc, DRM_MODE_DPMS_OFF);
116}
117
118
119static void xilinx_drm_crtc_commit(struct drm_crtc *base_crtc)
120{
121 xilinx_drm_crtc_dpms(base_crtc, DRM_MODE_DPMS_ON);
122 xilinx_drm_plane_commit(base_crtc->primary);
123}
124
125
126static bool xilinx_drm_crtc_mode_fixup(struct drm_crtc *base_crtc,
127 const struct drm_display_mode *mode,
128 struct drm_display_mode *adjusted_mode)
129{
130
131 return true;
132}
133
134
135static int xilinx_drm_crtc_mode_set(struct drm_crtc *base_crtc,
136 struct drm_display_mode *mode,
137 struct drm_display_mode *adjusted_mode,
138 int x, int y,
139 struct drm_framebuffer *old_fb)
140{
141 struct xilinx_drm_crtc *crtc = to_xilinx_crtc(base_crtc);
142 struct videomode vm;
143 long diff;
144 int ret;
145
146 if (crtc->pixel_clock_enabled) {
147 clk_disable_unprepare(crtc->pixel_clock);
148 crtc->pixel_clock_enabled = false;
149 }
150
151
152 ret = clk_set_rate(crtc->pixel_clock, adjusted_mode->clock * 1000);
153 if (ret) {
154 DRM_ERROR("failed to set a pixel clock\n");
155 return ret;
156 }
157
158 diff = clk_get_rate(crtc->pixel_clock) - adjusted_mode->clock * 1000;
159 if (abs(diff) > (adjusted_mode->clock * 1000) / 20)
160 DRM_DEBUG_KMS("actual pixel clock rate(%d) is off by %ld\n",
161 adjusted_mode->clock, diff);
162
163 if (crtc->vtc) {
164
165 vm.hactive = adjusted_mode->hdisplay;
166 vm.hfront_porch = adjusted_mode->hsync_start -
167 adjusted_mode->hdisplay;
168 vm.hback_porch = adjusted_mode->htotal -
169 adjusted_mode->hsync_end;
170 vm.hsync_len = adjusted_mode->hsync_end -
171 adjusted_mode->hsync_start;
172
173 vm.vactive = adjusted_mode->vdisplay;
174 vm.vfront_porch = adjusted_mode->vsync_start -
175 adjusted_mode->vdisplay;
176 vm.vback_porch = adjusted_mode->vtotal -
177 adjusted_mode->vsync_end;
178 vm.vsync_len = adjusted_mode->vsync_end -
179 adjusted_mode->vsync_start;
180
181 xilinx_vtc_config_sig(crtc->vtc, &vm);
182 }
183
184
185 if (crtc->cresample)
186 xilinx_cresample_configure(crtc->cresample,
187 adjusted_mode->hdisplay,
188 adjusted_mode->vdisplay);
189 if (crtc->rgb2yuv)
190 xilinx_rgb2yuv_configure(crtc->rgb2yuv,
191 adjusted_mode->hdisplay,
192 adjusted_mode->vdisplay);
193
194
195 xilinx_drm_plane_manager_mode_set(crtc->plane_manager,
196 adjusted_mode->hdisplay,
197 adjusted_mode->vdisplay);
198 ret = xilinx_drm_plane_mode_set(base_crtc->primary,
199 base_crtc->primary->fb, 0, 0,
200 adjusted_mode->hdisplay,
201 adjusted_mode->vdisplay,
202 x, y,
203 adjusted_mode->hdisplay,
204 adjusted_mode->vdisplay);
205 if (ret) {
206 DRM_ERROR("failed to mode set a plane\n");
207 return ret;
208 }
209
210 return 0;
211}
212
213static int _xilinx_drm_crtc_mode_set_base(struct drm_crtc *base_crtc,
214 struct drm_framebuffer *fb,
215 int x, int y)
216{
217 struct xilinx_drm_crtc *crtc = to_xilinx_crtc(base_crtc);
218 int ret;
219
220
221 xilinx_drm_plane_manager_mode_set(crtc->plane_manager,
222 base_crtc->hwmode.hdisplay,
223 base_crtc->hwmode.vdisplay);
224 ret = xilinx_drm_plane_mode_set(base_crtc->primary,
225 fb, 0, 0,
226 base_crtc->hwmode.hdisplay,
227 base_crtc->hwmode.vdisplay,
228 x, y,
229 base_crtc->hwmode.hdisplay,
230 base_crtc->hwmode.vdisplay);
231 if (ret) {
232 DRM_ERROR("failed to mode set a plane\n");
233 return ret;
234 }
235
236
237 xilinx_drm_crtc_commit(base_crtc);
238
239 return 0;
240}
241
242
243static int xilinx_drm_crtc_mode_set_base(struct drm_crtc *base_crtc,
244 int x, int y,
245 struct drm_framebuffer *old_fb)
246{
247
248 return _xilinx_drm_crtc_mode_set_base(base_crtc, base_crtc->primary->fb,
249 x, y);
250}
251
252
253static void xilinx_drm_crtc_load_lut(struct drm_crtc *base_crtc)
254{
255
256}
257
258static struct drm_crtc_helper_funcs xilinx_drm_crtc_helper_funcs = {
259 .dpms = xilinx_drm_crtc_dpms,
260 .prepare = xilinx_drm_crtc_prepare,
261 .commit = xilinx_drm_crtc_commit,
262 .mode_fixup = xilinx_drm_crtc_mode_fixup,
263 .mode_set = xilinx_drm_crtc_mode_set,
264 .mode_set_base = xilinx_drm_crtc_mode_set_base,
265 .load_lut = xilinx_drm_crtc_load_lut,
266};
267
268
269void xilinx_drm_crtc_destroy(struct drm_crtc *base_crtc)
270{
271 struct xilinx_drm_crtc *crtc = to_xilinx_crtc(base_crtc);
272
273
274 xilinx_drm_crtc_dpms(base_crtc, DRM_MODE_DPMS_OFF);
275
276 drm_crtc_cleanup(base_crtc);
277
278 if (crtc->dp_sub)
279 xilinx_drm_dp_sub_put(crtc->dp_sub);
280
281 if (crtc->pixel_clock_enabled) {
282 clk_disable_unprepare(crtc->pixel_clock);
283 crtc->pixel_clock_enabled = false;
284 }
285
286 xilinx_drm_plane_remove_manager(crtc->plane_manager);
287}
288
289
290int xilinx_drm_crtc_helper_set_config(struct drm_mode_set *set)
291{
292 struct drm_device *drm = set->crtc->dev;
293
294 xilinx_drm_set_config(drm, set);
295
296 return drm_crtc_helper_set_config(set);
297}
298
299
300void xilinx_drm_crtc_cancel_page_flip(struct drm_crtc *base_crtc,
301 struct drm_file *file)
302{
303 struct xilinx_drm_crtc *crtc = to_xilinx_crtc(base_crtc);
304 struct drm_device *drm = base_crtc->dev;
305 struct drm_pending_vblank_event *event;
306 unsigned long flags;
307
308 spin_lock_irqsave(&drm->event_lock, flags);
309 event = crtc->event;
310 if (event && (event->base.file_priv == file)) {
311 crtc->event = NULL;
312 kfree(&event->base);
313 drm_crtc_vblank_put(base_crtc);
314 }
315 spin_unlock_irqrestore(&drm->event_lock, flags);
316}
317
318
319static void xilinx_drm_crtc_finish_page_flip(struct drm_crtc *base_crtc)
320{
321 struct xilinx_drm_crtc *crtc = to_xilinx_crtc(base_crtc);
322 struct drm_device *drm = base_crtc->dev;
323 struct drm_pending_vblank_event *event;
324 unsigned long flags;
325
326 spin_lock_irqsave(&drm->event_lock, flags);
327 event = crtc->event;
328 crtc->event = NULL;
329 if (event) {
330 drm_crtc_send_vblank_event(base_crtc, event);
331 drm_crtc_vblank_put(base_crtc);
332 }
333 spin_unlock_irqrestore(&drm->event_lock, flags);
334}
335
336
337static int xilinx_drm_crtc_page_flip(struct drm_crtc *base_crtc,
338 struct drm_framebuffer *fb,
339 struct drm_pending_vblank_event *event,
340 uint32_t page_flip_flags)
341{
342 struct xilinx_drm_crtc *crtc = to_xilinx_crtc(base_crtc);
343 struct drm_device *drm = base_crtc->dev;
344 unsigned long flags;
345 int ret;
346
347 spin_lock_irqsave(&drm->event_lock, flags);
348 if (crtc->event != NULL) {
349 spin_unlock_irqrestore(&drm->event_lock, flags);
350 return -EBUSY;
351 }
352 spin_unlock_irqrestore(&drm->event_lock, flags);
353
354
355 ret = _xilinx_drm_crtc_mode_set_base(base_crtc, fb,
356 base_crtc->x, base_crtc->y);
357 if (ret) {
358 DRM_ERROR("failed to mode set a plane\n");
359 return ret;
360 }
361
362 base_crtc->primary->fb = fb;
363
364 if (event) {
365 event->pipe = 0;
366 drm_crtc_vblank_get(base_crtc);
367 spin_lock_irqsave(&drm->event_lock, flags);
368 crtc->event = event;
369 spin_unlock_irqrestore(&drm->event_lock, flags);
370 }
371
372 return 0;
373}
374
375
376static void xilinx_drm_crtc_vblank_handler(void *data)
377{
378 struct drm_crtc *base_crtc = data;
379 struct drm_device *drm;
380
381 if (!base_crtc)
382 return;
383
384 drm = base_crtc->dev;
385
386 drm_handle_vblank(drm, 0);
387 xilinx_drm_crtc_finish_page_flip(base_crtc);
388}
389
390
391void xilinx_drm_crtc_enable_vblank(struct drm_crtc *base_crtc)
392{
393 struct xilinx_drm_crtc *crtc = to_xilinx_crtc(base_crtc);
394
395 if (crtc->vtc)
396 xilinx_vtc_enable_vblank_intr(crtc->vtc,
397 xilinx_drm_crtc_vblank_handler,
398 base_crtc);
399 if (crtc->dp_sub)
400 xilinx_drm_dp_sub_enable_vblank(crtc->dp_sub,
401 xilinx_drm_crtc_vblank_handler,
402 base_crtc);
403}
404
405
406void xilinx_drm_crtc_disable_vblank(struct drm_crtc *base_crtc)
407{
408 struct xilinx_drm_crtc *crtc = to_xilinx_crtc(base_crtc);
409
410 if (crtc->dp_sub)
411 xilinx_drm_dp_sub_disable_vblank(crtc->dp_sub);
412 if (crtc->vtc)
413 xilinx_vtc_disable_vblank_intr(crtc->vtc);
414}
415
416
417
418
419
420
421
422
423void xilinx_drm_crtc_restore(struct drm_crtc *base_crtc)
424{
425 struct xilinx_drm_crtc *crtc = to_xilinx_crtc(base_crtc);
426
427 xilinx_drm_plane_restore(crtc->plane_manager);
428}
429
430
431unsigned int xilinx_drm_crtc_get_max_width(struct drm_crtc *base_crtc)
432{
433 return xilinx_drm_plane_get_max_width(base_crtc->primary);
434}
435
436
437bool xilinx_drm_crtc_check_format(struct drm_crtc *base_crtc, uint32_t fourcc)
438{
439 struct xilinx_drm_crtc *crtc = to_xilinx_crtc(base_crtc);
440
441 return xilinx_drm_plane_check_format(crtc->plane_manager, fourcc);
442}
443
444
445uint32_t xilinx_drm_crtc_get_format(struct drm_crtc *base_crtc)
446{
447 return xilinx_drm_plane_get_format(base_crtc->primary);
448}
449
450
451
452
453
454
455
456
457
458unsigned int xilinx_drm_crtc_get_align(struct drm_crtc *base_crtc)
459{
460 return xilinx_drm_plane_get_align(base_crtc->primary);
461}
462
463static struct drm_crtc_funcs xilinx_drm_crtc_funcs = {
464 .destroy = xilinx_drm_crtc_destroy,
465 .set_config = xilinx_drm_crtc_helper_set_config,
466 .page_flip = xilinx_drm_crtc_page_flip,
467};
468
469
470struct drm_crtc *xilinx_drm_crtc_create(struct drm_device *drm)
471{
472 struct xilinx_drm_crtc *crtc;
473 struct drm_plane *primary_plane;
474 struct device_node *sub_node;
475 int possible_crtcs = 1;
476 int ret;
477
478 crtc = devm_kzalloc(drm->dev, sizeof(*crtc), GFP_KERNEL);
479 if (!crtc)
480 return ERR_PTR(-ENOMEM);
481
482
483 sub_node = of_parse_phandle(drm->dev->of_node, "xlnx,cresample", 0);
484 if (sub_node) {
485 crtc->cresample = xilinx_cresample_probe(drm->dev, sub_node);
486 of_node_put(sub_node);
487 if (IS_ERR(crtc->cresample)) {
488 DRM_ERROR("failed to probe a cresample\n");
489 return ERR_CAST(crtc->cresample);
490 }
491 }
492
493
494 sub_node = of_parse_phandle(drm->dev->of_node, "xlnx,rgb2yuv", 0);
495 if (sub_node) {
496 crtc->rgb2yuv = xilinx_rgb2yuv_probe(drm->dev, sub_node);
497 of_node_put(sub_node);
498 if (IS_ERR(crtc->rgb2yuv)) {
499 DRM_ERROR("failed to probe a rgb2yuv\n");
500 return ERR_CAST(crtc->rgb2yuv);
501 }
502 }
503
504
505 crtc->plane_manager = xilinx_drm_plane_probe_manager(drm);
506 if (IS_ERR(crtc->plane_manager)) {
507 if (PTR_ERR(crtc->plane_manager) != -EPROBE_DEFER)
508 DRM_ERROR("failed to probe a plane manager\n");
509 return ERR_CAST(crtc->plane_manager);
510 }
511
512
513 primary_plane = xilinx_drm_plane_create_primary(crtc->plane_manager,
514 possible_crtcs);
515 if (IS_ERR(primary_plane)) {
516 DRM_ERROR("failed to create a primary plane for crtc\n");
517 ret = PTR_ERR(primary_plane);
518 goto err_plane;
519 }
520
521
522 xilinx_drm_plane_create_planes(crtc->plane_manager, possible_crtcs);
523
524 crtc->pixel_clock = devm_clk_get(drm->dev, NULL);
525 if (IS_ERR(crtc->pixel_clock)) {
526 if (PTR_ERR(crtc->pixel_clock) == -EPROBE_DEFER) {
527 ret = PTR_ERR(crtc->pixel_clock);
528 goto err_plane;
529 } else {
530 DRM_DEBUG_KMS("failed to get pixel clock\n");
531 crtc->pixel_clock = NULL;
532 }
533
534 }
535
536 ret = clk_prepare_enable(crtc->pixel_clock);
537 if (ret) {
538 DRM_ERROR("failed to enable a pixel clock\n");
539 crtc->pixel_clock_enabled = false;
540 goto err_plane;
541 }
542 crtc->pixel_clock_enabled = true;
543
544 sub_node = of_parse_phandle(drm->dev->of_node, "xlnx,vtc", 0);
545 if (sub_node) {
546 crtc->vtc = xilinx_vtc_probe(drm->dev, sub_node);
547 of_node_put(sub_node);
548 if (IS_ERR(crtc->vtc)) {
549 DRM_ERROR("failed to probe video timing controller\n");
550 ret = PTR_ERR(crtc->vtc);
551 goto err_pixel_clk;
552 }
553 }
554
555 crtc->dp_sub = xilinx_drm_dp_sub_of_get(drm->dev->of_node);
556 if (IS_ERR(crtc->dp_sub)) {
557 ret = PTR_ERR(crtc->dp_sub);
558 if (ret != -EPROBE_DEFER)
559 DRM_ERROR("failed to get a dp_sub\n");
560 goto err_pixel_clk;
561 }
562
563 crtc->dpms = DRM_MODE_DPMS_OFF;
564
565
566 ret = drm_crtc_init_with_planes(drm, &crtc->base, primary_plane,
567 NULL, &xilinx_drm_crtc_funcs, NULL);
568 if (ret) {
569 DRM_ERROR("failed to initialize crtc\n");
570 goto err_pixel_clk;
571 }
572 drm_crtc_helper_add(&crtc->base, &xilinx_drm_crtc_helper_funcs);
573
574 return &crtc->base;
575
576err_pixel_clk:
577 if (crtc->pixel_clock_enabled) {
578 clk_disable_unprepare(crtc->pixel_clock);
579 crtc->pixel_clock_enabled = false;
580 }
581err_plane:
582 xilinx_drm_plane_remove_manager(crtc->plane_manager);
583 return ERR_PTR(ret);
584}
585