Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 53b3cf65 authored by Sandeep Panda's avatar Sandeep Panda Committed by Steve Cohen
Browse files

drm/msm/dsi-staging: add error handling support to DSI driver



Add functions to handle and recover from various DSI errors
in DRM DSI driver. The errors that are currently handled are
DSI FIFO OVERFLOW, FIFO UNDERFLOW, DSI BTA TIMEOUT and
DSI LP/RX TIMEOUT.

Change-Id: Ifc4eeaf01b3b5204b26745b6cc2dcffb71cb3f57
Signed-off-by: default avatarSandeep Panda <spanda@codeaurora.org>
parent beef2607
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -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:
@@ -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;
}

/**
+8 −0
Original line number Diff line number Diff line
@@ -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);
@@ -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);
+135 −40
Original line number Diff line number Diff line
@@ -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) {
@@ -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:
@@ -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);
@@ -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);
}

/**
@@ -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,
@@ -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) {
@@ -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;
	}
@@ -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);
@@ -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.
@@ -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 */
@@ -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);
+24 −0
Original line number Diff line number Diff line
@@ -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.
@@ -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;
@@ -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.
@@ -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;
@@ -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_ */
+43 −1
Original line number Diff line number Diff line
@@ -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,
@@ -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
};
@@ -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),
@@ -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)
};

/**
@@ -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,
@@ -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
};
@@ -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),
@@ -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),
};

/**
@@ -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