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

Commit 222e8d90 authored by Sandeep Panda's avatar Sandeep Panda Committed by Gerrit - the friendly Code Review server
Browse files

drm/msm: create ESD worker thread to check panel status



Create ESD worker thread which periodically checks for
panel status. If panel health check is successful then
reschedule the work to be executed after a predefined delay.
If panel does not respond then PANEL_DEAD will reported to
user space to trigger the recovery procedure.

Change-Id: I58ab04dabd47b07ef6df80bdb9b22c20e087deec
Signed-off-by: default avatarSandeep Panda <spanda@codeaurora.org>
parent bc882fb8
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -3611,6 +3611,9 @@ int dsi_display_get_info(struct msm_display_info *info, void *disp)
		break;
	}

	if (display->panel->esd_config.esd_enabled)
		info->capabilities |= MSM_DISPLAY_ESD_ENABLED;

	memcpy(&info->roi_caps, &display->panel->roi_caps,
			sizeof(info->roi_caps));

+2 −0
Original line number Diff line number Diff line
@@ -212,12 +212,14 @@ enum msm_display_compression_type {
 * @MSM_DISPLAY_CAP_CMD_MODE:           Command mode supported
 * @MSM_DISPLAY_CAP_HOT_PLUG:           Hot plug detection supported
 * @MSM_DISPLAY_CAP_EDID:               EDID supported
 * @MSM_DISPLAY_ESD_ENABLED:            ESD feature enabled
 */
enum msm_display_caps {
	MSM_DISPLAY_CAP_VID_MODE	= BIT(0),
	MSM_DISPLAY_CAP_CMD_MODE	= BIT(1),
	MSM_DISPLAY_CAP_HOT_PLUG	= BIT(2),
	MSM_DISPLAY_CAP_EDID		= BIT(3),
	MSM_DISPLAY_ESD_ENABLED		= BIT(4),
};

/**
+77 −0
Original line number Diff line number Diff line
@@ -366,6 +366,29 @@ int sde_connector_get_info(struct drm_connector *connector,
	return c_conn->ops.get_info(info, c_conn->display);
}

void sde_connector_schedule_status_work(struct drm_connector *connector,
		bool en)
{
	struct sde_connector *c_conn;
	struct msm_display_info info;

	c_conn = to_sde_connector(connector);
	if (!c_conn)
		return;

	sde_connector_get_info(connector, &info);
	if (c_conn->ops.check_status &&
		(info.capabilities & MSM_DISPLAY_ESD_ENABLED)) {
		if (en)
			/* Schedule ESD status check */
			schedule_delayed_work(&c_conn->status_work,
				msecs_to_jiffies(STATUS_CHECK_INTERVAL_MS));
		else
			/* Cancel any pending ESD status check */
			cancel_delayed_work_sync(&c_conn->status_work);
	}
}

static int _sde_connector_update_power_locked(struct sde_connector *c_conn)
{
	struct drm_connector *connector;
@@ -411,6 +434,9 @@ static int _sde_connector_update_power_locked(struct sde_connector *c_conn)
	}
	c_conn->last_panel_power_mode = mode;

	if (mode != SDE_MODE_DPMS_ON)
		sde_connector_schedule_status_work(connector, false);

	return rc;
}

@@ -492,6 +518,9 @@ static void sde_connector_destroy(struct drm_connector *connector)

	c_conn = to_sde_connector(connector);

	/* cancel if any pending esd work */
	sde_connector_schedule_status_work(connector, false);

	if (c_conn->ops.put_modes)
		c_conn->ops.put_modes(connector, c_conn->display);

@@ -1160,6 +1189,48 @@ sde_connector_best_encoder(struct drm_connector *connector)
	return c_conn->encoder;
}

static void sde_connector_check_status_work(struct work_struct *work)
{
	struct sde_connector *conn;
	struct drm_event event;
	int rc = 0;
	bool panel_dead = false;

	conn = container_of(to_delayed_work(work),
			struct sde_connector, status_work);
	if (!conn) {
		SDE_ERROR("not able to get connector object\n");
		return;
	}

	mutex_lock(&conn->lock);
	if (!conn->ops.check_status ||
			(conn->dpms_mode != DRM_MODE_DPMS_ON)) {
		SDE_DEBUG("dpms mode: %d\n", conn->dpms_mode);
		mutex_unlock(&conn->lock);
		return;
	}

	rc = conn->ops.check_status(conn->display);
	mutex_unlock(&conn->lock);
	if (rc > 0) {
		SDE_DEBUG("esd check status success conn_id: %d enc_id: %d\n",
				conn->base.base.id, conn->encoder->base.id);
		schedule_delayed_work(&conn->status_work,
			msecs_to_jiffies(STATUS_CHECK_INTERVAL_MS));
	} else {
		SDE_EVT32(rc, SDE_EVTLOG_ERROR);
		SDE_ERROR("failed report PANEL_DEAD conn_id: %d enc_id: %d\n",
				conn->base.base.id, conn->encoder->base.id);
		/* report panel dead event */
		panel_dead = true;
		event.type = DRM_EVENT_PANEL_DEAD;
		event.length = sizeof(u32);
		msm_mode_object_event_notify(&conn->base.base,
			conn->base.dev, &event, (u8 *)&panel_dead);
	}
}

