]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/commitdiff
video: tegra: dsi: add new ganged mode parameters
authorDaniel Solomon <daniels@nvidia.com>
Wed, 25 Feb 2015 22:01:03 +0000 (14:01 -0800)
committerMitch Luban <mluban@nvidia.com>
Tue, 10 Mar 2015 19:54:23 +0000 (12:54 -0700)
* Add support for left/right ganged mode with overlap
  region
* Add ability to swap DSIA and DSIB in ganged mode, for
  panels where DSIB connects to the master DSI controller IC.
* Add ability to write DSI host and panel commands to both
  links instead of just to the master link

Bug 1614907

Change-Id: Ib7ccfe6a1b61317a768568c74893d39b3ebf3cf8
Signed-off-by: Daniel Solomon <daniels@nvidia.com>
Reviewed-on: http://git-master/r/711289
Reviewed-by: Mitch Luban <mluban@nvidia.com>
Tested-by: Mitch Luban <mluban@nvidia.com>
Documentation/devicetree/bindings/video/nvidia,tegra114-dsi.txt
Documentation/devicetree/bindings/video/nvidia,tegra124-dsi.txt
Documentation/devicetree/bindings/video/nvidia,tegra210-dsi.txt
arch/arm/mach-tegra/include/mach/dc.h
drivers/video/tegra/dc/dsi.c
drivers/video/tegra/dc/of_dc.c
include/dt-bindings/display/tegra-panel.h

index fc8ac2aa4c9c5ff96b734d6394ad2a61992e2b81..fccb403c541964496b41d03912b4e6d659d47a4f 100644 (file)
@@ -68,7 +68,7 @@ NVIDIA TEGRA114 Display Serial Interface
  - nvidia,dsi-pkt-seq: custom packet sequence since some panels need non standard packet sequence.
  - nvidia,dsi-te-gpio: specifies a GPIO used for dsi panel TE signal.
  - nvidia,nvidia,dsi-ganged-type: specifies dsi ganged type. 1 for TEGRA_DSI_GANGED_SYMMETRIC_LEFT_RIGHT,
-   2 for TEGRA_DSI_GANGED_SYMMETRIC_EVEN_ODD.
+   2 for TEGRA_DSI_GANGED_SYMMETRIC_EVEN_ODD, 3 for TEGRA_DSI_GANGED_SYMMETRIC_LEFT_RIGHT_OVERLAP
  - nvidia,dsi-phy-hsdexit: dsi phy timing, t_hsdexit_ns.
  - nvidia,dsi-phy-hstrail: dsi phy timing, t_hstrail_ns.
  - nvidia,dsi-phy-datzero: dsi phy timing, t_datzero_ns.
@@ -83,6 +83,11 @@ NVIDIA TEGRA114 Display Serial Interface
  - nvidia,dsi-phy-taget: dsi phy timing, t_taget_ns.
  - nvidia,dsi-phy-tasure: dsi phy timing, t_tasure_ns.
  - nvidia,dsi-phy-tago: dsi phy timing, t_tago_ns.
+ - nvidia,dsi-ganged-overlap: ganged symmetric left/right overlap mode overlap region, in pixels
+ - nvidia,dsi-ganged-swap-links: swap DSIA and DSIB in ganged mode (for ganged panels where DSIB connects
+   to master DSI controller IC), 1 for true and 0 for false.
+ - nvidia,dsi-ganged-write-to-all-links: write DSI host and panel commands to both links, with exception of
+   setting up per-link ganged mode start address and range, 1 for true and 0 for false.
 
  - Child nodes represent node of modes, output settings,
    smart dimmer settings, color management unit settings.
index d551d3d2fd3a613dc6ec8e012d89d67696775e62..006e7423bba879106f8cf2d134cdea69df3ce453 100644 (file)
@@ -68,7 +68,7 @@ NVIDIA TEGRA124 Display Serial Interface
  - nvidia,dsi-pkt-seq: custom packet sequence since some panels need non standard packet sequence.
  - nvidia,dsi-te-gpio: specifies a GPIO used for dsi panel TE signal.
  - nvidia,nvidia,dsi-ganged-type: specifies dsi ganged type. 1 for TEGRA_DSI_GANGED_SYMMETRIC_LEFT_RIGHT,
