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