static const struct drm_connector_helper_funcs sde_connector_helper_ops = {
	.get_modes =    sde_connector_get_modes,
	.mode_valid =   sde_connector_mode_valid,
@@ -1368,6 +1439,9 @@ struct drm_connector *sde_connector_init(struct drm_device *dev,

	priv->connectors[priv->num_connectors++] = &c_conn->base;

	INIT_DELAYED_WORK(&c_conn->status_work,
			sde_connector_check_status_work);

	return &c_conn->base;

error_destroy_property:
@@ -1399,6 +1473,9 @@ int sde_connector_register_custom_event(struct sde_kms *kms,
	case DRM_EVENT_SYS_BACKLIGHT:
		ret = 0;
		break;
	case DRM_EVENT_PANEL_DEAD:
		ret = 0;
		break;
	default:
		break;
	}
+16 −0
Original line number Diff line number Diff line
@@ -212,6 +212,13 @@ struct sde_connector_ops {
	 * @display: Pointer to private display structure
	 */
	void (*send_hpd_event)(void *display);

	/**
	 * check_status - check status of connected display panel
	 * @display: Pointer to private display handle
	 * Returns: positive value for success, negetive or zero for failure
	 */
	int (*check_status)(void *display);
};

/**
@@ -261,6 +268,7 @@ struct sde_connector_evt {
 * @event_table: Array of registered events
 * @event_lock: Lock object for event_table
 * @bl_device: backlight device node
 * @status_work: work object to perform status checks
 */
struct sde_connector {
	struct drm_connector base;
@@ -293,6 +301,7 @@ struct sde_connector {
	spinlock_t event_lock;

	struct backlight_device *bl_device;
	struct delayed_work status_work;
};

/**
@@ -580,4 +589,11 @@ static inline bool sde_connector_needs_offset(struct drm_connector *connector)
int sde_connector_get_dither_cfg(struct drm_connector *conn,
		struct drm_connector_state *state, void **cfg, size_t *len);

/**
 * sde_connector_schedule_status_work - manage ESD thread
 * conn: Pointer to drm_connector struct
 * @en: flag to start/stop ESD thread
 */
void sde_connector_schedule_status_work(struct drm_connector *conn, bool en);

#endif /* _SDE_CONNECTOR_H_ */
+10 −1
Original line number Diff line number Diff line
@@ -3755,6 +3755,10 @@ static void sde_crtc_disable(struct drm_crtc *crtc)

	SDE_DEBUG("crtc%d\n", crtc->base.id);

	for (i = 0; i < cstate->num_connectors; i++)
		sde_connector_schedule_status_work(cstate->connectors[i],
							false);

	if (sde_kms_is_suspend_state(crtc->dev))
		_sde_crtc_set_suspend(crtc, true);

@@ -3847,13 +3851,15 @@ static void sde_crtc_enable(struct drm_crtc *crtc)
	struct sde_crtc_irq_info *node = NULL;
	struct drm_event event;
	u32 power_on;
	int ret;
	int ret, i;
	struct sde_crtc_state *cstate;

	if (!crtc || !crtc->dev || !crtc->dev->dev_private) {
		SDE_ERROR("invalid crtc\n");
		return;
	}
	priv = crtc->dev->dev_private;
	cstate = to_sde_crtc_state(crtc->state);

	SDE_DEBUG("crtc%d\n", crtc->base.id);
	SDE_EVT32_VERBOSE(DRMID(crtc));
@@ -3904,6 +3910,9 @@ static void sde_crtc_enable(struct drm_crtc *crtc)
		SDE_POWER_EVENT_POST_ENABLE | SDE_POWER_EVENT_POST_DISABLE |
		SDE_POWER_EVENT_PRE_DISABLE,
		sde_crtc_handle_power_event, crtc, sde_crtc->name);

	for (i = 0; i < cstate->num_connectors; i++)
		sde_connector_schedule_status_work(cstate->connectors[i], true);
}

struct plane_state {
Loading