techpack: display: Introduce new exposure dim layer driver
This driver provides exposure adjustment function by Qcom SDE dim layer without change panel hardware brightness to avoid PWM flicker on OLED devices. Thanks to OnePlus' opensource code for inspiring me to use dim layer. Use expo_calc_backlight to remap brightness with hardware and SDE, checking Disable Hardware Overlays in developer options if you face blocks with differents brightness issue. [Ayrton: Backported from lahaina to SMxx50.0 SDE Driver for compatibility] Signed-off-by: DevriesL <therkduan@gmail.com> Signed-off-by: Carlos Ayrton Lopez Arroyo <15030201@itcelaya.edu.mx>
This commit is contained in:
parent
b26fd3f0db
commit
a73e986502
@ -80,6 +80,8 @@ msm_drm-$(CONFIG_DRM_SDE_RSC) += sde_rsc.o \
|
||||
sde_rsc_hw.o \
|
||||
sde_rsc_hw_v3.o \
|
||||
|
||||
msm_drm-$(CONFIG_DRM_SDE_EXPO) += sde/sde_expo_dim_layer.o
|
||||
|
||||
msm_drm-$(CONFIG_DRM_MSM_DSI) += dsi/dsi_phy.o \
|
||||
dsi/dsi_pwr.o \
|
||||
dsi/dsi_phy.o \
|
||||
|
@ -22,6 +22,10 @@
|
||||
#include "sde_dbg.h"
|
||||
#include "dsi_parser.h"
|
||||
|
||||
#ifdef CONFIG_DRM_SDE_EXPO
|
||||
#include "sde_expo_dim_layer.h"
|
||||
#endif
|
||||
|
||||
#define to_dsi_display(x) container_of(x, struct dsi_display, host)
|
||||
#define INT_BASE_10 10
|
||||
|
||||
@ -234,6 +238,12 @@ int dsi_display_set_backlight(struct drm_connector *connector,
|
||||
goto error;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DRM_SDE_EXPO
|
||||
if (bl_lvl && !panel->mi_cfg.in_aod) {
|
||||
bl_temp = expo_map_dim_level((u32)bl_temp, dsi_display);
|
||||
}
|
||||
#endif
|
||||
|
||||
rc = dsi_panel_set_backlight(panel, (u32)bl_temp);
|
||||
if (rc)
|
||||
DSI_ERR("unable to set backlight\n");
|
||||
|
@ -171,6 +171,9 @@ enum msm_mdp_crtc_property {
|
||||
CRTC_PROP_IDLE_PC_STATE,
|
||||
CRCT_PROP_MI_FOD_SYNC_INFO,
|
||||
|
||||
#ifdef CONFIG_DRM_SDE_EXPO
|
||||
CRTC_PROP_DIM_LAYER_EXPO,
|
||||
#endif
|
||||
/* total # of properties */
|
||||
CRTC_PROP_COUNT
|
||||
};
|
||||
|
@ -45,6 +45,11 @@
|
||||
#include "xiaomi_frame_stat.h"
|
||||
#include "dsi_display.h"
|
||||
|
||||
#ifdef CONFIG_DRM_SDE_EXPO
|
||||
#include "dsi_display.h"
|
||||
#include "dsi_panel.h"
|
||||
#endif
|
||||
|
||||
#define SDE_PSTATES_MAX (SDE_STAGE_MAX * 4)
|
||||
#define SDE_MULTIRECT_PLANE_MAX (SDE_STAGE_MAX * 2)
|
||||
#define IDLE_TIMEOUT_DEFAULT (1100)
|
||||
@ -1483,6 +1488,12 @@ static void _sde_crtc_blend_setup_mixer(struct drm_crtc *crtc,
|
||||
if (cstate->fod_dim_layer)
|
||||
_sde_crtc_setup_dim_layer_cfg(crtc, sde_crtc,
|
||||
mixer, cstate->fod_dim_layer);
|
||||
#ifdef CONFIG_DRM_SDE_EXPO
|
||||
if (cstate->exposure_dim_layer) {
|
||||
_sde_crtc_setup_dim_layer_cfg(crtc, sde_crtc,
|
||||
mixer, cstate->exposure_dim_layer);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
_sde_crtc_program_lm_output_roi(crtc);
|
||||
@ -2599,6 +2610,49 @@ static void _sde_crtc_set_dim_layer_v1(struct drm_crtc *crtc,
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DRM_SDE_EXPO
|
||||
static int sde_crtc_config_exposure_dim_layer(struct drm_crtc_state *crtc_state, int stage)
|
||||
{
|
||||
struct sde_kms *kms;
|
||||
struct sde_hw_dim_layer *dim_layer;
|
||||
struct sde_crtc_state *cstate = to_sde_crtc_state(crtc_state);
|
||||
struct drm_display_mode *mode = &crtc_state->adjusted_mode;
|
||||
int alpha = sde_crtc_get_property(cstate, CRTC_PROP_DIM_LAYER_EXPO);
|
||||
struct dsi_display *dsi_display = get_main_display();
|
||||
struct dsi_panel *panel = dsi_display->panel;
|
||||
|
||||
kms = _sde_crtc_get_kms(crtc_state->crtc);
|
||||
if (!kms || !kms->catalog) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (cstate->num_dim_layers == SDE_MAX_DIM_LAYERS - 1) {
|
||||
pr_err("failed to get available dim layer for exposure\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
if ((stage + SDE_STAGE_0) >= kms->catalog->mixer[0].sblk->maxblendstages) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dim_layer = &cstate->dim_layer[cstate->num_dim_layers];
|
||||
dim_layer->flags = SDE_DRM_DIM_LAYER_INCLUSIVE;
|
||||
dim_layer->stage = stage + SDE_STAGE_0;
|
||||
|
||||
dim_layer->rect.x = 0;
|
||||
dim_layer->rect.y = 0;
|
||||
dim_layer->rect.w = mode->hdisplay;
|
||||
dim_layer->rect.h = mode->vdisplay;
|
||||
dim_layer->color_fill = (struct sde_mdss_color) {0, 0, 0, alpha};
|
||||
cstate->exposure_dim_layer = dim_layer;
|
||||
|
||||
dim_layer->flags = SDE_CRTC_DIRTY_DIM_LAYER_EXPO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* _sde_crtc_set_dest_scaler - copy dest scaler settings from userspace
|
||||
* @sde_crtc : Pointer to sde crtc
|
||||
@ -4839,6 +4893,27 @@ static int _sde_crtc_check_get_pstates(struct drm_crtc *crtc,
|
||||
return rc;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DRM_SDE_EXPO
|
||||
static int sde_crtc_exposure_atomic_check(struct sde_crtc_state *cstate,
|
||||
struct plane_state *pstates, int cnt)
|
||||
{
|
||||
int i, zpos = 0;
|
||||
|
||||
for (i = 0; i < cnt; i++) {
|
||||
if (pstates[i].stage > zpos)
|
||||
zpos = pstates[i].stage;
|
||||
}
|
||||
zpos++;
|
||||
|
||||
if (sde_crtc_config_exposure_dim_layer(&cstate->base, zpos)) {
|
||||
SDE_ERROR("Failed to config dim layer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int _sde_crtc_check_zpos(struct drm_crtc_state *state,
|
||||
struct sde_crtc *sde_crtc,
|
||||
struct plane_state *pstates,
|
||||
@ -4947,6 +5022,12 @@ static int _sde_crtc_atomic_check_pstates(struct drm_crtc *crtc,
|
||||
|
||||
sde_crtc_fod_atomic_check(cstate, pstates, cnt);
|
||||
|
||||
#ifdef CONFIG_DRM_SDE_EXPO
|
||||
rc = sde_crtc_exposure_atomic_check(cstate, pstates, cnt);
|
||||
if (rc)
|
||||
return rc;
|
||||
#endif
|
||||
|
||||
/* assign mixer stages based on sorted zpos property */
|
||||
rc = _sde_crtc_check_zpos(state, sde_crtc, pstates, cstate, mode, cnt);
|
||||
if (rc)
|
||||
@ -5383,6 +5464,11 @@ static void sde_crtc_install_properties(struct drm_crtc *crtc,
|
||||
msm_property_install_volatile_range(&sde_crtc->property_info,
|
||||
"output_fence", 0x0, 0, ~0, 0, CRTC_PROP_OUTPUT_FENCE);
|
||||
|
||||
#ifdef CONFIG_DRM_SDE_EXPO
|
||||
msm_property_install_volatile_range(&sde_crtc->property_info,
|
||||
"dim_layer_exposure", 0x0, 0, ~0, 0, CRTC_PROP_DIM_LAYER_EXPO);
|
||||
#endif
|
||||
|
||||
msm_property_install_range(&sde_crtc->property_info,
|
||||
"output_fence_offset", 0x0, 0, 1, 0,
|
||||
CRTC_PROP_OUTPUT_FENCE_OFFSET);
|
||||
|
@ -409,6 +409,12 @@ typedef struct sde_crtc_mi_dc_backlight
|
||||
int32_t mi_dc_bl_layer_alpha;
|
||||
} sde_crtc_mi_dc_backlight;
|
||||
|
||||
#ifdef CONFIG_DRM_SDE_EXPO
|
||||
enum sde_crtc_dirty_flags {
|
||||
SDE_CRTC_DIRTY_DIM_LAYER_EXPO,
|
||||
};
|
||||
#endif
|
||||
|
||||
typedef struct sde_crtc_mi_layer
|
||||
{
|
||||
int32_t layer_index;
|
||||
@ -489,6 +495,9 @@ struct sde_crtc_state {
|
||||
/* Mi crtc state */
|
||||
struct sde_crtc_mi_state mi_state;
|
||||
uint32_t num_dim_layers_bank;
|
||||
#ifdef CONFIG_DRM_SDE_EXPO
|
||||
struct sde_hw_dim_layer *exposure_dim_layer;
|
||||
#endif
|
||||
};
|
||||
|
||||
enum sde_crtc_irq_state {
|
||||
|
102
techpack/display/msm/sde/sde_expo_dim_layer.c
Normal file
102
techpack/display/msm/sde/sde_expo_dim_layer.c
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* A new exposure driver based on SDE dim layer for OLED devices
|
||||
*
|
||||
* Copyright (C) 2012-2014, The Linux Foundation. All rights reserved.
|
||||
* Copyright (C) 2019, Devries <therkduan@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "dsi_display.h"
|
||||
#include "sde_crtc.h"
|
||||
#include "sde_expo_dim_layer.h"
|
||||
|
||||
static int interpolate(int x, int xa, int xb, int ya, int yb)
|
||||
{
|
||||
int bf, factor, plus;
|
||||
int sub = 0;
|
||||
|
||||
bf = 2 * (yb - ya) * (x - xa) / (xb - xa);
|
||||
factor = bf / 2;
|
||||
plus = bf % 2;
|
||||
if ((xa - xb) && (yb - ya))
|
||||
sub = 2 * (x - xa) * (x - xb) / (yb - ya) / (xa - xb);
|
||||
|
||||
return ya + factor + plus + sub;
|
||||
}
|
||||
|
||||
static int brightness_to_alpha(uint8_t brightness)
|
||||
{
|
||||
int level = ARRAY_SIZE(brightness_alpha_lut);
|
||||
int index, alpha;
|
||||
|
||||
for (index = 0; index < ARRAY_SIZE(brightness_alpha_lut); index++) {
|
||||
if (brightness_alpha_lut[index][BRIGHTNESS] >= brightness)
|
||||
break;
|
||||
}
|
||||
|
||||
if (index == 0)
|
||||
alpha = brightness_alpha_lut[0][ALPHA];
|
||||
else if (index == level)
|
||||
alpha = brightness_alpha_lut[level - 1][ALPHA];
|
||||
else
|
||||
alpha = interpolate(brightness,
|
||||
brightness_alpha_lut[index - 1][BRIGHTNESS],
|
||||
brightness_alpha_lut[index][BRIGHTNESS],
|
||||
brightness_alpha_lut[index - 1][ALPHA],
|
||||
brightness_alpha_lut[index][ALPHA]);
|
||||
|
||||
return alpha;
|
||||
}
|
||||
|
||||
static void set_dim_layer_exposure(uint8_t brightness, struct dsi_display *display)
|
||||
{
|
||||
struct drm_crtc *crtc;
|
||||
struct drm_crtc_state *state;
|
||||
struct msm_drm_private *priv;
|
||||
struct drm_property *prop;
|
||||
|
||||
if (!display->drm_conn) {
|
||||
pr_err("The display is not connected!!\n");
|
||||
return;
|
||||
};
|
||||
|
||||
if (!display->drm_conn->state->crtc) {
|
||||
pr_err("No CRTC on display connector!!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
crtc = display->drm_conn->state->crtc;
|
||||
state = crtc->state;
|
||||
priv = crtc->dev->dev_private;
|
||||
prop = priv->crtc_property[CRTC_PROP_DIM_LAYER_EXPO];
|
||||
|
||||
crtc->funcs->atomic_set_property(crtc, state, prop, (uint64_t)brightness_to_alpha(brightness));
|
||||
}
|
||||
|
||||
uint32_t expo_map_dim_level(uint32_t level, struct dsi_display *display)
|
||||
{
|
||||
uint32_t override_level, brightness;
|
||||
uint8_t dim_brightness;
|
||||
|
||||
if (level < DIM_THRES_LEVEL) {
|
||||
override_level = DIM_THRES_LEVEL;
|
||||
} else {
|
||||
override_level = level;
|
||||
}
|
||||
|
||||
brightness = level / BACKLIGHT_DIM_SCALE;
|
||||
dim_brightness = brightness > U8_MAX ? U8_MAX : brightness;
|
||||
|
||||
set_dim_layer_exposure(dim_brightness, display);
|
||||
|
||||
return override_level;
|
||||
}
|
54
techpack/display/msm/sde/sde_expo_dim_layer.h
Normal file
54
techpack/display/msm/sde/sde_expo_dim_layer.h
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* A new exposure driver based on SDE dim layer for OLED devices
|
||||
*
|
||||
* Copyright (C) 2012-2014, The Linux Foundation. All rights reserved.
|
||||
* Copyright (C) 2019, Devries <therkduan@gmail.com>
|
||||
*
|
||||
* 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 SDE_EXPO_DIM_LAYER_H
|
||||
#define SDE_EXPO_DIM_LAYER_H
|
||||
|
||||
#define DIM_THRES_LEVEL 440
|
||||
#define BACKLIGHT_DIM_SCALE 6
|
||||
|
||||
enum {
|
||||
BRIGHTNESS = 0,
|
||||
ALPHA = 1,
|
||||
LUT_MAX,
|
||||
};
|
||||
|
||||
static const uint8_t brightness_alpha_lut[][LUT_MAX] = {
|
||||
/* {brightness, alpha} */
|
||||
{0, 0xFF},
|
||||
{2, 0xE0},
|
||||
{3, 0xD5},
|
||||
{4, 0xD3},
|
||||
{5, 0xD0},
|
||||
{6, 0xCE},
|
||||
{7, 0xCB},
|
||||
{8, 0xC8},
|
||||
{9, 0xC4},
|
||||
{10, 0xBA},
|
||||
{12, 0xB0},
|
||||
{15, 0xA0},
|
||||
{20, 0x8B},
|
||||
{30, 0x72},
|
||||
{32, 0x5A},
|
||||
{45, 0x38},
|
||||
{60, 0x0E},
|
||||
{78, 0x00}
|
||||
};
|
||||
|
||||
uint32_t expo_map_dim_level(uint32_t level, struct dsi_display *display);
|
||||
|
||||
#endif /* SDE_EXPO_DIM_LAYER_H */
|
Loading…
Reference in New Issue
Block a user