Loading drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c +6 −0 Original line number Diff line number Diff line Loading @@ -62,6 +62,11 @@ static void dsi_catalog_cmn_init(struct dsi_ctrl_hw *ctrl, ctrl->ops.debug_bus = dsi_ctrl_hw_cmn_debug_bus; ctrl->ops.get_cmd_read_data = dsi_ctrl_hw_cmn_get_cmd_read_data; ctrl->ops.clear_rdbk_register = dsi_ctrl_hw_cmn_clear_rdbk_reg; ctrl->ops.ctrl_reset = dsi_ctrl_hw_cmn_ctrl_reset; ctrl->ops.mask_error_intr = dsi_ctrl_hw_cmn_mask_error_intr; ctrl->ops.error_intr_ctrl = dsi_ctrl_hw_cmn_error_intr_ctrl; ctrl->ops.get_error_mask = dsi_ctrl_hw_cmn_get_error_mask; ctrl->ops.get_hw_version = dsi_ctrl_hw_cmn_get_hw_version; switch (version) { case DSI_CTRL_VERSION_1_4: Loading Loading @@ -203,6 +208,7 @@ static void dsi_catalog_phy_3_0_init(struct dsi_phy_hw *phy) phy->ops.ulps_ops.is_lanes_in_ulps = dsi_phy_hw_v3_0_is_lanes_in_ulps; phy->ops.phy_timing_val = dsi_phy_hw_timing_val_v3_0; phy->ops.phy_lane_reset = dsi_phy_hw_v3_0_lane_reset; } /** Loading drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h +8 −0 Original line number Diff line number Diff line Loading @@ -102,6 +102,7 @@ u32 dsi_phy_hw_v3_0_get_lanes_in_ulps(struct dsi_phy_hw *phy); bool dsi_phy_hw_v3_0_is_lanes_in_ulps(u32 lanes, u32 ulps_lanes); int dsi_phy_hw_timing_val_v3_0(struct dsi_phy_per_lane_cfgs *timing_cfg, u32 *timing_val, u32 size); int dsi_phy_hw_v3_0_lane_reset(struct dsi_phy_hw *phy); /* DSI controller common ops */ u32 dsi_ctrl_hw_cmn_get_interrupt_status(struct dsi_ctrl_hw *ctrl); Loading Loading @@ -178,6 +179,13 @@ u32 dsi_ctrl_hw_cmn_get_cmd_read_data(struct dsi_ctrl_hw *ctrl, u32 pkt_size, u32 *hw_read_cnt); void dsi_ctrl_hw_cmn_clear_rdbk_reg(struct dsi_ctrl_hw *ctrl); void dsi_ctrl_hw_22_schedule_dma_cmd(struct dsi_ctrl_hw *ctrl, int line_on); int dsi_ctrl_hw_cmn_ctrl_reset(struct dsi_ctrl_hw *ctrl, int mask); void dsi_ctrl_hw_cmn_mask_error_intr(struct dsi_ctrl_hw *ctrl, u32 idx, bool en); void dsi_ctrl_hw_cmn_error_intr_ctrl(struct dsi_ctrl_hw *ctrl, bool en); u32 dsi_ctrl_hw_cmn_get_error_mask(struct dsi_ctrl_hw *ctrl); u32 dsi_ctrl_hw_cmn_get_hw_version(struct dsi_ctrl_hw *ctrl); /* Definitions specific to 1.4 DSI controller hardware */ int dsi_ctrl_hw_14_wait_for_lane_idle(struct dsi_ctrl_hw *ctrl, u32 lanes); Loading drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c +135 −40 Original line number Diff line number Diff line Loading @@ -1041,6 +1041,9 @@ static int dsi_message_tx(struct dsi_ctrl *dsi_ctrl, dsi_ctrl_wait_for_video_done(dsi_ctrl); dsi_ctrl_enable_status_interrupt(dsi_ctrl, DSI_SINT_CMD_MODE_DMA_DONE, NULL); if (dsi_ctrl->hw.ops.mask_error_intr) dsi_ctrl->hw.ops.mask_error_intr(&dsi_ctrl->hw, BIT(DSI_FIFO_OVERFLOW), true); reinit_completion(&dsi_ctrl->irq_info.cmd_dma_done); if (flags & DSI_CTRL_CMD_FETCH_MEMORY) { Loading Loading @@ -1081,6 +1084,9 @@ static int dsi_message_tx(struct dsi_ctrl *dsi_ctrl, } } if (dsi_ctrl->hw.ops.mask_error_intr) dsi_ctrl->hw.ops.mask_error_intr(&dsi_ctrl->hw, BIT(DSI_FIFO_OVERFLOW), false); dsi_ctrl->hw.ops.reset_cmd_fifo(&dsi_ctrl->hw); } error: Loading Loading @@ -1945,7 +1951,7 @@ int dsi_ctrl_setup(struct dsi_ctrl *dsi_ctrl) } dsi_ctrl->hw.ops.enable_status_interrupts(&dsi_ctrl->hw, 0x0); dsi_ctrl->hw.ops.enable_error_interrupts(&dsi_ctrl->hw, 0x0); dsi_ctrl->hw.ops.enable_error_interrupts(&dsi_ctrl->hw, 0xFF00E0); dsi_ctrl->hw.ops.ctrl_en(&dsi_ctrl->hw, true); mutex_unlock(&dsi_ctrl->ctrl_lock); Loading Loading @@ -1996,33 +2002,77 @@ int dsi_ctrl_phy_reset_config(struct dsi_ctrl *dsi_ctrl, bool enable) static void dsi_ctrl_handle_error_status(struct dsi_ctrl *dsi_ctrl, unsigned long int error) { pr_err("%s: %lu\n", __func__, error); struct dsi_event_cb_info cb_info; /* DTLN PHY error */ if (error & 0x3000e00) cb_info = dsi_ctrl->irq_info.irq_err_cb; /* disable error interrupts */ if (dsi_ctrl->hw.ops.error_intr_ctrl) dsi_ctrl->hw.ops.error_intr_ctrl(&dsi_ctrl->hw, false); /* clear error interrupts first */ if (dsi_ctrl->hw.ops.clear_error_status) dsi_ctrl->hw.ops.clear_error_status(&dsi_ctrl->hw, 0x3000e00); error); /* DTLN PHY error */ if (error & 0x3000E00) pr_err("dsi PHY contention error: 0x%lx\n", error); /* TX timeout error */ if (error & 0xE0) { if (error & 0xA0) { if (cb_info.event_cb) { cb_info.event_idx = DSI_LP_Rx_TIMEOUT; (void)cb_info.event_cb(cb_info.event_usr_ptr, cb_info.event_idx, dsi_ctrl->cell_index, 0, 0, 0, 0); } } pr_err("tx timeout error: 0x%lx\n", error); } /* DSI FIFO OVERFLOW error */ if (error & 0xf0000) { if (dsi_ctrl->hw.ops.clear_error_status) dsi_ctrl->hw.ops.clear_error_status(&dsi_ctrl->hw, 0xf0000); if (error & 0xF0000) { u32 mask = 0; if (dsi_ctrl->hw.ops.get_error_mask) mask = dsi_ctrl->hw.ops.get_error_mask(&dsi_ctrl->hw); /* no need to report FIFO overflow if already masked */ if (cb_info.event_cb && !(mask & 0xf0000)) { cb_info.event_idx = DSI_FIFO_OVERFLOW; (void)cb_info.event_cb(cb_info.event_usr_ptr, cb_info.event_idx, dsi_ctrl->cell_index, 0, 0, 0, 0); pr_err("dsi FIFO OVERFLOW error: 0x%lx\n", error); } } /* DSI FIFO UNDERFLOW error */ if (error & 0xf00000) { if (dsi_ctrl->hw.ops.clear_error_status) dsi_ctrl->hw.ops.clear_error_status(&dsi_ctrl->hw, 0xf00000); if (error & 0xF00000) { if (cb_info.event_cb) { cb_info.event_idx = DSI_FIFO_UNDERFLOW; (void)cb_info.event_cb(cb_info.event_usr_ptr, cb_info.event_idx, dsi_ctrl->cell_index, 0, 0, 0, 0); } pr_err("dsi FIFO UNDERFLOW error: 0x%lx\n", error); } /* DSI PLL UNLOCK error */ if (error & BIT(8)) if (dsi_ctrl->hw.ops.clear_error_status) dsi_ctrl->hw.ops.clear_error_status(&dsi_ctrl->hw, BIT(8)); pr_err("dsi PLL unlock error: 0x%lx\n", error); /* ACK error */ if (error & 0xF) pr_err("ack error: 0x%lx\n", error); /* enable back DSI interrupts */ if (dsi_ctrl->hw.ops.error_intr_ctrl) dsi_ctrl->hw.ops.error_intr_ctrl(&dsi_ctrl->hw, true); } /** Loading @@ -2036,39 +2086,28 @@ static irqreturn_t dsi_ctrl_isr(int irq, void *ptr) struct dsi_ctrl *dsi_ctrl; struct dsi_event_cb_info cb_info; unsigned long flags; uint32_t cell_index, status, i; uint64_t errors; uint32_t status = 0x0, i; uint64_t errors = 0x0; if (!ptr) return IRQ_NONE; dsi_ctrl = ptr; /* clear status interrupts */ /* check status interrupts */ if (dsi_ctrl->hw.ops.get_interrupt_status) status = dsi_ctrl->hw.ops.get_interrupt_status(&dsi_ctrl->hw); else status = 0x0; if (dsi_ctrl->hw.ops.clear_interrupt_status) dsi_ctrl->hw.ops.clear_interrupt_status(&dsi_ctrl->hw, status); spin_lock_irqsave(&dsi_ctrl->irq_info.irq_lock, flags); cell_index = dsi_ctrl->cell_index; spin_unlock_irqrestore(&dsi_ctrl->irq_info.irq_lock, flags); /* clear error interrupts */ /* check error interrupts */ if (dsi_ctrl->hw.ops.get_error_status) errors = dsi_ctrl->hw.ops.get_error_status(&dsi_ctrl->hw); else errors = 0x0; if (errors) { /* clear interrupts */ if (dsi_ctrl->hw.ops.clear_interrupt_status) dsi_ctrl->hw.ops.clear_interrupt_status(&dsi_ctrl->hw, 0x0); /* handle DSI error recovery */ if (status & DSI_ERROR) dsi_ctrl_handle_error_status(dsi_ctrl, errors); if (dsi_ctrl->hw.ops.clear_error_status) dsi_ctrl->hw.ops.clear_error_status(&dsi_ctrl->hw, errors); } if (status & DSI_CMD_MODE_DMA_DONE) { dsi_ctrl_disable_status_interrupt(dsi_ctrl, Loading @@ -2089,9 +2128,16 @@ static irqreturn_t dsi_ctrl_isr(int irq, void *ptr) } if (status & DSI_BTA_DONE) { u32 fifo_overflow_mask = (DSI_DLN0_HS_FIFO_OVERFLOW | DSI_DLN1_HS_FIFO_OVERFLOW | DSI_DLN2_HS_FIFO_OVERFLOW | DSI_DLN3_HS_FIFO_OVERFLOW); dsi_ctrl_disable_status_interrupt(dsi_ctrl, DSI_SINT_BTA_DONE); complete_all(&dsi_ctrl->irq_info.bta_done); if (dsi_ctrl->hw.ops.clear_error_status) dsi_ctrl->hw.ops.clear_error_status(&dsi_ctrl->hw, fifo_overflow_mask); } for (i = 0; status && i < DSI_STATUS_INTERRUPT_COUNT; ++i) { Loading @@ -2104,7 +2150,8 @@ static irqreturn_t dsi_ctrl_isr(int irq, void *ptr) if (cb_info.event_cb) (void)cb_info.event_cb(cb_info.event_usr_ptr, cb_info.event_idx, cell_index, irq, 0, 0, 0); dsi_ctrl->cell_index, irq, 0, 0, 0); } status >>= 1; } Loading Loading @@ -2314,7 +2361,7 @@ int dsi_ctrl_host_init(struct dsi_ctrl *dsi_ctrl, bool is_splash_enabled) dsi_ctrl_setup_isr(dsi_ctrl); dsi_ctrl->hw.ops.enable_status_interrupts(&dsi_ctrl->hw, 0x0); dsi_ctrl->hw.ops.enable_error_interrupts(&dsi_ctrl->hw, 0x0); dsi_ctrl->hw.ops.enable_error_interrupts(&dsi_ctrl->hw, 0xFF00E0); pr_debug("[DSI_%d]Host initialization complete, continuous splash status:%d\n", dsi_ctrl->cell_index, is_splash_enabled); Loading @@ -2337,6 +2384,48 @@ int dsi_ctrl_soft_reset(struct dsi_ctrl *dsi_ctrl) return 0; } int dsi_ctrl_reset(struct dsi_ctrl *dsi_ctrl, int mask) { int rc = 0; if (!dsi_ctrl) return -EINVAL; mutex_lock(&dsi_ctrl->ctrl_lock); rc = dsi_ctrl->hw.ops.ctrl_reset(&dsi_ctrl->hw, mask); mutex_unlock(&dsi_ctrl->ctrl_lock); return rc; } int dsi_ctrl_get_hw_version(struct dsi_ctrl *dsi_ctrl) { int rc = 0; if (!dsi_ctrl) return -EINVAL; mutex_lock(&dsi_ctrl->ctrl_lock); rc = dsi_ctrl->hw.ops.get_hw_version(&dsi_ctrl->hw); mutex_unlock(&dsi_ctrl->ctrl_lock); return rc; } int dsi_ctrl_vid_engine_en(struct dsi_ctrl *dsi_ctrl, bool on) { int rc = 0; if (!dsi_ctrl) return -EINVAL; mutex_lock(&dsi_ctrl->ctrl_lock); dsi_ctrl->hw.ops.video_engine_en(&dsi_ctrl->hw, on); mutex_unlock(&dsi_ctrl->ctrl_lock); return rc; } /** * dsi_ctrl_host_deinit() - De-Initialize DSI host hardware. * @dsi_ctrl: DSI controller handle. Loading Loading @@ -2538,6 +2627,9 @@ int dsi_ctrl_cmd_tx_trigger(struct dsi_ctrl *dsi_ctrl, u32 flags) dsi_ctrl_wait_for_video_done(dsi_ctrl); dsi_ctrl_enable_status_interrupt(dsi_ctrl, DSI_SINT_CMD_MODE_DMA_DONE, NULL); if (dsi_ctrl->hw.ops.mask_error_intr) dsi_ctrl->hw.ops.mask_error_intr(&dsi_ctrl->hw, BIT(DSI_FIFO_OVERFLOW), true); reinit_completion(&dsi_ctrl->irq_info.cmd_dma_done); /* trigger command */ Loading Loading @@ -2568,6 +2660,9 @@ int dsi_ctrl_cmd_tx_trigger(struct dsi_ctrl *dsi_ctrl, u32 flags) dsi_ctrl->cell_index); } } if (dsi_ctrl->hw.ops.mask_error_intr) dsi_ctrl->hw.ops.mask_error_intr(&dsi_ctrl->hw, BIT(DSI_FIFO_OVERFLOW), false); } mutex_unlock(&dsi_ctrl->ctrl_lock); Loading drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h +24 −0 Original line number Diff line number Diff line Loading @@ -146,6 +146,7 @@ struct dsi_ctrl_state_info { * @irq_stat_mask: Hardware mask of currently enabled interrupts. * @irq_stat_refcount: Number of times each interrupt has been requested. * @irq_stat_cb: Status IRQ callback definitions. * @irq_err_cb: IRQ callback definition to handle DSI ERRORs. * @cmd_dma_done: Completion signal for DSI_CMD_MODE_DMA_DONE interrupt * @vid_frame_done: Completion signal for DSI_VIDEO_MODE_FRAME_DONE int. * @cmd_frame_done: Completion signal for DSI_CMD_FRAME_DONE interrupt. Loading @@ -156,6 +157,7 @@ struct dsi_ctrl_interrupts { uint32_t irq_stat_mask; int irq_stat_refcount[DSI_STATUS_INTERRUPT_COUNT]; struct dsi_event_cb_info irq_stat_cb[DSI_STATUS_INTERRUPT_COUNT]; struct dsi_event_cb_info irq_err_cb; struct completion cmd_dma_done; struct completion vid_frame_done; Loading @@ -177,6 +179,7 @@ struct dsi_ctrl_interrupts { * @current_state: Current driver and hardware state. * @clk_cb: Callback for DSI clock control. * @irq_info: Interrupt information. * @recovery_cb: Recovery call back to SDE. * @clk_info: Clock information. * @clk_freq: DSi Link clock frequency information. * @pwr_info: Power information. Loading Loading @@ -215,6 +218,7 @@ struct dsi_ctrl { struct clk_ctrl_cb clk_cb; struct dsi_ctrl_interrupts irq_info; struct dsi_event_cb_info recovery_cb; /* Clock and power states */ struct dsi_ctrl_clk_info clk_info; Loading Loading @@ -651,4 +655,24 @@ void dsi_ctrl_drv_register(void); */ void dsi_ctrl_drv_unregister(void); /** * dsi_ctrl_reset() - Reset DSI PHY CLK/DATA lane * @dsi_ctrl: DSI controller handle. * @mask: Mask to indicate if CLK and/or DATA lane needs reset. */ int dsi_ctrl_reset(struct dsi_ctrl *dsi_ctrl, int mask); /** * dsi_ctrl_get_hw_version() - read dsi controller hw revision * @dsi_ctrl: DSI controller handle. */ int dsi_ctrl_get_hw_version(struct dsi_ctrl *dsi_ctrl); /** * dsi_ctrl_vid_engine_en() - Control DSI video engine HW state * @dsi_ctrl: DSI controller handle. * @on: variable to control video engine ON/OFF. */ int dsi_ctrl_vid_engine_en(struct dsi_ctrl *dsi_ctrl, bool on); #endif /* _DSI_CTRL_H_ */ drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h +43 −1 Original line number Diff line number Diff line Loading @@ -96,6 +96,7 @@ enum dsi_test_pattern { * @DSI_SINT_DESKEW_DONE: The deskew calibration operation done. * @DSI_SINT_DYN_BLANK_DMA_DONE: The dynamic blankin DMA operation has * completed. * @DSI_SINT_ERROR: DSI error has happened. */ enum dsi_status_int_index { DSI_SINT_CMD_MODE_DMA_DONE = 0, Loading @@ -108,6 +109,7 @@ enum dsi_status_int_index { DSI_SINT_DYN_REFRESH_DONE = 7, DSI_SINT_DESKEW_DONE = 8, DSI_SINT_DYN_BLANK_DMA_DONE = 9, DSI_SINT_ERROR = 10, DSI_STATUS_INTERRUPT_COUNT }; Loading @@ -126,6 +128,7 @@ enum dsi_status_int_index { * @DSI_DESKEW_DONE: The deskew calibration operation has completed * @DSI_DYN_BLANK_DMA_DONE: The dynamic blankin DMA operation has * completed. * @DSI_ERROR: DSI error has happened. */ enum dsi_status_int_type { DSI_CMD_MODE_DMA_DONE = BIT(DSI_SINT_CMD_MODE_DMA_DONE), Loading @@ -137,7 +140,8 @@ enum dsi_status_int_type { DSI_CMD_FRAME_DONE = BIT(DSI_SINT_CMD_FRAME_DONE), DSI_DYN_REFRESH_DONE = BIT(DSI_SINT_DYN_REFRESH_DONE), DSI_DESKEW_DONE = BIT(DSI_SINT_DESKEW_DONE), DSI_DYN_BLANK_DMA_DONE = BIT(DSI_SINT_DYN_BLANK_DMA_DONE) DSI_DYN_BLANK_DMA_DONE = BIT(DSI_SINT_DYN_BLANK_DMA_DONE), DSI_ERROR = BIT(DSI_SINT_ERROR) }; /** Loading Loading @@ -175,6 +179,7 @@ enum dsi_status_int_type { * @DSI_EINT_DLN1_LP1_CONTENTION: PHY level contention while lane 1 high. * @DSI_EINT_DLN2_LP1_CONTENTION: PHY level contention while lane 2 high. * @DSI_EINT_DLN3_LP1_CONTENTION: PHY level contention while lane 3 high. * @DSI_EINT_PANEL_SPECIFIC_ERR: DSI Protocol violation error. */ enum dsi_error_int_index { DSI_EINT_RDBK_SINGLE_ECC_ERR = 0, Loading Loading @@ -209,6 +214,7 @@ enum dsi_error_int_index { DSI_EINT_DLN1_LP1_CONTENTION = 29, DSI_EINT_DLN2_LP1_CONTENTION = 30, DSI_EINT_DLN3_LP1_CONTENTION = 31, DSI_EINT_PANEL_SPECIFIC_ERR = 32, DSI_ERROR_INTERRUPT_COUNT }; Loading Loading @@ -248,6 +254,7 @@ enum dsi_error_int_index { * @DSI_DLN1_LP1_CONTENTION: PHY level contention while lane 1 is high. * @DSI_DLN2_LP1_CONTENTION: PHY level contention while lane 2 is high. * @DSI_DLN3_LP1_CONTENTION: PHY level contention while lane 3 is high. * @DSI_PANEL_SPECIFIC_ERR: DSI Protocol violation. */ enum dsi_error_int_type { DSI_RDBK_SINGLE_ECC_ERR = BIT(DSI_EINT_RDBK_SINGLE_ECC_ERR), Loading Loading @@ -282,6 +289,7 @@ enum dsi_error_int_type { DSI_DLN1_LP1_CONTENTION = BIT(DSI_EINT_DLN1_LP1_CONTENTION), DSI_DLN2_LP1_CONTENTION = BIT(DSI_EINT_DLN2_LP1_CONTENTION), DSI_DLN3_LP1_CONTENTION = BIT(DSI_EINT_DLN3_LP1_CONTENTION), DSI_PANEL_SPECIFIC_ERR = BIT(DSI_EINT_PANEL_SPECIFIC_ERR), }; /** Loading Loading @@ -735,6 +743,40 @@ struct dsi_ctrl_hw_ops { * needs to be sent. */ void (*schedule_dma_cmd)(struct dsi_ctrl_hw *ctrl, int line_no); /** * ctrl_reset() - Reset DSI lanes to recover from DSI errors * @ctrl: Pointer to the controller host hardware. * @mask: Indicates the error type. */ int (*ctrl_reset)(struct dsi_ctrl_hw *ctrl, int mask); /** * mask_error_int() - Mask/Unmask particular DSI error interrupts * @ctrl: Pointer to the controller host hardware. * @idx: Indicates the errors to be masked. * @en: Bool for mask or unmask of the error */ void (*mask_error_intr)(struct dsi_ctrl_hw *ctrl, u32 idx, bool en); /** * error_intr_ctrl() - Mask/Unmask master DSI error interrupt * @ctrl: Pointer to the controller host hardware. * @en: Bool for mask or unmask of DSI error */ void (*error_intr_ctrl)(struct dsi_ctrl_hw *ctrl, bool en); /** * get_error_mask() - get DSI error interrupt mask status * @ctrl: Pointer to the controller host hardware. */ u32 (*get_error_mask)(struct dsi_ctrl_hw *ctrl); /** * get_hw_version() - get DSI controller hw version * @ctrl: Pointer to the controller host hardware. */ u32 (*get_hw_version)(struct dsi_ctrl_hw *ctrl); }; /* Loading Loading
drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c +6 −0 Original line number Diff line number Diff line Loading @@ -62,6 +62,11 @@ static void dsi_catalog_cmn_init(struct dsi_ctrl_hw *ctrl, ctrl->ops.debug_bus = dsi_ctrl_hw_cmn_debug_bus; ctrl->ops.get_cmd_read_data = dsi_ctrl_hw_cmn_get_cmd_read_data; ctrl->ops.clear_rdbk_register = dsi_ctrl_hw_cmn_clear_rdbk_reg; ctrl->ops.ctrl_reset = dsi_ctrl_hw_cmn_ctrl_reset; ctrl->ops.mask_error_intr = dsi_ctrl_hw_cmn_mask_error_intr; ctrl->ops.error_intr_ctrl = dsi_ctrl_hw_cmn_error_intr_ctrl; ctrl->ops.get_error_mask = dsi_ctrl_hw_cmn_get_error_mask; ctrl->ops.get_hw_version = dsi_ctrl_hw_cmn_get_hw_version; switch (version) { case DSI_CTRL_VERSION_1_4: Loading Loading @@ -203,6 +208,7 @@ static void dsi_catalog_phy_3_0_init(struct dsi_phy_hw *phy) phy->ops.ulps_ops.is_lanes_in_ulps = dsi_phy_hw_v3_0_is_lanes_in_ulps; phy->ops.phy_timing_val = dsi_phy_hw_timing_val_v3_0; phy->ops.phy_lane_reset = dsi_phy_hw_v3_0_lane_reset; } /** Loading
drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h +8 −0 Original line number Diff line number Diff line Loading @@ -102,6 +102,7 @@ u32 dsi_phy_hw_v3_0_get_lanes_in_ulps(struct dsi_phy_hw *phy); bool dsi_phy_hw_v3_0_is_lanes_in_ulps(u32 lanes, u32 ulps_lanes); int dsi_phy_hw_timing_val_v3_0(struct dsi_phy_per_lane_cfgs *timing_cfg, u32 *timing_val, u32 size); int dsi_phy_hw_v3_0_lane_reset(struct dsi_phy_hw *phy); /* DSI controller common ops */ u32 dsi_ctrl_hw_cmn_get_interrupt_status(struct dsi_ctrl_hw *ctrl); Loading Loading @@ -178,6 +179,13 @@ u32 dsi_ctrl_hw_cmn_get_cmd_read_data(struct dsi_ctrl_hw *ctrl, u32 pkt_size, u32 *hw_read_cnt); void dsi_ctrl_hw_cmn_clear_rdbk_reg(struct dsi_ctrl_hw *ctrl); void dsi_ctrl_hw_22_schedule_dma_cmd(struct dsi_ctrl_hw *ctrl, int line_on); int dsi_ctrl_hw_cmn_ctrl_reset(struct dsi_ctrl_hw *ctrl, int mask); void dsi_ctrl_hw_cmn_mask_error_intr(struct dsi_ctrl_hw *ctrl, u32 idx, bool en); void dsi_ctrl_hw_cmn_error_intr_ctrl(struct dsi_ctrl_hw *ctrl, bool en); u32 dsi_ctrl_hw_cmn_get_error_mask(struct dsi_ctrl_hw *ctrl); u32 dsi_ctrl_hw_cmn_get_hw_version(struct dsi_ctrl_hw *ctrl); /* Definitions specific to 1.4 DSI controller hardware */ int dsi_ctrl_hw_14_wait_for_lane_idle(struct dsi_ctrl_hw *ctrl, u32 lanes); Loading
drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c +135 −40 Original line number Diff line number Diff line Loading @@ -1041,6 +1041,9 @@ static int dsi_message_tx(struct dsi_ctrl *dsi_ctrl, dsi_ctrl_wait_for_video_done(dsi_ctrl); dsi_ctrl_enable_status_interrupt(dsi_ctrl, DSI_SINT_CMD_MODE_DMA_DONE, NULL); if (dsi_ctrl->hw.ops.mask_error_intr) dsi_ctrl->hw.ops.mask_error_intr(&dsi_ctrl->hw, BIT(DSI_FIFO_OVERFLOW), true); reinit_completion(&dsi_ctrl->irq_info.cmd_dma_done); if (flags & DSI_CTRL_CMD_FETCH_MEMORY) { Loading Loading @@ -1081,6 +1084,9 @@ static int dsi_message_tx(struct dsi_ctrl *dsi_ctrl, } } if (dsi_ctrl->hw.ops.mask_error_intr) dsi_ctrl->hw.ops.mask_error_intr(&dsi_ctrl->hw, BIT(DSI_FIFO_OVERFLOW), false); dsi_ctrl->hw.ops.reset_cmd_fifo(&dsi_ctrl->hw); } error: Loading Loading @@ -1945,7 +1951,7 @@ int dsi_ctrl_setup(struct dsi_ctrl *dsi_ctrl) } dsi_ctrl->hw.ops.enable_status_interrupts(&dsi_ctrl->hw, 0x0); dsi_ctrl->hw.ops.enable_error_interrupts(&dsi_ctrl->hw, 0x0); dsi_ctrl->hw.ops.enable_error_interrupts(&dsi_ctrl->hw, 0xFF00E0); dsi_ctrl->hw.ops.ctrl_en(&dsi_ctrl->hw, true); mutex_unlock(&dsi_ctrl->ctrl_lock); Loading Loading @@ -1996,33 +2002,77 @@ int dsi_ctrl_phy_reset_config(struct dsi_ctrl *dsi_ctrl, bool enable) static void dsi_ctrl_handle_error_status(struct dsi_ctrl *dsi_ctrl, unsigned long int error) { pr_err("%s: %lu\n", __func__, error); struct dsi_event_cb_info cb_info; /* DTLN PHY error */ if (error & 0x3000e00) cb_info = dsi_ctrl->irq_info.irq_err_cb; /* disable error interrupts */ if (dsi_ctrl->hw.ops.error_intr_ctrl) dsi_ctrl->hw.ops.error_intr_ctrl(&dsi_ctrl->hw, false); /* clear error interrupts first */ if (dsi_ctrl->hw.ops.clear_error_status) dsi_ctrl->hw.ops.clear_error_status(&dsi_ctrl->hw, 0x3000e00); error); /* DTLN PHY error */ if (error & 0x3000E00) pr_err("dsi PHY contention error: 0x%lx\n", error); /* TX timeout error */ if (error & 0xE0) { if (error & 0xA0) { if (cb_info.event_cb) { cb_info.event_idx = DSI_LP_Rx_TIMEOUT; (void)cb_info.event_cb(cb_info.event_usr_ptr, cb_info.event_idx, dsi_ctrl->cell_index, 0, 0, 0, 0); } } pr_err("tx timeout error: 0x%lx\n", error); } /* DSI FIFO OVERFLOW error */ if (error & 0xf0000) { if (dsi_ctrl->hw.ops.clear_error_status) dsi_ctrl->hw.ops.clear_error_status(&dsi_ctrl->hw, 0xf0000); if (error & 0xF0000) { u32 mask = 0; if (dsi_ctrl->hw.ops.get_error_mask) mask = dsi_ctrl->hw.ops.get_error_mask(&dsi_ctrl->hw); /* no need to report FIFO overflow if already masked */ if (cb_info.event_cb && !(mask & 0xf0000)) { cb_info.event_idx = DSI_FIFO_OVERFLOW; (void)cb_info.event_cb(cb_info.event_usr_ptr, cb_info.event_idx, dsi_ctrl->cell_index, 0, 0, 0, 0); pr_err("dsi FIFO OVERFLOW error: 0x%lx\n", error); } } /* DSI FIFO UNDERFLOW error */ if (error & 0xf00000) { if (dsi_ctrl->hw.ops.clear_error_status) dsi_ctrl->hw.ops.clear_error_status(&dsi_ctrl->hw, 0xf00000); if (error & 0xF00000) { if (cb_info.event_cb) { cb_info.event_idx = DSI_FIFO_UNDERFLOW; (void)cb_info.event_cb(cb_info.event_usr_ptr, cb_info.event_idx, dsi_ctrl->cell_index, 0, 0, 0, 0); } pr_err("dsi FIFO UNDERFLOW error: 0x%lx\n", error); } /* DSI PLL UNLOCK error */ if (error & BIT(8)) if (dsi_ctrl->hw.ops.clear_error_status) dsi_ctrl->hw.ops.clear_error_status(&dsi_ctrl->hw, BIT(8)); pr_err("dsi PLL unlock error: 0x%lx\n", error); /* ACK error */ if (error & 0xF) pr_err("ack error: 0x%lx\n", error); /* enable back DSI interrupts */ if (dsi_ctrl->hw.ops.error_intr_ctrl) dsi_ctrl->hw.ops.error_intr_ctrl(&dsi_ctrl->hw, true); } /** Loading @@ -2036,39 +2086,28 @@ static irqreturn_t dsi_ctrl_isr(int irq, void *ptr) struct dsi_ctrl *dsi_ctrl; struct dsi_event_cb_info cb_info; unsigned long flags; uint32_t cell_index, status, i; uint64_t errors; uint32_t status = 0x0, i; uint64_t errors = 0x0; if (!ptr) return IRQ_NONE; dsi_ctrl = ptr; /* clear status interrupts */ /* check status interrupts */ if (dsi_ctrl->hw.ops.get_interrupt_status) status = dsi_ctrl->hw.ops.get_interrupt_status(&dsi_ctrl->hw); else status = 0x0; if (dsi_ctrl->hw.ops.clear_interrupt_status) dsi_ctrl->hw.ops.clear_interrupt_status(&dsi_ctrl->hw, status); spin_lock_irqsave(&dsi_ctrl->irq_info.irq_lock, flags); cell_index = dsi_ctrl->cell_index; spin_unlock_irqrestore(&dsi_ctrl->irq_info.irq_lock, flags); /* clear error interrupts */ /* check error interrupts */ if (dsi_ctrl->hw.ops.get_error_status) errors = dsi_ctrl->hw.ops.get_error_status(&dsi_ctrl->hw); else errors = 0x0; if (errors) { /* clear interrupts */ if (dsi_ctrl->hw.ops.clear_interrupt_status) dsi_ctrl->hw.ops.clear_interrupt_status(&dsi_ctrl->hw, 0x0); /* handle DSI error recovery */ if (status & DSI_ERROR) dsi_ctrl_handle_error_status(dsi_ctrl, errors); if (dsi_ctrl->hw.ops.clear_error_status) dsi_ctrl->hw.ops.clear_error_status(&dsi_ctrl->hw, errors); } if (status & DSI_CMD_MODE_DMA_DONE) { dsi_ctrl_disable_status_interrupt(dsi_ctrl, Loading @@ -2089,9 +2128,16 @@ static irqreturn_t dsi_ctrl_isr(int irq, void *ptr) } if (status & DSI_BTA_DONE) { u32 fifo_overflow_mask = (DSI_DLN0_HS_FIFO_OVERFLOW | DSI_DLN1_HS_FIFO_OVERFLOW | DSI_DLN2_HS_FIFO_OVERFLOW | DSI_DLN3_HS_FIFO_OVERFLOW); dsi_ctrl_disable_status_interrupt(dsi_ctrl, DSI_SINT_BTA_DONE); complete_all(&dsi_ctrl->irq_info.bta_done); if (dsi_ctrl->hw.ops.clear_error_status) dsi_ctrl->hw.ops.clear_error_status(&dsi_ctrl->hw, fifo_overflow_mask); } for (i = 0; status && i < DSI_STATUS_INTERRUPT_COUNT; ++i) { Loading @@ -2104,7 +2150,8 @@ static irqreturn_t dsi_ctrl_isr(int irq, void *ptr) if (cb_info.event_cb) (void)cb_info.event_cb(cb_info.event_usr_ptr, cb_info.event_idx, cell_index, irq, 0, 0, 0); dsi_ctrl->cell_index, irq, 0, 0, 0); } status >>= 1; } Loading Loading @@ -2314,7 +2361,7 @@ int dsi_ctrl_host_init(struct dsi_ctrl *dsi_ctrl, bool is_splash_enabled) dsi_ctrl_setup_isr(dsi_ctrl); dsi_ctrl->hw.ops.enable_status_interrupts(&dsi_ctrl->hw, 0x0); dsi_ctrl->hw.ops.enable_error_interrupts(&dsi_ctrl->hw, 0x0); dsi_ctrl->hw.ops.enable_error_interrupts(&dsi_ctrl->hw, 0xFF00E0); pr_debug("[DSI_%d]Host initialization complete, continuous splash status:%d\n", dsi_ctrl->cell_index, is_splash_enabled); Loading @@ -2337,6 +2384,48 @@ int dsi_ctrl_soft_reset(struct dsi_ctrl *dsi_ctrl) return 0; } int dsi_ctrl_reset(struct dsi_ctrl *dsi_ctrl, int mask) { int rc = 0; if (!dsi_ctrl) return -EINVAL; mutex_lock(&dsi_ctrl->ctrl_lock); rc = dsi_ctrl->hw.ops.ctrl_reset(&dsi_ctrl->hw, mask); mutex_unlock(&dsi_ctrl->ctrl_lock); return rc; } int dsi_ctrl_get_hw_version(struct dsi_ctrl *dsi_ctrl) { int rc = 0; if (!dsi_ctrl) return -EINVAL; mutex_lock(&dsi_ctrl->ctrl_lock); rc = dsi_ctrl->hw.ops.get_hw_version(&dsi_ctrl->hw); mutex_unlock(&dsi_ctrl->ctrl_lock); return rc; } int dsi_ctrl_vid_engine_en(struct dsi_ctrl *dsi_ctrl, bool on) { int rc = 0; if (!dsi_ctrl) return -EINVAL; mutex_lock(&dsi_ctrl->ctrl_lock); dsi_ctrl->hw.ops.video_engine_en(&dsi_ctrl->hw, on); mutex_unlock(&dsi_ctrl->ctrl_lock); return rc; } /** * dsi_ctrl_host_deinit() - De-Initialize DSI host hardware. * @dsi_ctrl: DSI controller handle. Loading Loading @@ -2538,6 +2627,9 @@ int dsi_ctrl_cmd_tx_trigger(struct dsi_ctrl *dsi_ctrl, u32 flags) dsi_ctrl_wait_for_video_done(dsi_ctrl); dsi_ctrl_enable_status_interrupt(dsi_ctrl, DSI_SINT_CMD_MODE_DMA_DONE, NULL); if (dsi_ctrl->hw.ops.mask_error_intr) dsi_ctrl->hw.ops.mask_error_intr(&dsi_ctrl->hw, BIT(DSI_FIFO_OVERFLOW), true); reinit_completion(&dsi_ctrl->irq_info.cmd_dma_done); /* trigger command */ Loading Loading @@ -2568,6 +2660,9 @@ int dsi_ctrl_cmd_tx_trigger(struct dsi_ctrl *dsi_ctrl, u32 flags) dsi_ctrl->cell_index); } } if (dsi_ctrl->hw.ops.mask_error_intr) dsi_ctrl->hw.ops.mask_error_intr(&dsi_ctrl->hw, BIT(DSI_FIFO_OVERFLOW), false); } mutex_unlock(&dsi_ctrl->ctrl_lock); Loading
drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h +24 −0 Original line number Diff line number Diff line Loading @@ -146,6 +146,7 @@ struct dsi_ctrl_state_info { * @irq_stat_mask: Hardware mask of currently enabled interrupts. * @irq_stat_refcount: Number of times each interrupt has been requested. * @irq_stat_cb: Status IRQ callback definitions. * @irq_err_cb: IRQ callback definition to handle DSI ERRORs. * @cmd_dma_done: Completion signal for DSI_CMD_MODE_DMA_DONE interrupt * @vid_frame_done: Completion signal for DSI_VIDEO_MODE_FRAME_DONE int. * @cmd_frame_done: Completion signal for DSI_CMD_FRAME_DONE interrupt. Loading @@ -156,6 +157,7 @@ struct dsi_ctrl_interrupts { uint32_t irq_stat_mask; int irq_stat_refcount[DSI_STATUS_INTERRUPT_COUNT]; struct dsi_event_cb_info irq_stat_cb[DSI_STATUS_INTERRUPT_COUNT]; struct dsi_event_cb_info irq_err_cb; struct completion cmd_dma_done; struct completion vid_frame_done; Loading @@ -177,6 +179,7 @@ struct dsi_ctrl_interrupts { * @current_state: Current driver and hardware state. * @clk_cb: Callback for DSI clock control. * @irq_info: Interrupt information. * @recovery_cb: Recovery call back to SDE. * @clk_info: Clock information. * @clk_freq: DSi Link clock frequency information. * @pwr_info: Power information. Loading Loading @@ -215,6 +218,7 @@ struct dsi_ctrl { struct clk_ctrl_cb clk_cb; struct dsi_ctrl_interrupts irq_info; struct dsi_event_cb_info recovery_cb; /* Clock and power states */ struct dsi_ctrl_clk_info clk_info; Loading Loading @@ -651,4 +655,24 @@ void dsi_ctrl_drv_register(void); */ void dsi_ctrl_drv_unregister(void); /** * dsi_ctrl_reset() - Reset DSI PHY CLK/DATA lane * @dsi_ctrl: DSI controller handle. * @mask: Mask to indicate if CLK and/or DATA lane needs reset. */ int dsi_ctrl_reset(struct dsi_ctrl *dsi_ctrl, int mask); /** * dsi_ctrl_get_hw_version() - read dsi controller hw revision * @dsi_ctrl: DSI controller handle. */ int dsi_ctrl_get_hw_version(struct dsi_ctrl *dsi_ctrl); /** * dsi_ctrl_vid_engine_en() - Control DSI video engine HW state * @dsi_ctrl: DSI controller handle. * @on: variable to control video engine ON/OFF. */ int dsi_ctrl_vid_engine_en(struct dsi_ctrl *dsi_ctrl, bool on); #endif /* _DSI_CTRL_H_ */
drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h +43 −1 Original line number Diff line number Diff line Loading @@ -96,6 +96,7 @@ enum dsi_test_pattern { * @DSI_SINT_DESKEW_DONE: The deskew calibration operation done. * @DSI_SINT_DYN_BLANK_DMA_DONE: The dynamic blankin DMA operation has * completed. * @DSI_SINT_ERROR: DSI error has happened. */ enum dsi_status_int_index { DSI_SINT_CMD_MODE_DMA_DONE = 0, Loading @@ -108,6 +109,7 @@ enum dsi_status_int_index { DSI_SINT_DYN_REFRESH_DONE = 7, DSI_SINT_DESKEW_DONE = 8, DSI_SINT_DYN_BLANK_DMA_DONE = 9, DSI_SINT_ERROR = 10, DSI_STATUS_INTERRUPT_COUNT }; Loading @@ -126,6 +128,7 @@ enum dsi_status_int_index { * @DSI_DESKEW_DONE: The deskew calibration operation has completed * @DSI_DYN_BLANK_DMA_DONE: The dynamic blankin DMA operation has * completed. * @DSI_ERROR: DSI error has happened. */ enum dsi_status_int_type { DSI_CMD_MODE_DMA_DONE = BIT(DSI_SINT_CMD_MODE_DMA_DONE), Loading @@ -137,7 +140,8 @@ enum dsi_status_int_type { DSI_CMD_FRAME_DONE = BIT(DSI_SINT_CMD_FRAME_DONE), DSI_DYN_REFRESH_DONE = BIT(DSI_SINT_DYN_REFRESH_DONE), DSI_DESKEW_DONE = BIT(DSI_SINT_DESKEW_DONE), DSI_DYN_BLANK_DMA_DONE = BIT(DSI_SINT_DYN_BLANK_DMA_DONE) DSI_DYN_BLANK_DMA_DONE = BIT(DSI_SINT_DYN_BLANK_DMA_DONE), DSI_ERROR = BIT(DSI_SINT_ERROR) }; /** Loading Loading @@ -175,6 +179,7 @@ enum dsi_status_int_type { * @DSI_EINT_DLN1_LP1_CONTENTION: PHY level contention while lane 1 high. * @DSI_EINT_DLN2_LP1_CONTENTION: PHY level contention while lane 2 high. * @DSI_EINT_DLN3_LP1_CONTENTION: PHY level contention while lane 3 high. * @DSI_EINT_PANEL_SPECIFIC_ERR: DSI Protocol violation error. */ enum dsi_error_int_index { DSI_EINT_RDBK_SINGLE_ECC_ERR = 0, Loading Loading @@ -209,6 +214,7 @@ enum dsi_error_int_index { DSI_EINT_DLN1_LP1_CONTENTION = 29, DSI_EINT_DLN2_LP1_CONTENTION = 30, DSI_EINT_DLN3_LP1_CONTENTION = 31, DSI_EINT_PANEL_SPECIFIC_ERR = 32, DSI_ERROR_INTERRUPT_COUNT }; Loading Loading @@ -248,6 +254,7 @@ enum dsi_error_int_index { * @DSI_DLN1_LP1_CONTENTION: PHY level contention while lane 1 is high. * @DSI_DLN2_LP1_CONTENTION: PHY level contention while lane 2 is high. * @DSI_DLN3_LP1_CONTENTION: PHY level contention while lane 3 is high. * @DSI_PANEL_SPECIFIC_ERR: DSI Protocol violation. */ enum dsi_error_int_type { DSI_RDBK_SINGLE_ECC_ERR = BIT(DSI_EINT_RDBK_SINGLE_ECC_ERR), Loading Loading @@ -282,6 +289,7 @@ enum dsi_error_int_type { DSI_DLN1_LP1_CONTENTION = BIT(DSI_EINT_DLN1_LP1_CONTENTION), DSI_DLN2_LP1_CONTENTION = BIT(DSI_EINT_DLN2_LP1_CONTENTION), DSI_DLN3_LP1_CONTENTION = BIT(DSI_EINT_DLN3_LP1_CONTENTION), DSI_PANEL_SPECIFIC_ERR = BIT(DSI_EINT_PANEL_SPECIFIC_ERR), }; /** Loading Loading @@ -735,6 +743,40 @@ struct dsi_ctrl_hw_ops { * needs to be sent. */ void (*schedule_dma_cmd)(struct dsi_ctrl_hw *ctrl, int line_no); /** * ctrl_reset() - Reset DSI lanes to recover from DSI errors * @ctrl: Pointer to the controller host hardware. * @mask: Indicates the error type. */ int (*ctrl_reset)(struct dsi_ctrl_hw *ctrl, int mask); /** * mask_error_int() - Mask/Unmask particular DSI error interrupts * @ctrl: Pointer to the controller host hardware. * @idx: Indicates the errors to be masked. * @en: Bool for mask or unmask of the error */ void (*mask_error_intr)(struct dsi_ctrl_hw *ctrl, u32 idx, bool en); /** * error_intr_ctrl() - Mask/Unmask master DSI error interrupt * @ctrl: Pointer to the controller host hardware. * @en: Bool for mask or unmask of DSI error */ void (*error_intr_ctrl)(struct dsi_ctrl_hw *ctrl, bool en); /** * get_error_mask() - get DSI error interrupt mask status * @ctrl: Pointer to the controller host hardware. */ u32 (*get_error_mask)(struct dsi_ctrl_hw *ctrl); /** * get_hw_version() - get DSI controller hw version * @ctrl: Pointer to the controller host hardware. */ u32 (*get_hw_version)(struct dsi_ctrl_hw *ctrl); }; /* Loading