video: tegra: Move to using simple-panel and pwm-backlight
authorSimon Glass <sjg@chromium.org>
Sun, 8 May 2016 22:55:20 +0000 (16:55 -0600)
committerTom Warren <twarren@nvidia.com>
Tue, 5 Jul 2016 20:19:08 +0000 (13:19 -0700)
We have standard drivers for panels and backlights which can do most of the
work for us. Move the tegra20 LCD driver over to use those instead of custom
code.

This patch includes device tree changes for the nvidia boards. I have only
been able to test seaboard. If this patch is applied, these boards will
also need to be synced with the kernel, and updated to use display-timings:

   - colibri
   - medcom-wide
   - paz00
   - tec

Signed-off-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Tom Warren <twarren@nvidia.com>
arch/arm/dts/tegra20-harmony.dts
arch/arm/dts/tegra20-seaboard.dts
arch/arm/dts/tegra20-ventana.dts
configs/colibri_t20_defconfig
configs/harmony_defconfig
configs/medcom-wide_defconfig
configs/paz00_defconfig
configs/seaboard_defconfig
configs/tec_defconfig
configs/ventana_defconfig
drivers/video/tegra.c

index a8540d4e9cdb07a8cdaa43f20e173488d4f946af..8e9fe5ad3f162f84612d0e4b8ecb6e54b6b99733 100644 (file)
                        status = "okay";
                        rgb {
                                status = "okay";
-                               nvidia,panel = <&lcd_panel>;
+
+                               nvidia,panel = <&panel>;
+
+                               display-timings {
+                                       timing@0 {
+                                               /* Seaboard has 1366x768 */
+                                               clock-frequency = <42430000>;
+                                               hactive = <1024>;
+                                               vactive = <600>;
+                                               hback-porch = <138>;
+                                               hfront-porch = <34>;
+                                               hsync-len = <136>;
+                                               vback-porch = <21>;
+                                               vfront-porch = <4>;
+                                               vsync-len = <4>;
+                                       };
+                               };
                        };
                };
 
                };
        };
 
