[PATCH v1 00/12] Tegra DSI/DC code refinement

- Use DM based clock API - Switch to upstream style DSI panel bindings - improve ganged mode support - remove hardcoded Tegra 2 parts
Svyatoslav Ryhel (12): video: tegra20: dc: switch to newer clk API video: tegra20: dc: remove hardcoded Tegra 2 specific parts video: tegra20: dc: remove excessive headers video: tegra20: dc: improve code quality video: tegra20: dsi: check for panels among child nodes video: tegra20: dsi: switch to newer clk API video: tegra20: dsi: move ganged DSI configuration before master panel enable video: tegra20: dsi: make SOL delay calculation mode independent video: tegra20: dsi: calculate packet parameters for video mode video: tegra20: dsi: enable DC only if it is available video: panel: lq101r1sx01: remove unnecessary setup ARM: tegra: endeavoru: adjust panel node
arch/arm/dts/tegra30-htc-endeavoru.dts | 23 ++- .../include/asm/arch-tegra20/clock-tables.h | 2 + drivers/video/sharp-lq101r1sx01.c | 28 ++-- drivers/video/tegra20/tegra-dc.c | 104 ++++++------- drivers/video/tegra20/tegra-dsi.c | 146 ++++++++++++------ 5 files changed, 170 insertions(+), 133 deletions(-)

