techpack: display: Import Xiaomi changes

* From dagu-s-oss

Change-Id: Ifa6dad25e33b9b27a1ae59ee98da415ae0ed07e6
This commit is contained in:
Sebastiano Barezzi
2022-11-21 23:22:53 +01:00
committed by Sebastiano Barezzi
parent b13d1eec55
commit ab2c13308c
47 changed files with 8739 additions and 139 deletions

View File

@@ -35,6 +35,7 @@ msm_drm-$(CONFIG_DRM_MSM_SDE) += sde/sde_crtc.o \
sde/sde_kms.o \
sde/sde_plane.o \
sde/sde_connector.o \
sde/clone_cooling_device.o \
sde/sde_color_processing.o \
sde/sde_vbif.o \
sde_io_util.o \
@@ -100,6 +101,9 @@ msm_drm-$(CONFIG_DRM_MSM_DSI) += dsi/dsi_phy.o \
dsi/dsi_panel.o \
dsi/dsi_clk_manager.o \
dsi/dsi_display_test.o \
dsi/dsi_display_mi.o \
dsi/dsi_panel_mi.o \
dsi/mi_disp_lhbm.o \
msm_drm-$(CONFIG_DSI_PARSER) += dsi/dsi_parser.o \

View File

@@ -83,6 +83,8 @@ static void dsi_catalog_cmn_init(struct dsi_ctrl_hw *ctrl,
ctrl->ops.config_clk_gating = NULL;
ctrl->ops.map_mdp_regs = NULL;
ctrl->ops.log_line_count = NULL;
ctrl->ops.configure_cmddma_window = NULL;
ctrl->ops.reset_trig_ctrl = NULL;
break;
case DSI_CTRL_VERSION_2_0:
ctrl->ops.setup_lane_map = dsi_ctrl_hw_20_setup_lane_map;
@@ -100,6 +102,8 @@ static void dsi_catalog_cmn_init(struct dsi_ctrl_hw *ctrl,
ctrl->ops.config_clk_gating = NULL;
ctrl->ops.map_mdp_regs = NULL;
ctrl->ops.log_line_count = NULL;
ctrl->ops.configure_cmddma_window = NULL;
ctrl->ops.reset_trig_ctrl = NULL;
break;
case DSI_CTRL_VERSION_2_2:
case DSI_CTRL_VERSION_2_3:
@@ -122,6 +126,10 @@ static void dsi_catalog_cmn_init(struct dsi_ctrl_hw *ctrl,
dsi_ctrl_hw_kickoff_non_embedded_mode;
ctrl->ops.map_mdp_regs = dsi_ctrl_hw_22_map_mdp_regs;
ctrl->ops.log_line_count = dsi_ctrl_hw_22_log_line_count;
ctrl->ops.configure_cmddma_window =
dsi_ctrl_hw_22_configure_cmddma_window;
ctrl->ops.reset_trig_ctrl =
dsi_ctrl_hw_22_reset_trigger_controls;
break;
default:
break;

View File

@@ -274,5 +274,12 @@ int dsi_phy_hw_v4_0_cache_phy_timings(struct dsi_phy_per_lane_cfgs *timings,
int dsi_ctrl_hw_22_map_mdp_regs(struct platform_device *pdev,
struct dsi_ctrl_hw *ctrl);
void dsi_ctrl_hw_22_configure_cmddma_window(struct dsi_ctrl_hw *ctrl,
struct dsi_ctrl_cmd_dma_info *cmd,
u32 line_no, u32 window);
void dsi_ctrl_hw_22_reset_trigger_controls(struct dsi_ctrl_hw *ctrl,
struct dsi_host_common_cfg *cfg);
u32 dsi_ctrl_hw_22_log_line_count(struct dsi_ctrl_hw *ctrl, bool cmd_mode);
#endif /* _DSI_CATALOG_H_ */

View File

@@ -552,6 +552,7 @@ static int dsi_ctrl_init_regmap(struct platform_device *pdev,
}
ctrl->hw.mmss_misc_base = ptr;
ctrl->hw.disp_cc_base = NULL;
ctrl->hw.mdp_intf_base = NULL;
break;
case DSI_CTRL_VERSION_2_2:
case DSI_CTRL_VERSION_2_3:
@@ -564,6 +565,10 @@ static int dsi_ctrl_init_regmap(struct platform_device *pdev,
}
ctrl->hw.disp_cc_base = ptr;
ctrl->hw.mmss_misc_base = NULL;
ptr = msm_ioremap(pdev, "mdp_intf_base", ctrl->name);
if (!IS_ERR(ptr))
ctrl->hw.mdp_intf_base = ptr;
break;
default:
break;
@@ -1226,6 +1231,61 @@ int dsi_message_validate_tx_mode(struct dsi_ctrl *dsi_ctrl,
return rc;
}
static void dsi_configure_command_scheduling(struct dsi_ctrl *dsi_ctrl,
struct dsi_ctrl_cmd_dma_info *cmd_mem)
{
u32 line_no = 0, window = 0, sched_line_no = 0;
struct dsi_ctrl_hw_ops dsi_hw_ops = dsi_ctrl->hw.ops;
struct dsi_mode_info *timing = &(dsi_ctrl->host_config.video_timing);
line_no = dsi_ctrl->host_config.common_config.dma_sched_line;
window = dsi_ctrl->host_config.common_config.dma_sched_window;
SDE_EVT32(dsi_ctrl->cell_index, SDE_EVTLOG_FUNC_ENTRY, line_no, window);
/*
* In case of command scheduling in video mode, the line at which
* the command is scheduled can revert to the default value i.e. 1
* for the following cases:
* 1) No schedule line defined by the panel.
* 2) schedule line defined is greater than VFP.
*/
if ((dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE) &&
dsi_hw_ops.schedule_dma_cmd &&
(dsi_ctrl->current_state.vid_engine_state ==
DSI_CTRL_ENGINE_ON)) {
sched_line_no = (line_no == 0) ? 1 : line_no;
if (timing) {
if (sched_line_no >= timing->v_front_porch)
sched_line_no = 1;
sched_line_no += timing->v_back_porch +
timing->v_sync_width + timing->v_active;
}
dsi_hw_ops.schedule_dma_cmd(&dsi_ctrl->hw, sched_line_no);
}
/*
* In case of command scheduling in command mode, the window size
* is reset to zero, if the total scheduling window is greater
* than the panel height.
*/
if ((dsi_ctrl->host_config.panel_mode == DSI_OP_CMD_MODE) &&
dsi_hw_ops.configure_cmddma_window) {
sched_line_no = line_no;
if ((sched_line_no + window) > timing->v_active)
window = 0;
sched_line_no += timing->v_active;
dsi_hw_ops.configure_cmddma_window(&dsi_ctrl->hw, cmd_mem,
sched_line_no, window);
}
SDE_EVT32(dsi_ctrl->cell_index, SDE_EVTLOG_FUNC_EXIT,
sched_line_no, window);
}
static u32 calculate_schedule_line(struct dsi_ctrl *dsi_ctrl, u32 flags)
{
u32 line_no = 0x1;
@@ -1234,7 +1294,7 @@ static u32 calculate_schedule_line(struct dsi_ctrl *dsi_ctrl, u32 flags)
/* check if custom dma scheduling line needed */
if ((dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE) &&
(flags & DSI_CTRL_CMD_CUSTOM_DMA_SCHED))
line_no = dsi_ctrl->host_config.u.video_engine.dma_sched_line;
line_no = dsi_ctrl->host_config.common_config.dma_sched_line;
timing = &(dsi_ctrl->host_config.video_timing);
@@ -1252,20 +1312,31 @@ static void dsi_kickoff_msg_tx(struct dsi_ctrl *dsi_ctrl,
u32 flags)
{
u32 hw_flags = 0;
u32 line_no = 0x1;
struct dsi_ctrl_hw_ops dsi_hw_ops = dsi_ctrl->hw.ops;
SDE_EVT32(dsi_ctrl->cell_index, SDE_EVTLOG_FUNC_ENTRY, flags,
msg->flags);
line_no = calculate_schedule_line(dsi_ctrl, flags);
if (dsi_ctrl->hw.reset_trig_ctrl)
dsi_hw_ops.reset_trig_ctrl(&dsi_ctrl->hw,
&dsi_ctrl->host_config.common_config);
if ((dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE) &&
dsi_hw_ops.schedule_dma_cmd &&
(dsi_ctrl->current_state.vid_engine_state ==
DSI_CTRL_ENGINE_ON))
dsi_hw_ops.schedule_dma_cmd(&dsi_ctrl->hw,
line_no);
/*
* Always enable DMA scheduling for video mode panel.
*
* In video mode panel, if the DMA is triggered very close to
* the beginning of the active window and the DMA transfer
* happens in the last line of VBP, then the HW state will
* stay in ‘wait’ and return to ‘idle’ in the first line of VFP.
* But somewhere in the middle of the active window, if SW
* disables DSI command mode engine while the HW is still
* waiting and re-enable after timing engine is OFF. So the
* HW never ‘sees’ another vblank line and hence it gets
* stuck in the ‘wait’ state.
*/
if ((flags & DSI_CTRL_CMD_CUSTOM_DMA_SCHED) ||
(dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE))
dsi_configure_command_scheduling(dsi_ctrl, cmd_mem);
dsi_ctrl->cmd_mode = (dsi_ctrl->host_config.panel_mode ==
DSI_OP_CMD_MODE);

View File

@@ -854,6 +854,25 @@ struct dsi_ctrl_hw_ops {
* @cmd_mode:» Boolean to indicate command mode operation.
*/
u32 (*log_line_count)(struct dsi_ctrl_hw *ctrl, bool cmd_mode);
/**
* hw.ops.configure_cmddma_window() - configure DMA window for CMD TX
* @ctrl: Pointer to the controller host hardware.
* @cmd: Pointer to the DSI DMA command info.
* @line_no: Line number at which the CMD needs to be triggered.
* @window: Width of the DMA CMD window.
*/
void (*configure_cmddma_window)(struct dsi_ctrl_hw *ctrl,
struct dsi_ctrl_cmd_dma_info *cmd,
u32 line_no, u32 window);
/**
* hw.ops.reset_trig_ctrl() - resets trigger control of DSI controller
* @ctrl: Pointer to the controller host hardware.
* @cfg: Common configuration parameters.
*/
void (*reset_trig_ctrl)(struct dsi_ctrl_hw *ctrl,
struct dsi_host_common_cfg *cfg);
};
/*
@@ -891,6 +910,7 @@ struct dsi_ctrl_hw {
void __iomem *te_rd_ptr_reg;
void __iomem *line_count_reg;
u32 disp_cc_length;
void __iomem *mdp_intf_base;
u32 index;
/* features */
@@ -903,6 +923,7 @@ struct dsi_ctrl_hw {
bool phy_isolation_enabled;
bool null_insertion_enabled;
bool reset_trig_ctrl;
};
#endif /* _DSI_CTRL_HW_H_ */

View File

@@ -12,6 +12,12 @@
/* register to configure DMA scheduling */
#define DSI_DMA_SCHEDULE_CTRL 0x100
#define DSI_DMA_SCHEDULE_CTRL2 0x0104
/* offset addresses of MDP INTF base register, to be mapped for debug feature */
#define MDP_INTF_TEAR_OFFSET 0x280
#define MDP_INTF_TEAR_LINE_COUNT_OFFSET 0x30
#define MDP_INTF_LINE_COUNT_OFFSET 0xB0
/* MDP INTF registers to be mapped*/
#define MDP_INTF1_TEAR_LINE_COUNT 0xAE6BAB0
@@ -51,6 +57,7 @@ void dsi_ctrl_hw_22_schedule_dma_cmd(struct dsi_ctrl_hw *ctrl, int line_no)
reg |= (line_no & 0xffff);
DSI_W32(ctrl, DSI_DMA_SCHEDULE_CTRL, reg);
ctrl->reset_trig_ctrl = true;
}
/*
@@ -181,10 +188,85 @@ u32 dsi_ctrl_hw_22_log_line_count(struct dsi_ctrl_hw *ctrl, bool cmd_mode)
u32 reg = 0;
if (cmd_mode && ctrl->te_rd_ptr_reg)
reg = readl_relaxed(ctrl->te_rd_ptr_reg);
else if (ctrl->line_count_reg)
reg = readl_relaxed(ctrl->line_count_reg);
if (IS_ERR_OR_NULL(ctrl->mdp_intf_base))
return reg;
if (cmd_mode)
reg = readl_relaxed(ctrl->mdp_intf_base + MDP_INTF_TEAR_OFFSET
+ MDP_INTF_TEAR_LINE_COUNT_OFFSET);
else
reg = readl_relaxed(ctrl->mdp_intf_base
+ MDP_INTF_LINE_COUNT_OFFSET);
return reg;
}
/**
* dsi_ctrl_hw_22_configure_cmddma_window() - configure DMA window for CMD TX
* @ctrl: Pointer to the controller host hardware.
* @cmd: Pointer to the DSI DMA command info.
* @line_no: Line number at which the CMD needs to be triggered.
* @window: Width of the DMA CMD window.
*/
void dsi_ctrl_hw_22_configure_cmddma_window(struct dsi_ctrl_hw *ctrl,
struct dsi_ctrl_cmd_dma_info *cmd,
u32 line_no, u32 window)
{
u32 reg = 0;
if (!window)
return;
if (cmd->en_broadcast) {
reg = DSI_R32(ctrl, DSI_TRIG_CTRL);
if (cmd->is_master) {
reg &= ~0xF;
reg |= 0xc;
} else {
reg &= ~0xF;
reg |= BIT(16);
}
DSI_W32(ctrl, DSI_TRIG_CTRL, reg);
if (cmd->is_master) {
reg = 0;
reg |= line_no;
reg |= window << 16;
DSI_W32(ctrl, DSI_DMA_SCHEDULE_CTRL2, reg);
}
} else {
reg = DSI_R32(ctrl, DSI_TRIG_CTRL);
reg &= ~0xF;
reg |= 0xc;
DSI_W32(ctrl, DSI_TRIG_CTRL, reg);
reg = 0;
reg |= line_no;
reg |= window << 16;
DSI_W32(ctrl, DSI_DMA_SCHEDULE_CTRL2, reg);
}
ctrl->reset_trig_ctrl = true;
}
/**
* dsi_ctrl_hw_22_reset_trigger_controls() - reset dsi trigger configurations
* @ctrl: Pointer to the controller host hardware.
* @cfg: DSI host configuration that is common to both video and
* command modes.
*/
void dsi_ctrl_hw_22_reset_trigger_controls(struct dsi_ctrl_hw *ctrl,
struct dsi_host_common_cfg *cfg)
{
u32 reg = 0;
const u8 trigger_map[DSI_TRIGGER_MAX] = {
0x0, 0x2, 0x1, 0x4, 0x5, 0x6 };
reg |= (cfg->te_mode == DSI_TE_ON_EXT_PIN) ? BIT(31) : 0;
reg |= (trigger_map[cfg->dma_cmd_trigger] & 0x7);
reg |= (trigger_map[cfg->mdp_cmd_trigger] & 0x7) << 4;
DSI_W32(ctrl, DSI_TRIG_CTRL, reg);
DSI_W32(ctrl, DSI_DMA_SCHEDULE_CTRL2, 0x0);
DSI_W32(ctrl, DSI_DMA_SCHEDULE_CTRL, 0x0);
ctrl->reset_trig_ctrl = false;
}

View File

@@ -297,6 +297,7 @@ enum dsi_cmd_set_type {
DSI_CMD_SET_POST_CMD_TO_VID_SWITCH,
DSI_CMD_SET_VID_TO_CMD_SWITCH,
DSI_CMD_SET_POST_VID_TO_CMD_SWITCH,
DSI_CMD_SET_PANEL_STATUS_OFFSET,
DSI_CMD_SET_PANEL_STATUS,
DSI_CMD_SET_LP1,
DSI_CMD_SET_LP2,
@@ -307,6 +308,107 @@ enum dsi_cmd_set_type {
DSI_CMD_SET_POST_TIMING_SWITCH,
DSI_CMD_SET_QSYNC_ON,
DSI_CMD_SET_QSYNC_OFF,
/* xiaomi add start */
DSI_CMD_SET_MI_CEON,
DSI_CMD_SET_MI_CEOFF,
DSI_CMD_SET_MI_CABCUION,
DSI_CMD_SET_MI_CABCSTILLON,
DSI_CMD_SET_MI_CABCMOVIEON,
DSI_CMD_SET_MI_CABCOFF,
DSI_CMD_SET_MI_SKINCE_CABCUION,
DSI_CMD_SET_MI_SKINCE_CABCSTILLON,
DSI_CMD_SET_MI_SKINCE_CABCMOVIEON,
DSI_CMD_SET_MI_SKINCE_CABCOFF,
DSI_CMD_SET_MI_DIMMINGON,
DSI_CMD_SET_MI_DIMMINGOFF,
DSI_CMD_SET_MI_ACL_OFF,
DSI_CMD_SET_MI_ACL_L1,
DSI_CMD_SET_MI_ACL_L2,
DSI_CMD_SET_MI_ACL_L3,
DSI_CMD_SET_DISP_LCD_HBM_L1_ON,
DSI_CMD_SET_DISP_LCD_HBM_L2_ON,
DSI_CMD_SET_DISP_LCD_HBM_L3_ON,
DSI_CMD_SET_DISP_LCD_HBM_OFF,
DSI_CMD_SET_MI_HBM_ON,
DSI_CMD_SET_MI_HBM_OFF,
DSI_CMD_SET_MI_HBM_FOD_ON,
DSI_CMD_SET_MI_HBM_FOD_OFF,
DSI_CMD_SET_MI_FOD_LHBM_WHITE_1000NIT,
DSI_CMD_SET_MI_FOD_LHBM_WHITE_110NIT,
DSI_CMD_SET_MI_FOD_LHBM_GREEN_500NIT,
DSI_CMD_SET_MI_FOD_LHBM_OFF,
DSI_CMD_SET_MI_FOD_LHBM_GREEN_500NIT_READ_REG_PRE,
DSI_CMD_SET_MI_FOD_LHBM_GREEN_500NIT_READ_REG,
DSI_CMD_SET_MI_FOD_LHBM_WHITE_1000NIT_GIR_OFF_READ_REG_PRE,
DSI_CMD_SET_MI_FOD_LHBM_WHITE_1000NIT_GIR_ON_READ_REG_PRE,
DSI_CMD_SET_MI_FOD_LHBM_WHITE_110NIT_GIR_OFF_READ_REG_PRE,
DSI_CMD_SET_MI_FOD_LHBM_WHITE_110NIT_GIR_ON_READ_REG_PRE,
DSI_CMD_SET_MI_FOD_LHBM_WHITE_1000NIT_READ_OFFSET_REG,
DSI_CMD_SET_MI_FOD_LHBM_WHITE_110NIT_READ_OFFSET_REG,
DSI_CMD_SET_MI_FOD_LHBM_WHITE_READ_B2_REG,
DSI_CMD_SET_MI_FOD_LHBM_WHITE_READ_B5_REG,
DSI_CMD_SET_MI_FOD_LHBM_WHITE_READ_B8_REG,
DSI_CMD_SET_MI_HBM_HDR_ON,
DSI_CMD_SET_MI_HBM_HDR_OFF,
DSI_CMD_SET_MI_HBM_FOD2NORM,
DSI_CMD_SET_MI_NORMAL1,
DSI_CMD_SET_MI_CRC_DCIP3,
DSI_CMD_SET_MI_SRGB,
DSI_CMD_SET_MI_DOZE_HBM,
DSI_CMD_SET_MI_DOZE_LBM,
DSI_CMD_SET_MI_CRC_OFF,
DSI_CMD_SET_MI_ELVSS_DIMMING_OFF,
DSI_CMD_SET_MI_FLAT_MODE_ON,
DSI_CMD_SET_MI_FLAT_MODE_OFF,
DSI_CMD_SET_MI_GIR_ON,
DSI_CMD_SET_MI_GIR_OFF,
DSI_CMD_SET_MI_GIR_READ_REG_PRE,
DSI_CMD_SET_MI_GIR_OFF_READ_REG_PRE,
DSI_CMD_SET_MI_GIR_READ_REG,
DSI_CMD_SET_TIMING_SWITCH_GIR_ON,
DSI_CMD_SET_MI_LEVEL2_KEY_ENABLE,
DSI_CMD_SET_MI_GAMMA_OTP_READ_C8,
DSI_CMD_SET_MI_GAMMA_OTP_READ_C9,
DSI_CMD_SET_MI_GAMMA_OTP_READ_B3_PRE,
DSI_CMD_SET_MI_GAMMA_OTP_READ_B3,
DSI_CMD_SET_MI_LEVEL2_KEY_DISABLE,
DSI_CMD_SET_MI_GAMMA_FLASH_READ_PRE,
DSI_CMD_SET_MI_GAMMA_FLASH_READ_FB,
DSI_CMD_SET_MI_WHITE_POINT_READ,
DSI_CMD_SET_MI_ELVSS_DIMMING_OFFSET,
DSI_CMD_SET_MI_ELVSS_DIMMING_READ,
DSI_CMD_SET_MI_DC_ON,
DSI_CMD_SET_MI_DC_OFF,
DSI_CMD_SET_MI_VI_SETTING_LOW,
DSI_CMD_SET_MI_VI_SETTING_HIGH,
DSI_CMD_SET_MI_SWITCH_PAGE4,
DSI_CMD_SET_MI_DC_READ,
DSI_CMD_SET_MI_DC_READ_D2,
DSI_CMD_SET_MI_DC_READ_D4,
DSI_CMD_SET_MI_AOD_TO_DC_ON,
DSI_CMD_SET_MI_DYNAMIC_ELVSS_ON,
DSI_CMD_SET_MI_DYNAMIC_ELVSS_OFF,
DSI_CMD_SET_MI_GAMMA_PRE_READ,
DSI_CMD_SET_MI_GAMMA_READ_1ST_PRE,
DSI_CMD_SET_MI_GAMMA_READ_2ND_PRE,
DSI_CMD_SET_MI_GAMMA_READ_3RD_PRE,
DSI_CMD_SET_MI_GAMMA_READ_4TH_PRE,
DSI_CMD_SET_MI_GAMMA_READ_5TH_PRE,
DSI_CMD_SET_MI_GAMMA_READ_6TH_PRE,
DSI_CMD_SET_MI_GAMMA_READ_B7,
DSI_CMD_SET_MI_GAMMA_B7,
DSI_CMD_SET_MI_BLACK_SETTING,
DSI_CMD_SET_MI_READ_LOCKDOWN_INFO,
DSI_CMD_SET_DISP_PEN_120HZ,
DSI_CMD_SET_DISP_PEN_60HZ,
DSI_CMD_SET_DISP_PEN_30HZ,
DSI_CMD_SET_DISABLE_INSERT_BLACK,
DSI_CMD_SET_INSERT_BLACK,
DSI_CMD_SET_MI_ROUND_ON,
DSI_CMD_SET_MI_ROUND_OFF,
DSI_CMD_SET_MI_DIM_FP_DBV_MAX_IN_HBM,
DSI_CMD_SET_MI_DIM_FP_DBV_MAX_IN_NORMAL,
/* xiaomi add end */
DSI_CMD_SET_MAX
};
@@ -515,6 +617,10 @@ struct dsi_host_common_cfg {
enum dsi_phy_type phy_type;
struct dsi_split_link_config split_link;
u32 byte_intf_clk_div;
u32 clk_strength;
bool cphy_strength;
u32 dma_sched_line;
u32 dma_sched_window;
};
/**

View File

@@ -7,12 +7,14 @@
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/err.h>
#include <drm/drm_notifier_mi.h>
#include "msm_drv.h"
#include "sde_connector.h"
#include "msm_mmu.h"
#include "dsi_display.h"
#include "dsi_panel.h"
#include "dsi_panel_mi.h"
#include "dsi_ctrl.h"
#include "dsi_ctrl_hw.h"
#include "dsi_drm.h"
@@ -33,6 +35,10 @@
#define DSI_CLOCK_BITRATE_RADIX 10
#define MAX_TE_SOURCE_ID 2
DEFINE_MUTEX(dsi_display_clk_mutex);
extern int mi_disp_lhbm_attach_primary_dsi_display(struct dsi_display *display);
static char dsi_display_primary[MAX_CMDLINE_PARAM_LEN];
static char dsi_display_secondary[MAX_CMDLINE_PARAM_LEN];
static struct dsi_display_boot_param boot_displays[MAX_DSI_ACTIVE_DISPLAY] = {
@@ -246,7 +252,7 @@ int dsi_display_set_backlight(struct drm_connector *connector,
return rc;
}
static int dsi_display_cmd_engine_enable(struct dsi_display *display)
int dsi_display_cmd_engine_enable(struct dsi_display *display)
{
int rc = 0;
int i;
@@ -290,7 +296,7 @@ static int dsi_display_cmd_engine_enable(struct dsi_display *display)
return rc;
}
static int dsi_display_cmd_engine_disable(struct dsi_display *display)
int dsi_display_cmd_engine_disable(struct dsi_display *display)
{
int rc = 0;
int i;
@@ -476,7 +482,7 @@ static void dsi_display_register_te_irq(struct dsi_display *display)
}
/* Allocate memory for cmd dma tx buffer */
static int dsi_host_alloc_cmd_tx_buffer(struct dsi_display *display)
int dsi_host_alloc_cmd_tx_buffer(struct dsi_display *display)
{
int rc = 0, cnt = 0;
struct dsi_display_ctrl *display_ctrl;
@@ -646,8 +652,10 @@ static int dsi_display_read_status(struct dsi_display_ctrl *ctrl,
lenp = config->status_valid_params ?: config->status_cmds_rlen;
count = config->status_cmd.count;
cmds = config->status_cmd.cmds;
flags |= (DSI_CTRL_CMD_FETCH_MEMORY | DSI_CTRL_CMD_READ |
DSI_CTRL_CMD_CUSTOM_DMA_SCHED);
flags |= (DSI_CTRL_CMD_FETCH_MEMORY | DSI_CTRL_CMD_READ);
if (ctrl->ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE)
flags |= DSI_CTRL_CMD_CUSTOM_DMA_SCHED;
for (i = 0; i < count; ++i) {
memset(config->status_buf, 0x0, SZ_4K);
@@ -655,6 +663,10 @@ static int dsi_display_read_status(struct dsi_display_ctrl *ctrl,
cmds[i].msg.flags |= MIPI_DSI_MSG_LASTCOMMAND;
flags |= DSI_CTRL_CMD_LAST_COMMAND;
}
if ((cmds[i].msg.flags & MIPI_DSI_MSG_CMD_DMA_SCHED) &&
(panel->panel_initialized))
flags |= DSI_CTRL_CMD_CUSTOM_DMA_SCHED;
if (config->status_cmd.state == DSI_CMD_SET_STATE_LP)
cmds[i].msg.flags |= MIPI_DSI_MSG_USE_LPM;
cmds[i].msg.rx_buf = config->status_buf;
@@ -781,6 +793,7 @@ int dsi_display_check_status(struct drm_connector *connector, void *display,
bool te_check_override)
{
struct dsi_display *dsi_display = display;
struct drm_panel_esd_config *config;
struct dsi_panel *panel;
u32 status_mode;
int rc = 0x1, ret;
@@ -832,6 +845,11 @@ int dsi_display_check_status(struct drm_connector *connector, void *display,
dsi_display_mask_ctrl_error_interrupts(dsi_display, mask, true);
if (status_mode == ESD_MODE_REG_READ) {
config = &(panel->esd_config);
if (config->offset_cmd.count != 0) {
rc = dsi_panel_write_cmd_set(panel, &config->offset_cmd);
}
rc = dsi_display_status_reg_read(dsi_display);
} else if (status_mode == ESD_MODE_SW_BTA) {
rc = dsi_display_status_bta_request(dsi_display);
@@ -1045,24 +1063,46 @@ int dsi_display_set_power(struct drm_connector *connector,
int power_mode, void *disp)
{
struct dsi_display *display = disp;
struct dsi_panel_mi_cfg *mi_cfg;
int rc = 0;
struct mi_drm_notifier notify_data;
if (!display || !display->panel) {
DSI_ERR("invalid display/panel\n");
return -EINVAL;
}
mi_cfg = &display->panel->mi_cfg;
notify_data.data = &power_mode;
notify_data.id = MSM_DRM_PRIMARY_DISPLAY;
switch (power_mode) {
case SDE_MODE_DPMS_LP1:
mi_cfg->in_aod = true;
mi_drm_notifier_call_chain(MI_DRM_EARLY_EVENT_BLANK, &notify_data);
rc = dsi_panel_set_lp1(display->panel);
if (mi_cfg->unset_doze_brightness)
dsi_panel_set_doze_brightness(display->panel,
mi_cfg->unset_doze_brightness, true);
mi_drm_notifier_call_chain(MI_DRM_EVENT_BLANK, &notify_data);
break;
case SDE_MODE_DPMS_LP2:
mi_cfg->in_aod = true;
mi_drm_notifier_call_chain(MI_DRM_EARLY_EVENT_BLANK, &notify_data);
rc = dsi_panel_set_lp2(display->panel);
if (mi_cfg->unset_doze_brightness)
dsi_panel_set_doze_brightness(display->panel,
mi_cfg->unset_doze_brightness, true);
mi_drm_notifier_call_chain(MI_DRM_EVENT_BLANK, &notify_data);
break;
case SDE_MODE_DPMS_ON:
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_drm_notifier_call_chain(MI_DRM_EARLY_EVENT_BLANK, &notify_data);
rc = dsi_panel_set_nolp(display->panel);
mi_drm_notifier_call_chain(MI_DRM_EVENT_BLANK, &notify_data);
}
break;
case SDE_MODE_DPMS_OFF:
default:
@@ -2760,6 +2800,12 @@ static int dsi_display_broadcast_cmd(struct dsi_display *display,
m_flags |= DSI_CTRL_CMD_LAST_COMMAND;
}
if ((msg->flags & MIPI_DSI_MSG_CMD_DMA_SCHED) &&
(display->panel->panel_initialized)) {
flags |= DSI_CTRL_CMD_CUSTOM_DMA_SCHED;
m_flags |= DSI_CTRL_CMD_CUSTOM_DMA_SCHED;
}
if (display->queue_cmd_waits ||
msg->flags & MIPI_DSI_MSG_ASYNC_OVERRIDE) {
flags |= DSI_CTRL_CMD_ASYNC_WAIT;
@@ -2940,6 +2986,10 @@ static ssize_t dsi_host_transfer(struct mipi_dsi_host *host,
msg->flags & MIPI_DSI_MSG_ASYNC_OVERRIDE)
cmd_flags |= DSI_CTRL_CMD_ASYNC_WAIT;
if ((msg->flags & MIPI_DSI_MSG_CMD_DMA_SCHED) &&
(display->panel->panel_initialized))
cmd_flags |= DSI_CTRL_CMD_CUSTOM_DMA_SCHED;
rc = dsi_ctrl_cmd_transfer(display->ctrl[ctrl_idx].ctrl, msg,
&cmd_flags);
if (rc) {
@@ -4951,7 +5001,23 @@ int dsi_display_splash_res_cleanup(struct dsi_display *display)
static int dsi_display_force_update_dsi_clk(struct dsi_display *display)
{
int rc = 0;
int rc = 0, i = 0;
struct dsi_display_ctrl *ctrl;
/*
* The force update dsi clock, is the only clock update function that toggles the state of
* DSI clocks without any ref count protection. With the addition of ASYNC command wait,
* there is a need for adding a check for any queued waits before updating these clocks.
*/
display_for_each_ctrl(i, display) {
ctrl = &display->ctrl[i];
if (!ctrl->ctrl || !ctrl->ctrl->dma_wait_queued)
continue;
flush_workqueue(display->dma_cmd_workq);
cancel_work_sync(&ctrl->ctrl->dma_cmd_wait);
ctrl->ctrl->dma_wait_queued = false;
}
rc = dsi_display_link_clk_force_update_ctrl(display->dsi_clk_handle);
@@ -5210,6 +5276,10 @@ static int dsi_display_bind(struct device *dev,
/* register te irq handler */
dsi_display_register_te_irq(display);
rc = mi_disp_lhbm_attach_primary_dsi_display(display);
if (rc)
DSI_ERR("lhbm attach primary_dsi_display fail\n");
goto error;
error_host_deinit:
@@ -5416,6 +5486,7 @@ int dsi_display_dev_probe(struct platform_device *pdev)
display->panel_node = panel_node;
display->pdev = pdev;
display->boot_disp = boot_disp;
display->is_prim_display = true;
dsi_display_parse_cmdline_topology(display, index);
@@ -6782,6 +6853,11 @@ int dsi_display_set_mode(struct dsi_display *display,
timing.h_active, timing.v_active,
timing.refresh_rate);
if (display->panel->cur_mode->timing.refresh_rate != timing.refresh_rate) {
if (display->drm_conn && display->drm_conn->kdev)
sysfs_notify(&display->drm_conn->kdev->kobj, NULL, "dynamic_fps");
}
memcpy(display->panel->cur_mode, &adj_mode, sizeof(adj_mode));
error:
mutex_unlock(&display->display_lock);
@@ -7598,6 +7674,69 @@ int dsi_display_enable(struct dsi_display *display)
display->panel->panel_initialized = true;
DSI_DEBUG("cont splash enabled, display enable not required\n");
rc = dsi_panel_update_elvss_dimming(display->panel);
if (rc) {
DSI_ERR("[%s] failed to update elvss dimming parameter, rc=%d\n",
display->name, rc);
}
rc = dsi_panel_read_gamma_param(display->panel);
if (rc) {
DSI_ERR("[%s] failed to read gamma para, rc=%d\n",
display->name, rc);
} else {
rc = dsi_panel_update_gamma_param(display->panel);
if (rc) {
DSI_ERR("[%s] failed to update gamma para, rc=%d\n",
display->name, rc);
}
}
rc = dsi_panel_read_dc_param(display->panel);
if (rc) {
DSI_ERR("[%s] failed to read DC para, rc=%d\n",
display->name, rc);
} else {
rc = dsi_panel_update_dc_param(display->panel);
if (rc) {
DSI_ERR("[%s] failed to update DC para, rc=%d\n",
display->name, rc);
}
}
rc = mi_dsi_panel_read_and_update_dc_param_v2(display->panel);
if (rc) {
DSI_ERR("[%s] failed to read DC para, rc=%d\n",
display->name, rc);
}
rc = mi_dsi_panel_read_and_update_gir_param(display->panel);
if (rc) {
DSI_ERR("[%s] failed to read and update gir para, rc=%d\n",
display->name, rc);
}
rc = mi_dsi_panel_read_and_update_lhbm_green_500nit_param(display->panel);
if (rc) {
DSI_ERR("[%s] failed to read and update fod lhbm green 500nit para, rc=%d\n",
display->name, rc);
}
rc = mi_dsi_panel_read_lhbm_white_param(display->panel);
if (rc) {
DSI_ERR("[%s] failed to read fod lhbm white para, rc=%d\n",
display->name, rc);
}
if (display->panel->mi_cfg.is_tddi_flag) {
rc = dsi_panel_lockdowninfo_param_read(display->panel);
if (!rc) {
DSI_ERR("[%s] failed to read lockdowninfo para, rc=%d\n",
display->name, rc);
}
}
return 0;
}
@@ -7636,10 +7775,28 @@ int dsi_display_enable(struct dsi_display *display)
if (mode->dsi_mode_flags & DSI_MODE_FLAG_DMS) {
rc = dsi_panel_switch(display->panel);
if (rc)
if (rc) {
DSI_ERR("[%s] failed to switch DSI panel mode, rc=%d\n",
display->name, rc);
goto error;
}
if ((display->panel->mi_cfg.panel_id >> 8) == 0x4A3153004202) {
rc = dsi_panel_dc_switch(display->panel);
if (rc) {
DSI_ERR("[%s] failed to set dc command, rc=%d\n",
display->name, rc);
goto error;
}
}
rc = dsi_panel_switch_disp_rate_gpio(display->panel);
if (rc) {
DSI_ERR("[%s] failed to set disp_rate gpio, rc=%d\n",
display->name, rc);
goto error;
}
goto error;
}

View File

@@ -199,6 +199,7 @@ struct dsi_display {
const char *display_type;
struct list_head list;
bool is_cont_splash_enabled;
bool is_prim_display;
bool sw_te_using_wd;
struct mutex display_lock;
int disp_te_gpio;
@@ -735,4 +736,14 @@ int dsi_display_cont_splash_config(void *display);
int dsi_display_get_panel_vfp(void *display,
int h_active, int v_active);
int dsi_display_cmd_engine_enable(struct dsi_display *display);
int dsi_display_cmd_engine_disable(struct dsi_display *display);
int dsi_host_alloc_cmd_tx_buffer(struct dsi_display *display);
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);
#endif /* _DSI_DISPLAY_H_ */

View File

@@ -0,0 +1,117 @@
/*
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
*
* 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.
*
*/
#define pr_fmt(fmt) "mi-dsi-display:[%s] " fmt, __func__
#include <linux/list.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/err.h>
#include "msm_drv.h"
#include "sde_connector.h"
#include "msm_mmu.h"
#include "dsi_display.h"
#include "dsi_panel.h"
#include "dsi_panel_mi.h"
#include "dsi_ctrl.h"
#include "dsi_ctrl_hw.h"
#include "dsi_drm.h"
#include "dsi_clk.h"
#include "dsi_pwr.h"
#include "sde_dbg.h"
#include "dsi_parser.h"
#include "dsi_mi_feature.h"
#include "../msm_drv.h"
#define to_dsi_bridge(x) container_of((x), struct dsi_bridge, base)
static atomic64_t g_param = ATOMIC64_INIT(0);
int dsi_display_set_disp_param(struct drm_connector *connector,
u32 param_type)
{
struct dsi_display *display = NULL;
struct dsi_bridge *c_bridge = NULL;
int ret = 0;
if (!connector || !connector->encoder || !connector->encoder->bridge) {
pr_err("Invalid connector/encoder/bridge ptr\n");
return -EINVAL;
}
c_bridge = to_dsi_bridge(connector->encoder->bridge);
display = c_bridge->display;
if (!display || !display->panel) {
pr_err("Invalid display/panel ptr\n");
return -EINVAL;
}
atomic64_set(&g_param, param_type);
if (sde_kms_is_suspend_blocked(display->drm_dev) &&
dsi_panel_is_need_tx_cmd(param_type)) {
pr_err("sde_kms is suspended, skip to set_disp_param\n");
return -EBUSY;
}
ret = dsi_panel_set_disp_param(display->panel, param_type);
return ret;
}
int dsi_display_hbm_set_disp_param(struct drm_connector *connector,
u32 op_code)
{
int rc;
struct sde_connector *c_conn;
c_conn = to_sde_connector(connector);
pr_debug("%s fod hbm command:0x%x \n", __func__, op_code);
if (op_code == DISPPARAM_HBM_FOD_ON) {
rc = dsi_display_set_disp_param(connector, DISPPARAM_HBM_FOD_ON);
} else if (op_code == DISPPARAM_HBM_FOD_OFF) {
/* close HBM and restore DC */
rc = dsi_display_set_disp_param(connector, DISPPARAM_HBM_FOD_OFF);
} else if(op_code == DISPPARAM_DIMMING_OFF) {
rc = dsi_display_set_disp_param(connector, DISPPARAM_DIMMING_OFF);
} else if (op_code == DISPPARAM_HBM_BACKLIGHT_RESEND) {
rc = dsi_display_set_disp_param(connector, DISPPARAM_HBM_BACKLIGHT_RESEND);
}
return rc;
}
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;
}

View File

@@ -6,12 +6,19 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_atomic.h>
#include <drm/drm_notifier_mi.h>
#include "msm_kms.h"
#include "sde_connector.h"
#include "dsi_drm.h"
#include "sde_trace.h"
#include <drm/drm_bridge.h>
#include <linux/pm_wakeup.h>
#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)
@@ -28,6 +35,13 @@ static struct dsi_display_mode_priv_info default_priv_info = {
.dsc_enabled = false,
};
#define WAIT_RESUME_TIMEOUT 200
struct dsi_bridge *gbridge;
static struct delayed_work prim_panel_work;
static atomic_t prim_panel_is_on;
static struct wakeup_source *prim_panel_wakelock;
static void convert_to_dsi_mode(const struct drm_display_mode *drm_mode,
struct dsi_display_mode *dsi_mode)
{
@@ -165,6 +179,9 @@ static void dsi_bridge_pre_enable(struct drm_bridge *bridge)
{
int rc = 0;
struct dsi_bridge *c_bridge = to_dsi_bridge(bridge);
struct mi_drm_notifier notify_data;
struct dsi_panel_mi_cfg *mi_cfg = NULL;
int power_mode = 0;
if (!bridge) {
DSI_ERR("Invalid params\n");
@@ -179,6 +196,8 @@ 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);
mi_cfg = &c_bridge->display->panel->mi_cfg;
/* By this point mode should have been validated through mode_fixup */
rc = dsi_display_set_mode(c_bridge->display,
&(c_bridge->dsi_mode), 0x0);
@@ -188,6 +207,29 @@ static void dsi_bridge_pre_enable(struct drm_bridge *bridge)
return;
}
if (c_bridge->display->is_prim_display && atomic_read(&prim_panel_is_on) && !mi_cfg->fod_dimlayer_enabled) {
cancel_delayed_work_sync(&prim_panel_work);
__pm_relax(prim_panel_wakelock);
if (c_bridge->display->panel->panel_mode == DSI_OP_VIDEO_MODE) {
DSI_INFO("skip set display config for video panel in fpc\n");
return;
} else if (c_bridge->display->panel->panel_mode == DSI_OP_CMD_MODE &&
c_bridge->dsi_mode.dsi_mode_flags != DSI_MODE_FLAG_DMS) {
DSI_INFO("skip set display config because timming not switch for command panel\n");
return;
}
}
if (mi_cfg->fod_dimlayer_enabled) {
power_mode = sde_connector_get_lp(c_bridge->display->drm_conn);
} else {
power_mode = MI_DRM_BLANK_UNBLANK;
}
notify_data.data = &power_mode;
notify_data.id = MSM_DRM_PRIMARY_DISPLAY;
mi_drm_notifier_call_chain(MI_DRM_EARLY_EVENT_BLANK, &notify_data);
if (c_bridge->dsi_mode.dsi_mode_flags &
(DSI_MODE_FLAG_SEAMLESS | DSI_MODE_FLAG_VRR |
DSI_MODE_FLAG_DYN_CLK)) {
@@ -212,12 +254,16 @@ static void dsi_bridge_pre_enable(struct drm_bridge *bridge)
c_bridge->id, rc);
(void)dsi_display_unprepare(c_bridge->display);
}
mi_drm_notifier_call_chain(MI_DRM_EVENT_BLANK, &notify_data);
SDE_ATRACE_END("dsi_display_enable");
rc = dsi_display_splash_res_cleanup(c_bridge->display);
if (rc)
DSI_ERR("Continuous splash pipeline cleanup failed, rc=%d\n",
rc);
if (c_bridge->display->is_prim_display)
atomic_set(&prim_panel_is_on, true);
}
static void dsi_bridge_enable(struct drm_bridge *bridge)
@@ -250,6 +296,12 @@ static void dsi_bridge_enable(struct drm_bridge *bridge)
sde_connector_schedule_status_work(display->drm_conn,
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)
@@ -257,16 +309,38 @@ 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;
@@ -285,12 +359,27 @@ static void dsi_bridge_post_disable(struct drm_bridge *bridge)
{
int rc = 0;
struct dsi_bridge *c_bridge = to_dsi_bridge(bridge);
struct mi_drm_notifier notify_data;
struct dsi_panel_mi_cfg *mi_cfg = NULL;
int power_mode = 0;
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_EARLY_EVENT_BLANK, &notify_data);
SDE_ATRACE_BEGIN("dsi_bridge_post_disable");
SDE_ATRACE_BEGIN("dsi_display_disable");
rc = dsi_display_disable(c_bridge->display);
@@ -309,9 +398,25 @@ static void dsi_bridge_post_disable(struct drm_bridge *bridge)
SDE_ATRACE_END("dsi_bridge_post_disable");
return;
}
mi_drm_notifier_call_chain(MI_DRM_EVENT_BLANK, &notify_data);
SDE_ATRACE_END("dsi_bridge_post_disable");
if (c_bridge->display->is_prim_display)
atomic_set(&prim_panel_is_on, false);
}
static void prim_panel_off_delayed_work(struct work_struct *work)
{
mutex_lock(&gbridge->base.lock);
if (atomic_read(&prim_panel_is_on)) {
dsi_bridge_post_disable(&gbridge->base);
__pm_relax(prim_panel_wakelock);
mutex_unlock(&gbridge->base.lock);
return;
}
mutex_unlock(&gbridge->base.lock);
} // git
static void dsi_bridge_mode_set(struct drm_bridge *bridge,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
@@ -426,7 +531,8 @@ static bool dsi_bridge_mode_fixup(struct drm_bridge *bridge,
(!(dsi_mode.dsi_mode_flags & DSI_MODE_FLAG_POMS)) &&
(!(dsi_mode.dsi_mode_flags & DSI_MODE_FLAG_DYN_CLK)) &&
(!crtc_state->active_changed ||
display->is_cont_splash_enabled)) {
display->is_cont_splash_enabled) &&
display->config.panel_mode == DSI_OP_CMD_MODE) {
dsi_mode.dsi_mode_flags |= DSI_MODE_FLAG_DMS;
SDE_EVT32(SDE_EVTLOG_FUNC_CASE2,
@@ -1057,6 +1163,18 @@ struct dsi_bridge *dsi_drm_bridge_init(struct dsi_display *display,
}
encoder->bridge = &bridge->base;
encoder->bridge->is_dsi_drm_bridge = true;
mutex_init(&encoder->bridge->lock);
if (display->is_prim_display) {
gbridge = bridge;
prim_panel_wakelock = wakeup_source_create("prim_panel_wakelock");
wakeup_source_add(prim_panel_wakelock);
atomic_set(&prim_panel_is_on, false);
INIT_DELAYED_WORK(&prim_panel_work, prim_panel_off_delayed_work);
}
return bridge;
error_free_bridge:
kfree(bridge);
@@ -1069,5 +1187,12 @@ void dsi_drm_bridge_cleanup(struct dsi_bridge *bridge)
if (bridge && bridge->base.encoder)
bridge->base.encoder->bridge = NULL;
if (bridge == gbridge) {
atomic_set(&prim_panel_is_on, false);
cancel_delayed_work_sync(&prim_panel_work);
wakeup_source_remove(prim_panel_wakelock);
wakeup_source_destroy(prim_panel_wakelock);
}
kfree(bridge);
}

View File

@@ -23,6 +23,7 @@ struct dsi_bridge {
struct dsi_display *display;
struct dsi_display_mode dsi_mode;
struct mutex lock;
};
/**

View File

@@ -0,0 +1,98 @@
/*
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
*
* 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 _DSI_MI_FEATURE_H_
#define _DSI_MI_FEATURE_H_
enum DISPPARAM_MODE {
DISPPARAM_WARM = 0x1,
DISPPARAM_DEFAULT = 0x2,
DISPPARAM_COLD = 0x3,
DISPPARAM_PAPERMODE8 = 0x5,
DISPPARAM_PAPERMODE1 = 0x6,
DISPPARAM_PAPERMODE2 = 0x7,
DISPPARAM_PAPERMODE3 = 0x8,
DISPPARAM_PAPERMODE4 = 0x9,
DISPPARAM_PAPERMODE5 = 0xA,
DISPPARAM_PAPERMODE6 = 0xB,
DISPPARAM_PAPERMODE7 = 0xC,
DISPPARAM_WHITEPOINT_XY = 0xE,
DISPPARAM_CE_ON = 0x10,
DISPPARAM_CE_OFF = 0xF0,
DISPPARAM_CABCUI_ON = 0x100,
DISPPARAM_CABCSTILL_ON = 0x200,
DISPPARAM_CABCMOVIE_ON = 0x300,
DISPPARAM_CABC_OFF = 0x400,
DISPPARAM_SKIN_CE_CABCUI_ON = 0x500,
DISPPARAM_SKIN_CE_CABCSTILL_ON = 0x600,
DISPPARAM_SKIN_CE_CABCMOVIE_ON = 0x700,
DISPPARAM_SKIN_CE_CABC_OFF = 0x800,
DISPPARAM_DIMMING_OFF = 0xE00,
DISPPARAM_DIMMING = 0xF00,
DISPPARAM_ACL_L1 = 0x1000,
DISPPARAM_ACL_L2 = 0x2000,
DISPPARAM_ACL_L3 = 0x3000,
DISPPARAM_LOW_BRIGHTNESS_FOD = 0xD000,
DISPPARAM_FP_STATUS = 0xE000,
DISPPARAM_ACL_OFF = 0xF000,
DISPPARAM_ROUND_ON = 0xB000,
DISPPARAM_ROUND_OFF = 0xC000,
DISPPARAM_HBM_ON = 0x10000,
DISPPARAM_HBM_FOD_ON = 0x20000,
DISPPARAM_HBM_FOD2NORM = 0x30000,
DISPPARAM_DC_ON = 0x40000,
DISPPARAM_DC_OFF = 0x50000,
DISPPARAM_HBM_HDR_ON = 0x60000,
DISPPARAM_FOD_UNLOCK_SUCCESS = 0x70000,
DISPPARAM_FOD_UNLOCK_FAIL = 0x80000,
DISPPARAM_HBM_HDR_OFF = 0x90000,
DISPPARAM_HBM_FOD_OFF = 0xE0000,
DISPPARAM_HBM_OFF = 0xF0000,
DISPPARAM_LCD_HBM_OFF = 0xA0000,
DISPPARAM_LCD_HBM_L1_ON = 0xB0000,
DISPPARAM_LCD_HBM_L2_ON = 0xC0000,
DISPPARAM_LCD_HBM_L3_ON = 0xD0000,
DISPPARAM_NORMALMODE1 = 0x100000,
DISPPARAM_P3 = 0x200000,
DISPPARAM_SRGB = 0x300000,
DISPPARAM_SKIN_CE = 0x400000,
DISPPARAM_SKIN_CE_OFF = 0x500000,
DISPPARAM_DOZE_BRIGHTNESS_HBM = 0x600000,
DISPPARAM_DOZE_BRIGHTNESS_LBM = 0x700000,
DISPPARAM_DOZE_OFF = 0x800000,
DISPPARAM_HBM_BACKLIGHT_RESEND = 0xA00000,
DISPPARAM_FOD_BACKLIGHT = 0xD00000,
DISPPARAM_CRC_OFF = 0xF00000,
DISPPARAM_FOD_BACKLIGHT_ON = 0x1000000,
DISPPARAM_FOD_BACKLIGHT_OFF = 0x2000000,
DISPPARAM_ELVSS_DIMMING_ON = 0x3000000,
DISPPARAM_ELVSS_DIMMING_OFF = 0x4000000,
DISPPARAM_FLAT_MODE_ON = 0x5000000,
DISPPARAM_FLAT_MODE_OFF = 0x6000000,
DISPPARAM_DITHER_ON = 0x7000000,
DISPPARAM_DITHER_OFF = 0x8000000,
DISPPARAM_SET_THERMAL_HBM_DISABLE = 0xC000000,
DISPPARAM_CLEAR_THERMAL_HBM_DISABLE = 0xD000000,
DISPPARAM_GIR_ON = 0xE0000000,
DISPPARAM_GIR_OFF = 0xF0000000,
};
#endif /* _DSI_MI_FEATURE_H_ */

File diff suppressed because it is too large Load Diff

View File

@@ -20,6 +20,7 @@
#include "dsi_pwr.h"
#include "dsi_parser.h"
#include "msm_drv.h"
#include "dsi_panel_mi.h"
#define MAX_BL_LEVEL 4096
#define MAX_BL_SCALE_LEVEL 1024
@@ -34,6 +35,7 @@
* Override to use async transfer
*/
#define MIPI_DSI_MSG_ASYNC_OVERRIDE BIT(4)
#define MIPI_DSI_MSG_CMD_DMA_SCHED BIT(5)
enum dsi_panel_rotation {
DSI_PANEL_ROTATE_NONE = 0,
@@ -118,6 +120,7 @@ struct dsi_backlight_config {
u32 bl_min_level;
u32 bl_max_level;
u32 brightness_max_level;
u32 brightness_init_level;
u32 bl_level;
u32 bl_scale;
u32 bl_scale_sv;
@@ -145,8 +148,10 @@ struct dsi_panel_reset_config {
u32 count;
int reset_gpio;
int tp_reset_gpio;
int disp_en_gpio;
int lcd_mode_sel_gpio;
u32 reset_powerdown_delay;
u32 mode_sel_state;
};
@@ -163,6 +168,7 @@ struct drm_panel_esd_config {
bool esd_enabled;
enum esd_check_status_mode status_mode;
struct dsi_panel_cmd_set offset_cmd;
struct dsi_panel_cmd_set status_cmd;
u32 *status_cmds_rlen;
u32 *status_valid_params;
@@ -199,6 +205,7 @@ struct dsi_panel {
struct dsi_regulator_info power_info;
struct dsi_backlight_config bl_config;
struct dsi_backlight_config bl_slaver_config;
struct dsi_panel_reset_config reset_config;
struct dsi_pinctrl_info pinctrl;
struct drm_panel_hdr_properties hdr_props;
@@ -222,6 +229,8 @@ struct dsi_panel {
bool sync_broadcast_en;
struct dsi_panel_mi_cfg mi_cfg;
int panel_test_gpio;
int power_mode;
enum dsi_panel_physical_type panel_type;
@@ -330,6 +339,8 @@ int dsi_panel_switch(struct dsi_panel *panel);
int dsi_panel_post_switch(struct dsi_panel *panel);
int dsi_panel_dc_switch(struct dsi_panel *panel);
void dsi_dsc_pclk_param_calc(struct msm_display_dsc_info *dsc, int intf_width);
void dsi_panel_bl_handoff(struct dsi_panel *panel);
@@ -345,4 +356,18 @@ void dsi_panel_ext_bridge_put(struct dsi_panel *panel);
void dsi_panel_calc_dsi_transfer_time(struct dsi_host_common_cfg *config,
struct dsi_display_mode *mode, u32 frame_threshold_us);
int dsi_panel_tx_cmd_set(struct dsi_panel *panel,
enum dsi_cmd_set_type type);
int dsi_panel_update_backlight(struct dsi_panel *panel,
u32 bl_lvl);
int dsi_panel_get_cmd_pkt_count(const char *data, u32 length, u32 *cnt);
int dsi_panel_alloc_cmd_packets(struct dsi_panel_cmd_set *cmd,
u32 packet_count);
int dsi_panel_create_cmd_packets(const char *data,
u32 length,
u32 count,
struct dsi_cmd_desc *cmd);
void dsi_panel_destroy_cmd_packets(struct dsi_panel_cmd_set *set);
void dsi_panel_dealloc_cmd_packets(struct dsi_panel_cmd_set *set);
#endif /* _DSI_PANEL_H_ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,415 @@
/*
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
*
* 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 _DSI_PANEL_MI_H_
#define _DSI_PANEL_MI_H_
#include <linux/of_device.h>
#include <linux/types.h>
#include <linux/bitops.h>
#include <linux/errno.h>
#include <linux/backlight.h>
#include <drm/drm_panel.h>
#include <drm/msm_drm.h>
#include "dsi_defs.h"
#include "dsi_ctrl_hw.h"
#include "dsi_clk.h"
#include "dsi_pwr.h"
#include "dsi_parser.h"
#include "msm_drv.h"
#define DEFAULT_FOD_OFF_DIMMING_DELAY 170
#define DEFAULT_FOD_OFF_ENTER_AOD_DELAY 300
#define DISPPARAM_THERMAL_SET 0x1
#define DEFAULT_CABC_WRITE_DELAY 3000
#define MAX_VSYNC_COUNT 200
enum doze_bkl {
DOZE_TO_NORMAL = 0,
DOZE_BRIGHTNESS_HBM,
DOZE_BRIGHTNESS_LBM,
DOZE_BRIGHTNESS_MAX,
};
enum bkl_dimming_state {
STATE_NONE,
STATE_DIM_BLOCK,
STATE_DIM_RESTORE,
STATE_ALL
};
enum dsi_gamma_cmd_set_type {
DSI_CMD_SET_MI_GAMMA_SWITCH_60HZ = 0,
DSI_CMD_SET_MI_GAMMA_SWITCH_90HZ,
DSI_CMD_SET_MI_GAMMA_SWITCH_MAX
};
/* 60Hz gamma and 90Hz gamma info */
struct gamma_cfg {
bool read_done;
u8 otp_read_c8[135];
u8 otp_read_c9[180];
u8 otp_read_b3[45];
u32 flash_read_total_param;
u32 flash_read_c1_index;
u32 gamma_checksum;
u8 flash_read_c8[135];
u8 flash_read_c9[180];
u8 flash_read_b3[45];
u8 flash_read_checksum[2];
u32 update_c8_index;
u32 update_c9_index;
u32 update_b3_index;
bool update_done_60hz;
bool update_done_90hz;
bool black_setting_flag;
};
/* Enter/Exit DC_LUT info */
struct dc_cfg {
bool read_done;
bool update_done;
u32 update_d2_index;
u8 enter_dc_lut[75];
u8 exit_dc_lut[75];
};
struct dc_cfg_v2 {
bool read_done;
bool update_done;
int update_dc_on_reg_index;
int update_dc_off_reg_index;
u8 enter_dc_lut[75];
u8 exit_dc_lut[75];
};
enum dc_lut_state {
DC_LUT_D2,
DC_LUT_D4,
DC_LUT_MAX
};
enum fingerprint_status {
FINGERPRINT_NONE = 0,
ENROLL_START = 1,
ENROLL_STOP = 2,
AUTH_START = 3,
AUTH_STOP = 4,
HEART_RATE_START = 5,
HEART_RATE_STOP = 6,
};
struct lockdowninfo_cfg {
u8 lockdowninfo[16];
bool lockdowninfo_read_done;
};
struct greenish_gamma_cfg {
u32 index_1st_param;
u32 index_2nd_param;
u32 index_3rd_param;
u32 index_4th_param;
u32 index_5th_param;
u32 index_6th_param;
u32 greenish_gamma_update_offset;
u32 greenish_gamma_update_param_count;
bool gamma_update_done;
};
typedef struct brightness_alpha {
uint32_t brightness;
uint32_t alpha;
} brightness_alpha;
struct gir_cfg {
bool update_done;
int update_index;
int update_index2;
u8 gir_param[4];
};
struct fod_lhbm_green_500nit_cfg {
bool update_done;
int update_index;
u8 fod_lhbm_green_500nit_param[2];
};
struct fod_lhbm_white_cfg {
bool update_done;
int update_index;
int lhbm_white_read_pre;
int lhbm_white_read_offset;
u8 fod_lhbm_white_param[6];
};
enum fod_lhbm_white_state {
FOD_LHBM_WHITE_1000NIT_GIROFF,
FOD_LHBM_WHITE_1000NIT_GIRON,
FOD_LHBM_WHITE_110NIT_GIROFF,
FOD_LHBM_WHITE_110NIT_GIRON,
FOD_LHBM_WHITE_MAX
};
struct dsi_panel_mi_cfg {
struct dsi_panel *dsi_panel;
/* xiaomi panel id */
u64 panel_id;
/* xiaomi feature enable flag */
bool mi_feature_enabled;
/* bl_is_big_endian indicate brightness value
* high byte to 1st parameter, low byte to 2nd parameter
* eg: 0x51 { 0x03, 0xFF } ->
* u8 payload[2] = { brightness >> 8, brightness & 0xff}
*/
bool bl_is_big_endian;
u32 last_bl_level;
u32 last_nonzero_bl_level;
/* indicate refresh frequency Fps gpio */
int disp_rate_gpio;
/* gamma read */
bool gamma_update_flag;
struct gamma_cfg gamma_cfg;
/* greenish gamma read */
bool greenish_gamma_update_flag;
u32 greenish_gamma_read_len;
struct greenish_gamma_cfg greenish_gamma_cfg;
/* dc read */
bool dc_update_flag;
struct dc_cfg dc_cfg;
bool dc_update_flag_v2;
struct dc_cfg_v2 dc_cfg_v2[DC_LUT_MAX];
/* white point coordinate info */
bool wp_read_enabled;
u32 wp_reg_read_len;
u32 wp_info_index;
u32 wp_info_len;
/* HBM and brightness use 51 reg ctrl */
bool hbm_51_ctrl_flag;
u32 hbm_off_51_index;
u32 fod_off_51_index;
u32 fod_off_b5_index;
u32 fod_on_b2_index;
bool vi_setting_enabled;
u32 vi_switch_threshold;
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;
u32 update_hbm_fod_on_index;
u32 update_hbm_fod_off_index;
u32 dimming_state;
u32 panel_on_dimming_delay;
struct delayed_work dimming_enable_delayed_work;
struct delayed_work enter_aod_delayed_work;
struct delayed_work cabc_delayed_work;
bool hbm_enabled;
bool thermal_hbm_disabled;
bool fod_hbm_enabled;
bool fod_hbm_layer_enabled;
bool fod_skip_nolp;
bool fod_to_nolp;
u32 doze_brightness_state;
u32 unset_doze_brightness;
u32 fod_off_dimming_delay;
ktime_t fod_backlight_off_time;
ktime_t fod_hbm_off_time;
u32 fod_ui_ready;
bool layer_fod_unlock_success;
bool sysfs_fod_unlock_success;
bool into_aod_pending;
bool layer_aod_flag;
struct wakeup_source *aod_wakelock;
bool fod_backlight_flag;
u32 fod_target_backlight;
bool fod_flag;
/* set doze hbm/lbm only in AOD */
bool in_aod;
u32 dc_threshold;
bool dc_enable;
u32 dc_type;
u32 hbm_brightness;
u32 max_brightness_clone;
u32 aod_backlight;
uint32_t doze_brightness;
bool bl_wait_frame;
bool bl_enable;
bool is_tddi_flag;
bool tddi_doubleclick_flag;
bool panel_dead_flag;
bool fod_dimlayer_enabled;
bool prepare_before_fod_hbm_on;
bool delay_before_fod_hbm_on;
bool delay_after_fod_hbm_on;
bool delay_before_fod_hbm_off;
bool delay_after_fod_hbm_off;
uint32_t brightnes_alpha_lut_item_count;
brightness_alpha *brightness_alpha_lut;
struct lockdowninfo_cfg lockdowninfo_read;
bool dither_enabled;
u32 cabc_current_status;
u32 cabc_temp_status;
int current_tp_code_fps;
bool local_hbm_enabled;
bool fod_lhbm_87reg_ctrl_flag;
u32 fod_lhbm_white_1000nit_87reg_index;
u32 fod_lhbm_white_110nit_87reg_index;
u32 fod_lhbm_green_500nit_87reg_index;
bool fod_lhbm_b2reg_ctrl_flag;
u32 fod_lhbm_white_1000nit_b2reg_index;
u32 fod_lhbm_white_110nit_b2reg_index;
bool local_hbm_cur_status;
bool fod_lhbm_low_brightness_enabled;
bool fod_lhbm_low_brightness_allow;
u32 fp_status;
int doze_hbm_dbv_level;
int doze_lbm_dbv_level;
int lhbm_target;
int pending_lhbm_state;
bool fod_lhbm_green_500nit_update_flag;
struct fod_lhbm_green_500nit_cfg fod_lhbm_green_500nit_cfg;
bool fod_lhbm_white_update_flag;
struct fod_lhbm_white_cfg fod_lhbm_white_cfg[FOD_LHBM_WHITE_MAX];
bool fod_anim_layer_enabled;
bool dim_fp_dbv_max_in_hbm_flag;
bool gir_update_flag;
struct gir_cfg gir_cfg;
bool gir_enabled;
bool request_gir_status;
bool nolp_b2reg_ctrl_flag;
u32 nolp_b2reg_index;
};
struct dsi_read_config {
bool is_read;
struct dsi_panel_cmd_set read_cmd;
u32 cmds_rlen;
u8 rbuf[256];
};
static inline const char *get_doze_brightness_name(__u32 doze_brightness)
{
switch (doze_brightness) {
case DOZE_TO_NORMAL:
return "doze_to_normal";
case DOZE_BRIGHTNESS_HBM:
return "doze_brightness_high";
case DOZE_BRIGHTNESS_LBM:
return "doze_brightness_low";
default:
return "Unknown";
}
}
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);
int dsi_panel_esd_irq_ctrl(struct dsi_panel *panel,
bool enable);
int dsi_panel_esd_irq_ctrl_locked(struct dsi_panel *panel,
bool enable);
int dsi_panel_write_cmd_set(struct dsi_panel *panel,
struct dsi_panel_cmd_set *cmd_sets);
int dsi_panel_read_cmd_set(struct dsi_panel *panel,
struct dsi_read_config *read_config);
int dsi_panel_write_mipi_reg(struct dsi_panel *panel, char *buf);
ssize_t dsi_panel_read_mipi_reg(struct dsi_panel *panel, char *buf);
bool dsi_panel_is_need_tx_cmd(u32 param);
int dsi_panel_set_disp_param(struct dsi_panel *panel, u32 param);
int dsi_panel_read_gamma_param(struct dsi_panel *panel);
int dsi_panel_update_gamma_param(struct dsi_panel *panel);
int dsi_panel_write_gamma_cmd_set(struct dsi_panel *panel,
enum dsi_gamma_cmd_set_type type);
int dsi_panel_read_dc_param(struct dsi_panel *panel);
int dsi_panel_update_dc_param(struct dsi_panel *panel);
int mi_dsi_panel_read_and_update_dc_param_v2(struct dsi_panel *panel);
int mi_dsi_panel_read_and_update_gir_param(struct dsi_panel *panel);
int mi_dsi_panel_read_and_update_lhbm_green_500nit_param(struct dsi_panel *panel);
int mi_dsi_panel_read_lhbm_white_param(struct dsi_panel *panel);
int mi_dsi_panel_read_lhbm_white_reg(struct dsi_panel *panel, int fod_lhbm_white_state);
int mi_dsi_panel_update_lhbm_white_param(struct dsi_panel *panel, int fod_lhbm_white_state, int cmd_index);
int dsi_panel_switch_disp_rate_gpio(struct dsi_panel *panel);
ssize_t dsi_panel_read_wp_info(struct dsi_panel *panel, char *buf);
int dsi_panel_set_doze_brightness(struct dsi_panel *panel,
int doze_brightness, bool need_panel_lock);
int dsi_panel_update_elvss_dimming(struct dsi_panel *panel);
int dsi_panel_read_greenish_gamma_setting(struct dsi_panel *panel);
int dsi_panel_update_greenish_gamma_setting(struct dsi_panel *panel);
int dsi_panel_match_fps_pen_setting(struct dsi_panel *panel,
struct dsi_display_mode *adj_mode);
int dsi_panel_lockdowninfo_param_read(struct dsi_panel *panel);
int dsi_panel_power_turn_off(bool on);
int mi_dsi_panel_set_fod_brightness(struct mipi_dsi_device *dsi, u16 brightness);
#endif /* _DSI_PANEL_MI_H_ */

View File

@@ -885,6 +885,8 @@ int dsi_phy_enable(struct msm_dsi_phy *phy,
phy->cfg.data_lanes = config->common_config.data_lanes;
phy->cfg.pll_source = pll_source;
phy->cfg.bit_clk_rate_hz = config->bit_clk_rate_hz;
phy->cfg.clk_strength = config->common_config.clk_strength;
phy->cfg.cphy_strength = config->common_config.cphy_strength;
/**
* If PHY timing parameters are not present in panel dtsi file,

View File

@@ -115,6 +115,8 @@ struct dsi_phy_cfg {
enum dsi_phy_type phy_type;
unsigned long bit_clk_rate_hz;
u32 data_lanes;
unsigned long clk_strength;
bool cphy_strength;
};
struct dsi_phy_hw;

View File

@@ -290,6 +290,14 @@ static void dsi_phy_hw_cphy_enable(struct dsi_phy_hw *phy,
glbl_rescode_bot_ctrl);
DSI_W32(phy, DSIPHY_CMN_GLBL_LPTX_STR_CTRL, 0x55);
if (cfg->cphy_strength) {
DSI_W32(phy, DSIPHY_CMN_VREG_CTRL_0, 0x50);
DSI_W32(phy, DSIPHY_CMN_VREG_CTRL_1, 0x54);
DSI_W32(phy, DSIPHY_CMN_GLBL_RESCODE_OFFSET_TOP_CTRL, 0x1F);
DSI_W32(phy, DSIPHY_CMN_GLBL_RESCODE_OFFSET_BOT_CTRL, 0x1F);
DSI_W32(phy, DSIPHY_CMN_GLBL_RESCODE_OFFSET_MID_CTRL, 0x1F);
}
/* Remove power down from all blocks */
DSI_W32(phy, DSIPHY_CMN_CTRL_0, 0x7f);
@@ -355,12 +363,21 @@ static void dsi_phy_hw_dphy_enable(struct dsi_phy_hw *phy,
vreg_ctrl_0 = less_than_1500_mhz ? 0x53 : 0x52;
glbl_rescode_top_ctrl = less_than_1500_mhz ? 0x3d : 0x00;
glbl_rescode_bot_ctrl = less_than_1500_mhz ? 0x39 : 0x3c;
glbl_str_swi_cal_sel_ctrl = 0x00;
glbl_hstx_str_ctrl_0 = 0x88;
if (cfg->clk_strength == 0) {
glbl_str_swi_cal_sel_ctrl = 0x00;
glbl_hstx_str_ctrl_0 = 0x88;
} else {
glbl_str_swi_cal_sel_ctrl = 0x03;
glbl_hstx_str_ctrl_0 = cfg->clk_strength;
}
} else {
vreg_ctrl_0 = less_than_1500_mhz ? 0x5B : 0x59;
glbl_str_swi_cal_sel_ctrl = less_than_1500_mhz ? 0x03 : 0x00;
glbl_hstx_str_ctrl_0 = less_than_1500_mhz ? 0x66 : 0x88;
if (cfg->clk_strength == 0) {
glbl_hstx_str_ctrl_0 = less_than_1500_mhz ? 0x66 : 0x88;
} else {
glbl_hstx_str_ctrl_0 = cfg->clk_strength;
}
glbl_rescode_top_ctrl = 0x03;
glbl_rescode_bot_ctrl = 0x3c;
}
@@ -397,7 +414,11 @@ static void dsi_phy_hw_dphy_enable(struct dsi_phy_hw *phy,
glbl_rescode_top_ctrl);
DSI_W32(phy, DSIPHY_CMN_GLBL_RESCODE_OFFSET_BOT_CTRL,
glbl_rescode_bot_ctrl);
DSI_W32(phy, DSIPHY_CMN_GLBL_LPTX_STR_CTRL, 0x55);
if (cfg->clk_strength == 0) {
DSI_W32(phy, DSIPHY_CMN_GLBL_LPTX_STR_CTRL, 0x55);
} else {
DSI_W32(phy, DSIPHY_CMN_GLBL_LPTX_STR_CTRL, cfg->clk_strength);
}
/* Remove power down from all blocks */
DSI_W32(phy, DSIPHY_CMN_CTRL_0, 0x7f);

View File

@@ -0,0 +1,340 @@
#include "mi_disp_lhbm.h"
struct disp_lhbm *g_disp_lhbm = NULL;
static atomic_t fod_work_status = ATOMIC_INIT(FOD_WORK_INIT);
static atomic_t touch_current_status = ATOMIC_INIT(-1);
static atomic_t touch_last_status = ATOMIC_INIT(-1);
extern void sde_crtc_fod_ui_ready(struct dsi_display *display, int type, int value);
int mi_get_disp_id(struct dsi_display *display)
{
if (!strncmp(display->display_type, "primary", 7))
return MI_DISP_PRIMARY;
else
return MI_DISP_SECONDARY;
}
static int mi_disp_fod_thread_create(struct disp_lhbm *dl_ptr, int disp_id)
{
int ret = 0;
struct disp_thread *dt_ptr = NULL;
struct sched_param param = { 0 };
param.sched_priority = 16;
dt_ptr = &dl_ptr->fod_thread;
dt_ptr->dd_ptr = &dl_ptr->d_display[disp_id];
kthread_init_worker(&dt_ptr->worker);
dt_ptr->thread = kthread_run(kthread_worker_fn,
&dt_ptr->worker, "disp_fod:%d", disp_id);
ret = sched_setscheduler(dt_ptr->thread, SCHED_FIFO, &param);
if (ret)
pr_err("%s display thread priority update failed: %d\n", LHBM_TAG, ret);
if (IS_ERR(dt_ptr->thread)) {
pr_err("%s failed to create disp_feature kthread\n", LHBM_TAG);
dt_ptr->thread = NULL;
}
pr_info("%s create disp_fod:%d kthread success\n", LHBM_TAG, disp_id);
return ret;
}
static int mi_get_fod_lhbm_target_brightness(struct dsi_display *display)
{
int target = LOCAL_LHBM_TARGET_BRIGHTNESS_WHITE_1000NIT;
if(display->panel->mi_cfg.fp_status == HEART_RATE_START) {
target = LOCAL_LHBM_TARGET_BRIGHTNESS_GREEN_500NIT;
} else if (display->panel->mi_cfg.fod_lhbm_low_brightness_enabled && display->panel->mi_cfg.fod_lhbm_low_brightness_allow){
target = LOCAL_LHBM_TARGET_BRIGHTNESS_WHITE_110NIT;
}
if(display->panel->mi_cfg.fp_status == ENROLL_START) {
target = LOCAL_LHBM_TARGET_BRIGHTNESS_WHITE_1000NIT;
}
return target;
}
static int mi_dsi_panel_set_fod_lhbm(struct dsi_panel *panel, int lhbm_target)
{
int rc = 0;
if (!panel) {
pr_err("%s invalid params\n", LHBM_TAG);
return -EINVAL;
}
if (!panel->panel_initialized){
pr_err("%s Panel not initialized!\n", LHBM_TAG);
return -ENODEV;
}
if (lhbm_target == LOCAL_LHBM_TARGET_BRIGHTNESS_NONE) {
if (panel->mi_cfg.local_hbm_cur_status == true) {
rc = dsi_panel_set_disp_param(panel, DISPPARAM_HBM_FOD_OFF);
}
} else {
if (panel->mi_cfg.local_hbm_cur_status == false) {
rc = dsi_panel_set_disp_param(panel, DISPPARAM_HBM_FOD_ON|lhbm_target);
if(panel->mi_cfg.in_aod == true) {
pr_info("%s in aod status delay 30 ms lhbm on\n", LHBM_TAG);
mdelay(70);
}
}
}
return rc;
}
static int mi_sde_connector_fod_lhbm(struct drm_connector *connector, bool from_touch, int fod_btn)
{
int rc = 0;
struct sde_connector *c_conn;
struct dsi_display *display;
bool btn_down;
int lhbm_target;
struct dsi_panel_mi_cfg *mi_cfg;
if (!connector) {
pr_err("%s invalid connector ptr\n", LHBM_TAG);
return -EINVAL;
}
c_conn = to_sde_connector(connector);
if (c_conn->connector_type != DRM_MODE_CONNECTOR_DSI) {
pr_err("%s not DRM_MODE_CONNECTOR_DSI\n", LHBM_TAG);
return -EINVAL;
}
display = (struct dsi_display *) c_conn->display;
if (!display || !display->panel) {
pr_err("%s invalid display/panel ptr\n", LHBM_TAG);
return -EINVAL;
}
if (mi_get_disp_id(display) != MI_DISP_PRIMARY) {
pr_err("%s not MI_DISP_PRIMARY\n", LHBM_TAG);
return -EINVAL;
}
mi_cfg = &display->panel->mi_cfg;
btn_down = (fod_btn == 1);
pr_info("%s dsi_mi_sde_connector_fod_lhbm=%d\n", LHBM_TAG, btn_down);
if (btn_down) {
if (!mi_cfg->pending_lhbm_state && !from_touch) {
rc = -EINVAL;
pr_info("%s LHBM on from display skip\n", LHBM_TAG);
} else {
lhbm_target = mi_get_fod_lhbm_target_brightness(display);
rc = mi_dsi_panel_set_fod_lhbm(display->panel, lhbm_target);
display->panel->mi_cfg.lhbm_target = lhbm_target;
if (!rc) {
mi_cfg->pending_lhbm_state = 0;
} else if (rc == -ENODEV) {
pr_info("%s LHBM on !panel_initialized rc=%d\n", LHBM_TAG, rc);
mi_cfg->pending_lhbm_state = 1;
} else {
pr_err("%s LHBM on failed rc=%d\n", LHBM_TAG, rc);
}
}
} else {
rc = mi_dsi_panel_set_fod_lhbm(display->panel, LOCAL_LHBM_TARGET_BRIGHTNESS_NONE);
display->panel->mi_cfg.lhbm_target = LOCAL_LHBM_TARGET_BRIGHTNESS_NONE;
mi_cfg->pending_lhbm_state = 0;
if (rc) {
pr_err("%s LHBM off failed rc=%d\n", LHBM_TAG, rc);
}
}
return rc;
}
static void mi_disp_set_fod_work_handler(struct kthread_work *work)
{
int rc = 0;
struct fod_work_data *fod_data = NULL;
struct disp_work *cur_work = container_of(work,
struct disp_work, work);
fod_data = (struct fod_work_data *)(cur_work->data);
if (!fod_data || !fod_data->display) {
pr_err("%s invalid params\n", LHBM_TAG);
return;
}
if (fod_data->from_touch) {
atomic_set(&fod_work_status, FOD_WORK_DOING);
do {
pr_debug("%s from touch, current(%d),last(%d)\n",
LHBM_TAG, atomic_read(&touch_current_status), atomic_read(&touch_last_status));
atomic_set(&touch_current_status, atomic_read(&touch_last_status));
if (atomic_read(&touch_current_status) == 0) {
//mi_sde_connector_fod_lhbm_notify(fod_data->display->drm_conn,
//atomic_read(&touch_current_status));
sde_crtc_fod_ui_ready(fod_data->display, 2, atomic_read(&touch_current_status));
}
rc = mi_sde_connector_fod_lhbm(fod_data->display->drm_conn, true, atomic_read(&touch_current_status));
if (atomic_read(&touch_current_status) == 1) {
if (rc) {
pr_err("%s LHBM on failed rc=%d, not notify\n", LHBM_TAG, rc);
} else {
//mi_sde_connector_fod_lhbm_notify(fod_data->display->drm_conn,
//atomic_read(&touch_current_status));
sde_crtc_fod_ui_ready(fod_data->display, 2, atomic_read(&touch_current_status));
}
}
} while (atomic_read(&touch_current_status) != atomic_read(&touch_last_status));
atomic_set(&fod_work_status, FOD_WORK_DONE);
} else {
pr_debug("%s not from touch, fod_btn(%d)\n", LHBM_TAG, fod_data->fod_btn);
if (fod_data->fod_btn == 0) {
sde_crtc_fod_ui_ready(fod_data->display, 2, fod_data->fod_btn);
}
rc = mi_sde_connector_fod_lhbm(fod_data->display->drm_conn, false, fod_data->fod_btn);
if (fod_data->fod_btn == 1) {
if (rc) {
pr_err("%s LHBM on failed rc=%d, not notify\n", LHBM_TAG, rc);
} else {
sde_crtc_fod_ui_ready(fod_data->display, 2, fod_data->fod_btn);
}
}
}
kfree(cur_work);
pr_debug("%s fod work handler done\n", LHBM_TAG);
}
int mi_disp_set_fod_queue_work(u32 fod_btn, bool from_touch)
{
struct disp_lhbm *dl_ptr = g_disp_lhbm;
struct disp_work *cur_work;
struct dsi_display *display = NULL;
struct fod_work_data *fod_data;
int fp_status = FINGERPRINT_NONE;
struct dsi_panel_mi_cfg *mi_cfg;
static bool ignore_fod_btn = false;
if (!dl_ptr) {
pr_err("%s invalid params\n", LHBM_TAG);
return -EINVAL;
}
display = (struct dsi_display *)dl_ptr->d_display[MI_DISP_PRIMARY].display;
if (!display || !display->panel) {
pr_err("%s invalid params\n", LHBM_TAG);
return -EINVAL;
}
mi_cfg = &display->panel->mi_cfg;
fp_status = mi_cfg->fp_status;
if (from_touch) {
if (atomic_read(&fod_work_status) == FOD_WORK_DOING) {
pr_debug("%s work doing: from touch current(%d), new fod_btn(%d), skip\n",
LHBM_TAG, atomic_read(&touch_current_status), fod_btn);
atomic_set(&touch_last_status, fod_btn);
return 0;
} else {
if (ignore_fod_btn) {
if (fod_btn == 1) {
return 0;
} else {
ignore_fod_btn = false;
pr_info("%s clear ignore state\n", LHBM_TAG);
return 0;
}
}
if (atomic_read(&touch_current_status) == fod_btn) {
pr_debug("%s from touch fod_btn(%d), skip\n", LHBM_TAG, fod_btn);
return 0;
} else {
mutex_lock(&display->display_lock);
if (display->panel->power_mode == SDE_MODE_DPMS_ON && atomic_read(&touch_current_status) == 0
&& fod_btn == 1 && !mi_cfg->fod_anim_layer_enabled) {
pr_info("%s ignore fod_btn due to fod anim is disable!\n", LHBM_TAG);
ignore_fod_btn = true;
mutex_unlock(&display->display_lock);
return 0;
}
mutex_unlock(&display->display_lock);
atomic_set(&touch_last_status, fod_btn);
pr_debug("%s from touch fod_btn=%d\n", LHBM_TAG, fod_btn);
}
}
}
fp_status = display->panel->mi_cfg.fp_status;
if (fp_status == ENROLL_STOP || fp_status == AUTH_STOP || fp_status == HEART_RATE_STOP) {
if (fod_btn == 1) {
pr_info("%s fp_state=%d, skip\n", LHBM_TAG, fp_status);
return 0;
}
}
cur_work = kzalloc(sizeof(*cur_work) + sizeof(*fod_data), GFP_ATOMIC);
if (!cur_work)
return -ENOMEM;
fod_data = (struct fod_work_data *)((u8 *)cur_work + sizeof(struct disp_work));
fod_data->display = display;
fod_data->fod_btn = fod_btn;
fod_data->from_touch = from_touch;
kthread_init_work(&cur_work->work, mi_disp_set_fod_work_handler);
cur_work->dd_ptr = &dl_ptr->d_display[MI_DISP_PRIMARY];
//cur_work->wq = &dl_ptr->fod_pending_wq;
cur_work->data = fod_data;
pr_info("%s fod_queue_work: fod_btn(%d)\n", LHBM_TAG, fod_btn);
kthread_queue_work(&dl_ptr->fod_thread.worker, &cur_work->work);
return 0;
}
EXPORT_SYMBOL_GPL(mi_disp_set_fod_queue_work);
int mi_disp_lhbm_attach_primary_dsi_display(struct dsi_display *display)
{
struct disp_lhbm *dl_ptr = NULL;
struct disp_display *dd_ptr = NULL;
int ret = 0;
if (!strncmp(display->display_type, "primary", 7)) {
dl_ptr = kzalloc(sizeof(struct disp_lhbm), GFP_KERNEL);
if (!dl_ptr) {
pr_err("%s can not allocate Buffer\n", LHBM_TAG);
return -ENOMEM;
}
dd_ptr = &dl_ptr->d_display[MI_DISP_PRIMARY];
dd_ptr->display = (void *)display;
ret = mi_disp_fod_thread_create(dl_ptr, MI_DISP_PRIMARY);
if (ret) {
kfree(dl_ptr);
pr_err("%s failed to create fod kthread\n", LHBM_TAG);
goto err_exit;
}
g_disp_lhbm = dl_ptr;
pr_info("%s lhbm attach primary_dsi_display success\n", LHBM_TAG);
} else {
pr_debug("%s is not primary_dsi_display\n", LHBM_TAG);
}
err_exit:
return ret;
}

View File

@@ -0,0 +1,78 @@
#ifndef _MI_DISP_LHBM_H_
#define _MI_DISP_LHBM_H_
#include <linux/kthread.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/spinlock.h>
#include <uapi/linux/sched/types.h>
#include "dsi_display.h"
#include "sde_connector.h"
#include "dsi_panel_mi.h"
#include "dsi_mi_feature.h"
#define LHBM_TAG "[mi-lhbm]"
enum disp_display_type {
MI_DISP_PRIMARY = 0,
MI_DISP_SECONDARY,
MI_DISP_MAX,
};
struct disp_work {
struct kthread_work work;
struct kthread_delayed_work delayed_work;
struct disp_display *dd_ptr;
wait_queue_head_t *wq;
void *data;
};
struct disp_thread {
struct task_struct *thread;
struct kthread_worker worker;
struct disp_display *dd_ptr;
};
struct disp_display {
void *display;
int intf_type;
struct mutex mutex_lock;
};
struct disp_lhbm {
struct disp_display d_display[MI_DISP_MAX];
struct disp_thread fod_thread;
//wait_queue_head_t fod_pending_wq;
};
struct fod_work_data {
struct dsi_display *display;
int fod_btn;
bool from_touch;
};
enum {
FOD_WORK_INIT = 0,
FOD_WORK_DOING = 1,
FOD_WORK_DONE = 2,
};
enum mi_panel_op_code {
MI_FOD_HBM_ON = 0,
MI_FOD_HBM_OFF,
MI_FOD_AOD_TO_NORMAL,
MI_FOD_NORMAL_TO_AOD,
};
enum local_lhbm_target_brightness {
LOCAL_LHBM_TARGET_BRIGHTNESS_NONE,
LOCAL_LHBM_TARGET_BRIGHTNESS_WHITE_1000NIT,
LOCAL_LHBM_TARGET_BRIGHTNESS_WHITE_110NIT,
LOCAL_LHBM_TARGET_BRIGHTNESS_GREEN_500NIT,
LOCAL_LHBM_TARGET_BRIGHTNESS_MAX
};
int mi_disp_set_fod_queue_work(u32 fod_btn, bool from_touch);
#endif

View File

@@ -0,0 +1,420 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
*/
#ifndef _MI_DISP_NVT_ALPHA_DATA_H_
#define _MI_DISP_NVT_ALPHA_DATA_H_
static const int fpr_alpha_set[4096] = {
0x000, 0x071, 0x0af, 0x0d2, 0x0f0, 0x10a, 0x121, 0x135, 0x14d, 0x15b,
0x16c, 0x17a, 0x188, 0x196, 0x1a4, 0x1b2, 0x1bd, 0x1cb, 0x1d6, 0x1e2,
0x1f1, 0x1fe, 0x209, 0x214, 0x224, 0x22c, 0x232, 0x23c, 0x246, 0x24f,
0x258, 0x261, 0x26a, 0x273, 0x27b, 0x282, 0x28a, 0x294, 0x29c, 0x2a4,
0x2ac, 0x2b4, 0x2bb, 0x2c5, 0x2ca, 0x2d6, 0x2dd, 0x2e4, 0x2ed, 0x2f6,
0x2fd, 0x302, 0x309, 0x30d, 0x314, 0x31d, 0x323, 0x326, 0x32a, 0x330,
0x337, 0x33d, 0x343, 0x349, 0x34f, 0x355, 0x35b, 0x361, 0x367, 0x36d,
0x372, 0x378, 0x37c, 0x383, 0x387, 0x38c, 0x394, 0x399, 0x39f, 0x3a4,
0x3aa, 0x3af, 0x3b4, 0x3b9, 0x3bf, 0x3c4, 0x3c9, 0x3ce, 0x3d3, 0x3d8,
0x3dd, 0x3e2, 0x3e7, 0x3f0, 0x3f7, 0x3fa, 0x401, 0x407, 0x40a, 0x40f,
0x416, 0x418, 0x41f, 0x424, 0x426, 0x42d, 0x432, 0x436, 0x439, 0x43f,
0x444, 0x448, 0x44b, 0x44f, 0x457, 0x45c, 0x45e, 0x463, 0x467, 0x46d,
0x46f, 0x476, 0x47a, 0x47c, 0x484, 0x485, 0x48d, 0x48f, 0x495, 0x495,
0x49d, 0x49f, 0x4a3, 0x4a9, 0x4ad, 0x4af, 0x4b7, 0x4b9, 0x4bd, 0x4c3,
0x4c5, 0x4c7, 0x4cb, 0x4d1, 0x4d5, 0x4db, 0x4df, 0x4e0, 0x4e6, 0x4e8,
0x4ec, 0x4f0, 0x4f5, 0x4f9, 0x4fd, 0x4ff, 0x504, 0x50a, 0x50c, 0x50f,
0x515, 0x519, 0x51a, 0x51e, 0x522, 0x527, 0x52b, 0x52e, 0x52e, 0x535,
0x537, 0x53a, 0x53e, 0x545, 0x547, 0x548, 0x54e, 0x553, 0x555, 0x558,
0x55a, 0x561, 0x561, 0x564, 0x567, 0x56d, 0x56e, 0x573, 0x575, 0x57a,
0x57d, 0x57f, 0x584, 0x589, 0x58b, 0x58e, 0x591, 0x592, 0x596, 0x597,
0x59c, 0x59f, 0x5a1, 0x5a2, 0x5a7, 0x5aa, 0x5ab, 0x5af, 0x5b2, 0x5b7,
0x5b8, 0x5bb, 0x5be, 0x5c0, 0x5c1, 0x5c4, 0x5c9, 0x5ca, 0x5cb, 0x5d4,
0x5d5, 0x5da, 0x5dd, 0x5e0, 0x5e1, 0x5e4, 0x5e6, 0x5e7, 0x5ec, 0x5eb,
0x5f2, 0x5f1, 0x5f4, 0x5f5, 0x5f9, 0x5fa, 0x5ff, 0x602, 0x607, 0x606,
0x609, 0x60c, 0x60f, 0x612, 0x613, 0x618, 0x61d, 0x61f, 0x620, 0x623,
0x626, 0x629, 0x62e, 0x62f, 0x634, 0x634, 0x637, 0x63a, 0x63d, 0x63c,
0x642, 0x645, 0x648, 0x649, 0x64e, 0x64e, 0x653, 0x658, 0x659, 0x65b,
0x65e, 0x661, 0x662, 0x66c, 0x66f, 0x670, 0x673, 0x677, 0x678, 0x67b,
0x67f, 0x680, 0x683, 0x685, 0x688, 0x68b, 0x691, 0x690, 0x695, 0x695,
0x698, 0x69b, 0x69d, 0x69c, 0x69f, 0x6a3, 0x6a4, 0x6aa, 0x6ad, 0x6ac,
0x6b6, 0x6b9, 0x6bb, 0x6bc, 0x6be, 0x6c1, 0x6c4, 0x6c6, 0x6cb, 0x6cb,
0x6cc, 0x6d2, 0x6d5, 0x6d9, 0x6da, 0x6dd, 0x6dd, 0x6e2, 0x6e2, 0x6e5,
0x6e7, 0x6ea, 0x6ec, 0x6ed, 0x6f1, 0x6f4, 0x6fc, 0x6fd, 0x6ff, 0x701,
0x700, 0x700, 0x703, 0x707, 0x708, 0x708, 0x709, 0x70b, 0x711, 0x710,
0x714, 0x713, 0x713, 0x716, 0x71a, 0x71c, 0x71d, 0x71d, 0x71e, 0x722,
0x722, 0x725, 0x727, 0x729, 0x72c, 0x726, 0x729, 0x72b, 0x72d, 0x730,
0x732, 0x734, 0x737, 0x739, 0x73b, 0x73e, 0x740, 0x73a, 0x73d, 0x73f,
0x741, 0x744, 0x746, 0x748, 0x74a, 0x74d, 0x74f, 0x751, 0x754, 0x74e,
0x758, 0x75a, 0x75d, 0x75f, 0x759, 0x75c, 0x75e, 0x760, 0x762, 0x765,
0x767, 0x769, 0x76b, 0x76e, 0x770, 0x772, 0x76c, 0x76e, 0x771, 0x773,
0x775, 0x777, 0x77a, 0x77c, 0x77e, 0x780, 0x782, 0x785, 0x787, 0x789,
0x78b, 0x78d, 0x788, 0x78a, 0x78c, 0x78e, 0x790, 0x792, 0x795, 0x797,
0x799, 0x79b, 0x79d, 0x79f, 0x7a1, 0x7a4, 0x7a6, 0x7a8, 0x7a2, 0x7a4,
0x7a6, 0x7a8, 0x7ab, 0x7ad, 0x7af, 0x7b1, 0x7b3, 0x7b5, 0x7b7, 0x7b9,
0x7bb, 0x7b6, 0x7c0, 0x7c2, 0x7c4, 0x7c6, 0x7c0, 0x7ca, 0x7c4, 0x7ce,
0x7c8, 0x7d2, 0x7d5, 0x7cf, 0x7d1, 0x7d3, 0x7d5, 0x7d7, 0x7d9, 0x7db,
0x7dd, 0x7df, 0x7e1, 0x7db, 0x7e5, 0x7df, 0x7e1, 0x7e3, 0x7e5, 0x7e7,
0x7e9, 0x7eb, 0x7ed, 0x7f0, 0x7f2, 0x7f4, 0x7f6, 0x7f8, 0x7fa, 0x7fc,
0x7fe, 0x800, 0x802, 0x804, 0x806, 0x800, 0x80a, 0x804, 0x806, 0x808,
0x812, 0x814, 0x80e, 0x80f, 0x811, 0x813, 0x815, 0x817, 0x819, 0x81b,
0x81d, 0x81f, 0x821, 0x823, 0x825, 0x827, 0x829, 0x82b, 0x82d, 0x82f,
0x831, 0x833, 0x835, 0x837, 0x839, 0x83a, 0x83c, 0x83e, 0x838, 0x842,
0x844, 0x846, 0x840, 0x84a, 0x844, 0x84e, 0x850, 0x851, 0x853, 0x855,
0x857, 0x859, 0x85b, 0x85d, 0x85f, 0x861, 0x863, 0x864, 0x866, 0x868,
0x86a, 0x86c, 0x86e, 0x870, 0x872, 0x873, 0x875, 0x877, 0x879, 0x87b,
0x87d, 0x87f, 0x881, 0x882, 0x884, 0x886, 0x888, 0x88a, 0x88c, 0x88d,
0x88f, 0x891, 0x893, 0x895, 0x897, 0x899, 0x89a, 0x89c, 0x89e, 0x8a0,
0x8a2, 0x8a4, 0x8a5, 0x8a7, 0x8a9, 0x8ab, 0x8ad, 0x8ae, 0x8b8, 0x8ba,
0x8bc, 0x8b6, 0x8bf, 0x8c1, 0x8c3, 0x8c5, 0x8c7, 0x8c8, 0x8ca, 0x8cc,
0x8ce, 0x8d0, 0x8d1, 0x8d3, 0x8d5, 0x8d7, 0x8d9, 0x8e2, 0x8dc, 0x8de,
0x8e0, 0x8e1, 0x8e3, 0x8e5, 0x8e7, 0x8e9, 0x8ea, 0x8ec, 0x8ee, 0x8f0,
0x8f1, 0x8f3, 0x8f5, 0x8f7, 0x900, 0x902, 0x904, 0x906, 0x907, 0x909,
0x90b, 0x90d, 0x90e, 0x910, 0x912, 0x914, 0x915, 0x917, 0x919, 0x91b,
0x91c, 0x91e, 0x920, 0x921, 0x923, 0x925, 0x927, 0x928, 0x92a, 0x92c,
0x92d, 0x937, 0x931, 0x933, 0x93c, 0x93e, 0x938, 0x939, 0x93b, 0x93d,
0x93f, 0x948, 0x94a, 0x944, 0x94d, 0x94f, 0x951, 0x952, 0x954, 0x956,
0x957, 0x959, 0x95b, 0x95d, 0x95e, 0x960, 0x962, 0x963, 0x96d, 0x967,
0x970, 0x972, 0x96c, 0x96d, 0x96f, 0x979, 0x97a, 0x97c, 0x97e, 0x977,
0x981, 0x983, 0x984, 0x986, 0x988, 0x989, 0x98b, 0x98d, 0x98e, 0x990,
0x991, 0x99b, 0x995, 0x996, 0x998, 0x99a, 0x99b, 0x9a5, 0x99f, 0x9a8,
0x9a2, 0x9a3, 0x9ad, 0x9af, 0x9b0, 0x9b2, 0x9ac, 0x9b5, 0x9b7, 0x9b8,
0x9ba, 0x9bc, 0x9bd, 0x9bf, 0x9c1, 0x9c2, 0x9c4, 0x9c5, 0x9c7, 0x9c9,
0x9d2, 0x9cc, 0x9d5, 0x9d7, 0x9d1, 0x9d2, 0x9dc, 0x9dd, 0x9df, 0x9e1,
0x9e2, 0x9e4, 0x9e5, 0x9e7, 0x9e9, 0x9ea, 0x9ec, 0x9ed, 0x9ef, 0x9f1,
0x9f2, 0x9f4, 0x9f5, 0x9f7, 0xa01, 0xa02, 0xa04, 0xa05, 0x9ff, 0xa08,
0xa0a, 0xa0c, 0xa0d, 0xa0f, 0xa10, 0xa12, 0xa13, 0xa1d, 0xa16, 0xa18,
0xa1a, 0xa1b, 0xa25, 0xa1e, 0xa28, 0xa21, 0xa2b, 0xa2d, 0xa2e, 0xa30,
0xa31, 0xa33, 0xa34, 0xa36, 0xa37, 0xa39, 0xa3a, 0xa3c, 0xa3e, 0xa3f,
0xa41, 0xa42, 0xa4c, 0xa45, 0xa4f, 0xa50, 0xa52, 0xa53, 0xa55, 0xa56,
0xa58, 0xa59, 0xa5b, 0xa5d, 0xa5e, 0xa60, 0xa61, 0xa63, 0xa6c, 0xa66,
0xa6c, 0xa71, 0xa6c, 0xa71, 0xa72, 0xa74, 0xa78, 0xa7a, 0xa7b, 0xa7d,
0xa7e, 0xa80, 0xa81, 0xa83, 0xa8a, 0xa86, 0xa8d, 0xa89, 0xa8d, 0xa8f,
0xa8d, 0xa8f, 0xa90, 0xa92, 0xa93, 0xa95, 0xa96, 0xa98, 0xa96, 0xa9b,
0xa9c, 0xa9b, 0xa9f, 0xa9e, 0xa9f, 0xaa1, 0xa9f, 0xaa1, 0xaa5, 0xaa4,
0xaa5, 0xaaa, 0xaa8, 0xaaa, 0xaab, 0xaac, 0xaab, 0xaaf, 0xaab, 0xaaf,
0xab1, 0xab2, 0xab1, 0xab5, 0xab4, 0xab5, 0xaba, 0xab8, 0xaba, 0xab8,
0xabf, 0xabe, 0xabf, 0xac4, 0xac5, 0xac4, 0xac8, 0xac4, 0xac8, 0xaca,
0xac8, 0xac9, 0xace, 0xacc, 0xace, 0xacf, 0xad1, 0xacf, 0xad4, 0xad5,
0xad3, 0xad8, 0xad6, 0xad8, 0xad9, 0xad8, 0xad9, 0xade, 0xadc, 0xadd,
0xae2, 0xae3, 0xae2, 0xae6, 0xae2, 0xae6, 0xae7, 0xae6, 0xae7, 0xae9,
0xae7, 0xaec, 0xaea, 0xaee, 0xaf0, 0xaee, 0xaf3, 0xaf1, 0xaef, 0xaf4,
0xaf5, 0xaf4, 0xaf8, 0xafa, 0xaf8, 0xafc, 0xafb, 0xaf9, 0xafe, 0xaff,
0xb00, 0xb02, 0xb00, 0xb02, 0xb03, 0xb04, 0xb03, 0xb04, 0xb06, 0xb07,
0xb08, 0xb0d, 0xb0b, 0xb0d, 0xb0e, 0xb0f, 0xb11, 0xb0f, 0xb11, 0xb12,
0xb13, 0xb15, 0xb13, 0xb15, 0xb19, 0xb14, 0xb1c, 0xb1d, 0xb1b, 0xb1d,
0xb1e, 0xb20, 0xb27, 0xb25, 0xb2a, 0xb2b, 0xb2a, 0xb28, 0xb2c, 0xb2b,
0xb2c, 0xb30, 0xb32, 0xb30, 0xb2f, 0xb33, 0xb31, 0xb36, 0xb37, 0xb35,
0xb3a, 0xb35, 0xb39, 0xb3b, 0xb3c, 0xb3b, 0xb3f, 0xb3d, 0xb3f, 0xb40,
0xb44, 0xb40, 0xb44, 0xb45, 0xb44, 0xb48, 0xb4a, 0xb4b, 0xb49, 0xb4e,
0xb49, 0xb4d, 0xb52, 0xb4d, 0xb51, 0xb53, 0xb51, 0xb55, 0xb57, 0xb55,
0xb54, 0xb56, 0xb57, 0xb58, 0xb5a, 0xb5b, 0xb5c, 0xb5e, 0xb5f, 0xb60,
0xb62, 0xb63, 0xb64, 0xb66, 0xb67, 0xb68, 0xb6a, 0xb6b, 0xb6c, 0xb6e,
0xb67, 0xb70, 0xb6a, 0xb73, 0xb74, 0xb6e, 0xb6f, 0xb70, 0xb72, 0xb7b,
0xb74, 0xb76, 0xb77, 0xb78, 0xb7a, 0xb7b, 0xb7c, 0xb7e, 0xb7f, 0xb80,
0xb82, 0xb83, 0xb84, 0xb86, 0xb87, 0xb88, 0xb89, 0xb8b, 0xb8c, 0xb85,
0xb8f, 0xb90, 0xb89, 0xb93, 0xb94, 0xb95, 0xb97, 0xb98, 0xb91, 0xba2,
0xba4, 0xba5, 0xba6, 0xbb0, 0xba9, 0xbaa, 0xbac, 0xbad, 0xbae, 0xbb7,
0xbb1, 0xbb2, 0xbb3, 0xbb5, 0xbb6, 0xbb7, 0xbb9, 0xbba, 0xbbb, 0xbbc,
0xbbe, 0xbbf, 0xbc0, 0xbc2, 0xbc3, 0xbc4, 0xbc5, 0xbc7, 0xbc8, 0xbc9,
0xbcb, 0xbcc, 0xbcd, 0xbce, 0xbc8, 0xbd1, 0xbd2, 0xbd3, 0xbcd, 0xbce,
0xbcf, 0xbd1, 0xbd2, 0xbd3, 0xbd4, 0xbd6, 0xbd7, 0xbd8, 0xbda, 0xbcb,
0xbcc, 0xbcd, 0xbcf, 0xbd0, 0xbd1, 0xbd2, 0xbd4, 0xbd5, 0xbd6, 0xbd7,
0xbd9, 0xbe2, 0xbdb, 0xbdc, 0xbde, 0xbdf, 0xbe0, 0xbe2, 0xbe3, 0xbdc,
0xbe5, 0xbe7, 0xbe8, 0xbe1, 0xbea, 0xbe4, 0xbe5, 0xbee, 0xbef, 0xbe9,
0xbf2, 0xbeb, 0xbf4, 0xbee, 0xbf7, 0xbf0, 0xbf1, 0xbf3, 0xbf4, 0xbfd,
0xbf6, 0xbf8, 0xc01, 0xbfa, 0xbfb, 0xbfd, 0xbfe, 0xbff, 0xc00, 0xc02,
0xc03, 0xc04, 0xc05, 0xc06, 0xc08, 0xc09, 0xc0a, 0xc0b, 0xc15, 0xc0e,
0xc0f, 0xc10, 0xc12, 0xc13, 0xc14, 0xc0d, 0xc0f, 0xc18, 0xc19, 0xc1a,
0xc13, 0xc1d, 0xc16, 0xc1f, 0xc20, 0xc1a, 0xc1b, 0xc1c, 0xc1d, 0xc26,
0xc20, 0xc21, 0xc22, 0xc23, 0xc25, 0xc26, 0xc27, 0xc28, 0xc29, 0xc2b,
0xc2c, 0xc2d, 0xc2e, 0xc30, 0xc31, 0xc32, 0xc33, 0xc34, 0xc36, 0xc37,
0xc40, 0xc41, 0xc3a, 0xc3c, 0xc3d, 0xc46, 0xc3f, 0xc40, 0xc42, 0xc43,
0xc4c, 0xc45, 0xc47, 0xc48, 0xc49, 0xc4a, 0xc4b, 0xc4d, 0xc4e, 0xc4f,
0xc50, 0xc51, 0xc53, 0xc54, 0xc55, 0xc56, 0xc57, 0xc59, 0xc5a, 0xc5b,
0xc5c, 0xc5d, 0xc5f, 0xc60, 0xc61, 0xc62, 0xc63, 0xc64, 0xc66, 0xc67,
0xc68, 0xc69, 0xc6a, 0xc6c, 0xc6d, 0xc6e, 0xc6f, 0xc70, 0xc72, 0xc73,
0xc74, 0xc75, 0xc76, 0xc77, 0xc79, 0xc7a, 0xc7b, 0xc7c, 0xc75, 0xc7f,
0xc80, 0xc81, 0xc82, 0xc7b, 0xc84, 0xc86, 0xc87, 0xc80, 0xc89, 0xc8a,
0xc84, 0xc8d, 0xc86, 0xc87, 0xc90, 0xc91, 0xc93, 0xc94, 0xc95, 0xc96,
0xc97, 0xc98, 0xc9a, 0xc9b, 0xc94, 0xc9d, 0xc96, 0xc9f, 0xca1, 0xc9a,
0xca3, 0xc9c, 0xca5, 0xca6, 0xca8, 0xca1, 0xcaa, 0xca3, 0xca4, 0xcad,
0xca7, 0xca8, 0xcb1, 0xcaa, 0xcb3, 0xcb4, 0xcad, 0xcaf, 0xcb8, 0xcb1,
0xcb2, 0xcb3, 0xcb4, 0xcb6, 0xcb7, 0xcb8, 0xcb9, 0xcc2, 0xcbb, 0xcbc,
0xcbe, 0xcbf, 0xcc0, 0xcc9, 0xcc2, 0xcc3, 0xcc5, 0xcc6, 0xcc7, 0xcd0,
0xcd1, 0xcca, 0xccb, 0xccd, 0xcd6, 0xcd7, 0xcd0, 0xcd9, 0xcd2, 0xcdb,
0xcd5, 0xcde, 0xcdf, 0xcd8, 0xce1, 0xce2, 0xce3, 0xcdd, 0xce6, 0xce7,
0xce8, 0xce9, 0xcea, 0xceb, 0xcec, 0xcee, 0xce7, 0xcf0, 0xcf1, 0xcf2,
0xcf3, 0xcf4, 0xcf6, 0xcf7, 0xcf8, 0xcf9, 0xcfa, 0xcfb, 0xcf4, 0xcf5,
0xcf7, 0xcf8, 0xcf9, 0xd02, 0xd03, 0xd04, 0xd05, 0xd06, 0xd08, 0xd09,
0xd0a, 0xd0b, 0xd0c, 0xd0d, 0xd0e, 0xd0f, 0xd11, 0xd12, 0xd13, 0xd14,
0xd15, 0xd16, 0xd17, 0xd18, 0xd1a, 0xd1b, 0xd1c, 0xd1d, 0xd1e, 0xd1f,
0xd20, 0xd21, 0xd22, 0xd24, 0xd25, 0xd26, 0xd27, 0xd28, 0xd29, 0xd2a,
0xd2b, 0xd2c, 0xd2e, 0xd2f, 0xd30, 0xd31, 0xd32, 0xd33, 0xd34, 0xd35,
0xd36, 0xd38, 0xd39, 0xd3a, 0xd3b, 0xd3c, 0xd3d, 0xd3e, 0xd3f, 0xd40,
0xd41, 0xd43, 0xd44, 0xd45, 0xd46, 0xd47, 0xd48, 0xd49, 0xd4a, 0xd4b,
0xd4c, 0xd4e, 0xd4f, 0xd50, 0xd51, 0xd52, 0xd4b, 0xd54, 0xd55, 0xd4e,
0xd57, 0xd58, 0xd52, 0xd5b, 0xd5c, 0xd55, 0xd5e, 0xd5f, 0xd58, 0xd61,
0xd62, 0xd63, 0xd64, 0xd66, 0xd67, 0xd68, 0xd69, 0xd6a, 0xd73, 0xd74,
0xd6d, 0xd6e, 0xd6f, 0xd70, 0xd72, 0xd7b, 0xd74, 0xd75, 0xd76, 0xd77,
0xd78, 0xd79, 0xd82, 0xd7b, 0xd84, 0xd7d, 0xd7f, 0xd80, 0xd81, 0xd82,
0xd8b, 0xd84, 0xd8d, 0xd8e, 0xd87, 0xd88, 0xd91, 0xd8a, 0xd93, 0xd94,
0xd8e, 0xd97, 0xd98, 0xd91, 0xd92, 0xd9b, 0xd9c, 0xd95, 0xd96, 0xd9f,
0xda0, 0xda1, 0xda2, 0xda3, 0xda5, 0xda6, 0xd9f, 0xda8, 0xda9, 0xdaa,
0xdab, 0xdac, 0xdad, 0xdae, 0xdaf, 0xdb0, 0xdb1, 0xdb2, 0xdb3, 0xdb5,
0xdb6, 0xdb7, 0xdb8, 0xdb9, 0xdba, 0xdbb, 0xdbc, 0xdbd, 0xdbe, 0xdbf,
0xdc0, 0xdc1, 0xdc2, 0xdc3, 0xdc4, 0xdc5, 0xdc7, 0xdc8, 0xdc9, 0xdca,
0xdcb, 0xdcc, 0xdcd, 0xdce, 0xdcf, 0xdd0, 0xdd1, 0xdd2, 0xddb, 0xdd4,
0xdd5, 0xdd6, 0xdd7, 0xdd8, 0xdd9, 0xddb, 0xddc, 0xddd, 0xdde, 0xddf,
0xde0, 0xde1, 0xde2, 0xde3, 0xde4, 0xde5, 0xdee, 0xdef, 0xde8, 0xdf1,
0xdea, 0xdeb, 0xdf4, 0xdf5, 0xdee, 0xdf7, 0xdf8, 0xdf2, 0xdfb, 0xdfc,
0xdf5, 0xdfe, 0xdff, 0xe00, 0xe01, 0xe02, 0xe03, 0xe04, 0xe05, 0xe06,
0xe07, 0xe08, 0xe09, 0xe0a, 0xe0b, 0xe0c, 0xe0d, 0xe0e, 0xe0f, 0xe10,
0xe11, 0xe12, 0xe13, 0xe14, 0xe16, 0xe17, 0xe18, 0xe19, 0xe1a, 0xe1b,
0xe1c, 0xe1d, 0xe1e, 0xe1f, 0xe20, 0xe21, 0xe22, 0xe23, 0xe24, 0xe25,
0xe26, 0xe2f, 0xe28, 0xe29, 0xe32, 0xe2b, 0xe2c, 0xe2d, 0xe2e, 0xe2f,
0xe38, 0xe39, 0xe32, 0xe33, 0xe3c, 0xe3d, 0xe36, 0xe3f, 0xe38, 0xe41,
0xe42, 0xe43, 0xe3c, 0xe45, 0xe47, 0xe48, 0xe49, 0xe42, 0xe4b, 0xe4c,
0xe4d, 0xe4e, 0xe4f, 0xe50, 0xe49, 0xe52, 0xe4b, 0xe54, 0xe55, 0xe4e,
0xe4f, 0xe50, 0xe59, 0xe5a, 0xe5b, 0xe5c, 0xe55, 0xe5e, 0xe5f, 0xe60,
0xe61, 0xe6a, 0xe63, 0xe64, 0xe6d, 0xe66, 0xe67, 0xe68, 0xe69, 0xe6a,
0xe6b, 0xe6c, 0xe6d, 0xe6e, 0xe6f, 0xe70, 0xe79, 0xe72, 0xe73, 0xe7c,
0xe75, 0xe7e, 0xe7f, 0xe80, 0xe81, 0xe82, 0xe83, 0xe84, 0xe85, 0xe7e,
0xe87, 0xe88, 0xe89, 0xe8a, 0xe8b, 0xe8c, 0xe8d, 0xe8e, 0xe8f, 0xe90,
0xe91, 0xe92, 0xe93, 0xe94, 0xe95, 0xe96, 0xe97, 0xe98, 0xe99, 0xe9a,
0xe9b, 0xe9c, 0xe9d, 0xe9e, 0xe9f, 0xea0, 0xea1, 0xea2, 0xea3, 0xeac,
0xea5, 0xea6, 0xea7, 0xea8, 0xea9, 0xeb2, 0xeab, 0xeac, 0xeb5, 0xeae,
0xeaf, 0xeb8, 0xeb9, 0xeba, 0xebb, 0xeb4, 0xebd, 0xebe, 0xebf, 0xec0,
0xec1, 0xec2, 0xebb, 0xec4, 0xec5, 0xec6, 0xec7, 0xec7, 0xec8, 0xec9,
0xeca, 0xecb, 0xecc, 0xecd, 0xece, 0xecf, 0xed0, 0xed1, 0xed2, 0xed3,
0xed4, 0xed5, 0xede, 0xed7, 0xed8, 0xee1, 0xeda, 0xedb, 0xee4, 0xee5,
0xede, 0xee7, 0xee0, 0xee9, 0xeea, 0xee3, 0xeec, 0xeed, 0xeee, 0xeef,
0xee8, 0xef1, 0xef2, 0xeeb, 0xef4, 0xeed, 0xef6, 0xef7, 0xef0, 0xef8,
0xef9, 0xefa, 0xefb, 0xefc, 0xefd, 0xefe, 0xeff, 0xf00, 0xf01, 0xf0a,
0xf0b, 0xf04, 0xf0d, 0xf06, 0xf07, 0xf10, 0xf11, 0xf0a, 0xf13, 0xf0c,
0xf0d, 0xf16, 0xf17, 0xf18, 0xf19, 0xf1a, 0xf13, 0xf1c, 0xf1c, 0xf1d,
0xf1e, 0xf1f, 0xf20, 0xf21, 0xf22, 0xf23, 0xf24, 0xf25, 0xf26, 0xf27,
0xf28, 0xf29, 0xf2a, 0xf2b, 0xf2c, 0xf2d, 0xf36, 0xf2f, 0xf30, 0xf39,
0xf32, 0xf33, 0xf3b, 0xf34, 0xf3d, 0xf3e, 0xf3f, 0xf38, 0xf41, 0xf42,
0xf43, 0xf44, 0xf45, 0xf46, 0xf47, 0xf48, 0xf49, 0xf4a, 0xf4b, 0xf4c,
0xf4d, 0xf4e, 0xf4f, 0xf4f, 0xf50, 0xf51, 0xf52, 0xf53, 0xf4c, 0xf55,
0xf56, 0xf57, 0xf58, 0xf59, 0xf5a, 0xf5b, 0xf5c, 0xf5d, 0xf5e, 0xf5f,
0xf60, 0xf69, 0xf69, 0xf6a, 0xf6b, 0xf6c, 0xf6d, 0xf6e, 0xf6f, 0xf68,
0xf71, 0xf72, 0xf73, 0xf74, 0xf75, 0xf76, 0xf77, 0xf78, 0xf79, 0xf79,
0xf7a, 0xf7b, 0xf7c, 0xf7d, 0xf7e, 0xf7f, 0xf80, 0xf81, 0xf82, 0xf83,
0xf8c, 0xf85, 0xf86, 0xf8f, 0xf88, 0xf90, 0xf89, 0xf8a, 0xf93, 0xf94,
0xf95, 0xf96, 0xf97, 0xf90, 0xf91, 0xf9a, 0xf9b, 0xf9c, 0xf9d, 0xf9e,
0xf9e, 0xf9f, 0xfa0, 0xfa1, 0xfa2, 0xfa3, 0xfa4, 0xfa5, 0xfa6, 0xfa7,
0xfa8, 0xfa9, 0xfaa, 0xfab, 0xfb3, 0xfac, 0xfad, 0xfae, 0xfaf, 0xfb0,
0xfb9, 0xfba, 0xfbb, 0xfb4, 0xfbd, 0xfbe, 0xfbf, 0xfb7, 0xfc0, 0xfc1,
0xfc2, 0xfc3, 0xfc4, 0xfc5, 0xfc6, 0xfc7, 0xfc8, 0xfc9, 0xfca, 0xfcb,
0xfcb, 0xfcc, 0xfcd, 0xfce, 0xfcf, 0xfd0, 0xfd1, 0xfda, 0xfd3, 0xfd4,
0xfd5, 0xfd6, 0xfd7, 0xfd7, 0xfd8, 0xfe1, 0xfda, 0xfdb, 0xfdc, 0xfdd,
0xfde, 0xfdf, 0xfe0, 0xfe9, 0xfea, 0xfea, 0xfeb, 0xfec, 0xfed, 0xfee,
0xfef, 0xff0, 0xff1, 0xff2, 0xff3, 0xff4, 0xff4, 0xff5, 0xff6, 0xff7,
0xff8, 0xff9, 0xffa, 0xffb, 0xffc, 0xffd, 0xffe, 0xfff, 0xc43, 0xc43,
0xc44, 0xc41, 0xc41, 0xc42, 0xc46, 0xc43, 0xc43, 0xc44, 0xc44, 0xc45,
0xc46, 0xc46, 0xc47, 0xc47, 0xc48, 0xc48, 0xc49, 0xc49, 0xc4a, 0xc4b,
0xc4b, 0xc4c, 0xc4c, 0xc4d, 0xc4d, 0xc4e, 0xc4e, 0xc4f, 0xc50, 0xc50,
0xc51, 0xc51, 0xc52, 0xc52, 0xc53, 0xc53, 0xc54, 0xc55, 0xc55, 0xc56,
0xc56, 0xc57, 0xc57, 0xc58, 0xc58, 0xc59, 0xc5a, 0xc5a, 0xc5b, 0xc5b,
0xc5c, 0xc5c, 0xc5d, 0xc5d, 0xc5a, 0xc5e, 0xc5f, 0xc60, 0xc5c, 0xc5d,
0xc5d, 0xc5e, 0xc5e, 0xc5f, 0xc5f, 0xc60, 0xc61, 0xc61, 0xc62, 0xc62,
0xc5f, 0xc63, 0xc64, 0xc64, 0xc65, 0xc65, 0xc66, 0xc67, 0xc67, 0xc68,
0xc68, 0xc69, 0xc69, 0xc66, 0xc66, 0xc67, 0xc6b, 0xc68, 0xc65, 0xc6d,
0xc6a, 0xc6a, 0xc67, 0xc6f, 0xc6c, 0xc6c, 0xc71, 0xc69, 0xc6e, 0xc6b,
0xc6f, 0xc70, 0xc6c, 0xc71, 0xc71, 0xc72, 0xc72, 0xc73, 0xc73, 0xc70,
0xc71, 0xc75, 0xc72, 0xc72, 0xc73, 0xc77, 0xc78, 0xc78, 0xc75, 0xc75,
0xc76, 0xc77, 0xc77, 0xc7c, 0xc78, 0xc79, 0xc79, 0xc7e, 0xc7e, 0xc7f,
0xc7f, 0xc80, 0xc81, 0xc81, 0xc82, 0xc8a, 0xc8b, 0xc8b, 0xc8c, 0xc8c,
0xc8d, 0xc8d, 0xc8e, 0xc8e, 0xc8f, 0xc8c, 0xc90, 0xc8d, 0xc91, 0xc92,
0xc92, 0xc8f, 0xc8f, 0xc90, 0xc94, 0xc95, 0xc95, 0xc92, 0xc93, 0xc93,
0xc94, 0xc94, 0xc95, 0xc95, 0xc96, 0xc96, 0xc93, 0xc97, 0xc98, 0xc98,
0xc99, 0xc96, 0xc96, 0xc97, 0xc9b, 0xc9c, 0xc9c, 0xc9d, 0xc99, 0xc9a,
0xc9a, 0xc9b, 0xc9f, 0xc9c, 0xca1, 0xc9d, 0xc9e, 0xc9e, 0xc9b, 0xc9f,
0xca0, 0xca0, 0xca1, 0xca1, 0xca2, 0xca2, 0xca7, 0xc9f, 0xca4, 0xca1,
0xca5, 0xca6, 0xcaa, 0xca7, 0xca7, 0xca8, 0xca8, 0xca9, 0xca9, 0xcaa,
0xca6, 0xcab, 0xcab, 0xcac, 0xcad, 0xca9, 0xcae, 0xcae, 0xcaf, 0xcaf,
0xcac, 0xcac, 0xcad, 0xcb1, 0xcb2, 0xcb2, 0xcaf, 0xcb3, 0xcb0, 0xcb1,
0xcb1, 0xcb2, 0xcb6, 0xcb3, 0xcb3, 0xcb4, 0xcb4, 0xcb5, 0xcb5, 0xcba,
0xcb6, 0xcb7, 0xcb7, 0xcb8, 0xcbc, 0xcb9, 0xcba, 0xcba, 0xcbb, 0xcbb,
0xcbc, 0xcc0, 0xcbd, 0xcbd, 0xcba, 0xcba, 0xcbb, 0xcbf, 0xcc0, 0xcbc,
0xcc1, 0xcbd, 0xcc2, 0xcbf, 0xcc3, 0xcc0, 0xcc4, 0xcc1, 0xcc1, 0xcc2,
0xcc2, 0xccb, 0xcc7, 0xccc, 0xccc, 0xcc9, 0xcc9, 0xcce, 0xcd2, 0xccf,
0xccb, 0xccc, 0xccd, 0xcd1, 0xcce, 0xcd2, 0xccf, 0xccf, 0xcd0, 0xcd0,
0xcd1, 0xcd1, 0xcd2, 0xcd2, 0xcd3, 0xcd3, 0xcd4, 0xcd4, 0xcd5, 0xcd5,
0xcd6, 0xcd7, 0xcd7, 0xcd4, 0xcd4, 0xcd5, 0xcd5, 0xcda, 0xcd6, 0xcd7,
0xcd7, 0xcd8, 0xcdc, 0xcd5, 0xcdd, 0xcda, 0xcda, 0xcd7, 0xcdb, 0xcd8,
0xcdc, 0xcdd, 0xcdd, 0xcda, 0xcdb, 0xcdb, 0xce0, 0xce0, 0xcdd, 0xcdd,
0xcde, 0xcde, 0xce3, 0xcdf, 0xce0, 0xce0, 0xce1, 0xce1, 0xcde, 0xce2,
0xce3, 0xce3, 0xce0, 0xce4, 0xce1, 0xce1, 0xce2, 0xce2, 0xce3, 0xce4,
0xce8, 0xce5, 0xce5, 0xce6, 0xce6, 0xce7, 0xce7, 0xce8, 0xce8, 0xce9,
0xce9, 0xcea, 0xcea, 0xceb, 0xceb, 0xce8, 0xce8, 0xced, 0xced, 0xcea,
0xcea, 0xcef, 0xcef, 0xcf0, 0xcf0, 0xced, 0xcee, 0xcee, 0xcef, 0xcf3,
0xcf0, 0xcf0, 0xcf1, 0xcf1, 0xcf2, 0xcf2, 0xcf3, 0xcf3, 0xcf8, 0xcf4,
0xcf5, 0xcf5, 0xcf6, 0xcfa, 0xcf7, 0xcf7, 0xcf8, 0xcf8, 0xcf5, 0xcf9,
0xcfa, 0xcfa, 0xcfb, 0xcfb, 0xcfc, 0xcfc, 0xcfd, 0xcfd, 0xd06, 0xd07,
0xd03, 0xd04, 0xd04, 0xd05, 0xd05, 0xd06, 0xd0a, 0xd0b, 0xd0b, 0xd08,
0xd08, 0xd09, 0xd0d, 0xd0a, 0xd0a, 0xd0b, 0xd0b, 0xd0c, 0xd0c, 0xd0d,
0xd0d, 0xd12, 0xd12, 0xd13, 0xd13, 0xd14, 0xd14, 0xd11, 0xd15, 0xd0e,
0xd16, 0xd1b, 0xd17, 0xd14, 0xd18, 0xd15, 0xd19, 0xd16, 0xd1a, 0xd1b,
0xd1b, 0xd18, 0xd1c, 0xd1d, 0xd1a, 0xd1a, 0xd1b, 0xd1b, 0xd1c, 0xd1c,
0xd1d, 0xd21, 0xd1e, 0xd22, 0xd1f, 0xd1f, 0xd24, 0xd20, 0xd21, 0xd21,
0xd22, 0xd22, 0xd1f, 0xd23, 0xd20, 0xd24, 0xd25, 0xd25, 0xd26, 0xd26,
0xd23, 0xd27, 0xd28, 0xd28, 0xd25, 0xd25, 0xd26, 0xd26, 0xd27, 0xd2b,
0xd28, 0xd2c, 0xd29, 0xd29, 0xd2e, 0xd2a, 0xd2b, 0xd2b, 0xd2c, 0xd2c,
0xd2d, 0xd29, 0xd2a, 0xd2e, 0xd33, 0xd33, 0xd34, 0xd30, 0xd31, 0xd35,
0xd36, 0xd32, 0xd37, 0xd37, 0xd30, 0xd34, 0xd39, 0xd35, 0xd36, 0xd3a,
0xd37, 0xd3b, 0xd38, 0xd3c, 0xd3d, 0xd3d, 0xd3a, 0xd3e, 0xd3b, 0xd3f,
0xd40, 0xd40, 0xd3d, 0xd3d, 0xd3e, 0xd3e, 0xd3b, 0xd43, 0xd40, 0xd40,
0xd45, 0xd41, 0xd42, 0xd42, 0xd4b, 0xd4b, 0xd4c, 0xd4c, 0xd4d, 0xd4d,
0xd4e, 0xd4e, 0xd4b, 0xd4f, 0xd4c, 0xd50, 0xd51, 0xd4d, 0xd4e, 0xd4e,
0xd4f, 0xd53, 0xd50, 0xd50, 0xd51, 0xd51, 0xd52, 0xd52, 0xd53, 0xd53,
0xd50, 0xd54, 0xd55, 0xd55, 0xd52, 0xd56, 0xd53, 0xd53, 0xd58, 0xd54,
0xd55, 0xd59, 0xd5a, 0xd56, 0xd53, 0xd57, 0xd58, 0xd58, 0xd5d, 0xd59,
0xd5a, 0xd5a, 0xd5b, 0xd5f, 0xd5c, 0xd5c, 0xd5d, 0xd5d, 0xd5e, 0xd5e,
0xd5f, 0xd5f, 0xd60, 0xd60, 0xd61, 0xd61, 0xd62, 0xd62, 0xd63, 0xd63,
0xd64, 0xd60, 0xd65, 0xd65, 0xd62, 0xd66, 0xd63, 0xd63, 0xd64, 0xd68,
0xd69, 0xd69, 0xd6a, 0xd6a, 0xd67, 0xd67, 0xd68, 0xd68, 0xd69, 0xd69,
0xd6a, 0xd66, 0xd6f, 0xd6f, 0xd70, 0xd70, 0xd6d, 0xd71, 0xd6e, 0xd72,
0xd73, 0xd73, 0xd74, 0xd70, 0xd71, 0xd71, 0xd7a, 0xd76, 0xd73, 0xd73,
0xd74, 0xd78, 0xd75, 0xd79, 0xd7a, 0xd7a, 0xd77, 0xd77, 0xd78, 0xd78,
0xd79, 0xd79, 0xd79, 0xd7a, 0xd76, 0xd7b, 0xd77, 0xd7c, 0xd7c, 0xd7d,
0xd7d, 0xd7e, 0xd7a, 0xd7f, 0xd7b, 0xd7c, 0xd7c, 0xd81, 0xd81, 0xd7e,
0xd82, 0xd87, 0xd87, 0xd84, 0xd88, 0xd89, 0xd85, 0xd8a, 0xd8a, 0xd8b,
0xd87, 0xd8c, 0xd88, 0xd89, 0xd8d, 0xd8a, 0xd8e, 0xd8b, 0xd8f, 0xd8c,
0xd8c, 0xd8d, 0xd8d, 0xd92, 0xd8e, 0xd8f, 0xd8f, 0xd93, 0xd90, 0xd90,
0xd8d, 0xd95, 0xd92, 0xd92, 0xd93, 0xd93, 0xd98, 0xd94, 0xd99, 0xd95,
0xd96, 0xd9a, 0xd97, 0xd93, 0xd94, 0xd9c, 0xd99, 0xd99, 0xd9a, 0xd9a,
0xd9b, 0xd9b, 0xd9c, 0xd9c, 0xd9d, 0xd9d, 0xd9a, 0xda2, 0xd9f, 0xda3,
0xda4, 0xda4, 0xda1, 0xda1, 0xda5, 0xd9e, 0xda2, 0xda3, 0xda3, 0xda0,
0xda4, 0xda5, 0xda5, 0xda6, 0xda6, 0xda7, 0xdab, 0xda8, 0xda8, 0xda9,
0xda9, 0xdaa, 0xdaa, 0xdab, 0xdaf, 0xdac, 0xdac, 0xdad, 0xda9, 0xdae,
0xdae, 0xdab, 0xdaf, 0xdab, 0xdac, 0xdb0, 0xdb1, 0xdad, 0xdb2, 0xdae,
0xdb3, 0xdb3, 0xdb0, 0xdb0, 0xdb5, 0xdb1, 0xdb2, 0xdb2, 0xdb3, 0xdb3,
0xdb4, 0xdb4, 0xdb5, 0xdb5, 0xdb6, 0xdb6, 0xdb7, 0xdb7, 0xdb8, 0xdb4,
0xdb8, 0xdb9, 0xdb9, 0xdba, 0xdba, 0xdbb, 0xdbb, 0xdbc, 0xdb8, 0xdb9,
0xdb9, 0xdbe, 0xdbe, 0xdbf, 0xdbb, 0xdbc, 0xdc0, 0xdc5, 0xdc5, 0xdc6,
0xdc6, 0xdc7, 0xdc7, 0xdc7, 0xdc4, 0xdc8, 0xdc9, 0xdc9, 0xdc6, 0xdc6,
0xdcb, 0xdcf, 0xdcc, 0xdcc, 0xdcd, 0xdcd, 0xdca, 0xdce, 0xdcf, 0xdcf,
0xdcc, 0xdcc, 0xdc9, 0xdcd, 0xdd2, 0xdd2, 0xdd2, 0xdd3, 0xdd3, 0xdd4,
0xdd0, 0xdd1, 0xdd5, 0xdd2, 0xdda, 0xdd3, 0xdd7, 0xdd4, 0xdd8, 0xdd9,
0xdd9, 0xdd6, 0xdd6, 0xdd7, 0xdd7, 0xddb, 0xdd8, 0xdd8, 0xdd9, 0xdd9,
0xdd2, 0xdda, 0xddb, 0xddb, 0xddc, 0xdd8, 0xddd, 0xddd, 0xdde, 0xdde,
0xddb, 0xddb, 0xddc, 0xddc, 0xddd, 0xddd, 0xde1, 0xdde, 0xdde, 0xddf,
0xddf, 0xde0, 0xde0, 0xde1, 0xde1, 0xdde, 0xde2, 0xde3, 0xde3, 0xde4,
0xde4, 0xde1, 0xde5, 0xde5, 0xde6, 0xde6, 0xde7, 0xde7, 0xde8, 0xde8,
0xde9, 0xde5, 0xdea, 0xdea, 0xdeb, 0xdeb, 0xde8, 0xdec, 0xded, 0xdf5,
0xdf1, 0xdf6, 0xdf2, 0xdf3, 0xdf3, 0xdf4, 0xdf8, 0xdf5, 0xdf5, 0xdf6,
0xdf2, 0xdf7, 0xdf7, 0xdf8, 0xdf8, 0xdf9, 0xdf1, 0xdf9, 0xdf6, 0xdfa,
0xdfb, 0xdfb, 0xdf8, 0xdfc, 0xdf9, 0xdf9, 0xdfe, 0xdfe, 0xdfb, 0xdff,
0xdfc, 0xdfc, 0xdfd, 0xdfd, 0xe09, 0xe0a, 0xe06, 0xe0b, 0xe07, 0xe0c,
0xe08, 0xe09, 0xe09, 0xe0a, 0xe0a, 0xe0b, 0xe0b, 0xe08, 0xe0c, 0xe10,
0xe0d, 0xe11, 0xe0e, 0xe0e, 0xe13, 0xe13, 0xe10, 0xe10, 0xe11, 0xe11,
0xe12, 0xe12, 0xe17, 0xe13, 0xe13, 0xe14, 0xe18, 0xe15, 0xe19, 0xe1a,
0xe1a, 0xe1b, 0xe1b, 0xe18, 0xe18, 0xe15, 0xe19, 0xe1e, 0xe1a, 0xe1e,
0xe1b, 0xe1b, 0xe1c, 0xe1c, 0xe1d, 0xe21, 0xe1a, 0xe1e, 0xe1f, 0xe1f,
0xe20, 0xe20, 0xe20, 0xe21, 0xe21, 0xe22, 0xe22, 0xe23, 0xe23, 0xe24,
0xe24, 0xe25, 0xe29, 0xe26, 0xe26, 0xe27, 0xe23, 0xe27, 0xe28, 0xe28,
0xe29, 0xe25, 0xe26, 0xe26, 0xe27, 0xe27, 0xe28, 0xe28, 0xe29, 0xe29,
0xe29, 0xe26, 0xe2a, 0xe27, 0xe27, 0xe2c, 0xe2c, 0xe29, 0xe29, 0xe2e,
0xe2e, 0xe2f, 0xe2b, 0xe2b, 0xe2c, 0xe30, 0xe2d, 0xe2d, 0xe2e, 0xe32,
0xe2f, 0xe2f, 0xe30, 0xe30, 0xe31, 0xe31, 0xe31, 0xe32, 0xe2e, 0xe33,
0xe2f, 0xe34, 0xe34, 0xe31, 0xe35, 0xe32, 0xe32, 0xe37, 0xe37, 0xe37,
0xe34, 0xe38, 0xe35, 0xe39, 0xe3a, 0xe3a, 0xe3b, 0xe3b, 0xe38, 0xe3c,
0xe44, 0xe41, 0xe41, 0xe42, 0xe42, 0xe43, 0xe43, 0xe48, 0xe48, 0xe49,
0xe49, 0xe46, 0xe46, 0xe46, 0xe4b, 0xe4b, 0xe48, 0xe48, 0xe45, 0xe49,
0xe4e, 0xe4e, 0xe4b, 0xe4f, 0xe4b, 0xe4c, 0xe4c, 0xe51, 0xe4d, 0xe4e,
0xe4e, 0xe4f, 0xe4f, 0xe4c, 0xe50, 0xe50, 0xe51, 0xe51, 0xe56, 0xe52,
0xe53, 0xe57, 0xe58, 0xe54, 0xe59, 0xe59, 0xe56, 0xe56, 0xe5a, 0xe57,
0xe5b, 0xe5c, 0xe58, 0xe59, 0xe5d, 0xe5e, 0xe5e, 0xe5f, 0xe5b, 0xe5f,
0xe5c, 0xe60, 0xe5d, 0xe5d, 0xe5a, 0xe5e, 0xe5f, 0xe63, 0xe60, 0xe64,
0xe64, 0xe65, 0xe61, 0xe62, 0xe62, 0xe63, 0xe63, 0xe64, 0xe64, 0xe65,
0xe65, 0xe65, 0xe66, 0xe66, 0xe67, 0xe67, 0xe6c, 0xe68, 0xe69, 0xe69,
0xe69, 0xe6a, 0xe6a, 0xe6b, 0xe6b, 0xe6c, 0xe6c, 0xe6d, 0xe71, 0xe6e,
0xe6e, 0xe6e, 0xe6f, 0xe6f, 0xe70, 0xe70, 0xe71, 0xe71, 0xe6e, 0xe76,
0xe73, 0xe73, 0xe73, 0xe74, 0xe74, 0xe71, 0xe79, 0xe76, 0xe76, 0xe77,
0xe77, 0xe77, 0xe74, 0xe78, 0xe79, 0xe79, 0xe7a, 0xe7a, 0xe7b, 0xe7b,
0xe80, 0xe7c, 0xe7c, 0xe7d, 0xe79, 0xe7e, 0xe7a, 0xe83, 0xe83, 0xe84,
0xe84, 0xe84, 0xe85, 0xe85, 0xe86, 0xe86, 0xe8b, 0xe87, 0xe84, 0xe84,
0xe89, 0xe89, 0xe85, 0xe86, 0xe8e, 0xe87, 0xe87, 0xe8c, 0xe90, 0xe89,
0xe89, 0xe89, 0xe8e, 0xe8a, 0xe8f, 0xe8b, 0xe8c, 0xe8c, 0xe91, 0xe91,
0xe8d, 0xe8e, 0xe92, 0xe8f, 0xe93, 0xe90, 0xe94, 0xe91, 0xe95, 0xe96,
0xe96, 0xe96, 0xe97, 0xe93, 0xe98, 0xe98, 0xe99, 0xe9d, 0xe9a, 0xe9a,
0xe9a, 0xe9b, 0xe9f, 0xe9c, 0xe9c, 0xe99, 0xe99, 0xe9e, 0xe9e, 0xe9e,
0xea3, 0xe9f, 0xea4, 0xea0, 0xea1, 0xea1, 0xe9e, 0xea2, 0xea2, 0xea3,
0xea3, 0xea4, 0xea8, 0xea1, 0xea9, 0xeaa, 0xea6, 0xea6, 0xea7, 0xea7,
0xea8, 0xea8, 0xea9, 0xea5, 0xea6, 0xeaa, 0xeaa, 0xeab, 0xeab, 0xea8,
0xeac, 0xead, 0xead, 0xeae, 0xeaa, 0xeae, 0xeab, 0xeab, 0xeac, 0xeb0,
0xeb1, 0xead, 0xeae, 0xeb2, 0xeae, 0xeaf, 0xeb3, 0xeb4, 0xeb8, 0xeb5,
0xeb5, 0xeb6, 0xeb6, 0xeb6, 0xeb7, 0xeb7, 0xeb4, 0xeb4, 0xeb9, 0xeb9,
0xeb6, 0xeba, 0xeba, 0xeb7, 0xeb7, 0xebc, 0xebc, 0xebd, 0xeb9, 0xebd,
0xeba, 0xeba, 0xebb, 0xec3, 0xec0, 0xec4, 0xec1, 0xec1, 0xec5, 0xec2,
0xec6, 0xec7, 0xec7, 0xec8, 0xec8, 0xec5, 0xec9, 0xec5, 0xeca, 0xeca,
0xecb, 0xecb, 0xec8, 0xecc, 0xec8, 0xec9, 0xec9, 0xeca, 0xeca, 0xecb,
0xecb, 0xecc, 0xecc, 0xecc, 0xecd, 0xecd, 0xece, 0xed2, 0xed3, 0xed3,
0xed4, 0xed8, 0xed4, 0xed1, 0xed5, 0xed6, 0xed6, 0xed3, 0xecf, 0xedb,
0xed8, 0xed4, 0xed9, 0xed9, 0xed6, 0xeda, 0xed7, 0xedb, 0xedb, 0xedc,
0xedc, 0xedd, 0xedd, 0xede, 0xeda, 0xede, 0xedf, 0xedf, 0xedc, 0xedc,
0xedd, 0xedd, 0xee2, 0xede, 0xede, 0xee3, 0xedf, 0xee4, 0xee4, 0xee1,
0xee5, 0xee1, 0xee2, 0xee2, 0xee3, 0xee7, 0xee8, 0xee4, 0xee9, 0xee9,
0xee5, 0xee6, 0xeee, 0xee7, 0xee7, 0xee8, 0xee8, 0xee8, 0xeed, 0xeed,
0xeee, 0xeee, 0xeeb, 0xeeb, 0xeef, 0xef0, 0xef4, 0xeed, 0xeed, 0xef2,
0xeee, 0xeef, 0xeef, 0xeef, 0xef0, 0xef0, 0xef1, 0xef1, 0xef2, 0xef2,
0xef2, 0xef3, 0xef3, 0xef4, 0xef4, 0xef1, 0xef5, 0xef1, 0xef6, 0xef6,
0xef3, 0xef7, 0xef4, 0xef8, 0xef1, 0xef9, 0xef1, 0xefa, 0xef6, 0xefb,
0xf03, 0xf04, 0xf08, 0xf04, 0xf05, 0xf05, 0xf06, 0xf06, 0xf07, 0xf0b,
0xf03, 0xf08, 0xf04, 0xf09, 0xf09, 0xf0a, 0xf0a, 0xf0a, 0xf0b, 0xf0b,
0xf10, 0xf10, 0xf0d, 0xf0d, 0xf0d, 0xf0e, 0xf0e, 0xf0f, 0xf13, 0xf10,
0xf10, 0xf10, 0xf11, 0xf15, 0xf12, 0xf12, 0xf13, 0xf13, 0xf10, 0xf14,
0xf14, 0xf15, 0xf15, 0xf16, 0xf1a, 0xf13, 0xf17, 0xf1b, 0xf1c, 0xf18,
0xf19, 0xf19, 0xf1a, 0xf1a, 0xf16, 0xf1b, 0xf1b, 0xf1c, 0xf20, 0xf1d,
0xf19, 0xf21, 0xf1e, 0xf1e, 0xf1f, 0xf1f, 0xf1c, 0xf20, 0xf20, 0xf25,
0xf21, 0xf22, 0xf22, 0xf23, 0xf23, 0xf23, 0xf20, 0xf24, 0xf25, 0xf25,
0xf22, 0xf22, 0xf22, 0xf23, 0xf27, 0xf24, 0xf24, 0xf25, 0xf29, 0xf25,
0xf2a, 0xf22, 0xf23, 0xf2b, 0xf28, 0xf2c, 0xf2c, 0xf29, 0xf29, 0xf2a,
0xf2a, 0xf2b, 0xf27, 0xf2b, 0xf2c, 0xf2c, 0xf2d, 0xf2d, 0xf2a, 0xf32,
0xf32, 0xf2f, 0xf2f, 0xf30, 0xf30, 0xf30, 0xf35, 0xf31, 0xf32, 0xf36,
0xf33, 0xf33, 0xf37, 0xf34, 0xf34, 0xf35, 0xf35, 0xf36, 0xf32, 0xf3a,
0xf37, 0xf37, 0xf38, 0xf34, 0xf39, 0xf39, 0xf45, 0xf42, 0xf46, 0xf47,
0xf47, 0xf48, 0xf48, 0xf48, 0xf45, 0xf49, 0xf4a, 0xf4a, 0xf4b, 0xf4b,
0xf47, 0xf4c, 0xf48, 0xf49, 0xf51, 0xf4e, 0xf4e, 0xf4a, 0xf4f, 0xf4f,
0xf4c, 0xf50, 0xf50, 0xf51, 0xf51, 0xf52, 0xf52, 0xf4f, 0xf57, 0xf53,
0xf54, 0xf54, 0xf59, 0xf59, 0xf56, 0xf56, 0xf56, 0xf57, 0xf57, 0xf58,
0xf58, 0xf59, 0xf59, 0xf59, 0xf5a, 0xf5a, 0xf57, 0xf5b, 0xf5b, 0xf58,
0xf58, 0xf5d, 0xf59, 0xf5e, 0xf5e, 0xf5e, 0xf5b, 0xf5f, 0xf5c, 0xf5c,
0xf5d, 0xf5d, 0xf5d, 0xf5e, 0xf5e, 0xf5f, 0xf5f, 0xf5f, 0xf5c, 0xf60,
0xf61, 0xf61, 0xf5e, 0xf62, 0xf5e, 0xf63, 0xf63, 0xf60, 0xf64, 0xf61,
0xf65, 0xf65, 0xf66, 0xf66, 0xf63, 0xf67, 0xf67, 0xf68, 0xf68, 0xf69,
0xf69, 0xf66, 0xf6a, 0xf6a, 0xf6b, 0xf6b, 0xf6c, 0xf6c, 0xf6d, 0xf6d,
0xf6d, 0xf72, 0xf6e, 0xf6f, 0xf73, 0xf73, 0xf74, 0xf70, 0xf75, 0xf75,
0xf72, 0xf72, 0xf76, 0xf77, 0xf77, 0xf74, 0xf78, 0xf78, 0xf79, 0xf79,
0xf7a, 0xf7a, 0xf7b, 0xf77, 0xf7b, 0xf78, 0xf7c, 0xf7d, 0xf7d, 0xf7d,
0xf7a, 0xf7a, 0xf7f, 0xf83, 0xf84, 0xf84, 0xf84, 0xf81, 0xf85, 0xf86,
0xf86, 0xf83, 0xf83, 0xf87, 0xf84, 0xf84, 0xf85, 0xf89, 0xf89, 0xf86,
0xf86, 0xf87, 0xf87, 0xf8c, 0xf8c, 0xf88, 0xf89, 0xf89, 0xf8a, 0xf8a,
0xf8a, 0xf93, 0xf8b, 0xf8c, 0xf88, 0xf89, 0xf8d, 0xf91, 0xf8e, 0xf92,
0xf8b, 0xf8f, 0xf8f, 0xf94, 0xf94, 0xf91, 0xf91, 0xf95, 0xf96, 0xf96,
0xf97, 0xf97, 0xf98, 0xf98, 0xf98, 0xf99, 0xf99, 0xf9a, 0xf9a, 0xf96,
0xf9b, 0xf9b, 0xf9c, 0xf9c, 0xf9d, 0xf9d, 0xfa1, 0xf9e, 0xf9e, 0xf9b,
0xf9f, 0xf9f, 0xfa0, 0xfa0, 0xf9d, 0xfa5, 0xf9e, 0xfa2, 0xfa2, 0xf9f,
0xfa3, 0xfa0, 0xfa0, 0xfa4, 0xfa5, 0xfa5, 0xfa2, 0xf9e, 0xfa2, 0xfa3,
0xfa3, 0xfa4, 0xfa8, 0xfa5, 0xfa5, 0xfa5, 0xfa6, 0xfaa, 0xfa7, 0xfa7,
0xfa7, 0xfa8, 0xfa8, 0xfa9, 0xfa9, 0xfaa, 0xfae, 0xfaa, 0xfab, 0xfaf,
0xfb0, 0xfac, 0xfb0, 0xfb1, 0xfb1, 0xfae, 0xfb2, 0xfae, 0xfb3, 0xfaf,
0xfb4, 0xfb4, 0xfad, 0xfb1, 0xfb5, 0xfb6, 0xfb6, 0xfb7, 0xfb3, 0xfb7,
0xfb4, 0xfb4, 0xfb9, 0xfb9, 0xfb9, 0xfba, 0xfba, 0xfb7, 0xfb7, 0xfc3,
0xfc0, 0xfc4, 0xfc1, 0xfbd, 0xfc2, 0xfbe, 0xfc6, 0xfc3, 0xfc3, 0xfc4,
0xfc0, 0xfc0, 0xfc1, 0xfc5, 0xfc2, 0xfc2, 0xfc6, 0xfc3, 0xfc3, 0xfc8,
0xfc8, 0xfc5, 0xfc5, 0xfc5, 0xfca, 0xfca, 0xfcb, 0xfcb, 0xfcb, 0xfc8,
0xfcc, 0xfc9, 0xfc9, 0xfcd, 0xfce, 0xfca, 0xfcf, 0xfcf, 0xfcf, 0xfd0,
0xfd0, 0xfd1, 0xfd1, 0xfca, 0xfd2, 0xfd2, 0xfcf, 0xfd3, 0xfd4, 0xfd4,
0xfd4, 0xfd5, 0xfd1, 0xfd2, 0xfd6, 0xfd6, 0xfd7, 0xfdf, 0xfdc, 0xfdc,
0xfe0, 0xfe1, 0xfe1, 0xfde, 0xfde, 0xfde, 0xfdf, 0xfe3, 0xfe4, 0xfe4,
0xfdd, 0xfe1, 0xfe1, 0xfe6, 0xfe2, 0xfe3, 0xfe3, 0xfe7, 0xfe4, 0xfe4,
0xfe9, 0xfe9, 0xfe9, 0xfea, 0xfe6, 0xfe7, 0xfe7, 0xfe7, 0xfec, 0xfe8,
0xfe9, 0xfe9, 0xfe9, 0xfea, 0xfea, 0xfeb, 0xfeb, 0xff0, 0xfec, 0xfec,
0xff1, 0xff1, 0xff2, 0xff2, 0xff2, 0xfef, 0xfeb, 0xff0, 0xff4, 0xff4,
0xff5, 0xff1, 0xff6, 0xff6, 0xff6, 0xff7, 0xff7, 0xff8, 0xff8, 0xff8,
0xff9, 0xff5, 0xffa, 0xffa, 0xffa, 0xff7, 0xff3, 0xffc, 0xff8, 0xffc,
0xffd, 0xffd, 0xffa, 0xffa, 0xfff, 0xfff
};
#endif /* _MI_DISP_NVT_ALPHA_DATA_H_ */

View File

@@ -47,6 +47,7 @@
#include "msm_mmu.h"
#include "sde_wb.h"
#include "sde_dbg.h"
#include "dsi/dsi_panel_mi.h"
/*
* MSM driver version:
@@ -2060,6 +2061,8 @@ static void msm_pdev_shutdown(struct platform_device *pdev)
return;
}
dsi_panel_power_turn_off(false);
msm_lastclose(ddev);
/* set this after lastclose to allow kickoff from lastclose */

View File

@@ -128,6 +128,7 @@ enum msm_mdp_plane_property {
PLANE_PROP_SRC_CONFIG,
PLANE_PROP_FB_TRANSLATION_MODE,
PLANE_PROP_MULTIRECT_MODE,
PLANE_PROP_MI_LAYER_INFO,
/* total # of properties */
PLANE_PROP_COUNT
@@ -164,6 +165,7 @@ enum msm_mdp_crtc_property {
CRTC_PROP_CAPTURE_OUTPUT,
CRTC_PROP_IDLE_PC_STATE,
CRTC_PROP_MI_FOD_SYNC_INFO,
/* total # of properties */
CRTC_PROP_COUNT

View File

@@ -0,0 +1,165 @@
#include <linux/err.h>
#include <linux/slab.h>
#include "sde_dbg.h"
#include "clone_cooling_device.h"
#include "../dsi/dsi_display.h"
#include "../dsi/dsi_panel_mi.h"
#define BL_NODE_NAME_SIZE 32
static int bd_cdev_get_max_brightness_clone(struct thermal_cooling_device *cdev,
unsigned long *state)
{
struct sde_clone_cdev *cdev_clone;
struct backlight_device *bd;
if (!cdev)
return -EINVAL;
cdev_clone = (struct sde_clone_cdev *)cdev->devdata;
if (!cdev_clone)
return -EINVAL;
bd = cdev_clone->bd;
if (!bd)
return -ENODEV;
if (!cdev_clone->panel)
return -ENODEV;
*state = cdev_clone->panel->mi_cfg.max_brightness_clone;
return 0;
}
static int bd_cdev_get_cur_brightness_clone(struct thermal_cooling_device *cdev,
unsigned long *state)
{
struct sde_clone_cdev *cdev_clone;
struct backlight_device *bd;
if (!cdev)
return -EINVAL;
cdev_clone = (struct sde_clone_cdev *)cdev->devdata;
if (!cdev_clone)
return -EINVAL;
bd = cdev_clone->bd;
if (!bd)
return -ENODEV;
*state = cdev_clone->panel->mi_cfg.max_brightness_clone - bd->thermal_brightness_clone_limit;
return 0;
}
static int bd_cdev_set_cur_brightness_clone(struct thermal_cooling_device *cdev,
unsigned long state)
{
struct sde_clone_cdev *cdev_clone;
unsigned long brightness_lvl;
struct backlight_device *bd;
int rc = 0;
if (!cdev)
return -EINVAL;
cdev_clone = (struct sde_clone_cdev *)cdev->devdata;
if (!cdev_clone)
return -EINVAL;
bd = cdev_clone->bd;
if (!bd)
return -ENODEV;
if (state > cdev_clone->panel->mi_cfg.max_brightness_clone)
return -EINVAL;
brightness_lvl = cdev_clone->panel->mi_cfg.max_brightness_clone - state;
if (brightness_lvl == bd->thermal_brightness_clone_limit)
return 0;
bd->thermal_brightness_clone_limit = brightness_lvl;
SDE_INFO("backup_brightness_clone[%d], thermal limit[%d]\n", bd->props.brightness_clone_backup, bd->thermal_brightness_clone_limit);
#ifndef CONFIG_THERMAL_DIMMING
brightness_lvl = (bd->props.brightness_clone_backup
<= bd->thermal_brightness_clone_limit) ?
bd->props.brightness_clone_backup :
bd->thermal_brightness_clone_limit;
bd->props.brightness_clone = brightness_lvl;
sysfs_notify(&bd->dev.kobj, NULL, "brightness_clone");
#else
sysfs_notify(&cdev->device.kobj, NULL, "cur_state");
#endif
return rc;
}
static struct thermal_cooling_device_ops bd_cdev_clone_ops = {
.get_max_state = bd_cdev_get_max_brightness_clone,
.get_cur_state = bd_cdev_get_cur_brightness_clone,
.set_cur_state = bd_cdev_set_cur_brightness_clone,
};
int backlight_clone_cdev_register(struct sde_clone_cdev *cdev_clone,
struct device *parent,
struct backlight_device *bd)
{
static int display_clone_count;
char bl_node_name[BL_NODE_NAME_SIZE];
if (!bd || !parent || !cdev_clone)
return -EINVAL;
if (!of_find_property(parent->of_node, "#cooling-cells", NULL))
return -ENODEV;
snprintf(bl_node_name, BL_NODE_NAME_SIZE, "brightness%u-clone", display_clone_count++);
cdev_clone->bd = bd;
cdev_clone->cdev = thermal_of_cooling_device_register(parent->of_node,
bl_node_name, cdev_clone, &bd_cdev_clone_ops);
if (!&(cdev_clone->cdev)) {
pr_err("Cooling device register failed\n");
return -EINVAL;
}
else
display_clone_count++;
return 0;
}
void backlight_clone_cdev_unregister(struct sde_clone_cdev *cdev_clone)
{
if (!cdev_clone)
return;
thermal_cooling_device_unregister(cdev_clone->cdev);
}
int sde_backlight_clone_setup(struct sde_connector *c_conn, struct device *parent, struct backlight_device *bd)
{
struct dsi_display *display;
struct sde_clone_cdev *cdev_clone = NULL;
int rc = 0;
if (!c_conn || !parent || !bd)
return -ENOMEM;
display = (struct dsi_display *) c_conn->display;
if (!display || !display->panel)
return -ENOMEM;
cdev_clone = devm_kzalloc(parent, sizeof(*cdev_clone), GFP_KERNEL);
if (!cdev_clone)
return -ENOMEM;
cdev_clone->panel = display->panel;
bd->thermal_brightness_clone_limit = cdev_clone->panel->mi_cfg.max_brightness_clone;
rc = backlight_clone_cdev_register(cdev_clone, parent, bd);
if (rc) {
pr_err("Failed to register backlight_clone_cdev\n");
return -ENODEV;
}
c_conn->cdev_clone = cdev_clone;
return 0;
}

View File

@@ -0,0 +1,19 @@
#include <linux/device.h>
#include <linux/backlight.h>
#include <linux/thermal.h>
#include <linux/notifier.h>
#include "sde_connector.h"
#include "dsi_panel.h"
struct sde_connector;
struct sde_clone_cdev {
struct thermal_cooling_device *cdev;
struct backlight_device *bd;
struct dsi_panel *panel;
};
int sde_backlight_clone_setup(struct sde_connector *c_conn,
struct device *dev,
struct backlight_device *bd);
void backlight_clone_cdev_unregister(struct sde_clone_cdev *cdev_clone);

View File

@@ -19,6 +19,7 @@
#include "sde_core_irq.h"
#include "dsi_panel.h"
#include "sde_hw_color_proc_common_v4.h"
#include "sde_connector.h"
struct sde_cp_node {
u32 property_id;
@@ -44,6 +45,16 @@ struct sde_cp_prop_attach {
uint64_t val;
};
struct pcc_check_info {
uint32_t crtc_id;
bool initialized;
struct drm_property pcc_property;
uint64_t pcc_val;
uint64_t fod_val;
};
static struct pcc_check_info pcc_info;
#define ALIGNED_OFFSET (U32_MAX & ~(LTM_GUARD_BYTES))
static void dspp_pcc_install_property(struct drm_crtc *crtc);
@@ -235,16 +246,62 @@ static int set_dspp_vlut_feature(struct sde_hw_dspp *hw_dspp,
return ret;
}
static struct drm_msm_pcc color_transform_pcc_cfg = {
.r.c = 0, .r.r = 32768, .r.g = 0, .r.b = 0,
.g.c = 0, .g.r = 0, .g.g = 32768, .g.b = 0,
.b.c = 0, .b.r = 0, .b.g = 0, .b.b = 32768,};
static struct drm_msm_pcc pcc_cfg_clear;
void sde_dspp_clear_pcc(struct sde_hw_cp_cfg *hw_cfg)
{
if (!hw_cfg->payload) {
DRM_INFO("hw_cfg->payload in NULL\n");
return;
}
hw_cfg->payload_clear = &pcc_cfg_clear;
pcc_cfg_clear.r.c = color_transform_pcc_cfg.r.c;
pcc_cfg_clear.r.r = color_transform_pcc_cfg.r.r;
pcc_cfg_clear.r.g = color_transform_pcc_cfg.r.g;
pcc_cfg_clear.r.b = color_transform_pcc_cfg.r.b;
pcc_cfg_clear.g.c = color_transform_pcc_cfg.g.c;
pcc_cfg_clear.g.r = color_transform_pcc_cfg.g.r;
pcc_cfg_clear.g.g = color_transform_pcc_cfg.g.g;
pcc_cfg_clear.g.b = color_transform_pcc_cfg.g.b;
pcc_cfg_clear.b.c = color_transform_pcc_cfg.b.c;
pcc_cfg_clear.b.r = color_transform_pcc_cfg.b.r;
pcc_cfg_clear.b.g = color_transform_pcc_cfg.b.g;
pcc_cfg_clear.b.b = color_transform_pcc_cfg.b.b;
}
static int set_dspp_pcc_feature(struct sde_hw_dspp *hw_dspp,
struct sde_hw_cp_cfg *hw_cfg,
struct sde_crtc *hw_crtc)
{
int ret = 0;
struct drm_msm_pcc *pcc_cfg;
if (!hw_dspp || !hw_dspp->ops.setup_pcc)
ret = -EINVAL;
else
else {
if (hw_cfg->payload) {
pcc_cfg = hw_cfg->payload;
}
if (hw_crtc->mi_dimlayer_type & MI_DIMLAYER_FOD_HBM_OVERLAY) {
sde_dspp_clear_pcc(hw_cfg);
} else {
hw_cfg->payload_clear = NULL;
}
if (hw_cfg->payload_clear) {
pcc_cfg = hw_cfg->payload_clear;
}
hw_dspp->ops.setup_pcc(hw_dspp, hw_cfg);
}
return ret;
}
@@ -1314,7 +1371,7 @@ static void _sde_cp_crtc_enable_hist_irq(struct sde_crtc *sde_crtc)
struct sde_hw_dspp *hw_dspp = NULL;
struct sde_crtc_irq_info *node = NULL;
int i, irq_idx, ret = 0;
unsigned long flags;
unsigned long flags, state_flags;
if (!crtc_drm) {
DRM_ERROR("invalid crtc %pK\n", crtc_drm);
@@ -1344,12 +1401,13 @@ static void _sde_cp_crtc_enable_hist_irq(struct sde_crtc *sde_crtc)
spin_lock_irqsave(&sde_crtc->spin_lock, flags);
node = _sde_cp_get_intr_node(DRM_EVENT_HISTOGRAM, sde_crtc);
spin_unlock_irqrestore(&sde_crtc->spin_lock, flags);
if (!node)
if (!node) {
spin_unlock_irqrestore(&sde_crtc->spin_lock, flags);
return;
}
spin_lock_irqsave(&node->state_lock, flags);
spin_lock_irqsave(&node->state_lock, state_flags);
if (node->state == IRQ_DISABLED) {
ret = sde_core_irq_enable(kms, &irq_idx, 1);
if (ret)
@@ -1357,7 +1415,8 @@ static void _sde_cp_crtc_enable_hist_irq(struct sde_crtc *sde_crtc)
else
node->state = IRQ_ENABLED;
}
spin_unlock_irqrestore(&node->state_lock, flags);
spin_unlock_irqrestore(&node->state_lock, state_flags);
spin_unlock_irqrestore(&sde_crtc->spin_lock, flags);
}
static int sde_cp_crtc_checkfeature(struct sde_cp_node *prop_node,
@@ -1467,6 +1526,7 @@ static void sde_cp_crtc_setfeature(struct sde_cp_node *prop_node,
hw_cfg.mixer_info = hw_lm;
hw_cfg.displayh = num_mixers * hw_lm->cfg.out_width;
hw_cfg.displayv = hw_lm->cfg.out_height;
hw_cfg.mi_dimlayer_type = sde_crtc->mi_dimlayer_type;
ret = set_feature(hw_dspp, &hw_cfg, sde_crtc);
if (ret)
@@ -1931,6 +1991,12 @@ int sde_cp_crtc_set_property(struct drm_crtc *crtc,
struct sde_crtc *sde_crtc = NULL;
int ret = 0, i = 0, dspp_cnt, lm_cnt;
u8 found = 0;
bool fod_changed = false;
if (!pcc_info.initialized) {
pcc_info.crtc_id = crtc->base.id;
pcc_info.initialized = true;
}
if (!crtc || !property) {
DRM_ERROR("invalid crtc %pK property %pK\n", crtc, property);
@@ -1943,11 +2009,36 @@ int sde_cp_crtc_set_property(struct drm_crtc *crtc,
return -EINVAL;
}
if (!strncmp(property->name, "mi_fod_sync_info", sizeof("mi_fod_sync_info"))
&& pcc_info.crtc_id == crtc->base.id) {
if ((val & MI_DIMLAYER_FOD_HBM_OVERLAY) != (pcc_info.fod_val & MI_DIMLAYER_FOD_HBM_OVERLAY)) {
fod_changed = true;
}
pcc_info.fod_val = val;
}
mutex_lock(&sde_crtc->crtc_cp_lock);
list_for_each_entry(prop_node, &sde_crtc->feature_list, feature_list) {
if (property->base.id == prop_node->property_id) {
found = 1;
break;
if (!strncmp(property->name, "SDE_DSPP_PCC_V4", sizeof("SDE_DSPP_PCC_V4"))
&& pcc_info.crtc_id == crtc->base.id) {
pcc_info.pcc_val = val;
pcc_info.pcc_property.flags = property->flags;
pcc_info.pcc_property.base.id = property->base.id;
}
if (fod_changed) {
list_for_each_entry(prop_node, &sde_crtc->feature_list, feature_list) {
if (pcc_info.pcc_property.base.id == prop_node->property_id) {
found = 1;
break;
}
}
} else {
list_for_each_entry(prop_node, &sde_crtc->feature_list, feature_list) {
if (property->base.id == prop_node->property_id) {
found = 1;
break;
}
}
}
@@ -1999,11 +2090,17 @@ int sde_cp_crtc_set_property(struct drm_crtc *crtc,
/* remove the property from dirty list */
list_del_init(&prop_node->dirty_list);
if (!val)
if (!val) {
ret = sde_cp_disable_crtc_property(crtc, property, prop_node);
else
ret = sde_cp_enable_crtc_property(crtc, property,
} else {
if (fod_changed) {
ret = sde_cp_enable_crtc_property(crtc, &pcc_info.pcc_property,
prop_node, pcc_info.pcc_val);
} else {
ret = sde_cp_enable_crtc_property(crtc, property,
prop_node, val);
}
}
if (!ret) {
/* remove the property from active list */
@@ -2011,6 +2108,10 @@ int sde_cp_crtc_set_property(struct drm_crtc *crtc,
/* Mark the feature as dirty */
sde_cp_update_list(prop_node, sde_crtc, true);
}
if (fod_changed) {
ret = -ENOENT;
}
exit:
mutex_unlock(&sde_crtc->crtc_cp_lock);
return ret;
@@ -2091,6 +2192,7 @@ void sde_cp_crtc_destroy_properties(struct drm_crtc *crtc)
}
sde_crtc->ltm_buffer_cnt = 0;
sde_crtc->ltm_hist_en = false;
sde_crtc->hist_irq_idx = -1;
mutex_destroy(&sde_crtc->crtc_cp_lock);
INIT_LIST_HEAD(&sde_crtc->active_list);
@@ -2186,6 +2288,7 @@ void sde_cp_crtc_clear(struct drm_crtc *crtc)
}
sde_crtc->ltm_buffer_cnt = 0;
sde_crtc->ltm_hist_en = false;
sde_crtc->hist_irq_idx = -1;
INIT_LIST_HEAD(&sde_crtc->ltm_buf_free);
INIT_LIST_HEAD(&sde_crtc->ltm_buf_busy);
}
@@ -2392,9 +2495,15 @@ static void dspp_ltm_install_property(struct drm_crtc *crtc)
char feature_name[256];
struct sde_kms *kms = NULL;
struct sde_mdss_cfg *catalog = NULL;
u32 version;
u32 version = 0, ltm_sw_fuse = 0;
kms = get_kms(crtc);
if (!kms || !kms->hw_sw_fuse) {
DRM_ERROR("!kms = %d\n", !kms);
return;
}
ltm_sw_fuse = sde_hw_get_ltm_sw_fuse_value(kms->hw_sw_fuse);
catalog = kms->catalog;
version = catalog->dspp[0].sblk->ltm.version >> 16;
snprintf(feature_name, ARRAY_SIZE(feature_name), "%s%d",
@@ -2965,45 +3074,20 @@ static void sde_cp_hist_interrupt_cb(void *arg, int irq_idx)
struct sde_crtc *crtc = arg;
struct drm_crtc *crtc_drm = &crtc->base;
struct sde_hw_dspp *hw_dspp;
struct sde_kms *kms;
struct sde_crtc_irq_info *node = NULL;
u32 lock_hist = 1;
u32 i;
int ret = 0;
unsigned long flags;
/* disable histogram irq */
kms = get_kms(crtc_drm);
spin_lock_irqsave(&crtc->spin_lock, flags);
node = _sde_cp_get_intr_node(DRM_EVENT_HISTOGRAM, crtc);
spin_unlock_irqrestore(&crtc->spin_lock, flags);
if (!node) {
DRM_DEBUG_DRIVER("cannot find histogram event node in crtc\n");
return;
}
spin_lock_irqsave(&node->state_lock, flags);
if (node->state == IRQ_ENABLED) {
if (sde_core_irq_disable_nolock(kms, irq_idx)) {
DRM_ERROR("failed to disable irq %d, ret %d\n",
irq_idx, ret);
spin_unlock_irqrestore(&node->state_lock, flags);
return;
}
node->state = IRQ_DISABLED;
}
spin_unlock_irqrestore(&node->state_lock, flags);
/* lock histogram buffer */
for (i = 0; i < crtc->num_mixers; i++) {
hw_dspp = crtc->mixers[i].hw_dspp;
if (hw_dspp && hw_dspp->ops.lock_histogram)
hw_dspp->ops.lock_histogram(hw_dspp, NULL);
hw_dspp->ops.lock_histogram(hw_dspp, &lock_hist);
}
crtc->hist_irq_idx = irq_idx;
/* notify histogram event */
sde_crtc_event_queue(crtc_drm, sde_cp_notify_hist_event,
NULL, true);
&crtc->hist_irq_idx, true);
}
static void sde_cp_notify_hist_event(struct drm_crtc *crtc_drm, void *arg)
@@ -3013,10 +3097,12 @@ static void sde_cp_notify_hist_event(struct drm_crtc *crtc_drm, void *arg)
struct drm_event event;
struct drm_msm_hist *hist_data;
struct sde_kms *kms;
int ret;
u32 i;
struct sde_crtc_irq_info *node = NULL;
unsigned long flags, state_flags;
int ret, irq_idx;
u32 i, lock_hist = 0;
if (!crtc_drm) {
if (!crtc_drm || !arg) {
DRM_ERROR("invalid crtc %pK\n", crtc_drm);
return;
}
@@ -3027,15 +3113,70 @@ static void sde_cp_notify_hist_event(struct drm_crtc *crtc_drm, void *arg)
return;
}
if (!crtc->hist_blob)
return;
kms = get_kms(crtc_drm);
if (!kms || !kms->dev) {
SDE_ERROR("invalid arg(s)\n");
return;
}
/* disable histogram irq */
spin_lock_irqsave(&crtc->spin_lock, flags);
node = _sde_cp_get_intr_node(DRM_EVENT_HISTOGRAM, crtc);
if (!node) {
spin_unlock_irqrestore(&crtc->spin_lock, flags);
DRM_DEBUG_DRIVER("cannot find histogram event node in crtc\n");
/* unlock histogram */
ret = pm_runtime_get_sync(kms->dev->dev);
if (ret < 0) {
SDE_ERROR("failed to enable power resource %d\n", ret);
SDE_EVT32(ret, SDE_EVTLOG_ERROR);
return;
}
for (i = 0; i < crtc->num_mixers; i++) {
hw_dspp = crtc->mixers[i].hw_dspp;
if (hw_dspp && hw_dspp->ops.lock_histogram)
hw_dspp->ops.lock_histogram(hw_dspp,
&lock_hist);
}
pm_runtime_put_sync(kms->dev->dev);
return;
}
irq_idx = *(int *)arg;
spin_lock_irqsave(&node->state_lock, state_flags);
if (node->state == IRQ_ENABLED) {
ret = sde_core_irq_disable_nolock(kms, irq_idx);
if (ret) {
DRM_ERROR("failed to disable irq %d, ret %d\n",
irq_idx, ret);
spin_unlock_irqrestore(&node->state_lock, state_flags);
spin_unlock_irqrestore(&crtc->spin_lock, flags);
ret = pm_runtime_get_sync(kms->dev->dev);
if (ret < 0) {
SDE_ERROR("failed to enable power %d\n", ret);
SDE_EVT32(ret, SDE_EVTLOG_ERROR);
return;
}
/* unlock histogram */
for (i = 0; i < crtc->num_mixers; i++) {
hw_dspp = crtc->mixers[i].hw_dspp;
if (hw_dspp && hw_dspp->ops.lock_histogram)
hw_dspp->ops.lock_histogram(hw_dspp,
&lock_hist);
}
pm_runtime_put_sync(kms->dev->dev);
return;
}
node->state = IRQ_DISABLED;
}
spin_unlock_irqrestore(&node->state_lock, state_flags);
spin_unlock_irqrestore(&crtc->spin_lock, flags);
if (!crtc->hist_blob)
return;
ret = pm_runtime_get_sync(kms->dev->dev);
if (ret < 0) {
SDE_ERROR("failed to enable power resource %d\n", ret);

View File

@@ -14,9 +14,16 @@
#include <linux/backlight.h>
#include <linux/string.h>
#include "dsi_drm.h"
#include "dsi_defs.h"
#include "dsi_display.h"
#include "sde_crtc.h"
#include "sde_rm.h"
#include "sde_trace.h"
#include "dsi_mi_feature.h"
#include "dsi_display.h"
#include "dsi_panel_mi.h"
#include "clone_cooling_device.h"
#include "mi_disp_lhbm.h"
#define BL_NODE_NAME_SIZE 32
#define HDR10_PLUS_VSIF_TYPE_CODE 0x81
@@ -78,13 +85,19 @@ static int sde_backlight_device_update_status(struct backlight_device *bd)
brightness = bd->props.brightness;
c_conn = bl_get_data(bd);
display = (struct dsi_display *) c_conn->display;
if((display->panel->mi_cfg.panel_id == 0x4C38314100420400) && (bd->thermal_brightness_limit != 0)) {
brightness = (brightness <= bd->thermal_brightness_limit) ? brightness : bd->thermal_brightness_limit;
bd->props.brightness = brightness;
}
if ((bd->props.power != FB_BLANK_UNBLANK) ||
(bd->props.state & BL_CORE_FBBLANK) ||
(bd->props.state & BL_CORE_SUSPENDED))
brightness = 0;
c_conn = bl_get_data(bd);
display = (struct dsi_display *) c_conn->display;
if (brightness > display->panel->bl_config.bl_max_level)
brightness = display->panel->bl_config.bl_max_level;
@@ -111,6 +124,7 @@ static int sde_backlight_device_update_status(struct backlight_device *bd)
rc = c_conn->ops.set_backlight(&c_conn->base,
c_conn->display, bl_lvl);
c_conn->unset_bl_level = 0;
c_conn->mi_dimlayer_state.current_backlight = bl_lvl;
}
return rc;
@@ -134,6 +148,7 @@ static int sde_backlight_setup(struct sde_connector *c_conn,
struct dsi_backlight_config *bl_config;
static int display_count;
char bl_node_name[BL_NODE_NAME_SIZE];
int rc = 0;
if (!c_conn || !dev || !dev->dev) {
SDE_ERROR("invalid param\n");
@@ -149,7 +164,7 @@ static int sde_backlight_setup(struct sde_connector *c_conn,
display = (struct dsi_display *) c_conn->display;
bl_config = &display->panel->bl_config;
props.max_brightness = bl_config->brightness_max_level;
props.brightness = bl_config->brightness_max_level;
props.brightness = bl_config->brightness_init_level;
snprintf(bl_node_name, BL_NODE_NAME_SIZE, "panel%u-backlight",
display_count);
c_conn->bl_device = backlight_device_register(bl_node_name, dev->dev,
@@ -161,7 +176,15 @@ static int sde_backlight_setup(struct sde_connector *c_conn,
return -ENODEV;
}
display_count++;
rc = sde_backlight_clone_setup(c_conn, dev->dev, c_conn->bl_device);
if (rc) {
SDE_ERROR("Failed to register backlight_clone_cdev: %ld\n",
PTR_ERR(c_conn->cdev_clone));
backlight_clone_cdev_unregister(c_conn->cdev_clone);
backlight_device_unregister(c_conn->bl_device);
c_conn->bl_device = NULL;
return -ENODEV;
}
return 0;
}
@@ -547,6 +570,9 @@ static int _sde_connector_update_power_locked(struct sde_connector *c_conn)
SDE_DEBUG("conn %d - dpms %d, lp %d, panel %d\n", connector->base.id,
c_conn->dpms_mode, c_conn->lp_mode, mode);
if (SDE_MODE_DPMS_OFF == mode)
c_conn->fod_frame_count = 0;
if (mode != c_conn->last_panel_power_mode && c_conn->ops.set_power) {
display = c_conn->display;
set_power = c_conn->ops.set_power;
@@ -760,6 +786,347 @@ struct sde_connector_dyn_hdr_metadata *sde_connector_get_dyn_hdr_meta(
return &c_state->dyn_hdr_meta;
}
void sde_crtc_fod_ui_ready(struct dsi_display *display, int type, int value)
{
if (!display)
return;
if (type == 1) /* HBM */
{
if (value == 0)
display->panel->mi_cfg.fod_ui_ready &= ~0x01;
else if (value == 1)
display->panel->mi_cfg.fod_ui_ready |= 0x01;
}
if (type == 2) /* ICON */
{
if (display->panel->mi_cfg.local_hbm_enabled) {
if (value == 0)
display->panel->mi_cfg.fod_ui_ready &= ~0x07;
else if (value == 1) {
if (display->panel->mi_cfg.lhbm_target == LOCAL_LHBM_TARGET_BRIGHTNESS_WHITE_110NIT)
display->panel->mi_cfg.fod_ui_ready |= 0x07;
else if (display->panel->mi_cfg.lhbm_target == LOCAL_LHBM_TARGET_BRIGHTNESS_WHITE_1000NIT
|| display->panel->mi_cfg.lhbm_target == LOCAL_LHBM_TARGET_BRIGHTNESS_GREEN_500NIT)
display->panel->mi_cfg.fod_ui_ready |= 0x03;
}
} else {
if (value == 0)
display->panel->mi_cfg.fod_ui_ready &= ~0x02;
else if (value == 1)
display->panel->mi_cfg.fod_ui_ready |= 0x02;
}
}
SDE_INFO("fod_ui_ready notify=%d", display->panel->mi_cfg.fod_ui_ready);
sysfs_notify(&display->drm_conn->kdev->kobj, NULL, "fod_ui_ready");
}
int mi_sde_connector_gir_fence(struct drm_connector *connector)
{
int rc = 0;
struct sde_connector *c_conn;
struct dsi_display *dsi_display;
struct dsi_panel_mi_cfg *mi_cfg;
if (!connector) {
SDE_ERROR("invalid connector ptr\n");
return -EINVAL;
}
c_conn = to_sde_connector(connector);
if (c_conn->connector_type != DRM_MODE_CONNECTOR_DSI)
return 0;
dsi_display = (struct dsi_display *) c_conn->display;
if (!dsi_display || !dsi_display->panel) {
SDE_ERROR("invalid display/panel ptr\n");
return -EINVAL;
}
if (strncmp(dsi_display->display_type, "primary", 7))
return -EINVAL;
mi_cfg = &dsi_display->panel->mi_cfg;
mutex_lock(&dsi_display->panel->panel_lock);
if (mi_cfg->request_gir_status == true && mi_cfg->gir_enabled == false) {
SDE_ATRACE_BEGIN("DISP_FEATURE_GIR_ON");
SDE_INFO("mi-dsi-panel: gir on\n");
dsi_panel_tx_cmd_set(dsi_display->panel, DSI_CMD_SET_MI_GIR_ON);
sde_encoder_wait_for_event(c_conn->encoder,MSM_ENC_VBLANK);
SDE_ATRACE_END("DISP_FEATURE_GIR_ON");
mi_cfg->gir_enabled = true;
} else if (mi_cfg->request_gir_status == false && mi_cfg->gir_enabled == true) {
SDE_ATRACE_BEGIN("DISP_FEATURE_GIR_OFF");
SDE_INFO("mi-dsi-panel: gir off\n");
dsi_panel_tx_cmd_set(dsi_display->panel, DSI_CMD_SET_MI_GIR_OFF);
sde_encoder_wait_for_event(c_conn->encoder,MSM_ENC_VBLANK);
SDE_ATRACE_END("DISP_FEATURE_GIR_OFF");
mi_cfg->gir_enabled = false;
}
mutex_unlock(&dsi_display->panel->panel_lock);
return rc;
}
static int _sde_connector_mi_dimlayer_hbm_fence(struct drm_connector *connector)
{
int rc = 0;
struct sde_connector *c_conn;
struct dsi_display *dsi_display;
bool skip = false;
bool Prepare_Kickoff = false;
bool Ready_Kickoff = false;
static int skip_frame_count = 0;
bool hbm_overlay;
static bool last_fod_unlock_success;
static bool last_layer_aod_flag;
bool crc_off_after_delay_of_hbm_on = false;
struct dsi_panel_mi_cfg *mi_cfg;
bool anim;
static bool last_anim = false;
if (!connector) {
SDE_ERROR("invalid argument\n");
return -EINVAL;
}
c_conn = to_sde_connector(connector);
Prepare_Kickoff = get_sde_encoder_virt_prepare_kickoff(connector);
Ready_Kickoff = get_sde_encoder_virt_ready_kickoff(connector);
if (c_conn->connector_type != DRM_MODE_CONNECTOR_DSI)
return 0;
dsi_display = (struct dsi_display *) c_conn->display;
if (!dsi_display || !dsi_display->panel) {
SDE_ERROR("invalid display/panel\n");
return -EINVAL;
}
mi_cfg = &dsi_display->panel->mi_cfg;
if (!mi_cfg) {
SDE_ERROR("invalid mi_cfg\n");
return -EINVAL;
}
if (!c_conn->allow_bl_update) {
/*Skip 2 frames after panel on to avoid hbm flicker*/
if (mi_cfg->dc_type == 1 && dsi_display->panel->power_mode == SDE_MODE_DPMS_ON)
skip_frame_count = 2;
return 0;
}
if (skip_frame_count) {
SDE_INFO("skip_frame_count=%d\n", skip_frame_count);
skip_frame_count--;
return 0;
}
mi_cfg->layer_fod_unlock_success =
c_conn->mi_dimlayer_state.mi_dimlayer_type & MI_FOD_UNLOCK_SUCCESS;
if (last_fod_unlock_success != mi_cfg->layer_fod_unlock_success)
SDE_INFO("layer_fod_unlock_success = %d\n",
mi_cfg->layer_fod_unlock_success);
last_fod_unlock_success = mi_cfg->layer_fod_unlock_success;
mi_cfg->layer_aod_flag = c_conn->mi_dimlayer_state.mi_dimlayer_type & MI_DIMLAYER_AOD;
if (last_layer_aod_flag != mi_cfg->layer_aod_flag)
SDE_INFO("layer_aod_flag = %d\n", mi_cfg->layer_aod_flag);
last_layer_aod_flag = mi_cfg->layer_aod_flag;
hbm_overlay = c_conn->mi_dimlayer_state.mi_dimlayer_type & MI_DIMLAYER_FOD_HBM_OVERLAY;
if (hbm_overlay) {
/* TODO: mutex_lock(&panel->panel_lock); */
if (mi_cfg->fod_hbm_layer_enabled == false) {
/* in AOD, first frame should be skipped for hardware limitation */
if (mi_cfg->dc_type != 2 &&
(dsi_display->panel->power_mode == SDE_MODE_DPMS_LP1 ||
dsi_display->panel->power_mode == SDE_MODE_DPMS_LP2)) {
SDE_INFO("fod_frame_count=%d\n", c_conn->fod_frame_count);
if (c_conn->fod_frame_count == 0)
skip = true;
c_conn->fod_frame_count++;
} else {
c_conn->fod_frame_count = 0;
}
if (skip == false) {
/* dimming off before hbm ctl */
if (mi_cfg->prepare_before_fod_hbm_on && ((mi_cfg->panel_id >> 8) == 0x4A3232003808)) {
/* Set flags to disable dimming and backlight */
mi_cfg->dimming_state = STATE_DIM_BLOCK;
mi_cfg->fod_hbm_enabled = true;
sde_connector_pre_hbm_ctl(connector);
sde_encoder_wait_for_event(c_conn->encoder, MSM_ENC_VBLANK);
}
if (mi_cfg->delay_before_fod_hbm_on)
sde_encoder_wait_for_event(c_conn->encoder, MSM_ENC_VBLANK);
if (mi_cfg->fod_dimlayer_enabled)
sde_connector_hbm_ctl(connector, DISPPARAM_HBM_FOD_ON);
/* Send crc off cmd before delay only if DC off(MIUI-1755728) */
if (mi_cfg->dc_type == 2) {
if (!mi_cfg->dc_enable || (mi_cfg->dc_enable &&
mi_cfg->last_bl_level > mi_cfg->dc_threshold)) {
dsi_panel_acquire_panel_lock(dsi_display->panel);
rc = dsi_panel_tx_cmd_set(dsi_display->panel,
DSI_CMD_SET_MI_CRC_OFF);
dsi_panel_release_panel_lock(dsi_display->panel);
} else {
crc_off_after_delay_of_hbm_on = true;
}
}
if (mi_cfg->delay_after_fod_hbm_on) {
sde_encoder_wait_for_event(c_conn->encoder, MSM_ENC_VBLANK);
}
/* Turn off crc after delay of hbm on can avoid flash high
* brightness if DC on (MIUI-1755728) */
if (mi_cfg->dc_type == 2 && crc_off_after_delay_of_hbm_on) {
dsi_panel_acquire_panel_lock(dsi_display->panel);
rc = dsi_panel_tx_cmd_set(dsi_display->panel,
DSI_CMD_SET_MI_CRC_OFF);
dsi_panel_release_panel_lock(dsi_display->panel);
}
mi_cfg->fod_hbm_layer_enabled = true;
/*sde_crtc_fod_ui_ready(dsi_display, 1, 1);*/
}
}
} else {
if (mi_cfg->fod_hbm_layer_enabled == true) {
SDE_INFO("layer_fod_unlock_success = %d, sysfs_fod_unlock_success = %d\n",
mi_cfg->layer_fod_unlock_success,
mi_cfg->sysfs_fod_unlock_success);
if (mi_cfg->delay_before_fod_hbm_off)
sde_encoder_wait_for_event(c_conn->encoder, MSM_ENC_VBLANK);
sde_connector_hbm_ctl(connector, DISPPARAM_HBM_FOD_OFF);
if (mi_cfg->dc_type)
sysfs_notify(&c_conn->bl_device->dev.kobj, NULL, "brightness_clone");
if (mi_cfg->delay_after_fod_hbm_off)
sde_encoder_wait_for_event(c_conn->encoder, MSM_ENC_VBLANK);
mi_cfg->fod_hbm_layer_enabled = false;
/*sde_crtc_fod_ui_ready(dsi_display, 1, 0);*/
}
}
#if 0
icon = c_conn->mi_dimlayer_state.mi_dimlayer_type & MI_DIMLAYER_FOD_ICON;
if (last_icon != icon) {
if (icon) {
sde_crtc_fod_ui_ready(dsi_display, 2, 1);
} else {
if (last_icon)
sde_crtc_fod_ui_ready(dsi_display, 2, 0);
}
}
last_icon = icon;
#endif
//for l3a && j11
if (mi_cfg->panel_id == 0x4C334100420200 || mi_cfg->panel_id == 0x4A323200380801) {
if (!mi_cfg->layer_aod_flag) {
if (c_conn->lp_mode == SDE_MODE_DPMS_ON)
mi_cfg->bl_enable = true;
if (!mi_cfg->bl_wait_frame && c_conn->lp_mode == SDE_MODE_DPMS_ON) {
set_sde_encoder_virt_ready_kickoff(connector,true);
if (Prepare_Kickoff) {
SDE_ATRACE_BEGIN("set_backlight_after_aod");
mutex_lock(&dsi_display->panel->panel_lock);
dsi_panel_set_backlight(dsi_display->panel, dsi_display->panel->mi_cfg.last_bl_level);
mutex_unlock(&dsi_display->panel->panel_lock);
SDE_ATRACE_END("set_backlight_after_aod");
SDE_INFO("backlight %d set after aod layer\n", mi_cfg->last_bl_level);
mi_cfg->bl_wait_frame = true;
set_sde_encoder_virt_ready_kickoff(connector,false);
set_sde_encoder_virt_prepare_kickoff(connector,false);
}
} else
set_sde_encoder_virt_ready_kickoff(connector,false);
}
}
anim = c_conn->mi_dimlayer_state.mi_dimlayer_type & MI_LAYER_FOD_ANIM;
if (last_anim != anim) {
if (anim) {
mi_cfg->fod_anim_layer_enabled = true;
} else {
mi_cfg->fod_anim_layer_enabled = false;
}
}
last_anim = anim;
return rc;
}
void sde_connector_fod_notify(struct drm_connector *conn)
{
struct sde_connector *c_conn;
bool icon, hbm_state;
static bool last_icon = false;
static bool last_hbm_state = false;
struct dsi_display *dsi_display;
if (!conn) {
SDE_ERROR("invalid params\n");
return;
}
c_conn = to_sde_connector(conn);
if (c_conn->connector_type != DRM_MODE_CONNECTOR_DSI) {
SDE_ERROR("not DRM_MODE_CONNECTOR_DSIl\n");
return;
}
dsi_display = (struct dsi_display *) c_conn->display;
if (!dsi_display || !dsi_display->panel) {
SDE_ERROR("invalid display/panel\n");
return;
}
icon = c_conn->mi_dimlayer_state.mi_dimlayer_type & MI_DIMLAYER_FOD_ICON;
if (last_icon != icon) {
if (icon) {
/* Make sure icon was displayed on panel before notifying
* fingerprint to capture image */
if (dsi_display->panel->mi_cfg.fod_hbm_layer_enabled) {
sde_encoder_wait_for_event(c_conn->encoder,
MSM_ENC_TX_COMPLETE);
}
sde_crtc_fod_ui_ready(dsi_display, 2, 1);
} else {
sde_crtc_fod_ui_ready(dsi_display, 2, 0);
}
}
last_icon = icon;
hbm_state = dsi_display->panel->mi_cfg.fod_hbm_layer_enabled;
if (last_hbm_state != hbm_state) {
if (hbm_state) {
/* The black screen fingerprint unlocks, waits for HBM effect */
if (icon) {
sde_encoder_wait_for_event(c_conn->encoder,
MSM_ENC_TX_COMPLETE);
}
sde_crtc_fod_ui_ready(dsi_display, 1, 1);
} else {
sde_crtc_fod_ui_ready(dsi_display, 1, 0);
}
}
last_hbm_state = hbm_state;
}
int sde_connector_pre_kickoff(struct drm_connector *connector)
{
struct sde_connector *c_conn;
@@ -805,6 +1172,11 @@ int sde_connector_pre_kickoff(struct drm_connector *connector)
SDE_EVT32_VERBOSE(connector->base.id);
mi_sde_connector_gir_fence(connector);
/* fingerprint hbm fence */
_sde_connector_mi_dimlayer_hbm_fence(connector);
rc = c_conn->ops.pre_kickoff(connector, c_conn->display, &params);
if (c_conn->connector_type == DRM_MODE_CONNECTOR_DSI)
@@ -909,10 +1281,20 @@ void sde_connector_helper_bridge_enable(struct drm_connector *connector)
MSM_ENC_TX_COMPLETE);
c_conn->allow_bl_update = true;
if (display->panel->mi_cfg.pending_lhbm_state) {
mi_disp_set_fod_queue_work(1, false);
}
if (c_conn->bl_device) {
c_conn->bl_device->props.power = FB_BLANK_UNBLANK;
c_conn->bl_device->props.state &= ~BL_CORE_FBBLANK;
backlight_update_status(c_conn->bl_device);
if (!(display->panel->cur_mode->dsi_mode_flags & DSI_MODE_FLAG_DMS)
&& !(display->panel->cur_mode->dsi_mode_flags & DSI_MODE_FLAG_DMS_FPS)){
if(c_conn->bl_device->props.brightness != 0)
{
backlight_update_status(c_conn->bl_device);
}
}
}
c_conn->panel_dead = false;
}
@@ -966,7 +1348,8 @@ void sde_connector_destroy(struct drm_connector *connector)
drm_property_blob_put(c_conn->blob_mode_info);
if (c_conn->blob_ext_hdr)
drm_property_blob_put(c_conn->blob_ext_hdr);
if (c_conn->cdev_clone)
backlight_clone_cdev_unregister(c_conn->cdev_clone);
if (c_conn->bl_device)
backlight_device_unregister(c_conn->bl_device);
drm_connector_unregister(connector);
@@ -1452,11 +1835,13 @@ static int sde_connector_atomic_set_property(struct drm_connector *connector,
* atomic set property framework.
*/
case CONNECTOR_PROP_BL_SCALE:
c_conn->bl_scale = val;
//c_conn->bl_scale = val;
c_conn->bl_scale = MAX_BL_SCALE_LEVEL;
c_conn->bl_scale_dirty = true;
break;
case CONNECTOR_PROP_SV_BL_SCALE:
c_conn->bl_scale_sv = val;
//c_conn->bl_scale_sv = val;
c_conn->bl_scale_sv = MAX_SV_BL_SCALE_LEVEL;
c_conn->bl_scale_dirty = true;
break;
case CONNECTOR_PROP_HDR_METADATA:
@@ -2149,6 +2534,7 @@ static void _sde_connector_report_panel_dead(struct sde_connector *conn,
bool skip_pre_kickoff)
{
struct drm_event event;
struct dsi_display *display = (struct dsi_display *)(conn->display);
if (!conn)
return;
@@ -2162,6 +2548,7 @@ static void _sde_connector_report_panel_dead(struct sde_connector *conn,
return;
conn->panel_dead = true;
display->panel->mi_cfg.panel_dead_flag = true;
event.type = DRM_EVENT_PANEL_DEAD;
event.length = sizeof(bool);
msm_mode_object_event_notify(&conn->base.base,
@@ -2256,6 +2643,103 @@ 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;
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) &&
display->panel->host_config.cphy_strength) {
SDE_ERROR("trigger esd by mistake,return\n");
return IRQ_HANDLED;
}
if (c_conn->connector_type == DRM_MODE_CONNECTOR_DSI) {
dsi_panel_acquire_panel_lock(display->panel);
dsi_panel_esd_irq_ctrl_locked(display->panel, false);
if (!dsi_panel_initialized(display->panel)) {
SDE_ERROR("%s display panel not initialized!\n",
display->display_type);
dsi_panel_release_panel_lock(display->panel);
return IRQ_HANDLED;
}
if (atomic_read(&(display->panel->esd_recovery_pending))) {
DSI_INFO("%s display ESD recovery already pending\n",
display->display_type);
dsi_panel_release_panel_lock(display->panel);
return IRQ_HANDLED;
}
if (!c_conn->panel_dead) {
atomic_set(&display->panel->esd_recovery_pending, 1);
} else {
DSI_INFO("%s display already notify PANEL_DEAD\n",
display->display_type);
dsi_panel_release_panel_lock(display->panel);
return IRQ_HANDLED;
}
power_mode = display->panel->power_mode;
dsi_panel_release_panel_lock(display->panel);
if (power_mode == SDE_MODE_DPMS_ON ||
power_mode == SDE_MODE_DPMS_LP1) {
_sde_connector_report_panel_dead(c_conn, false);
} else {
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("%s display esd irq check failed report"
" PANEL_DEAD conn_id: %d enc_id: %d\n",
display->display_type,
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,
@@ -2709,6 +3193,8 @@ 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:
@@ -2807,3 +3293,107 @@ int sde_connector_event_notify(struct drm_connector *connector, uint32_t type,
return ret;
}
int sde_connector_hbm_ctl(struct drm_connector *connector, uint32_t op_code)
{
int ret = 0;
ret = dsi_display_hbm_set_disp_param(connector, op_code);
return ret;
}
int sde_connector_pre_hbm_ctl(struct drm_connector *connector)
{
int ret;
/* close dimming */
ret = dsi_display_hbm_set_disp_param(connector, DISPPARAM_HBM_BACKLIGHT_RESEND);
return ret;
}
#define to_dsi_bridge(x) container_of((x), struct dsi_bridge, base)
static uint32_t interpolate(uint32_t x, uint32_t xa, uint32_t xb, uint32_t ya, uint32_t yb)
{
uint32_t bf;
bf = ya - (ya - yb) * (x - xa) / (xb - xa);
return bf;
}
static uint32_t brightness_to_alpha(struct dsi_panel_mi_cfg *mi_cfg, uint32_t brightness)
{
int i;
int level = mi_cfg->brightnes_alpha_lut_item_count;
if (brightness == 0x0)
return mi_cfg->brightness_alpha_lut[0].alpha;
for (i = 0; i < level; i++){
if (mi_cfg->brightness_alpha_lut[i].brightness >= brightness)
break;
}
if (i == level)
return mi_cfg->brightness_alpha_lut[i - 1].alpha;
else
return interpolate(brightness,
mi_cfg->brightness_alpha_lut[i-1].brightness, mi_cfg->brightness_alpha_lut[i].brightness,
mi_cfg->brightness_alpha_lut[i-1].alpha, mi_cfg->brightness_alpha_lut[i].alpha);
}
void sde_connector_mi_get_current_alpha(struct drm_connector *connector, uint32_t brightness, uint32_t *alpha)
{
struct dsi_display *display = NULL;
struct dsi_bridge *c_bridge = NULL;
struct dsi_panel_mi_cfg *mi_cfg = NULL;
if (!connector || !connector->encoder || !connector->encoder->bridge) {
SDE_ERROR("Invalid connector/encoder/bridge ptr\n");
return;
}
c_bridge = to_dsi_bridge(connector->encoder->bridge);
display = c_bridge->display;
if (!display || !display->panel) {
SDE_ERROR("invalid display/panel ptr\n");
return;
}
mi_cfg = &display->panel->mi_cfg;
*alpha = brightness_to_alpha(mi_cfg, brightness);
return;
}
void sde_connector_mi_get_current_backlight(struct drm_connector *connector, uint32_t *brightness)
{
struct sde_connector *c_conn = to_sde_connector(connector);
struct dsi_display *display = NULL;
struct dsi_bridge *c_bridge = NULL;
if (!connector || !connector->encoder || !connector->encoder->bridge) {
SDE_ERROR("Invalid connector/encoder/bridge ptr\n");
return;
}
c_bridge = to_dsi_bridge(connector->encoder->bridge);
display = c_bridge->display;
if (!display || !display->panel) {
SDE_ERROR("invalid display/panel ptr\n");
return;
}
if (display->panel->mi_cfg.in_aod) {
*brightness = display->panel->mi_cfg.aod_backlight;
return;
}
*brightness = c_conn->mi_dimlayer_state.current_backlight;
}
void sde_connector_mi_update_dimlayer_state(struct drm_connector *connector,
enum mi_dimlayer_type mi_dimlayer_type)
{
struct sde_connector *c_conn = to_sde_connector(connector);
c_conn->mi_dimlayer_state.mi_dimlayer_type = mi_dimlayer_type;
}

View File

@@ -389,6 +389,22 @@ struct sde_connector_dyn_hdr_metadata {
bool dynamic_hdr_update;
};
enum mi_dimlayer_type {
MI_DIMLAYER_NULL = 0x0,
MI_DIMLAYER_FOD_HBM_OVERLAY = 0x1,
MI_DIMLAYER_FOD_ICON = 0x2,
MI_DIMLAYER_AOD = 0x4,
MI_LAYER_FOD_ANIM = 0x8,
MI_FOD_UNLOCK_SUCCESS = 0x10,
MI_DIMLAYER_MAX,
};
struct mi_dimlayer_state
{
enum mi_dimlayer_type mi_dimlayer_type;
uint32_t current_backlight;
};
/**
* struct sde_connector - local sde connector structure
* @base: Base drm connector structure
@@ -468,6 +484,7 @@ struct sde_connector {
spinlock_t event_lock;
struct backlight_device *bl_device;
struct sde_clone_cdev *cdev_clone;
struct delayed_work status_work;
u32 esd_status_interval;
bool panel_dead;
@@ -486,6 +503,9 @@ struct sde_connector {
bool last_cmd_tx_sts;
bool hdr_capable;
struct mi_dimlayer_state mi_dimlayer_state;
u32 fod_frame_count;
};
/**
@@ -971,4 +991,22 @@ int sde_connector_get_panel_vfp(struct drm_connector *connector,
*/
int sde_connector_esd_status(struct drm_connector *connector);
/**
* sde_connector_hbm_ctl - mi function to control hbm
* @connector: Pointer to DRM connector object
* @op_code: hbm operation code
*/
int sde_connector_hbm_ctl(struct drm_connector *connector, uint32_t op_code);
int sde_connector_pre_hbm_ctl(struct drm_connector *connector);
void sde_connector_mi_update_dimlayer_state(struct drm_connector *connector,
enum mi_dimlayer_type mi_dimlayer_type);
void sde_connector_mi_get_current_backlight(struct drm_connector *connector, uint32_t *brightness);
void sde_connector_mi_get_current_alpha(struct drm_connector *connector, uint32_t brightness, uint32_t *alpha);
void sde_connector_fod_notify(struct drm_connector *connector);
#endif /* _SDE_CONNECTOR_H_ */

View File

@@ -2161,12 +2161,12 @@ static void sde_crtc_frame_event_cb(void *data, u32 event)
SDE_DEBUG("crtc%d\n", crtc->base.id);
SDE_EVT32_VERBOSE(DRMID(crtc), event);
spin_lock_irqsave(&sde_crtc->spin_lock, flags);
spin_lock_irqsave(&sde_crtc->fevent_spin_lock, flags);
fevent = list_first_entry_or_null(&sde_crtc->frame_event_list,
struct sde_crtc_frame_event, list);
if (fevent)
list_del_init(&fevent->list);
spin_unlock_irqrestore(&sde_crtc->spin_lock, flags);
spin_unlock_irqrestore(&sde_crtc->fevent_spin_lock, flags);
if (!fevent) {
SDE_ERROR("crtc%d event %d overflow\n",
@@ -2206,6 +2206,14 @@ static void sde_crtc_frame_event_cb(void *data, u32 event)
kthread_queue_work(&priv->event_thread[crtc_id].worker, &fevent->work);
}
static void _sde_crtc_mi_update_state(struct sde_crtc_state *cstate, enum mi_dimlayer_type dimlayer_state)
{
int i = 0;
for (i = 0; i < cstate->num_connectors; i++)
sde_connector_mi_update_dimlayer_state(cstate->connectors[i], dimlayer_state);
}
void sde_crtc_prepare_commit(struct drm_crtc *crtc,
struct drm_crtc_state *old_state)
{
@@ -2447,9 +2455,9 @@ static void sde_crtc_frame_event_work(struct kthread_work *work)
SDE_ERROR("crtc%d ts:%lld received panel dead event\n",
crtc->base.id, ktime_to_ns(fevent->ts));
spin_lock_irqsave(&sde_crtc->spin_lock, flags);
spin_lock_irqsave(&sde_crtc->fevent_spin_lock, flags);
list_add_tail(&fevent->list, &sde_crtc->frame_event_list);
spin_unlock_irqrestore(&sde_crtc->spin_lock, flags);
spin_unlock_irqrestore(&sde_crtc->fevent_spin_lock, flags);
SDE_ATRACE_END("crtc_frame_event");
}
@@ -2498,6 +2506,7 @@ void _sde_crtc_clear_dim_layers_v1(struct drm_crtc_state *state)
memset(&cstate->dim_layer[i], 0, sizeof(cstate->dim_layer[i]));
cstate->num_dim_layers = 0;
cstate->num_dim_layers_bank = 0;
}
/**
@@ -2546,6 +2555,7 @@ static void _sde_crtc_set_dim_layer_v1(struct drm_crtc *crtc,
/* populate from user space */
cstate->num_dim_layers = count;
cstate->num_dim_layers_bank = count;
for (i = 0; i < count; i++) {
user_cfg = &dim_layer_v1.layer_cfg[i];
@@ -3158,6 +3168,8 @@ static void sde_crtc_atomic_begin(struct drm_crtc *crtc,
struct sde_splash_display *splash_display;
bool cont_splash_enabled = false;
size_t i;
uint32_t fod_sync_info;
struct sde_crtc_state *cstate;
if (!crtc) {
SDE_ERROR("invalid crtc\n");
@@ -3235,8 +3247,14 @@ static void sde_crtc_atomic_begin(struct drm_crtc *crtc,
}
if (sde_kms_is_cp_operation_allowed(sde_kms) &&
(cont_splash_enabled || sde_crtc->enabled))
(cont_splash_enabled || sde_crtc->enabled)) {
cstate = to_sde_crtc_state(crtc->state);
fod_sync_info = sde_crtc_get_mi_fod_sync_info(cstate);
sde_crtc->mi_dimlayer_type = fod_sync_info;
sde_cp_crtc_apply_properties(crtc);
}
/*
* PP_DONE irq is only used by command mode for now.
@@ -3588,6 +3606,7 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc,
unsigned long flags;
enum sde_crtc_idle_pc_state idle_pc_state;
struct sde_encoder_kickoff_params params = { 0 };
uint32_t fod_sync_info;
if (!crtc) {
SDE_ERROR("invalid argument\n");
@@ -3617,6 +3636,9 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc,
idle_pc_state = sde_crtc_get_property(cstate, CRTC_PROP_IDLE_PC_STATE);
fod_sync_info = sde_crtc_get_mi_fod_sync_info(cstate);
_sde_crtc_mi_update_state(cstate, fod_sync_info);
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
if (encoder->crtc != crtc)
continue;
@@ -4921,6 +4943,157 @@ static int sde_crtc_atomic_check(struct drm_crtc *crtc,
return rc;
}
static uint32_t get_current_brightness(struct sde_crtc_state *cstate)
{
int i;
uint32_t brightness;
for (i = 0; i < cstate->num_connectors; i++) {
sde_connector_mi_get_current_backlight(cstate->connectors[i], &brightness);
}
return brightness;
}
static uint32_t get_current_alpha(struct sde_crtc_state *cstate, uint32_t brightness)
{
int i;
uint32_t alpha;
for (i = 0; i < cstate->num_connectors; i++) {
sde_connector_mi_get_current_alpha(cstate->connectors[i], brightness, &alpha);
}
return alpha;
}
static uint32_t _sde_crtc_config_mi_dim_layer_lapha(struct sde_crtc_state *cstate)
{
uint32_t alpha, current_brightness;
current_brightness = get_current_brightness(cstate);
if(cstate->mi_state.dimlayer_backlight_stash == current_brightness)
return cstate->mi_state.dimlayer_alpha_stash;
alpha = get_current_alpha(cstate, current_brightness) & 0x000000FF;
cstate->mi_state.dimlayer_backlight_stash = current_brightness;
cstate->mi_state.dimlayer_alpha_stash = alpha;
return alpha;
}
void _sde_crtc_config_mi_dim_layer(struct sde_crtc *sde_crtc, struct sde_crtc_state *cstate,
struct drm_crtc_state *drm_state, uint32_t dim_layer_stage)
{
uint32_t alpha;
struct sde_hw_mixer *lm;
struct sde_crtc_mixer *mixer;
struct drm_display_mode *display_mode = &drm_state->adjusted_mode;
alpha = _sde_crtc_config_mi_dim_layer_lapha(cstate);
mixer = sde_crtc->mixers;
lm = mixer->hw_lm;
cstate->mi_state.mi_dim_layer = cstate->dim_layer;
if (lm && lm->ops.setup_dim_layer) {
if (cstate->num_dim_layers_bank <= SDE_MAX_DIM_LAYERS) {
cstate->dim_layer[cstate->num_dim_layers_bank].flags = SDE_DRM_DIM_LAYER_INCLUSIVE;
cstate->dim_layer[cstate->num_dim_layers_bank].stage = dim_layer_stage + SDE_STAGE_0;
cstate->dim_layer[cstate->num_dim_layers_bank].rect.x = 0x0;
cstate->dim_layer[cstate->num_dim_layers_bank].rect.y = 0x0;
cstate->dim_layer[cstate->num_dim_layers_bank].rect.w = display_mode->hdisplay;
cstate->dim_layer[cstate->num_dim_layers_bank].rect.h = display_mode->vdisplay;
cstate->dim_layer[cstate->num_dim_layers_bank].color_fill = (struct sde_mdss_color) {0x0, 0x0, 0x0, alpha};
cstate->num_dim_layers = cstate->num_dim_layers_bank + 1;
_sde_crtc_mi_update_state(cstate, MI_DIMLAYER_FOD_ICON);
} else {
SDE_ERROR("invalid number of dim_layers:%d", cstate->num_dim_layers);
}
}
}
int sde_crtc_mi_atomic_check(struct sde_crtc *sde_crtc, struct sde_crtc_state *cstate,
void *pstates, int cnt)
{
uint32_t i;
uint32_t mi_plane;
uint32_t dim_layer_stage = 0x0;
uint32_t mi_aodlayer_index = 0x0;
uint32_t mi_iconlayer_index = 0x0;
uint32_t mi_pressed_Iconlayer_index = 0x0;
bool mi_dimlayer_switch_enable = true;
int max_stage = 0;
struct plane_state *pstates_ = (struct plane_state *)pstates;
/* dimlayer switch for FOD and DC function */
if (!mi_dimlayer_switch_enable)
return 0;
for (i = 0; i < cnt; i++) {
mi_plane = sde_plane_get_mi_layer_info(pstates_[i].drm_pstate);
switch (mi_plane) {
case MI_LAYER_FOD_HBM_OVERLAY:
mi_pressed_Iconlayer_index = i;
break;
case MI_LAYER_FOD_ICON:
mi_iconlayer_index = i;
break;
case MI_LAYER_AOD:
mi_aodlayer_index = i;
break;
default:
break;
}
}
/* Create mi dim layer under index layer */
if (mi_pressed_Iconlayer_index > 0) {
dim_layer_stage = pstates_[mi_pressed_Iconlayer_index].stage;
for (i = 0; i < cnt; i++) {
if (pstates_[i].stage >= dim_layer_stage) {
pstates_[i].stage++;
pstates_[i].sde_pstate->stage++;
if (pstates_[i].stage > max_stage)
max_stage = pstates_[i].stage;
}
}
/* do not use same stage */
for (i = 0; i < cstate->num_dim_layers; i++) {
if (cstate->dim_layer[i].stage >= dim_layer_stage &&
cstate->dim_layer[i].stage <= max_stage)
cstate->dim_layer[i].stage++;
}
} else if ((mi_iconlayer_index > 0)) {
for (i = 0; i < cnt; i++) {
if (pstates_[i].stage > dim_layer_stage)
dim_layer_stage = pstates_[i].stage;
}
/* do not use same stage */
for (i = 0; i < cstate->num_dim_layers; i++) {
if (cstate->dim_layer[i].stage > dim_layer_stage )
cstate->dim_layer[i].stage = dim_layer_stage++;
}
dim_layer_stage++;
}
if (dim_layer_stage > SDE_STAGE_MAX - SDE_STAGE_0) {
SDE_ERROR(" > %d plane stages assigned\n", SDE_STAGE_MAX - SDE_STAGE_0);
return 0;
}
if (dim_layer_stage > 0x0 && cstate->mi_state.mi_dim_layer == NULL) {
SDE_ATRACE_BEGIN("dimlayer_show");
_sde_crtc_config_mi_dim_layer(sde_crtc, cstate, &cstate->base, dim_layer_stage);
SDE_ATRACE_END("dimlayer_show");
} else {
cstate->mi_state.mi_dim_layer = NULL;
_sde_crtc_mi_update_state(cstate, MI_DIMLAYER_NULL);
}
return 0;
}
/**
* sde_crtc_get_num_datapath - get the number of datapath active
* of primary connector
@@ -5072,6 +5245,10 @@ static void sde_crtc_install_properties(struct drm_crtc *crtc,
return;
}
/* mi properties */
msm_property_install_range(&sde_crtc->property_info, "mi_fod_sync_info",
0x0, 0, U32_MAX, 0, CRTC_PROP_MI_FOD_SYNC_INFO);
/* range properties */
msm_property_install_range(&sde_crtc->property_info,
"input_fence_timeout", 0x0, 0, SDE_CRTC_MAX_INPUT_FENCE_TIMEOUT,
@@ -6283,6 +6460,7 @@ struct drm_crtc *sde_crtc_init(struct drm_device *dev, struct drm_plane *plane)
mutex_init(&sde_crtc->crtc_lock);
spin_lock_init(&sde_crtc->spin_lock);
spin_lock_init(&sde_crtc->fevent_spin_lock);
atomic_set(&sde_crtc->frame_pending, 0);
mutex_init(&sde_crtc->vblank_modeset_ctrl_lock);
@@ -6618,3 +6796,11 @@ void sde_crtc_update_cont_splash_settings(struct drm_crtc *crtc)
rate : kms->perf.max_core_clk_rate;
sde_crtc->cur_perf.core_clk_rate = kms->perf.max_core_clk_rate;
}
uint32_t sde_crtc_get_mi_fod_sync_info(struct sde_crtc_state *cstate)
{
if (!cstate)
return 0;
return sde_crtc_get_property(cstate, CRTC_PROP_MI_FOD_SYNC_INFO);
}

View File

@@ -340,6 +340,7 @@ struct sde_crtc {
struct sde_crtc_frame_event frame_events[SDE_CRTC_FRAME_EVENT_SIZE];
struct list_head frame_event_list;
spinlock_t spin_lock;
spinlock_t fevent_spin_lock;
/* for handling internal event thread */
struct sde_crtc_event event_cache[SDE_CRTC_MAX_EVENT_COUNT];
@@ -373,14 +374,60 @@ struct sde_crtc {
struct mutex ltm_buffer_lock;
spinlock_t ltm_lock;
bool needs_hw_reset;
int hist_irq_idx;
int comp_ratio;
uint32_t mi_dimlayer_type;
struct drm_property_blob *dspp_blob_info;
};
#define to_sde_crtc(x) container_of(x, struct sde_crtc, base)
/**
* enum sde_crtc_mi_layer_type: type of mi layer
* @MI_LAYER_FOD_PRESSED_ICON: FOD touched icon layer
* @MI_LAYER_FOD_ICON: FOD untouch icon layer
* @MI_LAYER_AOD: AOD layer
*/
enum sde_crtc_mi_layer_type {
MI_LAYER_NULL = 0x0,
MI_LAYER_FOD_HBM_OVERLAY = 0x1,
MI_LAYER_FOD_ICON = 0x2,
MI_LAYER_AOD = 0x4,
MI_LAYER_MAX,
};
/**
* sde_crtc_mi_dc_backlight - mi dc backlight
* @mi_dc_bl_state: dc backlihgt state
* @mi_dc_backlight_level: last backlight stash
* @mi_dc_layer_alpha: dc dim layer alpha
*/
typedef struct sde_crtc_mi_dc_backlight
{
uint8_t mi_dc_bl_state;
int32_t mi_dc_bl_level;
int32_t mi_dc_bl_layer_alpha;
} sde_crtc_mi_dc_backlight;
typedef struct sde_crtc_mi_layer
{
int32_t layer_index;
enum sde_crtc_mi_layer_type last_state;
} sde_crtc_mi_layer;
/**
* sde_crtc_mi_state - mi crtc state
* @mi_dim_layer: dim layer added by Mi
*/
struct sde_crtc_mi_state {
struct sde_hw_dim_layer *mi_dim_layer;
struct sde_crtc_mi_layer mi_layer;
uint32_t dimlayer_backlight_stash;
uint8_t dimlayer_alpha_stash;
};
/**
* struct sde_crtc_state - sde container for atomic crtc state
* @base: Base drm crtc state structure
@@ -438,6 +485,10 @@ struct sde_crtc_state {
struct sde_hw_scaler3_lut_cfg scl3_lut_cfg;
struct sde_core_perf_params new_perf;
/* Mi crtc state */
struct sde_crtc_mi_state mi_state;
uint32_t num_dim_layers_bank;
int secure_session;
};
@@ -860,6 +911,25 @@ void sde_crtc_misr_setup(struct drm_crtc *crtc, bool enable, u32 frame_count);
void sde_crtc_get_misr_info(struct drm_crtc *crtc,
struct sde_crtc_misr_info *crtc_misr_info);
/**
* sde_crtc_mi_atomic_check - to do crtc mi atomic check
* @crtc: Pointer to sde crtc state structure
* @cstate: Pointer to sde crtc state structure
* @pstates: Pointer to sde plane state structure
* @cnt: plane refence count
*/
int sde_crtc_mi_atomic_check(struct sde_crtc *sde_crtc, struct sde_crtc_state *cstate,
void *pstates, int cnt);
/**
* sde_crtc_mi_atomic_check - to do crtc mi atomic check
* @crtc: Pointer to sde crtc state structure
* @cstate: Pointer to sde crtc state structure
* @pstates: Pointer to sde plane state structure
* @cnt: plane refence count
*/
uint32_t sde_crtc_get_mi_fod_sync_info(struct sde_crtc_state *cstate);
/**
* sde_crtc_get_num_datapath - get the number of datapath active
* of primary connector

View File

@@ -40,6 +40,9 @@
#include "sde_core_irq.h"
#include "sde_hw_top.h"
#include "sde_hw_qdss.h"
#include "dsi_display.h"
#include "dsi_panel_mi.h"
#include "dsi_drm.h"
#define SDE_DEBUG_ENC(e, fmt, ...) SDE_DEBUG("enc%d " fmt,\
(e) ? (e)->base.base.id : -1, ##__VA_ARGS__)
@@ -283,6 +286,7 @@ struct sde_encoder_virt {
struct kthread_delayed_work delayed_off_work;
struct kthread_work vsync_event_work;
struct kthread_work input_event_work;
struct kthread_work touch_notify_work;
struct kthread_work esd_trigger_work;
struct input_handler *input_handler;
struct msm_display_topology topology;
@@ -300,10 +304,45 @@ struct sde_encoder_virt {
bool elevated_ahb_vote;
struct pm_qos_request pm_qos_cpu_req;
struct msm_mode_info mode_info;
bool prepare_kickoff;
bool ready_kickoff;
};
#define to_sde_encoder_virt(x) container_of(x, struct sde_encoder_virt, base)
bool get_sde_encoder_virt_prepare_kickoff(struct drm_connector *connector)
{
struct sde_encoder_virt *sde_enc;
sde_enc = to_sde_encoder_virt(connector->encoder);
return sde_enc->prepare_kickoff;
}
bool get_sde_encoder_virt_ready_kickoff(struct drm_connector *connector)
{
struct sde_encoder_virt *sde_enc;
sde_enc = to_sde_encoder_virt(connector->encoder);
return sde_enc->ready_kickoff;
}
void set_sde_encoder_virt_prepare_kickoff(struct drm_connector *connector,bool enable)
{
struct sde_encoder_virt *sde_enc;
sde_enc = to_sde_encoder_virt(connector->encoder);
sde_enc->prepare_kickoff = enable;
}
void set_sde_encoder_virt_ready_kickoff(struct drm_connector *connector,bool enable)
{
struct sde_encoder_virt *sde_enc;
sde_enc = to_sde_encoder_virt(connector->encoder);
sde_enc->ready_kickoff = enable;
}
void sde_encoder_uidle_enable(struct drm_encoder *drm_enc, bool enable)
{
struct sde_encoder_virt *sde_enc;
@@ -2336,9 +2375,13 @@ static void sde_encoder_input_event_handler(struct input_handle *handle,
SDE_EVT32_VERBOSE(DRMID(drm_enc));
disp_thread = &priv->disp_thread[sde_enc->crtc->index];
kthread_queue_work(&disp_thread->worker,
&sde_enc->input_event_work);
&sde_enc->touch_notify_work);
/* Only consider EV_ABS (touch) events in QC original design */
if (type == EV_ABS && sde_encoder_check_curr_mode(drm_enc, MSM_DISPLAY_CMD_MODE))
kthread_queue_work(&disp_thread->worker,
&sde_enc->input_event_work);
}
void sde_encoder_control_idle_pc(struct drm_encoder *drm_enc, bool enable)
@@ -3175,6 +3218,10 @@ static const struct input_device_id sde_input_ids[] = {
BIT_MASK(ABS_MT_POSITION_X) |
BIT_MASK(ABS_MT_POSITION_Y) },
},
{
.flags = INPUT_DEVICE_ID_MATCH_EVBIT,
.evbit = { BIT_MASK(EV_KEY) },
},
{ },
};
@@ -3184,8 +3231,10 @@ static void _sde_encoder_input_handler_register(
struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
int rc;
#if 0
if (!sde_encoder_check_curr_mode(drm_enc, MSM_DISPLAY_CMD_MODE))
return;
#endif
if (sde_enc->input_handler && !sde_enc->input_handler->private) {
sde_enc->input_handler->private = sde_enc;
@@ -3205,8 +3254,10 @@ static void _sde_encoder_input_handler_unregister(
{
struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
#if 0
if (!sde_encoder_check_curr_mode(drm_enc, MSM_DISPLAY_CMD_MODE))
return;
#endif
if (sde_enc->input_handler && sde_enc->input_handler->private) {
input_unregister_handler(sde_enc->input_handler);
@@ -4477,11 +4528,29 @@ static void _sde_encoder_setup_dither(struct sde_encoder_phys *phys)
struct msm_display_dsc_info *dsc = NULL;
struct sde_encoder_virt *sde_enc;
struct sde_hw_pingpong *hw_pp;
struct dsi_display *dsi_display;
struct sde_connector *c_conn;
struct dsi_panel_mi_cfg *mi_cfg;
if (!phys || !phys->connector || !phys->hw_pp ||
!phys->hw_pp->ops.setup_dither || !phys->parent)
return;
c_conn = to_sde_connector(phys->connector);
if (c_conn->connector_type == DRM_MODE_CONNECTOR_DSI) {
dsi_display = (struct dsi_display *) c_conn->display;
if (!dsi_display || !dsi_display->panel) {
SDE_ERROR("invalid display/panel\n");
return;
}
mi_cfg = &dsi_display->panel->mi_cfg;
if (!mi_cfg->dither_enabled) {
SDE_DEBUG("dither_enabled = %d\n", mi_cfg->dither_enabled);
return;
}
}
topology = sde_connector_get_topology_name(phys->connector);
if ((topology == SDE_RM_TOPOLOGY_PPSPLIT) &&
(phys->split_role == ENC_ROLE_SLAVE))
@@ -4639,6 +4708,26 @@ static void sde_encoder_input_event_work_handler(struct kthread_work *work)
SDE_ENC_RC_EVENT_EARLY_WAKEUP);
}
static void sde_encoder_touch_notify_work_handler(struct kthread_work *work)
{
struct dsi_bridge *c_bridge = NULL;
struct dsi_display *dsi_display = NULL;
struct drm_encoder *drm_enc = NULL;
struct sde_encoder_virt *sde_enc = container_of(work,
struct sde_encoder_virt, touch_notify_work);
if (!sde_enc) {
SDE_ERROR("invalid encoder for the touch notify\n");
return;
}
drm_enc = &sde_enc->base;
c_bridge = container_of(drm_enc->bridge, struct dsi_bridge, base);
if (c_bridge)
dsi_display = c_bridge->display;
}
static void sde_encoder_vsync_event_work_handler(struct kthread_work *work)
{
struct sde_encoder_virt *sde_enc = container_of(work,
@@ -4976,6 +5065,9 @@ int sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc,
sde_enc->cur_master, sde_kms->qdss_enabled);
end:
if (sde_enc->ready_kickoff) {
sde_enc->prepare_kickoff = true;
}
SDE_ATRACE_END("sde_encoder_prepare_for_kickoff");
return ret;
}
@@ -5023,8 +5115,13 @@ void sde_encoder_kickoff(struct drm_encoder *drm_enc, bool is_error)
{
struct sde_encoder_virt *sde_enc;
struct sde_encoder_phys *phys;
struct dsi_bridge *bridge = NULL;
struct dsi_display *dsi_display = NULL;
struct dsi_display_mode adj_mode;
ktime_t wakeup_time;
unsigned int i;
struct sde_kms *sde_kms = NULL;
struct msm_drm_private *priv = NULL;
if (!drm_enc) {
SDE_ERROR("invalid encoder\n");
@@ -5039,6 +5136,20 @@ void sde_encoder_kickoff(struct drm_encoder *drm_enc, bool is_error)
if (is_error)
_sde_encoder_reset_ctl_hw(drm_enc);
if (sde_enc->disp_info.intf_type == DRM_MODE_CONNECTOR_DSI
&& drm_enc->bridge)
bridge = container_of(drm_enc->bridge, struct dsi_bridge, base);
if (bridge) {
adj_mode = bridge->dsi_mode;
dsi_display = bridge->display;
if (dsi_display && dsi_display->panel
&& (dsi_display->panel->host_config.phy_type == DSI_PHY_TYPE_CPHY || dsi_display->panel->mi_cfg.panel_id == 0x4C38314100420400)
&& adj_mode.dsi_mode_flags & DSI_MODE_FLAG_VRR) {
mutex_lock(&dsi_display->panel->panel_lock);
sde_encoder_vid_wait_for_active(drm_enc);
}
}
/* All phys encs are ready to go, trigger the kickoff */
_sde_encoder_kickoff_phys(sde_enc);
@@ -5056,6 +5167,19 @@ void sde_encoder_kickoff(struct drm_encoder *drm_enc, bool is_error)
nsecs_to_jiffies(ktime_to_ns(wakeup_time)));
}
if (dsi_display && dsi_display->panel
&& (dsi_display->panel->host_config.phy_type == DSI_PHY_TYPE_CPHY || dsi_display->panel->mi_cfg.panel_id == 0x4C38314100420400)
&& adj_mode.dsi_mode_flags & DSI_MODE_FLAG_VRR) {
dsi_panel_match_fps_pen_setting(dsi_display->panel, &adj_mode);
mutex_unlock(&dsi_display->panel->panel_lock);
}
priv = sde_enc->base.dev->dev_private;
if (priv != NULL) {
sde_kms = to_sde_kms(priv->kms);
sde_kms_kickoff_count(sde_kms);
}
SDE_ATRACE_END("encoder_kickoff");
}
@@ -5815,7 +5939,7 @@ struct drm_encoder *sde_encoder_init_with_ops(
sde_enc->rsc_client = NULL;
}
if (disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) {
if (disp_info->capabilities & (MSM_DISPLAY_CAP_CMD_MODE | MSM_DISPLAY_CAP_VID_MODE)) {
ret = _sde_encoder_input_handler(sde_enc);
if (ret)
SDE_ERROR(
@@ -5834,6 +5958,9 @@ struct drm_encoder *sde_encoder_init_with_ops(
kthread_init_work(&sde_enc->input_event_work,
sde_encoder_input_event_work_handler);
kthread_init_work(&sde_enc->touch_notify_work,
sde_encoder_touch_notify_work_handler);
kthread_init_work(&sde_enc->esd_trigger_work,
sde_encoder_esd_trigger_work_handler);
@@ -5858,6 +5985,37 @@ struct drm_encoder *sde_encoder_init(
return sde_encoder_init_with_ops(dev, disp_info, NULL);
}
int sde_encoder_vid_wait_for_active(
struct drm_encoder *drm_enc)
{
struct drm_display_mode mode;
struct sde_encoder_virt *sde_enc = NULL;
u32 ln_cnt, min_ln_cnt, active_mark_region;
u32 i, retry = 15;
if (!drm_enc) {
SDE_ERROR("invalid encoder\n");
return -EINVAL;
}
sde_enc = to_sde_encoder_virt(drm_enc);
for (i = 0; i < sde_enc->num_phys_encs; i++) {
struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
if (!phys || (phys->ops.is_master && !phys->ops.is_master(phys)))
continue;
mode = phys->cached_mode;
min_ln_cnt = (mode.vtotal - mode.vsync_start) +
(mode.vsync_end - mode.vsync_start);
active_mark_region = mode.vdisplay + min_ln_cnt - mode.vdisplay / 4;
while (retry) {
ln_cnt = phys->ops.get_line_count(phys);
if ((ln_cnt > min_ln_cnt) && (ln_cnt < active_mark_region))
return 0;
udelay(2000);
retry--;
}
}
return -EINVAL;
}
int sde_encoder_wait_for_event(struct drm_encoder *drm_enc,
enum msm_event_wait event)
{

View File

@@ -372,6 +372,13 @@ void sde_encoder_needs_hw_reset(struct drm_encoder *enc);
*/
void sde_encoder_uidle_enable(struct drm_encoder *drm_enc, bool enable);
/**
* sde_encoder_vid_wait_for_active - wait Vactive region for some mark region
* @drm_enc: Pointer to drm encoder structure
* @Return: non zero value if wait timeout occurred
*/
int sde_encoder_vid_wait_for_active(struct drm_encoder *enc);
/**
* sde_encoder_virt_reset - delay encoder virt reset
* @drm_enc: Pointer to drm encoder structure
@@ -399,4 +406,12 @@ static inline struct sde_kms *sde_encoder_get_kms(struct drm_encoder *drm_enc)
return to_sde_kms(priv->kms);
}
bool get_sde_encoder_virt_prepare_kickoff(struct drm_connector *connector);
bool get_sde_encoder_virt_ready_kickoff(struct drm_connector *connector);
void set_sde_encoder_virt_prepare_kickoff(struct drm_connector *connector,bool enable);
void set_sde_encoder_virt_ready_kickoff(struct drm_connector *connector,bool enable);
#endif /* __SDE_ENCODER_H__ */

View File

@@ -222,7 +222,11 @@ void sde_setup_dspp_pccv4(struct sde_hw_dspp *ctx, void *cfg)
return;
}
pcc_cfg = hw_cfg->payload;
if (hw_cfg->payload_clear) {
pcc_cfg = hw_cfg->payload_clear;
} else {
pcc_cfg = hw_cfg->payload;
}
for (i = 0; i < PCC_NUM_PLANES; i++) {
base = ctx->cap->sblk->pcc.base + (i * sizeof(u32));

View File

@@ -688,7 +688,11 @@ void sde_setup_dspp_pcc_v1_7(struct sde_hw_dspp *ctx, void *cfg)
return;
}
DRM_DEBUG_DRIVER("Enable PCC feature\n");
pcc = hw_cfg->payload;
if (hw_cfg->payload_clear) {
pcc = hw_cfg->payload_clear;
} else {
pcc = hw_cfg->payload;
}
SDE_REG_WRITE(&ctx->hw, ctx->cap->sblk->pcc.base + PCC_CONST_COEFF_OFF,
pcc->r.c & PCC_CONST_COEFF_MASK);
@@ -951,17 +955,17 @@ void sde_read_dspp_hist_v1_7(struct sde_hw_dspp *ctx, void *cfg)
void sde_lock_dspp_hist_v1_7(struct sde_hw_dspp *ctx, void *cfg)
{
u32 offset_ctl;
u32 offset_ctl, val;
if (!ctx) {
if (!ctx || !cfg) {
DRM_ERROR("invalid parameters ctx %pK", ctx);
return;
}
offset_ctl = ctx->cap->sblk->hist.base + PA_HIST_CTRL_DSPP_OFF;
/* lock hist buffer */
SDE_REG_WRITE(&ctx->hw, offset_ctl, 1);
val = (*(u32 *)cfg) & 0x1;
SDE_REG_WRITE(&ctx->hw, offset_ctl, val);
}
void sde_setup_dspp_dither_v1_7(struct sde_hw_dspp *ctx, void *cfg)

View File

@@ -552,6 +552,8 @@ struct sde_hw_cp_cfg {
u32 displayh;
struct sde_hw_dspp *dspp[DSPP_MAX];
bool broadcast_disabled;
u32 mi_dimlayer_type;
void *payload_clear;
};
/**

View File

@@ -1278,7 +1278,12 @@ void reg_dmav1_setup_dspp_pccv4(struct sde_hw_dspp *ctx, void *cfg)
return;
}
pcc_cfg = hw_cfg->payload;
if (hw_cfg->payload_clear) {
pcc_cfg = hw_cfg->payload_clear;
} else {
pcc_cfg = hw_cfg->payload;
}
dma_ops = sde_reg_dma_get_ops();
dma_ops->reset_reg_dma_buf(dspp_buf[PCC][ctx->idx]);

View File

@@ -50,6 +50,8 @@
#define MDP_WD_TIMER_4_CTL2 0x444
#define MDP_WD_TIMER_4_LOAD_VALUE 0x448
#define LTM_SW_FUSE_OFFSET 0x10
#define MDP_TICK_COUNT 16
#define XO_CLK_RATE 19200
#define MS_TICKS_IN_SEC 1000
@@ -649,3 +651,33 @@ void sde_hw_mdp_destroy(struct sde_hw_mdp *mdp)
kfree(mdp);
}
struct sde_hw_sw_fuse *sde_hw_sw_fuse_init(void __iomem *addr,
u32 sw_fuse_len, const struct sde_mdss_cfg *m)
{
struct sde_hw_sw_fuse *c;
c = kzalloc(sizeof(*c), GFP_KERNEL);
if (!c)
return ERR_PTR(-ENOMEM);
c->hw.base_off = addr;
c->hw.blk_off = 0;
c->hw.length = sw_fuse_len;
c->hw.hwversion = m->hwversion;
return c;
}
void sde_hw_sw_fuse_destroy(struct sde_hw_sw_fuse *sw_fuse)
{
kfree(sw_fuse);
}
u32 sde_hw_get_ltm_sw_fuse_value(struct sde_hw_sw_fuse *sw_fuse)
{
u32 ltm_sw_fuse = 0;
if (sw_fuse)
ltm_sw_fuse = SDE_REG_READ(&sw_fuse->hw, LTM_SW_FUSE_OFFSET);
return ltm_sw_fuse;
}

View File

@@ -242,6 +242,12 @@ struct sde_hw_sid {
struct sde_hw_blk_reg_map hw;
};
#define SW_FUSE_ENABLE 0x1
struct sde_hw_sw_fuse {
/* sw fuse base */
struct sde_hw_blk_reg_map hw;
};
/**
* sde_hw_sid_rotator_set - initialize the sid blk reg map
* @addr: Mapped register io address
@@ -279,4 +285,23 @@ struct sde_hw_mdp *sde_hw_mdptop_init(enum sde_mdp idx,
void sde_hw_mdp_destroy(struct sde_hw_mdp *mdp);
/**
* sde_hw_sw_fuse_init - initialize the sw fuse blk reg map
* @addr: Mapped register io address
* @sw_fuse_len: Length of block
* @m: Pointer to mdss catalog data
*/
struct sde_hw_sw_fuse *sde_hw_sw_fuse_init(void __iomem *addr,
u32 sw_fuse_len, const struct sde_mdss_cfg *m);
/**
* sde_hw_sw_fuse_destroy - free memory for sw fuse
* @sw_fuse: sde_hw_sw_fuse
*/
void sde_hw_sw_fuse_destroy(struct sde_hw_sw_fuse *sw_fuse);
/**
* sde_hw_get_ltm_sw_fuse_value - read LTM sw fuse register value
* @sw_fuse: sde_hw_sw_fuse
*/
u32 sde_hw_get_ltm_sw_fuse_value(struct sde_hw_sw_fuse *sw_fuse);
#endif /*_SDE_HW_TOP_H */

View File

@@ -1199,6 +1199,8 @@ static void sde_kms_complete_commit(struct msm_kms *kms,
pr_err("Connector Post kickoff failed rc=%d\n",
rc);
}
sde_connector_fod_notify(connector);
}
_sde_kms_drm_check_dpms(old_state, DRM_PANEL_EVENT_BLANK);
@@ -1930,6 +1932,14 @@ static void _sde_kms_hw_destroy(struct sde_kms *sde_kms,
msm_iounmap(pdev, sde_kms->sid);
sde_kms->sid = NULL;
if (sde_kms->hw_sw_fuse)
sde_hw_sw_fuse_destroy(sde_kms->hw_sw_fuse);
sde_kms->hw_sw_fuse = NULL;
if (sde_kms->sw_fuse)
msm_iounmap(pdev, sde_kms->sw_fuse);
sde_kms->sw_fuse = NULL;
if (sde_kms->reg_dma)
msm_iounmap(pdev, sde_kms->reg_dma);
sde_kms->reg_dma = NULL;
@@ -3552,6 +3562,19 @@ static int _sde_kms_hw_init_ioremap(struct sde_kms *sde_kms,
if (rc)
SDE_ERROR("dbg base register sid failed: %d\n", rc);
sde_kms->sw_fuse = msm_ioremap(platformdev, "swfuse_phys",
"swfuse_phys");
if (IS_ERR(sde_kms->sw_fuse)) {
sde_kms->sw_fuse = NULL;
SDE_DEBUG("sw_fuse is not defined");
} else {
sde_kms->sw_fuse_len = msm_iomap_size(platformdev,
"swfuse_phys");
rc = sde_dbg_reg_register_base("sw_fuse", sde_kms->sw_fuse,
sde_kms->sw_fuse_len);
if (rc)
SDE_ERROR("dbg base register sw_fuse failed: %d\n", rc);
}
error:
return rc;
}
@@ -3756,6 +3779,17 @@ static int _sde_kms_hw_init_blocks(struct sde_kms *sde_kms,
goto perf_err;
}
if (sde_kms->sw_fuse) {
sde_kms->hw_sw_fuse = sde_hw_sw_fuse_init(sde_kms->sw_fuse,
sde_kms->sw_fuse_len, sde_kms->catalog);
if (IS_ERR(sde_kms->hw_sw_fuse)) {
SDE_ERROR("failed to init sw_fuse %ld\n",
PTR_ERR(sde_kms->hw_sw_fuse));
sde_kms->hw_sw_fuse = NULL;
}
} else {
sde_kms->hw_sw_fuse = NULL;
}
/*
* _sde_kms_drm_obj_init should create the DRM related objects
* i.e. CRTCs, planes, encoders, connectors and so forth
@@ -3933,3 +3967,17 @@ int sde_kms_handle_recovery(struct drm_encoder *encoder)
SDE_EVT32(DRMID(encoder), MSM_ENC_ACTIVE_REGION);
return sde_encoder_wait_for_event(encoder, MSM_ENC_ACTIVE_REGION);
}
void sde_kms_kickoff_count(struct sde_kms *sde_kms)
{
int i;
struct dsi_display *display = NULL;
if (sde_kms != NULL) {
for (i = 0; i < sde_kms->dsi_display_count; ++i) {
display = sde_kms->dsi_displays[i];
}
}
return;
}

View File

@@ -249,9 +249,10 @@ struct sde_kms {
/* io/register spaces: */
void __iomem *mmio, *vbif[VBIF_MAX], *reg_dma, *sid,
*imem;
*imem, *sw_fuse;
unsigned long mmio_len, vbif_len[VBIF_MAX],
reg_dma_len, sid_len, imem_len;
unsigned long sw_fuse_len;
struct regulator *vdd;
struct regulator *mmagic;
@@ -277,6 +278,7 @@ struct sde_kms {
struct sde_hw_mdp *hw_mdp;
struct sde_hw_uidle *hw_uidle;
struct sde_hw_sid *hw_sid;
struct sde_hw_sw_fuse *hw_sw_fuse;
int dsi_display_count;
void **dsi_displays;
int wb_display_count;
@@ -662,6 +664,8 @@ void sde_kms_timeline_status(struct drm_device *dev);
*/
int sde_kms_handle_recovery(struct drm_encoder *encoder);
void sde_kms_kickoff_count(struct sde_kms *sde_kms);
/**
* sde_kms_update_pm_qos_irq_request - Update Qos vote for CPU receiving
* display IRQ

View File

@@ -3418,6 +3418,18 @@ void sde_plane_restore(struct drm_plane *plane)
sde_plane_atomic_update(plane, plane->state);
}
uint32_t sde_plane_get_mi_layer_info(const struct drm_plane_state *drm_state)
{
struct sde_plane_state *pstate;
if (!drm_state)
return 0;
pstate = to_sde_plane_state(drm_state);
return sde_plane_get_property(pstate, PLANE_PROP_MI_LAYER_INFO);
}
bool sde_plane_is_cache_required(struct drm_plane *plane)
{
struct sde_plane_state *pstate;
@@ -3574,6 +3586,9 @@ static void _sde_plane_install_properties(struct drm_plane *plane,
zpos_def = drm_plane_index(plane) + 1;
}
msm_property_install_range(&psde->property_info, "mi_layer_info",
0x0, 0, U32_MAX, 0, PLANE_PROP_MI_LAYER_INFO);
msm_property_install_range(&psde->property_info, "zpos",
0x0, 0, zpos_max, zpos_def, PLANE_PROP_ZPOS);

View File

@@ -308,4 +308,10 @@ void sde_plane_setup_src_split_order(struct drm_plane *plane,
*/
bool sde_plane_is_cache_required(struct drm_plane *plane);
/*
* sde_plane_get_mi_layer_info - get mi layer info
* @plane: Pointer to DRM plane object
*/
uint32_t sde_plane_get_mi_layer_info(const struct drm_plane_state *drm_state);
#endif /* _SDE_PLANE_H_ */

View File

@@ -2075,6 +2075,38 @@ void sde_rm_release(struct sde_rm *rm, struct drm_encoder *enc, bool nxt)
mutex_unlock(&rm->rm_lock);
}
static void _sde_rm_check_and_modify_commit_rsvps(
struct sde_rm *rm,
struct sde_rm_rsvp *rsvp)
{
struct sde_rm_hw_blk *blk;
enum sde_hw_blk_type type;
bool modify = false;
if (!rsvp)
return;
for (type = 0; type < SDE_HW_BLK_MAX; type++) {
list_for_each_entry(blk, &rm->hw_blks[type], list) {
if (blk->rsvp_nxt && blk->rsvp_nxt->enc_id == rsvp->enc_id
&& blk->rsvp_nxt != rsvp) {
modify = true;
}
}
}
if (modify) {
for (type = 0; type < SDE_HW_BLK_MAX; type++) {
list_for_each_entry(blk, &rm->hw_blks[type], list) {
if (blk->rsvp_nxt && blk->rsvp_nxt->enc_id
== rsvp->enc_id) {
blk->rsvp_nxt = rsvp;
}
}
}
}
}
static int _sde_rm_commit_rsvp(
struct sde_rm *rm,
struct sde_rm_rsvp *rsvp,
@@ -2084,6 +2116,8 @@ static int _sde_rm_commit_rsvp(
enum sde_hw_blk_type type;
int ret = 0;
_sde_rm_check_and_modify_commit_rsvps(rm, rsvp);
/* Swap next rsvp to be the active */
for (type = 0; type < SDE_HW_BLK_MAX; type++) {
list_for_each_entry(blk, &rm->hw_blks[type], list) {

View File

@@ -594,6 +594,10 @@ static void dsi_pll_setup_config(struct dsi_pll_7nm *pll,
config->enable_ssc = rsc->ssc_en;
config->ssc_center = rsc->ssc_center;
if (pll->cphy_enabled) {
config->enable_ssc = false;
}
if (config->enable_ssc) {
if (rsc->ssc_freq)
config->ssc_freq = rsc->ssc_freq;

View File

@@ -227,6 +227,7 @@ static int mdss_pll_probe(struct platform_device *pdev)
int rc = 0;
const char *label;
struct mdss_pll_resources *pll_res;
bool ssc_disable;
if (!pdev->dev.of_node) {
pr_err("MDSS pll driver only supports device tree probe\n");
@@ -256,6 +257,13 @@ static int mdss_pll_probe(struct platform_device *pdev)
pll_res->ssc_en = of_property_read_bool(pdev->dev.of_node,
"qcom,dsi-pll-ssc-en");
ssc_disable = of_property_read_bool(pdev->dev.of_node,
"qcom,dsi-pll-ssc-disable");
if (pll_res->ssc_en == true && ssc_disable == true) {
pll_res->ssc_en = false;
pr_info("ssc disable due to qcom,dsi-pll-ssc-disable is defined\n");
}
if (pll_res->ssc_en) {
pr_info("%s: label=%s PLL SSC enabled\n", __func__, label);