@@ -368,6 +368,12 @@ static void tegra_dc_setup_window(struct tegra_plane *plane,
368
368
h_size = window -> src .w * bpp ;
369
369
v_size = window -> src .h ;
370
370
371
+ if (window -> reflect_x )
372
+ h_offset += (window -> src .w - 1 ) * bpp ;
373
+
374
+ if (window -> reflect_y )
375
+ v_offset += window -> src .h - 1 ;
376
+
371
377
value = V_PRESCALED_SIZE (v_size ) | H_PRESCALED_SIZE (h_size );
372
378
tegra_plane_writel (plane , value , DC_WIN_PRESCALED_SIZE );
373
379
@@ -404,9 +410,6 @@ static void tegra_dc_setup_window(struct tegra_plane *plane,
404
410
tegra_plane_writel (plane , window -> stride [0 ], DC_WIN_LINE_STRIDE );
405
411
}
406
412
407
- if (window -> reflect_y )
408
- v_offset += window -> src .h - 1 ;
409
-
410
413
tegra_plane_writel (plane , h_offset , DC_WINBUF_ADDR_H_OFFSET );
411
414
tegra_plane_writel (plane , v_offset , DC_WINBUF_ADDR_V_OFFSET );
412
415
@@ -470,6 +473,9 @@ static void tegra_dc_setup_window(struct tegra_plane *plane,
470
473
value |= COLOR_EXPAND ;
471
474
}
472
475
476
+ if (window -> reflect_x )
477
+ value |= H_DIRECTION ;
478
+
473
479
if (window -> reflect_y )
474
480
value |= V_DIRECTION ;
475
481
@@ -601,7 +607,10 @@ static int tegra_plane_atomic_check(struct drm_plane *plane,
601
607
struct drm_plane_state * state )
602
608
{
603
609
struct tegra_plane_state * plane_state = to_tegra_plane_state (state );
604
- unsigned int rotation = DRM_MODE_ROTATE_0 | DRM_MODE_REFLECT_Y ;
610
+ unsigned int supported_rotation = DRM_MODE_ROTATE_0 |
611
+ DRM_MODE_REFLECT_X |
612
+ DRM_MODE_REFLECT_Y ;
613
+ unsigned int rotation = state -> rotation ;
605
614
struct tegra_bo_tiling * tiling = & plane_state -> tiling ;
606
615
struct tegra_plane * tegra = to_tegra_plane (plane );
607
616
struct tegra_dc * dc = to_tegra_dc (state -> crtc );
@@ -639,7 +648,21 @@ static int tegra_plane_atomic_check(struct drm_plane *plane,
639
648
return - EINVAL ;
640
649
}
641
650
642
- rotation = drm_rotation_simplify (state -> rotation , rotation );
651
+ /*
652
+ * Older userspace used custom BO flag in order to specify the Y
653
+ * reflection, while modern userspace uses the generic DRM rotation
654
+ * property in order to achieve the same result. The legacy BO flag
655
+ * duplicates the DRM rotation property when both are set.
656
+ */
657
+ if (tegra_fb_is_bottom_up (state -> fb ))
658
+ rotation |= DRM_MODE_REFLECT_Y ;
659
+
660
+ rotation = drm_rotation_simplify (rotation , supported_rotation );
661
+
662
+ if (rotation & DRM_MODE_REFLECT_X )
663
+ plane_state -> reflect_x = true;
664
+ else
665
+ plane_state -> reflect_x = false;
643
666
644
667
if (rotation & DRM_MODE_REFLECT_Y )
645
668
plane_state -> reflect_y = true;
@@ -706,7 +729,8 @@ static void tegra_plane_atomic_update(struct drm_plane *plane,
706
729
window .dst .w = drm_rect_width (& plane -> state -> dst );
707
730
window .dst .h = drm_rect_height (& plane -> state -> dst );
708
731
window .bits_per_pixel = fb -> format -> cpp [0 ] * 8 ;
709
- window .reflect_y = tegra_fb_is_bottom_up (fb ) || state -> reflect_y ;
732
+ window .reflect_x = state -> reflect_x ;
733
+ window .reflect_y = state -> reflect_y ;
710
734
711
735
/* copy from state */
712
736
window .zpos = plane -> state -> normalized_zpos ;
@@ -792,6 +816,7 @@ static struct drm_plane *tegra_primary_plane_create(struct drm_device *drm,
792
816
err = drm_plane_create_rotation_property (& plane -> base ,
793
817
DRM_MODE_ROTATE_0 ,
794
818
DRM_MODE_ROTATE_0 |
819
+ DRM_MODE_REFLECT_X |
795
820
DRM_MODE_REFLECT_Y );
796
821
if (err < 0 )
797
822
dev_err (dc -> dev , "failed to create rotation property: %d\n" ,
@@ -1080,6 +1105,7 @@ static struct drm_plane *tegra_dc_overlay_plane_create(struct drm_device *drm,
1080
1105
err = drm_plane_create_rotation_property (& plane -> base ,
1081
1106
DRM_MODE_ROTATE_0 ,
1082
1107
DRM_MODE_ROTATE_0 |
1108
+ DRM_MODE_REFLECT_X |
1083
1109
DRM_MODE_REFLECT_Y );
1084
1110
if (err < 0 )
1085
1111
dev_err (dc -> dev , "failed to create rotation property: %d\n" ,
0 commit comments