diff options
-rw-r--r-- | drivers/video/tegra20/tegra-dc.c | 34 | ||||
-rw-r--r-- | drivers/video/tegra20/tegra-dc.h | 1 | ||||
-rw-r--r-- | drivers/video/tegra20/tegra-dsi.c | 14 |
3 files changed, 36 insertions, 13 deletions
diff --git a/drivers/video/tegra20/tegra-dc.c b/drivers/video/tegra20/tegra-dc.c index cc4b5b70015..2c9017807f2 100644 --- a/drivers/video/tegra20/tegra-dc.c +++ b/drivers/video/tegra20/tegra-dc.c @@ -46,6 +46,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 */ + ulong scdiv; /* Clock divider used by disp_clk_ctrl */ bool rotation; /* 180 degree panel turn */ bool pipe; /* DC controller: 0 for A, 1 for B */ }; @@ -124,8 +125,6 @@ static int update_display_mode(struct tegra_lcd_priv *priv) struct dc_disp_reg *disp = &priv->dc->disp; struct display_timing *dt = &priv->timing; unsigned long val; - unsigned long rate; - unsigned long div; writel(0x0, &disp->disp_timing_opt); @@ -148,21 +147,11 @@ static int update_display_mode(struct tegra_lcd_priv *priv) writel(val, &disp->disp_interface_ctrl); } - /* - * The pixel clock divider is in 7.1 format (where the bottom bit - * represents 0.5). Here we calculate the divider needed to get from - * the display clock (typically 600MHz) to the pixel clock. We round - * up or down as requried. - */ - rate = clock_get_periph_rate(priv->dc_clk[0], priv->dc_clk[1]); - div = ((rate * 2 + priv->pixel_clock / 2) / priv->pixel_clock) - 2; - debug("Display clock %lu, divider %lu\n", rate, div); - if (priv->soc->has_rgb) writel(0x00010001, &disp->shift_clk_opt); val = PIXEL_CLK_DIVIDER_PCD1 << PIXEL_CLK_DIVIDER_SHIFT; - val |= div << SHIFT_CLK_DIVIDER_SHIFT; + val |= priv->scdiv << SHIFT_CLK_DIVIDER_SHIFT; writel(val, &disp->disp_clk_ctrl); return 0; @@ -313,6 +302,17 @@ static int tegra_display_probe(struct tegra_lcd_priv *priv, #endif /* + * The pixel clock divider is in 7.1 format (where the bottom bit + * represents 0.5). Here we calculate the divider needed to get from + * the display clock (typically 600MHz) to the pixel clock. We round + * up or down as required. + */ + if (!priv->scdiv) + priv->scdiv = ((rate * 2 + priv->pixel_clock / 2) + / priv->pixel_clock) - 2; + debug("Display clock %lu, divider %lu\n", rate, priv->scdiv); + + /* * HOST1X is init by default at 150MHz with PLLC as parent */ clock_start_periph_pll(PERIPH_ID_HOST1X, CLOCK_ID_CGENERAL, @@ -373,6 +373,14 @@ static int tegra_lcd_probe(struct udevice *dev) } } + /* Get shift clock divider from Tegra DSI if used */ + if (!strcmp(priv->panel->name, TEGRA_DSI_A) || + !strcmp(priv->panel->name, TEGRA_DSI_B)) { + struct tegra_dc_plat *dc_plat = dev_get_plat(priv->panel); + + priv->scdiv = dc_plat->scdiv; + } + if (tegra_display_probe(priv, (void *)plat->base)) { debug("%s: Failed to probe display driver\n", __func__); return -1; diff --git a/drivers/video/tegra20/tegra-dc.h b/drivers/video/tegra20/tegra-dc.h index 75fc0fa4de4..05042dab1c6 100644 --- a/drivers/video/tegra20/tegra-dc.h +++ b/drivers/video/tegra20/tegra-dc.h @@ -23,6 +23,7 @@ struct tegra_dc_plat { struct udevice *dev; /* Display controller device */ struct dc_ctlr *dc; /* Display controller regmap */ bool pipe; /* DC number: 0 for A, 1 for B */ + ulong scdiv; /* Shift clock divider */ }; /* This holds information about a window which can be displayed */ diff --git a/drivers/video/tegra20/tegra-dsi.c b/drivers/video/tegra20/tegra-dsi.c index 72b91ed26bf..de225ed3766 100644 --- a/drivers/video/tegra20/tegra-dsi.c +++ b/drivers/video/tegra20/tegra-dsi.c @@ -743,6 +743,7 @@ static int tegra_dsi_panel_timings(struct udevice *dev, static void tegra_dsi_init_clocks(struct udevice *dev) { struct tegra_dsi_priv *priv = dev_get_priv(dev); + struct tegra_dc_plat *dc_plat = dev_get_plat(dev); struct mipi_dsi_device *device = &priv->device; unsigned int mul, div; unsigned long bclk, plld; @@ -754,6 +755,19 @@ static void tegra_dsi_init_clocks(struct udevice *dev) plld = DIV_ROUND_UP(bclk * 8, USEC_PER_SEC); + dc_plat->scdiv = ((plld * USEC_PER_SEC + + priv->timing.pixelclock.typ / 2) / + priv->timing.pixelclock.typ) - 2; + + /* + * BUG: If DISP1 is a PLLD/D2 child, it cannot go over 370MHz. The + * cause of this is not quite clear. This can be overcomed by + * halving the PLLD/D2 if the target rate is > 800MHz. This way + * DISP1 and DSI clocks will be equal. + */ + if (plld > 800) + plld /= 2; + switch (clock_get_osc_freq()) { case CLOCK_OSC_FREQ_12_0: /* OSC is 12Mhz */ case CLOCK_OSC_FREQ_48_0: /* OSC is 48Mhz */ |