mdss: dsi: add support for DSI data lane overflow recovery
Sometimes the DSI lanes can overflow due to the CLK lane getting stuck at HS state and not transiting to LP state. Add support for display recovery in such cases for video mode panels. Add code so that this recovery is done during the active period. Change-Id: Ib56e7bccb4b3b9525ff0f4c4fca54971610a7326 Signed-off-by: Chandan Uddaraju <chandanu@codeaurora.org>
This commit is contained in:
parent
1e0cb3a69b
commit
c4abe728b8
6 changed files with 333 additions and 15 deletions
|
@ -1161,7 +1161,7 @@ static int mdss_dsi_set_stream_size(struct mdss_panel_data *pdata)
|
|||
}
|
||||
|
||||
int mdss_dsi_register_recovery_handler(struct mdss_dsi_ctrl_pdata *ctrl,
|
||||
struct mdss_panel_recovery *recovery)
|
||||
struct mdss_intf_recovery *recovery)
|
||||
{
|
||||
mutex_lock(&ctrl->mutex);
|
||||
ctrl->recovery = recovery;
|
||||
|
@ -1249,7 +1249,7 @@ static int mdss_dsi_event_handler(struct mdss_panel_data *pdata,
|
|||
break;
|
||||
case MDSS_EVENT_REGISTER_RECOVERY_HANDLER:
|
||||
rc = mdss_dsi_register_recovery_handler(ctrl_pdata,
|
||||
(struct mdss_panel_recovery *)arg);
|
||||
(struct mdss_intf_recovery *)arg);
|
||||
break;
|
||||
default:
|
||||
pr_debug("%s: unhandled event=%d\n", __func__, event);
|
||||
|
|
|
@ -273,7 +273,8 @@ enum {
|
|||
|
||||
#define DSI_EV_PLL_UNLOCKED 0x0001
|
||||
#define DSI_EV_MDP_FIFO_UNDERFLOW 0x0002
|
||||
#define DSI_EV_DSI_FIFO_EMPTY 0x0003
|
||||
#define DSI_EV_DSI_FIFO_EMPTY 0x0004
|
||||
#define DSI_EV_DLNx_FIFO_OVERFLOW 0x0008
|
||||
#define DSI_EV_MDP_BUSY_RELEASE 0x80000000
|
||||
|
||||
struct mdss_dsi_ctrl_pdata {
|
||||
|
@ -338,7 +339,7 @@ struct mdss_dsi_ctrl_pdata {
|
|||
struct dss_module_power power_data[DSI_MAX_PM];
|
||||
u32 dsi_irq_mask;
|
||||
struct mdss_hw *dsi_hw;
|
||||
struct mdss_panel_recovery *recovery;
|
||||
struct mdss_intf_recovery *recovery;
|
||||
|
||||
struct dsi_panel_cmds on_cmds;
|
||||
struct dsi_panel_cmds off_cmds;
|
||||
|
@ -459,7 +460,7 @@ int mdss_panel_get_dst_fmt(u32 bpp, char mipi_mode, u32 pixel_packing,
|
|||
char *dst_format);
|
||||
|
||||
int mdss_dsi_register_recovery_handler(struct mdss_dsi_ctrl_pdata *ctrl,
|
||||
struct mdss_panel_recovery *recovery);
|
||||
struct mdss_intf_recovery *recovery);
|
||||
|
||||
static inline const char *__mdss_dsi_pm_name(enum dsi_pm_type module)
|
||||
{
|
||||
|
|
|
@ -49,6 +49,9 @@ struct mdss_hw mdss_dsi1_hw = {
|
|||
|
||||
#define DSI_BTA_EVENT_TIMEOUT (HZ / 10)
|
||||
|
||||
/* Mutex common for both the controllers */
|
||||
static struct mutex dsi_mtx;
|
||||
|
||||
/* event */
|
||||
struct dsi_event_q {
|
||||
struct mdss_dsi_ctrl_pdata *ctrl;
|
||||
|
@ -111,6 +114,7 @@ void mdss_dsi_ctrl_init(struct device *ctrl_dev,
|
|||
if (dsi_event.inited == 0) {
|
||||
kthread_run(dsi_event_thread, (void *)&dsi_event,
|
||||
"mdss_dsi_event");
|
||||
mutex_init(&dsi_mtx);
|
||||
dsi_event.inited = 1;
|
||||
}
|
||||
}
|
||||
|
@ -355,7 +359,7 @@ void mdss_dsi_host_init(struct mdss_panel_data *pdata)
|
|||
|
||||
/* allow only ack-err-status to generate interrupt */
|
||||
/* DSI_ERR_INT_MASK0 */
|
||||
MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x010c, 0x13ff3fe0);
|
||||
MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x010c, 0x03f03fe0);
|
||||
|
||||
intr_ctrl |= DSI_INTR_ERROR_MASK;
|
||||
MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0110,
|
||||
|
@ -430,6 +434,179 @@ void mdss_dsi_sw_reset(struct mdss_dsi_ctrl_pdata *ctrl, bool restore)
|
|||
}
|
||||
}
|
||||
|
||||
static void mdss_dsi_ctl_phy_reset(struct mdss_dsi_ctrl_pdata *ctrl)
|
||||
{
|
||||
u32 data0, data1;
|
||||
struct mdss_dsi_ctrl_pdata *ctrl0, *ctrl1;
|
||||
u32 ln0, ln1, ln_ctrl0, ln_ctrl1, i;
|
||||
/*
|
||||
* Add 2 ms delay suggested by HW team.
|
||||
* Check clk lane stop state after every 200 us
|
||||
*/
|
||||
u32 loop = 10, u_dly = 200;
|
||||
pr_debug("%s: MDSS DSI CTRL and PHY reset. ctrl-num = %d\n",
|
||||
__func__, ctrl->ndx);
|
||||
|
||||
if (ctrl->panel_data.panel_info.is_split_display) {
|
||||
pr_debug("%s: Split display enabled\n", __func__);
|
||||
ctrl0 = mdss_dsi_get_ctrl_by_index(DSI_CTRL_0);
|
||||
ctrl1 = mdss_dsi_get_ctrl_by_index(DSI_CTRL_1);
|
||||
|
||||
if (ctrl0->recovery)
|
||||
ctrl0->recovery->fxn(ctrl0->recovery->data,
|
||||
MDP_INTF_DSI_VIDEO_FIFO_OVERFLOW);
|
||||
/*
|
||||
* Disable PHY contention detection and receive.
|
||||
* Configure the strength ctrl 1 register.
|
||||
*/
|
||||
MIPI_OUTP((ctrl0->phy_io.base) + 0x0188, 0);
|
||||
MIPI_OUTP((ctrl1->phy_io.base) + 0x0188, 0);
|
||||
|
||||
data0 = MIPI_INP(ctrl0->ctrl_base + 0x0004);
|
||||
data1 = MIPI_INP(ctrl1->ctrl_base + 0x0004);
|
||||
/* Disable DSI video mode */
|
||||
MIPI_OUTP(ctrl0->ctrl_base + 0x004, 0x1f5);
|
||||
MIPI_OUTP(ctrl1->ctrl_base + 0x004, 0x1f5);
|
||||
/* Disable DSI controller */
|
||||
MIPI_OUTP(ctrl0->ctrl_base + 0x004, 0x1f4);
|
||||
MIPI_OUTP(ctrl1->ctrl_base + 0x004, 0x1f4);
|
||||
/* "Force On" all dynamic clocks */
|
||||
MIPI_OUTP(ctrl0->ctrl_base + 0x11c, 0x100a00);
|
||||
MIPI_OUTP(ctrl1->ctrl_base + 0x11c, 0x100a00);
|
||||
|
||||
/* DSI_SW_RESET */
|
||||
MIPI_OUTP(ctrl0->ctrl_base + 0x118, 0x1);
|
||||
MIPI_OUTP(ctrl1->ctrl_base + 0x118, 0x1);
|
||||
wmb();
|
||||
MIPI_OUTP(ctrl0->ctrl_base + 0x118, 0x0);
|
||||
MIPI_OUTP(ctrl1->ctrl_base + 0x118, 0x0);
|
||||
wmb();
|
||||
|
||||
/* Remove "Force On" all dynamic clocks */
|
||||
MIPI_OUTP(ctrl0->ctrl_base + 0x11c, 0x00); /* DSI_CLK_CTRL */
|
||||
MIPI_OUTP(ctrl1->ctrl_base + 0x11c, 0x00); /* DSI_CLK_CTRL */
|
||||
|
||||
/* Enable DSI controller */
|
||||
MIPI_OUTP(ctrl0->ctrl_base + 0x004, 0x1f5);
|
||||
MIPI_OUTP(ctrl1->ctrl_base + 0x004, 0x1f5);
|
||||
|
||||
/*
|
||||
* Toggle Clk lane Force TX stop so that
|
||||
* clk lane status is no more in stop state
|
||||
*/
|
||||
ln0 = MIPI_INP(ctrl0->ctrl_base + 0x00a8);
|
||||
ln1 = MIPI_INP(ctrl1->ctrl_base + 0x00a8);
|
||||
pr_debug("%s: lane status, ctrl0 = 0x%x, ctrl1 = 0x%x\n",
|
||||
__func__, ln0, ln1);
|
||||
ln_ctrl0 = MIPI_INP(ctrl0->ctrl_base + 0x00ac);
|
||||
ln_ctrl1 = MIPI_INP(ctrl1->ctrl_base + 0x00ac);
|
||||
MIPI_OUTP(ctrl0->ctrl_base + 0x0ac, ln_ctrl0 | BIT(20));
|
||||
MIPI_OUTP(ctrl1->ctrl_base + 0x0ac, ln_ctrl1 | BIT(20));
|
||||
ln_ctrl0 = MIPI_INP(ctrl0->ctrl_base + 0x00ac);
|
||||
ln_ctrl1 = MIPI_INP(ctrl1->ctrl_base + 0x00ac);
|
||||
for (i = 0; i < loop; i++) {
|
||||
ln0 = MIPI_INP(ctrl0->ctrl_base + 0x00a8);
|
||||
ln1 = MIPI_INP(ctrl1->ctrl_base + 0x00a8);
|
||||
if ((ln0 == 0x1f1f) && (ln1 == 0x1f1f))
|
||||
break;
|
||||
else
|
||||
/* Check clk lane stopState for every 200us */
|
||||
udelay(u_dly);
|
||||
}
|
||||
if (i == loop) {
|
||||
MDSS_XLOG(ctrl0->ndx, ln0, 0x1f1f);
|
||||
MDSS_XLOG(ctrl1->ndx, ln1, 0x1f1f);
|
||||
pr_err("Clock lane still in stop state");
|
||||
MDSS_XLOG_TOUT_HANDLER("mdp", "dsi0", "dsi1",
|
||||
"panic");
|
||||
}
|
||||
pr_debug("%s: lane ctrl, ctrl0 = 0x%x, ctrl1 = 0x%x\n",
|
||||
__func__, ln0, ln1);
|
||||
MIPI_OUTP(ctrl0->ctrl_base + 0x0ac, ln_ctrl0 & ~BIT(20));
|
||||
MIPI_OUTP(ctrl1->ctrl_base + 0x0ac, ln_ctrl1 & ~BIT(20));
|
||||
|
||||
/* Enable Video mode for DSI controller */
|
||||
MIPI_OUTP(ctrl0->ctrl_base + 0x004, 0x1f7);
|
||||
MIPI_OUTP(ctrl1->ctrl_base + 0x004, 0x1f7);
|
||||
|
||||
/*
|
||||
* Enable PHY contention detection and receive.
|
||||
* Configure the strength ctrl 1 register.
|
||||
*/
|
||||
MIPI_OUTP((ctrl0->phy_io.base) + 0x0188, 0x6);
|
||||
MIPI_OUTP((ctrl1->phy_io.base) + 0x0188, 0x6);
|
||||
/*
|
||||
* Add sufficient delay to make sure
|
||||
* pixel transmission as started
|
||||
*/
|
||||
udelay(200);
|
||||
} else {
|
||||
if (ctrl->recovery)
|
||||
ctrl->recovery->fxn(ctrl->recovery->data,
|
||||
MDP_INTF_DSI_VIDEO_FIFO_OVERFLOW);
|
||||
/* Disable PHY contention detection and receive */
|
||||
MIPI_OUTP((ctrl->phy_io.base) + 0x0188, 0);
|
||||
|
||||
data0 = MIPI_INP(ctrl->ctrl_base + 0x0004);
|
||||
/* Disable DSI video mode */
|
||||
MIPI_OUTP(ctrl->ctrl_base + 0x004, 0x1f5);
|
||||
/* Disable DSI controller */
|
||||
MIPI_OUTP(ctrl->ctrl_base + 0x004, 0x1f4);
|
||||
/* "Force On" all dynamic clocks */
|
||||
MIPI_OUTP(ctrl->ctrl_base + 0x11c, 0x100a00);
|
||||
|
||||
/* DSI_SW_RESET */
|
||||
MIPI_OUTP(ctrl->ctrl_base + 0x118, 0x1);
|
||||
wmb();
|
||||
MIPI_OUTP(ctrl->ctrl_base + 0x118, 0x0);
|
||||
wmb();
|
||||
|
||||
/* Remove "Force On" all dynamic clocks */
|
||||
MIPI_OUTP(ctrl->ctrl_base + 0x11c, 0x00);
|
||||
/* Enable DSI controller */
|
||||
MIPI_OUTP(ctrl->ctrl_base + 0x004, 0x1f5);
|
||||
|
||||
/*
|
||||
* Toggle Clk lane Force TX stop so that
|
||||
* clk lane status is no more in stop state
|
||||
*/
|
||||
ln0 = MIPI_INP(ctrl->ctrl_base + 0x00a8);
|
||||
pr_debug("%s: lane status, ctrl = 0x%x\n",
|
||||
__func__, ln0);
|
||||
ln_ctrl0 = MIPI_INP(ctrl->ctrl_base + 0x00ac);
|
||||
MIPI_OUTP(ctrl->ctrl_base + 0x0ac, ln_ctrl0 | BIT(20));
|
||||
ln_ctrl0 = MIPI_INP(ctrl->ctrl_base + 0x00ac);
|
||||
for (i = 0; i < loop; i++) {
|
||||
ln0 = MIPI_INP(ctrl->ctrl_base + 0x00a8);
|
||||
if (ln0 == 0x1f1f)
|
||||
break;
|
||||
else
|
||||
/* Check clk lane stopState for every 200us */
|
||||
udelay(u_dly);
|
||||
}
|
||||
if (i == loop) {
|
||||
MDSS_XLOG(ctrl->ndx, ln0, 0x1f1f);
|
||||
pr_err("Clock lane still in stop state");
|
||||
MDSS_XLOG_TOUT_HANDLER("mdp", "dsi0", "dsi1",
|
||||
"panic");
|
||||
}
|
||||
pr_debug("%s: lane status = 0x%x\n",
|
||||
__func__, ln0);
|
||||
MIPI_OUTP(ctrl->ctrl_base + 0x0ac, ln_ctrl0 & ~BIT(20));
|
||||
|
||||
/* Enable Video mode for DSI controller */
|
||||
MIPI_OUTP(ctrl->ctrl_base + 0x004, 0x1f7);
|
||||
/* Enable PHY contention detection and receiver */
|
||||
MIPI_OUTP((ctrl->phy_io.base) + 0x0188, 0x6);
|
||||
/*
|
||||
* Add sufficient delay to make sure
|
||||
* pixel transmission as started
|
||||
*/
|
||||
udelay(200);
|
||||
}
|
||||
pr_debug("Recovery done\n");
|
||||
}
|
||||
|
||||
void mdss_dsi_err_intr_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, u32 mask,
|
||||
int enable)
|
||||
{
|
||||
|
@ -522,7 +699,8 @@ void mdss_dsi_op_mode_config(int mode,
|
|||
|
||||
if (mode == DSI_VIDEO_MODE) {
|
||||
dsi_ctrl |= 0x03;
|
||||
intr_ctrl = DSI_INTR_CMD_DMA_DONE_MASK | DSI_INTR_BTA_DONE_MASK;
|
||||
intr_ctrl = DSI_INTR_CMD_DMA_DONE_MASK | DSI_INTR_BTA_DONE_MASK
|
||||
| DSI_INTR_ERROR_MASK;
|
||||
} else { /* command mode */
|
||||
dsi_ctrl |= 0x05;
|
||||
if (pdata->panel_info.type == MIPI_VIDEO_PANEL)
|
||||
|
@ -1663,9 +1841,12 @@ static int dsi_event_thread(void *data)
|
|||
if (todo & DSI_EV_MDP_FIFO_UNDERFLOW) {
|
||||
mutex_lock(&ctrl->mutex);
|
||||
if (ctrl->recovery) {
|
||||
pr_debug("%s: Handling underflow event\n",
|
||||
__func__);
|
||||
mdss_dsi_clk_ctrl(ctrl, DSI_ALL_CLKS, 1);
|
||||
mdss_dsi_sw_reset(ctrl, true);
|
||||
ctrl->recovery->fxn(ctrl->recovery->data);
|
||||
ctrl->recovery->fxn(ctrl->recovery->data,
|
||||
MDP_INTF_DSI_CMD_FIFO_UNDERFLOW);
|
||||
mdss_dsi_clk_ctrl(ctrl, DSI_ALL_CLKS, 0);
|
||||
}
|
||||
mutex_unlock(&ctrl->mutex);
|
||||
|
@ -1677,7 +1858,20 @@ static int dsi_event_thread(void *data)
|
|||
if (todo & DSI_EV_DSI_FIFO_EMPTY)
|
||||
mdss_dsi_sw_reset(ctrl, true);
|
||||
|
||||
if (todo & DSI_EV_DLNx_FIFO_OVERFLOW) {
|
||||
pr_debug("%s: Handling overflow event\n",
|
||||
__func__);
|
||||
mutex_lock(&dsi_mtx);
|
||||
mdss_dsi_clk_ctrl(ctrl, DSI_ALL_CLKS, 1);
|
||||
mdss_dsi_ctl_phy_reset(ctrl);
|
||||
mdss_dsi_err_intr_ctrl(ctrl, DSI_INTR_ERROR_MASK, 1);
|
||||
mdss_dsi_clk_ctrl(ctrl, DSI_ALL_CLKS, 0);
|
||||
mutex_unlock(&dsi_mtx);
|
||||
}
|
||||
|
||||
if (todo & DSI_EV_MDP_BUSY_RELEASE) {
|
||||
pr_debug("%s: Handling MDP_BUSY_RELEASE event\n",
|
||||
__func__);
|
||||
spin_lock_irqsave(&ctrl->mdp_lock, flag);
|
||||
ctrl->mdp_busy = false;
|
||||
mdss_dsi_disable_irq_nosync(ctrl, DSI_MDP_TERM);
|
||||
|
@ -1755,6 +1949,11 @@ void mdss_dsi_fifo_status(struct mdss_dsi_ctrl_pdata *ctrl)
|
|||
if (status & 0xcccc4489) {
|
||||
MIPI_OUTP(base + 0x000c, status);
|
||||
pr_err("%s: status=%x\n", __func__, status);
|
||||
if (status & 0x44440000) {/* DLNx_HS_FIFO_OVERFLOW */
|
||||
dsi_send_events(ctrl, DSI_EV_DLNx_FIFO_OVERFLOW);
|
||||
/* Ignore FIFO EMPTY when overflow happens */
|
||||
status = status & 0xeeeeffff;
|
||||
}
|
||||
if (status & 0x0080) /* CMD_DMA_FIFO_UNDERFLOW */
|
||||
dsi_send_events(ctrl, DSI_EV_MDP_FIFO_UNDERFLOW);
|
||||
if (status & 0x11110000) /* DLN_FIFO_EMPTY */
|
||||
|
|
|
@ -48,7 +48,7 @@ struct mdss_mdp_cmd_ctx {
|
|||
struct work_struct clk_work;
|
||||
struct work_struct pp_done_work;
|
||||
atomic_t pp_done_cnt;
|
||||
struct mdss_panel_recovery recovery;
|
||||
struct mdss_intf_recovery intf_recovery;
|
||||
struct mdss_mdp_cmd_ctx *sync_ctx; /* for partial update */
|
||||
u32 pp_timeout_report_cnt;
|
||||
};
|
||||
|
@ -312,7 +312,7 @@ static void mdss_mdp_cmd_readptr_done(void *arg)
|
|||
spin_unlock(&ctx->clk_lock);
|
||||
}
|
||||
|
||||
static void mdss_mdp_cmd_underflow_recovery(void *data)
|
||||
static void mdss_mdp_cmd_intf_recovery(void *data, int event)
|
||||
{
|
||||
struct mdss_mdp_cmd_ctx *ctx = data;
|
||||
unsigned long flags;
|
||||
|
@ -324,6 +324,18 @@ static void mdss_mdp_cmd_underflow_recovery(void *data)
|
|||
|
||||
if (!ctx->ctl)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Currently, only intf_fifo_underflow is
|
||||
* supported for recovery sequence for command
|
||||
* mode DSI interface
|
||||
*/
|
||||
if (event != MDP_INTF_DSI_CMD_FIFO_UNDERFLOW) {
|
||||
pr_warn("%s: unsupported recovery event:%d\n",
|
||||
__func__, event);
|
||||
return;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&ctx->koff_lock, flags);
|
||||
if (atomic_read(&ctx->koff_cnt)) {
|
||||
mdss_mdp_ctl_reset(ctx->ctl);
|
||||
|
@ -707,7 +719,7 @@ int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg)
|
|||
|
||||
mdss_mdp_ctl_intf_event(ctl,
|
||||
MDSS_EVENT_REGISTER_RECOVERY_HANDLER,
|
||||
(void *)&ctx->recovery);
|
||||
(void *)&ctx->intf_recovery);
|
||||
}
|
||||
|
||||
MDSS_XLOG(ctl->num, ctl->roi.x, ctl->roi.y, ctl->roi.w,
|
||||
|
@ -991,8 +1003,8 @@ static int mdss_mdp_cmd_intfs_setup(struct mdss_mdp_ctl *ctl,
|
|||
atomic_set(&ctx->pp_done_cnt, 0);
|
||||
INIT_LIST_HEAD(&ctx->vsync_handlers);
|
||||
|
||||
ctx->recovery.fxn = mdss_mdp_cmd_underflow_recovery;
|
||||
ctx->recovery.data = ctx;
|
||||
ctx->intf_recovery.fxn = mdss_mdp_cmd_intf_recovery;
|
||||
ctx->intf_recovery.data = ctx;
|
||||
|
||||
pr_debug("%s: ctx=%p num=%d mixer=%d\n", __func__,
|
||||
ctx, ctx->pp_num, mixer->num);
|
||||
|
|
|
@ -27,6 +27,9 @@
|
|||
/* wait for at least 2 vsyncs for lowest refresh rate (24hz) */
|
||||
#define VSYNC_TIMEOUT_US 100000
|
||||
|
||||
/* Poll time to do recovery during active region */
|
||||
#define POLL_TIME_USEC_FOR_LN_CNT 500
|
||||
|
||||
#define MDP_INTR_MASK_INTF_VSYNC(intf_num) \
|
||||
(1 << (2 * (intf_num - MDSS_MDP_INTF0) + MDSS_MDP_IRQ_INTF_VSYNC))
|
||||
|
||||
|
@ -66,6 +69,7 @@ struct mdss_mdp_video_ctx {
|
|||
spinlock_t dfps_lock;
|
||||
struct mutex vsync_mtx;
|
||||
struct list_head vsync_handlers;
|
||||
struct mdss_intf_recovery intf_recovery;
|
||||
};
|
||||
|
||||
static void mdss_mdp_fetch_start_config(struct mdss_mdp_video_ctx *ctx,
|
||||
|
@ -120,6 +124,89 @@ int mdss_mdp_video_addr_setup(struct mdss_data_type *mdata,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void mdss_mdp_video_intf_recovery(void *data, int event)
|
||||
{
|
||||
struct mdss_mdp_video_ctx *ctx;
|
||||
struct mdss_mdp_ctl *ctl = data;
|
||||
struct mdss_panel_info *pinfo;
|
||||
u32 line_cnt, min_ln_cnt, active_lns_cnt;
|
||||
u32 clk_rate, clk_period, time_of_line;
|
||||
u32 delay;
|
||||
|
||||
if (!data) {
|
||||
pr_err("%s: invalid ctl\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Currently, only intf_fifo_overflow is
|
||||
* supported for recovery sequence for video
|
||||
* mode DSI interface
|
||||
*/
|
||||
if (event != MDP_INTF_DSI_VIDEO_FIFO_OVERFLOW) {
|
||||
pr_warn("%s: unsupported recovery event:%d\n",
|
||||
__func__, event);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx = ctl->priv_data;
|
||||
pr_debug("%s: ctl num = %d, event = %d\n",
|
||||
__func__, ctl->num, event);
|
||||
|
||||
pinfo = &ctl->panel_data->panel_info;
|
||||
clk_rate = ((ctl->intf_type == MDSS_INTF_DSI) ?
|
||||
pinfo->mipi.dsi_pclk_rate :
|
||||
pinfo->clk_rate);
|
||||
|
||||
clk_rate /= 1000; /* in kHz */
|
||||
if (!clk_rate) {
|
||||
pr_err("Unable to get proper clk_rate\n");
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* calculate clk_period as pico second to maintain good
|
||||
* accuracy with high pclk rate and this number is in 17 bit
|
||||
* range.
|
||||
*/
|
||||
clk_period = 1000000000 / clk_rate;
|
||||
if (!clk_period) {
|
||||
pr_err("Unable to calculate clock period\n");
|
||||
return;
|
||||
}
|
||||
min_ln_cnt = pinfo->lcdc.v_back_porch + pinfo->lcdc.v_front_porch
|
||||
+ pinfo->lcdc.v_pulse_width;
|
||||
active_lns_cnt = pinfo->yres;
|
||||
time_of_line = (pinfo->lcdc.h_back_porch +
|
||||
pinfo->lcdc.h_front_porch +
|
||||
pinfo->lcdc.h_pulse_width +
|
||||
pinfo->xres) * clk_period;
|
||||
|
||||
/* delay in micro seconds */
|
||||
delay = (time_of_line * min_ln_cnt) / 1000000;
|
||||
|
||||
/*
|
||||
* Wait for max delay before
|
||||
* polling to check active region
|
||||
*/
|
||||
if (delay > POLL_TIME_USEC_FOR_LN_CNT)
|
||||
delay = POLL_TIME_USEC_FOR_LN_CNT;
|
||||
|
||||
while (1) {
|
||||
line_cnt = mdss_mdp_video_line_count(ctl);
|
||||
|
||||
if ((line_cnt >= min_ln_cnt) && (line_cnt < active_lns_cnt)) {
|
||||
pr_debug("%s, Needed lines left line_cnt=%d\n",
|
||||
__func__, line_cnt);
|
||||
return;
|
||||
} else {
|
||||
pr_warn("line count is less. line_cnt = %d\n",
|
||||
line_cnt);
|
||||
/* Add delay so that line count is in active region */
|
||||
udelay(delay);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int mdss_mdp_video_timegen_setup(struct mdss_mdp_ctl *ctl,
|
||||
struct intf_timing_params *p)
|
||||
{
|
||||
|
@ -1047,6 +1134,20 @@ static int mdss_mdp_video_intfs_setup(struct mdss_mdp_ctl *ctl,
|
|||
atomic_set(&ctx->vsync_ref, 0);
|
||||
INIT_WORK(&ctl->recover_work, recover_underrun_work);
|
||||
|
||||
if (ctl->intf_type == MDSS_INTF_DSI) {
|
||||
ctx->intf_recovery.fxn = mdss_mdp_video_intf_recovery;
|
||||
ctx->intf_recovery.data = ctl;
|
||||
if (mdss_mdp_ctl_intf_event(ctl,
|
||||
MDSS_EVENT_REGISTER_RECOVERY_HANDLER,
|
||||
(void *)&ctx->intf_recovery)) {
|
||||
pr_err("Failed to register intf recovery handler\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
ctx->intf_recovery.fxn = NULL;
|
||||
ctx->intf_recovery.data = NULL;
|
||||
}
|
||||
|
||||
mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_INTF_VSYNC,
|
||||
(inum + MDSS_MDP_INTF0),
|
||||
mdss_mdp_video_vsync_intr_done, ctl);
|
||||
|
|
|
@ -125,8 +125,11 @@ struct mdss_panel_cfg {
|
|||
bool init_done;
|
||||
};
|
||||
|
||||
struct mdss_panel_recovery {
|
||||
void (*fxn)(void *ctx);
|
||||
#define MDP_INTF_DSI_CMD_FIFO_UNDERFLOW 0x0001
|
||||
#define MDP_INTF_DSI_VIDEO_FIFO_OVERFLOW 0x0002
|
||||
|
||||
struct mdss_intf_recovery {
|
||||
void (*fxn)(void *ctx, int event);
|
||||
void *data;
|
||||
};
|
||||
|
||||
|
@ -172,6 +175,8 @@ struct mdss_panel_recovery {
|
|||
* based on the dsi mode passed as argument.
|
||||
* - 0: update to video mode
|
||||
* - 1: update to command mode
|
||||
* @MDSS_EVENT_REGISTER_RECOVERY_HANDLER: Event to recover the interface in
|
||||
* case there was any errors detected.
|
||||
*/
|
||||
enum mdss_intf_events {
|
||||
MDSS_EVENT_RESET = 1,
|
||||
|
|
Loading…
Add table
Reference in a new issue