-       lcd_panel: panel {
-               clock = <42430000>;
-               xres = <1024>;
-               yres = <600>;
-               left-margin = <138>;
-               right-margin = <34>;
-               hsync-len = <136>;
-               lower-margin = <4>;
-               upper-margin = <21>;
-               vsync-len = <4>;
-               hsync-active-high;
-               vsyncx-active-high;
-               nvidia,bits-per-pixel = <16>;
-               nvidia,pwm = <&pwm 0 0>;
-               nvidia,backlight-enable-gpios = <&gpio TEGRA_GPIO(B, 5)
-                                                       GPIO_ACTIVE_HIGH>;
-               nvidia,lvds-shutdown-gpios = <&gpio TEGRA_GPIO(B, 2)
-                                                       GPIO_ACTIVE_HIGH>;
-               nvidia,backlight-vdd-gpios = <&gpio TEGRA_GPIO(W, 0)
-                                                       GPIO_ACTIVE_HIGH>;
-               nvidia,panel-vdd-gpios = <&gpio TEGRA_GPIO(C, 6)
-                                                       GPIO_ACTIVE_HIGH>;
-               nvidia,panel-timings = <0 0 200 0 0>;
+       panel: panel {
+               compatible = "auo,b101aw03", "simple-panel";
+
+               power-supply = <&vdd_pnl_reg>;
+               enable-gpios = <&gpio TEGRA_GPIO(B, 2) GPIO_ACTIVE_HIGH>;
+
+               backlight = <&backlight>;
        };
 
        regulators {
index 61690943b80ea105347982004ded0ed5fb9f8b39..0a454f98cf3aa4ba213637d149f8dc4c955467a9 100644 (file)
                                status = "okay";
 
                                nvidia,panel = <&panel>;
+
+                               display-timings {
+                                       timing@0 {
+                                               /* Seaboard has 1366x768 */
+                                               clock-frequency = <70600000>;
+                                               hactive = <1366>;
+                                               vactive = <768>;
+                                               hback-porch = <58>;
+                                               hfront-porch = <58>;
+                                               hsync-len = <58>;
+                                               vback-porch = <4>;
+                                               vfront-porch = <4>;
+                                               vsync-len = <4>;
+                                               hsync-active = <1>;
+                                       };
+                               };
                        };
                };
 
        };
 
        panel: panel {
-               /* Seaboard has 1366x768 */
-               clock = <70600000>;
-               xres = <1366>;
-               yres = <768>;
-               left-margin = <58>;
-               right-margin = <58>;
-               hsync-len = <58>;
-               lower-margin = <4>;
-               upper-margin = <4>;
-               vsync-len = <4>;
-               hsync-active-high;
-               nvidia,bits-per-pixel = <16>;
-               nvidia,pwm = <&pwm 2 0>;
-               nvidia,backlight-enable-gpios = <&gpio TEGRA_GPIO(D, 4)
-                                                       GPIO_ACTIVE_HIGH>;
-               nvidia,lvds-shutdown-gpios = <&gpio TEGRA_GPIO(B, 2)
-                                                       GPIO_ACTIVE_HIGH>;
-               nvidia,backlight-vdd-gpios = <&gpio TEGRA_GPIO(W, 0)
-                                                       GPIO_ACTIVE_HIGH>;
-               nvidia,panel-vdd-gpios = <&gpio TEGRA_GPIO(C, 6)
-                                                       GPIO_ACTIVE_HIGH>;
-               nvidia,panel-timings = <400 4 203 17 15>;
+               compatible = "chunghwa,claa101wa01a", "simple-panel";
+
+               power-supply = <&vdd_pnl_reg>;
+               enable-gpios = <&gpio TEGRA_GPIO(B, 2) GPIO_ACTIVE_HIGH>;
+
+               backlight = <&backlight>;
+               ddc-i2c-bus = <&lvds_ddc>;
        };
 
        regulators {
index 0ce46aebcbc070fe3dcae3977ecbea1613d6c0a0..143e964459a0713b5a8e0f4de2d66a473750fc3f 100644 (file)
                        status = "okay";
                        rgb {
                                status = "okay";
-                               nvidia,panel = <&lcd_panel>;
+
+                               nvidia,panel = <&panel>;
+
+                               display-timings {
+                                       timing@0 {
+                                               /* Seaboard has 1366x768 */
+                                               clock-frequency = <70600000>;
+                                               hactive = <1366>;
+                                               vactive = <768>;
+                                               hback-porch = <58>;
+                                               hfront-porch = <58>;
+                                               hsync-len = <58>;
+                                               vback-porch = <4>;
+                                               vfront-porch = <4>;
+                                               vsync-len = <4>;
+                                               hsync-active = <1>;
+                                       };
+                               };
                        };
                };
 
                };
        };
 
+       panel: panel {
+               compatible = "chunghwa,claa101wa01a", "simple-panel";
+
+               power-supply = <&vdd_pnl_reg>;
+               enable-gpios = <&gpio TEGRA_GPIO(B, 2) GPIO_ACTIVE_HIGH>;
+
+               backlight = <&backlight>;
+               ddc-i2c-bus = <&lvds_ddc>;
+       };
+
        regulators {
                compatible = "simple-bus";
                #address-cells = <1>;
                };
        };
 
