- 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.
- 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.
- 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.
- 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.
- 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.
- 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.
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);
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 =
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.
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;
}
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");
}
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) |
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"
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);
/* 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;
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;
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;
}
/* 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) {
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");
}
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);
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) {