Loading drivers/video/msm/mdss/mdss_dsi.c +1 −0 Original line number Diff line number Diff line Loading @@ -714,6 +714,7 @@ static int mdss_dsi_event_handler(struct mdss_panel_data *pdata, mdss_dsi_clk_req(ctrl_pdata, (int)arg); break; case MDSS_EVENT_DSI_CMDLIST_KOFF: ctrl_pdata->recovery = (struct mdss_panel_recovery *)arg; mdss_dsi_cmdlist_commit(ctrl_pdata, 1); case MDSS_EVENT_PANEL_UPDATE_FPS: if (arg != NULL) { Loading drivers/video/msm/mdss/mdss_dsi.h +6 −1 Original line number Diff line number Diff line Loading @@ -307,6 +307,10 @@ enum { DSI_CTRL_MAX, }; #define DSI_EV_PLL_UNLOCKED 0x0001 #define DSI_EV_MDP_FIFO_UNDERFLOW 0x0002 #define DSI_EV_MDP_BUSY_RELEASE 0x80000000 struct mdss_dsi_ctrl_pdata { int ndx; /* panel_num */ int (*on) (struct mdss_panel_data *pdata); Loading Loading @@ -344,6 +348,7 @@ struct mdss_dsi_ctrl_pdata { struct dss_module_power power_data; u32 dsi_irq_mask; struct mdss_hw *dsi_hw; struct mdss_panel_recovery *recovery; struct dsi_panel_cmds on_cmds; struct dsi_panel_cmds off_cmds; Loading Loading @@ -386,7 +391,7 @@ void mdss_dsi_cmd_mode_ctrl(int enable); void mdp4_dsi_cmd_trigger(void); void mdss_dsi_cmd_mdp_start(struct mdss_dsi_ctrl_pdata *ctrl); void mdss_dsi_cmd_bta_sw_trigger(struct mdss_panel_data *pdata); void mdss_dsi_ack_err_status(unsigned char *dsi_base); void mdss_dsi_ack_err_status(struct mdss_dsi_ctrl_pdata *ctrl); int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable); void mdss_dsi_clk_req(struct mdss_dsi_ctrl_pdata *ctrl, int enable); Loading drivers/video/msm/mdss/mdss_dsi_host.c +218 −20 Original line number Diff line number Diff line Loading @@ -19,11 +19,13 @@ #include <linux/dma-mapping.h> #include <linux/slab.h> #include <linux/iopoll.h> #include <linux/kthread.h> #include <mach/iommu_domains.h> #include "mdss.h" #include "mdss_dsi.h" #include "mdss_panel.h" #define VSYNC_PERIOD 17 Loading @@ -44,6 +46,28 @@ struct mdss_hw mdss_dsi1_hw = { .irq_handler = mdss_dsi_isr, }; #define DSI_EVENT_Q_MAX 4 /* event */ struct dsi_event_q { struct mdss_dsi_ctrl_pdata *ctrl; u32 todo; }; struct mdss_dsi_event { int inited; wait_queue_head_t event_q; u32 event_pndx; u32 event_gndx; struct dsi_event_q todo_list[DSI_EVENT_Q_MAX]; spinlock_t event_lock; }; static struct mdss_dsi_event dsi_event; static int dsi_event_thread(void *data); void mdss_dsi_ctrl_init(struct mdss_dsi_ctrl_pdata *ctrl) { if (ctrl->shared_pdata.broadcast_enable) Loading Loading @@ -80,6 +104,13 @@ void mdss_dsi_ctrl_init(struct mdss_dsi_ctrl_pdata *ctrl) mutex_init(&ctrl->cmd_mutex); mdss_dsi_buf_alloc(&ctrl->tx_buf, SZ_4K); mdss_dsi_buf_alloc(&ctrl->rx_buf, SZ_4K); if (dsi_event.inited == 0) { kthread_run(dsi_event_thread, (void *)&dsi_event, "mdss_dsi_event"); dsi_event.inited = 1; } } void mdss_dsi_clk_req(struct mdss_dsi_ctrl_pdata *ctrl, int enable) Loading @@ -94,6 +125,21 @@ void mdss_dsi_clk_req(struct mdss_dsi_ctrl_pdata *ctrl, int enable) mdss_dsi_clk_ctrl(ctrl, enable); } void mdss_dsi_pll_relock(struct mdss_dsi_ctrl_pdata *ctrl) { int i, cnt; cnt = ctrl->clk_cnt; /* disable dsi clk */ for (i = 0; i < cnt; i++) mdss_dsi_clk_ctrl(ctrl, 0); /* enable dsi clk */ for (i = 0; i < cnt; i++) mdss_dsi_clk_ctrl(ctrl, 1); } void mdss_dsi_enable_irq(struct mdss_dsi_ctrl_pdata *ctrl, u32 term) { unsigned long flags; Loading Loading @@ -942,6 +988,50 @@ void mdss_dsi_sw_reset(struct mdss_panel_data *pdata) wmb(); } void mdss_dsi_sw_reset_restore(struct mdss_dsi_ctrl_pdata *ctrl) { u32 data0, data1; data0 = MIPI_INP(ctrl->ctrl_base + 0x0004); data1 = data0; data1 &= ~0x01; MIPI_OUTP(ctrl->ctrl_base + 0x0004, data1); /* * dsi controller need to be disabled before * clocks turned on */ wmb(); /* make sure dsi contoller is disabled */ /* turn esc, byte, dsi, pclk, sclk, hclk on */ MIPI_OUTP(ctrl->ctrl_base + 0x11c, 0x23f); /* DSI_CLK_CTRL */ wmb(); /* make sure clocks enabled */ /* dsi controller can only be reset while clocks are running */ MIPI_OUTP(ctrl->ctrl_base + 0x118, 0x01); wmb(); /* make sure reset happen */ MIPI_OUTP(ctrl->ctrl_base + 0x118, 0x00); wmb(); /* controller out of reset */ MIPI_OUTP(ctrl->ctrl_base + 0x0004, data0); wmb(); /* make sure dsi controller enabled again */ } void mdss_dsi_err_intr_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, u32 mask, int enable) { u32 intr; intr = MIPI_INP(ctrl->ctrl_base + 0x0110); if (enable) intr |= mask; else intr &= ~mask; pr_debug("%s: intr=%x enable=%d\n", __func__, intr, enable); MIPI_OUTP(ctrl->ctrl_base + 0x0110, intr); /* DSI_INTL_CTRL */ } void mdss_dsi_controller_cfg(int enable, struct mdss_panel_data *pdata) { Loading Loading @@ -1072,7 +1162,7 @@ void mdss_dsi_cmd_bta_sw_trigger(struct mdss_panel_data *pdata) 0, timeout_us)) pr_info("%s: DSI status=%x failed\n", __func__, status); mdss_dsi_ack_err_status((ctrl_pdata->ctrl_base)); mdss_dsi_ack_err_status(ctrl_pdata); pr_debug("%s: BTA done, status = %d\n", __func__, status); } Loading Loading @@ -1756,9 +1846,89 @@ int mdss_dsi_cmdlist_put(struct mdss_dsi_ctrl_pdata *ctrl, return ret; } void mdss_dsi_ack_err_status(unsigned char *base) static void dsi_send_events(struct mdss_dsi_ctrl_pdata *ctrl, u32 events) { struct dsi_event_q *evq; if (!dsi_event.inited) return; pr_debug("%s: ev=%x\n", __func__, events); spin_lock(&dsi_event.event_lock); evq = &dsi_event.todo_list[dsi_event.event_pndx++]; evq->todo = events; evq->ctrl = ctrl; dsi_event.event_pndx %= DSI_EVENT_Q_MAX; wake_up(&dsi_event.event_q); spin_unlock(&dsi_event.event_lock); } static int dsi_event_thread(void *data) { struct mdss_dsi_event *ev; struct dsi_event_q *evq; struct mdss_dsi_ctrl_pdata *ctrl; unsigned long flag; struct sched_param param; u32 todo = 0; int ret; param.sched_priority = 16; ret = sched_setscheduler_nocheck(current, SCHED_FIFO, ¶m); if (ret) pr_err("%s: set priority failed\n", __func__); ev = (struct mdss_dsi_event *)data; /* event */ init_waitqueue_head(&ev->event_q); spin_lock_init(&ev->event_lock); while (1) { wait_event(ev->event_q, (ev->event_pndx != ev->event_gndx)); spin_lock_irqsave(&ev->event_lock, flag); evq = &ev->todo_list[ev->event_gndx++]; todo = evq->todo; ctrl = evq->ctrl; evq->todo = 0; ev->event_gndx %= DSI_EVENT_Q_MAX; spin_unlock_irqrestore(&ev->event_lock, flag); pr_debug("%s: ev=%x\n", __func__, todo); if (todo & DSI_EV_PLL_UNLOCKED) mdss_dsi_pll_relock(ctrl); if (todo & DSI_EV_MDP_FIFO_UNDERFLOW) { if (ctrl->recovery) { mdss_dsi_sw_reset_restore(ctrl); ctrl->recovery->fxn(ctrl->recovery->data); } } if (todo & DSI_EV_MDP_BUSY_RELEASE) { spin_lock(&ctrl->mdp_lock); ctrl->mdp_busy = false; mdss_dsi_disable_irq_nosync(ctrl, DSI_MDP_TERM); complete(&ctrl->mdp_comp); spin_unlock(&ctrl->mdp_lock); /* enable dsi error interrupt */ mdss_dsi_err_intr_ctrl(ctrl, DSI_INTR_ERROR_MASK, 1); } } return 0; } void mdss_dsi_ack_err_status(struct mdss_dsi_ctrl_pdata *ctrl) { u32 status; unsigned char *base; base = ctrl->ctrl_base; status = MIPI_INP(base + 0x0068);/* DSI_ACK_ERR_STATUS */ Loading @@ -1768,20 +1938,27 @@ void mdss_dsi_ack_err_status(unsigned char *base) } } void mdss_dsi_timeout_status(unsigned char *base) void mdss_dsi_timeout_status(struct mdss_dsi_ctrl_pdata *ctrl) { u32 status; unsigned char *base; base = ctrl->ctrl_base; status = MIPI_INP(base + 0x00c0);/* DSI_TIMEOUT_STATUS */ if (status & 0x0111) { MIPI_OUTP(base + 0x00c0, status); pr_err("%s: status=%x\n", __func__, status); } } void mdss_dsi_dln0_phy_err(unsigned char *base) void mdss_dsi_dln0_phy_err(struct mdss_dsi_ctrl_pdata *ctrl) { u32 status; unsigned char *base; base = ctrl->ctrl_base; status = MIPI_INP(base + 0x00b4);/* DSI_DLN0_PHY_ERR */ Loading @@ -1791,44 +1968,70 @@ void mdss_dsi_dln0_phy_err(unsigned char *base) } } void mdss_dsi_fifo_status(unsigned char *base) void mdss_dsi_fifo_status(struct mdss_dsi_ctrl_pdata *ctrl) { u32 status; unsigned char *base; base = ctrl->ctrl_base; status = MIPI_INP(base + 0x000c);/* DSI_FIFO_STATUS */ if (status & 0x44444489) { /* fifo underflow, overflow */ if (status & 0xcccc4489) { MIPI_OUTP(base + 0x000c, status); pr_err("%s: status=%x\n", __func__, status); if (status & 0x0080) /* CMD_DMA_FIFO_UNDERFLOW */ dsi_send_events(ctrl, DSI_EV_MDP_FIFO_UNDERFLOW); } } void mdss_dsi_status(unsigned char *base) void mdss_dsi_status(struct mdss_dsi_ctrl_pdata *ctrl) { u32 status; unsigned char *base; base = ctrl->ctrl_base; status = MIPI_INP(base + 0x0008);/* DSI_STATUS */ if (status & 0x80000000) { if (status & 0x80000000) { /* INTERLEAVE_OP_CONTENTION */ MIPI_OUTP(base + 0x0008, status); pr_err("%s: status=%x\n", __func__, status); } } void mdss_dsi_error(struct mdss_dsi_ctrl_pdata *ctrl) void mdss_dsi_clk_status(struct mdss_dsi_ctrl_pdata *ctrl) { u32 status; unsigned char *base; base = ctrl->ctrl_base; status = MIPI_INP(base + 0x0120);/* DSI_CLK_STATUS */ /* DSI_ERR_INT_MASK0 */ mdss_dsi_ack_err_status(base); /* mask0, 0x01f */ mdss_dsi_timeout_status(base); /* mask0, 0x0e0 */ mdss_dsi_fifo_status(base); /* mask0, 0x133d00 */ mdss_dsi_status(base); /* mask0, 0xc0100 */ mdss_dsi_dln0_phy_err(base); /* mask0, 0x3e00000 */ if (status & 0x10000) { /* DSI_CLK_PLL_UNLOCKED */ MIPI_OUTP(base + 0x0120, status); dsi_send_events(ctrl, DSI_EV_PLL_UNLOCKED); pr_err("%s: status=%x\n", __func__, status); } } void mdss_dsi_error(struct mdss_dsi_ctrl_pdata *ctrl) { /* disable dsi error interrupt */ mdss_dsi_err_intr_ctrl(ctrl, DSI_INTR_ERROR_MASK, 0); /* DSI_ERR_INT_MASK0 */ mdss_dsi_clk_status(ctrl); /* Mask0, 0x10000000 */ mdss_dsi_fifo_status(ctrl); /* mask0, 0x133d00 */ mdss_dsi_ack_err_status(ctrl); /* mask0, 0x01f */ mdss_dsi_timeout_status(ctrl); /* mask0, 0x0e0 */ mdss_dsi_status(ctrl); /* mask0, 0xc0100 */ mdss_dsi_dln0_phy_err(ctrl); /* mask0, 0x3e00000 */ dsi_send_events(ctrl, DSI_EV_MDP_BUSY_RELEASE); } irqreturn_t mdss_dsi_isr(int irq, void *ptr) { Loading Loading @@ -1856,12 +2059,7 @@ irqreturn_t mdss_dsi_isr(int irq, void *ptr) if (isr & DSI_INTR_ERROR) { pr_err("%s: isr=%x %x", __func__, isr, (int)DSI_INTR_ERROR); spin_lock(&ctrl->mdp_lock); ctrl->mdp_busy = false; mdss_dsi_disable_irq_nosync(ctrl, DSI_MDP_TERM); complete(&ctrl->mdp_comp); mdss_dsi_error(ctrl); spin_unlock(&ctrl->mdp_lock); } if (isr & DSI_INTR_VIDEO_DONE) { Loading drivers/video/msm/mdss/mdss_mdp.h +1 −0 Original line number Diff line number Diff line Loading @@ -607,4 +607,5 @@ int mdss_mdp_wb_get_format(struct msm_fb_data_type *mfd, #define mfd_to_wb(mfd) (((struct mdss_overlay_private *)\ (mfd->mdp.private1))->wb) int mdss_mdp_ctl_reset(struct mdss_mdp_ctl *ctl); #endif /* MDSS_MDP_H */ drivers/video/msm/mdss/mdss_mdp_ctl.c +36 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ #include <linux/mutex.h> #include <linux/platform_device.h> #include <linux/dma-mapping.h> #include <linux/delay.h> #include "mdss_fb.h" #include "mdss_mdp.h" Loading Loading @@ -1213,6 +1214,41 @@ int mdss_mdp_ctl_stop(struct mdss_mdp_ctl *ctl) return ret; } /* * mdss_mdp_ctl_reset() - reset mdp ctl path. * @ctl: mdp controller. * this function called when underflow happen, * it will reset mdp ctl path and poll for its completion * * Note: called within atomic context. */ int mdss_mdp_ctl_reset(struct mdss_mdp_ctl *ctl) { u32 status = 1; int cnt = 20; mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_SW_RESET, 1); /* * it takes around 30us to have mdp finish resetting its ctl path * poll every 50us so that reset should be completed at 1st poll */ do { udelay(50); status = mdss_mdp_ctl_read(ctl, MDSS_MDP_REG_CTL_SW_RESET); status &= 0x01; pr_debug("status=%x\n", status); cnt--; if (cnt == 0) { pr_err("timeout\n"); return -EAGAIN; } } while (status); return 0; } static int mdss_mdp_mixer_setup(struct mdss_mdp_ctl *ctl, struct mdss_mdp_mixer *mixer) { Loading Loading
drivers/video/msm/mdss/mdss_dsi.c +1 −0 Original line number Diff line number Diff line Loading @@ -714,6 +714,7 @@ static int mdss_dsi_event_handler(struct mdss_panel_data *pdata, mdss_dsi_clk_req(ctrl_pdata, (int)arg); break; case MDSS_EVENT_DSI_CMDLIST_KOFF: ctrl_pdata->recovery = (struct mdss_panel_recovery *)arg; mdss_dsi_cmdlist_commit(ctrl_pdata, 1); case MDSS_EVENT_PANEL_UPDATE_FPS: if (arg != NULL) { Loading
drivers/video/msm/mdss/mdss_dsi.h +6 −1 Original line number Diff line number Diff line Loading @@ -307,6 +307,10 @@ enum { DSI_CTRL_MAX, }; #define DSI_EV_PLL_UNLOCKED 0x0001 #define DSI_EV_MDP_FIFO_UNDERFLOW 0x0002 #define DSI_EV_MDP_BUSY_RELEASE 0x80000000 struct mdss_dsi_ctrl_pdata { int ndx; /* panel_num */ int (*on) (struct mdss_panel_data *pdata); Loading Loading @@ -344,6 +348,7 @@ struct mdss_dsi_ctrl_pdata { struct dss_module_power power_data; u32 dsi_irq_mask; struct mdss_hw *dsi_hw; struct mdss_panel_recovery *recovery; struct dsi_panel_cmds on_cmds; struct dsi_panel_cmds off_cmds; Loading Loading @@ -386,7 +391,7 @@ void mdss_dsi_cmd_mode_ctrl(int enable); void mdp4_dsi_cmd_trigger(void); void mdss_dsi_cmd_mdp_start(struct mdss_dsi_ctrl_pdata *ctrl); void mdss_dsi_cmd_bta_sw_trigger(struct mdss_panel_data *pdata); void mdss_dsi_ack_err_status(unsigned char *dsi_base); void mdss_dsi_ack_err_status(struct mdss_dsi_ctrl_pdata *ctrl); int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable); void mdss_dsi_clk_req(struct mdss_dsi_ctrl_pdata *ctrl, int enable); Loading
drivers/video/msm/mdss/mdss_dsi_host.c +218 −20 Original line number Diff line number Diff line Loading @@ -19,11 +19,13 @@ #include <linux/dma-mapping.h> #include <linux/slab.h> #include <linux/iopoll.h> #include <linux/kthread.h> #include <mach/iommu_domains.h> #include "mdss.h" #include "mdss_dsi.h" #include "mdss_panel.h" #define VSYNC_PERIOD 17 Loading @@ -44,6 +46,28 @@ struct mdss_hw mdss_dsi1_hw = { .irq_handler = mdss_dsi_isr, }; #define DSI_EVENT_Q_MAX 4 /* event */ struct dsi_event_q { struct mdss_dsi_ctrl_pdata *ctrl; u32 todo; }; struct mdss_dsi_event { int inited; wait_queue_head_t event_q; u32 event_pndx; u32 event_gndx; struct dsi_event_q todo_list[DSI_EVENT_Q_MAX]; spinlock_t event_lock; }; static struct mdss_dsi_event dsi_event; static int dsi_event_thread(void *data); void mdss_dsi_ctrl_init(struct mdss_dsi_ctrl_pdata *ctrl) { if (ctrl->shared_pdata.broadcast_enable) Loading Loading @@ -80,6 +104,13 @@ void mdss_dsi_ctrl_init(struct mdss_dsi_ctrl_pdata *ctrl) mutex_init(&ctrl->cmd_mutex); mdss_dsi_buf_alloc(&ctrl->tx_buf, SZ_4K); mdss_dsi_buf_alloc(&ctrl->rx_buf, SZ_4K); if (dsi_event.inited == 0) { kthread_run(dsi_event_thread, (void *)&dsi_event, "mdss_dsi_event"); dsi_event.inited = 1; } } void mdss_dsi_clk_req(struct mdss_dsi_ctrl_pdata *ctrl, int enable) Loading @@ -94,6 +125,21 @@ void mdss_dsi_clk_req(struct mdss_dsi_ctrl_pdata *ctrl, int enable) mdss_dsi_clk_ctrl(ctrl, enable); } void mdss_dsi_pll_relock(struct mdss_dsi_ctrl_pdata *ctrl) { int i, cnt; cnt = ctrl->clk_cnt; /* disable dsi clk */ for (i = 0; i < cnt; i++) mdss_dsi_clk_ctrl(ctrl, 0); /* enable dsi clk */ for (i = 0; i < cnt; i++) mdss_dsi_clk_ctrl(ctrl, 1); } void mdss_dsi_enable_irq(struct mdss_dsi_ctrl_pdata *ctrl, u32 term) { unsigned long flags; Loading Loading @@ -942,6 +988,50 @@ void mdss_dsi_sw_reset(struct mdss_panel_data *pdata) wmb(); } void mdss_dsi_sw_reset_restore(struct mdss_dsi_ctrl_pdata *ctrl) { u32 data0, data1; data0 = MIPI_INP(ctrl->ctrl_base + 0x0004); data1 = data0; data1 &= ~0x01; MIPI_OUTP(ctrl->ctrl_base + 0x0004, data1); /* * dsi controller need to be disabled before * clocks turned on */ wmb(); /* make sure dsi contoller is disabled */ /* turn esc, byte, dsi, pclk, sclk, hclk on */ MIPI_OUTP(ctrl->ctrl_base + 0x11c, 0x23f); /* DSI_CLK_CTRL */ wmb(); /* make sure clocks enabled */ /* dsi controller can only be reset while clocks are running */ MIPI_OUTP(ctrl->ctrl_base + 0x118, 0x01); wmb(); /* make sure reset happen */ MIPI_OUTP(ctrl->ctrl_base + 0x118, 0x00); wmb(); /* controller out of reset */ MIPI_OUTP(ctrl->ctrl_base + 0x0004, data0); wmb(); /* make sure dsi controller enabled again */ } void mdss_dsi_err_intr_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, u32 mask, int enable) { u32 intr; intr = MIPI_INP(ctrl->ctrl_base + 0x0110); if (enable) intr |= mask; else intr &= ~mask; pr_debug("%s: intr=%x enable=%d\n", __func__, intr, enable); MIPI_OUTP(ctrl->ctrl_base + 0x0110, intr); /* DSI_INTL_CTRL */ } void mdss_dsi_controller_cfg(int enable, struct mdss_panel_data *pdata) { Loading Loading @@ -1072,7 +1162,7 @@ void mdss_dsi_cmd_bta_sw_trigger(struct mdss_panel_data *pdata) 0, timeout_us)) pr_info("%s: DSI status=%x failed\n", __func__, status); mdss_dsi_ack_err_status((ctrl_pdata->ctrl_base)); mdss_dsi_ack_err_status(ctrl_pdata); pr_debug("%s: BTA done, status = %d\n", __func__, status); } Loading Loading @@ -1756,9 +1846,89 @@ int mdss_dsi_cmdlist_put(struct mdss_dsi_ctrl_pdata *ctrl, return ret; } void mdss_dsi_ack_err_status(unsigned char *base) static void dsi_send_events(struct mdss_dsi_ctrl_pdata *ctrl, u32 events) { struct dsi_event_q *evq; if (!dsi_event.inited) return; pr_debug("%s: ev=%x\n", __func__, events); spin_lock(&dsi_event.event_lock); evq = &dsi_event.todo_list[dsi_event.event_pndx++]; evq->todo = events; evq->ctrl = ctrl; dsi_event.event_pndx %= DSI_EVENT_Q_MAX; wake_up(&dsi_event.event_q); spin_unlock(&dsi_event.event_lock); } static int dsi_event_thread(void *data) { struct mdss_dsi_event *ev; struct dsi_event_q *evq; struct mdss_dsi_ctrl_pdata *ctrl; unsigned long flag; struct sched_param param; u32 todo = 0; int ret; param.sched_priority = 16; ret = sched_setscheduler_nocheck(current, SCHED_FIFO, ¶m); if (ret) pr_err("%s: set priority failed\n", __func__); ev = (struct mdss_dsi_event *)data; /* event */ init_waitqueue_head(&ev->event_q); spin_lock_init(&ev->event_lock); while (1) { wait_event(ev->event_q, (ev->event_pndx != ev->event_gndx)); spin_lock_irqsave(&ev->event_lock, flag); evq = &ev->todo_list[ev->event_gndx++]; todo = evq->todo; ctrl = evq->ctrl; evq->todo = 0; ev->event_gndx %= DSI_EVENT_Q_MAX; spin_unlock_irqrestore(&ev->event_lock, flag); pr_debug("%s: ev=%x\n", __func__, todo); if (todo & DSI_EV_PLL_UNLOCKED) mdss_dsi_pll_relock(ctrl); if (todo & DSI_EV_MDP_FIFO_UNDERFLOW) { if (ctrl->recovery) { mdss_dsi_sw_reset_restore(ctrl); ctrl->recovery->fxn(ctrl->recovery->data); } } if (todo & DSI_EV_MDP_BUSY_RELEASE) { spin_lock(&ctrl->mdp_lock); ctrl->mdp_busy = false; mdss_dsi_disable_irq_nosync(ctrl, DSI_MDP_TERM); complete(&ctrl->mdp_comp); spin_unlock(&ctrl->mdp_lock); /* enable dsi error interrupt */ mdss_dsi_err_intr_ctrl(ctrl, DSI_INTR_ERROR_MASK, 1); } } return 0; } void mdss_dsi_ack_err_status(struct mdss_dsi_ctrl_pdata *ctrl) { u32 status; unsigned char *base; base = ctrl->ctrl_base; status = MIPI_INP(base + 0x0068);/* DSI_ACK_ERR_STATUS */ Loading @@ -1768,20 +1938,27 @@ void mdss_dsi_ack_err_status(unsigned char *base) } } void mdss_dsi_timeout_status(unsigned char *base) void mdss_dsi_timeout_status(struct mdss_dsi_ctrl_pdata *ctrl) { u32 status; unsigned char *base; base = ctrl->ctrl_base; status = MIPI_INP(base + 0x00c0);/* DSI_TIMEOUT_STATUS */ if (status & 0x0111) { MIPI_OUTP(base + 0x00c0, status); pr_err("%s: status=%x\n", __func__, status); } } void mdss_dsi_dln0_phy_err(unsigned char *base) void mdss_dsi_dln0_phy_err(struct mdss_dsi_ctrl_pdata *ctrl) { u32 status; unsigned char *base; base = ctrl->ctrl_base; status = MIPI_INP(base + 0x00b4);/* DSI_DLN0_PHY_ERR */ Loading @@ -1791,44 +1968,70 @@ void mdss_dsi_dln0_phy_err(unsigned char *base) } } void mdss_dsi_fifo_status(unsigned char *base) void mdss_dsi_fifo_status(struct mdss_dsi_ctrl_pdata *ctrl) { u32 status; unsigned char *base; base = ctrl->ctrl_base; status = MIPI_INP(base + 0x000c);/* DSI_FIFO_STATUS */ if (status & 0x44444489) { /* fifo underflow, overflow */ if (status & 0xcccc4489) { MIPI_OUTP(base + 0x000c, status); pr_err("%s: status=%x\n", __func__, status); if (status & 0x0080) /* CMD_DMA_FIFO_UNDERFLOW */ dsi_send_events(ctrl, DSI_EV_MDP_FIFO_UNDERFLOW); } } void mdss_dsi_status(unsigned char *base) void mdss_dsi_status(struct mdss_dsi_ctrl_pdata *ctrl) { u32 status; unsigned char *base; base = ctrl->ctrl_base; status = MIPI_INP(base + 0x0008);/* DSI_STATUS */ if (status & 0x80000000) { if (status & 0x80000000) { /* INTERLEAVE_OP_CONTENTION */ MIPI_OUTP(base + 0x0008, status); pr_err("%s: status=%x\n", __func__, status); } } void mdss_dsi_error(struct mdss_dsi_ctrl_pdata *ctrl) void mdss_dsi_clk_status(struct mdss_dsi_ctrl_pdata *ctrl) { u32 status; unsigned char *base; base = ctrl->ctrl_base; status = MIPI_INP(base + 0x0120);/* DSI_CLK_STATUS */ /* DSI_ERR_INT_MASK0 */ mdss_dsi_ack_err_status(base); /* mask0, 0x01f */ mdss_dsi_timeout_status(base); /* mask0, 0x0e0 */ mdss_dsi_fifo_status(base); /* mask0, 0x133d00 */ mdss_dsi_status(base); /* mask0, 0xc0100 */ mdss_dsi_dln0_phy_err(base); /* mask0, 0x3e00000 */ if (status & 0x10000) { /* DSI_CLK_PLL_UNLOCKED */ MIPI_OUTP(base + 0x0120, status); dsi_send_events(ctrl, DSI_EV_PLL_UNLOCKED); pr_err("%s: status=%x\n", __func__, status); } } void mdss_dsi_error(struct mdss_dsi_ctrl_pdata *ctrl) { /* disable dsi error interrupt */ mdss_dsi_err_intr_ctrl(ctrl, DSI_INTR_ERROR_MASK, 0); /* DSI_ERR_INT_MASK0 */ mdss_dsi_clk_status(ctrl); /* Mask0, 0x10000000 */ mdss_dsi_fifo_status(ctrl); /* mask0, 0x133d00 */ mdss_dsi_ack_err_status(ctrl); /* mask0, 0x01f */ mdss_dsi_timeout_status(ctrl); /* mask0, 0x0e0 */ mdss_dsi_status(ctrl); /* mask0, 0xc0100 */ mdss_dsi_dln0_phy_err(ctrl); /* mask0, 0x3e00000 */ dsi_send_events(ctrl, DSI_EV_MDP_BUSY_RELEASE); } irqreturn_t mdss_dsi_isr(int irq, void *ptr) { Loading Loading @@ -1856,12 +2059,7 @@ irqreturn_t mdss_dsi_isr(int irq, void *ptr) if (isr & DSI_INTR_ERROR) { pr_err("%s: isr=%x %x", __func__, isr, (int)DSI_INTR_ERROR); spin_lock(&ctrl->mdp_lock); ctrl->mdp_busy = false; mdss_dsi_disable_irq_nosync(ctrl, DSI_MDP_TERM); complete(&ctrl->mdp_comp); mdss_dsi_error(ctrl); spin_unlock(&ctrl->mdp_lock); } if (isr & DSI_INTR_VIDEO_DONE) { Loading
drivers/video/msm/mdss/mdss_mdp.h +1 −0 Original line number Diff line number Diff line Loading @@ -607,4 +607,5 @@ int mdss_mdp_wb_get_format(struct msm_fb_data_type *mfd, #define mfd_to_wb(mfd) (((struct mdss_overlay_private *)\ (mfd->mdp.private1))->wb) int mdss_mdp_ctl_reset(struct mdss_mdp_ctl *ctl); #endif /* MDSS_MDP_H */
drivers/video/msm/mdss/mdss_mdp_ctl.c +36 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ #include <linux/mutex.h> #include <linux/platform_device.h> #include <linux/dma-mapping.h> #include <linux/delay.h> #include "mdss_fb.h" #include "mdss_mdp.h" Loading Loading @@ -1213,6 +1214,41 @@ int mdss_mdp_ctl_stop(struct mdss_mdp_ctl *ctl) return ret; } /* * mdss_mdp_ctl_reset() - reset mdp ctl path. * @ctl: mdp controller. * this function called when underflow happen, * it will reset mdp ctl path and poll for its completion * * Note: called within atomic context. */ int mdss_mdp_ctl_reset(struct mdss_mdp_ctl *ctl) { u32 status = 1; int cnt = 20; mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_SW_RESET, 1); /* * it takes around 30us to have mdp finish resetting its ctl path * poll every 50us so that reset should be completed at 1st poll */ do { udelay(50); status = mdss_mdp_ctl_read(ctl, MDSS_MDP_REG_CTL_SW_RESET); status &= 0x01; pr_debug("status=%x\n", status); cnt--; if (cnt == 0) { pr_err("timeout\n"); return -EAGAIN; } } while (status); return 0; } static int mdss_mdp_mixer_setup(struct mdss_mdp_ctl *ctl, struct mdss_mdp_mixer *mixer) { Loading