disp: msm: read mdp intf line count and trigger dma accordingly

This change reads the video line count from
MDP_INTF_LINE_COUNT register and checks whether
DMA trigger happens close to the schedule line.
If it is not close to the schedule line, then DMA
command transfer is triggered. Without this change
there is a chance that when 2 DSI's with broadcast,
schedule enabled, the DMA command gets triggered close
to the schedule line which could cause DMA timeout.

Change-Id: Ida92e63e46b4cc703d57ce24097834f810776aa8
Signed-off-by: Harigovindan P <harigovi@codeaurora.org>
This commit is contained in:
Harigovindan P authored and Gerrit - the friendly Code Review server committed 2020-09-09 01:24:11 -07:00
1 parent d0f5c748b2
commit beea6cd22d
7 files changed
+175 -14

No files matched your search

+7 -1
View File
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/errno.h>
@@ -81,6 +81,8 @@ static void dsi_catalog_cmn_init(struct dsi_ctrl_hw *ctrl,
ctrl->ops.schedule_dma_cmd = NULL;
ctrl->ops.kickoff_command_non_embedded_mode = NULL;
ctrl->ops.config_clk_gating = NULL;
ctrl->ops.map_mdp_regs = NULL;
ctrl->ops.log_line_count = NULL;
break;
case DSI_CTRL_VERSION_2_0:
ctrl->ops.setup_lane_map = dsi_ctrl_hw_20_setup_lane_map;
@@ -96,6 +98,8 @@ static void dsi_catalog_cmn_init(struct dsi_ctrl_hw *ctrl,
ctrl->ops.schedule_dma_cmd = NULL;
ctrl->ops.kickoff_command_non_embedded_mode = NULL;
ctrl->ops.config_clk_gating = NULL;
ctrl->ops.map_mdp_regs = NULL;
ctrl->ops.log_line_count = NULL;
break;
case DSI_CTRL_VERSION_2_2:
case DSI_CTRL_VERSION_2_3:
@@ -116,6 +120,8 @@ static void dsi_catalog_cmn_init(struct dsi_ctrl_hw *ctrl,
ctrl->ops.schedule_dma_cmd = dsi_ctrl_hw_22_schedule_dma_cmd;
ctrl->ops.kickoff_command_non_embedded_mode =
dsi_ctrl_hw_kickoff_non_embedded_mode;
ctrl->ops.map_mdp_regs = dsi_ctrl_hw_22_map_mdp_regs;
ctrl->ops.log_line_count = dsi_ctrl_hw_22_log_line_count;
break;
default:
break;
+6 -1
View File
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
*/
#ifndef _DSI_CATALOG_H_
@@ -270,4 +270,9 @@ void dsi_phy_hw_v4_0_dyn_refresh_pipe_delay(struct dsi_phy_hw *phy,
int dsi_phy_hw_v4_0_cache_phy_timings(struct dsi_phy_per_lane_cfgs *timings,
u32 *dst, u32 size);
int dsi_ctrl_hw_22_map_mdp_regs(struct platform_device *pdev,
struct dsi_ctrl_hw *ctrl);
u32 dsi_ctrl_hw_22_log_line_count(struct dsi_ctrl_hw *ctrl, bool cmd_mode);
#endif /* _DSI_CATALOG_H_ */
+71 -10
View File
@@ -1219,6 +1219,24 @@ int dsi_message_validate_tx_mode(struct dsi_ctrl *dsi_ctrl,
return rc;
}
static u32 calculate_schedule_line(struct dsi_ctrl *dsi_ctrl, u32 flags)
{
u32 line_no = 0x1;
struct dsi_mode_info *timing;
/* check if custom dma scheduling line needed */
if ((dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE) &&
(flags & DSI_CTRL_CMD_CUSTOM_DMA_SCHED))
line_no = dsi_ctrl->host_config.u.video_engine.dma_sched_line;
timing = &(dsi_ctrl->host_config.video_timing);
if (timing)
line_no += timing->v_back_porch + timing->v_sync_width +
timing->v_active;
return line_no;
}
static void dsi_kickoff_msg_tx(struct dsi_ctrl *dsi_ctrl,
const struct mipi_dsi_msg *msg,
@@ -1228,20 +1246,13 @@ static void dsi_kickoff_msg_tx(struct dsi_ctrl *dsi_ctrl,
{
u32 hw_flags = 0;
u32 line_no = 0x1;
struct dsi_mode_info *timing;
struct dsi_ctrl_hw_ops dsi_hw_ops = dsi_ctrl->hw.ops;
SDE_EVT32(dsi_ctrl->cell_index, SDE_EVTLOG_FUNC_ENTRY, flags,
msg->flags);
/* check if custom dma scheduling line needed */
if ((dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE) &&
(flags & DSI_CTRL_CMD_CUSTOM_DMA_SCHED))
line_no = dsi_ctrl->host_config.u.video_engine.dma_sched_line;
timing = &(dsi_ctrl->host_config.video_timing);
if (timing)
line_no += timing->v_back_porch + timing->v_sync_width +
timing->v_active;
line_no = calculate_schedule_line(dsi_ctrl, flags);
if ((dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE) &&
dsi_hw_ops.schedule_dma_cmd &&
(dsi_ctrl->current_state.vid_engine_state ==
@@ -1249,6 +1260,8 @@ static void dsi_kickoff_msg_tx(struct dsi_ctrl *dsi_ctrl,
dsi_hw_ops.schedule_dma_cmd(&dsi_ctrl->hw,
line_no);
dsi_ctrl->cmd_mode = (dsi_ctrl->host_config.panel_mode ==
DSI_OP_CMD_MODE);
hw_flags |= (flags & DSI_CTRL_CMD_DEFER_TRIGGER) ?
DSI_CTRL_HW_CMD_WAIT_FOR_TRIGGER : 0;
@@ -1967,6 +1980,9 @@ static int dsi_ctrl_dev_probe(struct platform_device *pdev)
DSI_CTRL_DEBUG(dsi_ctrl, "failed to init axi bus client, rc = %d\n",
rc);
if (dsi_ctrl->hw.ops.map_mdp_regs)
dsi_ctrl->hw.ops.map_mdp_regs(pdev, &dsi_ctrl->hw);
item->ctrl = dsi_ctrl;
mutex_lock(&dsi_ctrl_list_lock);
@@ -3298,6 +3314,10 @@ int dsi_ctrl_cmd_tx_trigger(struct dsi_ctrl *dsi_ctrl, u32 flags)
{
int rc = 0;
struct dsi_ctrl_hw_ops dsi_hw_ops;
u32 v_total = 0, fps = 0, cur_line = 0, mem_latency_us = 100;
u32 line_time = 0, schedule_line = 0x1, latency_by_line = 0;
struct dsi_mode_info *timing;
unsigned long flag;
if (!dsi_ctrl) {
DSI_CTRL_ERR(dsi_ctrl, "Invalid params\n");
@@ -3313,6 +3333,18 @@ int dsi_ctrl_cmd_tx_trigger(struct dsi_ctrl *dsi_ctrl, u32 flags)
mutex_lock(&dsi_ctrl->ctrl_lock);
timing = &(dsi_ctrl->host_config.video_timing);
if (timing &&
(dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE)) {
v_total = timing->v_sync_width + timing->v_back_porch +
timing->v_front_porch + timing->v_active;
fps = timing->refresh_rate;
schedule_line = calculate_schedule_line(dsi_ctrl, flags);
line_time = (1000000 / fps) / v_total;
latency_by_line = CEIL(mem_latency_us, line_time);
}
if (!(flags & DSI_CTRL_CMD_BROADCAST_MASTER))
dsi_hw_ops.trigger_command_dma(&dsi_ctrl->hw);
@@ -3325,7 +3357,36 @@ int dsi_ctrl_cmd_tx_trigger(struct dsi_ctrl *dsi_ctrl, u32 flags)
reinit_completion(&dsi_ctrl->irq_info.cmd_dma_done);
/* trigger command */
dsi_hw_ops.trigger_command_dma(&dsi_ctrl->hw);
if ((dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE) &&
dsi_hw_ops.schedule_dma_cmd &&
(dsi_ctrl->current_state.vid_engine_state ==
DSI_CTRL_ENGINE_ON)) {
/*
* This change reads the video line count from
* MDP_INTF_LINE_COUNT register and checks whether
* DMA trigger happens close to the schedule line.
* If it is not close to the schedule line, then DMA
* command transfer is triggered.
*/
while (1) {
local_irq_save(flag);
cur_line =
dsi_hw_ops.log_line_count(&dsi_ctrl->hw,
dsi_ctrl->cmd_mode);
if (cur_line <
(schedule_line - latency_by_line) ||
cur_line > (schedule_line + 1)) {
dsi_hw_ops.trigger_command_dma(
&dsi_ctrl->hw);
local_irq_restore(flag);
break;
}
local_irq_restore(flag);
udelay(1000);
}
} else
dsi_hw_ops.trigger_command_dma(&dsi_ctrl->hw);
if (flags & DSI_CTRL_CMD_ASYNC_WAIT) {
dsi_ctrl->dma_wait_queued = true;
queue_work(dsi_ctrl->dma_cmd_workq,
+3
View File
@@ -239,6 +239,8 @@ struct dsi_ctrl_interrupts {
* insert null packet.
* @modeupdated: Boolean to send new roi if mode is updated.
* @split_link_supported: Boolean to check if hw supports split link.
* @cmd_mode: Boolean to indicate if panel is running in
command mode.
*/
struct dsi_ctrl {
struct platform_device *pdev;
@@ -299,6 +301,7 @@ struct dsi_ctrl {
bool null_insertion_enabled;
bool modeupdated;
bool split_link_supported;
bool cmd_mode;
};
/**
+25
View File
@@ -838,6 +838,22 @@ struct dsi_ctrl_hw_ops {
* @sel_phy: Bool to control whether to select phy or controller
*/
void (*hs_req_sel)(struct dsi_ctrl_hw *ctrl, bool sel_phy);
/**
* hw.ops.map_mdp_regs() - maps MDP interface line count registers.
* @pdev:» Pointer to platform device.
* @ctrl:» Pointer to the controller host hardware.
*/
int (*map_mdp_regs)(struct platform_device *pdev,
struct dsi_ctrl_hw *ctrl);
/**
* hw.ops.log_line_count() - reads the MDP interface line count
* registers.
* @ctrl:» Pointer to the controller host hardware.
* @cmd_mode:» Boolean to indicate command mode operation.
*/
u32 (*log_line_count)(struct dsi_ctrl_hw *ctrl, bool cmd_mode);
};
/*
@@ -848,6 +864,13 @@ struct dsi_ctrl_hw_ops {
* @mmss_misc_length: Length of mmss_misc register map.
* @disp_cc_base: Base address of disp_cc register map.
* @disp_cc_length: Length of disp_cc register map.
* @te_rd_ptr_reg: Address of MDP_TEAR_INTF_TEAR_LINE_COUNT. This
* register is used for testing and validating the RD
* ptr value when a CMD is triggered and it succeeds.
* @line_count_reg: Address of MDP_TEAR_INTF_LINE_COUNT. This
* register is used for testing and validating the
* line count value when a CMD is triggered and it
* succeeds.
* @index: Instance ID of the controller.
* @feature_map: Features supported by the DSI controller.
* @ops: Function pointers to the operations supported by the
@@ -865,6 +888,8 @@ struct dsi_ctrl_hw {
void __iomem *mmss_misc_base;
u32 mmss_misc_length;
void __iomem *disp_cc_base;
void __iomem *te_rd_ptr_reg;
void __iomem *line_count_reg;
u32 disp_cc_length;
u32 index;
+63 -1
View File
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
*/
#include "dsi_ctrl_hw.h"
@@ -13,6 +13,10 @@
/* register to configure DMA scheduling */
#define DSI_DMA_SCHEDULE_CTRL 0x100
/* MDP INTF registers to be mapped*/
#define MDP_INTF1_TEAR_LINE_COUNT 0xAE6BAB0
#define MDP_INTF1_LINE_COUNT 0xAE6B8B0
/**
* dsi_ctrl_hw_22_phy_reset_config() - to configure clamp control during ulps
* @ctrl: Pointer to the controller host hardware.
@@ -126,3 +130,61 @@ void dsi_ctrl_hw_22_config_clk_gating(struct dsi_ctrl_hw *ctrl, bool enable,
DSI_DISP_CC_W32(ctrl, DISP_CC_MISC_CMD_REG_OFF, reg);
}
/**
* dsi_ctrl_hw_22_map_mdp_regs() - maps MDP interface line count registers.
* @pdev: Pointer to platform device.
* @ctrl: Pointer to the controller host hardware.
*
* Return: 0 on success and error on failure.
*/
int dsi_ctrl_hw_22_map_mdp_regs(struct platform_device *pdev,
struct dsi_ctrl_hw *ctrl)
{
int rc = 0;
void __iomem *ptr = NULL, *ptr1 = NULL;
if (ctrl->index == 0) {
ptr = devm_ioremap(&pdev->dev, MDP_INTF1_TEAR_LINE_COUNT, 1);
if (IS_ERR_OR_NULL(ptr)) {
DSI_CTRL_HW_ERR(ctrl,
"MDP TE LINE COUNT address not found\n");
rc = PTR_ERR(ptr);
return rc;
}
ptr1 = devm_ioremap(&pdev->dev, MDP_INTF1_LINE_COUNT, 1);
if (IS_ERR_OR_NULL(ptr1)) {
DSI_CTRL_HW_ERR(ctrl,
"MDP TE LINE COUNT address not found\n");
rc = PTR_ERR(ptr1);
return rc;
}
}
ctrl->te_rd_ptr_reg = ptr;
ctrl->line_count_reg = ptr1;
return rc;
}
/**
* dsi_ctrl_hw_22_log_line_count() - reads the MDP interface line count
* registers.
* @ctrl: Pointer to the controller host hardware.
* @cmd_mode: Boolean to indicate command mode operation.
*
* Return: INTF register value.
*/
u32 dsi_ctrl_hw_22_log_line_count(struct dsi_ctrl_hw *ctrl, bool cmd_mode)
{
u32 reg = 0;
if (cmd_mode && ctrl->te_rd_ptr_reg)
reg = readl_relaxed(ctrl->te_rd_ptr_reg);
else if (ctrl->line_count_reg)
reg = readl_relaxed(ctrl->line_count_reg);
return reg;
}
-1
View File
@@ -778,7 +778,6 @@ void dsi_ctrl_hw_cmn_reset_cmd_fifo(struct dsi_ctrl_hw *ctrl)
void dsi_ctrl_hw_cmn_trigger_command_dma(struct dsi_ctrl_hw *ctrl)
{
DSI_W32(ctrl, DSI_CMD_MODE_DMA_SW_TRIGGER, 0x1);
DSI_CTRL_HW_DBG(ctrl, "CMD DMA triggered\n");
}
/**