-       lcd_panel: panel {
-               clock = <72072000>;
-               xres = <1366>;
-               yres = <768>;
-               left-margin = <58>;
-               right-margin = <58>;
-               hsync-len = <58>;
-               lower-margin = <4>;
-               upper-margin = <4>;
-               vsync-len = <4>;
-               hsync-active-high;
-               vsync-active-high;
-               nvidia,bits-per-pixel = <16>;
-               nvidia,pwm = <&pwm 2 0>;
-               nvidia,backlight-enable-gpios = <&gpio TEGRA_GPIO(D, 4)
-                                                       GPIO_ACTIVE_HIGH>;
-               nvidia,lvds-shutdown-gpios = <&gpio TEGRA_GPIO(B, 2)
-                                                       GPIO_ACTIVE_HIGH>;
-               nvidia,backlight-vdd-gpios = <&gpio TEGRA_GPIO(W, 0)
-                                                       GPIO_ACTIVE_HIGH>;
-               nvidia,panel-vdd-gpios = <&gpio TEGRA_GPIO(C, 6)
-                                                       GPIO_ACTIVE_HIGH>;
-               nvidia,panel-timings = <0 0 200 0 0>;
-       };
-
        sound {
                compatible = "nvidia,tegra-audio-wm8903-ventana",
                             "nvidia,tegra-audio-wm8903";
index a3b2a3c862f87fd249af7a394ba51f56b5236b0d..5907a33dc31ab6c7c5fd0e9997a7d4484577c854 100644 (file)
@@ -23,6 +23,8 @@ CONFIG_CMD_DHCP=y
 CONFIG_CMD_MII=y
 CONFIG_CMD_PING=y
 CONFIG_CMD_CACHE=y
+CONFIG_CMD_PMIC=y
+CONFIG_CMD_REGULATOR=y
 CONFIG_CMD_EXT2=y
 CONFIG_CMD_EXT4=y
 CONFIG_CMD_EXT4_WRITE=y
@@ -30,6 +32,7 @@ CONFIG_CMD_FAT=y
 CONFIG_CMD_FS_GENERIC=y
 CONFIG_DM_PMIC=y
 CONFIG_DM_REGULATOR=y
+CONFIG_DM_REGULATOR_FIXED=y
 CONFIG_PWM_TEGRA=y
 CONFIG_SYS_NS16550=y
 CONFIG_USB=y
index 129a72b1cf9ec93cf2e9545e2c55bd48d70477eb..e0b9559992a17c570b8f4a962e1713fb8babab94 100644 (file)
@@ -20,6 +20,8 @@ CONFIG_CMD_DHCP=y
 # CONFIG_CMD_NFS is not set
 CONFIG_CMD_MII=y
 CONFIG_CMD_PING=y
+CONFIG_CMD_PMIC=y
+CONFIG_CMD_REGULATOR=y
 CONFIG_CMD_EXT2=y
 CONFIG_CMD_EXT4=y
 CONFIG_CMD_EXT4_WRITE=y
@@ -27,6 +29,7 @@ CONFIG_CMD_FAT=y
 CONFIG_CMD_FS_GENERIC=y
 CONFIG_DM_PMIC=y
 CONFIG_DM_REGULATOR=y
+CONFIG_DM_REGULATOR_FIXED=y
 CONFIG_PWM_TEGRA=y
 CONFIG_SYS_NS16550=y
 CONFIG_USB=y
index 02eb70431b25012923e7c225c5180ba3ea62f8e3..14cb53a889e57b2731a6780c8e0c1bf366902d58 100644 (file)
@@ -21,6 +21,8 @@ CONFIG_CMD_DHCP=y
 # CONFIG_CMD_NFS is not set
 CONFIG_CMD_MII=y
 CONFIG_CMD_PING=y
+CONFIG_CMD_PMIC=y
+CONFIG_CMD_REGULATOR=y
 CONFIG_CMD_EXT2=y
 CONFIG_CMD_EXT4=y
 CONFIG_CMD_EXT4_WRITE=y
@@ -28,6 +30,7 @@ CONFIG_CMD_FAT=y
 CONFIG_CMD_FS_GENERIC=y
 CONFIG_DM_PMIC=y
 CONFIG_DM_REGULATOR=y
+CONFIG_DM_REGULATOR_FIXED=y
 CONFIG_PWM_TEGRA=y
 CONFIG_SYS_NS16550=y
 CONFIG_USB=y
index 0fe43b1c958b9902ab36bcce1888723bcd959ae1..000bbfbaf75df85cbf07aca941c39667b61932aa 100644 (file)
@@ -20,6 +20,8 @@ CONFIG_CMD_DHCP=y
 # CONFIG_CMD_NFS is not set
 CONFIG_CMD_MII=y
 CONFIG_CMD_PING=y
+CONFIG_CMD_PMIC=y
+CONFIG_CMD_REGULATOR=y
 CONFIG_CMD_EXT2=y
 CONFIG_CMD_EXT4=y
 CONFIG_CMD_EXT4_WRITE=y
@@ -27,6 +29,7 @@ CONFIG_CMD_FAT=y
 CONFIG_CMD_FS_GENERIC=y
 CONFIG_DM_PMIC=y
 CONFIG_DM_REGULATOR=y
+CONFIG_DM_REGULATOR_FIXED=y
 CONFIG_PWM_TEGRA=y
 CONFIG_SYS_NS16550=y
 CONFIG_USB=y
index 3f8648ddeb1ea66afa5ec1ed409950ad562c18a7..3c5c413c6d63e0ca1e079af70cb265106db516f0 100644 (file)
@@ -21,6 +21,8 @@ CONFIG_CMD_DHCP=y
 # CONFIG_CMD_NFS is not set
 CONFIG_CMD_MII=y
 CONFIG_CMD_PING=y
+CONFIG_CMD_PMIC=y
+CONFIG_CMD_REGULATOR=y
 CONFIG_CMD_EXT2=y
 CONFIG_CMD_EXT4=y
 CONFIG_CMD_EXT4_WRITE=y
@@ -28,6 +30,7 @@ CONFIG_CMD_FAT=y
 CONFIG_CMD_FS_GENERIC=y
 CONFIG_DM_PMIC=y
 CONFIG_DM_REGULATOR=y
+CONFIG_DM_REGULATOR_FIXED=y
 CONFIG_PWM_TEGRA=y
 CONFIG_SYS_NS16550=y
 CONFIG_USB=y
index 20551013999ccdc22793e240f150ae6a39765598..dc7169b7d6d69e215660ed6b7989cf085f229377 100644 (file)
@@ -21,6 +21,8 @@ CONFIG_CMD_DHCP=y
 # CONFIG_CMD_NFS is not set
 CONFIG_CMD_MII=y
 CONFIG_CMD_PING=y
+CONFIG_CMD_PMIC=y
+CONFIG_CMD_REGULATOR=y
 CONFIG_CMD_EXT2=y
 CONFIG_CMD_EXT4=y
 CONFIG_CMD_EXT4_WRITE=y
@@ -28,6 +30,7 @@ CONFIG_CMD_FAT=y
 CONFIG_CMD_FS_GENERIC=y
 CONFIG_DM_PMIC=y
 CONFIG_DM_REGULATOR=y
+CONFIG_DM_REGULATOR_FIXED=y
 CONFIG_PWM_TEGRA=y
 CONFIG_SYS_NS16550=y
 CONFIG_USB=y
index 97b13a1b1d4ed9357e6e147ef36b211bbdbb33dd..07a4afee3c5a97cfbc13f7a2eadebea6d2178b2c 100644 (file)
@@ -20,6 +20,8 @@ CONFIG_CMD_DHCP=y
 # CONFIG_CMD_NFS is not set
 CONFIG_CMD_MII=y
 CONFIG_CMD_PING=y
+CONFIG_CMD_PMIC=y
+CONFIG_CMD_REGULATOR=y
 CONFIG_CMD_EXT2=y
 CONFIG_CMD_EXT4=y
 CONFIG_CMD_EXT4_WRITE=y
@@ -27,6 +29,7 @@ CONFIG_CMD_FAT=y
 CONFIG_CMD_FS_GENERIC=y
 CONFIG_DM_PMIC=y
 CONFIG_DM_REGULATOR=y
+CONFIG_DM_REGULATOR_FIXED=y
 CONFIG_PWM_TEGRA=y
 CONFIG_SYS_NS16550=y
 CONFIG_USB=y
index c01809e89e142a0de3a3b609e478e55c19f03bbb..5c48c3b9645eb5eade89d197aa0a63759b366935 100644 (file)
@@ -6,6 +6,7 @@
 #include <common.h>
 #include <dm.h>
 #include <fdtdec.h>
+#include <panel.h>
 #include <pwm.h>
 #include <video.h>
 #include <asm/system.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
-/* These are the stages we go throuh in enabling the LCD */
-enum stage_t {
-       STAGE_START,
-       STAGE_PANEL_VDD,
-       STAGE_LVDS,
-       STAGE_BACKLIGHT_VDD,
-       STAGE_PWM,
-       STAGE_BACKLIGHT_EN,
-       STAGE_DONE,
-};
-
-#define FDT_LCD_TIMINGS        4
-
-enum {
-       FDT_LCD_TIMING_REF_TO_SYNC,
-       FDT_LCD_TIMING_SYNC_WIDTH,
-       FDT_LCD_TIMING_BACK_PORCH,
-       FDT_LCD_TIMING_FRONT_PORCH,
-
-       FDT_LCD_TIMING_COUNT,
-};
-
 enum lcd_cache_t {
        FDT_LCD_CACHE_OFF               = 0,
        FDT_LCD_CACHE_WRITE_THROUGH     = 1 << 0,
@@ -54,37 +33,15 @@ enum lcd_cache_t {
 
 /* Information about the display controller */
 struct tegra_lcd_priv {
-       enum stage_t stage;     /* Current stage we are at */
-       unsigned long timer_next; /* Time we can move onto next stage */
        int width;                      /* width in pixels */
        int height;                     /* height in pixels */
-
-       /*
-        * log2 of number of bpp, in general, unless it bpp is 24 in which
-        * case this field holds 24 also! This is a U-Boot thing.
-        */
-       int log2_bpp;
+       enum video_log2_bpp log2_bpp;   /* colour depth */
+       struct display_timing timing;
+       struct udevice *panel;
        struct disp_ctlr *disp;         /* Display controller to use */
        fdt_addr_t frame_buffer;        /* Address of frame buffer */
        unsigned pixel_clock;           /* Pixel clock in Hz */
-       uint horiz_timing[FDT_LCD_TIMING_COUNT];        /* Horizontal timing */
-       uint vert_timing[FDT_LCD_TIMING_COUNT];         /* Vertical timing */
-       struct udevice *pwm;
-       int pwm_channel;                /* PWM channel to use for backlight */
        enum lcd_cache_t cache_type;
-
-       struct gpio_desc backlight_en;  /* GPIO for backlight enable */
-       struct gpio_desc lvds_shutdown; /* GPIO for lvds shutdown */
-       struct gpio_desc backlight_vdd; /* GPIO for backlight vdd */
-       struct gpio_desc panel_vdd;     /* GPIO for panel vdd */
-       /*
-        * Panel required timings
-        * Timing 1: delay between panel_vdd-rise and data-rise
-        * Timing 2: delay between data-rise and backlight_vdd-rise
-        * Timing 3: delay between backlight_vdd and pwm-rise
-        * Timing 4: delay between pwm-rise and backlight_en-rise
-        */
-       uint panel_timings[FDT_LCD_TIMINGS];
 };
 
 enum {
@@ -150,26 +107,23 @@ static void update_window(struct dc_ctlr *dc, struct disp_ctl_win *win)
        writel(val, &dc->cmd.state_ctrl);
 }
 
-static void write_pair(struct tegra_lcd_priv *priv, int item, u32 *reg)
-{
-       writel(priv->horiz_timing[item] |
-                       (priv->vert_timing[item] << 16), reg);
-}
-
 static int update_display_mode(struct dc_disp_reg *disp,
                               struct tegra_lcd_priv *priv)
 {
+       struct display_timing *dt = &priv->timing;
        unsigned long val;
        unsigned long rate;
        unsigned long div;
 
        writel(0x0, &disp->disp_timing_opt);
-       write_pair(priv, FDT_LCD_TIMING_REF_TO_SYNC, &disp->ref_to_sync);
-       write_pair(priv, FDT_LCD_TIMING_SYNC_WIDTH, &disp->sync_width);
-       write_pair(priv, FDT_LCD_TIMING_BACK_PORCH, &disp->back_porch);
-       write_pair(priv, FDT_LCD_TIMING_FRONT_PORCH, &disp->front_porch);
 
-       writel(priv->width | (priv->height << 16), &disp->disp_active);
+       writel(1 | 1 << 16, &disp->ref_to_sync);
+       writel(dt->hsync_len.typ | dt->vsync_len.typ << 16, &disp->sync_width);
+       writel(dt->hback_porch.typ | dt->vback_porch.typ << 16,
+              &disp->back_porch);
+       writel((dt->hfront_porch.typ - 1) | (dt->vfront_porch.typ - 1) << 16,
+              &disp->front_porch);
+       writel(dt->hactive.typ | (dt->vactive.typ << 16), &disp->disp_active);
 
        val = DE_SELECT_ACTIVE << DE_SELECT_SHIFT;
        val |= DE_CONTROL_NORMAL << DE_CONTROL_SHIFT;
@@ -287,12 +241,11 @@ static int setup_window(struct disp_ctl_win *win,
        win->stride = priv->width * (1 << priv->log2_bpp) / 8;
        debug("%s: depth = %d\n", __func__, priv->log2_bpp);
        switch (priv->log2_bpp) {
-       case 5:
-       case 24:
+       case VIDEO_BPP32:
                win->fmt = COLOR_DEPTH_R8G8B8A8;
                win->bpp = 32;
                break;
-       case 4:
+       case VIDEO_BPP16:
                win->fmt = COLOR_DEPTH_B5G6R5;
                win->bpp = 16;
                break;
@@ -305,18 +258,6 @@ static int setup_window(struct disp_ctl_win *win,
        return 0;
 }
 
-static void debug_timing(const char *name, unsigned int timing[])
-{
-#ifdef DEBUG
-       int i;
-
-       debug("%s timing: ", name);
-       for (i = 0; i < FDT_LCD_TIMING_COUNT; i++)
-               debug("%d ", timing[i]);
-       debug("\n");
-#endif
-}
-
 /**
  * Register a new display based on device tree configuration.
  *
@@ -363,112 +304,6 @@ static int tegra_display_probe(const void *blob, struct tegra_lcd_priv *priv,
        return 0;
 }
 
-/**
- * Handle the next stage of device init
- */
-static int handle_stage(const void *blob, struct tegra_lcd_priv *priv)
-{
-       debug("%s: stage %d\n", __func__, priv->stage);
-
-       /* do the things for this stage */
-       switch (priv->stage) {
-       case STAGE_START:
-               /*
-                * It is possible that the FDT has requested that the LCD be
-                * disabled. We currently don't support this. It would require
-                * changes to U-Boot LCD subsystem to have LCD support
-                * compiled in but not used. An easier option might be to
-                * still have a frame buffer, but leave the backlight off and
-                * remove all mention of lcd in the stdout environment
-                * variable.
-                */
-
-               funcmux_select(PERIPH_ID_DISP1, FUNCMUX_DEFAULT);
-               break;
-       case STAGE_PANEL_VDD:
-               if (dm_gpio_is_valid(&priv->panel_vdd))
-                       dm_gpio_set_value(&priv->panel_vdd, 1);
-               break;
-       case STAGE_LVDS:
-               if (dm_gpio_is_valid(&priv->lvds_shutdown))
-                       dm_gpio_set_value(&priv->lvds_shutdown, 1);
-               break;
-       case STAGE_BACKLIGHT_VDD:
-               if (dm_gpio_is_valid(&priv->backlight_vdd))
-                       dm_gpio_set_value(&priv->backlight_vdd, 1);
-               break;
-       case STAGE_PWM:
-               /* Enable PWM at 15/16 high, 32768 Hz with divider 1 */
-               pinmux_set_func(PMUX_PINGRP_GPU, PMUX_FUNC_PWM);
-               pinmux_tristate_disable(PMUX_PINGRP_GPU);
-
-               pwm_set_config(priv->pwm, priv->pwm_channel, 0xdf, 0xff);
-               pwm_set_enable(priv->pwm, priv->pwm_channel, true);
-               break;
-       case STAGE_BACKLIGHT_EN:
-               if (dm_gpio_is_valid(&priv->backlight_en))
-                       dm_gpio_set_value(&priv->backlight_en, 1);
-               break;
-       case STAGE_DONE:
-               break;
-       }
-
-       /* set up timer for next stage */
-       priv->timer_next = timer_get_us();
-       if (priv->stage < FDT_LCD_TIMINGS)
-               priv->timer_next += priv->panel_timings[priv->stage] * 1000;
-
-       /* move to next stage */
-       priv->stage++;
-       return 0;
-}
-
-/**
- * Perform the next stage of the LCD init if it is time to do so.
- *
- * LCD init can be time-consuming because of the number of delays we need
- * while waiting for the backlight power supply, etc. This function can
- * be called at various times during U-Boot operation to advance the
- * initialization of the LCD to the next stage if sufficient time has
- * passed since the last stage. It keeps track of what stage it is up to
- * and the time that it is permitted to move to the next stage.
- *
- * The final call should have wait=1 to complete the init.
- *
- * @param blob fdt blob containing LCD information
- * @param wait 1 to wait until all init is complete, and then return
- *             0 to return immediately, potentially doing nothing if it is
- *             not yet time for the next init.
- */
-static int tegra_lcd_check_next_stage(const void *blob,
-                                     struct tegra_lcd_priv *priv, int wait)
-{
-       if (priv->stage == STAGE_DONE)
-               return 0;
-
-       do {
-               /* wait if we need to */
-               debug("%s: stage %d\n", __func__, priv->stage);
-               if (priv->stage != STAGE_START) {
-                       int delay = priv->timer_next - timer_get_us();
-
-                       if (delay > 0) {
-                               if (wait)
-                                       udelay(delay);
-                               else
-                                       return 0;
-                       }
-               }
-
-               if (handle_stage(blob, priv))
-                       return -1;
-       } while (wait && priv->stage != STAGE_DONE);
-       if (priv->stage == STAGE_DONE)
-               debug("%s: LCD init complete\n", __func__);
-
-       return 0;
-}
-
 static int tegra_lcd_probe(struct udevice *dev)
 {
        struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
@@ -476,14 +311,23 @@ static int tegra_lcd_probe(struct udevice *dev)
        struct tegra_lcd_priv *priv = dev_get_priv(dev);
        const void *blob = gd->fdt_blob;
        int type = DCACHE_OFF;
+       int ret;
 
        /* Initialize the Tegra display controller */
+       funcmux_select(PERIPH_ID_DISP1, FUNCMUX_DEFAULT);
        if (tegra_display_probe(blob, priv, (void *)plat->base)) {
                printf("%s: Failed to probe display driver\n", __func__);
                return -1;
        }
 
-       tegra_lcd_check_next_stage(blob, priv, 1);
+       pinmux_set_func(PMUX_PINGRP_GPU, PMUX_FUNC_PWM);
+       pinmux_tristate_disable(PMUX_PINGRP_GPU);
+
+       ret = panel_enable_backlight(priv->panel);
+       if (ret) {
+               debug("%s: Cannot enable backlight, ret=%d\n", __func__, ret);
+               return ret;
+       }
 
        /* Set up the LCD caching as requested */
        if (priv->cache_type & FDT_LCD_CACHE_WRITE_THROUGH)
@@ -507,13 +351,11 @@ static int tegra_lcd_probe(struct udevice *dev)
 static int tegra_lcd_ofdata_to_platdata(struct udevice *dev)
 {
        struct tegra_lcd_priv *priv = dev_get_priv(dev);
-       struct fdtdec_phandle_args args;
        const void *blob = gd->fdt_blob;
+       struct display_timing *timing;
        int node = dev->of_offset;
-       int front, back, ref;
        int panel_node;
        int rgb;
-       int bpp, bit;
        int ret;
 
        priv->disp = (struct disp_ctlr *)dev_get_addr(dev);
@@ -523,96 +365,40 @@ static int tegra_lcd_ofdata_to_platdata(struct udevice *dev)
        }
 
        rgb = fdt_subnode_offset(blob, node, "rgb");
-
-       panel_node = fdtdec_lookup_phandle(blob, rgb, "nvidia,panel");
-       if (panel_node < 0) {
-               debug("%s: Cannot find panel information\n", __func__);
+       if (rgb < 0) {
+               debug("%s: Cannot find rgb subnode for '%s' (ret=%d)\n",
+                     __func__, dev->name, rgb);
                return -EINVAL;
        }
 
-       priv->width = fdtdec_get_int(blob, panel_node, "xres", -1);
-       priv->height = fdtdec_get_int(blob, panel_node, "yres", -1);
-       priv->pixel_clock = fdtdec_get_int(blob, panel_node, "clock", 0);
-       if (!priv->pixel_clock || priv->width == -1 || priv->height == -1) {
-               debug("%s: Pixel parameters missing\n", __func__);
-               return -EINVAL;
-       }
-
-       back = fdtdec_get_int(blob, panel_node, "left-margin", -1);
-       front = fdtdec_get_int(blob, panel_node, "right-margin", -1);
-       ref = fdtdec_get_int(blob, panel_node, "hsync-len", -1);
-       if ((back | front | ref) == -1) {
-               debug("%s: Horizontal parameters missing\n", __func__);
-               return -EINVAL;
-       }
-
-       /* Use a ref-to-sync of 1 always, and take this from the front porch */
-       priv->horiz_timing[FDT_LCD_TIMING_REF_TO_SYNC] = 1;
-       priv->horiz_timing[FDT_LCD_TIMING_SYNC_WIDTH] = ref;
-       priv->horiz_timing[FDT_LCD_TIMING_BACK_PORCH] = back;
-       priv->horiz_timing[FDT_LCD_TIMING_FRONT_PORCH] = front -
-               priv->horiz_timing[FDT_LCD_TIMING_REF_TO_SYNC];
-       debug_timing("horiz", priv->horiz_timing);
-
-       back = fdtdec_get_int(blob, panel_node, "upper-margin", -1);
-       front = fdtdec_get_int(blob, panel_node, "lower-margin", -1);
-       ref = fdtdec_get_int(blob, panel_node, "vsync-len", -1);
-       if ((back | front | ref) == -1) {
-               debug("%s: Vertical parameters missing\n", __func__);
-               return -EINVAL;
-       }
-
-       priv->vert_timing[FDT_LCD_TIMING_REF_TO_SYNC] = 1;
-       priv->vert_timing[FDT_LCD_TIMING_SYNC_WIDTH] = ref;
-       priv->vert_timing[FDT_LCD_TIMING_BACK_PORCH] = back;
-       priv->vert_timing[FDT_LCD_TIMING_FRONT_PORCH] = front -
-               priv->vert_timing[FDT_LCD_TIMING_REF_TO_SYNC];
-       debug_timing("vert", priv->vert_timing);
-
-       bpp = fdtdec_get_int(blob, panel_node, "nvidia,bits-per-pixel", -1);
-       bit = ffs(bpp) - 1;
-       if (bpp == (1 << bit))
-               priv->log2_bpp = bit;
-       else
-               priv->log2_bpp = bpp;
-       if (bpp == -1) {
-               debug("%s: Pixel bpp parameters missing\n", __func__);
+       ret = fdtdec_decode_display_timing(blob, rgb, 0, &priv->timing);
+       if (ret) {
+               debug("%s: Cannot read display timing for '%s' (ret=%d)\n",
+                     __func__, dev->name, ret);
                return -EINVAL;
        }
+       timing = &priv->timing;
+       priv->width = timing->hactive.typ;
+       priv->height = timing->vactive.typ;
+       priv->pixel_clock = timing->pixelclock.typ;
+       priv->log2_bpp = VIDEO_BPP16;
 
-       if (fdtdec_parse_phandle_with_args(blob, panel_node, "nvidia,pwm",
-                                          "#pwm-cells", 0, 0, &args)) {
-               debug("%s: Unable to decode PWM\n", __func__);
+       /*
+        * Sadly the panel phandle is in an rgb subnode so we cannot use
+        * uclass_get_device_by_phandle().
+        */
+       panel_node = fdtdec_lookup_phandle(blob, rgb, "nvidia,panel");
+       if (panel_node < 0) {
+               debug("%s: Cannot find panel information\n", __func__);
                return -EINVAL;
        }
-
-       ret = uclass_get_device_by_of_offset(UCLASS_PWM, args.node, &priv->pwm);
+       ret = uclass_get_device_by_of_offset(UCLASS_PANEL, panel_node,
+                                            &priv->panel);
        if (ret) {
-               debug("%s: Unable to find PWM\n", __func__);
-               return -EINVAL;
+               debug("%s: Cannot find panel for '%s' (ret=%d)\n", __func__,
+                     dev->name, ret);
+               return ret;
        }
-       priv->pwm_channel = args.args[0];
-
-       priv->cache_type = fdtdec_get_int(blob, panel_node, "nvidia,cache-type",
-                                         FDT_LCD_CACHE_WRITE_BACK_FLUSH);
-
-       /* These GPIOs are all optional */
-       gpio_request_by_name_nodev(blob, panel_node,
-                                  "nvidia,backlight-enable-gpios", 0,
-                                  &priv->backlight_en, GPIOD_IS_OUT);
-       gpio_request_by_name_nodev(blob, panel_node,
-                                  "nvidia,lvds-shutdown-gpios", 0,
-                                  &priv->lvds_shutdown, GPIOD_IS_OUT);
-       gpio_request_by_name_nodev(blob, panel_node,
-                                  "nvidia,backlight-vdd-gpios", 0,
-                                  &priv->backlight_vdd, GPIOD_IS_OUT);
-       gpio_request_by_name_nodev(blob, panel_node,
-                                  "nvidia,panel-vdd-gpios", 0,
-                                  &priv->panel_vdd, GPIOD_IS_OUT);
-
-       if (fdtdec_get_int_array(blob, panel_node, "nvidia,panel-timings",
-                                priv->panel_timings, FDT_LCD_TIMINGS))
-               return -EINVAL;
 
        return 0;
 }