techpack: display: implement fod hbm mode
Change-Id: I5e7061386243b21a6365634b3aff7ea73f5c08f1
This commit is contained in:
parent
4ee3ac9f50
commit
2bfa0ef8e8
@ -291,6 +291,10 @@ enum dsi_cmd_set_type {
|
||||
DSI_CMD_SET_QSYNC_OFF,
|
||||
DSI_CMD_SET_MI_DOZE_HBM,
|
||||
DSI_CMD_SET_MI_DOZE_HBM_NOLP,
|
||||
DSI_CMD_SET_MI_LOCAL_HBM_NORMAL_WHITE_1000NIT,
|
||||
DSI_CMD_SET_MI_LOCAL_HBM_HLPM_WHITE_1000NIT,
|
||||
DSI_CMD_SET_MI_LOCAL_HBM_OFF_TO_NORMAL,
|
||||
DSI_CMD_SET_MI_LOCAL_HBM_OFF_TO_HLPM,
|
||||
DSI_CMD_SET_MAX
|
||||
};
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <video/mipi_display.h>
|
||||
|
||||
#include "dsi_panel.h"
|
||||
#include "dsi_display.h"
|
||||
#include "dsi_ctrl_hw.h"
|
||||
#include "dsi_parser.h"
|
||||
#include "sde_dbg.h"
|
||||
@ -649,6 +650,126 @@ int dsi_panel_set_doze_status(struct dsi_panel *panel, bool status) {
|
||||
return dsi_panel_update_doze(panel);
|
||||
}
|
||||
|
||||
static int dsi_panel_update_cmd_reg51(struct dsi_panel *panel, enum dsi_cmd_set_type type,
|
||||
int bl_lvl)
|
||||
{
|
||||
struct dsi_display_mode_priv_info *priv_info;
|
||||
struct dsi_cmd_desc *cmds = NULL;
|
||||
u32 count;
|
||||
u32 index;
|
||||
u8 *tx_buf;
|
||||
|
||||
if (!panel || !panel->cur_mode || !panel->cur_mode->priv_info) {
|
||||
DSI_ERR("invalid params\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
priv_info = panel->cur_mode->priv_info;
|
||||
|
||||
switch (type) {
|
||||
case DSI_CMD_SET_MI_LOCAL_HBM_NORMAL_WHITE_1000NIT:
|
||||
index = panel->local_hbm_on_1000nit_51_index;
|
||||
break;
|
||||
default:
|
||||
DSI_ERR("wrong cmd type!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (index == -1) {
|
||||
DSI_ERR("cmd %d does not have an index for register 0x51\n", type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cmds = priv_info->cmd_sets[type].cmds;
|
||||
count = priv_info->cmd_sets[type].count;
|
||||
if (!cmds || count <= index) {
|
||||
DSI_ERR("cmd %d does not contain index %d\n", type, index);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
tx_buf = (u8 *)cmds[index].msg.tx_buf;
|
||||
if (!tx_buf) {
|
||||
DSI_ERR("cmd %d tx_buf is null\n", type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (tx_buf[0] != 0x51) {
|
||||
DSI_ERR("cmd %d tx_buf[0] is not for register 0x51\n", type, tx_buf[0]);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
tx_buf[1] = (bl_lvl >> 8) & 0x07;
|
||||
tx_buf[2] = bl_lvl & 0xff;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dsi_panel_set_fod_hbm(struct dsi_panel *panel, bool status)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (status == panel->fod_hbm_enabled)
|
||||
return 0;
|
||||
|
||||
panel->fod_hbm_enabled = status;
|
||||
|
||||
if (status) {
|
||||
if (panel->doze_enabled) {
|
||||
rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_MI_LOCAL_HBM_HLPM_WHITE_1000NIT);
|
||||
if (rc)
|
||||
DSI_ERR("[%s] failed to send doze local hbm on cmd, rc=%d\n",
|
||||
panel->name, rc);
|
||||
} else {
|
||||
rc = dsi_panel_update_cmd_reg51(panel,
|
||||
DSI_CMD_SET_MI_LOCAL_HBM_NORMAL_WHITE_1000NIT,
|
||||
panel->bl_config.real_bl_level);
|
||||
rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_MI_LOCAL_HBM_NORMAL_WHITE_1000NIT);
|
||||
if (rc)
|
||||
DSI_ERR("[%s] failed to send local hbm on cmd, rc=%d\n",
|
||||
panel->name, rc);
|
||||
}
|
||||
} else {
|
||||
if (panel->doze_enabled) {
|
||||
rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_MI_LOCAL_HBM_OFF_TO_HLPM);
|
||||
if (rc)
|
||||
DSI_ERR("[%s] failed to send doze local hbm off cmd, rc=%d\n",
|
||||
panel->name, rc);
|
||||
} else {
|
||||
rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_MI_LOCAL_HBM_OFF_TO_NORMAL);
|
||||
if (rc)
|
||||
DSI_ERR("[%s] failed to send local hbm off cmd, rc=%d\n",
|
||||
panel->name, rc);
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int dsi_panel_is_fod_hbm_applied(struct dsi_panel *panel)
|
||||
{
|
||||
bool value;
|
||||
mutex_lock(&panel->panel_lock);
|
||||
value = panel->fod_hbm_requested == panel->fod_hbm_enabled;
|
||||
mutex_unlock(&panel->panel_lock);
|
||||
return value;
|
||||
}
|
||||
|
||||
int dsi_panel_get_fod_hbm(struct dsi_panel *panel)
|
||||
{
|
||||
bool value;
|
||||
mutex_lock(&panel->panel_lock);
|
||||
value = panel->fod_hbm_enabled;
|
||||
mutex_unlock(&panel->panel_lock);
|
||||
return value;
|
||||
}
|
||||
|
||||
void dsi_panel_apply_requested_fod_hbm(struct dsi_panel *panel)
|
||||
{
|
||||
mutex_lock(&panel->panel_lock);
|
||||
dsi_panel_set_fod_hbm(panel, panel->fod_hbm_requested);
|
||||
mutex_unlock(&panel->panel_lock);
|
||||
}
|
||||
|
||||
int dsi_panel_set_backlight(struct dsi_panel *panel, u32 bl_lvl)
|
||||
{
|
||||
int rc = 0;
|
||||
@ -1801,6 +1922,10 @@ const char *cmd_set_prop_map[DSI_CMD_SET_MAX] = {
|
||||
"qcom,mdss-dsi-qsync-off-commands",
|
||||
"mi,mdss-dsi-doze-hbm-command",
|
||||
"mi,mdss-dsi-doze-hbm-nolp-command",
|
||||
"mi,mdss-dsi-local-hbm-normal-white-1000nit-command",
|
||||
"mi,mdss-dsi-local-hbm-hlpm-white-1000nit-command",
|
||||
"mi,mdss-dsi-local-hbm-off-to-normal-command",
|
||||
"mi,mdss-dsi-local-hbm-off-to-hlpm-command",
|
||||
};
|
||||
|
||||
const char *cmd_set_state_map[DSI_CMD_SET_MAX] = {
|
||||
@ -1829,6 +1954,10 @@ const char *cmd_set_state_map[DSI_CMD_SET_MAX] = {
|
||||
"qcom,mdss-dsi-qsync-off-commands-state",
|
||||
"mi,mdss-dsi-doze-hbm-command-state",
|
||||
"mi,mdss-dsi-doze-hbm-nolp-command-state",
|
||||
"mi,mdss-dsi-local-hbm-normal-white-1000nit-command-state",
|
||||
"mi,mdss-dsi-local-hbm-hlpm-white-1000nit-command-state",
|
||||
"mi,mdss-dsi-local-hbm-off-to-normal-command-state",
|
||||
"mi,mdss-dsi-local-hbm-off-to-hlpm-command-state",
|
||||
};
|
||||
|
||||
int dsi_panel_get_cmd_pkt_count(const char *data, u32 length, u32 *cnt)
|
||||
@ -3471,6 +3600,20 @@ error:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int dsi_panel_parse_fod(struct dsi_panel *panel)
|
||||
{
|
||||
struct dsi_parser_utils *utils = &panel->utils;
|
||||
int rc;
|
||||
|
||||
panel->local_hbm_on_1000nit_51_index = -1;
|
||||
rc = utils->read_u32(utils->data, "mi,local-hbm-on-1000nit-51-index",
|
||||
&panel->local_hbm_on_1000nit_51_index);
|
||||
if (rc)
|
||||
DSI_INFO("mi,local-hbm-on-1000nit-51-index not specified\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dsi_panel_update_util(struct dsi_panel *panel,
|
||||
struct device_node *parser_node)
|
||||
{
|
||||
@ -3519,6 +3662,99 @@ static void dsi_panel_setup_vm_ops(struct dsi_panel *panel, bool trusted_vm_env)
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t sysfs_fod_hbm_write(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct dsi_display *display;
|
||||
struct dsi_panel *panel;
|
||||
bool status;
|
||||
int rc = 0;
|
||||
|
||||
display = dev_get_drvdata(dev);
|
||||
if (!display) {
|
||||
DSI_ERR("Invalid display\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = kstrtobool(buf, &status);
|
||||
if (rc) {
|
||||
DSI_ERR("%s: kstrtobool failed. rc=%d\n", __func__, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
panel = display->panel;
|
||||
|
||||
mutex_lock(&panel->panel_lock);
|
||||
if (!panel->panel_initialized)
|
||||
goto exit;
|
||||
|
||||
panel->fod_hbm_requested = status;
|
||||
|
||||
exit:
|
||||
mutex_unlock(&panel->panel_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t sysfs_fod_ui_read(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct dsi_display *display;
|
||||
struct dsi_panel *panel;
|
||||
bool status;
|
||||
|
||||
display = dev_get_drvdata(dev);
|
||||
if (!display) {
|
||||
pr_err("Invalid display\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
panel = display->panel;
|
||||
|
||||
mutex_lock(&panel->panel_lock);
|
||||
status = panel->fod_ui;
|
||||
mutex_unlock(&panel->panel_lock);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", status);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(fod_hbm, 0200, NULL, sysfs_fod_hbm_write);
|
||||
static DEVICE_ATTR(fod_ui, 0400, sysfs_fod_ui_read, NULL);
|
||||
|
||||
static struct attribute *panel_attrs[] = {
|
||||
&dev_attr_fod_hbm.attr,
|
||||
&dev_attr_fod_ui.attr,
|
||||
NULL,
|
||||
};
|
||||
static struct attribute_group panel_attrs_group = {
|
||||
.attrs = panel_attrs,
|
||||
};
|
||||
|
||||
void dsi_panel_set_fod_ui(struct dsi_panel *panel, bool status)
|
||||
{
|
||||
mutex_lock(&panel->panel_lock);
|
||||
panel->fod_ui = status;
|
||||
mutex_unlock(&panel->panel_lock);
|
||||
|
||||
sysfs_notify(&panel->parent->kobj, NULL, "fod_ui");
|
||||
}
|
||||
|
||||
static int dsi_panel_sysfs_init(struct dsi_panel *panel)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
rc = sysfs_create_group(&panel->parent->kobj, &panel_attrs_group);
|
||||
if (rc)
|
||||
DSI_ERR("failed to create panel sysfs attributes\n");
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void dsi_panel_sysfs_deinit(struct dsi_panel *panel)
|
||||
{
|
||||
sysfs_remove_group(&panel->parent->kobj, &panel_attrs_group);
|
||||
}
|
||||
|
||||
struct dsi_panel *dsi_panel_get(struct device *parent,
|
||||
struct device_node *of_node,
|
||||
struct device_node *parser_node,
|
||||
@ -3635,6 +3871,10 @@ struct dsi_panel *dsi_panel_get(struct device *parent,
|
||||
if (rc)
|
||||
DSI_DEBUG("failed to parse esd config, rc=%d\n", rc);
|
||||
|
||||
rc = dsi_panel_parse_fod(panel);
|
||||
if (rc)
|
||||
DSI_DEBUG("failed to parse fod, rc=%d\n", rc);
|
||||
|
||||
rc = dsi_panel_vreg_get(panel);
|
||||
if (rc) {
|
||||
DSI_ERR("[%s] failed to get panel regulators, rc=%d\n",
|
||||
@ -3647,11 +3887,18 @@ struct dsi_panel *dsi_panel_get(struct device *parent,
|
||||
panel->drm_panel.dev = &panel->mipi_device.dev;
|
||||
panel->mipi_device.dev.of_node = of_node;
|
||||
panel->doze_enabled = false;
|
||||
panel->fod_ui = false;
|
||||
panel->fod_hbm_enabled = false;
|
||||
panel->fod_hbm_requested = false;
|
||||
|
||||
rc = drm_panel_add(&panel->drm_panel);
|
||||
if (rc)
|
||||
goto error_vreg_put;
|
||||
|
||||
rc = dsi_panel_sysfs_init(panel);
|
||||
if (rc)
|
||||
goto error;
|
||||
|
||||
mutex_init(&panel->panel_lock);
|
||||
|
||||
return panel;
|
||||
@ -3669,6 +3916,8 @@ void dsi_panel_put(struct dsi_panel *panel)
|
||||
/* free resources allocated for ESD check */
|
||||
dsi_panel_esd_config_deinit(&panel->esd_config);
|
||||
|
||||
dsi_panel_sysfs_deinit(panel);
|
||||
|
||||
kfree(panel);
|
||||
}
|
||||
|
||||
|
@ -270,6 +270,11 @@ struct dsi_panel {
|
||||
struct dsi_panel_ops panel_ops;
|
||||
|
||||
bool doze_enabled;
|
||||
|
||||
bool fod_hbm_enabled;
|
||||
bool fod_hbm_requested;
|
||||
bool fod_ui;
|
||||
int local_hbm_on_1000nit_51_index;
|
||||
};
|
||||
|
||||
static inline bool dsi_panel_ulps_feature_enabled(struct dsi_panel *panel)
|
||||
@ -405,4 +410,10 @@ int dsi_panel_create_cmd_packets(const char *data, u32 length, u32 count,
|
||||
void dsi_panel_destroy_cmd_packets(struct dsi_panel_cmd_set *set);
|
||||
|
||||
void dsi_panel_dealloc_cmd_packets(struct dsi_panel_cmd_set *set);
|
||||
|
||||
int dsi_panel_is_fod_hbm_applied(struct dsi_panel *panel);
|
||||
int dsi_panel_get_fod_hbm(struct dsi_panel *panel);
|
||||
void dsi_panel_apply_requested_fod_hbm(struct dsi_panel *panel);
|
||||
void dsi_panel_set_fod_ui(struct dsi_panel *panel, bool status);
|
||||
|
||||
#endif /* _DSI_PANEL_H_ */
|
||||
|
@ -825,6 +825,78 @@ struct sde_connector_dyn_hdr_metadata *sde_connector_get_dyn_hdr_meta(
|
||||
return &c_state->dyn_hdr_meta;
|
||||
}
|
||||
|
||||
void sde_connector_fod_pre_kickoff(struct drm_connector *connector)
|
||||
{
|
||||
struct sde_connector *c_conn;
|
||||
struct dsi_display *display;
|
||||
struct dsi_panel *panel;
|
||||
|
||||
if (!connector)
|
||||
return;
|
||||
|
||||
c_conn = to_sde_connector(connector);
|
||||
if (c_conn->connector_type != DRM_MODE_CONNECTOR_DSI)
|
||||
return;
|
||||
|
||||
display = (struct dsi_display *) c_conn->display;
|
||||
if (!display)
|
||||
return;
|
||||
|
||||
if (display->display_selection_type != DSI_PRIMARY)
|
||||
return;
|
||||
|
||||
panel = display->panel;
|
||||
if (!panel)
|
||||
return;
|
||||
|
||||
if (dsi_panel_is_fod_hbm_applied(panel))
|
||||
return;
|
||||
|
||||
dsi_panel_apply_requested_fod_hbm(panel);
|
||||
|
||||
if (!dsi_panel_get_fod_hbm(panel))
|
||||
dsi_panel_set_fod_ui(panel, 0);
|
||||
}
|
||||
|
||||
void sde_connector_fod_post_kickoff(struct drm_connector *connector)
|
||||
{
|
||||
static bool old_fod_hbm_enabled = false;
|
||||
struct sde_connector *c_conn;
|
||||
struct dsi_display *display;
|
||||
struct dsi_panel *panel;
|
||||
bool fod_hbm_enabled;
|
||||
|
||||
if (!connector)
|
||||
return;
|
||||
|
||||
c_conn = to_sde_connector(connector);
|
||||
if (c_conn->connector_type != DRM_MODE_CONNECTOR_DSI)
|
||||
return;
|
||||
|
||||
display = (struct dsi_display *) c_conn->display;
|
||||
if (!display)
|
||||
return;
|
||||
|
||||
if (display->display_selection_type != DSI_PRIMARY)
|
||||
return;
|
||||
|
||||
panel = display->panel;
|
||||
if (!panel)
|
||||
return;
|
||||
|
||||
if (!dsi_panel_is_fod_hbm_applied(panel))
|
||||
return;
|
||||
|
||||
fod_hbm_enabled = dsi_panel_get_fod_hbm(panel);
|
||||
if (fod_hbm_enabled && fod_hbm_enabled != old_fod_hbm_enabled) {
|
||||
sde_encoder_wait_for_event(c_conn->encoder, MSM_ENC_TX_COMPLETE);
|
||||
sde_encoder_wait_for_event(c_conn->encoder, MSM_ENC_VBLANK);
|
||||
dsi_panel_set_fod_ui(panel, 1);
|
||||
}
|
||||
|
||||
old_fod_hbm_enabled = fod_hbm_enabled;
|
||||
}
|
||||
|
||||
int sde_connector_pre_kickoff(struct drm_connector *connector)
|
||||
{
|
||||
struct sde_connector *c_conn;
|
||||
@ -870,6 +942,8 @@ int sde_connector_pre_kickoff(struct drm_connector *connector)
|
||||
|
||||
SDE_EVT32_VERBOSE(connector->base.id);
|
||||
|
||||
sde_connector_fod_pre_kickoff(connector);
|
||||
|
||||
rc = c_conn->ops.pre_kickoff(connector, c_conn->display, ¶ms);
|
||||
|
||||
if (c_conn->connector_type == DRM_MODE_CONNECTOR_DSI)
|
||||
|
@ -1116,4 +1116,6 @@ int sde_connector_get_panel_vfp(struct drm_connector *connector,
|
||||
*/
|
||||
int sde_connector_esd_status(struct drm_connector *connector);
|
||||
|
||||
void sde_connector_fod_post_kickoff(struct drm_connector *connector);
|
||||
|
||||
#endif /* _SDE_CONNECTOR_H_ */
|
||||
|
@ -1517,6 +1517,8 @@ static void sde_kms_complete_commit(struct msm_kms *kms,
|
||||
pr_err("Connector Post kickoff failed rc=%d\n",
|
||||
rc);
|
||||
}
|
||||
|
||||
sde_connector_fod_post_kickoff(connector);
|
||||
}
|
||||
|
||||
vm_ops = sde_vm_get_ops(sde_kms);
|
||||
|
Loading…
Reference in New Issue
Block a user