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