techpack: display: add mi display notifier

Change-Id: I50670448c6a865744b2c003188500560666bb4e1
This commit is contained in:
Cosmin Tanislav 2021-09-02 00:05:14 +03:00 committed by Giovanni Ricca
parent 8bc0ed6f0e
commit f218b912e6
No known key found for this signature in database
5 changed files with 148 additions and 1 deletions

View File

@ -0,0 +1,52 @@
/*
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
* Copyright (C) 2020 XiaoMi, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef _MI_DRM_NOTIFIER_H_
#define _MI_DRM_NOTIFIER_H_
#include <linux/notifier.h>
/* A hardware display power mode state change occurred */
#define MI_DISP_DPMS_EVENT 0x01
/* A hardware display power mode state early change occurred */
#define MI_DISP_DPMS_EARLY_EVENT 0x02
enum {
/* panel: power on */
MI_DISP_DPMS_ON = 0,
MI_DISP_DPMS_LP1 = 1,
MI_DISP_DPMS_LP2 = 2,
MI_DISP_DPMS_STANDBY = 3,
MI_DISP_DPMS_SUSPEND = 4,
/* panel: power off */
MI_DISP_DPMS_POWERDOWN = 5,
};
enum mi_disp_id {
MI_DISPLAY_PRIMARY = 0,
MI_DISPLAY_SECONDARY,
MI_DISPLAY_MAX,
};
struct mi_disp_notifier {
int disp_id;
void *data;
};
int mi_disp_register_client(struct notifier_block *nb);
int mi_disp_unregister_client(struct notifier_block *nb);
int mi_disp_notifier_call_chain(unsigned long val, void *v);
#endif /* _MI_DRM_NOTIFIER_H_ */

View File

@ -4,6 +4,7 @@ ccflags-y += -I$(srctree)/techpack/display/msm/sde
ccflags-y += -I$(srctree)/techpack/display/rotator
ccflags-y += -I$(srctree)/techpack/display/hdcp
ccflags-y += -I$(srctree)/drivers/clk/qcom/
ccflags-y += -I$(srctree)/techpack/display/msm/mi_disp
msm_drm-$(CONFIG_DRM_MSM_DP) += dp/dp_altmode.o \
dp/dp_parser.o \
@ -140,6 +141,10 @@ msm_drm-$(CONFIG_DRM_MSM) += \
msm_drm-$(CONFIG_HDCP_QSEECOM) += ../hdcp/msm_hdcp.o \
msm_drm-$(CONFIG_DRM_MSM) += \
mi_disp/mi_disp_notifier.o \
mi_disp/mi_dsi_display.o
msm_drm-$(CONFIG_MSM_SDE_ROTATOR) += ../rotator/sde_rotator_dev.o \
../rotator/sde_rotator_core.o \
../rotator/sde_rotator_base.o \

View File

