1
2
3
4
5
6
7
8
9#include <linux/component.h>
10#include <linux/list.h>
11#include <linux/module.h>
12#include <linux/of_device.h>
13#include <linux/of_graph.h>
14#include <linux/platform_device.h>
15#include <linux/reset.h>
16
17#include <drm/drm_atomic.h>
18#include <drm/drm_atomic_helper.h>
19#include <drm/drm_crtc.h>
20#include <drm/drm_fb_cma_helper.h>
21#include <drm/drm_fourcc.h>
22#include <drm/drm_gem_cma_helper.h>
23#include <drm/drm_plane_helper.h>
24#include <drm/drm_probe_helper.h>
25
26#include "sun4i_backend.h"
27#include "sun4i_drv.h"
28#include "sun4i_frontend.h"
29#include "sun4i_layer.h"
30#include "sunxi_engine.h"
31
32struct sun4i_backend_quirks {
33
34 bool needs_output_muxing;
35
36
37 bool supports_lowest_plane_alpha;
38};
39
40static const u32 sunxi_rgb2yuv_coef[12] = {
41 0x00000107, 0x00000204, 0x00000064, 0x00000108,
42 0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808,
43 0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808
44};
45
46static void sun4i_backend_apply_color_correction(struct sunxi_engine *engine)
47{
48 int i;
49
50 DRM_DEBUG_DRIVER("Applying RGB to YUV color correction\n");
51
52
53 regmap_write(engine->regs, SUN4I_BACKEND_OCCTL_REG,
54 SUN4I_BACKEND_OCCTL_ENABLE);
55
56 for (i = 0; i < 12; i++)
57 regmap_write(engine->regs, SUN4I_BACKEND_OCRCOEF_REG(i),
58 sunxi_rgb2yuv_coef[i]);
59}
60
61static void sun4i_backend_disable_color_correction(struct sunxi_engine *engine)
62{
63 DRM_DEBUG_DRIVER("Disabling color correction\n");
64
65
66 regmap_update_bits(engine->regs, SUN4I_BACKEND_OCCTL_REG,
67 SUN4I_BACKEND_OCCTL_ENABLE, 0);
68}
69
70static void sun4i_backend_commit(struct sunxi_engine *engine)
71{
72 DRM_DEBUG_DRIVER("Committing changes\n");
73
74 regmap_write(engine->regs, SUN4I_BACKEND_REGBUFFCTL_REG,
75 SUN4I_BACKEND_REGBUFFCTL_AUTOLOAD_DIS |
76 SUN4I_BACKEND_REGBUFFCTL_LOADCTL);
77}
78
79void sun4i_backend_layer_enable(struct sun4i_backend *backend,
80 int layer, bool enable)
81{
82 u32 val;
83
84 DRM_DEBUG_DRIVER("%sabling layer %d\n", enable ? "En" : "Dis",
85 layer);
86
87 if (enable)
88 val = SUN4I_BACKEND_MODCTL_LAY_EN(layer);
89 else
90 val = 0;
91
92 regmap_update_bits(backend->engine.regs, SUN4I_BACKEND_MODCTL_REG,
93 SUN4I_BACKEND_MODCTL_LAY_EN(layer), val);
94}
95
96static int sun4i_backend_drm_format_to_layer(u32 format, u32 *mode)
97{
98 switch (format) {
99 case DRM_FORMAT_ARGB8888:
100 *mode = SUN4I_BACKEND_LAY_FBFMT_ARGB8888;
101 break;
102
103 case DRM_FORMAT_ARGB4444:
104 *mode = SUN4I_BACKEND_LAY_FBFMT_ARGB4444;
105 break;
106
107 case DRM_FORMAT_ARGB1555:
108 *mode = SUN4I_BACKEND_LAY_FBFMT_ARGB1555;
109 break;
110
111 case DRM_FORMAT_RGBA5551:
112 *mode = SUN4I_BACKEND_LAY_FBFMT_RGBA5551;
113 break;
114
115 case DRM_FORMAT_RGBA4444:
116 *mode = SUN4I_BACKEND_LAY_FBFMT_RGBA4444;
117 break;
118
119 case DRM_FORMAT_XRGB8888:
120 *mode = SUN4I_BACKEND_LAY_FBFMT_XRGB8888;
121 break;
122
123 case DRM_FORMAT_RGB888:
124 *mode = SUN4I_BACKEND_LAY_FBFMT_RGB888;
125 break;
126
127 case DRM_FORMAT_RGB565:
128 *mode = SUN4I_BACKEND_LAY_FBFMT_RGB565;
129 break;
130
131 default:
132 return -EINVAL;
133 }
134
135 return 0;
136}
137
138static const uint32_t sun4i_backend_formats[] = {
139 DRM_FORMAT_ARGB1555,
140 DRM_FORMAT_ARGB4444,
141 DRM_FORMAT_ARGB8888,
142 DRM_FORMAT_RGB565,
143 DRM_FORMAT_RGB888,
144 DRM_FORMAT_RGBA4444,
145 DRM_FORMAT_RGBA5551,
146 DRM_FORMAT_UYVY,
147 DRM_FORMAT_VYUY,
148 DRM_FORMAT_XRGB8888,
149 DRM_FORMAT_YUYV,
150 DRM_FORMAT_YVYU,
151};
152
153bool sun4i_backend_format_is_supported(uint32_t fmt, uint64_t modifier)
154{
155 unsigned int i;
156
157 if (modifier != DRM_FORMAT_MOD_LINEAR)
158 return false;
159
160 for (i = 0; i < ARRAY_SIZE(sun4i_backend_formats); i++)
161 if (sun4i_backend_formats[i] == fmt)
162 return true;
163
164 return false;
165}
166
167int sun4i_backend_update_layer_coord(struct sun4i_backend *backend,
168 int layer, struct drm_plane *plane)
169{
170 struct drm_plane_state *state = plane->state;
171
172 DRM_DEBUG_DRIVER("Updating layer %d\n", layer);
173
174 if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
175 DRM_DEBUG_DRIVER("Primary layer, updating global size W: %u H: %u\n",
176 state->crtc_w, state->crtc_h);
177 regmap_write(backend->engine.regs, SUN4I_BACKEND_DISSIZE_REG,
178 SUN4I_BACKEND_DISSIZE(state->crtc_w,
179 state->crtc_h));
180 }
181
182
183 DRM_DEBUG_DRIVER("Layer size W: %u H: %u\n",
184 state->crtc_w, state->crtc_h);
185 regmap_write(backend->engine.regs, SUN4I_BACKEND_LAYSIZE_REG(layer),
186 SUN4I_BACKEND_LAYSIZE(state->crtc_w,
187 state->crtc_h));
188
189
190 DRM_DEBUG_DRIVER("Layer coordinates X: %d Y: %d\n",
191 state->crtc_x, state->crtc_y);
192 regmap_write(backend->engine.regs, SUN4I_BACKEND_LAYCOOR_REG(layer),
193 SUN4I_BACKEND_LAYCOOR(state->crtc_x,
194 state->crtc_y));
195
196 return 0;
197}
198
199static int sun4i_backend_update_yuv_format(struct sun4i_backend *backend,
200 int layer, struct drm_plane *plane)
201{
202 struct drm_plane_state *state = plane->state;
203 struct drm_framebuffer *fb = state->fb;
204 const struct drm_format_info *format = fb->format;
205 const uint32_t fmt = format->format;
206 u32 val = SUN4I_BACKEND_IYUVCTL_EN;
207 int i;
208
209 for (i = 0; i < ARRAY_SIZE(sunxi_bt601_yuv2rgb_coef); i++)
210 regmap_write(backend->engine.regs,
211 SUN4I_BACKEND_YGCOEF_REG(i),
212 sunxi_bt601_yuv2rgb_coef[i]);
213
214
215
216
217
218 regmap_update_bits(backend->engine.regs, SUN4I_BACKEND_ATTCTL_REG0(layer),
219 SUN4I_BACKEND_ATTCTL_REG0_LAY_YUVEN,
220 SUN4I_BACKEND_ATTCTL_REG0_LAY_YUVEN);
221
222
223 if (drm_format_info_is_yuv_packed(format) &&
224 drm_format_info_is_yuv_sampling_422(format))
225 val |= SUN4I_BACKEND_IYUVCTL_FBFMT_PACKED_YUV422;
226 else
227 DRM_DEBUG_DRIVER("Unsupported YUV format (0x%x)\n", fmt);
228
229
230
231
232
233 switch (fmt) {
234 case DRM_FORMAT_YUYV:
235 val |= SUN4I_BACKEND_IYUVCTL_FBPS_VYUY;
236 break;
237 case DRM_FORMAT_YVYU:
238 val |= SUN4I_BACKEND_IYUVCTL_FBPS_UYVY;
239 break;
240 case DRM_FORMAT_UYVY:
241 val |= SUN4I_BACKEND_IYUVCTL_FBPS_YVYU;
242 break;
243 case DRM_FORMAT_VYUY:
244 val |= SUN4I_BACKEND_IYUVCTL_FBPS_YUYV;
245 break;
246 default:
247 DRM_DEBUG_DRIVER("Unsupported YUV pixel sequence (0x%x)\n",
248 fmt);
249 }
250
251 regmap_write(backend->engine.regs, SUN4I_BACKEND_IYUVCTL_REG, val);
252
253 return 0;
254}
255
256int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
257 int layer, struct drm_plane *plane)
258{
259 struct drm_plane_state *state = plane->state;
260 struct drm_framebuffer *fb = state->fb;
261 bool interlaced = false;
262 u32 val;
263 int ret;
264
265
266 regmap_update_bits(backend->engine.regs, SUN4I_BACKEND_ATTCTL_REG0(layer),
267 SUN4I_BACKEND_ATTCTL_REG0_LAY_YUVEN, 0);
268
269 if (plane->state->crtc)
270 interlaced = plane->state->crtc->state->adjusted_mode.flags
271 & DRM_MODE_FLAG_INTERLACE;
272
273 regmap_update_bits(backend->engine.regs, SUN4I_BACKEND_MODCTL_REG,
274 SUN4I_BACKEND_MODCTL_ITLMOD_EN,
275 interlaced ? SUN4I_BACKEND_MODCTL_ITLMOD_EN : 0);
276
277 DRM_DEBUG_DRIVER("Switching display backend interlaced mode %s\n",
278 interlaced ? "on" : "off");
279
280 val = SUN4I_BACKEND_ATTCTL_REG0_LAY_GLBALPHA(state->alpha >> 8);
281 if (state->alpha != DRM_BLEND_ALPHA_OPAQUE)
282 val |= SUN4I_BACKEND_ATTCTL_REG0_LAY_GLBALPHA_EN;
283 regmap_update_bits(backend->engine.regs,
284 SUN4I_BACKEND_ATTCTL_REG0(layer),
285 SUN4I_BACKEND_ATTCTL_REG0_LAY_GLBALPHA_MASK |
286 SUN4I_BACKEND_ATTCTL_REG0_LAY_GLBALPHA_EN,
287 val);
288
289 if (fb->format->is_yuv)
290 return sun4i_backend_update_yuv_format(backend, layer, plane);
291
292 ret = sun4i_backend_drm_format_to_layer(fb->format->format, &val);
293 if (ret) {
294 DRM_DEBUG_DRIVER("Invalid format\n");
295 return ret;
296 }
297
298 regmap_update_bits(backend->engine.regs,
299 SUN4I_BACKEND_ATTCTL_REG1(layer),
300 SUN4I_BACKEND_ATTCTL_REG1_LAY_FBFMT, val);
301
302 return 0;
303}
304
305int sun4i_backend_update_layer_frontend(struct sun4i_backend *backend,
306 int layer, uint32_t fmt)
307{
308 u32 val;
309 int ret;
310
311 ret = sun4i_backend_drm_format_to_layer(fmt, &val);
312 if (ret) {
313 DRM_DEBUG_DRIVER("Invalid format\n");
314 return ret;
315 }
316
317 regmap_update_bits(backend->engine.regs,
318 SUN4I_BACKEND_ATTCTL_REG0(layer),
319 SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN,
320 SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN);
321
322 regmap_update_bits(backend->engine.regs,
323 SUN4I_BACKEND_ATTCTL_REG1(layer),
324 SUN4I_BACKEND_ATTCTL_REG1_LAY_FBFMT, val);
325
326 return 0;
327}
328
329static int sun4i_backend_update_yuv_buffer(struct sun4i_backend *backend,
330 struct drm_framebuffer *fb,
331 dma_addr_t paddr)
332{
333
334 DRM_DEBUG_DRIVER("Setting packed YUV buffer address to %pad\n", &paddr);
335 regmap_write(backend->engine.regs, SUN4I_BACKEND_IYUVADD_REG(0), paddr);
336
337 DRM_DEBUG_DRIVER("Layer line width: %d bits\n", fb->pitches[0] * 8);
338 regmap_write(backend->engine.regs, SUN4I_BACKEND_IYUVLINEWIDTH_REG(0),
339 fb->pitches[0] * 8);
340
341 return 0;
342}
343
344int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
345 int layer, struct drm_plane *plane)
346{
347 struct drm_plane_state *state = plane->state;
348 struct drm_framebuffer *fb = state->fb;
349 u32 lo_paddr, hi_paddr;
350 dma_addr_t paddr;
351
352
353 DRM_DEBUG_DRIVER("Layer line width: %d bits\n", fb->pitches[0] * 8);
354 regmap_write(backend->engine.regs,
355 SUN4I_BACKEND_LAYLINEWIDTH_REG(layer),
356 fb->pitches[0] * 8);
357
358
359 paddr = drm_fb_cma_get_gem_addr(fb, state, 0);
360 DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);
361
362 if (fb->format->is_yuv)
363 return sun4i_backend_update_yuv_buffer(backend, fb, paddr);
364
365
366 lo_paddr = paddr << 3;
367 DRM_DEBUG_DRIVER("Setting address lower bits to 0x%x\n", lo_paddr);
368 regmap_write(backend->engine.regs,
369 SUN4I_BACKEND_LAYFB_L32ADD_REG(layer),
370 lo_paddr);
371
372
373 hi_paddr = paddr >> 29;
374 DRM_DEBUG_DRIVER("Setting address high bits to 0x%x\n", hi_paddr);
375 regmap_update_bits(backend->engine.regs, SUN4I_BACKEND_LAYFB_H4ADD_REG,
376 SUN4I_BACKEND_LAYFB_H4ADD_MSK(layer),
377 SUN4I_BACKEND_LAYFB_H4ADD(layer, hi_paddr));
378
379 return 0;
380}
381
382int sun4i_backend_update_layer_zpos(struct sun4i_backend *backend, int layer,
383 struct drm_plane *plane)
384{
385 struct drm_plane_state *state = plane->state;
386 struct sun4i_layer_state *p_state = state_to_sun4i_layer_state(state);
387 unsigned int priority = state->normalized_zpos;
388 unsigned int pipe = p_state->pipe;
389
390 DRM_DEBUG_DRIVER("Setting layer %d's priority to %d and pipe %d\n",
391 layer, priority, pipe);
392 regmap_update_bits(backend->engine.regs, SUN4I_BACKEND_ATTCTL_REG0(layer),
393 SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL_MASK |
394 SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL_MASK,
395 SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(p_state->pipe) |
396 SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL(priority));
397
398 return 0;
399}
400
401void sun4i_backend_cleanup_layer(struct sun4i_backend *backend,
402 int layer)
403{
404 regmap_update_bits(backend->engine.regs,
405 SUN4I_BACKEND_ATTCTL_REG0(layer),
406 SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN |
407 SUN4I_BACKEND_ATTCTL_REG0_LAY_YUVEN, 0);
408}
409
410static bool sun4i_backend_plane_uses_scaler(struct drm_plane_state *state)
411{
412 u16 src_h = state->src_h >> 16;
413 u16 src_w = state->src_w >> 16;
414
415 DRM_DEBUG_DRIVER("Input size %dx%d, output size %dx%d\n",
416 src_w, src_h, state->crtc_w, state->crtc_h);
417
418 if ((state->crtc_h != src_h) || (state->crtc_w != src_w))
419 return true;
420
421 return false;
422}
423
424static bool sun4i_backend_plane_uses_frontend(struct drm_plane_state *state)
425{
426 struct sun4i_layer *layer = plane_to_sun4i_layer(state->plane);
427 struct sun4i_backend *backend = layer->backend;
428 uint32_t format = state->fb->format->format;
429 uint64_t modifier = state->fb->modifier;
430
431 if (IS_ERR(backend->frontend))
432 return false;
433
434 if (!sun4i_frontend_format_is_supported(format, modifier))
435 return false;
436
437 if (!sun4i_backend_format_is_supported(format, modifier))
438 return true;
439
440
441
442
443
444
445
446
447 if (sun4i_backend_plane_uses_scaler(state))
448 return true;
449
450
451
452
453
454 return false;
455}
456
457static bool sun4i_backend_plane_is_supported(struct drm_plane_state *state,
458 bool *uses_frontend)
459{
460 if (sun4i_backend_plane_uses_frontend(state)) {
461 *uses_frontend = true;
462 return true;
463 }
464
465 *uses_frontend = false;
466
467
468 if (sun4i_backend_plane_uses_scaler(state))
469 return false;
470
471 return true;
472}
473
474static void sun4i_backend_atomic_begin(struct sunxi_engine *engine,
475 struct drm_crtc_state *old_state)
476{
477 u32 val;
478
479 WARN_ON(regmap_read_poll_timeout(engine->regs,
480 SUN4I_BACKEND_REGBUFFCTL_REG,
481 val, !(val & SUN4I_BACKEND_REGBUFFCTL_LOADCTL),
482 100, 50000));
483}
484
485static int sun4i_backend_atomic_check(struct sunxi_engine *engine,
486 struct drm_crtc_state *crtc_state)
487{
488 struct drm_plane_state *plane_states[SUN4I_BACKEND_NUM_LAYERS] = { 0 };
489 struct sun4i_backend *backend = engine_to_sun4i_backend(engine);
490 struct drm_atomic_state *state = crtc_state->state;
491 struct drm_device *drm = state->dev;
492 struct drm_plane *plane;
493 unsigned int num_planes = 0;
494 unsigned int num_alpha_planes = 0;
495 unsigned int num_frontend_planes = 0;
496 unsigned int num_alpha_planes_max = 1;
497 unsigned int num_yuv_planes = 0;
498 unsigned int current_pipe = 0;
499 unsigned int i;
500
501 DRM_DEBUG_DRIVER("Starting checking our planes\n");
502
503 if (!crtc_state->planes_changed)
504 return 0;
505
506 drm_for_each_plane_mask(plane, drm, crtc_state->plane_mask) {
507 struct drm_plane_state *plane_state =
508 drm_atomic_get_plane_state(state, plane);
509 struct sun4i_layer_state *layer_state =
510 state_to_sun4i_layer_state(plane_state);
511 struct drm_framebuffer *fb = plane_state->fb;
512 struct drm_format_name_buf format_name;
513
514 if (!sun4i_backend_plane_is_supported(plane_state,
515 &layer_state->uses_frontend))
516 return -EINVAL;
517
518 if (layer_state->uses_frontend) {
519 DRM_DEBUG_DRIVER("Using the frontend for plane %d\n",
520 plane->index);
521 num_frontend_planes++;
522 } else {
523 if (fb->format->is_yuv) {
524 DRM_DEBUG_DRIVER("Plane FB format is YUV\n");
525 num_yuv_planes++;
526 }
527 }
528
529 DRM_DEBUG_DRIVER("Plane FB format is %s\n",
530 drm_get_format_name(fb->format->format,
531 &format_name));
532 if (fb->format->has_alpha || (plane_state->alpha != DRM_BLEND_ALPHA_OPAQUE))
533 num_alpha_planes++;
534
535 DRM_DEBUG_DRIVER("Plane zpos is %d\n",
536 plane_state->normalized_zpos);
537
538
539 plane_states[plane_state->normalized_zpos] = plane_state;
540
541 num_planes++;
542 }
543
544
545 if (!num_planes)
546 return 0;
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582 if (backend->quirks->supports_lowest_plane_alpha)
583 num_alpha_planes_max++;
584
585 if (num_alpha_planes > num_alpha_planes_max) {
586 DRM_DEBUG_DRIVER("Too many planes with alpha, rejecting...\n");
587 return -EINVAL;
588 }
589
590
591 if (!backend->quirks->supports_lowest_plane_alpha &&
592 (plane_states[0]->fb->format->has_alpha ||
593 (plane_states[0]->alpha != DRM_BLEND_ALPHA_OPAQUE)))
594 return -EINVAL;
595
596 for (i = 1; i < num_planes; i++) {
597 struct drm_plane_state *p_state = plane_states[i];
598 struct drm_framebuffer *fb = p_state->fb;
599 struct sun4i_layer_state *s_state = state_to_sun4i_layer_state(p_state);
600
601
602
603
604
605 if (fb->format->has_alpha || (p_state->alpha != DRM_BLEND_ALPHA_OPAQUE))
606 current_pipe++;
607
608 s_state->pipe = current_pipe;
609 }
610
611
612 if (num_yuv_planes > SUN4I_BACKEND_NUM_YUV_PLANES) {
613 DRM_DEBUG_DRIVER("Too many planes with YUV, rejecting...\n");
614 return -EINVAL;
615 }
616
617 if (num_frontend_planes > SUN4I_BACKEND_NUM_FRONTEND_LAYERS) {
618 DRM_DEBUG_DRIVER("Too many planes going through the frontend, rejecting\n");
619 return -EINVAL;
620 }
621
622 DRM_DEBUG_DRIVER("State valid with %u planes, %u alpha, %u video, %u YUV\n",
623 num_planes, num_alpha_planes, num_frontend_planes,
624 num_yuv_planes);
625
626 return 0;
627}
628
629static void sun4i_backend_vblank_quirk(struct sunxi_engine *engine)
630{
631 struct sun4i_backend *backend = engine_to_sun4i_backend(engine);
632 struct sun4i_frontend *frontend = backend->frontend;
633
634 if (!frontend)
635 return;
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651 spin_lock(&backend->frontend_lock);
652 if (backend->frontend_teardown) {
653 sun4i_frontend_exit(frontend);
654 backend->frontend_teardown = false;
655 }
656 spin_unlock(&backend->frontend_lock);
657};
658
659static int sun4i_backend_init_sat(struct device *dev) {
660 struct sun4i_backend *backend = dev_get_drvdata(dev);
661 int ret;
662
663 backend->sat_reset = devm_reset_control_get(dev, "sat");
664 if (IS_ERR(backend->sat_reset)) {
665 dev_err(dev, "Couldn't get the SAT reset line\n");
666 return PTR_ERR(backend->sat_reset);
667 }
668
669 ret = reset_control_deassert(backend->sat_reset);
670 if (ret) {
671 dev_err(dev, "Couldn't deassert the SAT reset line\n");
672 return ret;
673 }
674
675 backend->sat_clk = devm_clk_get(dev, "sat");
676 if (IS_ERR(backend->sat_clk)) {
677 dev_err(dev, "Couldn't get our SAT clock\n");
678 ret = PTR_ERR(backend->sat_clk);
679 goto err_assert_reset;
680 }
681
682 ret = clk_prepare_enable(backend->sat_clk);
683 if (ret) {
684 dev_err(dev, "Couldn't enable the SAT clock\n");
685 return ret;
686 }
687
688 return 0;
689
690err_assert_reset:
691 reset_control_assert(backend->sat_reset);
692 return ret;
693}
694
695static int sun4i_backend_free_sat(struct device *dev) {
696 struct sun4i_backend *backend = dev_get_drvdata(dev);
697
698 clk_disable_unprepare(backend->sat_clk);
699 reset_control_assert(backend->sat_reset);
700
701 return 0;
702}
703
704
705
706
707
708
709
710
711
712static int sun4i_backend_of_get_id(struct device_node *node)
713{
714 struct device_node *ep, *remote;
715 struct of_endpoint of_ep;
716
717
718 ep = of_graph_get_endpoint_by_regs(node, 0, -1);
719 if (!ep)
720 return -EINVAL;
721
722 remote = of_graph_get_remote_endpoint(ep);
723 of_node_put(ep);
724 if (!remote)
725 return -EINVAL;
726
727 of_graph_parse_endpoint(remote, &of_ep);
728 of_node_put(remote);
729 return of_ep.id;
730}
731
732
733static struct sun4i_frontend *sun4i_backend_find_frontend(struct sun4i_drv *drv,
734 struct device_node *node)
735{
736 struct device_node *port, *ep, *remote;
737 struct sun4i_frontend *frontend;
738
739 port = of_graph_get_port_by_id(node, 0);
740 if (!port)
741 return ERR_PTR(-EINVAL);
742
743 for_each_available_child_of_node(port, ep) {
744 remote = of_graph_get_remote_port_parent(ep);
745 if (!remote)
746 continue;
747 of_node_put(remote);
748
749
750 list_for_each_entry(frontend, &drv->frontend_list, list) {
751 if (remote == frontend->node) {
752 of_node_put(port);
753 of_node_put(ep);
754 return frontend;
755 }
756 }
757 }
758 of_node_put(port);
759 return ERR_PTR(-EINVAL);
760}
761
762static const struct sunxi_engine_ops sun4i_backend_engine_ops = {
763 .atomic_begin = sun4i_backend_atomic_begin,
764 .atomic_check = sun4i_backend_atomic_check,
765 .commit = sun4i_backend_commit,
766 .layers_init = sun4i_layers_init,
767 .apply_color_correction = sun4i_backend_apply_color_correction,
768 .disable_color_correction = sun4i_backend_disable_color_correction,
769 .vblank_quirk = sun4i_backend_vblank_quirk,
770};
771
772static struct regmap_config sun4i_backend_regmap_config = {
773 .reg_bits = 32,
774 .val_bits = 32,
775 .reg_stride = 4,
776 .max_register = 0x5800,
777};
778
779static int sun4i_backend_bind(struct device *dev, struct device *master,
780 void *data)
781{
782 struct platform_device *pdev = to_platform_device(dev);
783 struct drm_device *drm = data;
784 struct sun4i_drv *drv = drm->dev_private;
785 struct sun4i_backend *backend;
786 const struct sun4i_backend_quirks *quirks;
787 struct resource *res;
788 void __iomem *regs;
789 int i, ret;
790
791 backend = devm_kzalloc(dev, sizeof(*backend), GFP_KERNEL);
792 if (!backend)
793 return -ENOMEM;
794 dev_set_drvdata(dev, backend);
795 spin_lock_init(&backend->frontend_lock);
796
797 if (of_find_property(dev->of_node, "interconnects", NULL)) {
798
799
800
801
802
803
804
805 ret = of_dma_configure(drm->dev, dev->of_node, true);
806 if (ret)
807 return ret;
808 } else {
809
810
811
812
813
814
815 drm->dev->dma_pfn_offset = PHYS_PFN_OFFSET;
816 }
817
818 backend->engine.node = dev->of_node;
819 backend->engine.ops = &sun4i_backend_engine_ops;
820 backend->engine.id = sun4i_backend_of_get_id(dev->of_node);
821 if (backend->engine.id < 0)
822 return backend->engine.id;
823
824 backend->frontend = sun4i_backend_find_frontend(drv, dev->of_node);
825 if (IS_ERR(backend->frontend))
826 dev_warn(dev, "Couldn't find matching frontend, frontend features disabled\n");
827
828 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
829 regs = devm_ioremap_resource(dev, res);
830 if (IS_ERR(regs))
831 return PTR_ERR(regs);
832
833 backend->reset = devm_reset_control_get(dev, NULL);
834 if (IS_ERR(backend->reset)) {
835 dev_err(dev, "Couldn't get our reset line\n");
836 return PTR_ERR(backend->reset);
837 }
838
839 ret = reset_control_deassert(backend->reset);
840 if (ret) {
841 dev_err(dev, "Couldn't deassert our reset line\n");
842 return ret;
843 }
844
845 backend->bus_clk = devm_clk_get(dev, "ahb");
846 if (IS_ERR(backend->bus_clk)) {
847 dev_err(dev, "Couldn't get the backend bus clock\n");
848 ret = PTR_ERR(backend->bus_clk);
849 goto err_assert_reset;
850 }
851 clk_prepare_enable(backend->bus_clk);
852
853 backend->mod_clk = devm_clk_get(dev, "mod");
854 if (IS_ERR(backend->mod_clk)) {
855 dev_err(dev, "Couldn't get the backend module clock\n");
856 ret = PTR_ERR(backend->mod_clk);
857 goto err_disable_bus_clk;
858 }
859 clk_prepare_enable(backend->mod_clk);
860
861 backend->ram_clk = devm_clk_get(dev, "ram");
862 if (IS_ERR(backend->ram_clk)) {
863 dev_err(dev, "Couldn't get the backend RAM clock\n");
864 ret = PTR_ERR(backend->ram_clk);
865 goto err_disable_mod_clk;
866 }
867 clk_prepare_enable(backend->ram_clk);
868
869 if (of_device_is_compatible(dev->of_node,
870 "allwinner,sun8i-a33-display-backend")) {
871 ret = sun4i_backend_init_sat(dev);
872 if (ret) {
873 dev_err(dev, "Couldn't init SAT resources\n");
874 goto err_disable_ram_clk;
875 }
876 }
877
878 backend->engine.regs = devm_regmap_init_mmio(dev, regs,
879 &sun4i_backend_regmap_config);
880 if (IS_ERR(backend->engine.regs)) {
881 dev_err(dev, "Couldn't create the backend regmap\n");
882 return PTR_ERR(backend->engine.regs);
883 }
884
885 list_add_tail(&backend->engine.list, &drv->engine_list);
886
887
888
889
890
891
892
893
894
895 for (i = 0x800; i < 0x1000; i += 4)
896 regmap_write(backend->engine.regs, i, 0);
897
898
899 regmap_write(backend->engine.regs, SUN4I_BACKEND_REGBUFFCTL_REG,
900 SUN4I_BACKEND_REGBUFFCTL_AUTOLOAD_DIS);
901
902
903 regmap_write(backend->engine.regs, SUN4I_BACKEND_MODCTL_REG,
904 SUN4I_BACKEND_MODCTL_DEBE_EN |
905 SUN4I_BACKEND_MODCTL_START_CTL);
906
907
908 quirks = of_device_get_match_data(dev);
909 if (quirks->needs_output_muxing) {
910
911
912
913
914
915
916
917
918
919
920 regmap_update_bits(backend->engine.regs,
921 SUN4I_BACKEND_MODCTL_REG,
922 SUN4I_BACKEND_MODCTL_OUT_SEL,
923 (backend->engine.id
924 ? SUN4I_BACKEND_MODCTL_OUT_LCD1
925 : SUN4I_BACKEND_MODCTL_OUT_LCD0));
926 }
927
928 backend->quirks = quirks;
929
930 return 0;
931
932err_disable_ram_clk:
933 clk_disable_unprepare(backend->ram_clk);
934err_disable_mod_clk:
935 clk_disable_unprepare(backend->mod_clk);
936err_disable_bus_clk:
937 clk_disable_unprepare(backend->bus_clk);
938err_assert_reset:
939 reset_control_assert(backend->reset);
940 return ret;
941}
942
943static void sun4i_backend_unbind(struct device *dev, struct device *master,
944 void *data)
945{
946 struct sun4i_backend *backend = dev_get_drvdata(dev);
947
948 list_del(&backend->engine.list);
949
950 if (of_device_is_compatible(dev->of_node,
951 "allwinner,sun8i-a33-display-backend"))
952 sun4i_backend_free_sat(dev);
953
954 clk_disable_unprepare(backend->ram_clk);
955 clk_disable_unprepare(backend->mod_clk);
956 clk_disable_unprepare(backend->bus_clk);
957 reset_control_assert(backend->reset);
958}
959
960static const struct component_ops sun4i_backend_ops = {
961 .bind = sun4i_backend_bind,
962 .unbind = sun4i_backend_unbind,
963};
964
965static int sun4i_backend_probe(struct platform_device *pdev)
966{
967 return component_add(&pdev->dev, &sun4i_backend_ops);
968}
969
970static int sun4i_backend_remove(struct platform_device *pdev)
971{
972 component_del(&pdev->dev, &sun4i_backend_ops);
973
974 return 0;
975}
976
977static const struct sun4i_backend_quirks sun4i_backend_quirks = {
978 .needs_output_muxing = true,
979};
980
981static const struct sun4i_backend_quirks sun5i_backend_quirks = {
982};
983
984static const struct sun4i_backend_quirks sun6i_backend_quirks = {
985};
986
987static const struct sun4i_backend_quirks sun7i_backend_quirks = {
988 .needs_output_muxing = true,
989 .supports_lowest_plane_alpha = true,
990};
991
992static const struct sun4i_backend_quirks sun8i_a33_backend_quirks = {
993 .supports_lowest_plane_alpha = true,
994};
995
996static const struct sun4i_backend_quirks sun9i_backend_quirks = {
997};
998
999static const struct of_device_id sun4i_backend_of_table[] = {
1000 {
1001 .compatible = "allwinner,sun4i-a10-display-backend",
1002 .data = &sun4i_backend_quirks,
1003 },
1004 {
1005 .compatible = "allwinner,sun5i-a13-display-backend",
1006 .data = &sun5i_backend_quirks,
1007 },
1008 {
1009 .compatible = "allwinner,sun6i-a31-display-backend",
1010 .data = &sun6i_backend_quirks,
1011 },
1012 {
1013 .compatible = "allwinner,sun7i-a20-display-backend",
1014 .data = &sun7i_backend_quirks,
1015 },
1016 {
1017 .compatible = "allwinner,sun8i-a23-display-backend",
1018 .data = &sun8i_a33_backend_quirks,
1019 },
1020 {
1021 .compatible = "allwinner,sun8i-a33-display-backend",
1022 .data = &sun8i_a33_backend_quirks,
1023 },
1024 {
1025 .compatible = "allwinner,sun9i-a80-display-backend",
1026 .data = &sun9i_backend_quirks,
1027 },
1028 { }
1029};
1030MODULE_DEVICE_TABLE(of, sun4i_backend_of_table);
1031
1032static struct platform_driver sun4i_backend_platform_driver = {
1033 .probe = sun4i_backend_probe,
1034 .remove = sun4i_backend_remove,
1035 .driver = {
1036 .name = "sun4i-backend",
1037 .of_match_table = sun4i_backend_of_table,
1038 },
1039};
1040module_platform_driver(sun4i_backend_platform_driver);
1041
1042MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
1043MODULE_DESCRIPTION("Allwinner A10 Display Backend Driver");
1044MODULE_LICENSE("GPL");
1045