Switch to struct clk instead of working with plain clock id.
Signed-off-by: Svyatoslav Ryhel clamor95@gmail.com --- drivers/video/tegra20/tegra-dc.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-)
diff --git a/drivers/video/tegra20/tegra-dc.c b/drivers/video/tegra20/tegra-dc.c index d24aa375b39..bd0d8ca7b8f 100644 --- a/drivers/video/tegra20/tegra-dc.c +++ b/drivers/video/tegra20/tegra-dc.c @@ -5,6 +5,7 @@
#include <backlight.h> #include <cpu_func.h> +#include <clk.h> #include <dm.h> #include <fdtdec.h> #include <log.h> @@ -44,7 +45,8 @@ struct tegra_lcd_priv { const struct tegra_dc_soc_info *soc; 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 */ + struct clk *clk; + struct clk *clk_parent; ulong scdiv; /* Clock divider used by disp_clk_ctrl */ bool rotation; /* 180 degree panel turn */ int pipe; /* DC controller: 0 for A, 1 for B */ @@ -301,7 +303,7 @@ static int tegra_display_probe(struct tegra_lcd_priv *priv, void *default_lcd_base) { struct disp_ctl_win window; - unsigned long rate = clock_get_rate(priv->dc_clk[1]); + unsigned long rate = clk_get_rate(priv->clk_parent);
priv->frame_buffer = (u32)default_lcd_base;
@@ -309,12 +311,12 @@ static int tegra_display_probe(struct tegra_lcd_priv *priv, * We halve the rate if DISP1 parent is PLLD, since actual parent * is plld_out0 which is PLLD divided by 2. */ - if (priv->dc_clk[1] == CLOCK_ID_DISPLAY) + if (priv->clk_parent->id == CLOCK_ID_DISPLAY) rate /= 2;
#ifndef CONFIG_TEGRA20 /* PLLD2 obeys same rules as PLLD but it is present only on T30+ */ - if (priv->dc_clk[1] == CLOCK_ID_DISPLAY2) + if (priv->clk_parent->id == CLOCK_ID_DISPLAY2) rate /= 2; #endif
@@ -334,7 +336,7 @@ static int tegra_display_probe(struct tegra_lcd_priv *priv, */ clock_start_periph_pll(PERIPH_ID_HOST1X, CLOCK_ID_CGENERAL, 150 * 1000000); - clock_start_periph_pll(priv->dc_clk[0], priv->dc_clk[1], + clock_start_periph_pll(priv->clk->id, priv->clk_parent->id, rate);
basic_init(&priv->dc->cmd); @@ -383,7 +385,7 @@ static int tegra_lcd_probe(struct udevice *dev) }
ret = tegra_powergate_sequence_power_up(powergate, - priv->dc_clk[0]); + priv->clk->id); if (ret < 0) { log_err("failed to power up DISP gate: %d", ret); return ret; @@ -451,11 +453,18 @@ static int tegra_lcd_of_to_plat(struct udevice *dev)
priv->soc = (struct tegra_dc_soc_info *)dev_get_driver_data(dev);
- ret = clock_decode_pair(dev, priv->dc_clk); - if (ret < 0) { - debug("%s: Cannot decode clocks for '%s' (ret = %d)\n", - __func__, dev->name, ret); - return -EINVAL; + priv->clk = devm_clk_get(dev, NULL); + if (IS_ERR(priv->clk)) { + log_debug("%s: Could not get DC clock: %ld\n", + __func__, PTR_ERR(priv->clk)); + return PTR_ERR(priv->clk); + } + + priv->clk_parent = devm_clk_get(dev, "parent"); + if (IS_ERR(priv->clk_parent)) { + log_debug("%s: Could not get DC clock parent: %ld\n", + __func__, PTR_ERR(priv->clk_parent)); + return PTR_ERR(priv->clk_parent); }
priv->rotation = dev_read_bool(dev, "nvidia,180-rotation");

Since pinmux driver now is available for Tegra 2, these parts may be removed from here and defined either in device tree or in the device board files.
Signed-off-by: Svyatoslav Ryhel clamor95@gmail.com --- .../include/asm/arch-tegra20/clock-tables.h | 2 ++ drivers/video/tegra20/tegra-dc.c | 18 ++---------------- 2 files changed, 4 insertions(+), 16 deletions(-)
diff --git a/arch/arm/include/asm/arch-tegra20/clock-tables.h b/arch/arm/include/asm/arch-tegra20/clock-tables.h index 861b3d5d07c..82685353bd1 100644 --- a/arch/arm/include/asm/arch-tegra20/clock-tables.h +++ b/arch/arm/include/asm/arch-tegra20/clock-tables.h @@ -32,6 +32,7 @@ enum clock_id {
CLOCK_ID_COUNT, /* number of clocks */ CLOCK_ID_NONE = -1, + CLOCK_ID_DISPLAY2 = CLOCK_ID_NONE, /* for compatibility */ };
/* The clocks supported by the hardware */ @@ -159,6 +160,7 @@ enum periph_id {
PERIPH_ID_COUNT, PERIPH_ID_NONE = -1, + PERIPH_ID_DSIB = CLOCK_ID_NONE, /* for compatibility */ };
enum pll_out_id { diff --git a/drivers/video/tegra20/tegra-dc.c b/drivers/video/tegra20/tegra-dc.c index bd0d8ca7b8f..d54279ebda1 100644 --- a/drivers/video/tegra20/tegra-dc.c +++ b/drivers/video/tegra20/tegra-dc.c @@ -311,15 +311,10 @@ static int tegra_display_probe(struct tegra_lcd_priv *priv, * We halve the rate if DISP1 parent is PLLD, since actual parent * is plld_out0 which is PLLD divided by 2. */ - if (priv->clk_parent->id == CLOCK_ID_DISPLAY) + if (priv->clk_parent->id == CLOCK_ID_DISPLAY || + priv->clk_parent->id == CLOCK_ID_DISPLAY2) rate /= 2;
-#ifndef CONFIG_TEGRA20 - /* PLLD2 obeys same rules as PLLD but it is present only on T30+ */ - if (priv->clk_parent->id == CLOCK_ID_DISPLAY2) - rate /= 2; -#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 @@ -366,10 +361,6 @@ static int tegra_lcd_probe(struct udevice *dev) int ret;
/* Initialize the Tegra display controller */ -#ifdef CONFIG_TEGRA20 - funcmux_select(PERIPH_ID_DISP1, FUNCMUX_DEFAULT); -#endif - if (priv->soc->has_pgate) { uint powergate;
@@ -409,11 +400,6 @@ static int tegra_lcd_probe(struct udevice *dev) return -1; }
-#ifdef CONFIG_TEGRA20 - pinmux_set_func(PMUX_PINGRP_GPU, PMUX_FUNC_PWM); - pinmux_tristate_disable(PMUX_PINGRP_GPU); -#endif - ret = panel_enable_backlight(priv->panel); if (ret) { debug("%s: Cannot enable backlight, ret=%d\n", __func__, ret);

Signed-off-by: Svyatoslav Ryhel clamor95@gmail.com --- drivers/video/tegra20/tegra-dc.c | 9 --------- 1 file changed, 9 deletions(-)
diff --git a/drivers/video/tegra20/tegra-dc.c b/drivers/video/tegra20/tegra-dc.c index d54279ebda1..54d60836b66 100644 --- a/drivers/video/tegra20/tegra-dc.c +++ b/drivers/video/tegra20/tegra-dc.c @@ -10,20 +10,11 @@ #include <fdtdec.h> #include <log.h> #include <panel.h> -#include <part.h> -#include <pwm.h> #include <video.h> -#include <asm/cache.h> -#include <asm/global_data.h> #include <asm/system.h> -#include <asm/gpio.h> #include <asm/io.h> - #include <asm/arch/clock.h> -#include <asm/arch/funcmux.h> -#include <asm/arch/pinmux.h> #include <asm/arch/powergate.h> -#include <asm/arch/pwm.h>
#include "tegra-dc.h"

Mainly unification and improving of readability.
Signed-off-by: Svyatoslav Ryhel clamor95@gmail.com --- drivers/video/tegra20/tegra-dc.c | 50 +++++++++++++++++--------------- 1 file changed, 27 insertions(+), 23 deletions(-)
diff --git a/drivers/video/tegra20/tegra-dc.c b/drivers/video/tegra20/tegra-dc.c index 54d60836b66..e366df9ab51 100644 --- a/drivers/video/tegra20/tegra-dc.c +++ b/drivers/video/tegra20/tegra-dc.c @@ -137,10 +137,9 @@ static int update_display_mode(struct tegra_lcd_priv *priv) val |= DATA_ALIGNMENT_MSB << DATA_ALIGNMENT_SHIFT; val |= DATA_ORDER_RED_BLUE << DATA_ORDER_SHIFT; writel(val, &disp->disp_interface_ctrl); - }
- if (priv->soc->has_rgb) writel(0x00010001, &disp->shift_clk_opt); + }
val = PIXEL_CLK_DIVIDER_PCD1 << PIXEL_CLK_DIVIDER_SHIFT; val |= priv->scdiv << SHIFT_CLK_DIVIDER_SHIFT; @@ -260,7 +259,9 @@ static int setup_window(struct tegra_lcd_priv *priv, win->out_h = priv->height; win->phys_addr = priv->frame_buffer; win->stride = priv->width * (1 << priv->log2_bpp) / 8; - debug("%s: depth = %d\n", __func__, priv->log2_bpp); + + log_debug("%s: depth = %d\n", __func__, priv->log2_bpp); + switch (priv->log2_bpp) { case VIDEO_BPP32: win->fmt = COLOR_DEPTH_R8G8B8A8; @@ -272,7 +273,7 @@ static int setup_window(struct tegra_lcd_priv *priv, break;
default: - debug("Unsupported LCD bit depth"); + log_debug("Unsupported LCD bit depth\n"); return -1; }
@@ -295,6 +296,7 @@ static int tegra_display_probe(struct tegra_lcd_priv *priv, { struct disp_ctl_win window; unsigned long rate = clk_get_rate(priv->clk_parent); + int ret;
priv->frame_buffer = (u32)default_lcd_base;
@@ -315,7 +317,7 @@ static int tegra_display_probe(struct tegra_lcd_priv *priv, 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); + log_debug("Display clock %lu, divider %lu\n", rate, priv->scdiv);
/* * HOST1X is init by default at 150MHz with PLLC as parent @@ -336,8 +338,9 @@ static int tegra_display_probe(struct tegra_lcd_priv *priv, if (priv->pixel_clock) update_display_mode(priv);
- if (setup_window(priv, &window)) - return -1; + ret = setup_window(priv, &window); + if (ret) + return ret;
update_window(priv, &window);
@@ -362,14 +365,14 @@ static int tegra_lcd_probe(struct udevice *dev)
ret = tegra_powergate_power_off(powergate); if (ret < 0) { - log_err("failed to power off DISP gate: %d", ret); + log_debug("failed to power off DISP gate: %d", ret); return ret; }
ret = tegra_powergate_sequence_power_up(powergate, priv->clk->id); if (ret < 0) { - log_err("failed to power up DISP gate: %d", ret); + log_debug("failed to power up DISP gate: %d", ret); return ret; } } @@ -386,14 +389,15 @@ static int tegra_lcd_probe(struct udevice *dev) memset((u8 *)plat->base, 0, plat->size); flush_dcache_all();
- if (tegra_display_probe(priv, (void *)plat->base)) { - debug("%s: Failed to probe display driver\n", __func__); - return -1; + ret = tegra_display_probe(priv, (void *)plat->base); + if (ret) { + log_debug("%s: Failed to probe display driver\n", __func__); + return ret; }
ret = panel_enable_backlight(priv->panel); if (ret) { - debug("%s: Cannot enable backlight, ret=%d\n", __func__, ret); + log_debug("%s: Cannot enable backlight, ret=%d\n", __func__, ret); return ret; }
@@ -406,8 +410,8 @@ static int tegra_lcd_probe(struct udevice *dev) uc_priv->xsize = priv->width; uc_priv->ysize = priv->height; uc_priv->bpix = priv->log2_bpp; - debug("LCD frame buffer at %08x, size %x\n", priv->frame_buffer, - plat->size); + log_debug("LCD frame buffer at %08x, size %x\n", priv->frame_buffer, + plat->size);
return panel_set_backlight(priv->panel, BACKLIGHT_DEFAULT); } @@ -424,7 +428,7 @@ static int tegra_lcd_of_to_plat(struct udevice *dev)
priv->dc = (struct dc_ctlr *)dev_read_addr_ptr(dev); if (!priv->dc) { - debug("%s: No display controller address\n", __func__); + log_debug("%s: No display controller address\n", __func__); return -EINVAL; }
@@ -449,8 +453,8 @@ static int tegra_lcd_of_to_plat(struct udevice *dev)
rgb = fdt_subnode_offset(blob, node, "rgb"); if (rgb < 0) { - debug("%s: Cannot find rgb subnode for '%s' (ret=%d)\n", - __func__, dev->name, rgb); + log_debug("%s: Cannot find rgb subnode for '%s' (ret=%d)\n", + __func__, dev->name, rgb); return -EINVAL; }
@@ -460,15 +464,15 @@ static int tegra_lcd_of_to_plat(struct udevice *dev) */ panel_node = fdtdec_lookup_phandle(blob, rgb, "nvidia,panel"); if (panel_node < 0) { - debug("%s: Cannot find panel information\n", __func__); + log_debug("%s: Cannot find panel information\n", __func__); return -EINVAL; }
ret = uclass_get_device_by_of_offset(UCLASS_PANEL, panel_node, &priv->panel); if (ret) { - debug("%s: Cannot find panel for '%s' (ret=%d)\n", __func__, - dev->name, ret); + log_debug("%s: Cannot find panel for '%s' (ret=%d)\n", __func__, + dev->name, ret); return ret; }
@@ -486,8 +490,8 @@ static int tegra_lcd_of_to_plat(struct udevice *dev) if (ret) { 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); + log_debug("%s: Cannot read display timing for '%s' (ret=%d)\n", + __func__, dev->name, ret); return -EINVAL; } }

Switch to Linux-like approach of DSI panel binding as a DSI controllers child node.
Signed-off-by: Svyatoslav Ryhel clamor95@gmail.com --- drivers/video/tegra20/tegra-dsi.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-)
diff --git a/drivers/video/tegra20/tegra-dsi.c b/drivers/video/tegra20/tegra-dsi.c index 6327266dd22..53db5a25d40 100644 --- a/drivers/video/tegra20/tegra-dsi.c +++ b/drivers/video/tegra20/tegra-dsi.c @@ -973,10 +973,22 @@ static int tegra_dsi_bridge_probe(struct udevice *dev) debug("%s: Cannot get avdd-dsi-csi-supply: error %d\n", __func__, ret);
- ret = uclass_get_device_by_phandle(UCLASS_PANEL, dev, - "panel", &priv->panel); + /* Check all DSI children */ + device_foreach_child(priv->panel, dev) { + if (device_get_uclass_id(priv->panel) == UCLASS_PANEL) + break; + } + + /* if loop exits without panel device return error */ + if (device_get_uclass_id(priv->panel) != UCLASS_PANEL) { + log_debug("%s: panel not found, ret %d\n", __func__, ret); + return -EINVAL; + } + + ret = uclass_get_device_by_ofnode(UCLASS_PANEL, dev_ofnode(priv->panel), + &priv->panel); if (ret) { - printf("%s: Cannot get panel: error %d\n", __func__, ret); + log_debug("%s: Cannot get panel: error %d\n", __func__, ret); return log_ret(ret); }
@@ -1036,6 +1048,7 @@ U_BOOT_DRIVER(tegra_dsi) = { .id = UCLASS_PANEL, .of_match = tegra_dsi_bridge_ids, .ops = &tegra_dsi_bridge_ops, + .bind = dm_scan_fdt_dev, .probe = tegra_dsi_bridge_probe, .plat_auto = sizeof(struct tegra_dc_plat), .priv_auto = sizeof(struct tegra_dsi_priv),

Switch to struct clk instead of working with plain clock id.
Signed-off-by: Svyatoslav Ryhel clamor95@gmail.com --- drivers/video/tegra20/tegra-dsi.c | 49 ++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 11 deletions(-)
diff --git a/drivers/video/tegra20/tegra-dsi.c b/drivers/video/tegra20/tegra-dsi.c index 53db5a25d40..97a30402902 100644 --- a/drivers/video/tegra20/tegra-dsi.c +++ b/drivers/video/tegra20/tegra-dsi.c @@ -5,6 +5,7 @@ */
#include <dm.h> +#include <clk.h> #include <log.h> #include <misc.h> #include <mipi_display.h> @@ -46,7 +47,9 @@ struct tegra_dsi_priv {
enum tegra_dsi_format format;
- int dsi_clk; + struct clk *clk; + struct clk *clk_parent; + int video_fifo_depth; int host_fifo_depth;
@@ -862,12 +865,26 @@ static void tegra_dsi_init_clocks(struct udevice *dev) unsigned int mul, div; unsigned long bclk, plld;
- if (!priv->slave) { + /* Switch parents of DSI clocks in case of not standard parent */ + if (priv->clk->id == PERIPH_ID_DSI && + priv->clk_parent->id == CLOCK_ID_DISPLAY2) { + /* Change DSIA clock parent to PLLD2 */ + struct clk_rst_ctlr *clkrst = + (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; + + /* DSIA_CLK_SRC */ + setbits_le32(&clkrst->crc_pll[CLOCK_ID_DISPLAY].pll_base, + BIT(25)); + } + + if (priv->clk->id == PERIPH_ID_DSIB && + priv->clk_parent->id == CLOCK_ID_DISPLAY) { /* Change DSIB clock parent to match DSIA */ struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
- clrbits_le32(&clkrst->plld2.pll_base, BIT(25)); /* DSIB_CLK_SRC */ + /* DSIB_CLK_SRC */ + clrbits_le32(&clkrst->plld2.pll_base, BIT(25)); }
tegra_dsi_get_muldiv(device->format, &mul, &div); @@ -893,16 +910,16 @@ static void tegra_dsi_init_clocks(struct udevice *dev) switch (clock_get_osc_freq()) { case CLOCK_OSC_FREQ_12_0: /* OSC is 12Mhz */ case CLOCK_OSC_FREQ_48_0: /* OSC is 48Mhz */ - clock_set_rate(CLOCK_ID_DISPLAY, plld, 12, 0, 8); + clock_set_rate(priv->clk_parent->id, plld, 12, 0, 8); break;
case CLOCK_OSC_FREQ_26_0: /* OSC is 26Mhz */ - clock_set_rate(CLOCK_ID_DISPLAY, plld, 26, 0, 8); + clock_set_rate(priv->clk_parent->id, plld, 26, 0, 8); break;
case CLOCK_OSC_FREQ_13_0: /* OSC is 13Mhz */ case CLOCK_OSC_FREQ_16_8: /* OSC is 16.8Mhz */ - clock_set_rate(CLOCK_ID_DISPLAY, plld, 13, 0, 8); + clock_set_rate(priv->clk_parent->id, plld, 13, 0, 8); break;
case CLOCK_OSC_FREQ_19_2: @@ -914,11 +931,7 @@ static void tegra_dsi_init_clocks(struct udevice *dev) break; }
- priv->dsi_clk = clock_decode_periph_id(dev); - - clock_enable(priv->dsi_clk); - udelay(2); - reset_set_enable(priv->dsi_clk, 0); + clk_enable(priv->clk); }
static int tegra_dsi_ganged_probe(struct udevice *dev) @@ -955,6 +968,20 @@ static int tegra_dsi_bridge_probe(struct udevice *dev) return -EINVAL; }
+ priv->clk = devm_clk_get(dev, NULL); + if (IS_ERR(priv->clk)) { + log_debug("%s: Could not get DSI clock: %ld\n", + __func__, PTR_ERR(priv->clk)); + return PTR_ERR(priv->clk); + } + + priv->clk_parent = devm_clk_get(dev, "parent"); + if (IS_ERR(priv->clk_parent)) { + log_debug("%s: Could not get DSI clock parent: %ld\n", + __func__, PTR_ERR(priv->clk_parent)); + return PTR_ERR(priv->clk_parent); + } + priv->video_fifo_depth = 1920; priv->host_fifo_depth = 64;

Master panel driver holds commands for both itself and link, so master panel should be requested after both master DSI and slave DSI are configured and ready.
Signed-off-by: Svyatoslav Ryhel clamor95@gmail.com --- drivers/video/tegra20/tegra-dsi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/video/tegra20/tegra-dsi.c b/drivers/video/tegra20/tegra-dsi.c index 97a30402902..97895f37739 100644 --- a/drivers/video/tegra20/tegra-dsi.c +++ b/drivers/video/tegra20/tegra-dsi.c @@ -819,6 +819,9 @@ static int tegra_dsi_encoder_enable(struct udevice *dev) tegra_dsi_set_phy_timing(&priv->dsi->ptiming, period * 8, &priv->dphy_timing);
+ if (priv->slave) + tegra_dsi_encoder_enable(priv->slave); + /* Perform panel HW setup */ ret = panel_enable_backlight(priv->panel); if (ret) @@ -833,9 +836,6 @@ static int tegra_dsi_encoder_enable(struct udevice *dev) value |= DSI_POWER_CONTROL_ENABLE; writel(value, &misc->dsi_pwr_ctrl);
- if (priv->slave) - tegra_dsi_encoder_enable(priv->slave); - return 0; }

Move SOL delay calculation outside of video mode conditions.
Signed-off-by: Svyatoslav Ryhel clamor95@gmail.com --- drivers/video/tegra20/tegra-dsi.c | 47 +++++++++++++++---------------- 1 file changed, 22 insertions(+), 25 deletions(-)
diff --git a/drivers/video/tegra20/tegra-dsi.c b/drivers/video/tegra20/tegra-dsi.c index 97895f37739..b65d2118de9 100644 --- a/drivers/video/tegra20/tegra-dsi.c +++ b/drivers/video/tegra20/tegra-dsi.c @@ -698,9 +698,6 @@ static void tegra_dsi_configure(struct udevice *dev, writel(hact << 16 | hbp, &len->dsi_pkt_len_2_3); writel(hfp, &len->dsi_pkt_len_4_5); writel(0x0f0f << 16, &len->dsi_pkt_len_6_7); - - /* set SOL delay (for non-burst mode only) */ - writel(8 * mul / div, &misc->dsi_sol_delay); } else { if (priv->master || priv->slave) { /* @@ -720,31 +717,31 @@ static void tegra_dsi_configure(struct udevice *dev, value = MIPI_DCS_WRITE_MEMORY_START << 8 | MIPI_DCS_WRITE_MEMORY_CONTINUE; writel(value, &len->dsi_dcs_cmds); + }
- /* set SOL delay */ - if (priv->master || priv->slave) { - unsigned long delay, bclk, bclk_ganged; - unsigned int lanes = device->lanes; - unsigned long htotal = timing->hactive.typ + timing->hfront_porch.typ + - timing->hback_porch.typ + timing->hsync_len.typ; - - /* SOL to valid, valid to FIFO and FIFO write delay */ - delay = 4 + 4 + 2; - delay = DIV_ROUND_UP(delay * mul, div * lanes); - /* FIFO read delay */ - delay = delay + 6; - - bclk = DIV_ROUND_UP(htotal * mul, div * lanes); - bclk_ganged = DIV_ROUND_UP(bclk * lanes / 2, lanes); - value = bclk - bclk_ganged + delay + 20; - } else { - /* TODO: revisit for non-ganged mode */ - value = 8 * mul / div; - } - - writel(value, &misc->dsi_sol_delay); + /* set SOL delay */ + if (priv->master || priv->slave) { + unsigned long delay, bclk, bclk_ganged; + unsigned int lanes = device->lanes; + unsigned long htotal = timing->hactive.typ + timing->hfront_porch.typ + + timing->hback_porch.typ + timing->hsync_len.typ; + + /* SOL to valid, valid to FIFO and FIFO write delay */ + delay = 4 + 4 + 2; + delay = DIV_ROUND_UP(delay * mul, div * lanes); + /* FIFO read delay */ + delay = delay + 6; + + bclk = DIV_ROUND_UP(htotal * mul, div * lanes); + bclk_ganged = DIV_ROUND_UP(bclk * lanes / 2, lanes); + value = bclk - bclk_ganged + delay + 20; + } else { + /* set SOL delay (for non-burst mode only) */ + value = 8 * mul / div; }
+ writel(value, &misc->dsi_sol_delay); + if (priv->slave) { /* * TODO: Support modes other than symmetrical left-right

Calculate packet parameters for video mode same way it is done or command mode, by halving timings plugged into equations.
Signed-off-by: Svyatoslav Ryhel clamor95@gmail.com --- drivers/video/tegra20/tegra-dsi.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/drivers/video/tegra20/tegra-dsi.c b/drivers/video/tegra20/tegra-dsi.c index b65d2118de9..6cf6cffc0e4 100644 --- a/drivers/video/tegra20/tegra-dsi.c +++ b/drivers/video/tegra20/tegra-dsi.c @@ -683,12 +683,19 @@ static void tegra_dsi_configure(struct udevice *dev, /* horizontal back porch */ hbp = timing->hback_porch.typ * mul / div;
- if ((mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) == 0) - hbp += hsw; - /* horizontal front porch */ hfp = timing->hfront_porch.typ * mul / div;
+ if (priv->master || priv->slave) { + hact /= 2; + hsw /= 2; + hbp /= 2; + hfp /= 2; + } + + if ((mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) == 0) + hbp += hsw; + /* subtract packet overhead */ hsw -= 10; hbp -= 14;

Perform DC configuration for peripheral device type only if DC registers are available. This is handy, for example, when DSI ganged mode is used and slave DSI has no DC associated with it.
Signed-off-by: Svyatoslav Ryhel clamor95@gmail.com --- drivers/video/tegra20/tegra-dsi.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/drivers/video/tegra20/tegra-dsi.c b/drivers/video/tegra20/tegra-dsi.c index 6cf6cffc0e4..0b395dbf9fa 100644 --- a/drivers/video/tegra20/tegra-dsi.c +++ b/drivers/video/tegra20/tegra-dsi.c @@ -66,12 +66,14 @@ static void tegra_dc_enable_controller(struct udevice *dev) struct dc_ctlr *dc = dc_plat->dc; u32 value;
- value = readl(&dc->disp.disp_win_opt); - value |= DSI_ENABLE; - writel(value, &dc->disp.disp_win_opt); + if (dc) { + value = readl(&dc->disp.disp_win_opt); + value |= DSI_ENABLE; + writel(value, &dc->disp.disp_win_opt);
- writel(GENERAL_UPDATE, &dc->cmd.state_ctrl); - writel(GENERAL_ACT_REQ, &dc->cmd.state_ctrl); + writel(GENERAL_UPDATE, &dc->cmd.state_ctrl); + writel(GENERAL_ACT_REQ, &dc->cmd.state_ctrl); + } }
static const char * const error_report[16] = {

Left-right split is enabled only by sending 0x1000 to MIPI_DCS_SET_COLUMN_ADDRESS (0x2a) and does not require any other manipulations. sharp_setup_symmetrical_split function is left as a reference for possible even-odd split implementation or video mode support where commands have to be sent to both links.
Signed-off-by: Svyatoslav Ryhel clamor95@gmail.com --- drivers/video/sharp-lq101r1sx01.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-)
diff --git a/drivers/video/sharp-lq101r1sx01.c b/drivers/video/sharp-lq101r1sx01.c index 5d8453fd796..504122abda6 100644 --- a/drivers/video/sharp-lq101r1sx01.c +++ b/drivers/video/sharp-lq101r1sx01.c @@ -57,9 +57,10 @@ static int sharp_lq101r1sx01_write(struct mipi_dsi_device *dsi, return 0; }
-static int sharp_setup_symmetrical_split(struct mipi_dsi_device *left, - struct mipi_dsi_device *right, - struct display_timing *timing) +static int __maybe_unused +sharp_setup_symmetrical_split(struct mipi_dsi_device *left, + struct mipi_dsi_device *right, + struct display_timing *timing) { int ret;
@@ -104,9 +105,7 @@ static int sharp_lq101r1sx01_enable_backlight(struct udevice *dev) return 0;
struct mipi_dsi_panel_plat *plat = dev_get_plat(dev); - struct mipi_dsi_panel_plat *plat_sec = dev_get_plat(priv->panel_sec); struct mipi_dsi_device *link1 = plat->device; - struct mipi_dsi_device *link2 = plat_sec->device; int ret;
ret = mipi_dsi_dcs_exit_sleep_mode(link1); @@ -142,16 +141,17 @@ static int sharp_lq101r1sx01_enable_backlight(struct udevice *dev) /* * TODO: The device supports both left-right and even-odd split * configurations, but this driver currently supports only the left- - * right split. To support a different mode a mechanism needs to be - * put in place to communicate the configuration back to the DSI host - * controller. + * right split in command mode. To support a different mode a + * mechanism needs to be put in place to communicate the + * configuration back to the DSI host controller. + * + * Left-right split is enabled only by sending 0x1000 to + * MIPI_DCS_SET_COLUMN_ADDRESS (0x2a) and does not require any + * other manipulations. sharp_setup_symmetrical_split function is + * left as a reference for possible even-odd split implementation + * or video mode support where commands have to be sent to both + * links. */ - ret = sharp_setup_symmetrical_split(link1, link2, &default_timing); - if (ret < 0) { - log_debug("%s: failed to set up symmetrical split: %d\n", - __func__, ret); - return ret; - }
ret = mipi_dsi_dcs_set_display_on(link1); if (ret < 0) {

Bind panel in Linux-style, as DSI child.
Signed-off-by: Svyatoslav Ryhel clamor95@gmail.com --- arch/arm/dts/tegra30-htc-endeavoru.dts | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-)
diff --git a/arch/arm/dts/tegra30-htc-endeavoru.dts b/arch/arm/dts/tegra30-htc-endeavoru.dts index dbff795bd89..8a0ba3c07cc 100644 --- a/arch/arm/dts/tegra30-htc-endeavoru.dts +++ b/arch/arm/dts/tegra30-htc-endeavoru.dts @@ -48,7 +48,17 @@
avdd-dsi-csi-supply = <&avdd_dsi_csi>;
- panel = <&panel>; + panel@0 { + compatible = "htc,edge-panel"; + reg = <0>; + + reset-gpios = <&gpio TEGRA_GPIO(N, 6) GPIO_ACTIVE_LOW>; + + vdd-supply = <&vdd_3v3_panel>; + vddio-supply = <&vdd_1v8_panel>; + + backlight = <&backlight>; + }; }; };
@@ -1292,17 +1302,6 @@ }; };
- panel: panel { - compatible = "htc,edge-panel"; - - reset-gpios = <&gpio TEGRA_GPIO(N, 6) GPIO_ACTIVE_LOW>; - - vdd-supply = <&vdd_3v3_panel>; - vddio-supply = <&vdd_1v8_panel>; - - backlight = <&backlight>; - }; - vcore_emmc: regulator-emmc { compatible = "regulator-fixed"; regulator-name = "vdd_2v85_sdmmc";
participants (1)
-
Svyatoslav Ryhel