video: tegra-dc: add 180 degree panel rotation
authorSvyatoslav Ryhel <clamor95@gmail.com>
Mon, 27 Mar 2023 08:11:45 +0000 (11:11 +0300)
committerAnatolij Gustschin <agust@denx.de>
Fri, 7 Apr 2023 17:46:24 +0000 (19:46 +0200)
Unlike 90 and 270 degree rotation, 180 degree rotation is more
common and does not require scaling. Implement it for correct
grouper support.

Tested-by: Andreas Westman Dorcsak <hedmoo@yahoo.com> # Google Nexus 7 2012
Tested-by: Svyatoslav Ryhel <clamor95@gmail.com> # Google Nexus 7 2012
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
drivers/video/tegra20/tegra-dc.c

index e004ee3..e279650 100644 (file)
@@ -37,6 +37,7 @@ struct tegra_lcd_priv {
        fdt_addr_t frame_buffer;        /* Address of frame buffer */
        unsigned pixel_clock;           /* Pixel clock in Hz */
        int dc_clk[2];                  /* Contains clk and its parent */
+       bool rotation;                  /* 180 degree panel turn */
 };
 
 enum {
@@ -46,8 +47,10 @@ enum {
        LCD_MAX_LOG2_BPP        = VIDEO_BPP16,
 };
 
-static void update_window(struct dc_ctlr *dc, struct disp_ctl_win *win)
+static void update_window(struct tegra_lcd_priv *priv,
+                         struct disp_ctl_win *win)
 {
+       struct dc_ctlr *dc = priv->dc;
        unsigned h_dda, v_dda;
        unsigned long val;
 
@@ -88,6 +91,10 @@ static void update_window(struct dc_ctlr *dc, struct disp_ctl_win *win)
        val = WIN_ENABLE;
        if (win->bpp < 24)
                val |= COLOR_EXPAND;
+
+       if (priv->rotation)
+               val |= H_DIRECTION | V_DIRECTION;
+
        writel(val, &dc->win.win_opt);
 
        writel((unsigned long)win->phys_addr, &dc->winbuf.start_addr);
@@ -224,8 +231,14 @@ static void rgb_enable(struct dc_com_reg *com)
 static int setup_window(struct disp_ctl_win *win,
                        struct tegra_lcd_priv *priv)
 {
-       win->x = 0;
-       win->y = 0;
+       if (priv->rotation) {
+               win->x = priv->width * 2;
+               win->y = priv->height;
+       } else {
+               win->x = 0;
+               win->y = 0;
+       }
+
        win->w = priv->width;
        win->h = priv->height;
        win->out_x = 0;
@@ -298,7 +311,7 @@ static int tegra_display_probe(const void *blob, struct tegra_lcd_priv *priv,
        if (setup_window(&window, priv))
                return -1;
 
-       update_window(priv->dc, &window);
+       update_window(priv, &window);
 
        return 0;
 }
@@ -370,6 +383,8 @@ static int tegra_lcd_of_to_plat(struct udevice *dev)
                return -EINVAL;
        }
 
+       priv->rotation = dev_read_bool(dev, "nvidia,180-rotation");
+
        rgb = fdt_subnode_offset(blob, node, "rgb");
        if (rgb < 0) {
                debug("%s: Cannot find rgb subnode for '%s' (ret=%d)\n",