@ -9,6 +9,8 @@
#include <linux/of_gpio.h>
#include <linux/err.h>
#include <drm/mi_disp_notifier.h>
#include "msm_drv.h"
#include "sde_connector.h"
#include "msm_mmu.h"
@ -21,6 +23,7 @@
#include "dsi_pwr.h"
#include "sde_dbg.h"
#include "dsi_parser.h"
#include "mi_dsi_display.h"
#define to_dsi_display(x) container_of(x, struct dsi_display, host)
#define INT_BASE_10 10
@ -1240,6 +1243,8 @@ int dsi_display_set_power(struct drm_connector *connector,
int power_mode, void *disp)
{
struct dsi_display *display = disp;
struct mi_disp_notifier notify_data;
int disp_id = 0;
int rc = 0;
if (!display || !display->panel) {
@ -1247,18 +1252,27 @@ int dsi_display_set_power(struct drm_connector *connector,
return -EINVAL;
}
disp_id = mi_get_disp_id(display);
notify_data.data = &power_mode;
notify_data.disp_id = disp_id;
switch (power_mode) {
case SDE_MODE_DPMS_LP1:
mi_disp_notifier_call_chain(MI_DISP_DPMS_EARLY_EVENT, &notify_data);
if (display->panel->power_mode == SDE_MODE_DPMS_LP2) {
if (dsi_display_set_ulp_load(display, false) < 0)
DSI_WARN("failed to set load for lp1 state\n");
}
rc = dsi_panel_set_lp1(display->panel);
mi_disp_notifier_call_chain(MI_DISP_DPMS_EVENT, &notify_data);
break;
case SDE_MODE_DPMS_LP2:
mi_disp_notifier_call_chain(MI_DISP_DPMS_EARLY_EVENT, &notify_data);
rc = dsi_panel_set_lp2(display->panel);
if (dsi_display_set_ulp_load(display, true) < 0)
DSI_WARN("failed to set load for lp2 state\n");
mi_disp_notifier_call_chain(MI_DISP_DPMS_EVENT, &notify_data);
break;
case SDE_MODE_DPMS_ON:
if (display->panel->power_mode == SDE_MODE_DPMS_LP2) {
@ -1266,8 +1280,11 @@ int dsi_display_set_power(struct drm_connector *connector,
DSI_WARN("failed to set load for on state\n");
}
if ((display->panel->power_mode == SDE_MODE_DPMS_LP1) ||
(display->panel->power_mode == SDE_MODE_DPMS_LP2))
(display->panel->power_mode == SDE_MODE_DPMS_LP2)) {
mi_disp_notifier_call_chain(MI_DISP_DPMS_EARLY_EVENT, &notify_data);
rc = dsi_panel_set_nolp(display->panel);
mi_disp_notifier_call_chain(MI_DISP_DPMS_EVENT, &notify_data);
}
break;
case SDE_MODE_DPMS_OFF:
default:

View File

@ -7,12 +7,14 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_atomic.h>
#include <drm/mi_disp_notifier.h>
#include "msm_kms.h"
#include "sde_connector.h"
#include "dsi_drm.h"
#include "sde_trace.h"
#include "sde_dbg.h"
#include "mi_dsi_display.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)
@ -169,6 +171,8 @@ static void dsi_bridge_pre_enable(struct drm_bridge *bridge)
{
int rc = 0;
struct dsi_bridge *c_bridge = to_dsi_bridge(bridge);
struct mi_disp_notifier notify_data;
int power_mode = 0;
if (!bridge) {
DSI_ERR("Invalid params\n");
@ -183,6 +187,11 @@ static void dsi_bridge_pre_enable(struct drm_bridge *bridge)
if (bridge->encoder->crtc->state->active_changed)
atomic_set(&c_bridge->display->panel->esd_recovery_pending, 0);
power_mode = sde_connector_get_lp(c_bridge->display->drm_conn);
notify_data.data = &power_mode;
notify_data.disp_id = mi_get_disp_id(c_bridge->display);
mi_disp_notifier_call_chain(MI_DISP_DPMS_EARLY_EVENT, &notify_data);
/* By this point mode should have been validated through mode_fixup */
rc = dsi_display_set_mode(c_bridge->display,
&(c_bridge->dsi_mode), 0x0);
@ -216,6 +225,8 @@ static void dsi_bridge_pre_enable(struct drm_bridge *bridge)
c_bridge->id, rc);
(void)dsi_display_unprepare(c_bridge->display);
}
mi_disp_notifier_call_chain(MI_DISP_DPMS_EVENT, &notify_data);
SDE_ATRACE_END("dsi_display_enable");
rc = dsi_display_splash_res_cleanup(c_bridge->display);
@ -295,12 +306,24 @@ static void dsi_bridge_post_disable(struct drm_bridge *bridge)
{
int rc = 0;
struct dsi_bridge *c_bridge = to_dsi_bridge(bridge);
struct mi_disp_notifier notify_data;
int power_mode = 0;
if (!bridge) {
DSI_ERR("Invalid params\n");
return;
}
if (!c_bridge || !c_bridge->display || !c_bridge->display->panel) {
DSI_ERR("Incorrect bridge details\n");
return;
}
power_mode = sde_connector_get_lp(c_bridge->display->drm_conn);
notify_data.data = &power_mode;
notify_data.disp_id = mi_get_disp_id(c_bridge->display);
mi_disp_notifier_call_chain(MI_DISP_DPMS_EARLY_EVENT, &notify_data);
SDE_ATRACE_BEGIN("dsi_bridge_post_disable");
SDE_ATRACE_BEGIN("dsi_display_disable");
rc = dsi_display_disable(c_bridge->display);
@ -319,6 +342,8 @@ static void dsi_bridge_post_disable(struct drm_bridge *bridge)
SDE_ATRACE_END("dsi_bridge_post_disable");
return;
}
mi_disp_notifier_call_chain(MI_DISP_DPMS_EVENT, &notify_data);
SDE_ATRACE_END("dsi_bridge_post_disable");
}

View File

@ -0,0 +1,48 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
* Copyright (C) 2020 XiaoMi, Inc.
*/
#include <linux/notifier.h>
static BLOCKING_NOTIFIER_HEAD(mi_disp_notifier_list);
/**
* mi_drm_register_client - register a client notifier
* @nb: notifier block to callback on events
*
* This function registers a notifier callback function
* to msm_drm_notifier_list, which would be called when
* received unblank/power down event.
*/
int mi_disp_register_client(struct notifier_block *nb)
{
return blocking_notifier_chain_register(&mi_disp_notifier_list, nb);
}
EXPORT_SYMBOL(mi_disp_register_client);
/**
* mi_drm_unregister_client - unregister a client notifier
* @nb: notifier block to callback on events
*
* This function unregisters the callback function from
* msm_drm_notifier_list.
*/
int mi_disp_unregister_client(struct notifier_block *nb)
{
return blocking_notifier_chain_unregister(&mi_disp_notifier_list, nb);
}
EXPORT_SYMBOL(mi_disp_unregister_client);
/**
* mi_drm_notifier_call_chain - notify clients of drm_events
* @val: event MSM_DRM_EARLY_EVENT_BLANK or MSM_DRM_EVENT_BLANK
* @v: notifier data, inculde display id and display blank
* event(unblank or power down).
*/
int mi_disp_notifier_call_chain(unsigned long val, void *v)
{
return blocking_notifier_call_chain(&mi_disp_notifier_list, val, v);
}
EXPORT_SYMBOL(mi_disp_notifier_call_chain);