disp: msm: Implement custom ESD IRQ handling

Change-Id: Ic1b928f941b7c573714e24aeb9e62cde0d6f2b13
Signed-off-by: UtsavBalar1231 <utsavbalar1231@gmail.com>
This commit is contained in:
UtsavBalar1231 2021-08-31 08:14:19 +05:30 committed by spakkkk
parent bca6c98700
commit a2e9d692e8
7 changed files with 221 additions and 0 deletions

View File

@ -746,6 +746,9 @@ char *dsi_display_get_cmdline_panel_info(void);
int dsi_display_hbm_set_disp_param(struct drm_connector *connector,
u32 param_type);
int dsi_display_esd_irq_ctrl(struct dsi_display *display,
bool enable);
struct dsi_display *get_main_display(void);
void dsi_display_set_fod_ui(struct dsi_display *display, bool status);

View File

@ -335,6 +335,28 @@ ssize_t dsi_display_fod_get(struct drm_connector *connector, char *buf)
return snprintf(buf, PAGE_SIZE, "%d\n", display->panel->mi_cfg.fod_ui_ready);
}
int dsi_display_esd_irq_ctrl(struct dsi_display *display,
bool enable)
{
int rc = 0;
if (!display) {
DSI_ERR("Invalid params\n");
return -EINVAL;
}
mutex_lock(&display->display_lock);
rc = dsi_panel_esd_irq_ctrl(display->panel, enable);
if (rc)
pr_err("[%s] failed to set esd irq, rc=%d\n",
display->name, rc);
mutex_unlock(&display->display_lock);
return rc;
}
ssize_t complete_commit_time_get(struct drm_connector *connector, char *buf)
{
struct dsi_display *dsi_display = NULL;

View File

@ -17,6 +17,8 @@
#include "msm_drv.h"
#include "sde_dbg.h"
#include "dsi_defs.h"
#include "sde_encoder.h"
#include "dsi_mi_feature.h"
#define to_dsi_bridge(x) container_of((x), struct dsi_bridge, base)
#define to_dsi_state(x) container_of((x), struct dsi_connector_state, base)
@ -340,6 +342,10 @@ static void dsi_bridge_enable(struct drm_bridge *bridge)
true);
}
rc = dsi_display_esd_irq_ctrl(c_bridge->display, true);
if (rc)
DSI_ERR("[%d] DSI display enable esd irq failed, rc=%d\n",
c_bridge->id, rc);
}
static void dsi_bridge_disable(struct drm_bridge *bridge)
@ -347,16 +353,36 @@ static void dsi_bridge_disable(struct drm_bridge *bridge)
int rc = 0;
int private_flags;
struct dsi_display *display;
struct mi_drm_notifier notify_data;
struct dsi_panel_mi_cfg *mi_cfg = NULL;
int power_mode = 0;
struct dsi_bridge *c_bridge = to_dsi_bridge(bridge);
if (!bridge) {
DSI_ERR("Invalid params\n");
return;
}
mi_cfg = &c_bridge->display->panel->mi_cfg;
if (mi_cfg->fod_dimlayer_enabled)
power_mode = sde_connector_get_lp(c_bridge->display->drm_conn);
else
power_mode = MI_DRM_BLANK_POWERDOWN;
notify_data.data = &power_mode;
notify_data.id = MSM_DRM_PRIMARY_DISPLAY;
mi_drm_notifier_call_chain(MI_DRM_PRE_EVENT_BLANK, &notify_data);
display = c_bridge->display;
private_flags =
bridge->encoder->crtc->state->adjusted_mode.private_flags;
rc = dsi_display_esd_irq_ctrl(c_bridge->display, false);
if (rc)
DSI_ERR("[%d] DSI display disable esd irq failed, rc=%d\n",
c_bridge->id, rc);
if (display && display->drm_conn) {
display->poms_pending =
private_flags & MSM_MODE_FLAG_SEAMLESS_POMS;

View File

@ -3725,6 +3725,11 @@ static int dsi_panel_parse_esd_config(struct dsi_panel *panel)
esd_config = &panel->esd_config;
esd_config->status_mode = ESD_MODE_MAX;
/* esd check using gpio irq method has high priority */
rc = dsi_panel_parse_esd_gpio_config(panel);
if (!rc)
return 0;
esd_config->esd_enabled = utils->read_bool(utils->data,
"qcom,esd-check-enabled");

View File

@ -275,6 +275,30 @@ static int dsi_panel_parse_elvss_dimming_config(struct dsi_panel *panel,
return rc;
}
int dsi_panel_parse_esd_gpio_config(struct dsi_panel *panel)
{
int rc = 0;
struct dsi_parser_utils *utils = &panel->utils;
struct dsi_panel_mi_cfg *mi_cfg = &panel->mi_cfg;
mi_cfg->esd_err_irq_gpio = of_get_named_gpio_flags(
utils->data, "mi,esd-err-irq-gpio",
0, (enum of_gpio_flags *)&(mi_cfg->esd_err_irq_flags));
if (gpio_is_valid(mi_cfg->esd_err_irq_gpio)) {
mi_cfg->esd_err_irq = gpio_to_irq(mi_cfg->esd_err_irq_gpio);
rc = gpio_request(mi_cfg->esd_err_irq_gpio, "esd_err_irq_gpio");
if (rc)
pr_err("Failed to request esd irq gpio %d, rc=%d\n",
mi_cfg->esd_err_irq_gpio, rc);
else
gpio_direction_input(mi_cfg->esd_err_irq_gpio);
} else {
rc = -EINVAL;
}
return rc;
}
int dsi_panel_parse_mi_config(struct dsi_panel *panel,
struct device_node *of_node)
{
@ -617,6 +641,47 @@ void display_utc_time_marker(const char *format, ...)
va_end(args);
}
int dsi_panel_esd_irq_ctrl(struct dsi_panel *panel,
bool enable)
{
struct dsi_panel_mi_cfg *mi_cfg;
struct irq_desc *desc;
if (!panel || !panel->panel_initialized) {
pr_err("Panel not ready!\n");
return -EINVAL;
}
mutex_lock(&panel->panel_lock);
mi_cfg = &panel->mi_cfg;
if (gpio_is_valid(mi_cfg->esd_err_irq_gpio)) {
if (mi_cfg->esd_err_irq) {
if (enable) {
if (!mi_cfg->esd_err_enabled) {
desc = irq_to_desc(mi_cfg->esd_err_irq);
if (!irq_settings_is_level(desc))
desc->istate &= ~IRQS_PENDING;
enable_irq(mi_cfg->esd_err_irq);
mi_cfg->esd_err_enabled = true;
pr_info("panel esd irq is enable\n");
}
} else {
if (mi_cfg->esd_err_enabled) {
disable_irq_nosync(mi_cfg->esd_err_irq);
mi_cfg->esd_err_enabled = false;
pr_info("panel esd irq is disable\n");
}
}
}
} else {
pr_info("panel esd irq gpio invalid\n");
}
mutex_unlock(&panel->panel_lock);
return 0;
}
int dsi_panel_update_elvss_dimming(struct dsi_panel *panel)
{
int rc = 0;

View File

@ -157,6 +157,11 @@ struct dsi_panel_mi_cfg {
bool dynamic_elvss_enabled;
int esd_err_irq_gpio;
int esd_err_irq;
int esd_err_irq_flags;
bool esd_err_enabled;
/* elvss dimming info */
bool elvss_dimming_check_enable;
u32 elvss_dimming_read_len;
@ -240,11 +245,16 @@ struct calc_hw_vsync {
u64 measured_fps_x1000;
};
int dsi_panel_parse_esd_gpio_config(struct dsi_panel *panel);
int dsi_panel_parse_mi_config(struct dsi_panel *panel,
struct device_node *of_node);
void display_utc_time_marker(const char *format, ...);
int dsi_panel_esd_irq_ctrl(struct dsi_panel *panel,
bool enable);
int dsi_panel_write_cmd_set(struct dsi_panel *panel,
struct dsi_panel_cmd_set *cmd_sets);

View File

@ -2662,6 +2662,93 @@ static void sde_connector_check_status_work(struct work_struct *work)
_sde_connector_report_panel_dead(conn, false);
}
static irqreturn_t esd_err_irq_handle(int irq, void *data)
{
struct sde_connector *c_conn = data;
struct dsi_display *display = c_conn->display;
struct drm_event event;
int power_mode;
const char *sde_power_mode_str[] = {
[SDE_MODE_DPMS_ON] = "SDE_MODE_DPMS_ON",
[SDE_MODE_DPMS_LP1] = "SDE_MODE_DPMS_LP1",
[SDE_MODE_DPMS_LP2] = "SDE_MODE_DPMS_LP2",
[SDE_MODE_DPMS_STANDBY] = "SDE_MODE_DPMS_STANDBY",
[SDE_MODE_DPMS_SUSPEND] = "SDE_MODE_DPMS_SUSPEND",
[SDE_MODE_DPMS_OFF] = "SDE_MODE_DPMS_OFF",
};
if (!display || !display->panel) {
SDE_ERROR("invalid display/panel\n");
return IRQ_HANDLED;
}
if (gpio_get_value(display->panel->mi_cfg.esd_err_irq_gpio)) {
SDE_ERROR("trigger esd by mistake,return\n");
return IRQ_HANDLED;
}
DSI_INFO("panel esd irq trigging \n");
if (c_conn->connector_type == DRM_MODE_CONNECTOR_DSI) {
if (dsi_panel_initialized(display->panel)) {
if (atomic_read(&(display->panel->esd_recovery_pending))) {
SDE_ERROR("ESD recovery already pending\n");
return IRQ_HANDLED;
}
power_mode = display->panel->power_mode;
DSI_INFO("power_mode = %s\n", sde_power_mode_str[power_mode]);
if (power_mode == SDE_MODE_DPMS_ON ||
power_mode == SDE_MODE_DPMS_LP1) {
atomic_set(&display->panel->esd_recovery_pending, 1);
_sde_connector_report_panel_dead(c_conn, false);
} else {
if (!c_conn->panel_dead) {
atomic_set(&display->panel->esd_recovery_pending, 1);
c_conn->panel_dead = true;
event.type = DRM_EVENT_PANEL_DEAD;
event.length = sizeof(bool);
msm_mode_object_event_notify(&c_conn->base.base,
c_conn->base.dev, &event, (u8 *)&c_conn->panel_dead);
SDE_EVT32(SDE_EVTLOG_ERROR);
SDE_ERROR("esd irq check failed report PANEL_DEAD"
" conn_id: %d enc_id: %d\n",
c_conn->base.base.id, c_conn->encoder->base.id);
}
}
}
}
return IRQ_HANDLED;
}
static int sde_connector_register_esd_irq(struct sde_connector *c_conn)
{
struct dsi_display *display = c_conn->display;
int rc = 0;
/* register esd irq and enable it after panel enabled */
if (c_conn->connector_type == DRM_MODE_CONNECTOR_DSI) {
if (!display || !display->panel) {
SDE_ERROR("invalid display/panel\n");
return -EINVAL;
}
if (display->panel->mi_cfg.esd_err_irq_gpio > 0) {
rc = request_threaded_irq(display->panel->mi_cfg.esd_err_irq,
NULL, esd_err_irq_handle,
display->panel->mi_cfg.esd_err_irq_flags,
"esd_err_irq", c_conn);
if (rc) {
SDE_ERROR("register esd irq failed\n");
} else {
SDE_INFO("register esd irq success\n");
disable_irq(display->panel->mi_cfg.esd_err_irq);
}
}
}
return rc;
}
static const struct drm_connector_helper_funcs sde_connector_helper_ops = {
.get_modes = sde_connector_get_modes,
.mode_valid = sde_connector_mode_valid,
@ -3115,6 +3202,9 @@ struct drm_connector *sde_connector_init(struct drm_device *dev,
INIT_DELAYED_WORK(&c_conn->status_work,
sde_connector_check_status_work);
sde_connector_register_esd_irq(c_conn);
return &c_conn->base;
error_destroy_property: