.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (C) 2014 Free Electrons |
---|
3 | 4 | * Copyright (C) 2014 Atmel |
---|
4 | 5 | * |
---|
5 | 6 | * Author: Boris BREZILLON <boris.brezillon@free-electrons.com> |
---|
6 | | - * |
---|
7 | | - * This program is free software; you can redistribute it and/or modify it |
---|
8 | | - * under the terms of the GNU General Public License version 2 as published by |
---|
9 | | - * the Free Software Foundation. |
---|
10 | | - * |
---|
11 | | - * This program is distributed in the hope that it will be useful, but WITHOUT |
---|
12 | | - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
---|
13 | | - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
---|
14 | | - * more details. |
---|
15 | | - * |
---|
16 | | - * You should have received a copy of the GNU General Public License along with |
---|
17 | | - * this program. If not, see <http://www.gnu.org/licenses/>. |
---|
18 | 7 | */ |
---|
| 8 | + |
---|
| 9 | +#include <linux/dmapool.h> |
---|
| 10 | +#include <linux/mfd/atmel-hlcdc.h> |
---|
| 11 | + |
---|
| 12 | +#include <drm/drm_atomic.h> |
---|
| 13 | +#include <drm/drm_atomic_helper.h> |
---|
| 14 | +#include <drm/drm_fb_cma_helper.h> |
---|
| 15 | +#include <drm/drm_fourcc.h> |
---|
| 16 | +#include <drm/drm_gem_cma_helper.h> |
---|
| 17 | +#include <drm/drm_plane_helper.h> |
---|
19 | 18 | |
---|
20 | 19 | #include "atmel_hlcdc_dc.h" |
---|
21 | 20 | |
---|
.. | .. |
---|
372 | 371 | atmel_hlcdc_layer_write_cfg(&plane->layer, ATMEL_HLCDC_LAYER_DMA_CFG, |
---|
373 | 372 | cfg); |
---|
374 | 373 | |
---|
375 | | - cfg = ATMEL_HLCDC_LAYER_DMA; |
---|
| 374 | + cfg = ATMEL_HLCDC_LAYER_DMA | ATMEL_HLCDC_LAYER_REP; |
---|
376 | 375 | |
---|
377 | 376 | if (plane->base.type != DRM_PLANE_TYPE_PRIMARY) { |
---|
378 | 377 | cfg |= ATMEL_HLCDC_LAYER_OVR | ATMEL_HLCDC_LAYER_ITER2BL | |
---|
.. | .. |
---|
549 | 548 | |
---|
550 | 549 | ovl_state = drm_plane_state_to_atmel_hlcdc_plane_state(ovl_s); |
---|
551 | 550 | |
---|
552 | | - if (!ovl_s->fb || |
---|
| 551 | + if (!ovl_s->visible || |
---|
| 552 | + !ovl_s->fb || |
---|
553 | 553 | ovl_s->fb->format->has_alpha || |
---|
554 | 554 | ovl_s->alpha != DRM_BLEND_ALPHA_OPAQUE) |
---|
555 | 555 | continue; |
---|
.. | .. |
---|
601 | 601 | struct drm_framebuffer *fb = state->base.fb; |
---|
602 | 602 | const struct drm_display_mode *mode; |
---|
603 | 603 | struct drm_crtc_state *crtc_state; |
---|
604 | | - unsigned int patched_crtc_w; |
---|
605 | | - unsigned int patched_crtc_h; |
---|
606 | | - unsigned int patched_src_w; |
---|
607 | | - unsigned int patched_src_h; |
---|
608 | | - unsigned int tmp; |
---|
609 | | - int x_offset = 0; |
---|
610 | | - int y_offset = 0; |
---|
611 | | - int hsub = 1; |
---|
612 | | - int vsub = 1; |
---|
| 604 | + int ret; |
---|
613 | 605 | int i; |
---|
614 | 606 | |
---|
615 | | - if (!state->base.crtc || !fb) |
---|
| 607 | + if (!state->base.crtc || WARN_ON(!fb)) |
---|
616 | 608 | return 0; |
---|
617 | 609 | |
---|
618 | 610 | crtc_state = drm_atomic_get_existing_crtc_state(s->state, s->crtc); |
---|
619 | 611 | mode = &crtc_state->adjusted_mode; |
---|
620 | 612 | |
---|
621 | | - state->src_x = s->src_x; |
---|
622 | | - state->src_y = s->src_y; |
---|
623 | | - state->src_h = s->src_h; |
---|
624 | | - state->src_w = s->src_w; |
---|
625 | | - state->crtc_x = s->crtc_x; |
---|
626 | | - state->crtc_y = s->crtc_y; |
---|
627 | | - state->crtc_h = s->crtc_h; |
---|
628 | | - state->crtc_w = s->crtc_w; |
---|
| 613 | + ret = drm_atomic_helper_check_plane_state(s, crtc_state, |
---|
| 614 | + (1 << 16) / 2048, |
---|
| 615 | + INT_MAX, true, true); |
---|
| 616 | + if (ret || !s->visible) |
---|
| 617 | + return ret; |
---|
| 618 | + |
---|
| 619 | + state->src_x = s->src.x1; |
---|
| 620 | + state->src_y = s->src.y1; |
---|
| 621 | + state->src_w = drm_rect_width(&s->src); |
---|
| 622 | + state->src_h = drm_rect_height(&s->src); |
---|
| 623 | + state->crtc_x = s->dst.x1; |
---|
| 624 | + state->crtc_y = s->dst.y1; |
---|
| 625 | + state->crtc_w = drm_rect_width(&s->dst); |
---|
| 626 | + state->crtc_h = drm_rect_height(&s->dst); |
---|
| 627 | + |
---|
629 | 628 | if ((state->src_x | state->src_y | state->src_w | state->src_h) & |
---|
630 | 629 | SUBPIXEL_MASK) |
---|
631 | 630 | return -EINVAL; |
---|
.. | .. |
---|
639 | 638 | if (state->nplanes > ATMEL_HLCDC_LAYER_MAX_PLANES) |
---|
640 | 639 | return -EINVAL; |
---|
641 | 640 | |
---|
642 | | - /* |
---|
643 | | - * Swap width and size in case of 90 or 270 degrees rotation |
---|
644 | | - */ |
---|
645 | | - if (drm_rotation_90_or_270(state->base.rotation)) { |
---|
646 | | - tmp = state->crtc_w; |
---|
647 | | - state->crtc_w = state->crtc_h; |
---|
648 | | - state->crtc_h = tmp; |
---|
649 | | - tmp = state->src_w; |
---|
650 | | - state->src_w = state->src_h; |
---|
651 | | - state->src_h = tmp; |
---|
652 | | - } |
---|
653 | | - |
---|
654 | | - if (state->crtc_x + state->crtc_w > mode->hdisplay) |
---|
655 | | - patched_crtc_w = mode->hdisplay - state->crtc_x; |
---|
656 | | - else |
---|
657 | | - patched_crtc_w = state->crtc_w; |
---|
658 | | - |
---|
659 | | - if (state->crtc_x < 0) { |
---|
660 | | - patched_crtc_w += state->crtc_x; |
---|
661 | | - x_offset = -state->crtc_x; |
---|
662 | | - state->crtc_x = 0; |
---|
663 | | - } |
---|
664 | | - |
---|
665 | | - if (state->crtc_y + state->crtc_h > mode->vdisplay) |
---|
666 | | - patched_crtc_h = mode->vdisplay - state->crtc_y; |
---|
667 | | - else |
---|
668 | | - patched_crtc_h = state->crtc_h; |
---|
669 | | - |
---|
670 | | - if (state->crtc_y < 0) { |
---|
671 | | - patched_crtc_h += state->crtc_y; |
---|
672 | | - y_offset = -state->crtc_y; |
---|
673 | | - state->crtc_y = 0; |
---|
674 | | - } |
---|
675 | | - |
---|
676 | | - patched_src_w = DIV_ROUND_CLOSEST(patched_crtc_w * state->src_w, |
---|
677 | | - state->crtc_w); |
---|
678 | | - patched_src_h = DIV_ROUND_CLOSEST(patched_crtc_h * state->src_h, |
---|
679 | | - state->crtc_h); |
---|
680 | | - |
---|
681 | | - hsub = drm_format_horz_chroma_subsampling(fb->format->format); |
---|
682 | | - vsub = drm_format_vert_chroma_subsampling(fb->format->format); |
---|
683 | | - |
---|
684 | 641 | for (i = 0; i < state->nplanes; i++) { |
---|
685 | 642 | unsigned int offset = 0; |
---|
686 | | - int xdiv = i ? hsub : 1; |
---|
687 | | - int ydiv = i ? vsub : 1; |
---|
| 643 | + int xdiv = i ? fb->format->hsub : 1; |
---|
| 644 | + int ydiv = i ? fb->format->vsub : 1; |
---|
688 | 645 | |
---|
689 | 646 | state->bpp[i] = fb->format->cpp[i]; |
---|
690 | 647 | if (!state->bpp[i]) |
---|
.. | .. |
---|
692 | 649 | |
---|
693 | 650 | switch (state->base.rotation & DRM_MODE_ROTATE_MASK) { |
---|
694 | 651 | case DRM_MODE_ROTATE_90: |
---|
695 | | - offset = ((y_offset + state->src_y + patched_src_w - 1) / |
---|
696 | | - ydiv) * fb->pitches[i]; |
---|
697 | | - offset += ((x_offset + state->src_x) / xdiv) * |
---|
698 | | - state->bpp[i]; |
---|
699 | | - state->xstride[i] = ((patched_src_w - 1) / ydiv) * |
---|
700 | | - fb->pitches[i]; |
---|
701 | | - state->pstride[i] = -fb->pitches[i] - state->bpp[i]; |
---|
702 | | - break; |
---|
703 | | - case DRM_MODE_ROTATE_180: |
---|
704 | | - offset = ((y_offset + state->src_y + patched_src_h - 1) / |
---|
705 | | - ydiv) * fb->pitches[i]; |
---|
706 | | - offset += ((x_offset + state->src_x + patched_src_w - 1) / |
---|
707 | | - xdiv) * state->bpp[i]; |
---|
708 | | - state->xstride[i] = ((((patched_src_w - 1) / xdiv) - 1) * |
---|
709 | | - state->bpp[i]) - fb->pitches[i]; |
---|
710 | | - state->pstride[i] = -2 * state->bpp[i]; |
---|
711 | | - break; |
---|
712 | | - case DRM_MODE_ROTATE_270: |
---|
713 | | - offset = ((y_offset + state->src_y) / ydiv) * |
---|
| 652 | + offset = (state->src_y / ydiv) * |
---|
714 | 653 | fb->pitches[i]; |
---|
715 | | - offset += ((x_offset + state->src_x + patched_src_h - 1) / |
---|
| 654 | + offset += ((state->src_x + state->src_w - 1) / |
---|
716 | 655 | xdiv) * state->bpp[i]; |
---|
717 | | - state->xstride[i] = -(((patched_src_w - 1) / ydiv) * |
---|
| 656 | + state->xstride[i] = -(((state->src_h - 1) / ydiv) * |
---|
718 | 657 | fb->pitches[i]) - |
---|
719 | 658 | (2 * state->bpp[i]); |
---|
720 | 659 | state->pstride[i] = fb->pitches[i] - state->bpp[i]; |
---|
721 | 660 | break; |
---|
| 661 | + case DRM_MODE_ROTATE_180: |
---|
| 662 | + offset = ((state->src_y + state->src_h - 1) / |
---|
| 663 | + ydiv) * fb->pitches[i]; |
---|
| 664 | + offset += ((state->src_x + state->src_w - 1) / |
---|
| 665 | + xdiv) * state->bpp[i]; |
---|
| 666 | + state->xstride[i] = ((((state->src_w - 1) / xdiv) - 1) * |
---|
| 667 | + state->bpp[i]) - fb->pitches[i]; |
---|
| 668 | + state->pstride[i] = -2 * state->bpp[i]; |
---|
| 669 | + break; |
---|
| 670 | + case DRM_MODE_ROTATE_270: |
---|
| 671 | + offset = ((state->src_y + state->src_h - 1) / |
---|
| 672 | + ydiv) * fb->pitches[i]; |
---|
| 673 | + offset += (state->src_x / xdiv) * state->bpp[i]; |
---|
| 674 | + state->xstride[i] = ((state->src_h - 1) / ydiv) * |
---|
| 675 | + fb->pitches[i]; |
---|
| 676 | + state->pstride[i] = -fb->pitches[i] - state->bpp[i]; |
---|
| 677 | + break; |
---|
722 | 678 | case DRM_MODE_ROTATE_0: |
---|
723 | 679 | default: |
---|
724 | | - offset = ((y_offset + state->src_y) / ydiv) * |
---|
725 | | - fb->pitches[i]; |
---|
726 | | - offset += ((x_offset + state->src_x) / xdiv) * |
---|
727 | | - state->bpp[i]; |
---|
| 680 | + offset = (state->src_y / ydiv) * fb->pitches[i]; |
---|
| 681 | + offset += (state->src_x / xdiv) * state->bpp[i]; |
---|
728 | 682 | state->xstride[i] = fb->pitches[i] - |
---|
729 | | - ((patched_src_w / xdiv) * |
---|
| 683 | + ((state->src_w / xdiv) * |
---|
730 | 684 | state->bpp[i]); |
---|
731 | 685 | state->pstride[i] = 0; |
---|
732 | 686 | break; |
---|
.. | .. |
---|
735 | 689 | state->offsets[i] = offset + fb->offsets[i]; |
---|
736 | 690 | } |
---|
737 | 691 | |
---|
738 | | - state->src_w = patched_src_w; |
---|
739 | | - state->src_h = patched_src_h; |
---|
740 | | - state->crtc_w = patched_crtc_w; |
---|
741 | | - state->crtc_h = patched_crtc_h; |
---|
| 692 | + /* |
---|
| 693 | + * Swap width and size in case of 90 or 270 degrees rotation |
---|
| 694 | + */ |
---|
| 695 | + if (drm_rotation_90_or_270(state->base.rotation)) { |
---|
| 696 | + swap(state->src_w, state->src_h); |
---|
| 697 | + } |
---|
742 | 698 | |
---|
743 | 699 | if (!desc->layout.size && |
---|
744 | 700 | (mode->hdisplay != state->crtc_w || |
---|
745 | 701 | mode->vdisplay != state->crtc_h)) |
---|
746 | | - return -EINVAL; |
---|
747 | | - |
---|
748 | | - if (desc->max_height && state->crtc_h > desc->max_height) |
---|
749 | | - return -EINVAL; |
---|
750 | | - |
---|
751 | | - if (desc->max_width && state->crtc_w > desc->max_width) |
---|
752 | 702 | return -EINVAL; |
---|
753 | 703 | |
---|
754 | 704 | if ((state->crtc_h != state->src_h || state->crtc_w != state->src_w) && |
---|
.. | .. |
---|
756 | 706 | state->base.fb->format->has_alpha)) |
---|
757 | 707 | return -EINVAL; |
---|
758 | 708 | |
---|
759 | | - if (state->crtc_x < 0 || state->crtc_y < 0) |
---|
760 | | - return -EINVAL; |
---|
761 | | - |
---|
762 | | - if (state->crtc_w + state->crtc_x > mode->hdisplay || |
---|
763 | | - state->crtc_h + state->crtc_y > mode->vdisplay) |
---|
764 | | - return -EINVAL; |
---|
765 | | - |
---|
766 | 709 | return 0; |
---|
| 710 | +} |
---|
| 711 | + |
---|
| 712 | +static void atmel_hlcdc_plane_atomic_disable(struct drm_plane *p, |
---|
| 713 | + struct drm_plane_state *old_state) |
---|
| 714 | +{ |
---|
| 715 | + struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p); |
---|
| 716 | + |
---|
| 717 | + /* Disable interrupts */ |
---|
| 718 | + atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IDR, |
---|
| 719 | + 0xffffffff); |
---|
| 720 | + |
---|
| 721 | + /* Disable the layer */ |
---|
| 722 | + atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHDR, |
---|
| 723 | + ATMEL_HLCDC_LAYER_RST | |
---|
| 724 | + ATMEL_HLCDC_LAYER_A2Q | |
---|
| 725 | + ATMEL_HLCDC_LAYER_UPDATE); |
---|
| 726 | + |
---|
| 727 | + /* Clear all pending interrupts */ |
---|
| 728 | + atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR); |
---|
767 | 729 | } |
---|
768 | 730 | |
---|
769 | 731 | static void atmel_hlcdc_plane_atomic_update(struct drm_plane *p, |
---|
.. | .. |
---|
776 | 738 | |
---|
777 | 739 | if (!p->state->crtc || !p->state->fb) |
---|
778 | 740 | return; |
---|
| 741 | + |
---|
| 742 | + if (!state->base.visible) { |
---|
| 743 | + atmel_hlcdc_plane_atomic_disable(p, old_s); |
---|
| 744 | + return; |
---|
| 745 | + } |
---|
779 | 746 | |
---|
780 | 747 | atmel_hlcdc_plane_update_pos_and_size(plane, state); |
---|
781 | 748 | atmel_hlcdc_plane_update_general_settings(plane, state); |
---|
.. | .. |
---|
796 | 763 | ATMEL_HLCDC_LAYER_UPDATE | |
---|
797 | 764 | (sr & ATMEL_HLCDC_LAYER_EN ? |
---|
798 | 765 | ATMEL_HLCDC_LAYER_A2Q : ATMEL_HLCDC_LAYER_EN)); |
---|
799 | | -} |
---|
800 | | - |
---|
801 | | -static void atmel_hlcdc_plane_atomic_disable(struct drm_plane *p, |
---|
802 | | - struct drm_plane_state *old_state) |
---|
803 | | -{ |
---|
804 | | - struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p); |
---|
805 | | - |
---|
806 | | - /* Disable interrupts */ |
---|
807 | | - atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IDR, |
---|
808 | | - 0xffffffff); |
---|
809 | | - |
---|
810 | | - /* Disable the layer */ |
---|
811 | | - atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHDR, |
---|
812 | | - ATMEL_HLCDC_LAYER_RST | |
---|
813 | | - ATMEL_HLCDC_LAYER_A2Q | |
---|
814 | | - ATMEL_HLCDC_LAYER_UPDATE); |
---|
815 | | - |
---|
816 | | - /* Clear all pending interrupts */ |
---|
817 | | - atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR); |
---|
818 | 766 | } |
---|
819 | 767 | |
---|
820 | 768 | static int atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane) |
---|
.. | .. |
---|
942 | 890 | "Failed to allocate initial plane state\n"); |
---|
943 | 891 | return; |
---|
944 | 892 | } |
---|
945 | | - |
---|
946 | | - p->state = &state->base; |
---|
947 | | - p->state->alpha = DRM_BLEND_ALPHA_OPAQUE; |
---|
948 | | - p->state->plane = p; |
---|
| 893 | + __drm_atomic_helper_plane_reset(p, &state->base); |
---|
949 | 894 | } |
---|
950 | 895 | } |
---|
951 | 896 | |
---|