aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/rockchip/rockchip_drm_vop.c')
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_vop.c157
1 files changed, 151 insertions, 6 deletions
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index db8358e6d230..619b6db05d58 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -15,6 +15,7 @@
15#include <drm/drm.h> 15#include <drm/drm.h>
16#include <drm/drmP.h> 16#include <drm/drmP.h>
17#include <drm/drm_atomic.h> 17#include <drm/drm_atomic.h>
18#include <drm/drm_atomic_uapi.h>
18#include <drm/drm_crtc.h> 19#include <drm/drm_crtc.h>
19#include <drm/drm_crtc_helper.h> 20#include <drm/drm_crtc_helper.h>
20#include <drm/drm_flip_work.h> 21#include <drm/drm_flip_work.h>
@@ -45,14 +46,26 @@
45#include "rockchip_drm_vop.h" 46#include "rockchip_drm_vop.h"
46#include "rockchip_rgb.h" 47#include "rockchip_rgb.h"
47 48
48#define VOP_WIN_SET(x, win, name, v) \ 49#define VOP_WIN_SET(vop, win, name, v) \
49 vop_reg_set(vop, &win->phy->name, win->base, ~0, v, #name) 50 vop_reg_set(vop, &win->phy->name, win->base, ~0, v, #name)
50#define VOP_SCL_SET(x, win, name, v) \ 51#define VOP_SCL_SET(vop, win, name, v) \
51 vop_reg_set(vop, &win->phy->scl->name, win->base, ~0, v, #name) 52 vop_reg_set(vop, &win->phy->scl->name, win->base, ~0, v, #name)
52#define VOP_SCL_SET_EXT(x, win, name, v) \ 53#define VOP_SCL_SET_EXT(vop, win, name, v) \
53 vop_reg_set(vop, &win->phy->scl->ext->name, \ 54 vop_reg_set(vop, &win->phy->scl->ext->name, \
54 win->base, ~0, v, #name) 55 win->base, ~0, v, #name)
55 56
57#define VOP_WIN_YUV2YUV_SET(vop, win_yuv2yuv, name, v) \
58 do { \
59 if (win_yuv2yuv && win_yuv2yuv->name.mask) \
60 vop_reg_set(vop, &win_yuv2yuv->name, 0, ~0, v, #name); \
61 } while (0)
62
63#define VOP_WIN_YUV2YUV_COEFFICIENT_SET(vop, win_yuv2yuv, name, v) \
64 do { \
65 if (win_yuv2yuv && win_yuv2yuv->phy->name.mask) \
66 vop_reg_set(vop, &win_yuv2yuv->phy->name, win_yuv2yuv->base, ~0, v, #name); \
67 } while (0)
68
56#define VOP_INTR_SET_MASK(vop, name, mask, v) \ 69#define VOP_INTR_SET_MASK(vop, name, mask, v) \
57 vop_reg_set(vop, &vop->data->intr->name, 0, mask, v, #name) 70 vop_reg_set(vop, &vop->data->intr->name, 0, mask, v, #name)
58 71
@@ -73,8 +86,11 @@
73#define VOP_INTR_GET_TYPE(vop, name, type) \ 86#define VOP_INTR_GET_TYPE(vop, name, type) \
74 vop_get_intr_type(vop, &vop->data->intr->name, type) 87 vop_get_intr_type(vop, &vop->data->intr->name, type)
75 88
76#define VOP_WIN_GET(x, win, name) \ 89#define VOP_WIN_GET(vop, win, name) \
77 vop_read_reg(x, win->offset, win->phy->name) 90 vop_read_reg(vop, win->offset, win->phy->name)
91
92#define VOP_WIN_HAS_REG(win, name) \
93 (!!(win->phy->name.mask))
78 94
79#define VOP_WIN_GET_YRGBADDR(vop, win) \ 95#define VOP_WIN_GET_YRGBADDR(vop, win) \
80 vop_readl(vop, win->base + win->phy->yrgb_mst.offset) 96 vop_readl(vop, win->base + win->phy->yrgb_mst.offset)
@@ -85,6 +101,18 @@
85#define to_vop(x) container_of(x, struct vop, crtc) 101#define to_vop(x) container_of(x, struct vop, crtc)
86#define to_vop_win(x) container_of(x, struct vop_win, base) 102#define to_vop_win(x) container_of(x, struct vop_win, base)
87 103
104/*
105 * The coefficients of the following matrix are all fixed points.
106 * The format is S2.10 for the 3x3 part of the matrix, and S9.12 for the offsets.
107 * They are all represented in two's complement.
108 */
109static const uint32_t bt601_yuv2rgb[] = {
110 0x4A8, 0x0, 0x662,
111 0x4A8, 0x1E6F, 0x1CBF,
112 0x4A8, 0x812, 0x0,
113 0x321168, 0x0877CF, 0x2EB127
114};
115
88enum vop_pending { 116enum vop_pending {
89 VOP_PENDING_FB_UNREF, 117 VOP_PENDING_FB_UNREF,
90}; 118};
@@ -92,6 +120,7 @@ enum vop_pending {
92struct vop_win { 120struct vop_win {
93 struct drm_plane base; 121 struct drm_plane base;
94 const struct vop_win_data *data; 122 const struct vop_win_data *data;
123 const struct vop_win_yuv2yuv_data *yuv2yuv_data;
95 struct vop *vop; 124 struct vop *vop;
96}; 125};
97 126
@@ -686,6 +715,11 @@ static int vop_plane_atomic_check(struct drm_plane *plane,
686 return -EINVAL; 715 return -EINVAL;
687 } 716 }
688 717
718 if (fb->format->is_yuv && state->rotation & DRM_MODE_REFLECT_Y) {
719 DRM_ERROR("Invalid Source: Yuv format does not support this rotation\n");
720 return -EINVAL;
721 }
722
689 return 0; 723 return 0;
690} 724}
691 725
@@ -713,6 +747,7 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
713 struct drm_crtc *crtc = state->crtc; 747 struct drm_crtc *crtc = state->crtc;
714 struct vop_win *vop_win = to_vop_win(plane); 748 struct vop_win *vop_win = to_vop_win(plane);
715 const struct vop_win_data *win = vop_win->data; 749 const struct vop_win_data *win = vop_win->data;
750 const struct vop_win_yuv2yuv_data *win_yuv2yuv = vop_win->yuv2yuv_data;
716 struct vop *vop = to_vop(state->crtc); 751 struct vop *vop = to_vop(state->crtc);
717 struct drm_framebuffer *fb = state->fb; 752 struct drm_framebuffer *fb = state->fb;
718 unsigned int actual_w, actual_h; 753 unsigned int actual_w, actual_h;
@@ -728,6 +763,8 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
728 bool rb_swap; 763 bool rb_swap;
729 int win_index = VOP_WIN_TO_INDEX(vop_win); 764 int win_index = VOP_WIN_TO_INDEX(vop_win);
730 int format; 765 int format;
766 int is_yuv = fb->format->is_yuv;
767 int i;
731 768
732 /* 769 /*
733 * can't update plane when vop is disabled. 770 * can't update plane when vop is disabled.
@@ -761,6 +798,13 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
761 offset += (src->y1 >> 16) * fb->pitches[0]; 798 offset += (src->y1 >> 16) * fb->pitches[0];
762 dma_addr = rk_obj->dma_addr + offset + fb->offsets[0]; 799 dma_addr = rk_obj->dma_addr + offset + fb->offsets[0];
763 800
801 /*
802 * For y-mirroring we need to move address
803 * to the beginning of the last line.
804 */
805 if (state->rotation & DRM_MODE_REFLECT_Y)
806 dma_addr += (actual_h - 1) * fb->pitches[0];
807
764 format = vop_convert_format(fb->format->format); 808 format = vop_convert_format(fb->format->format);
765 809
766 spin_lock(&vop->reg_lock); 810 spin_lock(&vop->reg_lock);
@@ -768,7 +812,13 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
768 VOP_WIN_SET(vop, win, format, format); 812 VOP_WIN_SET(vop, win, format, format);
769 VOP_WIN_SET(vop, win, yrgb_vir, DIV_ROUND_UP(fb->pitches[0], 4)); 813 VOP_WIN_SET(vop, win, yrgb_vir, DIV_ROUND_UP(fb->pitches[0], 4));
770 VOP_WIN_SET(vop, win, yrgb_mst, dma_addr); 814 VOP_WIN_SET(vop, win, yrgb_mst, dma_addr);
771 if (fb->format->is_yuv) { 815 VOP_WIN_YUV2YUV_SET(vop, win_yuv2yuv, y2r_en, is_yuv);
816 VOP_WIN_SET(vop, win, y_mir_en,
817 (state->rotation & DRM_MODE_REFLECT_Y) ? 1 : 0);
818 VOP_WIN_SET(vop, win, x_mir_en,
819 (state->rotation & DRM_MODE_REFLECT_X) ? 1 : 0);
820
821 if (is_yuv) {
772 int hsub = drm_format_horz_chroma_subsampling(fb->format->format); 822 int hsub = drm_format_horz_chroma_subsampling(fb->format->format);
773 int vsub = drm_format_vert_chroma_subsampling(fb->format->format); 823 int vsub = drm_format_vert_chroma_subsampling(fb->format->format);
774 int bpp = fb->format->cpp[1]; 824 int bpp = fb->format->cpp[1];
@@ -782,6 +832,13 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
782 dma_addr = rk_uv_obj->dma_addr + offset + fb->offsets[1]; 832 dma_addr = rk_uv_obj->dma_addr + offset + fb->offsets[1];
783 VOP_WIN_SET(vop, win, uv_vir, DIV_ROUND_UP(fb->pitches[1], 4)); 833 VOP_WIN_SET(vop, win, uv_vir, DIV_ROUND_UP(fb->pitches[1], 4));
784 VOP_WIN_SET(vop, win, uv_mst, dma_addr); 834 VOP_WIN_SET(vop, win, uv_mst, dma_addr);
835
836 for (i = 0; i < NUM_YUV2YUV_COEFFICIENTS; i++) {
837 VOP_WIN_YUV2YUV_COEFFICIENT_SET(vop,
838 win_yuv2yuv,
839 y2r_coefficients[i],
840 bt601_yuv2rgb[i]);
841 }
785 } 842 }
786 843
787 if (win->phy->scl) 844 if (win->phy->scl)
@@ -820,10 +877,83 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
820 spin_unlock(&vop->reg_lock); 877 spin_unlock(&vop->reg_lock);
821} 878}
822 879
880static int vop_plane_atomic_async_check(struct drm_plane *plane,
881 struct drm_plane_state *state)
882{
883 struct vop_win *vop_win = to_vop_win(plane);
884 const struct vop_win_data *win = vop_win->data;
885 int min_scale = win->phy->scl ? FRAC_16_16(1, 8) :
886 DRM_PLANE_HELPER_NO_SCALING;
887 int max_scale = win->phy->scl ? FRAC_16_16(8, 1) :
888 DRM_PLANE_HELPER_NO_SCALING;
889 struct drm_crtc_state *crtc_state;
890
891 if (plane != state->crtc->cursor)
892 return -EINVAL;
893
894 if (!plane->state)
895 return -EINVAL;
896
897 if (!plane->state->fb)
898 return -EINVAL;
899
900 if (state->state)
901 crtc_state = drm_atomic_get_existing_crtc_state(state->state,
902 state->crtc);
903 else /* Special case for asynchronous cursor updates. */
904 crtc_state = plane->crtc->state;
905
906 return drm_atomic_helper_check_plane_state(plane->state, crtc_state,
907 min_scale, max_scale,
908 true, true);
909}
910
911static void vop_plane_atomic_async_update(struct drm_plane *plane,
912 struct drm_plane_state *new_state)
913{
914 struct vop *vop = to_vop(plane->state->crtc);
915 struct drm_plane_state *plane_state;
916
917 plane_state = plane->funcs->atomic_duplicate_state(plane);
918 plane_state->crtc_x = new_state->crtc_x;
919 plane_state->crtc_y = new_state->crtc_y;
920 plane_state->crtc_h = new_state->crtc_h;
921 plane_state->crtc_w = new_state->crtc_w;
922 plane_state->src_x = new_state->src_x;
923 plane_state->src_y = new_state->src_y;
924 plane_state->src_h = new_state->src_h;
925 plane_state->src_w = new_state->src_w;
926
927 if (plane_state->fb != new_state->fb)
928 drm_atomic_set_fb_for_plane(plane_state, new_state->fb);
929
930 swap(plane_state, plane->state);
931
932 if (plane->state->fb && plane->state->fb != new_state->fb) {
933 drm_framebuffer_get(plane->state->fb);
934 WARN_ON(drm_crtc_vblank_get(plane->state->crtc) != 0);
935 drm_flip_work_queue(&vop->fb_unref_work, plane->state->fb);
936 set_bit(VOP_PENDING_FB_UNREF, &vop->pending);
937 }
938
939 if (vop->is_enabled) {
940 rockchip_drm_psr_inhibit_get_state(new_state->state);
941 vop_plane_atomic_update(plane, plane->state);
942 spin_lock(&vop->reg_lock);
943 vop_cfg_done(vop);
944 spin_unlock(&vop->reg_lock);
945 rockchip_drm_psr_inhibit_put_state(new_state->state);
946 }
947
948 plane->funcs->atomic_destroy_state(plane, plane_state);
949}
950
823static const struct drm_plane_helper_funcs plane_helper_funcs = { 951static const struct drm_plane_helper_funcs plane_helper_funcs = {
824 .atomic_check = vop_plane_atomic_check, 952 .atomic_check = vop_plane_atomic_check,
825 .atomic_update = vop_plane_atomic_update, 953 .atomic_update = vop_plane_atomic_update,
826 .atomic_disable = vop_plane_atomic_disable, 954 .atomic_disable = vop_plane_atomic_disable,
955 .atomic_async_check = vop_plane_atomic_async_check,
956 .atomic_async_update = vop_plane_atomic_async_update,
827 .prepare_fb = drm_gem_fb_prepare_fb, 957 .prepare_fb = drm_gem_fb_prepare_fb,
828}; 958};
829 959
@@ -1274,6 +1404,18 @@ out:
1274 return ret; 1404 return ret;
1275} 1405}
1276 1406
1407static void vop_plane_add_properties(struct drm_plane *plane,
1408 const struct vop_win_data *win_data)
1409{
1410 unsigned int flags = 0;
1411
1412 flags |= VOP_WIN_HAS_REG(win_data, x_mir_en) ? DRM_MODE_REFLECT_X : 0;
1413 flags |= VOP_WIN_HAS_REG(win_data, y_mir_en) ? DRM_MODE_REFLECT_Y : 0;
1414 if (flags)
1415 drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0,
1416 DRM_MODE_ROTATE_0 | flags);
1417}
1418
1277static int vop_create_crtc(struct vop *vop) 1419static int vop_create_crtc(struct vop *vop)
1278{ 1420{
1279 const struct vop_data *vop_data = vop->data; 1421 const struct vop_data *vop_data = vop->data;
@@ -1311,6 +1453,7 @@ static int vop_create_crtc(struct vop *vop)
1311 1453
1312 plane = &vop_win->base; 1454 plane = &vop_win->base;
1313 drm_plane_helper_add(plane, &plane_helper_funcs); 1455 drm_plane_helper_add(plane, &plane_helper_funcs);
1456 vop_plane_add_properties(plane, win_data);
1314 if (plane->type == DRM_PLANE_TYPE_PRIMARY) 1457 if (plane->type == DRM_PLANE_TYPE_PRIMARY)
1315 primary = plane; 1458 primary = plane;
1316 else if (plane->type == DRM_PLANE_TYPE_CURSOR) 1459 else if (plane->type == DRM_PLANE_TYPE_CURSOR)
@@ -1348,6 +1491,7 @@ static int vop_create_crtc(struct vop *vop)
1348 goto err_cleanup_crtc; 1491 goto err_cleanup_crtc;
1349 } 1492 }
1350 drm_plane_helper_add(&vop_win->base, &plane_helper_funcs); 1493 drm_plane_helper_add(&vop_win->base, &plane_helper_funcs);
1494 vop_plane_add_properties(&vop_win->base, win_data);
1351 } 1495 }
1352 1496
1353 port = of_get_child_by_name(dev->of_node, "port"); 1497 port = of_get_child_by_name(dev->of_node, "port");
@@ -1531,6 +1675,7 @@ static void vop_win_init(struct vop *vop)
1531 1675
1532 vop_win->data = win_data; 1676 vop_win->data = win_data;
1533 vop_win->vop = vop; 1677 vop_win->vop = vop;
1678 vop_win->yuv2yuv_data = &vop_data->win_yuv2yuv[i];
1534 } 1679 }
1535} 1680}
1536 1681