-   2 for TEGRA_DSI_GANGED_SYMMETRIC_EVEN_ODD.
+   2 for TEGRA_DSI_GANGED_SYMMETRIC_EVEN_ODD, 3 for TEGRA_DSI_GANGED_SYMMETRIC_LEFT_RIGHT_OVERLAP
  - nvidia,dsi-phy-hsdexit: dsi phy timing, t_hsdexit_ns.
  - nvidia,dsi-phy-hstrail: dsi phy timing, t_hstrail_ns.
  - nvidia,dsi-phy-datzero: dsi phy timing, t_datzero_ns.
@@ -83,6 +83,11 @@ NVIDIA TEGRA124 Display Serial Interface
  - nvidia,dsi-phy-taget: dsi phy timing, t_taget_ns.
  - nvidia,dsi-phy-tasure: dsi phy timing, t_tasure_ns.
  - nvidia,dsi-phy-tago: dsi phy timing, t_tago_ns.
+ - nvidia,dsi-ganged-overlap: ganged symmetric left/right overlap mode overlap region, in pixels
+ - nvidia,dsi-ganged-swap-links: swap DSIA and DSIB in ganged mode (for ganged panels where DSIB connects
+   to master DSI controller IC), 1 for true and 0 for false.
+ - nvidia,dsi-ganged-write-to-all-links: write DSI host and panel commands to both links, with exception of
+   setting up per-link ganged mode start address and range, 1 for true and 0 for false.
 
  - Child nodes represent node of modes, output settings,
    smart dimmer settings, color management unit settings.
index c32a89bfa39b03a07d15b7697ea8b00bdf4b3676..df649a0566b77ad64cfdf903241be0e99dc65a01 100644 (file)
@@ -68,7 +68,7 @@ NVIDIA TEGRA210 Display Serial Interface
  - nvidia,dsi-pkt-seq: custom packet sequence since some panels need non standard packet sequence.
  - nvidia,dsi-te-gpio: specifies a GPIO used for dsi panel TE signal.
  - nvidia,nvidia,dsi-ganged-type: specifies dsi ganged type. 1 for TEGRA_DSI_GANGED_SYMMETRIC_LEFT_RIGHT,
-   2 for TEGRA_DSI_GANGED_SYMMETRIC_EVEN_ODD.
+   2 for TEGRA_DSI_GANGED_SYMMETRIC_EVEN_ODD, 3 for TEGRA_DSI_GANGED_SYMMETRIC_LEFT_RIGHT_OVERLAP
  - nvidia,dsi-phy-hsdexit: dsi phy timing, t_hsdexit_ns.
  - nvidia,dsi-phy-hstrail: dsi phy timing, t_hstrail_ns.
  - nvidia,dsi-phy-datzero: dsi phy timing, t_datzero_ns.
@@ -83,6 +83,11 @@ NVIDIA TEGRA210 Display Serial Interface
  - nvidia,dsi-phy-taget: dsi phy timing, t_taget_ns.
  - nvidia,dsi-phy-tasure: dsi phy timing, t_tasure_ns.
  - nvidia,dsi-phy-tago: dsi phy timing, t_tago_ns.
+ - nvidia,dsi-ganged-overlap: ganged symmetric left/right overlap mode overlap region, in pixels
+ - nvidia,dsi-ganged-swap-links: swap DSIA and DSIB in ganged mode (for ganged panels where DSIB connects
+   to master DSI controller IC), 1 for true and 0 for false.
+ - nvidia,dsi-ganged-write-to-all-links: write DSI host and panel commands to both links, with exception of
+   setting up per-link ganged mode start address and range, 1 for true and 0 for false.
 
  - Child nodes represent node of modes, output settings,
    smart dimmer settings, color management unit settings.
