.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (C) 2015 Free Electrons |
---|
3 | 4 | * Copyright (C) 2015 NextThing Co |
---|
4 | 5 | * |
---|
5 | 6 | * Maxime Ripard <maxime.ripard@free-electrons.com> |
---|
6 | | - * |
---|
7 | | - * This program is free software; you can redistribute it and/or |
---|
8 | | - * modify it under the terms of the GNU General Public License as |
---|
9 | | - * published by the Free Software Foundation; either version 2 of |
---|
10 | | - * the License, or (at your option) any later version. |
---|
11 | 7 | */ |
---|
12 | | - |
---|
13 | | -#include <drm/drmP.h> |
---|
14 | | -#include <drm/drm_atomic.h> |
---|
15 | | -#include <drm/drm_atomic_helper.h> |
---|
16 | | -#include <drm/drm_crtc.h> |
---|
17 | | -#include <drm/drm_crtc_helper.h> |
---|
18 | | -#include <drm/drm_fb_cma_helper.h> |
---|
19 | | -#include <drm/drm_gem_cma_helper.h> |
---|
20 | | -#include <drm/drm_plane_helper.h> |
---|
21 | 8 | |
---|
22 | 9 | #include <linux/component.h> |
---|
23 | 10 | #include <linux/list.h> |
---|
| 11 | +#include <linux/module.h> |
---|
24 | 12 | #include <linux/of_device.h> |
---|
25 | 13 | #include <linux/of_graph.h> |
---|
| 14 | +#include <linux/dma-mapping.h> |
---|
| 15 | +#include <linux/platform_device.h> |
---|
26 | 16 | #include <linux/reset.h> |
---|
| 17 | + |
---|
| 18 | +#include <drm/drm_atomic.h> |
---|
| 19 | +#include <drm/drm_atomic_helper.h> |
---|
| 20 | +#include <drm/drm_crtc.h> |
---|
| 21 | +#include <drm/drm_fb_cma_helper.h> |
---|
| 22 | +#include <drm/drm_fourcc.h> |
---|
| 23 | +#include <drm/drm_gem_cma_helper.h> |
---|
| 24 | +#include <drm/drm_plane_helper.h> |
---|
| 25 | +#include <drm/drm_probe_helper.h> |
---|
27 | 26 | |
---|
28 | 27 | #include "sun4i_backend.h" |
---|
29 | 28 | #include "sun4i_drv.h" |
---|
.. | .. |
---|
34 | 33 | struct sun4i_backend_quirks { |
---|
35 | 34 | /* backend <-> TCON muxing selection done in backend */ |
---|
36 | 35 | bool needs_output_muxing; |
---|
| 36 | + |
---|
| 37 | + /* alpha at the lowest z position is not always supported */ |
---|
| 38 | + bool supports_lowest_plane_alpha; |
---|
37 | 39 | }; |
---|
38 | 40 | |
---|
39 | 41 | static const u32 sunxi_rgb2yuv_coef[12] = { |
---|
.. | .. |
---|
41 | 43 | 0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808, |
---|
42 | 44 | 0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808 |
---|
43 | 45 | }; |
---|
44 | | - |
---|
45 | | -/* |
---|
46 | | - * These coefficients are taken from the A33 BSP from Allwinner. |
---|
47 | | - * |
---|
48 | | - * The formula is for each component, each coefficient being multiplied by |
---|
49 | | - * 1024 and each constant being multiplied by 16: |
---|
50 | | - * G = 1.164 * Y - 0.391 * U - 0.813 * V + 135 |
---|
51 | | - * R = 1.164 * Y + 1.596 * V - 222 |
---|
52 | | - * B = 1.164 * Y + 2.018 * U + 276 |
---|
53 | | - * |
---|
54 | | - * This seems to be a conversion from Y[16:235] UV[16:240] to RGB[0:255], |
---|
55 | | - * following the BT601 spec. |
---|
56 | | - */ |
---|
57 | | -static const u32 sunxi_bt601_yuv2rgb_coef[12] = { |
---|
58 | | - 0x000004a7, 0x00001e6f, 0x00001cbf, 0x00000877, |
---|
59 | | - 0x000004a7, 0x00000000, 0x00000662, 0x00003211, |
---|
60 | | - 0x000004a7, 0x00000812, 0x00000000, 0x00002eb1, |
---|
61 | | -}; |
---|
62 | | - |
---|
63 | | -static inline bool sun4i_backend_format_is_planar_yuv(uint32_t format) |
---|
64 | | -{ |
---|
65 | | - switch (format) { |
---|
66 | | - case DRM_FORMAT_YUV411: |
---|
67 | | - case DRM_FORMAT_YUV422: |
---|
68 | | - case DRM_FORMAT_YUV444: |
---|
69 | | - return true; |
---|
70 | | - default: |
---|
71 | | - return false; |
---|
72 | | - } |
---|
73 | | -} |
---|
74 | | - |
---|
75 | | -static inline bool sun4i_backend_format_is_packed_yuv422(uint32_t format) |
---|
76 | | -{ |
---|
77 | | - switch (format) { |
---|
78 | | - case DRM_FORMAT_YUYV: |
---|
79 | | - case DRM_FORMAT_YVYU: |
---|
80 | | - case DRM_FORMAT_UYVY: |
---|
81 | | - case DRM_FORMAT_VYUY: |
---|
82 | | - return true; |
---|
83 | | - |
---|
84 | | - default: |
---|
85 | | - return false; |
---|
86 | | - } |
---|
87 | | -} |
---|
88 | 46 | |
---|
89 | 47 | static void sun4i_backend_apply_color_correction(struct sunxi_engine *engine) |
---|
90 | 48 | { |
---|
.. | .. |
---|
178 | 136 | return 0; |
---|
179 | 137 | } |
---|
180 | 138 | |
---|
| 139 | +static const uint32_t sun4i_backend_formats[] = { |
---|
| 140 | + DRM_FORMAT_ARGB1555, |
---|
| 141 | + DRM_FORMAT_ARGB4444, |
---|
| 142 | + DRM_FORMAT_ARGB8888, |
---|
| 143 | + DRM_FORMAT_RGB565, |
---|
| 144 | + DRM_FORMAT_RGB888, |
---|
| 145 | + DRM_FORMAT_RGBA4444, |
---|
| 146 | + DRM_FORMAT_RGBA5551, |
---|
| 147 | + DRM_FORMAT_UYVY, |
---|
| 148 | + DRM_FORMAT_VYUY, |
---|
| 149 | + DRM_FORMAT_XRGB8888, |
---|
| 150 | + DRM_FORMAT_YUYV, |
---|
| 151 | + DRM_FORMAT_YVYU, |
---|
| 152 | +}; |
---|
| 153 | + |
---|
| 154 | +bool sun4i_backend_format_is_supported(uint32_t fmt, uint64_t modifier) |
---|
| 155 | +{ |
---|
| 156 | + unsigned int i; |
---|
| 157 | + |
---|
| 158 | + if (modifier != DRM_FORMAT_MOD_LINEAR) |
---|
| 159 | + return false; |
---|
| 160 | + |
---|
| 161 | + for (i = 0; i < ARRAY_SIZE(sun4i_backend_formats); i++) |
---|
| 162 | + if (sun4i_backend_formats[i] == fmt) |
---|
| 163 | + return true; |
---|
| 164 | + |
---|
| 165 | + return false; |
---|
| 166 | +} |
---|
| 167 | + |
---|
181 | 168 | int sun4i_backend_update_layer_coord(struct sun4i_backend *backend, |
---|
182 | 169 | int layer, struct drm_plane *plane) |
---|
183 | 170 | { |
---|
.. | .. |
---|
215 | 202 | { |
---|
216 | 203 | struct drm_plane_state *state = plane->state; |
---|
217 | 204 | struct drm_framebuffer *fb = state->fb; |
---|
218 | | - uint32_t format = fb->format->format; |
---|
| 205 | + const struct drm_format_info *format = fb->format; |
---|
| 206 | + const uint32_t fmt = format->format; |
---|
219 | 207 | u32 val = SUN4I_BACKEND_IYUVCTL_EN; |
---|
220 | 208 | int i; |
---|
221 | 209 | |
---|
.. | .. |
---|
233 | 221 | SUN4I_BACKEND_ATTCTL_REG0_LAY_YUVEN); |
---|
234 | 222 | |
---|
235 | 223 | /* TODO: Add support for the multi-planar YUV formats */ |
---|
236 | | - if (sun4i_backend_format_is_packed_yuv422(format)) |
---|
| 224 | + if (drm_format_info_is_yuv_packed(format) && |
---|
| 225 | + drm_format_info_is_yuv_sampling_422(format)) |
---|
237 | 226 | val |= SUN4I_BACKEND_IYUVCTL_FBFMT_PACKED_YUV422; |
---|
238 | 227 | else |
---|
239 | | - DRM_DEBUG_DRIVER("Unsupported YUV format (0x%x)\n", format); |
---|
| 228 | + DRM_DEBUG_DRIVER("Unsupported YUV format (0x%x)\n", fmt); |
---|
240 | 229 | |
---|
241 | 230 | /* |
---|
242 | 231 | * Allwinner seems to list the pixel sequence from right to left, while |
---|
243 | 232 | * DRM lists it from left to right. |
---|
244 | 233 | */ |
---|
245 | | - switch (format) { |
---|
| 234 | + switch (fmt) { |
---|
246 | 235 | case DRM_FORMAT_YUYV: |
---|
247 | 236 | val |= SUN4I_BACKEND_IYUVCTL_FBPS_VYUY; |
---|
248 | 237 | break; |
---|
.. | .. |
---|
257 | 246 | break; |
---|
258 | 247 | default: |
---|
259 | 248 | DRM_DEBUG_DRIVER("Unsupported YUV pixel sequence (0x%x)\n", |
---|
260 | | - format); |
---|
| 249 | + fmt); |
---|
261 | 250 | } |
---|
262 | 251 | |
---|
263 | 252 | regmap_write(backend->engine.regs, SUN4I_BACKEND_IYUVCTL_REG, val); |
---|
.. | .. |
---|
371 | 360 | paddr = drm_fb_cma_get_gem_addr(fb, state, 0); |
---|
372 | 361 | DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr); |
---|
373 | 362 | |
---|
374 | | - /* |
---|
375 | | - * backend DMA accesses DRAM directly, bypassing the system |
---|
376 | | - * bus. As such, the address range is different and the buffer |
---|
377 | | - * address needs to be corrected. |
---|
378 | | - */ |
---|
379 | | - paddr -= PHYS_OFFSET; |
---|
380 | | - |
---|
381 | 363 | if (fb->format->is_yuv) |
---|
382 | 364 | return sun4i_backend_update_yuv_buffer(backend, fb, paddr); |
---|
383 | 365 | |
---|
.. | .. |
---|
417 | 399 | return 0; |
---|
418 | 400 | } |
---|
419 | 401 | |
---|
| 402 | +void sun4i_backend_cleanup_layer(struct sun4i_backend *backend, |
---|
| 403 | + int layer) |
---|
| 404 | +{ |
---|
| 405 | + regmap_update_bits(backend->engine.regs, |
---|
| 406 | + SUN4I_BACKEND_ATTCTL_REG0(layer), |
---|
| 407 | + SUN4I_BACKEND_ATTCTL_REG0_LAY_VDOEN | |
---|
| 408 | + SUN4I_BACKEND_ATTCTL_REG0_LAY_YUVEN, 0); |
---|
| 409 | +} |
---|
| 410 | + |
---|
420 | 411 | static bool sun4i_backend_plane_uses_scaler(struct drm_plane_state *state) |
---|
421 | 412 | { |
---|
422 | 413 | u16 src_h = state->src_h >> 16; |
---|
.. | .. |
---|
435 | 426 | { |
---|
436 | 427 | struct sun4i_layer *layer = plane_to_sun4i_layer(state->plane); |
---|
437 | 428 | struct sun4i_backend *backend = layer->backend; |
---|
| 429 | + uint32_t format = state->fb->format->format; |
---|
| 430 | + uint64_t modifier = state->fb->modifier; |
---|
438 | 431 | |
---|
439 | 432 | if (IS_ERR(backend->frontend)) |
---|
440 | 433 | return false; |
---|
441 | 434 | |
---|
442 | | - return sun4i_backend_plane_uses_scaler(state); |
---|
| 435 | + if (!sun4i_frontend_format_is_supported(format, modifier)) |
---|
| 436 | + return false; |
---|
| 437 | + |
---|
| 438 | + if (!sun4i_backend_format_is_supported(format, modifier)) |
---|
| 439 | + return true; |
---|
| 440 | + |
---|
| 441 | + /* |
---|
| 442 | + * TODO: The backend alone allows 2x and 4x integer scaling, including |
---|
| 443 | + * support for an alpha component (which the frontend doesn't support). |
---|
| 444 | + * Use the backend directly instead of the frontend in this case, with |
---|
| 445 | + * another test to return false. |
---|
| 446 | + */ |
---|
| 447 | + |
---|
| 448 | + if (sun4i_backend_plane_uses_scaler(state)) |
---|
| 449 | + return true; |
---|
| 450 | + |
---|
| 451 | + /* |
---|
| 452 | + * Here the format is supported by both the frontend and the backend |
---|
| 453 | + * and no frontend scaling is required, so use the backend directly. |
---|
| 454 | + */ |
---|
| 455 | + return false; |
---|
| 456 | +} |
---|
| 457 | + |
---|
| 458 | +static bool sun4i_backend_plane_is_supported(struct drm_plane_state *state, |
---|
| 459 | + bool *uses_frontend) |
---|
| 460 | +{ |
---|
| 461 | + if (sun4i_backend_plane_uses_frontend(state)) { |
---|
| 462 | + *uses_frontend = true; |
---|
| 463 | + return true; |
---|
| 464 | + } |
---|
| 465 | + |
---|
| 466 | + *uses_frontend = false; |
---|
| 467 | + |
---|
| 468 | + /* Scaling is not supported without the frontend. */ |
---|
| 469 | + if (sun4i_backend_plane_uses_scaler(state)) |
---|
| 470 | + return false; |
---|
| 471 | + |
---|
| 472 | + return true; |
---|
443 | 473 | } |
---|
444 | 474 | |
---|
445 | 475 | static void sun4i_backend_atomic_begin(struct sunxi_engine *engine, |
---|
.. | .. |
---|
457 | 487 | struct drm_crtc_state *crtc_state) |
---|
458 | 488 | { |
---|
459 | 489 | struct drm_plane_state *plane_states[SUN4I_BACKEND_NUM_LAYERS] = { 0 }; |
---|
| 490 | + struct sun4i_backend *backend = engine_to_sun4i_backend(engine); |
---|
460 | 491 | struct drm_atomic_state *state = crtc_state->state; |
---|
461 | 492 | struct drm_device *drm = state->dev; |
---|
462 | 493 | struct drm_plane *plane; |
---|
463 | 494 | unsigned int num_planes = 0; |
---|
464 | 495 | unsigned int num_alpha_planes = 0; |
---|
465 | 496 | unsigned int num_frontend_planes = 0; |
---|
| 497 | + unsigned int num_alpha_planes_max = 1; |
---|
466 | 498 | unsigned int num_yuv_planes = 0; |
---|
467 | 499 | unsigned int current_pipe = 0; |
---|
468 | 500 | unsigned int i; |
---|
.. | .. |
---|
480 | 512 | struct drm_framebuffer *fb = plane_state->fb; |
---|
481 | 513 | struct drm_format_name_buf format_name; |
---|
482 | 514 | |
---|
483 | | - if (sun4i_backend_plane_uses_frontend(plane_state)) { |
---|
| 515 | + if (!sun4i_backend_plane_is_supported(plane_state, |
---|
| 516 | + &layer_state->uses_frontend)) |
---|
| 517 | + return -EINVAL; |
---|
| 518 | + |
---|
| 519 | + if (layer_state->uses_frontend) { |
---|
484 | 520 | DRM_DEBUG_DRIVER("Using the frontend for plane %d\n", |
---|
485 | 521 | plane->index); |
---|
486 | | - |
---|
487 | | - layer_state->uses_frontend = true; |
---|
488 | 522 | num_frontend_planes++; |
---|
489 | 523 | } else { |
---|
490 | | - layer_state->uses_frontend = false; |
---|
| 524 | + if (fb->format->is_yuv) { |
---|
| 525 | + DRM_DEBUG_DRIVER("Plane FB format is YUV\n"); |
---|
| 526 | + num_yuv_planes++; |
---|
| 527 | + } |
---|
491 | 528 | } |
---|
492 | 529 | |
---|
493 | 530 | DRM_DEBUG_DRIVER("Plane FB format is %s\n", |
---|
.. | .. |
---|
495 | 532 | &format_name)); |
---|
496 | 533 | if (fb->format->has_alpha || (plane_state->alpha != DRM_BLEND_ALPHA_OPAQUE)) |
---|
497 | 534 | num_alpha_planes++; |
---|
498 | | - |
---|
499 | | - if (fb->format->is_yuv) { |
---|
500 | | - DRM_DEBUG_DRIVER("Plane FB format is YUV\n"); |
---|
501 | | - num_yuv_planes++; |
---|
502 | | - } |
---|
503 | 535 | |
---|
504 | 536 | DRM_DEBUG_DRIVER("Plane zpos is %d\n", |
---|
505 | 537 | plane_state->normalized_zpos); |
---|
.. | .. |
---|
526 | 558 | * the layer with the highest priority. |
---|
527 | 559 | * |
---|
528 | 560 | * The second step is the actual alpha blending, that takes |
---|
529 | | - * the two pipes as input, and uses the eventual alpha |
---|
| 561 | + * the two pipes as input, and uses the potential alpha |
---|
530 | 562 | * component to do the transparency between the two. |
---|
531 | 563 | * |
---|
532 | | - * This two steps scenario makes us unable to guarantee a |
---|
| 564 | + * This two-step scenario makes us unable to guarantee a |
---|
533 | 565 | * robust alpha blending between the 4 layers in all |
---|
534 | 566 | * situations, since this means that we need to have one layer |
---|
535 | 567 | * with alpha at the lowest position of our two pipes. |
---|
536 | 568 | * |
---|
537 | | - * However, we cannot even do that, since the hardware has a |
---|
538 | | - * bug where the lowest plane of the lowest pipe (pipe 0, |
---|
539 | | - * priority 0), if it has any alpha, will discard the pixel |
---|
540 | | - * entirely and just display the pixels in the background |
---|
541 | | - * color (black by default). |
---|
| 569 | + * However, we cannot even do that on every platform, since |
---|
| 570 | + * the hardware has a bug where the lowest plane of the lowest |
---|
| 571 | + * pipe (pipe 0, priority 0), if it has any alpha, will |
---|
| 572 | + * discard the pixel data entirely and just display the pixels |
---|
| 573 | + * in the background color (black by default). |
---|
542 | 574 | * |
---|
543 | | - * This means that we effectively have only three valid |
---|
544 | | - * configurations with alpha, all of them with the alpha being |
---|
545 | | - * on pipe1 with the lowest position, which can be 1, 2 or 3 |
---|
546 | | - * depending on the number of planes and their zpos. |
---|
| 575 | + * This means that on the affected platforms, we effectively |
---|
| 576 | + * have only three valid configurations with alpha, all of |
---|
| 577 | + * them with the alpha being on pipe1 with the lowest |
---|
| 578 | + * position, which can be 1, 2 or 3 depending on the number of |
---|
| 579 | + * planes and their zpos. |
---|
547 | 580 | */ |
---|
548 | | - if (num_alpha_planes > SUN4I_BACKEND_NUM_ALPHA_LAYERS) { |
---|
| 581 | + |
---|
| 582 | + /* For platforms that are not affected by the issue described above. */ |
---|
| 583 | + if (backend->quirks->supports_lowest_plane_alpha) |
---|
| 584 | + num_alpha_planes_max++; |
---|
| 585 | + |
---|
| 586 | + if (num_alpha_planes > num_alpha_planes_max) { |
---|
549 | 587 | DRM_DEBUG_DRIVER("Too many planes with alpha, rejecting...\n"); |
---|
550 | 588 | return -EINVAL; |
---|
551 | 589 | } |
---|
552 | 590 | |
---|
553 | 591 | /* We can't have an alpha plane at the lowest position */ |
---|
554 | | - if (plane_states[0]->fb->format->has_alpha || |
---|
| 592 | + if (!backend->quirks->supports_lowest_plane_alpha && |
---|
555 | 593 | (plane_states[0]->alpha != DRM_BLEND_ALPHA_OPAQUE)) |
---|
556 | 594 | return -EINVAL; |
---|
557 | 595 | |
---|
.. | .. |
---|
673 | 711 | */ |
---|
674 | 712 | static int sun4i_backend_of_get_id(struct device_node *node) |
---|
675 | 713 | { |
---|
676 | | - struct device_node *port, *ep; |
---|
677 | | - int ret = -EINVAL; |
---|
| 714 | + struct device_node *ep, *remote; |
---|
| 715 | + struct of_endpoint of_ep; |
---|
678 | 716 | |
---|
679 | | - /* input is port 0 */ |
---|
680 | | - port = of_graph_get_port_by_id(node, 0); |
---|
681 | | - if (!port) |
---|
| 717 | + /* Input port is 0, and we want the first endpoint. */ |
---|
| 718 | + ep = of_graph_get_endpoint_by_regs(node, 0, -1); |
---|
| 719 | + if (!ep) |
---|
682 | 720 | return -EINVAL; |
---|
683 | 721 | |
---|
684 | | - /* try finding an upstream endpoint */ |
---|
685 | | - for_each_available_child_of_node(port, ep) { |
---|
686 | | - struct device_node *remote; |
---|
687 | | - u32 reg; |
---|
| 722 | + remote = of_graph_get_remote_endpoint(ep); |
---|
| 723 | + of_node_put(ep); |
---|
| 724 | + if (!remote) |
---|
| 725 | + return -EINVAL; |
---|
688 | 726 | |
---|
689 | | - remote = of_graph_get_remote_endpoint(ep); |
---|
690 | | - if (!remote) |
---|
691 | | - continue; |
---|
692 | | - |
---|
693 | | - ret = of_property_read_u32(remote, "reg", ®); |
---|
694 | | - if (ret) |
---|
695 | | - continue; |
---|
696 | | - |
---|
697 | | - ret = reg; |
---|
698 | | - } |
---|
699 | | - |
---|
700 | | - of_node_put(port); |
---|
701 | | - |
---|
702 | | - return ret; |
---|
| 727 | + of_graph_parse_endpoint(remote, &of_ep); |
---|
| 728 | + of_node_put(remote); |
---|
| 729 | + return of_ep.id; |
---|
703 | 730 | } |
---|
704 | 731 | |
---|
705 | 732 | /* TODO: This needs to take multiple pipelines into account */ |
---|
.. | .. |
---|
742 | 769 | .vblank_quirk = sun4i_backend_vblank_quirk, |
---|
743 | 770 | }; |
---|
744 | 771 | |
---|
745 | | -static struct regmap_config sun4i_backend_regmap_config = { |
---|
| 772 | +static const struct regmap_config sun4i_backend_regmap_config = { |
---|
746 | 773 | .reg_bits = 32, |
---|
747 | 774 | .val_bits = 32, |
---|
748 | 775 | .reg_stride = 4, |
---|
.. | .. |
---|
766 | 793 | return -ENOMEM; |
---|
767 | 794 | dev_set_drvdata(dev, backend); |
---|
768 | 795 | spin_lock_init(&backend->frontend_lock); |
---|
| 796 | + |
---|
| 797 | + if (of_find_property(dev->of_node, "interconnects", NULL)) { |
---|
| 798 | + /* |
---|
| 799 | + * This assume we have the same DMA constraints for all our the |
---|
| 800 | + * devices in our pipeline (all the backends, but also the |
---|
| 801 | + * frontends). This sounds bad, but it has always been the case |
---|
| 802 | + * for us, and DRM doesn't do per-device allocation either, so |
---|
| 803 | + * we would need to fix DRM first... |
---|
| 804 | + */ |
---|
| 805 | + ret = of_dma_configure(drm->dev, dev->of_node, true); |
---|
| 806 | + if (ret) |
---|
| 807 | + return ret; |
---|
| 808 | + } else { |
---|
| 809 | + /* |
---|
| 810 | + * If we don't have the interconnect property, most likely |
---|
| 811 | + * because of an old DT, we need to set the DMA offset by hand |
---|
| 812 | + * on our device since the RAM mapping is at 0 for the DMA bus, |
---|
| 813 | + * unlike the CPU. |
---|
| 814 | + * |
---|
| 815 | + * XXX(hch): this has no business in a driver and needs to move |
---|
| 816 | + * to the device tree. |
---|
| 817 | + * |
---|
| 818 | + * If we have two subsequent calls to dma_direct_set_offset |
---|
| 819 | + * returns -EINVAL. Unfortunately, this happens when we have two |
---|
| 820 | + * backends in the system, and will result in the driver |
---|
| 821 | + * reporting an error while it has been setup properly before. |
---|
| 822 | + * Ignore EINVAL, but it should really be removed eventually. |
---|
| 823 | + */ |
---|
| 824 | + ret = dma_direct_set_offset(drm->dev, PHYS_OFFSET, 0, SZ_4G); |
---|
| 825 | + if (ret && ret != -EINVAL) |
---|
| 826 | + return ret; |
---|
| 827 | + } |
---|
769 | 828 | |
---|
770 | 829 | backend->engine.node = dev->of_node; |
---|
771 | 830 | backend->engine.ops = &sun4i_backend_engine_ops; |
---|
.. | .. |
---|
808 | 867 | ret = PTR_ERR(backend->mod_clk); |
---|
809 | 868 | goto err_disable_bus_clk; |
---|
810 | 869 | } |
---|
| 870 | + |
---|
| 871 | + ret = clk_set_rate_exclusive(backend->mod_clk, 300000000); |
---|
| 872 | + if (ret) { |
---|
| 873 | + dev_err(dev, "Couldn't set the module clock frequency\n"); |
---|
| 874 | + goto err_disable_bus_clk; |
---|
| 875 | + } |
---|
| 876 | + |
---|
811 | 877 | clk_prepare_enable(backend->mod_clk); |
---|
812 | 878 | |
---|
813 | 879 | backend->ram_clk = devm_clk_get(dev, "ram"); |
---|
.. | .. |
---|
877 | 943 | : SUN4I_BACKEND_MODCTL_OUT_LCD0)); |
---|
878 | 944 | } |
---|
879 | 945 | |
---|
| 946 | + backend->quirks = quirks; |
---|
| 947 | + |
---|
880 | 948 | return 0; |
---|
881 | 949 | |
---|
882 | 950 | err_disable_ram_clk: |
---|
883 | 951 | clk_disable_unprepare(backend->ram_clk); |
---|
884 | 952 | err_disable_mod_clk: |
---|
| 953 | + clk_rate_exclusive_put(backend->mod_clk); |
---|
885 | 954 | clk_disable_unprepare(backend->mod_clk); |
---|
886 | 955 | err_disable_bus_clk: |
---|
887 | 956 | clk_disable_unprepare(backend->bus_clk); |
---|
.. | .. |
---|
902 | 971 | sun4i_backend_free_sat(dev); |
---|
903 | 972 | |
---|
904 | 973 | clk_disable_unprepare(backend->ram_clk); |
---|
| 974 | + clk_rate_exclusive_put(backend->mod_clk); |
---|
905 | 975 | clk_disable_unprepare(backend->mod_clk); |
---|
906 | 976 | clk_disable_unprepare(backend->bus_clk); |
---|
907 | 977 | reset_control_assert(backend->reset); |
---|
.. | .. |
---|
939 | 1009 | }; |
---|
940 | 1010 | |
---|
941 | 1011 | static const struct sun4i_backend_quirks sun8i_a33_backend_quirks = { |
---|
| 1012 | + .supports_lowest_plane_alpha = true, |
---|
942 | 1013 | }; |
---|
943 | 1014 | |
---|
944 | 1015 | static const struct sun4i_backend_quirks sun9i_backend_quirks = { |
---|
.. | .. |
---|
962 | 1033 | .data = &sun7i_backend_quirks, |
---|
963 | 1034 | }, |
---|
964 | 1035 | { |
---|
| 1036 | + .compatible = "allwinner,sun8i-a23-display-backend", |
---|
| 1037 | + .data = &sun8i_a33_backend_quirks, |
---|
| 1038 | + }, |
---|
| 1039 | + { |
---|
965 | 1040 | .compatible = "allwinner,sun8i-a33-display-backend", |
---|
966 | 1041 | .data = &sun8i_a33_backend_quirks, |
---|
967 | 1042 | }, |
---|