index d56d4bd7f22e1335b23748fe9038a36a53691782..6e480f5c7e4d4e26a6b5ea0fc311488b09279ef8 100644 (file)
@@ -106,6 +106,7 @@ enum {
 enum {
        TEGRA_DSI_GANGED_SYMMETRIC_LEFT_RIGHT = 1,
        TEGRA_DSI_GANGED_SYMMETRIC_EVEN_ODD = 2,
+       TEGRA_DSI_GANGED_SYMMETRIC_LEFT_RIGHT_OVERLAP = 3,
 };
 
 enum {
@@ -354,6 +355,9 @@ struct tegra_dsi_out {
        u8              video_clock_mode;
        u8              video_burst_mode;
        u8              ganged_type;
+       u16             ganged_overlap;
+       bool            ganged_swap_links;
+       bool            ganged_write_to_all_links;
 
        u8              suspend_aggr;
 
index 8479f69dc1136b0eec38441b01b0890e941d675d..feec53eaa8ad64b6c0f73d07a585a7df8e8068f5 100644 (file)
@@ -483,7 +483,10 @@ static int __maybe_unused tegra_dsi_syncpt
 
        val = DSI_INCR_SYNCPT_COND(OP_DONE) |
                DSI_INCR_SYNCPT_INDX(dsi->syncpt_id);
-       tegra_dsi_controller_writel(dsi, val, DSI_INCR_SYNCPT, link_id);
+       if (dsi->info.ganged_type && dsi->info.ganged_write_to_all_links)
+               tegra_dsi_writel(dsi, val, DSI_INCR_SYNCPT);
+       else
+               tegra_dsi_controller_writel(dsi, val, DSI_INCR_SYNCPT, link_id);
 
        ret = nvhost_syncpt_wait_timeout_ext(dsi->dc->ndev, dsi->syncpt_id,
                dsi->syncpt_val + 1, (u32)MAX_SCHEDULE_TIMEOUT, NULL, NULL);
@@ -696,7 +699,9 @@ void tegra_dsi_init_clock_param(struct tegra_dc *dc)
 
        n_data_lanes = dsi->info.n_data_lanes;
        if (dsi->info.ganged_type == TEGRA_DSI_GANGED_SYMMETRIC_LEFT_RIGHT ||
-               dsi->info.ganged_type == TEGRA_DSI_GANGED_SYMMETRIC_EVEN_ODD)
+               dsi->info.ganged_type == TEGRA_DSI_GANGED_SYMMETRIC_EVEN_ODD ||
+               dsi->info.ganged_type ==
+                       TEGRA_DSI_GANGED_SYMMETRIC_LEFT_RIGHT_OVERLAP)
                n_data_lanes /= 2;
 
        dsi->dsi_control_val =
@@ -705,7 +710,9 @@ void tegra_dsi_init_clock_param(struct tegra_dc *dc)
                        DSI_CONTROL_VID_SOURCE(dc->ctrl_num) |
                        DSI_CONTROL_DATA_FORMAT(dsi->info.pixel_format);
 
-       if (dsi->info.ganged_type)
+       if (dsi->info.ganged_type &&
+               dsi->info.ganged_type !=
+                       TEGRA_DSI_GANGED_SYMMETRIC_LEFT_RIGHT_OVERLAP)
                tegra_dsi_pix_correction(dc, dsi);
 
        /* Below we are going to calculate dsi and dc clock rate.
@@ -1356,7 +1363,9 @@ static void tegra_dsi_set_sol_delay(struct tegra_dc *dc,
                if (dsi->info.ganged_type ==
                        TEGRA_DSI_GANGED_SYMMETRIC_LEFT_RIGHT ||
                        dsi->info.ganged_type ==
-                       TEGRA_DSI_GANGED_SYMMETRIC_EVEN_ODD) {
+                       TEGRA_DSI_GANGED_SYMMETRIC_EVEN_ODD ||
+                       dsi->info.ganged_type ==
+                       TEGRA_DSI_GANGED_SYMMETRIC_LEFT_RIGHT_OVERLAP) {
                        n_data_lanes_this_cont = dsi->info.n_data_lanes / 2;
                        n_data_lanes_ganged = dsi->info.n_data_lanes;
                }
@@ -1444,6 +1453,11 @@ static void tegra_dsi_setup_ganged_mode_pkt_length(struct tegra_dc *dc,
                hact_pkt_len_pix = DIV_ROUND_UP(hact_pkt_len_pix_orig, 2);
                pix_per_line = DIV_ROUND_UP(pix_per_line_orig, 2);
                break;
+       case TEGRA_DSI_GANGED_SYMMETRIC_LEFT_RIGHT_OVERLAP:
+               hact_pkt_len_pix = DIV_ROUND_UP(hact_pkt_len_pix_orig, 2) +
+                       dsi->info.ganged_overlap;
+               pix_per_line = DIV_ROUND_UP(pix_per_line_orig, 2);
+               break;
        default:
                dev_err(&dc->ndev->dev, "dsi: invalid ganged type\n");
        }
@@ -1463,9 +1477,12 @@ static void tegra_dsi_setup_ganged_mode_pkt_length(struct tegra_dc *dc,
                        DSI_PKT_LEN_4_5_LENGTH_5(0);
                tegra_dsi_controller_writel(dsi, val, DSI_PKT_LEN_4_5, i);
 
-               hact_pkt_len_pix =
-                       hact_pkt_len_pix_orig - hact_pkt_len_pix;
-               pix_per_line = pix_per_line_orig - pix_per_line;
+               if (dsi->info.ganged_type !=
+                       TEGRA_DSI_GANGED_SYMMETRIC_LEFT_RIGHT_OVERLAP) {
+                       hact_pkt_len_pix =
+                               hact_pkt_len_pix_orig - hact_pkt_len_pix;
+                       pix_per_line = pix_per_line_orig - pix_per_line;
+               }
        }
 
        val = DSI_PKT_LEN_6_7_LENGTH_6(0) |
@@ -2885,6 +2902,8 @@ static void tegra_dsi_ganged(struct tegra_dc *dc,
        u32 high_width = 0;
        u32 h_active = dc->out->modes->h_active;
        u32 val = 0;
+       int dsi_instances[2];
+       u16 ganged_pointer = DIV_ROUND_UP(h_active, 2);
 
        if (dsi->info.controller_vs < DSI_VS_1) {
                dev_err(&dc->ndev->dev, "dsi: ganged mode not"
@@ -2892,18 +2911,33 @@ static void tegra_dsi_ganged(struct tegra_dc *dc,
                return;
        }
 
+       if (dsi->info.ganged_swap_links) {
+               dsi_instances[0] = DSI_INSTANCE_1;
+               dsi_instances[1] = DSI_INSTANCE_0;
+       } else {
+               dsi_instances[0] = DSI_INSTANCE_0;
+               dsi_instances[1] = DSI_INSTANCE_1;
+       }
+
+       if (dsi->info.ganged_type ==
+               TEGRA_DSI_GANGED_SYMMETRIC_LEFT_RIGHT_OVERLAP &&
+               dsi->info.ganged_overlap)
+               ganged_pointer -= dsi->info.ganged_overlap;
+
        if (dsi->info.ganged_type ==
-                       TEGRA_DSI_GANGED_SYMMETRIC_LEFT_RIGHT) {
+                       TEGRA_DSI_GANGED_SYMMETRIC_LEFT_RIGHT ||
+               dsi->info.ganged_type ==
+                       TEGRA_DSI_GANGED_SYMMETRIC_LEFT_RIGHT_OVERLAP) {
                /* DSI 0 */
                tegra_dsi_controller_writel(dsi,
                        DSI_GANGED_MODE_START_POINTER(0),
-                       DSI_GANGED_MODE_START, DSI_INSTANCE_0);
+                       DSI_GANGED_MODE_START, dsi_instances[0]);
                /* DSI 1 */
                tegra_dsi_controller_writel(dsi,
-                       DSI_GANGED_MODE_START_POINTER(h_active / 2),
-                       DSI_GANGED_MODE_START, DSI_INSTANCE_1);
+                       DSI_GANGED_MODE_START_POINTER(ganged_pointer),
+                       DSI_GANGED_MODE_START, dsi_instances[1]);
 
-               low_width = DIV_ROUND_UP(h_active, 2);
+               low_width = ganged_pointer;
                high_width = h_active - low_width;
                val = DSI_GANGED_MODE_SIZE_VALID_LOW_WIDTH(low_width) |
                        DSI_GANGED_MODE_SIZE_VALID_HIGH_WIDTH(high_width);
@@ -2913,11 +2947,11 @@ static void tegra_dsi_ganged(struct tegra_dc *dc,
                /* DSI 0 */
                tegra_dsi_controller_writel(dsi,
                        DSI_GANGED_MODE_START_POINTER(0),
-                       DSI_GANGED_MODE_START, DSI_INSTANCE_0);
+                       DSI_GANGED_MODE_START, dsi_instances[0]);
                /* DSI 1 */
                tegra_dsi_controller_writel(dsi,
                        DSI_GANGED_MODE_START_POINTER(1),
-                       DSI_GANGED_MODE_START, DSI_INSTANCE_1);
+                       DSI_GANGED_MODE_START, dsi_instances[1]);
 
                low_width = 0x1;
                high_width = 0x1;
@@ -3234,8 +3268,8 @@ fail:
        return status;
 }
 
-static int _tegra_dsi_write_data(struct tegra_dc_dsi_data *dsi,
-                                       struct tegra_dsi_cmd *cmd)
+static int _tegra_dsi_controller_write_data(struct tegra_dc_dsi_data *dsi,
+                                       struct tegra_dsi_cmd *cmd, int link_id)
 {
        u8 virtual_channel;
        u32 val;
@@ -3246,7 +3280,7 @@ static int _tegra_dsi_write_data(struct tegra_dc_dsi_data *dsi,
 
        err = 0;
 
-       if (!dsi->info.ganged_type && cmd->link_id == TEGRA_DSI_LINK1) {
+       if (!dsi->info.ganged_type && link_id == TEGRA_DSI_LINK1) {
                dev_err(&dsi->dc->ndev->dev, "DSI invalid command\n");
                return -EINVAL;
        }
@@ -3257,7 +3291,7 @@ static int _tegra_dsi_write_data(struct tegra_dc_dsi_data *dsi,
        /* always use hw for ecc */
        val = (virtual_channel | data_id) << 0 |
                        data_len << 8;
-       tegra_dsi_controller_writel(dsi, val, DSI_WR_DATA, cmd->link_id);
+       tegra_dsi_controller_writel(dsi, val, DSI_WR_DATA, link_id);
 
        /* if pdata != NULL, pkt type is long pkt */
        if (pdata != NULL) {
@@ -3273,12 +3307,12 @@ static int _tegra_dsi_write_data(struct tegra_dc_dsi_data *dsi,
                                data_len = 0;
                        }
                        tegra_dsi_controller_writel(dsi, val,
-                               DSI_WR_DATA, cmd->link_id);
+                               DSI_WR_DATA, link_id);
                }
        }
 
        if (cmd->cmd_type != TEGRA_DSI_PACKET_VIDEO_VBLANK_CMD) {
-               err = tegra_dsi_host_trigger(dsi, cmd->link_id);
+               err = tegra_dsi_host_trigger(dsi, link_id);
                if (err < 0)
                        dev_err(&dsi->dc->ndev->dev, "DSI host trigger failed\n");
        }
@@ -3286,6 +3320,23 @@ static int _tegra_dsi_write_data(struct tegra_dc_dsi_data *dsi,
        return err;
 }
 
+static int _tegra_dsi_write_data(struct tegra_dc_dsi_data *dsi,
+                                       struct tegra_dsi_cmd *cmd)
+{
+       int i, err = 0;
+
+       if (dsi->info.ganged_type && dsi->info.ganged_write_to_all_links)
+               for (i = 0; i < dsi->max_instances; i++) {
+                       err = _tegra_dsi_controller_write_data(dsi, cmd, i);
+                       if (err)
+                               break;
+               }
+       else
+               err = _tegra_dsi_controller_write_data(dsi, cmd, cmd->link_id);
+
+       return err;
+}
+
 static void tegra_dc_dsi_hold_host(struct tegra_dc *dc)
 {
        struct tegra_dc_dsi_data *dsi = tegra_dc_get_outdata(dc);
@@ -3666,7 +3717,11 @@ static int tegra_dsi_bta(struct tegra_dc_dsi_data *dsi)
 
        val = tegra_dsi_readl(dsi, DSI_HOST_DSI_CONTROL);
        val |= DSI_HOST_DSI_CONTROL_IMM_BTA(TEGRA_DSI_ENABLE);
-       tegra_dsi_controller_writel(dsi, val,
+
+       if (dsi->info.ganged_type && dsi->info.ganged_write_to_all_links)
+               tegra_dsi_writel(dsi, val, DSI_HOST_DSI_CONTROL);
+       else
+               tegra_dsi_controller_writel(dsi, val,
                                DSI_HOST_DSI_CONTROL, TEGRA_DSI_LINK0);
 
        if (!tegra_cpu_is_asim() && DSI_USE_SYNC_POINTS) {
index 14e23cfbc1ed007e2c2d126d9980b6daca3519dc..403e147a2c74b8298a6e4158ddfdd43c9e0b7854 100644 (file)
@@ -1188,6 +1188,32 @@ static struct device_node *parse_dsi_settings(struct platform_device *ndev,
                OF_DC_LOG("dsi ganged_type %d\n", dsi->ganged_type);
        }
 
+       if (!of_property_read_u32(np_dsi_panel,
+               "nvidia,dsi-ganged-overlap", &temp)) {
+               dsi->ganged_overlap = (u16)temp;
+               OF_DC_LOG("dsi ganged overlap %d\n", dsi->ganged_overlap);
+               if (!dsi->ganged_type)
+                       pr_warn("specified ganged overlap, but no ganged type\n");
+       }
+
+       if (!of_property_read_u32(np_dsi_panel,
+               "nvidia,dsi-ganged-swap-links", &temp)) {
+               dsi->ganged_swap_links = (bool)temp;
+               OF_DC_LOG("dsi ganged swapped links %d\n",
+                       dsi->ganged_swap_links);
+               if (!dsi->ganged_type)
+                       pr_warn("specified ganged swapped links, but no ganged type\n");
+       }
+
+       if (!of_property_read_u32(np_dsi_panel,
+               "nvidia,dsi-ganged-write-to-all-links", &temp)) {
+               dsi->ganged_write_to_all_links = (bool)temp;
+               OF_DC_LOG("dsi ganged write to both links %d\n",
+                       dsi->ganged_write_to_all_links);
+               if (!dsi->ganged_type)
+                       pr_warn("specified ganged write to all links, but no ganged type\n");
+       }
+
        if (!of_property_read_u32(np_dsi_panel,
                "nvidia,dsi-suspend-aggr", &temp)) {
                dsi->suspend_aggr = (u8)temp;
index 6468d4625178a593edc3b6f5257779f2a96c76cd..9bc577674e3763fcad4cff30aada6c724319baef 100644 (file)
@@ -34,6 +34,7 @@
 
 #define TEGRA_DSI_GANGED_SYMMETRIC_LEFT_RIGHT  1
 #define TEGRA_DSI_GANGED_SYMMETRIC_EVEN_ODD    2
+#define TEGRA_DSI_GANGED_SYMMETRIC_LEFT_RIGHT_OVERLAP  3
 
 #define TEGRA_DSI_PACKET_CMD 0
 #define TEGRA_DSI_DELAY_MS 1