Import S928BXXU3AXH7 display-driver changes
This commit is contained in:
parent
336a9b0781
commit
f6312f1936
@ -0,0 +1,2 @@
|
||||
config PANEL_E3_S6E3HAE_AMB681AZ01_WQHD
|
||||
bool "LSI S6E3HAE LDI"
|
@ -0,0 +1 @@
|
||||
CONFIG_PANEL_E3_S6E3HAE_AMB681AZ01_WQHD=y
|
@ -4,6 +4,10 @@ export CONFIG_SYNC_FILE=y
|
||||
export CONFIG_DRM_MSM_DSI=y
|
||||
export CONFIG_DRM_MSM_DP=y
|
||||
export CONFIG_DRM_MSM_DP_MST=y
|
||||
ifneq ($(CONFIG_SEC_DISPLAYPORT),)
|
||||
export CONFIG_SECDP=y
|
||||
export CONFIG_SECDP_BIGDATA=y
|
||||
endif
|
||||
export CONFIG_DSI_PARSER=y
|
||||
export CONFIG_QCOM_MDSS_PLL=y
|
||||
export CONFIG_DRM_SDE_RSC=y
|
||||
@ -15,4 +19,4 @@ export CONFIG_HDCP_QSEECOM=y
|
||||
export CONFIG_DRM_SDE_VM=y
|
||||
export CONFIG_QTI_HW_FENCE=y
|
||||
export CONFIG_QCOM_SPEC_SYNC=y
|
||||
export CONFIG_QCOM_WCD939X_I2C=y
|
||||
export CONFIG_QCOM_WCD939X_I2C=n
|
||||
|
@ -10,6 +10,20 @@
|
||||
#define CONFIG_DRM_MSM_DSI 1
|
||||
#define CONFIG_DRM_MSM_DP 1
|
||||
#define CONFIG_DRM_MSM_DP_MST 1
|
||||
#if IS_ENABLED(CONFIG_SEC_DISPLAYPORT)
|
||||
#define CONFIG_SECDP 1
|
||||
#define CONFIG_SECDP_LOGGER 1
|
||||
#define CONFIG_SECDP_BIGDATA 1
|
||||
#if IS_ENABLED(CONFIG_SWITCH) || IS_ENABLED(CONFIG_ANDROID_SWITCH)
|
||||
#define CONFIG_SECDP_SWITCH 1
|
||||
#endif
|
||||
#if IS_ENABLED(CONFIG_SEC_FORCE_ERR)
|
||||
#define CONFIG_SECDP_DBG 1
|
||||
#endif
|
||||
#if IS_ENABLED(CONFIG_SEC_FACTORY)
|
||||
#define CONFIG_SECDP_FACTORY_DPSWITCH_TEST
|
||||
#endif
|
||||
#endif
|
||||
#define CONFIG_DSI_PARSER 1
|
||||
#define CONFIG_DRM_SDE_WB 1
|
||||
#define CONFIG_DRM_SDE_RSC 1
|
||||
@ -23,4 +37,4 @@
|
||||
#define CONFIG_DRM_SDE_VM 1
|
||||
#define CONFIG_QTI_HW_FENCE 1
|
||||
#define CONFIG_QCOM_SPEC_SYNC 1
|
||||
#define CONFIG_QCOM_WCD939X_I2C 1
|
||||
#define CONFIG_QCOM_WCD939X_I2C 0
|
||||
|
@ -12,3 +12,7 @@ ifeq ($(DISPLAY_DLKM_ENABLE), true)
|
||||
endif
|
||||
|
||||
DISPLAY_MODULES_DRIVER := msm_drm.ko
|
||||
|
||||
# ifdef CONFIG_DISPLAY_SAMSUNG
|
||||
PRODUCT_COPY_FILES += $(foreach f,$(wildcard vendor/qcom/opensource/display-drivers/msm/samsung/panel_data_file/*),$(f):/vendor/firmware/$(notdir $(f)))
|
||||
# endif // CONFIG_DISPLAY_SAMSUNG
|
||||
|
@ -3,4 +3,7 @@
|
||||
header-y += msm_hdcp.h
|
||||
header-y += sde_io_util.h
|
||||
header-y += sde_rsc.h
|
||||
header-y += sec_displayport.h
|
||||
header-y += secdp_bigdata.h
|
||||
header-y += secdp_logger.h
|
||||
|
||||
|
@ -0,0 +1,33 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2017-2021, 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 __SEC_DISPLAYPORT_H
|
||||
#define __SEC_DISPLAYPORT_H
|
||||
|
||||
/*
|
||||
* this function waits for completion of dp disconnection.
|
||||
* return : zero if dp resource is released completely.
|
||||
* non-zero if waiting timeout happens.
|
||||
*/
|
||||
int secdp_wait_for_disconnect_complete(void);
|
||||
|
||||
/**
|
||||
* if SSUSB gets reset, it need to call this callback to let DP know, since
|
||||
* DP shares PHY with SSUSB (combo PHY)
|
||||
* return 0 if success
|
||||
* return -1 otherwise
|
||||
*/
|
||||
int secdp_pdic_reset_cb(bool reset);
|
||||
|
||||
#endif/*__SEC_DISPLAYPORT_H*/
|
@ -0,0 +1,61 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2017-2021, 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 DISPLAYPORT_BIGDATA_H
|
||||
#define DISPLAYPORT_BIGDATA_H
|
||||
#include <linux/platform_device.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
enum DP_BD_ITEM_LIST {
|
||||
ERR_AUX,
|
||||
ERR_EDID,
|
||||
ERR_HDCP_AUTH,
|
||||
ERR_LINK_TRAIN,
|
||||
ERR_INF_IRQHPD,
|
||||
|
||||
BD_LINK_CONFIGURE,
|
||||
BD_ADAPTER_HWID,
|
||||
BD_ADAPTER_FWVER,
|
||||
BD_ADAPTER_TYPE,
|
||||
BD_MAX_LANE_COUNT,
|
||||
BD_MAX_LINK_RATE,
|
||||
BD_CUR_LANE_COUNT,
|
||||
BD_CUR_LINK_RATE,
|
||||
BD_HDCP_VER,
|
||||
BD_ORIENTATION,
|
||||
BD_RESOLUTION,
|
||||
BD_EDID,
|
||||
BD_ADT_VID,
|
||||
BD_ADT_PID,
|
||||
BD_DP_MODE,
|
||||
BD_SINK_NAME,
|
||||
BD_AUD_CH,
|
||||
BD_AUD_FREQ,
|
||||
BD_AUD_BIT,
|
||||
BD_ITEM_MAX,
|
||||
};
|
||||
|
||||
void secdp_bigdata_save_item(enum DP_BD_ITEM_LIST item, ...);
|
||||
void secdp_bigdata_inc_error_cnt(enum DP_BD_ITEM_LIST err);
|
||||
void secdp_bigdata_clr_error_cnt(enum DP_BD_ITEM_LIST err);
|
||||
void secdp_bigdata_connection(void);
|
||||
void secdp_bigdata_disconnection(void);
|
||||
void secdp_bigdata_init(struct class *dp_class);
|
||||
|
||||
ssize_t _secdp_bigdata_show(struct class *class,
|
||||
struct class_attribute *attr, char *buf);
|
||||
ssize_t _secdp_bigdata_store(struct class *dev,
|
||||
struct class_attribute *attr, const char *buf, size_t size);
|
||||
|
||||
#endif /* DISPLAYPORT_BIGDATA_H */
|
94
qcom/opensource/display-drivers/include/linux/secdp_logger.h
Normal file
94
qcom/opensource/display-drivers/include/linux/secdp_logger.h
Normal file
@ -0,0 +1,94 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2017-2021, 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 _SECDP_LOGGER_H_
|
||||
#define _SECDP_LOGGER_H_
|
||||
|
||||
#ifdef CONFIG_SECDP_LOGGER
|
||||
|
||||
void secdp_logger_set_max_count(int count);
|
||||
void secdp_logger_print(const char *fmt, ...);
|
||||
void secdp_logger_hex_dump(void *buf, void *pref, size_t len);
|
||||
int secdp_logger_init(void);
|
||||
void secdp_logger_deinit(void);
|
||||
|
||||
void secdp_logger_set_mode_max_count(unsigned int count);
|
||||
void secdp_logger_dec_mode_count(void);
|
||||
void secdp_logger_print_mode(const char *fmt, ...);
|
||||
|
||||
#define secdp_pr_debug(fmt, ...) \
|
||||
printk(KERN_DEBUG "[msm-dp] %s: " pr_fmt(fmt), __func__, ##__VA_ARGS__)
|
||||
|
||||
#define secdp_proc_err(fmt, ...) \
|
||||
do { \
|
||||
printk(KERN_ERR "[msm-dp] %s: " pr_fmt(fmt), __func__, ##__VA_ARGS__); \
|
||||
secdp_logger_print(fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define secdp_proc_info(fmt, ...) \
|
||||
do { \
|
||||
printk(KERN_INFO "[msm-dp] %s: " pr_fmt(fmt), __func__, ##__VA_ARGS__); \
|
||||
secdp_logger_print(fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define secdp_proc_warn(fmt, ...) \
|
||||
do { \
|
||||
printk(KERN_WARNING "[msm-dp] %s: " pr_fmt(fmt), __func__, ##__VA_ARGS__); \
|
||||
secdp_logger_print(fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define secdp_proc_info_mode(fmt, ...) \
|
||||
do { \
|
||||
printk(KERN_INFO "[msm-dp] %s: " pr_fmt(fmt), __func__, ##__VA_ARGS__); \
|
||||
secdp_logger_print_mode(fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define DP_INFO_M(fmt, ...) secdp_proc_info_mode(fmt, ##__VA_ARGS__)
|
||||
|
||||
#ifdef pr_debug
|
||||
#undef pr_debug
|
||||
#define pr_debug secdp_pr_debug
|
||||
#endif
|
||||
|
||||
#ifdef pr_err
|
||||
#undef pr_err
|
||||
#define pr_err secdp_proc_err
|
||||
#endif
|
||||
|
||||
#ifdef pr_info
|
||||
#undef pr_info
|
||||
#define pr_info secdp_proc_info
|
||||
#endif
|
||||
|
||||
#ifdef pr_warn
|
||||
#undef pr_warn
|
||||
#define pr_warn secdp_proc_warn
|
||||
#endif
|
||||
|
||||
#else/* !CONFIG_SECDP_LOGGER */
|
||||
|
||||
#define secdp_logger_set_max_count(x) do {} while (0)
|
||||
#define secdp_logger_print(fmt, ...) do {} while (0)
|
||||
#define secdp_logger_hex_dump(buf, pref, len) do {} while (0)
|
||||
#define secdp_logger_init(void) do {} while (0)
|
||||
|
||||
#ifdef pr_debug
|
||||
#undef pr_debug
|
||||
#define pr_debug pr_info
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif/*_SECDP_LOGGER_H_*/
|
@ -0,0 +1,54 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2017-2021, 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 _SECDP_LOGGER_EX_H_
|
||||
#define _SECDP_LOGGER_EX_H_
|
||||
|
||||
/*
|
||||
* if .c has its own pr_fmt, then use this instead of secdp_logger.h
|
||||
*/
|
||||
#ifdef CONFIG_SECDP_LOGGER
|
||||
void secdp_logger_print(const char *fmt, ...);
|
||||
|
||||
#define secdp_proc_info_ex(fmt, ...) \
|
||||
do { \
|
||||
printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__); \
|
||||
secdp_logger_print(fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define secdp_pr_info_ex(fmt, ...) \
|
||||
printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
|
||||
|
||||
#ifdef pr_debug
|
||||
#undef pr_debug
|
||||
#define pr_debug secdp_pr_info_ex
|
||||
#endif
|
||||
|
||||
#ifdef pr_err
|
||||
#undef pr_err
|
||||
#define pr_err secdp_proc_info_ex
|
||||
#endif
|
||||
|
||||
#ifdef pr_info
|
||||
#undef pr_info
|
||||
#define pr_info secdp_proc_info_ex
|
||||
#endif
|
||||
|
||||
#ifdef pr_warn
|
||||
#undef pr_warn
|
||||
#define pr_warn secdp_proc_info_ex
|
||||
#endif
|
||||
|
||||
#endif/*CONFIG_SECDP_LOGGER*/
|
||||
#endif/*_SECDP_LOGGER_EX_H_*/
|
268
qcom/opensource/display-drivers/msm/.Kbuild.lego.updated
Normal file
268
qcom/opensource/display-drivers/msm/.Kbuild.lego.updated
Normal file
@ -0,0 +1,268 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
KDIR := $(TOP)/kernel_platform/msm-kernel
|
||||
|
||||
ifeq ($(CONFIG_ARCH_WAIPIO), y)
|
||||
ifeq ($(CONFIG_ARCH_QTI_VM), y)
|
||||
include $(DISPLAY_ROOT)/config/gki_waipiodisptui.conf
|
||||
LINUX_INC += -include $(DISPLAY_ROOT)/config/gki_waipiodisptuiconf.h
|
||||
else
|
||||
include $(DISPLAY_ROOT)/config/gki_waipiodisp.conf
|
||||
LINUX_INC += -include $(DISPLAY_ROOT)/config/gki_waipiodispconf.h
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_ARCH_NEO), y)
|
||||
include $(DISPLAY_ROOT)/config/gki_neodisp.conf
|
||||
LINUX_INC += -include $(DISPLAY_ROOT)/config/gki_neodispconf.h
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_ARCH_PARROT), y)
|
||||
include $(DISPLAY_ROOT)/config/gki_parrotdisp.conf
|
||||
LINUX_INC += -include $(DISPLAY_ROOT)/config/gki_parrotdispconf.h
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_ARCH_PINEAPPLE), y)
|
||||
ifeq ($(CONFIG_ARCH_QTI_VM), y)
|
||||
include $(DISPLAY_ROOT)/config/gki_pineappledisptui.conf
|
||||
LINUX_INC += -include $(DISPLAY_ROOT)/config/gki_pineappledisptuiconf.h
|
||||
else
|
||||
include $(DISPLAY_ROOT)/config/gki_pineappledisp.conf
|
||||
LINUX_INC += -include $(DISPLAY_ROOT)/config/gki_pineappledispconf.h
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_ARCH_KALAMA), y)
|
||||
ifeq ($(CONFIG_ARCH_QTI_VM), y)
|
||||
include $(DISPLAY_ROOT)/config/gki_kalamadisptui.conf
|
||||
LINUX_INC += -include $(DISPLAY_ROOT)/config/gki_kalamadisptuiconf.h
|
||||
else
|
||||
include $(DISPLAY_ROOT)/config/gki_kalamadisp.conf
|
||||
LINUX_INC += -include $(DISPLAY_ROOT)/config/gki_kalamadispconf.h
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq (y, $(findstring y, $(CONFIG_ARCH_SA8155) $(CONFIG_ARCH_SA6155) $(CONFIG_ARCH_SA8195)))
|
||||
include $(DISPLAY_ROOT)/config/augen3disp.conf
|
||||
LINUX_INC += -include $(DISPLAY_ROOT)/config/augen3dispconf.h
|
||||
endif
|
||||
|
||||
LINUX_INC += -I$(KERNEL_SRC)/include/linux \
|
||||
-I$(KERNEL_SRC)/include/linux/drm
|
||||
|
||||
LINUX_INC += -I$(DISPLAY_ROOT) \
|
||||
-I$(DISPLAY_ROOT)/include \
|
||||
-I$(KERNEL_ROOT)/drivers/clk/qcom \
|
||||
-I$(KERNEL_SRC)/drivers/clk/qcom \
|
||||
-I$(DISPLAY_ROOT)/include/linux \
|
||||
-I$(DISPLAY_ROOT)/rotator \
|
||||
-I$(DISPLAY_ROOT)/msm \
|
||||
-I$(DISPLAY_ROOT)/msm/dp \
|
||||
-I$(DISPLAY_ROOT)/msm/dsi \
|
||||
-I$(DISPLAY_ROOT)/msm/sde \
|
||||
-I$(DISPLAY_ROOT)/include/uapi/display \
|
||||
|
||||
CDEFINES += -DANI_LITTLE_BYTE_ENDIAN \
|
||||
-DANI_LITTLE_BIT_ENDIAN \
|
||||
-DDOT11F_LITTLE_ENDIAN_HOST \
|
||||
-DANI_COMPILER_TYPE_GCC \
|
||||
-DANI_OS_TYPE_ANDROID=6 \
|
||||
-DPTT_SOCK_SVC_ENABLE \
|
||||
-Wall\
|
||||
-Werror\
|
||||
-D__linux__
|
||||
|
||||
KBUILD_CPPFLAGS += $(CDEFINES)
|
||||
|
||||
ccflags-y += $(LINUX_INC)
|
||||
|
||||
# CONFIG_DISPLAY_SAMSUNG start
|
||||
ccflags-y += -I$(DISPLAY_ROOT)/msm/samsung
|
||||
# CONFIG_DISPLAY_SAMSUNG end
|
||||
|
||||
ifeq ($(call cc-option-yn, -Wmaybe-uninitialized),y)
|
||||
EXTRA_CFLAGS += -Wmaybe-uninitialized
|
||||
endif
|
||||
|
||||
KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/display-drivers/hdcp/Module.symvers
|
||||
KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/display-drivers/msm/Module.symvers
|
||||
|
||||
ifeq ($(call cc-option-yn, -Wheader-guard),y)
|
||||
EXTRA_CFLAGS += -Wheader-guard
|
||||
endif
|
||||
|
||||
ccflags-y += -Wformat-extra-args -Wstrict-prototypes -Wformat-insufficient-args \
|
||||
-Wformat-invalid-specifier -Wformat-zero-length -Wnonnull
|
||||
|
||||
ifneq ($(MODNAME), qdsp6v2)
|
||||
CHIP_NAME ?= $(MODNAME)
|
||||
CDEFINES += -DMULTI_IF_NAME=\"$(CHIP_NAME)\"
|
||||
endif
|
||||
|
||||
######### CONFIG_DRM_MSM ########
|
||||
obj-m += msm_drm.o
|
||||
|
||||
msm_drm-$(CONFIG_HDCP_QSEECOM) := ../hdcp/msm_hdcp.o \
|
||||
dp/dp_hdcp2p2.o \
|
||||
sde_hdcp_1x.o \
|
||||
sde_hdcp_2x.o
|
||||
|
||||
msm_drm-$(CONFIG_MSM_SDE_ROTATOR) += ../rotator/sde_rotator_dev.o \
|
||||
../rotator/sde_rotator_dev.o \
|
||||
../rotator/sde_rotator_core.o \
|
||||
../rotator/sde_rotator_base.o \
|
||||
../rotator/sde_rotator_formats.o \
|
||||
../rotator/sde_rotator_util.o \
|
||||
../rotator/sde_rotator_io_util.o \
|
||||
../rotator/sde_rotator_smmu.o \
|
||||
../rotator/sde_rotator_r1_wb.o \
|
||||
../rotator/sde_rotator_r1_pipe.o \
|
||||
../rotator/sde_rotator_r1_ctl.o \
|
||||
../rotator/sde_rotator_r1.o \
|
||||
../rotator/sde_rotator_r3.o
|
||||
|
||||
ifeq ($(CONFIG_MSM_SDE_ROTATOR), y)
|
||||
msm_drm-$(CONFIG_SYNC_FILE) += ../rotator/sde_rotator_sync.o
|
||||
|
||||
msm_drm-$(CONFIG_DEBUG_FS) += ../rotator/sde_rotator_debug.o \
|
||||
../rotator/sde_rotator_r1_debug.o \
|
||||
../rotator/sde_rotator_r3_debug.o
|
||||
endif
|
||||
|
||||
msm_drm-$(CONFIG_DRM_SDE_VM) += sde/sde_vm_common.o \
|
||||
sde/sde_vm_primary.o \
|
||||
sde/sde_vm_trusted.o \
|
||||
sde/sde_vm_msgq.o
|
||||
|
||||
msm_drm-$(CONFIG_DRM_MSM_DP) += dp/dp_altmode.o \
|
||||
dp/dp_parser.o \
|
||||
dp/dp_power.o \
|
||||
dp/dp_catalog.o \
|
||||
dp/dp_catalog_v420.o \
|
||||
dp/dp_catalog_v200.o \
|
||||
dp/dp_aux.o \
|
||||
dp/dp_panel.o \
|
||||
dp/dp_link.o \
|
||||
dp/dp_ctrl.o \
|
||||
dp/dp_audio.o \
|
||||
dp/dp_debug.o \
|
||||
dp/dp_hpd.o \
|
||||
dp/dp_aux_bridge.o \
|
||||
dp/dp_bridge_hpd.o \
|
||||
dp/dp_mst_sim.o \
|
||||
dp/dp_mst_sim_helper.o \
|
||||
dp/dp_gpio_hpd.o \
|
||||
dp/dp_lphw_hpd.o \
|
||||
dp/dp_display.o \
|
||||
dp/dp_drm.o \
|
||||
dp/dp_pll.o \
|
||||
dp/dp_pll_5nm.o \
|
||||
dp/dp_pll_4nm.o
|
||||
|
||||
msm_drm-$(CONFIG_DRM_MSM_DP_MST) += dp/dp_mst_drm.o
|
||||
|
||||
msm_drm-$(CONFIG_DRM_MSM_DP_USBPD_LEGACY) += dp/dp_usbpd.o
|
||||
|
||||
# sec displayport
|
||||
msm_drm-$(CONFIG_SECDP) += dp/secdp_sysfs.o \
|
||||
dp/secdp_logger.o \
|
||||
dp/secdp_unit_test.o
|
||||
|
||||
msm_drm-$(CONFIG_SECDP_BIGDATA) += dp/secdp_bigdata.o
|
||||
|
||||
msm_drm-$(CONFIG_DRM_MSM_SDE) += sde/sde_crtc.o \
|
||||
sde/sde_encoder.o \
|
||||
sde/sde_encoder_dce.o \
|
||||
sde/sde_encoder_phys_vid.o \
|
||||
sde/sde_encoder_phys_cmd.o \
|
||||
sde/sde_irq.o sde/sde_core_irq.o \
|
||||
sde/sde_core_perf.o \
|
||||
sde/sde_rm.o \
|
||||
sde/sde_kms_utils.o \
|
||||
sde/sde_kms.o \
|
||||
sde/sde_plane.o \
|
||||
sde/sde_connector.o \
|
||||
sde/sde_color_processing.o \
|
||||
sde/sde_vbif.o \
|
||||
sde_dbg.o \
|
||||
sde_dbg_evtlog.o \
|
||||
sde_io_util.o \
|
||||
sde_vm_event.o \
|
||||
sde/sde_hw_reg_dma_v1_color_proc.o \
|
||||
sde/sde_hw_color_proc_v4.o \
|
||||
sde/sde_hw_ad4.o \
|
||||
sde/sde_hw_uidle.o \
|
||||
sde_edid_parser.o \
|
||||
sde/sde_hw_catalog.o \
|
||||
sde/sde_hw_cdm.o \
|
||||
sde/sde_hw_dspp.o \
|
||||
sde/sde_hw_intf.o \
|
||||
sde/sde_hw_lm.o \
|
||||
sde/sde_hw_ctl.o \
|
||||
sde/sde_hw_util.o \
|
||||
sde/sde_hw_sspp.o \
|
||||
sde/sde_hw_wb.o \
|
||||
sde/sde_hw_pingpong.o \
|
||||
sde/sde_hw_top.o \
|
||||
sde/sde_hw_interrupts.o \
|
||||
sde/sde_hw_vbif.o \
|
||||
sde/sde_formats.o \
|
||||
sde_power_handle.o \
|
||||
sde/sde_hw_color_processing_v1_7.o \
|
||||
sde/sde_reg_dma.o \
|
||||
sde/sde_hw_reg_dma_v1.o \
|
||||
sde/sde_hw_dsc.o \
|
||||
sde/sde_hw_dsc_1_2.o \
|
||||
sde/sde_hw_vdc.o \
|
||||
sde/sde_hw_ds.o \
|
||||
sde/sde_fence.o \
|
||||
sde/sde_hw_qdss.o \
|
||||
sde_dsc_helper.o \
|
||||
sde_vdc_helper.o \
|
||||
sde/sde_hw_dnsc_blur.o \
|
||||
sde/sde_hw_rc.o
|
||||
|
||||
msm_drm-$(CONFIG_DRM_SDE_WB) += sde/sde_wb.o \
|
||||
sde/sde_encoder_phys_wb.o
|
||||
|
||||
msm_drm-$(CONFIG_DRM_SDE_RSC) += sde_rsc.o \
|
||||
sde_rsc_hw.o \
|
||||
sde_rsc_hw_v3.o
|
||||
|
||||
msm_drm-$(CONFIG_DRM_MSM_DSI) += dsi/dsi_phy.o \
|
||||
dsi/dsi_pwr.o \
|
||||
dsi/dsi_phy.o \
|
||||
dsi/dsi_phy_hw_v3_0.o \
|
||||
dsi/dsi_phy_hw_v4_0.o \
|
||||
dsi/dsi_phy_hw_v5_0.o \
|
||||
dsi/dsi_phy_timing_calc.o \
|
||||
dsi/dsi_phy_timing_v3_0.o \
|
||||
dsi/dsi_phy_timing_v4_0.o \
|
||||
dsi/dsi_pll.o \
|
||||
dsi/dsi_pll_5nm.o \
|
||||
dsi/dsi_pll_4nm.o \
|
||||
dsi/dsi_ctrl_hw_cmn.o \
|
||||
dsi/dsi_ctrl_hw_2_2.o \
|
||||
dsi/dsi_ctrl.o \
|
||||
dsi/dsi_catalog.o \
|
||||
dsi/dsi_drm.o \
|
||||
dsi/dsi_display.o \
|
||||
dsi/dsi_panel.o \
|
||||
dsi/dsi_clk_manager.o \
|
||||
dsi/dsi_display_test.o
|
||||
|
||||
msm_drm-$(CONFIG_DSI_PARSER) += dsi/dsi_parser.o
|
||||
|
||||
msm_drm-$(CONFIG_THERMAL_OF) += msm_cooling_device.o
|
||||
|
||||
msm_drm-$(CONFIG_DRM_MSM) += msm_atomic.o \
|
||||
msm_fb.o \
|
||||
msm_drv.o \
|
||||
msm_gem.o \
|
||||
msm_gem_prime.o \
|
||||
msm_gem_vma.o \
|
||||
msm_smmu.o \
|
||||
msm_prop.o
|
||||
|
||||
CDEFINES += -DBUILD_TIMESTAMP=\"$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')\"
|
||||
|
@ -86,6 +86,10 @@ KBUILD_CPPFLAGS += $(CDEFINES)
|
||||
|
||||
ccflags-y += $(LINUX_INC)
|
||||
|
||||
# CONFIG_DISPLAY_SAMSUNG start
|
||||
ccflags-y += -I$(DISPLAY_ROOT)/msm/samsung
|
||||
# CONFIG_DISPLAY_SAMSUNG end
|
||||
|
||||
ifeq ($(call cc-option-yn, -Wmaybe-uninitialized),y)
|
||||
EXTRA_CFLAGS += -Wmaybe-uninitialized
|
||||
endif
|
||||
@ -169,6 +173,13 @@ msm_drm-$(CONFIG_DRM_MSM_DP_MST) += dp/dp_mst_drm.o
|
||||
|
||||
msm_drm-$(CONFIG_DRM_MSM_DP_USBPD_LEGACY) += dp/dp_usbpd.o
|
||||
|
||||
# sec displayport
|
||||
msm_drm-$(CONFIG_SECDP) += dp/secdp_sysfs.o \
|
||||
dp/secdp_logger.o \
|
||||
dp/secdp_unit_test.o
|
||||
|
||||
msm_drm-$(CONFIG_SECDP_BIGDATA) += dp/secdp_bigdata.o
|
||||
|
||||
msm_drm-$(CONFIG_DRM_MSM_SDE) += sde/sde_crtc.o \
|
||||
sde/sde_encoder.o \
|
||||
sde/sde_encoder_dce.o \
|
||||
@ -263,3 +274,72 @@ msm_drm-$(CONFIG_DRM_MSM) += msm_atomic.o \
|
||||
msm_smmu.o \
|
||||
msm_prop.o
|
||||
|
||||
include $(DISPLAY_ROOT)/msm/samsung/E3_S6E3HAE_AMB681AZ01/E3_S6E3HAE_AMB681AZ01.conf
|
||||
ccflags-y += -include $(DISPLAY_ROOT)/msm/samsung/E3_S6E3HAE_AMB681AZ01/E3_S6E3HAE_AMB681AZ01.h
|
||||
|
||||
XXD := /usr/bin/xxd
|
||||
SED := /bin/sed
|
||||
|
||||
#Translate .dat file to .h to cover the case which can not use request_firmware(Recovery Mode)
|
||||
CLEAR_TMP := $(shell rm -f E3_S6E3HAE_AMB681AZ01_PDF_DATA)
|
||||
COPY_TO_HERE := $(shell cp -vf $(DISPLAY_ROOT)/msm/samsung/panel_data_file/E3_S6E3HAE_AMB681AZ01.dat E3_S6E3HAE_AMB681AZ01_PDF_DATA)
|
||||
DATA_TO_HEX := $(shell $(XXD) -i E3_S6E3HAE_AMB681AZ01_PDF_DATA > $(DISPLAY_ROOT)/msm/samsung/E3_S6E3HAE_AMB681AZ01/E3_S6E3HAE_AMB681AZ01_PDF.h)
|
||||
ADD_NULL_CHR := $(shell $(SED) -i -e 's/\([0-9a-f]\)$$/\0, 0x00/' $(DISPLAY_ROOT)/msm/samsung/E3_S6E3HAE_AMB681AZ01/E3_S6E3HAE_AMB681AZ01_PDF.h)
|
||||
|
||||
msm_drm-$(CONFIG_PANEL_E3_S6E3HAE_AMB681AZ01_WQHD) += samsung/E3_S6E3HAE_AMB681AZ01/E3_S6E3HAE_AMB681AZ01_panel.o
|
||||
|
||||
include $(DISPLAY_ROOT)/msm/samsung/panel_common.conf
|
||||
ccflags-y += -include $(DISPLAY_ROOT)/msm/samsung/panel_common_conf.h
|
||||
|
||||
msm_drm-$(CONFIG_DISPLAY_SAMSUNG) += samsung/PBA_BOOTING/ss_dsi_panel_PBA_BOOTING_fhd.o
|
||||
include $(DISPLAY_ROOT)/msm/samsung/E3_S6E3HAF_AMB679FN01/E3_S6E3HAF_AMB679FN01.conf
|
||||
ccflags-y += -include $(DISPLAY_ROOT)/msm/samsung/E3_S6E3HAF_AMB679FN01/E3_S6E3HAF_AMB679FN01.h
|
||||
|
||||
XXD := /usr/bin/xxd
|
||||
SED := /bin/sed
|
||||
|
||||
#Translate .dat file to .h to cover the case which can not use request_firmware(Recovery Mode)
|
||||
CLEAR_TMP := $(shell rm -f E3_S6E3HAF_AMB679FN01_PDF_DATA)
|
||||
COPY_TO_HERE := $(shell cp -vf $(DISPLAY_ROOT)/msm/samsung/panel_data_file/E3_S6E3HAF_AMB679FN01.dat E3_S6E3HAF_AMB679FN01_PDF_DATA)
|
||||
DATA_TO_HEX := $(shell $(XXD) -i E3_S6E3HAF_AMB679FN01_PDF_DATA > $(DISPLAY_ROOT)/msm/samsung/E3_S6E3HAF_AMB679FN01/E3_S6E3HAF_AMB679FN01_PDF.h)
|
||||
ADD_NULL_CHR := $(shell $(SED) -i -e 's/\([0-9a-f]\)$$/\0, 0x00/' $(DISPLAY_ROOT)/msm/samsung/E3_S6E3HAF_AMB679FN01/E3_S6E3HAF_AMB679FN01_PDF.h)
|
||||
|
||||
msm_drm-$(CONFIG_PANEL_E3_S6E3HAF_AMB679FN01_WQHD) += samsung/E3_S6E3HAF_AMB679FN01/E3_S6E3HAF_AMB679FN01_panel.o
|
||||
|
||||
include $(DISPLAY_ROOT)/msm/samsung/panel_common.conf
|
||||
ccflags-y += -include $(DISPLAY_ROOT)/msm/samsung/panel_common_conf.h
|
||||
|
||||
ifeq ($(TARGET_BUILD_VARIANT), eng)
|
||||
ccflags-y += -DCONFIG_OPCODE_PARSER=1
|
||||
endif
|
||||
|
||||
msm_drm-$(CONFIG_DISPLAY_SAMSUNG) += samsung/ss_dsi_panel_sysfs.o \
|
||||
samsung/ss_dsi_panel_debug.o \
|
||||
samsung/ss_dsi_panel_common.o \
|
||||
samsung/ss_dsi_mdnie_lite_common.o \
|
||||
samsung/ss_dpui_common.o \
|
||||
samsung/ss_copr_common.o \
|
||||
samsung/ss_wrapper_common.o \
|
||||
samsung/ss_panel_parse.o \
|
||||
samsung/ss_panel_power.o \
|
||||
samsung/ss_ddi_poc_common.o
|
||||
|
||||
ifeq ($(CONFIG_SEC_KUNIT), y)
|
||||
ifeq ($(CONFIG_UML), y)
|
||||
obj-y += samsung/kunit_test/ss_dsi_panel_common_test.o
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
# LEGO
|
||||
subdir-ccflags-$(CONFIG_SEC_KUNIT) += \
|
||||
-Wno-unused-variable \
|
||||
-Wno-unused-function \
|
||||
-Wno-missing-braces \
|
||||
-Wno-format
|
||||
|
||||
|
||||
msm_drm-$(CONFIG_DISPLAY_SAMSUNG) += samsung/SELF_DISPLAY/self_display.o
|
||||
|
||||
|
||||
msm_drm-$(CONFIG_DISPLAY_SAMSUNG) += samsung/MAFPC/ss_dsi_mafpc.o
|
||||
|
38
qcom/opensource/display-drivers/msm/dp/Kconfig
Normal file
38
qcom/opensource/display-drivers/msm/dp/Kconfig
Normal file
@ -0,0 +1,38 @@
|
||||
config SEC_DISPLAYPORT
|
||||
bool "SEC DISPLAYPORT feature"
|
||||
default n
|
||||
help
|
||||
Samsung specific displayport changes.
|
||||
|
||||
config SEC_DISPLAYPORT_MST
|
||||
bool "SEC DISPLAYPORT MST feature"
|
||||
depends on SEC_DISPLAYPORT
|
||||
default n
|
||||
help
|
||||
Samsung specific displayport MST changes.
|
||||
|
||||
config SEC_DISPLAYPORT_BIGDATA
|
||||
bool "DISPLAYPORT bigdata"
|
||||
depends on !SEC_FACTORY
|
||||
default n
|
||||
help
|
||||
Enable DISPLAYPORT bigdata.
|
||||
|
||||
config SEC_DISPLAYPORT_LOGGER
|
||||
bool "SEC DISPLAYPORT LOGGER feature"
|
||||
depends on SEC_DISPLAYPORT
|
||||
help
|
||||
Samsung specific displayport log changes.
|
||||
|
||||
config SEC_DISPLAYPORT_ENG
|
||||
bool "SEC DISPLAYPORT ENG feature"
|
||||
depends on SEC_DISPLAYPORT
|
||||
help
|
||||
Samsung specific eng test code for displayport.
|
||||
|
||||
config SEC_DISPLAYPORT_AUX_CONTROL
|
||||
bool "SEC DISPLAYPORT Aux Control feature"
|
||||
depends on SEC_DISPLAYPORT
|
||||
default n
|
||||
help
|
||||
Support for AUX dongle control.
|
@ -41,6 +41,7 @@ enum dp_altmode_pin_assignment {
|
||||
DPAM_HPD_F,
|
||||
};
|
||||
|
||||
#if !defined(CONFIG_SECDP)
|
||||
static int dp_altmode_set_usb_dp_mode(struct dp_altmode_private *altmode)
|
||||
{
|
||||
int rc = 0;
|
||||
@ -226,6 +227,7 @@ static void dp_altmode_register(void *priv)
|
||||
else
|
||||
DP_DEBUG("success\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
static int dp_altmode_simulate_connect(struct dp_hpd *dp_hpd, bool hpd)
|
||||
{
|
||||
@ -271,7 +273,9 @@ static int dp_altmode_simulate_attention(struct dp_hpd *dp_hpd, int vdo)
|
||||
|
||||
struct dp_hpd *dp_altmode_get(struct device *dev, struct dp_hpd_cb *cb)
|
||||
{
|
||||
#if !defined(CONFIG_SECDP)
|
||||
int rc = 0;
|
||||
#endif
|
||||
struct dp_altmode_private *altmode;
|
||||
struct dp_altmode *dp_altmode;
|
||||
|
||||
@ -292,18 +296,22 @@ struct dp_hpd *dp_altmode_get(struct device *dev, struct dp_hpd_cb *cb)
|
||||
dp_altmode->base.simulate_connect = dp_altmode_simulate_connect;
|
||||
dp_altmode->base.simulate_attention = dp_altmode_simulate_attention;
|
||||
|
||||
#if !defined(CONFIG_SECDP)
|
||||
rc = altmode_register_notifier(dev, dp_altmode_register, altmode);
|
||||
if (rc < 0) {
|
||||
DP_ERR("altmode probe notifier registration failed: %d\n", rc);
|
||||
goto error;
|
||||
}
|
||||
#endif
|
||||
|
||||
DP_DEBUG("success\n");
|
||||
|
||||
return &dp_altmode->base;
|
||||
#if !defined(CONFIG_SECDP)
|
||||
error:
|
||||
kfree(altmode);
|
||||
return ERR_PTR(rc);
|
||||
#endif
|
||||
}
|
||||
|
||||
void dp_altmode_put(struct dp_hpd *dp_hpd)
|
||||
@ -318,8 +326,10 @@ void dp_altmode_put(struct dp_hpd *dp_hpd)
|
||||
altmode = container_of(dp_altmode, struct dp_altmode_private,
|
||||
dp_altmode);
|
||||
|
||||
#if !defined(CONFIG_SECDP)
|
||||
altmode_deregister_client(altmode->amclient);
|
||||
altmode_deregister_notifier(altmode->dev, altmode);
|
||||
#endif
|
||||
|
||||
kfree(altmode);
|
||||
}
|
||||
|
@ -19,6 +19,20 @@
|
||||
#include "dp_panel.h"
|
||||
#include "dp_debug.h"
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
#include "secdp.h"
|
||||
#if defined(CONFIG_SECDP_BIGDATA)
|
||||
#include <linux/secdp_bigdata.h>
|
||||
#endif
|
||||
#if defined(CONFIG_SECDP_SWITCH)
|
||||
#include <linux/switch.h>
|
||||
|
||||
static struct switch_dev switch_secdp_audio = {
|
||||
.name = "ch_hdmi_audio",
|
||||
};
|
||||
#endif
|
||||
#endif/*CONFIG_SECDP*/
|
||||
|
||||
struct dp_audio_private {
|
||||
struct platform_device *ext_pdev;
|
||||
struct platform_device *pdev;
|
||||
@ -410,6 +424,11 @@ static int dp_audio_info_setup(struct platform_device *pdev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECDP_BIGDATA)
|
||||
secdp_bigdata_save_item(BD_AUD_CH, params->num_of_channels);
|
||||
secdp_bigdata_save_item(BD_AUD_FREQ, params->sample_rate_hz);
|
||||
#endif
|
||||
|
||||
mutex_lock(&audio->ops_lock);
|
||||
|
||||
audio->channels = params->num_of_channels;
|
||||
@ -433,6 +452,38 @@ static int dp_audio_info_setup(struct platform_device *pdev,
|
||||
return rc;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
static void secdp_audio_use_one_sampling_freq(u8 *adb, int size)
|
||||
{
|
||||
const int one_adb_size = 3;
|
||||
int adb_count;
|
||||
|
||||
if (size <= 0)
|
||||
return;
|
||||
|
||||
adb_count = size / one_adb_size;
|
||||
while (adb_count > 0) {
|
||||
if (adb[1] & BIT(2))
|
||||
adb[1] = BIT(2); /* 48kHz */
|
||||
else if (adb[1] & BIT(1))
|
||||
adb[1] = BIT(1); /* 44.1kHz */
|
||||
else if (adb[1] & BIT(0))
|
||||
adb[1] = BIT(0); /* 32kHz */
|
||||
else if (adb[1] & BIT(3))
|
||||
adb[1] = BIT(3); /* 88kHz */
|
||||
else if (adb[1] & BIT(4))
|
||||
adb[1] = BIT(4); /* 96kHz */
|
||||
else if (adb[1] & BIT(5))
|
||||
adb[1] = BIT(5); /* 176kHz */
|
||||
else if (adb[1] & BIT(6))
|
||||
adb[1] = BIT(6); /* 192kHz */
|
||||
|
||||
adb += one_adb_size;
|
||||
adb_count--;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static int dp_audio_get_edid_blk(struct platform_device *pdev,
|
||||
struct msm_ext_disp_audio_edid_blk *blk)
|
||||
{
|
||||
@ -459,8 +510,19 @@ static int dp_audio_get_edid_blk(struct platform_device *pdev,
|
||||
|
||||
edid = audio->panel->edid_ctrl;
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
if (secdp_adapter_is_legacy())
|
||||
secdp_audio_use_one_sampling_freq(edid->audio_data_block, edid->adb_size);
|
||||
#endif
|
||||
blk->audio_data_blk = edid->audio_data_block;
|
||||
blk->audio_data_blk_size = edid->adb_size;
|
||||
#if defined(CONFIG_SECDP)
|
||||
print_hex_dump(KERN_DEBUG, "AUDIO_BLK: ",
|
||||
DUMP_PREFIX_NONE, 16, 1, blk->audio_data_blk,
|
||||
blk->audio_data_blk_size, false);
|
||||
secdp_logger_hex_dump(blk->audio_data_blk, "AUDIO_BLK:",
|
||||
blk->audio_data_blk_size);
|
||||
#endif
|
||||
|
||||
blk->spk_alloc_data_blk = edid->spkr_alloc_data_block;
|
||||
blk->spk_alloc_data_blk_size = edid->sadb_size;
|
||||
@ -677,6 +739,10 @@ end:
|
||||
return rc;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECDP_SWITCH)
|
||||
extern int secdp_get_audio_ch(void);
|
||||
#endif
|
||||
|
||||
static int dp_audio_notify(struct dp_audio_private *audio, u32 state)
|
||||
{
|
||||
int rc = 0;
|
||||
@ -695,6 +761,17 @@ static int dp_audio_notify(struct dp_audio_private *audio, u32 state)
|
||||
if (rc)
|
||||
goto end;
|
||||
|
||||
#if defined(CONFIG_SECDP_SWITCH)
|
||||
{
|
||||
if (!audio->dp_audio.has_mst) {
|
||||
int audio_ch = state ? secdp_get_audio_ch() : -1;
|
||||
|
||||
switch_set_state(&switch_secdp_audio, audio_ch);
|
||||
DP_INFO("secdp audio state:0x%x\n", audio_ch);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (atomic_read(&audio->acked))
|
||||
goto end;
|
||||
|
||||
@ -752,6 +829,13 @@ static int dp_audio_on(struct dp_audio *dp_audio)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
if (!secdp_get_cable_status()) {
|
||||
DP_INFO("cable is out\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
audio = container_of(dp_audio, struct dp_audio_private, dp_audio);
|
||||
if (IS_ERR(audio)) {
|
||||
DP_ERR("invalid input\n");
|
||||
@ -798,6 +882,13 @@ static int dp_audio_off(struct dp_audio *dp_audio, bool skip_wait)
|
||||
|
||||
ext = &audio->ext_audio_data;
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
if (!atomic_read(&audio->session_on)) {
|
||||
DP_INFO("dp audio already off\n");
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
work_pending = cancel_delayed_work_sync(&audio->notify_delayed_work);
|
||||
if (work_pending)
|
||||
DP_DEBUG("pending notification work completed\n");
|
||||
@ -830,6 +921,43 @@ static void dp_audio_notify_work_fn(struct work_struct *work)
|
||||
dp_audio_notify(audio, EXT_DISPLAY_CABLE_CONNECT);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECDP_SWITCH)
|
||||
int secdp_audio_register_switch(struct dp_audio *dp_audio)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (dp_audio->has_mst) {
|
||||
DP_INFO("skip switch register\n");
|
||||
rc = -ENODEV;
|
||||
goto end;
|
||||
}
|
||||
|
||||
rc = switch_dev_register(&switch_secdp_audio);
|
||||
if (rc) {
|
||||
DP_INFO("Failed to register secdp_audio switch %d\n", rc);
|
||||
rc = -ENODEV;
|
||||
goto end;
|
||||
}
|
||||
|
||||
DP_INFO("secdp_audio register success\n");
|
||||
end:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void secdp_audio_unregister_switch(struct dp_audio_private *audio)
|
||||
{
|
||||
struct dp_audio *dp_audio = &audio->dp_audio;
|
||||
|
||||
if (dp_audio->has_mst) {
|
||||
DP_DEBUG("skip switch unregister\n");
|
||||
return;
|
||||
}
|
||||
|
||||
switch_dev_unregister(&switch_secdp_audio);
|
||||
DP_INFO("secdp_audio unregister success\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
static int dp_audio_create_notify_workqueue(struct dp_audio_private *audio)
|
||||
{
|
||||
audio->notify_workqueue = create_workqueue("sdm_dp_audio_notify");
|
||||
@ -847,6 +975,10 @@ static void dp_audio_destroy_notify_workqueue(struct dp_audio_private *audio)
|
||||
{
|
||||
if (audio->notify_workqueue)
|
||||
destroy_workqueue(audio->notify_workqueue);
|
||||
|
||||
#if defined(CONFIG_SECDP_SWITCH)
|
||||
secdp_audio_unregister_switch(audio);
|
||||
#endif
|
||||
}
|
||||
|
||||
struct dp_audio *dp_audio_get(struct platform_device *pdev,
|
||||
|
@ -22,6 +22,9 @@ struct dp_audio {
|
||||
u32 lane_count;
|
||||
u32 bw_code;
|
||||
bool tui_active;
|
||||
#if defined(CONFIG_SECDP_SWITCH)
|
||||
bool has_mst;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* on()
|
||||
@ -73,4 +76,9 @@ struct dp_audio *dp_audio_get(struct platform_device *pdev,
|
||||
* @dp_audio: an instance of dp_audio.
|
||||
*/
|
||||
void dp_audio_put(struct dp_audio *dp_audio);
|
||||
|
||||
#if defined(CONFIG_SECDP_SWITCH)
|
||||
int secdp_audio_register_switch(struct dp_audio *dp_audio);
|
||||
#endif
|
||||
|
||||
#endif /* _DP_AUDIO_H_ */
|
||||
|
@ -16,6 +16,12 @@
|
||||
#include "dp_aux.h"
|
||||
#include "dp_hpd.h"
|
||||
#include "dp_debug.h"
|
||||
#if defined(CONFIG_SECDP)
|
||||
#if defined(CONFIG_SECDP_BIGDATA)
|
||||
#include <linux/secdp_bigdata.h>
|
||||
#endif
|
||||
#include "secdp.h"
|
||||
#endif
|
||||
|
||||
#define DP_AUX_ENUM_STR(x) #x
|
||||
#define DP_AUX_IPC_NUM_PAGES 10
|
||||
@ -69,7 +75,11 @@ struct dp_aux_private {
|
||||
struct dp_aux dp_aux;
|
||||
struct dp_catalog_aux *catalog;
|
||||
struct dp_aux_cfg *cfg;
|
||||
#if !defined(CONFIG_SECDP)
|
||||
struct device_node *aux_switch_node;
|
||||
#else
|
||||
struct secdp_misc *sec;
|
||||
#endif
|
||||
struct mutex mutex;
|
||||
struct completion comp;
|
||||
struct drm_dp_aux drm_aux;
|
||||
@ -104,9 +114,11 @@ static void dp_aux_hex_dump(struct drm_dp_aux *drm_aux,
|
||||
int i, linelen, remaining = msg->size;
|
||||
const int rowsize = 16;
|
||||
u8 linebuf[64];
|
||||
#if !defined(CONFIG_SECDP)
|
||||
struct dp_aux_private *aux = container_of(drm_aux,
|
||||
struct dp_aux_private, drm_aux);
|
||||
struct dp_aux *dp_aux = &aux->dp_aux;
|
||||
#endif
|
||||
|
||||
snprintf(prefix, sizeof(prefix), "%s %s %4xh(%2zu): ",
|
||||
(msg->request & DP_AUX_I2C_MOT) ? "I2C" : "NAT",
|
||||
@ -120,10 +132,12 @@ static void dp_aux_hex_dump(struct drm_dp_aux *drm_aux,
|
||||
hex_dump_to_buffer(msg->buffer + i, linelen, rowsize, 1,
|
||||
linebuf, sizeof(linebuf), false);
|
||||
|
||||
#if !defined(CONFIG_SECDP)
|
||||
if (msg->size == 1 && msg->address == 0)
|
||||
DP_DEBUG_V("%s%s\n", prefix, linebuf);
|
||||
else
|
||||
DP_AUX_DEBUG(dp_aux, "%s%s\n", prefix, linebuf);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -209,6 +223,21 @@ static u32 dp_aux_write(struct dp_aux_private *aux,
|
||||
return len;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
#define DDC_SEGMENT_ADDR 0x30
|
||||
|
||||
static bool secdp_check_seg_addr(struct dp_aux_private *aux,
|
||||
struct drm_dp_aux_msg *msg)
|
||||
{
|
||||
if (msg->address == DDC_SEGMENT_ADDR &&
|
||||
!(msg->request & DP_AUX_I2C_READ) &&
|
||||
msg->size == 1)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int dp_aux_cmd_fifo_tx(struct dp_aux_private *aux,
|
||||
struct drm_dp_aux_msg *msg)
|
||||
{
|
||||
@ -239,6 +268,15 @@ static int dp_aux_cmd_fifo_tx(struct dp_aux_private *aux,
|
||||
if (aux->aux_error_num == DP_AUX_ERR_NONE) {
|
||||
ret = len;
|
||||
} else {
|
||||
#if defined(CONFIG_SECDP)
|
||||
if (secdp_check_seg_addr(aux, msg)) {
|
||||
DP_AUX_ERR(dp_aux, "ignore %s during [%s]\n",
|
||||
dp_aux_get_error(aux->aux_error_num), prefix);
|
||||
aux->aux_error_num = DP_AUX_ERR_NONE;
|
||||
return msg->size;
|
||||
}
|
||||
#endif
|
||||
|
||||
DP_AUX_WARN_RATELIMITED(dp_aux, "aux err [%s] during [%s]\n",
|
||||
dp_aux_get_error(aux->aux_error_num), prefix);
|
||||
ret = -EINVAL;
|
||||
@ -298,6 +336,13 @@ static void dp_aux_native_handler(struct dp_aux_private *aux)
|
||||
aux->catalog->clear_hw_interrupts(aux->catalog);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECDP_BIGDATA)
|
||||
if (aux->aux_error_num == DP_AUX_ERR_NONE)
|
||||
secdp_bigdata_clr_error_cnt(ERR_AUX);
|
||||
else
|
||||
secdp_bigdata_inc_error_cnt(ERR_AUX);
|
||||
#endif
|
||||
|
||||
complete(&aux->comp);
|
||||
}
|
||||
|
||||
@ -327,6 +372,13 @@ static void dp_aux_i2c_handler(struct dp_aux_private *aux)
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECDP_BIGDATA)
|
||||
if (aux->aux_error_num == DP_AUX_ERR_NONE)
|
||||
secdp_bigdata_clr_error_cnt(ERR_AUX);
|
||||
else
|
||||
secdp_bigdata_inc_error_cnt(ERR_AUX);
|
||||
#endif
|
||||
|
||||
complete(&aux->comp);
|
||||
}
|
||||
|
||||
@ -558,6 +610,20 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *drm_aux,
|
||||
|
||||
ret = dp_aux_cmd_fifo_tx(aux, msg);
|
||||
if ((ret < 0) && !atomic_read(&aux->aborted)) {
|
||||
#if defined(CONFIG_SECDP)
|
||||
if (!secdp_get_cable_status() || !secdp_get_hpd_status()) {
|
||||
DP_INFO("hpd_low or cable_lost %d\n", ret);
|
||||
/*
|
||||
* don't need to repeat aux.
|
||||
* exit loop in drm_dp_dpcd_access()
|
||||
*/
|
||||
msg->reply = aux->native ?
|
||||
DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK;
|
||||
ret = msg->size;
|
||||
aux->retry_cnt = 0;
|
||||
goto unlock_exit;
|
||||
}
|
||||
#endif
|
||||
aux->retry_cnt++;
|
||||
if (!(aux->retry_cnt % retry_count))
|
||||
aux->catalog->update_aux_cfg(aux->catalog,
|
||||
@ -876,10 +942,15 @@ end:
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(CONFIG_SECDP)
|
||||
struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog,
|
||||
struct dp_parser *parser, struct device_node *aux_switch,
|
||||
struct dp_aux_bridge *aux_bridge, void *ipc_log_context,
|
||||
enum dp_aux_switch_type switch_type)
|
||||
struct dp_aux_bridge *aux_bridge, void *ipc_log_context)
|
||||
#else
|
||||
struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog,
|
||||
struct dp_parser *parser, struct device_node *aux_switch,
|
||||
struct dp_aux_bridge *aux_bridge, void *ipc_log_context, void *sec)
|
||||
#endif
|
||||
{
|
||||
int rc = 0;
|
||||
struct dp_aux_private *aux;
|
||||
@ -904,7 +975,11 @@ struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog,
|
||||
aux->dev = dev;
|
||||
aux->catalog = catalog;
|
||||
aux->cfg = parser->aux_cfg;
|
||||
#if !defined(CONFIG_SECDP)
|
||||
aux->aux_switch_node = aux_switch;
|
||||
#else
|
||||
aux->sec = (struct secdp_misc *)sec;
|
||||
#endif
|
||||
aux->aux_bridge = aux_bridge;
|
||||
dp_aux = &aux->dp_aux;
|
||||
aux->retry_cnt = 0;
|
||||
@ -920,24 +995,6 @@ struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog,
|
||||
dp_aux->set_sim_mode = dp_aux_set_sim_mode;
|
||||
dp_aux->ipc_log_context = ipc_log_context;
|
||||
|
||||
/*Condition to avoid allocating function pointers for aux bypass mode*/
|
||||
if (switch_type != DP_AUX_SWITCH_BYPASS) {
|
||||
#if IS_ENABLED(CONFIG_QCOM_FSA4480_I2C)
|
||||
if (switch_type == DP_AUX_SWITCH_FSA4480) {
|
||||
dp_aux->switch_configure = dp_aux_configure_fsa_switch;
|
||||
dp_aux->switch_register_notifier = fsa4480_reg_notifier;
|
||||
dp_aux->switch_unregister_notifier = fsa4480_unreg_notifier;
|
||||
}
|
||||
#endif
|
||||
#if IS_ENABLED(CONFIG_QCOM_WCD939X_I2C)
|
||||
if (switch_type == DP_AUX_SWITCH_WCD939x) {
|
||||
dp_aux->switch_configure = dp_aux_configure_wcd_switch;
|
||||
dp_aux->switch_register_notifier = wcd_usbss_reg_notifier;
|
||||
dp_aux->switch_unregister_notifier = wcd_usbss_unreg_notifier;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return dp_aux;
|
||||
error:
|
||||
return ERR_PTR(rc);
|
||||
|
@ -68,10 +68,15 @@ struct dp_aux {
|
||||
int (*switch_unregister_notifier)(struct notifier_block *nb, struct device_node *node);
|
||||
};
|
||||
|
||||
#if !defined(CONFIG_SECDP)
|
||||
struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog,
|
||||
struct dp_parser *parser, struct device_node *aux_switch,
|
||||
struct dp_aux_bridge *aux_bridge, void *ipc_log_context,
|
||||
enum dp_aux_switch_type switch_type);
|
||||
struct dp_aux_bridge *aux_bridge, void *ipc_log_context);
|
||||
#else
|
||||
struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog,
|
||||
struct dp_parser *parser, struct device_node *aux_switch,
|
||||
struct dp_aux_bridge *aux_bridge, void *ipc_log_context, void *sec);
|
||||
#endif
|
||||
void dp_aux_put(struct dp_aux *aux);
|
||||
|
||||
#endif /*__DP_AUX_H_*/
|
||||
|
@ -12,6 +12,9 @@
|
||||
#include "dp_reg.h"
|
||||
#include "dp_debug.h"
|
||||
#include "dp_link.h"
|
||||
#if defined(CONFIG_SECDP)
|
||||
#include "secdp.h"
|
||||
#endif
|
||||
|
||||
#define DP_GET_MSB(x) (x >> 8)
|
||||
#define DP_GET_LSB(x) (x & 0xff)
|
||||
@ -166,6 +169,11 @@ static u32 dp_read_hw(struct dp_catalog_private *catalog,
|
||||
{
|
||||
u32 data = 0;
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
if (secdp_phy_reset_check())
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
data = readl_relaxed(io_data->io.base + offset);
|
||||
|
||||
return data;
|
||||
@ -174,6 +182,11 @@ static u32 dp_read_hw(struct dp_catalog_private *catalog,
|
||||
static void dp_write_hw(struct dp_catalog_private *catalog,
|
||||
struct dp_io_data *io_data, u32 offset, u32 data)
|
||||
{
|
||||
#if defined(CONFIG_SECDP)
|
||||
if (secdp_phy_reset_check())
|
||||
return;
|
||||
#endif
|
||||
|
||||
writel_relaxed(data, io_data->io.base + offset);
|
||||
}
|
||||
|
||||
@ -290,7 +303,16 @@ static int dp_catalog_aux_clear_trans(struct dp_catalog_aux *aux, bool read)
|
||||
|
||||
if (read) {
|
||||
data = dp_read(DP_AUX_TRANS_CTRL);
|
||||
#if defined(CONFIG_SECDP)
|
||||
/* Prevent_CXX Major defect - Invalid Assignment: The type size
|
||||
* of both side variables are different:
|
||||
* "data" is 4 ( unsigned int ) and "data & 0xfffffffffffffdffUL
|
||||
* " is 8 ( unsigned long )
|
||||
*/
|
||||
data &= ((u32)~BIT(9));
|
||||
#else
|
||||
data &= ~BIT(9);
|
||||
#endif
|
||||
dp_write(DP_AUX_TRANS_CTRL, data);
|
||||
} else {
|
||||
dp_write(DP_AUX_TRANS_CTRL, 0);
|
||||
@ -314,6 +336,10 @@ static void dp_catalog_aux_clear_hw_interrupts(struct dp_catalog_aux *aux)
|
||||
io_data = catalog->io.dp_phy;
|
||||
|
||||
data = dp_read(DP_PHY_AUX_INTERRUPT_STATUS);
|
||||
#if defined(CONFIG_SECDP)
|
||||
if (data)
|
||||
DP_DEBUG("PHY_AUX_INTERRUPT_STATUS=0x%08x\n", data);
|
||||
#endif
|
||||
|
||||
dp_write(DP_PHY_AUX_INTERRUPT_CLEAR, 0x1f);
|
||||
wmb(); /* make sure 0x1f is written before next write */
|
||||
@ -390,6 +416,13 @@ static void dp_catalog_aux_update_cfg(struct dp_catalog_aux *aux,
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
if (!secdp_get_cable_status()) {
|
||||
DP_INFO("cable is out\n");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
catalog = dp_catalog_get_priv(aux);
|
||||
|
||||
io_data = catalog->io.dp_phy;
|
||||
@ -1682,7 +1715,9 @@ static void dp_catalog_panel_dp_flush(struct dp_catalog_panel *panel,
|
||||
static void dp_catalog_panel_pps_flush(struct dp_catalog_panel *panel)
|
||||
{
|
||||
dp_catalog_panel_dp_flush(panel, DP_PPS_FLUSH);
|
||||
#if !defined(CONFIG_SECDP)
|
||||
DP_DEBUG("pps flush for stream:%d\n", panel->stream_id);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void dp_catalog_panel_dhdr_flush(struct dp_catalog_panel *panel)
|
||||
@ -1956,6 +1991,22 @@ static void dp_catalog_ctrl_update_vx_px(struct dp_catalog_ctrl *ctrl,
|
||||
value1 = vm_pre_emphasis[v_level][p_level];
|
||||
}
|
||||
|
||||
#if defined(SECDP_SELF_TEST)
|
||||
if (secdp_self_test_status(ST_VOLTAGE_TUN) >= 0) {
|
||||
u8 val = secdp_self_test_get_arg(ST_VOLTAGE_TUN)[v_level*4 + p_level];
|
||||
|
||||
DP_INFO("[vx] value0: %02x => %02x\n", value0, val);
|
||||
value0 = val;
|
||||
}
|
||||
|
||||
if (secdp_self_test_status(ST_PREEM_TUN) >= 0) {
|
||||
u8 val = secdp_self_test_get_arg(ST_PREEM_TUN)[v_level*4 + p_level];
|
||||
|
||||
DP_INFO("[px] value0: %02x => %02x\n", value1, val);
|
||||
value1 = val;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* program default setting first */
|
||||
|
||||
io_data = catalog->io.dp_ln_tx0;
|
||||
@ -2956,6 +3007,10 @@ static int dp_catalog_init(struct device *dev, struct dp_catalog *dp_catalog,
|
||||
struct dp_catalog_private *catalog = container_of(dp_catalog,
|
||||
struct dp_catalog_private, dp_catalog);
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
dp_catalog->parser = parser;
|
||||
#endif
|
||||
|
||||
if (parser->hw_cfg.phy_version >= DP_PHY_VERSION_4_2_0)
|
||||
dp_catalog->sub = dp_catalog_get_v420(dev, dp_catalog, &catalog->io);
|
||||
else if (parser->hw_cfg.phy_version == DP_PHY_VERSION_2_0_0)
|
||||
|
@ -292,6 +292,10 @@ struct dp_catalog {
|
||||
|
||||
struct dp_catalog_sub *sub;
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
struct dp_parser *parser;
|
||||
#endif
|
||||
|
||||
void (*set_exe_mode)(struct dp_catalog *dp_catalog, char *mode);
|
||||
int (*get_reg_dump)(struct dp_catalog *dp_catalog,
|
||||
char *mode, u8 **out_buf, u32 *out_buf_len);
|
||||
@ -373,4 +377,28 @@ struct dp_catalog_sub *dp_catalog_get_v200(struct device *dev,
|
||||
|
||||
u32 dp_catalog_get_dp_core_version(struct dp_catalog *dp_catalog);
|
||||
u32 dp_catalog_get_dp_phy_version(struct dp_catalog *dp_catalog);
|
||||
|
||||
#if defined(CONFIG_SECDP_DBG)
|
||||
enum secdp_hw_preshoot_t {
|
||||
DP_HW_PRESHOOT_0,
|
||||
DP_HW_PRESHOOT_1,
|
||||
DP_HW_PRESHOOT_MAX,
|
||||
};
|
||||
|
||||
static inline char *secdp_preshoot_to_string(int hw)
|
||||
{
|
||||
switch (hw) {
|
||||
case DP_HW_PRESHOOT_0:
|
||||
return DP_ENUM_STR(DP_HW_PRESHOOT_0);
|
||||
case DP_HW_PRESHOOT_1:
|
||||
return DP_ENUM_STR(DP_HW_PRESHOOT_1);
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
int secdp_catalog_preshoot_show(struct dp_catalog *catalog, char *buf);
|
||||
void secdp_catalog_preshoot_store(struct dp_catalog *catalog, char *buf);
|
||||
#endif/*CONFIG_SECDP_DBG*/
|
||||
|
||||
#endif /* _DP_CATALOG_H_ */
|
||||
|
@ -12,6 +12,10 @@
|
||||
#include <linux/rational.h>
|
||||
#include <drm/drm_fixed.h>
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
#include "secdp.h"
|
||||
#endif
|
||||
|
||||
#define dp_catalog_get_priv_v420(x) ({ \
|
||||
struct dp_catalog *catalog; \
|
||||
catalog = container_of(x, struct dp_catalog, x); \
|
||||
@ -50,8 +54,95 @@ struct dp_catalog_private_v420 {
|
||||
struct dp_catalog_sub sub;
|
||||
struct dp_catalog_io *io;
|
||||
struct dp_catalog *dpc;
|
||||
|
||||
#if defined(CONFIG_SECDP_DBG)
|
||||
char preshoot[DP_HW_PRESHOOT_MAX];
|
||||
#endif
|
||||
};
|
||||
|
||||
#if defined(CONFIG_SECDP_DBG)
|
||||
int secdp_catalog_preshoot_show(struct dp_catalog *catalog, char *buf)
|
||||
{
|
||||
struct dp_catalog_private_v420 *catalog_priv;
|
||||
int rc = 0;
|
||||
|
||||
catalog_priv = container_of(catalog->sub,
|
||||
struct dp_catalog_private_v420, sub);
|
||||
|
||||
rc += scnprintf(buf + rc, PAGE_SIZE - rc,
|
||||
"%02x %02x\n",
|
||||
catalog_priv->preshoot[DP_HW_PRESHOOT_0],
|
||||
catalog_priv->preshoot[DP_HW_PRESHOOT_1]);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void secdp_catalog_preshoot_store(struct dp_catalog *catalog, char *buf)
|
||||
{
|
||||
struct dp_catalog_private_v420 *catalog_priv;
|
||||
char *tok;
|
||||
u32 value;
|
||||
int i, rc = 0;
|
||||
|
||||
catalog_priv = container_of(catalog->sub,
|
||||
struct dp_catalog_private_v420, sub);
|
||||
|
||||
for (i = 0; i < DP_HW_PRESHOOT_MAX; i++) {
|
||||
tok = strsep(&buf, ",");
|
||||
if (!tok)
|
||||
continue;
|
||||
|
||||
rc = kstrtouint(tok, 16, &value);
|
||||
if (rc) {
|
||||
DP_ERR("error: %s rc:%d\n", tok, rc);
|
||||
goto end;
|
||||
}
|
||||
|
||||
catalog_priv->preshoot[i] = value;
|
||||
}
|
||||
end:
|
||||
return;
|
||||
}
|
||||
|
||||
static void _secdp_catalog_preshoot_init(struct dp_catalog_private_v420 *catalog)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < DP_HW_PRESHOOT_MAX; i++)
|
||||
catalog->preshoot[i] = 0xff;
|
||||
}
|
||||
|
||||
static void _secdp_catalog_preshoot_adjust(
|
||||
struct dp_catalog_private_v420 *catalog)
|
||||
{
|
||||
struct dp_io_data *io_data;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < DP_HW_PRESHOOT_MAX; i++) {
|
||||
if (catalog->preshoot[i] != 0xff) {
|
||||
if (i == DP_HW_PRESHOOT_0)
|
||||
io_data = catalog->io->dp_ln_tx0;
|
||||
else if (i == DP_HW_PRESHOOT_1)
|
||||
io_data = catalog->io->dp_ln_tx1;
|
||||
else
|
||||
DP_ERR("cannot be here\n");
|
||||
|
||||
catalog->preshoot[i] |= BIT(5);
|
||||
|
||||
/*
|
||||
* USB3_DP_PHY_DP_QSERDES_TX0_PRE_EMPH
|
||||
* USB3_DP_PHY_DP_QSERDES_TX1_PRE_EMPH
|
||||
*/
|
||||
dp_write(0x108, catalog->preshoot[i]);
|
||||
|
||||
DP_INFO("%s 0x%02x write done!\n",
|
||||
secdp_preshoot_to_string(i),
|
||||
catalog->preshoot[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif/*CONFIG_SECDP_DBG*/
|
||||
|
||||
static void dp_catalog_aux_setup_v420(struct dp_catalog_aux *aux,
|
||||
struct dp_aux_cfg *cfg)
|
||||
{
|
||||
@ -248,6 +339,22 @@ static void dp_catalog_ctrl_update_vx_px_v420(struct dp_catalog_ctrl *ctrl,
|
||||
value1 = vm_pre_emphasis[v_level][p_level];
|
||||
}
|
||||
|
||||
#if defined(SECDP_SELF_TEST)
|
||||
if (secdp_self_test_status(ST_VOLTAGE_TUN) >= 0) {
|
||||
u8 val = secdp_self_test_get_arg(ST_VOLTAGE_TUN)[v_level*4 + p_level];
|
||||
|
||||
DP_INFO("[vx] value0: 0x%02x => 0x%02x\n", value0, val);
|
||||
value0 = val;
|
||||
}
|
||||
|
||||
if (secdp_self_test_status(ST_PREEM_TUN) >= 0) {
|
||||
u8 val = secdp_self_test_get_arg(ST_PREEM_TUN)[v_level*4 + p_level];
|
||||
|
||||
DP_INFO("[px] value0: 0x%02x => 0x%02x\n", value1, val);
|
||||
value1 = val;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* program default setting first */
|
||||
io_data = catalog->io->dp_ln_tx0;
|
||||
dp_write(TXn_TX_DRV_LVL_V420, 0x2A);
|
||||
@ -277,6 +384,10 @@ static void dp_catalog_ctrl_update_vx_px_v420(struct dp_catalog_ctrl *ctrl,
|
||||
DP_ERR("invalid vx (0x%x=0x%x), px (0x%x=0x%x\n",
|
||||
v_level, value0, p_level, value1);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECDP_DBG)
|
||||
_secdp_catalog_preshoot_adjust(catalog);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void dp_catalog_ctrl_lane_pnswap_v420(struct dp_catalog_ctrl *ctrl,
|
||||
@ -335,6 +446,10 @@ struct dp_catalog_sub *dp_catalog_get_v420(struct device *dev,
|
||||
|
||||
catalog_priv->sub.put = dp_catalog_put_v420;
|
||||
|
||||
#if defined(CONFIG_SECDP_DBG)
|
||||
_secdp_catalog_preshoot_init(catalog_priv);
|
||||
#endif
|
||||
|
||||
catalog->aux.setup = dp_catalog_aux_setup_v420;
|
||||
catalog->aux.clear_hw_interrupts = dp_catalog_aux_clear_hw_int_v420;
|
||||
catalog->panel.config_msa = dp_catalog_panel_config_msa_v420;
|
||||
|
@ -13,6 +13,12 @@
|
||||
#include "dp_ctrl.h"
|
||||
#include "dp_debug.h"
|
||||
#include "sde_dbg.h"
|
||||
#if defined(CONFIG_SECDP)
|
||||
#if defined(CONFIG_SECDP_BIGDATA)
|
||||
#include <linux/secdp_bigdata.h>
|
||||
#endif
|
||||
#include "secdp.h"
|
||||
#endif
|
||||
|
||||
#define DP_MST_DEBUG(fmt, ...) DP_DEBUG(fmt, ##__VA_ARGS__)
|
||||
|
||||
@ -65,6 +71,10 @@ struct dp_ctrl_private {
|
||||
struct dp_parser *parser;
|
||||
struct dp_catalog_ctrl *catalog;
|
||||
struct dp_pll *pll;
|
||||
#if defined(CONFIG_SECDP)
|
||||
struct secdp_misc *sec;
|
||||
bool link_train_status;
|
||||
#endif
|
||||
|
||||
struct completion idle_comp;
|
||||
struct completion video_comp;
|
||||
@ -243,6 +253,11 @@ static void dp_ctrl_update_hw_vx_px(struct dp_ctrl_private *ctrl)
|
||||
ctrl->link->link_params.bw_code == DP_LINK_BW_8_1)
|
||||
high = true;
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
secdp_redriver_linkinfo(ctrl->power, link->link_params.bw_code,
|
||||
link->phy_params.v_level, link->phy_params.p_level);
|
||||
#endif
|
||||
|
||||
ctrl->catalog->update_vx_px(ctrl->catalog,
|
||||
link->phy_params.v_level, link->phy_params.p_level, high);
|
||||
}
|
||||
@ -457,6 +472,11 @@ static int dp_ctrl_link_rate_down_shift(struct dp_ctrl_private *ctrl)
|
||||
|
||||
DP_DEBUG("new bw code=0x%x\n", ctrl->link->link_params.bw_code);
|
||||
|
||||
#if defined(CONFIG_SECDP_BIGDATA)
|
||||
secdp_bigdata_save_item(BD_CUR_LINK_RATE,
|
||||
ctrl->link->link_params.bw_code);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -561,9 +581,26 @@ static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl)
|
||||
u8 const encoding = 0x1, downspread = 0x00;
|
||||
struct drm_dp_link link_info = {0};
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
if (!secdp_get_cable_status()) {
|
||||
DP_INFO("cable is out\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
DP_ENTER("\n");
|
||||
ctrl->link_train_status = false;
|
||||
#endif
|
||||
|
||||
ctrl->link->phy_params.p_level = 0;
|
||||
ctrl->link->phy_params.v_level = 0;
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
if (secdp_check_hmd_dev(ctrl->sec, "PicoVR")) {
|
||||
DP_INFO("pico REAL Plus!\n");
|
||||
ctrl->link->phy_params.v_level = 2; /*800mV*/
|
||||
}
|
||||
#endif
|
||||
|
||||
link_info.num_lanes = ctrl->link->link_params.lane_count;
|
||||
link_info.rate = drm_dp_bw_code_to_link_rate(
|
||||
ctrl->link->link_params.bw_code);
|
||||
@ -609,11 +646,22 @@ static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl)
|
||||
DP_INFO("link training #2 successful\n");
|
||||
|
||||
end:
|
||||
#if defined(CONFIG_SECDP)
|
||||
if (!secdp_get_cable_status()) {
|
||||
DP_INFO("cable is out <2>\n");
|
||||
return -EIO;
|
||||
}
|
||||
#endif
|
||||
|
||||
dp_ctrl_state_ctrl(ctrl, 0);
|
||||
/* Make sure to clear the current pattern before starting a new one */
|
||||
wmb();
|
||||
|
||||
dp_ctrl_clear_training_pattern(ctrl);
|
||||
#if defined(CONFIG_SECDP)
|
||||
if (!ret)
|
||||
ctrl->link_train_status = true;
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -636,7 +684,10 @@ static int dp_ctrl_setup_main_link(struct dp_ctrl_private *ctrl)
|
||||
0x01);
|
||||
|
||||
ret = dp_ctrl_link_train(ctrl);
|
||||
|
||||
#if defined(CONFIG_SECDP_BIGDATA)
|
||||
if (ret)
|
||||
secdp_bigdata_inc_error_cnt(ERR_LINK_TRAIN);
|
||||
#endif
|
||||
end:
|
||||
return ret;
|
||||
}
|
||||
@ -722,6 +773,13 @@ static void dp_ctrl_select_training_pattern(struct dp_ctrl_private *ctrl,
|
||||
else
|
||||
pattern = DP_TRAINING_PATTERN_2;
|
||||
|
||||
#ifdef SECDP_MAX_HBR2
|
||||
if (pattern == DP_TRAINING_PATTERN_4) {
|
||||
DP_INFO("TPS4 to TPS3\n");
|
||||
downgrade = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!downgrade)
|
||||
goto end;
|
||||
|
||||
@ -754,6 +812,13 @@ static int dp_ctrl_link_setup(struct dp_ctrl_private *ctrl, bool shallow)
|
||||
link_params->lane_count);
|
||||
|
||||
while (1) {
|
||||
#if defined(CONFIG_SECDP)
|
||||
if (!secdp_get_cable_status()) {
|
||||
DP_INFO("cable is out\n");
|
||||
rc = -EIO;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
DP_DEBUG("bw_code=%d, lane_count=%d\n",
|
||||
link_params->bw_code, link_params->lane_count);
|
||||
|
||||
@ -793,6 +858,14 @@ static int dp_ctrl_link_setup(struct dp_ctrl_private *ctrl, bool shallow)
|
||||
break;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECDP) && !defined(SECDP_AUDIO_CTS)
|
||||
if ((ctrl->link->link_params.bw_code == DP_LINK_BW_1_62 && downgrade) ||
|
||||
!secdp_get_cable_status()) {
|
||||
rc = -EIO;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!link_train_max_retries || atomic_read(&ctrl->aborted)) {
|
||||
dp_ctrl_disable_link_clock(ctrl);
|
||||
break;
|
||||
@ -1384,6 +1457,16 @@ static void dp_ctrl_stream_off(struct dp_ctrl *dp_ctrl, struct dp_panel *panel)
|
||||
ctrl->stream_count--;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
bool secdp_get_link_train_status(struct dp_ctrl *dp_ctrl)
|
||||
{
|
||||
struct dp_ctrl_private *ctrl;
|
||||
|
||||
ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
|
||||
return ctrl->link_train_status;
|
||||
}
|
||||
#endif/*CONFIG_SECDP*/
|
||||
|
||||
static int dp_ctrl_on(struct dp_ctrl *dp_ctrl, bool mst_mode,
|
||||
bool fec_mode, bool dsc_mode, bool shallow)
|
||||
{
|
||||
@ -1417,6 +1500,10 @@ static int dp_ctrl_on(struct dp_ctrl *dp_ctrl, bool mst_mode,
|
||||
if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) {
|
||||
DP_DEBUG("using phy test link parameters\n");
|
||||
} else {
|
||||
#ifdef SECDP_OPTIMAL_LINK_RATE
|
||||
if (!ctrl->panel->tbox)
|
||||
rate = secdp_gen_link_clk(ctrl->panel);
|
||||
#endif
|
||||
ctrl->link->link_params.bw_code =
|
||||
drm_dp_link_rate_to_bw_code(rate);
|
||||
ctrl->link->link_params.lane_count =
|
||||
@ -1575,6 +1662,9 @@ struct dp_ctrl *dp_ctrl_get(struct dp_ctrl_in *in)
|
||||
ctrl->aux = in->aux;
|
||||
ctrl->link = in->link;
|
||||
ctrl->catalog = in->catalog;
|
||||
#if defined(CONFIG_SECDP)
|
||||
ctrl->sec = in->sec;
|
||||
#endif
|
||||
ctrl->pll = in->pll;
|
||||
ctrl->dev = in->dev;
|
||||
ctrl->mst_mode = false;
|
||||
|
@ -46,9 +46,16 @@ struct dp_ctrl_in {
|
||||
struct dp_power *power;
|
||||
struct dp_catalog_ctrl *catalog;
|
||||
struct dp_pll *pll;
|
||||
#if defined(CONFIG_SECDP)
|
||||
struct secdp_misc *sec;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct dp_ctrl *dp_ctrl_get(struct dp_ctrl_in *in);
|
||||
void dp_ctrl_put(struct dp_ctrl *dp_ctrl);
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
bool secdp_get_link_train_status(struct dp_ctrl *dp_ctrl);
|
||||
#endif
|
||||
|
||||
#endif /* _DP_CTRL_H_ */
|
||||
|
@ -25,6 +25,9 @@
|
||||
#include "dp_hpd.h"
|
||||
#include "dp_mst_sim.h"
|
||||
#include "dp_mst_drm.h"
|
||||
#if defined(CONFIG_SECDP)
|
||||
#include "secdp.h"
|
||||
#endif
|
||||
|
||||
#define DEBUG_NAME "drm_dp"
|
||||
|
||||
@ -161,6 +164,16 @@ static ssize_t dp_debug_write_edid(struct file *file,
|
||||
if (copy_from_user(buf, user_buff, size))
|
||||
goto bail;
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
if (!strncmp(buf, "reset", 5)) {
|
||||
DP_DEBUG("disable SIM_MODE_EDID\n");
|
||||
dp_debug_disable_sim_mode(debug, DP_SIM_MODE_EDID);
|
||||
kfree(buf);
|
||||
mutex_unlock(&debug->lock);
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
edid_size = size / char_to_nib;
|
||||
buf_t = buf;
|
||||
size = edid_size;
|
||||
|
@ -45,6 +45,7 @@
|
||||
DP_ERR_V(fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#if !defined(CONFIG_SECDP)
|
||||
#define DP_DEBUG_V(fmt, ...) \
|
||||
do { \
|
||||
if (drm_debug_enabled(DRM_UT_KMS)) \
|
||||
@ -80,6 +81,47 @@
|
||||
#define DP_ERR_RATELIMITED_V(fmt, ...) \
|
||||
pr_err_ratelimited("[drm:%s][msm-dp-err][%-4d]"fmt, __func__, \
|
||||
current->pid, ##__VA_ARGS__)
|
||||
#else
|
||||
#define DP_DEBUG_V(fmt, ...) \
|
||||
do { \
|
||||
if (drm_debug_enabled(DRM_UT_KMS)) \
|
||||
DRM_DEBUG("[msm-dp-debug][%-4d]"fmt, current->pid, \
|
||||
##__VA_ARGS__); \
|
||||
else \
|
||||
pr_debug(fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define DP_INFO_V(fmt, ...) \
|
||||
do { \
|
||||
if (drm_debug_enabled(DRM_UT_KMS)) \
|
||||
DRM_INFO("[msm-dp-info][%-4d]"fmt, current->pid, \
|
||||
##__VA_ARGS__); \
|
||||
else \
|
||||
pr_info(fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define DP_WARN_V(fmt, ...) pr_warn(fmt, ##__VA_ARGS__)
|
||||
#define DP_WARN_RATELIMITED_V(fmt, ...) pr_warn(fmt, ##__VA_ARGS__)
|
||||
#define DP_ERR_V(fmt, ...) pr_err(fmt, ##__VA_ARGS__)
|
||||
#define DP_ERR_RATELIMITED_V(fmt, ...) pr_err(fmt, ##__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SECDP_DBG)
|
||||
extern bool secdp_func_trace;
|
||||
#define DP_ENTER(fmt, ...) \
|
||||
do { \
|
||||
if (secdp_func_trace) \
|
||||
pr_debug("+++ " pr_fmt(fmt), ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
#define DP_LEAVE(fmt, ...) \
|
||||
do { \
|
||||
if (secdp_func_trace) \
|
||||
pr_debug("--- " pr_fmt(fmt), ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
#else
|
||||
#define DP_ENTER(fmt, ...) do {} while (0)
|
||||
#define DP_LEAVE(fmt, ...) do {} while (0)
|
||||
#endif
|
||||
|
||||
#define DEFAULT_DISCONNECT_DELAY_MS 0
|
||||
#define MAX_DISCONNECT_DELAY_MS 10000
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -141,4 +141,11 @@ static inline int dp_display_mmrm_callback(struct mmrm_client_notifier_data *not
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_DRM_MSM_DP */
|
||||
|
||||
#if defined(CONFIG_SECDP_DBG)
|
||||
int secdp_debug_set_ssc(struct secdp_misc *sec, bool onoff);
|
||||
bool secdp_debug_get_ssc(struct secdp_misc *sec);
|
||||
int secdp_show_hmd_dev(struct secdp_misc *sec, char *buf);
|
||||
#endif/*CONFIG_SECDP_DBG*/
|
||||
|
||||
#endif /* _DP_DISPLAY_H_ */
|
||||
|
@ -14,6 +14,9 @@
|
||||
#include "dp_drm.h"
|
||||
#include "dp_mst_drm.h"
|
||||
#include "dp_debug.h"
|
||||
#if defined(CONFIG_SECDP)
|
||||
#include "secdp.h"
|
||||
#endif
|
||||
|
||||
#define DP_MST_DEBUG(fmt, ...) DP_DEBUG(fmt, ##__VA_ARGS__)
|
||||
|
||||
|
@ -15,6 +15,9 @@
|
||||
#include <linux/of_gpio.h>
|
||||
#include "dp_gpio_hpd.h"
|
||||
#include "dp_debug.h"
|
||||
#if defined(CONFIG_SECDP)
|
||||
#include "secdp.h"
|
||||
#endif
|
||||
|
||||
struct dp_gpio_hpd_private {
|
||||
struct device *dev;
|
||||
|
@ -22,6 +22,10 @@
|
||||
#include "sde_hdcp_2x.h"
|
||||
#include "dp_debug.h"
|
||||
|
||||
#if defined(CONFIG_SECDP_DBG)
|
||||
#include <linux/secdp_logger.h>
|
||||
#endif
|
||||
|
||||
#define DP_INTR_STATUS2 (0x00000024)
|
||||
#define DP_INTR_STATUS3 (0x00000028)
|
||||
#define dp_read(offset) readl_relaxed((offset))
|
||||
@ -655,6 +659,10 @@ static int dp_hdcp2p2_read_rx_status(struct dp_hdcp2p2_ctrl *ctrl,
|
||||
}
|
||||
|
||||
cp_irq = buf & BIT(2);
|
||||
#ifdef SECDP_TEST_HDCP2P2_REAUTH
|
||||
cp_irq = true;
|
||||
DP_DEBUG("[HDCP2P2_REAUTH_TEST]\n");
|
||||
#endif
|
||||
DP_DEBUG("cp_irq=0x%x\n", cp_irq);
|
||||
buf = 0;
|
||||
|
||||
@ -667,6 +675,9 @@ static int dp_hdcp2p2_read_rx_status(struct dp_hdcp2p2_ctrl *ctrl,
|
||||
goto error;
|
||||
}
|
||||
*rx_status = buf;
|
||||
#ifdef SECDP_TEST_HDCP2P2_REAUTH
|
||||
*rx_status = 0x8;
|
||||
#endif
|
||||
DP_DEBUG("rx_status=0x%x\n", *rx_status);
|
||||
}
|
||||
|
||||
@ -792,6 +803,15 @@ static bool dp_hdcp2p2_supported(void *input)
|
||||
goto error;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < DP_HDCP_RXCAPS_LENGTH; i++)
|
||||
DP_DEBUG("rxcaps[%d] 0x%x\n", i, buf[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
DP_DEBUG("HDCP_CAPABLE=%lu\n", (buf[2] & BIT(1)) >> 1);
|
||||
DP_DEBUG("VERSION=%d\n", buf[0]);
|
||||
|
||||
|
@ -16,6 +16,9 @@
|
||||
#include "dp_lphw_hpd.h"
|
||||
#include "dp_debug.h"
|
||||
#include "dp_bridge_hpd.h"
|
||||
#if defined(CONFIG_SECDP)
|
||||
#include "secdp.h"
|
||||
#endif
|
||||
|
||||
static void dp_hpd_host_init(struct dp_hpd *dp_hpd,
|
||||
struct dp_catalog_hpd *catalog)
|
||||
|
@ -26,6 +26,12 @@
|
||||
#include "dp_link.h"
|
||||
#include "dp_panel.h"
|
||||
#include "dp_debug.h"
|
||||
#if defined(CONFIG_SECDP)
|
||||
#include "secdp.h"
|
||||
#if defined(CONFIG_SECDP_BIGDATA)
|
||||
#include <linux/secdp_bigdata.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
enum dynamic_range {
|
||||
DP_DYNAMIC_RANGE_RGB_VESA = 0x00,
|
||||
@ -902,6 +908,12 @@ static void dp_link_parse_sink_status_field(struct dp_link_private *link)
|
||||
link->link_status);
|
||||
if (len < DP_LINK_STATUS_SIZE)
|
||||
DP_ERR("DP link status read failed\n");
|
||||
#if defined(CONFIG_SECDP)
|
||||
else
|
||||
DP_INFO("[202h-207h] %02x-%02x-%02x-%02x-%02x-%02x\n",
|
||||
link->link_status[0], link->link_status[1], link->link_status[2],
|
||||
link->link_status[3], link->link_status[4], link->link_status[5]);
|
||||
#endif
|
||||
dp_link_parse_request(link);
|
||||
}
|
||||
|
||||
@ -1267,6 +1279,106 @@ static void dp_link_reset_data(struct dp_link_private *link)
|
||||
link->dp_link.test_response = 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
bool secdp_get_poor_connection_status(struct dp_link *dp_link)
|
||||
{
|
||||
return dp_link->poor_connection;
|
||||
}
|
||||
|
||||
void secdp_clear_link_status_cnt(struct dp_link *dp_link)
|
||||
{
|
||||
dp_link->poor_connection = false;
|
||||
dp_link->status_update_cnt = 0;
|
||||
}
|
||||
|
||||
/** refer to dp_link_parse_sink_status_field() */
|
||||
void secdp_read_link_status(struct dp_link *dp_link)
|
||||
{
|
||||
struct dp_link_private *link;
|
||||
int len = 0;
|
||||
|
||||
if (!dp_link) {
|
||||
DP_ERR("invalid input\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
link = container_of(dp_link, struct dp_link_private, dp_link);
|
||||
if (!link) {
|
||||
DP_ERR("link is null\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
DP_ENTER("\n");
|
||||
|
||||
len = drm_dp_dpcd_read_link_status(link->aux->drm_aux,
|
||||
link->link_status);
|
||||
if (len < DP_LINK_STATUS_SIZE) {
|
||||
DP_ERR("DP link status read failed %d\n", len);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
DP_INFO("[202h-207h] %02x-%02x-%02x-%02x-%02x-%02x\n",
|
||||
link->link_status[0], link->link_status[1], link->link_status[2],
|
||||
link->link_status[3], link->link_status[4], link->link_status[5]);
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @retval true if connection is stable
|
||||
* @retval false if connection is unstable(poor)
|
||||
*/
|
||||
bool secdp_check_link_stable(struct dp_link *dp_link)
|
||||
{
|
||||
bool stable = false;
|
||||
struct dp_link_private *link;
|
||||
|
||||
if (!dp_link) {
|
||||
DP_ERR("invalid input\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
link = container_of(dp_link, struct dp_link_private, dp_link);
|
||||
if (!link) {
|
||||
DP_ERR("link is null\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!(get_link_status(link->link_status, DP_LANE_ALIGN_STATUS_UPDATED) &
|
||||
DP_INTERLANE_ALIGN_DONE)) {
|
||||
DP_ERR("[204h] interlane_align_done is zero!\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
stable = true;
|
||||
exit:
|
||||
if (stable)
|
||||
DP_DEBUG("DP connection is stable!\n");
|
||||
|
||||
#if defined(CONFIG_SECDP_BIGDATA)
|
||||
if (!stable)
|
||||
secdp_bigdata_inc_error_cnt(ERR_INF_IRQHPD);
|
||||
#endif
|
||||
return stable;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECDP_DBG)
|
||||
int secdp_show_link_param(struct dp_link *dp_link, char *buf)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
rc += scnprintf(buf + rc, PAGE_SIZE - rc,
|
||||
"v_level: %u\np_level: %u\nlane_cnt: %u\nbw_code: 0x%x\n",
|
||||
dp_link->phy_params.v_level,
|
||||
dp_link->phy_params.p_level,
|
||||
dp_link->link_params.lane_count,
|
||||
dp_link->link_params.bw_code);
|
||||
|
||||
return rc;
|
||||
}
|
||||
#endif/*CONFIG_SECDP_DBG*/
|
||||
#endif/*CONFIG_SECDP*/
|
||||
|
||||
/**
|
||||
* dp_link_process_request() - handle HPD IRQ transition to HIGH
|
||||
* @link: pointer to link module data
|
||||
@ -1291,6 +1403,14 @@ static int dp_link_process_request(struct dp_link *dp_link)
|
||||
|
||||
dp_link_parse_sink_status_field(link);
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
if (secdp_get_power_status() && !secdp_check_link_stable(dp_link)) {
|
||||
dp_link->status_update_cnt++;
|
||||
DP_INFO("[link_request] status_update_cnt %d\n",
|
||||
dp_link->status_update_cnt);
|
||||
secdp_link_backoff_start();
|
||||
}
|
||||
#endif
|
||||
if (dp_link_is_test_edid_read(link)) {
|
||||
dp_link->sink_request |= DP_TEST_LINK_EDID_READ;
|
||||
goto exit;
|
||||
|
@ -148,6 +148,11 @@ struct dp_link {
|
||||
u32 sink_request;
|
||||
u32 test_response;
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
bool poor_connection;
|
||||
int status_update_cnt;
|
||||
#endif
|
||||
|
||||
struct dp_link_sink_count sink_count;
|
||||
struct dp_link_test_video test_video;
|
||||
struct dp_link_test_audio test_audio;
|
||||
@ -223,6 +228,9 @@ static inline u32 dp_link_bit_depth_to_bpp(u32 tbd)
|
||||
break;
|
||||
case DP_TEST_BIT_DEPTH_UNKNOWN:
|
||||
default:
|
||||
#if defined(CONFIG_SECDP)
|
||||
pr_debug("%s: tbd(%d)\n", __func__, tbd);
|
||||
#endif
|
||||
bpp = 0;
|
||||
}
|
||||
|
||||
@ -245,4 +253,15 @@ struct dp_link *dp_link_get(struct device *dev, struct dp_aux *aux, u32 dp_core_
|
||||
*/
|
||||
void dp_link_put(struct dp_link *dp_link);
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
void secdp_clear_link_status_cnt(struct dp_link *dp_link);
|
||||
void secdp_read_link_status(struct dp_link *dp_link);
|
||||
bool secdp_check_link_stable(struct dp_link *dp_link);
|
||||
bool secdp_get_poor_connection_status(struct dp_link *dp_link);
|
||||
|
||||
#if defined(CONFIG_SECDP_DBG)
|
||||
int secdp_show_link_param(struct dp_link *dp_link, char *buf);
|
||||
#endif/*CONFIG_SECDP_DBG*/
|
||||
#endif/*CONFIG_SECDP*/
|
||||
|
||||
#endif /* _DP_LINK_H_ */
|
||||
|
@ -52,6 +52,9 @@
|
||||
#include "dp_drm.h"
|
||||
#include "dp_debug.h"
|
||||
#include "dp_parser.h"
|
||||
#if defined(CONFIG_SECDP)
|
||||
#include "secdp.h"
|
||||
#endif
|
||||
|
||||
#define DP_MST_DEBUG(fmt, ...) DP_DEBUG(fmt, ##__VA_ARGS__)
|
||||
#define DP_MST_INFO(fmt, ...) DP_INFO(fmt, ##__VA_ARGS__)
|
||||
@ -334,8 +337,10 @@ static int dp_mst_calc_pbn_mode(struct dp_display_mode *dp_mode)
|
||||
pbn = drm_fixp2int(pbn_fp);
|
||||
pinfo->pbn = pbn;
|
||||
|
||||
#if !defined(CONFIG_SECDP)
|
||||
DP_DEBUG_V("pbn before overhead:%d pbn final:%d, bpp:%d\n", pinfo->pbn_no_overhead, pbn,
|
||||
bpp);
|
||||
#endif
|
||||
|
||||
return pbn;
|
||||
}
|
||||
@ -1225,6 +1230,9 @@ static int dp_mst_connector_get_modes(struct drm_connector *connector,
|
||||
struct dp_display_mode *dp_mode = NULL;
|
||||
int rc = 0;
|
||||
struct edid *edid = NULL;
|
||||
#if defined(CONFIG_SECDP)
|
||||
u8 i;
|
||||
#endif
|
||||
|
||||
DP_MST_DEBUG_V("enter:\n");
|
||||
SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_ENTRY, connector->base.id);
|
||||
@ -1247,6 +1255,14 @@ static int dp_mst_connector_get_modes(struct drm_connector *connector,
|
||||
mutex_lock(&mst->edid_lock);
|
||||
c_conn->cached_edid = edid;
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
for (i = 0; i <= edid->extensions; i++) {
|
||||
print_hex_dump(KERN_DEBUG, "EDID: ", DUMP_PREFIX_NONE, 16, 1,
|
||||
edid + i, EDID_LENGTH, false);
|
||||
secdp_logger_hex_dump(edid + i, "EDID:", EDID_LENGTH);
|
||||
}
|
||||
#endif
|
||||
|
||||
duplicate_edid:
|
||||
|
||||
edid = drm_edid_duplicate(c_conn->cached_edid);
|
||||
@ -1372,8 +1388,10 @@ int dp_mst_connector_get_mode_info(struct drm_connector *connector,
|
||||
rc = dp_connector_get_mode_info(connector, drm_mode, NULL, mode_info,
|
||||
display, avail_res);
|
||||
|
||||
#if !defined(CONFIG_SECDP)
|
||||
DP_MST_DEBUG_V("mst connector:%d get mode info. rc:%d\n",
|
||||
connector->base.id, rc);
|
||||
#endif
|
||||
|
||||
DP_MST_DEBUG_V("exit:\n");
|
||||
SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_EXIT, connector->base.id);
|
||||
|
@ -16,6 +16,13 @@
|
||||
#include "sde_dsc_helper.h"
|
||||
#include <drm/drm_edid.h>
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
#if defined(CONFIG_SECDP_BIGDATA)
|
||||
#include <linux/secdp_bigdata.h>
|
||||
#endif
|
||||
#include "secdp.h"
|
||||
#endif
|
||||
|
||||
#define DP_KHZ_TO_HZ 1000
|
||||
#define DP_PANEL_DEFAULT_BPP 24
|
||||
#define DP_MAX_DS_PORT_COUNT 1
|
||||
@ -73,6 +80,9 @@ struct dp_panel_private {
|
||||
struct dp_parser *parser;
|
||||
struct dp_catalog_panel *catalog;
|
||||
struct dp_panel *base;
|
||||
#if defined(CONFIG_SECDP)
|
||||
struct secdp_misc *sec;
|
||||
#endif
|
||||
bool panel_on;
|
||||
bool vsc_supported;
|
||||
bool vscext_supported;
|
||||
@ -84,12 +94,46 @@ struct dp_panel_private {
|
||||
u8 minor;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
static struct dp_panel *g_dp_panel;
|
||||
|
||||
enum downstream_port_type {
|
||||
DSP_TYPE_DP = 0x00,
|
||||
DSP_TYPE_VGA,
|
||||
DSP_TYPE_DVI_HDMI_DPPP,
|
||||
DSP_TYPE_OTHER,
|
||||
};
|
||||
|
||||
static inline char *mdss_dp_dsp_type_to_string(u32 dsp_type)
|
||||
{
|
||||
switch (dsp_type) {
|
||||
case DSP_TYPE_DP:
|
||||
return DP_ENUM_STR(DSP_TYPE_DP);
|
||||
case DSP_TYPE_VGA:
|
||||
return DP_ENUM_STR(DSP_TYPE_VGA);
|
||||
case DSP_TYPE_DVI_HDMI_DPPP:
|
||||
return DP_ENUM_STR(DSP_TYPE_DVI_HDMI_DPPP);
|
||||
case DSP_TYPE_OTHER:
|
||||
return DP_ENUM_STR(DSP_TYPE_OTHER);
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
/* OEM NAME */
|
||||
static const u8 vendor_name[8] = {'S', 'E', 'C', '.', 'M', 'C', 'B', 0};
|
||||
|
||||
/* MODEL NAME */
|
||||
static const u8 product_desc[16] = {'G', 'A', 'L', 'A', 'X', 'Y', 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0};
|
||||
#else
|
||||
/* OEM NAME */
|
||||
static const u8 vendor_name[8] = {81, 117, 97, 108, 99, 111, 109, 109};
|
||||
|
||||
/* MODEL NAME */
|
||||
static const u8 product_desc[16] = {83, 110, 97, 112, 100, 114, 97, 103,
|
||||
111, 110, 0, 0, 0, 0, 0, 0};
|
||||
#endif
|
||||
|
||||
struct dp_dhdr_maxpkt_calc_input {
|
||||
u32 mdp_clk;
|
||||
@ -1071,6 +1115,7 @@ static void _dp_panel_calc_tu(struct dp_tu_calc_input *in,
|
||||
tu_table->lower_boundary_count = tu.lower_boundary_count;
|
||||
tu_table->tu_size_minus1 = tu.tu_size_minus1;
|
||||
|
||||
#if !defined(CONFIG_SECDP)
|
||||
DP_DEBUG("TU: valid_boundary_link: %d\n", tu_table->valid_boundary_link);
|
||||
DP_DEBUG("TU: delay_start_link: %d\n", tu_table->delay_start_link);
|
||||
DP_DEBUG("TU: boundary_moderation_en: %d\n",
|
||||
@ -1082,6 +1127,7 @@ static void _dp_panel_calc_tu(struct dp_tu_calc_input *in,
|
||||
DP_DEBUG("TU: lower_boundary_count: %d\n",
|
||||
tu_table->lower_boundary_count);
|
||||
DP_DEBUG("TU: tu_size_minus1: %d\n", tu_table->tu_size_minus1);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void dp_panel_calc_tu_parameters(struct dp_panel *dp_panel,
|
||||
@ -1275,7 +1321,9 @@ static void _dp_panel_dsc_get_num_extra_pclk(struct msm_compression_info *comp_i
|
||||
else
|
||||
dsc->extra_width = 0;
|
||||
|
||||
#if !defined(CONFIG_SECDP)
|
||||
DP_DEBUG_V("extra pclks required: %d\n", dsc->extra_width);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void _dp_panel_dsc_bw_overhead_calc(struct dp_panel *dp_panel,
|
||||
@ -1304,8 +1352,10 @@ static void _dp_panel_dsc_bw_overhead_calc(struct dp_panel *dp_panel,
|
||||
dwidth_dsc_bytes = tot_num_hor_bytes + tot_num_eoc_symbols +
|
||||
tot_num_dummy_bytes;
|
||||
|
||||
#if !defined(CONFIG_SECDP)
|
||||
DP_DEBUG_V("dwidth_dsc_bytes:%d, tot_num_hor_bytes:%d\n",
|
||||
dwidth_dsc_bytes, tot_num_hor_bytes);
|
||||
#endif
|
||||
|
||||
dp_mode->dsc_overhead_fp = drm_fixp_from_fraction(dwidth_dsc_bytes,
|
||||
tot_num_hor_bytes);
|
||||
@ -1471,9 +1521,11 @@ static int dp_panel_dsc_prepare_basic_params(
|
||||
(dsc_version_minor == 0x1 || dsc_version_minor == 0x2))
|
||||
? true : false;
|
||||
|
||||
#if !defined(CONFIG_SECDP)
|
||||
DP_DEBUG_V("DSC version: %d.%d, dpcd value: %x\n",
|
||||
dsc_version_major, dsc_version_minor,
|
||||
dp_panel->sink_dsc_caps.version);
|
||||
#endif
|
||||
|
||||
if (!dsc_version_supported) {
|
||||
dsc_version_major = 1;
|
||||
@ -1496,8 +1548,12 @@ static int dp_panel_dsc_prepare_basic_params(
|
||||
}
|
||||
}
|
||||
|
||||
if (comp_info->dsc_info.slice_per_pkt == 0)
|
||||
if (comp_info->dsc_info.slice_per_pkt == 0) {
|
||||
#if defined(CONFIG_SECDP)
|
||||
DP_ERR("slice_per_pkt is zero\n");
|
||||
return -EINVAL;
|
||||
#endif
|
||||
}
|
||||
|
||||
ppr_max_index = dp_panel->dsc_dpcd[11] &= 0xf;
|
||||
if (!ppr_max_index || ppr_max_index >= 15) {
|
||||
@ -1528,8 +1584,20 @@ static int dp_panel_dsc_prepare_basic_params(
|
||||
!dp_panel_check_slice_support(
|
||||
comp_info->dsc_info.slice_per_pkt, slice_caps_1,
|
||||
slice_caps_2)) {
|
||||
if (i == ARRAY_SIZE(slice_per_line_tbl))
|
||||
#if defined(CONFIG_SECDP)
|
||||
DP_DEBUG("[%d] slice_width=%d, max_slice_width=%d, ppr_per_slice=%d, peak_throughput=%d, dp_panel_check_slice_support=%d\n",
|
||||
i, slice_width, max_slice_width, ppr_per_slice, peak_throughput, dp_panel_check_slice_support(
|
||||
comp_info->dsc_info.slice_per_pkt, slice_caps_1,
|
||||
slice_caps_2));
|
||||
DP_DEBUG("comp_info->dsc_info.slice_per_pkt=%d, slice_caps_1=%x, slice_caps_2=%x\n",
|
||||
comp_info->dsc_info.slice_per_pkt, slice_caps_1, slice_caps_2);
|
||||
#endif
|
||||
if (i == ARRAY_SIZE(slice_per_line_tbl)) {
|
||||
#if defined(CONFIG_SECDP)
|
||||
DP_ERR("reached end of slice_per_line_tbl %d\n", i);
|
||||
#endif
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rec = &slice_per_line_tbl[i];
|
||||
comp_info->dsc_info.slice_per_pkt = rec->num_slices;
|
||||
@ -1587,6 +1655,11 @@ static int dp_panel_read_dpcd(struct dp_panel *dp_panel, bool multi_func)
|
||||
goto end;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
DP_ENTER("\n");
|
||||
g_dp_panel = dp_panel;
|
||||
#endif
|
||||
|
||||
dpcd = dp_panel->dpcd;
|
||||
|
||||
panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
|
||||
@ -1627,6 +1700,9 @@ static int dp_panel_read_dpcd(struct dp_panel *dp_panel, bool multi_func)
|
||||
|
||||
print_hex_dump_debug("[drm-dp] SINK DPCD: ",
|
||||
DUMP_PREFIX_NONE, 8, 1, dp_panel->dpcd, rlen, false);
|
||||
#if defined(CONFIG_SECDP)
|
||||
secdp_logger_hex_dump(dp_panel->dpcd, "DPCD:", rlen);
|
||||
#endif
|
||||
|
||||
rlen = drm_dp_dpcd_read(panel->aux->drm_aux,
|
||||
DPRX_FEATURE_ENUMERATION_LIST, &rx_feature, 1);
|
||||
@ -1653,6 +1729,12 @@ static int dp_panel_read_dpcd(struct dp_panel *dp_panel, bool multi_func)
|
||||
/* override link params updated in dp_panel_init_panel_info */
|
||||
link_info->rate = min_t(unsigned long, panel->parser->max_lclk_khz,
|
||||
drm_dp_bw_code_to_link_rate(dpcd[DP_MAX_LINK_RATE]));
|
||||
#ifdef SECDP_MAX_HBR2
|
||||
if (link_info->rate > 540000) { /*DP_LINK_BW_5_4*/
|
||||
DP_DEBUG("set it to 540000!\n");
|
||||
link_info->rate = 540000;
|
||||
}
|
||||
#endif
|
||||
|
||||
link_info->num_lanes = dpcd[DP_MAX_LANE_COUNT] & DP_MAX_LANE_COUNT_MASK;
|
||||
|
||||
@ -1675,6 +1757,18 @@ static int dp_panel_read_dpcd(struct dp_panel *dp_panel, bool multi_func)
|
||||
DP_DEBUG("version:%d.%d, rate:%d, lanes:%d\n", panel->major,
|
||||
panel->minor, link_info->rate, link_info->num_lanes);
|
||||
|
||||
#ifdef SECDP_SELF_TEST
|
||||
if (secdp_self_test_status(ST_LINK_RATE) >= 0) {
|
||||
link_info->rate = secdp_self_test_get_arg(ST_LINK_RATE)[0];
|
||||
DP_INFO("secdp self test: link_rate %d\n", link_info->rate);
|
||||
}
|
||||
|
||||
if (secdp_self_test_status(ST_LANE_CNT) >= 0) {
|
||||
link_info->num_lanes = secdp_self_test_get_arg(ST_LANE_CNT)[0];
|
||||
DP_INFO("secdp self test: lane_cnt %d\n", link_info->num_lanes);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (drm_dp_enhanced_frame_cap(dpcd))
|
||||
link_info->capabilities |= DP_LINK_CAP_ENHANCED_FRAMING;
|
||||
|
||||
@ -1701,6 +1795,18 @@ static int dp_panel_read_dpcd(struct dp_panel *dp_panel, bool multi_func)
|
||||
DP_DEBUG("DS port count %d greater that max (%d) supported\n",
|
||||
dfp_count, DP_MAX_DS_PORT_COUNT);
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
dp_panel->dsp_type = (dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_TYPE_MASK) >> 1;
|
||||
DP_INFO("dsp_type: <%s>\n", mdss_dp_dsp_type_to_string(dp_panel->dsp_type));
|
||||
#if defined(CONFIG_SECDP_BIGDATA)
|
||||
secdp_bigdata_save_item(BD_ADAPTER_TYPE, mdss_dp_dsp_type_to_string(dp_panel->dsp_type));
|
||||
secdp_bigdata_save_item(BD_MAX_LANE_COUNT, link_info->num_lanes);
|
||||
secdp_bigdata_save_item(BD_MAX_LINK_RATE, dp_panel->dpcd[DP_MAX_LINK_RATE]);
|
||||
secdp_bigdata_save_item(BD_CUR_LANE_COUNT, link_info->num_lanes);
|
||||
secdp_bigdata_save_item(BD_CUR_LINK_RATE, dp_panel->dpcd[DP_MAX_LINK_RATE]);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
end:
|
||||
return rc;
|
||||
}
|
||||
@ -1724,6 +1830,279 @@ static int dp_panel_set_default_link_params(struct dp_panel *dp_panel)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef SECDP_OPTIMAL_LINK_RATE
|
||||
/*
|
||||
//IMPORT/Qualcomm/kernel/SM8350_R/msm-5.4/techpack/display/msm/dp/dp_panel.c#7
|
||||
//KERNEL/LEGO/BSP/Combination/SM8350_R/msm-5.4/techpack/display/msm/dp/dp_panel.c#10
|
||||
*/
|
||||
static u32 secdp_panel_get_min_req_link_rate(struct dp_panel *dp_panel)
|
||||
{
|
||||
const u32 encoding_factx10 = 8;
|
||||
u32 min_link_rate_khz = 0, lane_cnt;
|
||||
struct dp_panel_info *pinfo;
|
||||
|
||||
if (!dp_panel) {
|
||||
DP_ERR("invalid input\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
lane_cnt = dp_panel->link_info.num_lanes;
|
||||
pinfo = &dp_panel->max_timing_info;
|
||||
|
||||
/* num_lanes * lane_count * 8 >= pclk * bpp * 10 */
|
||||
min_link_rate_khz = pinfo->pixel_clk_khz /
|
||||
(lane_cnt * encoding_factx10);
|
||||
min_link_rate_khz *= pinfo->bpp;
|
||||
|
||||
DP_DEBUG("min lclk req=%d khz for pclk=%d khz, lanes=%d, bpp=%d\n",
|
||||
min_link_rate_khz, pinfo->pixel_clk_khz, lane_cnt,
|
||||
pinfo->bpp);
|
||||
end:
|
||||
return min_link_rate_khz;
|
||||
}
|
||||
|
||||
#define RES_1920X1080 2073600
|
||||
#define RES_2560X1440 3686400
|
||||
static bool ps176_high_refresh_rate_check(struct dp_panel *dp_panel)
|
||||
{
|
||||
struct dp_panel_private *panel;
|
||||
struct secdp_misc *sec;
|
||||
struct dp_panel_info *max_timing;
|
||||
int max_resolution;
|
||||
bool ret = false;
|
||||
|
||||
DP_ENTER("\n");
|
||||
|
||||
panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
|
||||
sec = panel->sec;
|
||||
|
||||
if (!secdp_adapter_check_parade(sec))
|
||||
goto end;
|
||||
|
||||
if (!secdp_adapter_check_ps176(sec))
|
||||
goto end;
|
||||
|
||||
max_timing = &dp_panel->max_timing_info;
|
||||
max_resolution = max_timing->h_active * max_timing->v_active;
|
||||
|
||||
if (max_resolution >= RES_1920X1080 &&
|
||||
max_timing->refresh_rate > 110 &&
|
||||
max_timing->pixel_clk_khz > 250000) {
|
||||
ret = true;
|
||||
} else if (max_resolution >= RES_2560X1440 &&
|
||||
max_timing->refresh_rate > 75 &&
|
||||
max_timing->pixel_clk_khz > 300000) {
|
||||
ret = true;
|
||||
}
|
||||
|
||||
DP_INFO("[ps176] max %ux%u@%uhz, pclk %uKhz, %d\n",
|
||||
max_timing->h_active, max_timing->v_active,
|
||||
max_timing->refresh_rate, max_timing->pixel_clk_khz, ret);
|
||||
end:
|
||||
DP_LEAVE("%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
u32 secdp_gen_link_clk(struct dp_panel *dp_panel)
|
||||
{
|
||||
u32 calc_link_rate, min_link_rate;
|
||||
|
||||
DP_ENTER("\n");
|
||||
|
||||
#ifndef SECDP_MAX_HBR2
|
||||
calc_link_rate = 810000;
|
||||
#else
|
||||
calc_link_rate = 540000;
|
||||
#endif
|
||||
|
||||
if (!dp_panel || ps176_high_refresh_rate_check(dp_panel))
|
||||
goto end;
|
||||
|
||||
min_link_rate = secdp_panel_get_min_req_link_rate(dp_panel);
|
||||
if (!min_link_rate)
|
||||
DP_INFO("timing not found\n");
|
||||
|
||||
if (min_link_rate <= 162000)
|
||||
calc_link_rate = 162000;
|
||||
else if (min_link_rate <= 270000)
|
||||
calc_link_rate = 270000;
|
||||
else if (min_link_rate <= 540000)
|
||||
calc_link_rate = 540000;
|
||||
#ifndef SECDP_MAX_HBR2
|
||||
else if (min_link_rate <= 810000)
|
||||
calc_link_rate = 810000;
|
||||
#endif
|
||||
else
|
||||
DP_ERR("too big!, set default\n");
|
||||
|
||||
DP_INFO("min_link_rate <%u>, calc_link_rate <%u>\n",
|
||||
min_link_rate, calc_link_rate);
|
||||
end:
|
||||
DP_LEAVE("\n");
|
||||
return calc_link_rate;
|
||||
}
|
||||
#endif/*SECDP_OPTIMAL_LINK_RATE*/
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
static int dp_panel_get_modes(struct dp_panel *dp_panel,
|
||||
struct drm_connector *connector, struct dp_display_mode *mode);
|
||||
static void dp_panel_convert_to_dp_mode(struct dp_panel *dp_panel,
|
||||
const struct drm_display_mode *drm_mode,
|
||||
struct dp_display_mode *dp_mode);
|
||||
|
||||
/**
|
||||
* dp_panel_get_min_req_link_rate() needs two info :
|
||||
* 1. pinfo->pixel_clk_khz
|
||||
* 2. pinfo->bpp
|
||||
* this function is made for future use of "SECDP_OPTIMAL_LINK_RATE"
|
||||
*/
|
||||
static void secdp_get_max_timing(struct dp_panel *dp_panel)
|
||||
{
|
||||
struct dp_link_params *link_params;
|
||||
struct dp_panel_private *panel;
|
||||
struct drm_device *dev;
|
||||
struct drm_connector *conn;
|
||||
struct drm_display_mode *mode, *temp;
|
||||
struct dp_display_mode dp_mode;
|
||||
struct dp_panel_info *pinfo, *timing;
|
||||
int rc;
|
||||
|
||||
conn = dp_panel->connector;
|
||||
dev = conn->dev;
|
||||
panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
|
||||
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
|
||||
pinfo = &dp_panel->max_timing_info;
|
||||
memset(pinfo, 0, sizeof(*pinfo));
|
||||
memset(&dp_mode, 0, sizeof(dp_mode));
|
||||
|
||||
link_params = &panel->link->link_params;
|
||||
link_params->bw_code = drm_dp_link_rate_to_bw_code(dp_panel->link_info.rate);
|
||||
link_params->lane_count = dp_panel->link_info.num_lanes;
|
||||
|
||||
rc = dp_panel_get_modes(dp_panel, conn, &dp_mode);
|
||||
if (!rc) {
|
||||
DP_INFO("no valid mode\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
list_for_each_entry(mode, &conn->probed_modes, head) {
|
||||
dp_panel_convert_to_dp_mode(dp_panel, mode, &dp_mode);
|
||||
timing = &dp_mode.timing;
|
||||
|
||||
if (pinfo->pixel_clk_khz < timing->pixel_clk_khz) {
|
||||
pinfo->h_active = timing->h_active;
|
||||
pinfo->v_active = timing->v_active;
|
||||
pinfo->refresh_rate = timing->refresh_rate;
|
||||
pinfo->pixel_clk_khz = timing->pixel_clk_khz;
|
||||
pinfo->bpp = timing->bpp;
|
||||
DP_INFO("updated, %ux%u@%uhz, pclk:%u, bpp:%u\n",
|
||||
pinfo->h_active, pinfo->v_active,
|
||||
pinfo->refresh_rate, pinfo->pixel_clk_khz,
|
||||
pinfo->bpp);
|
||||
}
|
||||
}
|
||||
|
||||
list_for_each_entry_safe(mode, temp, &conn->probed_modes, head) {
|
||||
list_del(&mode->head);
|
||||
drm_mode_destroy(conn->dev, mode);
|
||||
}
|
||||
end:
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
}
|
||||
|
||||
/* DP testbox list */
|
||||
static char secdp_tbox[][MON_NAME_LEN] = {
|
||||
"UNIGRAF TE",
|
||||
"UFG DPR-120",
|
||||
"UCD-400 DP",
|
||||
"UCD-400 DP1",
|
||||
"AGILENT ATR",
|
||||
"UFG DP SINK",
|
||||
};
|
||||
#define SECDP_TBOX_MAX 32
|
||||
|
||||
/** check if connected sink is testbox or not
|
||||
* return true if it's testbox
|
||||
* return false otherwise (real sink)
|
||||
*/
|
||||
static bool secdp_check_tbox(struct dp_panel *panel)
|
||||
{
|
||||
unsigned long i, size = SECDP_TBOX_MAX;
|
||||
size_t len = 0;
|
||||
bool ret = false;
|
||||
|
||||
len = strlen(panel->monitor_name);
|
||||
if (!len)
|
||||
goto end;
|
||||
|
||||
size = min(ARRAY_SIZE(secdp_tbox), size);
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
int rc;
|
||||
|
||||
rc = strncmp(panel->monitor_name, secdp_tbox[i], len);
|
||||
if (!rc) {
|
||||
DP_INFO("<%s> detected!\n", panel->monitor_name);
|
||||
ret = true;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
DP_INFO("real sink <%s>\n", panel->monitor_name);
|
||||
end:
|
||||
panel->tbox = ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void secdp_show_sink_caps(struct dp_panel *dp_panel)
|
||||
{
|
||||
DP_INFO("dpcd_rev:0x%02x, vendor:%s, monitor:%s\n",
|
||||
dp_panel->dpcd[DP_DPCD_REV],
|
||||
dp_panel->edid_ctrl->vendor_id,
|
||||
dp_panel->monitor_name);
|
||||
|
||||
if (dp_panel->dsc_en) {
|
||||
u32 dsc_version_major, dsc_version_minor;
|
||||
bool dsc_version_supported = false;
|
||||
|
||||
dsc_version_major = dp_panel->sink_dsc_caps.version & 0xF;
|
||||
dsc_version_minor = (dp_panel->sink_dsc_caps.version >> 4) & 0xF;
|
||||
dsc_version_supported = (dsc_version_major == 0x1 &&
|
||||
(dsc_version_minor == 0x1 || dsc_version_minor == 0x2))
|
||||
? true : false;
|
||||
|
||||
DP_INFO("DSC version: %d.%d(support:%d), dpcd value: %x\n",
|
||||
dsc_version_major, dsc_version_minor,
|
||||
dsc_version_supported,
|
||||
dp_panel->sink_dsc_caps.version);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECDP_BIGDATA)
|
||||
secdp_bigdata_save_item(BD_SINK_NAME, dp_panel->monitor_name);
|
||||
secdp_bigdata_save_item(BD_EDID, (char *)(dp_panel->edid_ctrl->edid));
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool secdp_fetch_monitor_name(struct edid *edid, char *name, int len)
|
||||
{
|
||||
struct edid *edid_dup;
|
||||
bool ret = false;
|
||||
|
||||
if (!edid)
|
||||
goto exit;
|
||||
|
||||
edid_dup = drm_edid_duplicate(edid);
|
||||
drm_edid_get_monitor_name(edid_dup, name, len);
|
||||
kfree(edid_dup);
|
||||
|
||||
ret = strlen(name) ? true : false;
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int dp_panel_read_edid(struct dp_panel *dp_panel,
|
||||
struct drm_connector *connector)
|
||||
{
|
||||
@ -1738,6 +2117,10 @@ static int dp_panel_read_edid(struct dp_panel *dp_panel,
|
||||
|
||||
panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
secdp_timing_init(panel->sec);
|
||||
#endif
|
||||
|
||||
sde_get_edid(connector, &panel->aux->drm_aux->ddc,
|
||||
(void **)&dp_panel->edid_ctrl);
|
||||
if (!dp_panel->edid_ctrl->edid) {
|
||||
@ -1745,6 +2128,10 @@ static int dp_panel_read_edid(struct dp_panel *dp_panel,
|
||||
ret = -EINVAL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
secdp_get_max_timing(dp_panel);
|
||||
#endif
|
||||
end:
|
||||
edid = dp_panel->edid_ctrl->edid;
|
||||
dp_panel->audio_supported = drm_detect_monitor_audio(edid);
|
||||
@ -1843,18 +2230,38 @@ static int dp_panel_read_sink_caps(struct dp_panel *dp_panel,
|
||||
|
||||
panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
usleep_range(10000, 11000);
|
||||
#endif
|
||||
|
||||
rc = dp_panel_read_dpcd(dp_panel, multi_func);
|
||||
if (rc || !is_link_rate_valid(drm_dp_link_rate_to_bw_code(
|
||||
dp_panel->link_info.rate)) || !is_lane_count_valid(
|
||||
dp_panel->link_info.num_lanes) ||
|
||||
((drm_dp_link_rate_to_bw_code(dp_panel->link_info.rate)) >
|
||||
dp_panel->max_bw_code)) {
|
||||
|
||||
#if !defined(CONFIG_SECDP)
|
||||
if ((rc == -ETIMEDOUT) || (rc == -ENODEV)) {
|
||||
DP_ERR("DPCD read failed, return early\n");
|
||||
goto end;
|
||||
}
|
||||
#else
|
||||
if (!secdp_get_hpd_status() || !secdp_get_cable_status()) {
|
||||
DP_INFO("hpd_low or cable_lost\n");
|
||||
rc = -ETIMEDOUT;
|
||||
goto end;
|
||||
}
|
||||
#endif
|
||||
DP_ERR("panel dpcd read failed/incorrect, set default params\n");
|
||||
dp_panel_set_default_link_params(dp_panel);
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
if (rc < 0) {
|
||||
rc = -ETIMEDOUT;
|
||||
goto end;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
downstream_ports = dp_panel->dpcd[DP_DOWNSTREAMPORT_PRESENT] &
|
||||
@ -1881,6 +2288,9 @@ static int dp_panel_read_sink_caps(struct dp_panel *dp_panel,
|
||||
rc = dp_panel_read_edid(dp_panel, connector);
|
||||
if (rc) {
|
||||
DP_ERR("panel edid read failed, set failsafe mode\n");
|
||||
#if defined(CONFIG_SECDP_BIGDATA)
|
||||
secdp_bigdata_inc_error_cnt(ERR_EDID);
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -1902,6 +2312,13 @@ skip_edid:
|
||||
|
||||
DP_INFO("fec_en=%d, dsc_en=%d, widebus_en=%d\n", dp_panel->fec_en,
|
||||
dp_panel->dsc_en, dp_panel->widebus_en);
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
secdp_fetch_monitor_name(dp_panel->edid_ctrl->edid, dp_panel->monitor_name, 14);
|
||||
secdp_check_tbox(dp_panel);
|
||||
secdp_show_sink_caps(dp_panel);
|
||||
#endif
|
||||
|
||||
end:
|
||||
return rc;
|
||||
}
|
||||
@ -1924,7 +2341,15 @@ static u32 dp_panel_get_supported_bpp(struct dp_panel *dp_panel,
|
||||
if (dsc_en)
|
||||
min_supported_bpp = 24;
|
||||
|
||||
#if !defined(CONFIG_SECDP)
|
||||
bpp = min_t(u32, mode_edid_bpp, max_supported_bpp);
|
||||
#else
|
||||
/* 4Kp60hz + bpp30 does not output audio with DP2HDMI dongle connection because
|
||||
* DP2HDMI dongle does not support HDR10 yet. It has bandwidth limitation
|
||||
*/
|
||||
bpp = min_t(u32, mode_edid_bpp,
|
||||
((dp_panel->dsp_type == DSP_TYPE_DP) ? max_supported_bpp : max_supported_bpp - 6));
|
||||
#endif
|
||||
|
||||
link_params = &panel->link->link_params;
|
||||
|
||||
@ -2042,6 +2467,9 @@ static int dp_panel_get_modes(struct dp_panel *dp_panel,
|
||||
panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
|
||||
|
||||
if (dp_panel->video_test) {
|
||||
#if defined(CONFIG_SECDP)
|
||||
DP_DEBUG("video_test:%d\n", dp_panel->video_test);
|
||||
#endif
|
||||
dp_panel_set_test_mode(panel, mode);
|
||||
return 1;
|
||||
} else if (dp_panel->edid_ctrl->edid) {
|
||||
@ -2427,6 +2855,27 @@ static bool dp_panel_hdr_supported(struct dp_panel *dp_panel)
|
||||
(panel->minor >= 4 || panel->vscext_supported);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
bool secdp_panel_hdr_supported(void)
|
||||
{
|
||||
struct dp_panel *dp_panel;
|
||||
bool hdr;
|
||||
|
||||
dp_panel = g_dp_panel;
|
||||
if (!dp_panel) {
|
||||
DP_ERR("invalid input\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
hdr = dp_panel_hdr_supported(dp_panel);
|
||||
|
||||
DP_INFO("dsp_type:%s, hdr:%d\n",
|
||||
mdss_dp_dsp_type_to_string(dp_panel->dsp_type), hdr);
|
||||
|
||||
return ((dp_panel->dsp_type == DSP_TYPE_DP) && hdr);
|
||||
}
|
||||
#endif/*CONFIG_SECDP*/
|
||||
|
||||
static u32 dp_panel_calc_dhdr_pkt_limit(struct dp_panel *dp_panel,
|
||||
struct dp_dhdr_maxpkt_calc_input *input)
|
||||
{
|
||||
@ -2829,6 +3278,20 @@ static void dp_panel_resolution_info(struct dp_panel_private *panel)
|
||||
pinfo->refresh_rate, pinfo->bpp, pinfo->pixel_clk_khz,
|
||||
panel->link->link_params.bw_code,
|
||||
panel->link->link_params.lane_count);
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
DP_INFO("SET NEW RESOLUTION: %dx%d@%dfps\n",
|
||||
pinfo->h_active, pinfo->v_active, pinfo->refresh_rate);
|
||||
#endif
|
||||
#if defined(CONFIG_SECDP_BIGDATA)
|
||||
{
|
||||
char buf[20] = {0, };
|
||||
|
||||
scnprintf(buf, 20, "%dx%d@%d",
|
||||
pinfo->h_active, pinfo->v_active, pinfo->refresh_rate);
|
||||
secdp_bigdata_save_item(BD_RESOLUTION, buf);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void dp_panel_config_sdp(struct dp_panel *dp_panel,
|
||||
@ -2914,6 +3377,14 @@ static int dp_panel_update_edid(struct dp_panel *dp_panel, struct edid *edid)
|
||||
dp_panel->edid_ctrl->edid = edid;
|
||||
sde_parse_edid(dp_panel->edid_ctrl);
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
if (!strlen(dp_panel->monitor_name)) {
|
||||
secdp_fetch_monitor_name(edid, dp_panel->monitor_name, 14);
|
||||
DP_INFO("[mst] vendor:%s, monitor:%s\n",
|
||||
dp_panel->edid_ctrl->vendor_id, dp_panel->monitor_name);
|
||||
}
|
||||
#endif
|
||||
|
||||
rc = _sde_edid_update_modes(dp_panel->connector, dp_panel->edid_ctrl);
|
||||
dp_panel->audio_supported = drm_detect_monitor_audio(edid);
|
||||
|
||||
@ -3156,9 +3627,16 @@ struct dp_panel *dp_panel_get(struct dp_panel_in *in)
|
||||
panel->catalog = in->catalog;
|
||||
panel->link = in->link;
|
||||
panel->parser = in->parser;
|
||||
#if defined(CONFIG_SECDP)
|
||||
panel->sec = in->sec;
|
||||
#endif
|
||||
|
||||
dp_panel = &panel->dp_panel;
|
||||
#ifndef SECDP_MAX_HBR2
|
||||
dp_panel->max_bw_code = DP_LINK_BW_8_1;
|
||||
#else
|
||||
dp_panel->max_bw_code = DP_LINK_BW_5_4;
|
||||
#endif
|
||||
dp_panel->spd_enabled = true;
|
||||
dp_panel->link_bw_code = 0;
|
||||
dp_panel->lane_count = 0;
|
||||
|
@ -93,6 +93,9 @@ struct dp_panel_in {
|
||||
struct drm_connector *connector;
|
||||
struct dp_panel *base_panel;
|
||||
struct dp_parser *parser;
|
||||
#if defined(CONFIG_SECDP)
|
||||
struct secdp_misc *sec;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct dp_dsc_caps {
|
||||
@ -130,6 +133,13 @@ struct dp_panel {
|
||||
u32 link_bw_code;
|
||||
u32 max_supported_bpp;
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
bool tbox;
|
||||
u8 monitor_name[14]; /* max 13 chars + null */
|
||||
u32 dsp_type;
|
||||
struct dp_panel_info max_timing_info;
|
||||
#endif
|
||||
|
||||
/* By default, stream_id is assigned to DP_INVALID_STREAM.
|
||||
* Client sets the stream id value using set_stream_id interface.
|
||||
*/
|
||||
@ -264,4 +274,10 @@ struct dp_panel *dp_panel_get(struct dp_panel_in *in);
|
||||
void dp_panel_put(struct dp_panel *dp_panel);
|
||||
void dp_panel_calc_tu_test(struct dp_tu_calc_input *in,
|
||||
struct dp_vc_tu_mapping_table *tu_table);
|
||||
|
||||
#define SECDP_OPTIMAL_LINK_RATE /* use optimum link_rate, not max link_rate */
|
||||
#ifdef SECDP_OPTIMAL_LINK_RATE
|
||||
u32 secdp_gen_link_clk(struct dp_panel *dp_panel);
|
||||
#endif
|
||||
|
||||
#endif /* _DP_PANEL_H_ */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -182,6 +182,42 @@ static inline char *dp_phy_aux_config_type_to_string(u32 cfg_type)
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
enum secdp_phy_pre_emphasis_type {
|
||||
PHY_PRE_EMP0, /* 0 db */
|
||||
PHY_PRE_EMP1, /* 3.5 db */
|
||||
PHY_PRE_EMP2, /* 6.0 db */
|
||||
PHY_PRE_EMP3, /* 9.5 db */
|
||||
// MAX_PRE_EMP_LEVELS,
|
||||
};
|
||||
|
||||
enum secdp_phy_voltage_type {
|
||||
PHY_VOLTAGE_SWING0, /* 0.4 v */
|
||||
PHY_VOLTAGE_SWING1, /* 0.6 v */
|
||||
PHY_VOLTAGE_SWING2, /* 0.8 v */
|
||||
PHY_VOLTAGE_SWING3, /* 1.2 v, optional */
|
||||
MAX_VOLTAGE_LEVELS,
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_COMBO_REDRIVER_PS5169)
|
||||
enum secdp_ps5169_pre_emphasis_type {
|
||||
PHY_PS5169_EMP0, /* 0 db */
|
||||
PHY_PS5169_EMP1, /* 3.5 db */
|
||||
PHY_PS5169_EMP2, /* 6.0 db */
|
||||
PHY_PS5169_EMP3, /* 9.5 db */
|
||||
MAX_PS5169_EMP_LEVELS,
|
||||
};
|
||||
|
||||
enum secdp_PS5169_voltage_type {
|
||||
PHY_PS5169_SWING0, /* 0.4 v */
|
||||
PHY_PS5169_SWING1, /* 0.6 v */
|
||||
PHY_PS5169_SWING2, /* 0.8 v */
|
||||
PHY_PS5169_SWING3, /* 1.2 v, optional */
|
||||
MAX_PS5169_SWING_LEVELS,
|
||||
};
|
||||
#endif/*CONFIG_COMBO_REDRIVER_PS5169*/
|
||||
#endif/*CONFIG_SECDP*/
|
||||
|
||||
/**
|
||||
* struct dp_parser - DP parser's data exposed to clients
|
||||
*
|
||||
@ -246,6 +282,29 @@ struct dp_parser {
|
||||
u8 *pre_emp_hbr_rbr;
|
||||
bool valid_lt_params;
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
struct regulator *aux_pullup_vreg;
|
||||
bool cc_dir_inv; /* CC_DIR is inversed, e.g, T865 */
|
||||
bool aux_sel_inv; /* inverse control of AUX_SEL e.g, D2Xq hwid 01,02 */
|
||||
int use_redrv; /* ptn36502 needs NOT AUX switch SEL control */
|
||||
int dex_dft_res; /* DeX default resolution, e.g, HG950 */
|
||||
bool prefer_support; /* true if prefer resolution has high priority */
|
||||
bool mrr_fps_nolimit; /* true if mirroring refresh rate has no limit */
|
||||
bool rf_tx_backoff; /* true if it RF TX Backoff is supported, for SHELL-less type connector */
|
||||
bool mst_support; /* true if MST is supported */
|
||||
|
||||
#if IS_ENABLED(CONFIG_COMBO_REDRIVER_PS5169)
|
||||
u8 ps5169_rbr_eq0[MAX_PS5169_SWING_LEVELS][MAX_PS5169_EMP_LEVELS];
|
||||
u8 ps5169_rbr_eq1[MAX_PS5169_SWING_LEVELS][MAX_PS5169_EMP_LEVELS];
|
||||
u8 ps5169_hbr_eq0[MAX_PS5169_SWING_LEVELS][MAX_PS5169_EMP_LEVELS];
|
||||
u8 ps5169_hbr_eq1[MAX_PS5169_SWING_LEVELS][MAX_PS5169_EMP_LEVELS];
|
||||
u8 ps5169_hbr2_eq0[MAX_PS5169_SWING_LEVELS][MAX_PS5169_EMP_LEVELS];
|
||||
u8 ps5169_hbr2_eq1[MAX_PS5169_SWING_LEVELS][MAX_PS5169_EMP_LEVELS];
|
||||
u8 ps5169_hbr3_eq0[MAX_PS5169_SWING_LEVELS][MAX_PS5169_EMP_LEVELS];
|
||||
u8 ps5169_hbr3_eq1[MAX_PS5169_SWING_LEVELS][MAX_PS5169_EMP_LEVELS];
|
||||
#endif/*CONFIG_COMBO_REDRIVER_PS5169*/
|
||||
#endif/*CONFIG_SECDP*/
|
||||
|
||||
int (*parse)(struct dp_parser *parser);
|
||||
struct dp_io_data *(*get_io)(struct dp_parser *parser, char *name);
|
||||
void (*get_io_buf)(struct dp_parser *parser, char *name);
|
||||
@ -286,4 +345,106 @@ struct dp_parser *dp_parser_get(struct platform_device *pdev);
|
||||
* @parser: pointer to the parser's data.
|
||||
*/
|
||||
void dp_parser_put(struct dp_parser *parser);
|
||||
|
||||
#if defined(CONFIG_SECDP) && IS_ENABLED(CONFIG_COMBO_REDRIVER_PS5169)
|
||||
enum secdp_ps5169_eq_t {
|
||||
DP_PS5169_EQ0,
|
||||
DP_PS5169_EQ1,
|
||||
DP_PS5169_EQ_MAX,
|
||||
};
|
||||
|
||||
enum secdp_ps5169_link_rate_t {
|
||||
DP_PS5169_RATE_RBR,
|
||||
DP_PS5169_RATE_HBR,
|
||||
DP_PS5169_RATE_HBR2,
|
||||
DP_PS5169_RATE_HBR3,
|
||||
DP_PS5169_RATE_MAX,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SECDP_DBG)
|
||||
enum secdp_link_rate_t {
|
||||
DP_LR_NONE = 0x0,
|
||||
DP_LR_HBR_RBR = 0x1,
|
||||
DP_LR_HBR2_3 = 0x2,
|
||||
};
|
||||
|
||||
static inline char *secdp_link_rate_to_string(int lr)
|
||||
{
|
||||
switch (lr) {
|
||||
case DP_LR_HBR_RBR:
|
||||
return DP_ENUM_STR(DP_LR_HBR_RBR);
|
||||
case DP_LR_HBR2_3:
|
||||
return DP_ENUM_STR(DP_LR_HBR2_3);
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
enum secdp_phy_param_t {
|
||||
DP_PARAM_NONE = 0x0,
|
||||
DP_PARAM_VX = 0x1, /* voltage swing */
|
||||
DP_PARAM_PX = 0x2, /* pre-emphasis */
|
||||
};
|
||||
|
||||
static inline char *secdp_phy_type_to_string(int param)
|
||||
{
|
||||
switch (param) {
|
||||
case DP_PARAM_VX:
|
||||
return DP_ENUM_STR(DP_PARAM_VX);
|
||||
case DP_PARAM_PX:
|
||||
return DP_ENUM_STR(DP_PARAM_PX);
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
/* voltage swing, pre-emphasis */
|
||||
int secdp_parse_vxpx_show(struct dp_parser *parser, enum secdp_link_rate_t lr,
|
||||
enum secdp_phy_param_t vxpx, char *buf);
|
||||
int secdp_parse_vxpx_store(struct dp_parser *parser, enum secdp_link_rate_t lr,
|
||||
enum secdp_phy_param_t vxpx, char *buf);
|
||||
int secdp_show_phy_param(struct dp_parser *parser, char *buf);
|
||||
|
||||
#if IS_ENABLED(CONFIG_COMBO_REDRIVER_PS5169)
|
||||
static inline char *secdp_ps5169_eq_to_string(int hw)
|
||||
{
|
||||
switch (hw) {
|
||||
case DP_PS5169_EQ0:
|
||||
return DP_ENUM_STR(DP_PS5169_EQ0);
|
||||
case DP_PS5169_EQ1:
|
||||
return DP_ENUM_STR(DP_PS5169_EQ1);
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static inline char *secdp_ps5169_rate_to_string(int hw)
|
||||
{
|
||||
switch (hw) {
|
||||
case DP_PS5169_RATE_RBR:
|
||||
return DP_ENUM_STR(DP_PS5169_RATE_RBR);
|
||||
case DP_PS5169_RATE_HBR:
|
||||
return DP_ENUM_STR(DP_PS5169_RATE_HBR);
|
||||
case DP_PS5169_RATE_HBR2:
|
||||
return DP_ENUM_STR(DP_PS5169_RATE_HBR2);
|
||||
case DP_PS5169_RATE_HBR3:
|
||||
return DP_ENUM_STR(DP_PS5169_RATE_HBR3);
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
int secdp_parse_ps5169_show(struct dp_parser *parser, enum secdp_ps5169_eq_t eq,
|
||||
enum secdp_ps5169_link_rate_t link_rate, char *buf);
|
||||
int secdp_parse_ps5169_store(struct dp_parser *parser, enum secdp_ps5169_eq_t eq,
|
||||
enum secdp_ps5169_link_rate_t link_rate, char *buf);
|
||||
int secdp_show_ps5169_param(struct dp_parser *parser, char *buf);
|
||||
#endif/*CONFIG_COMBO_REDRIVER_PS5169*/
|
||||
|
||||
/* AUX configuration */
|
||||
int secdp_aux_cfg_show(struct dp_parser *parser, char *buf);
|
||||
int secdp_aux_cfg_store(struct dp_parser *parser, char *buf);
|
||||
#endif/*CONFIG_SECDP_DBG*/
|
||||
|
||||
#endif
|
||||
|
@ -9,6 +9,10 @@
|
||||
#include "dp_debug.h"
|
||||
#include "dp_pll.h"
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
#include <linux/secdp_logger.h>
|
||||
#endif
|
||||
|
||||
static int dp_pll_fill_io(struct dp_pll *pll)
|
||||
{
|
||||
struct dp_parser *parser = pll->parser;
|
||||
|
@ -11,6 +11,28 @@
|
||||
#include "dp_debug.h"
|
||||
#include "dp_pll.h"
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/delay.h>
|
||||
#include "secdp.h"
|
||||
|
||||
#if IS_ENABLED(CONFIG_SBU_SWITCH_CONTROL)// && IS_ENABLED(CONFIG_IF_CB_MANAGER)
|
||||
#include <linux/usb/typec/manager/if_cb_manager.h>
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_COMBO_REDRIVER_PTN36502)
|
||||
#include <linux/combo_redriver/ptn36502.h>
|
||||
#elif IS_ENABLED(CONFIG_COMBO_REDRIVER_PS5169)
|
||||
#include <linux/combo_redriver/ps5169.h>
|
||||
#endif
|
||||
|
||||
#define DP_LINK_BW_RBR 0x06
|
||||
#define DP_LINK_BW_HBR 0x0a
|
||||
#define DP_LINK_BW_HBR2 0x14 /* 1.2 */
|
||||
#define DP_LINK_BW_HBR3 0x1e /* 1.4 */
|
||||
|
||||
#endif/*CONFIG_SECDP*/
|
||||
|
||||
#define DP_CLIENT_NAME_SIZE 20
|
||||
#define XO_CLK_KHZ 19200
|
||||
|
||||
@ -34,8 +56,32 @@ struct dp_power_private {
|
||||
bool strm0_clks_parked;
|
||||
bool strm1_clks_parked;
|
||||
bool link_clks_parked;
|
||||
#if defined(CONFIG_SECDP)
|
||||
bool aux_pullup_on;
|
||||
struct mutex dp_clk_lock;
|
||||
#if IS_ENABLED(CONFIG_SBU_SWITCH_CONTROL)
|
||||
enum sbu_switch_status sbu_status;
|
||||
#endif
|
||||
|
||||
void (*redrv_onoff)(struct dp_power_private *power,
|
||||
bool enable, int lane);
|
||||
void (*redrv_aux_ctrl)(struct dp_power_private *power, int cross);
|
||||
void (*redrv_notify_linkinfo)(struct dp_power_private *power,
|
||||
u32 bw_code, u8 v_level, u8 p_level);
|
||||
#endif
|
||||
};
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
#define DP_ENUM_STR(x) #x
|
||||
|
||||
enum redriver_switch_t {
|
||||
REDRIVER_SWITCH_UNKNOWN = -1,
|
||||
REDRIVER_SWITCH_RESET = 0,
|
||||
REDRIVER_SWITCH_CROSS,
|
||||
REDRIVER_SWITCH_THROU,
|
||||
};
|
||||
#endif
|
||||
|
||||
static int dp_power_regulator_init(struct dp_power_private *power)
|
||||
{
|
||||
int rc = 0, i = 0, j = 0;
|
||||
@ -84,6 +130,86 @@ static void dp_power_regulator_deinit(struct dp_power_private *power)
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
/* factory use only
|
||||
* ref: qusb_phy_enable_power()
|
||||
*/
|
||||
static int secdp_aux_pullup_vreg_enable(struct dp_power_private *power, bool on)
|
||||
{
|
||||
struct regulator *aux_pu_vreg;
|
||||
int rc = 0;
|
||||
|
||||
if (!power || !power->parser) {
|
||||
DP_ERR("error! power is null\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
aux_pu_vreg = power->parser->aux_pullup_vreg;
|
||||
if (!aux_pu_vreg) {
|
||||
DP_ERR("error! vdda33 is null\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
DP_ENTER("on:%d\n", on);
|
||||
|
||||
#define QUSB2PHY_3P3_VOL_MIN 3104000 /* uV */
|
||||
#define QUSB2PHY_3P3_VOL_MAX 3105000 /* uV */
|
||||
#define QUSB2PHY_3P3_HPM_LOAD 30000 /* uA */
|
||||
|
||||
if (on) {
|
||||
if (power->aux_pullup_on) {
|
||||
DP_INFO("already on\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = regulator_set_load(aux_pu_vreg, QUSB2PHY_3P3_HPM_LOAD);
|
||||
if (rc < 0) {
|
||||
DP_ERR("Unable to set HPM of vdda33:%d\n", rc);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = regulator_set_voltage(aux_pu_vreg, QUSB2PHY_3P3_VOL_MIN,
|
||||
QUSB2PHY_3P3_VOL_MAX);
|
||||
if (rc) {
|
||||
DP_ERR("Unable to set voltage for vdda33:%d\n", rc);
|
||||
goto put_vdda33_lpm;
|
||||
}
|
||||
|
||||
rc = regulator_enable(aux_pu_vreg);
|
||||
if (rc) {
|
||||
DP_ERR("Unable to enable vdda33:%d\n", rc);
|
||||
goto unset_vdd33;
|
||||
}
|
||||
|
||||
DP_INFO("[AUX_PU] on success\n");
|
||||
power->aux_pullup_on = true;
|
||||
} else {
|
||||
|
||||
rc = regulator_disable(aux_pu_vreg);
|
||||
if (rc)
|
||||
DP_ERR("Unable to disable vdda33:%d\n", rc);
|
||||
|
||||
unset_vdd33:
|
||||
rc = regulator_set_voltage(aux_pu_vreg, 0,
|
||||
QUSB2PHY_3P3_VOL_MAX);
|
||||
if (rc)
|
||||
DP_ERR("Unable to set 0 voltage for vdda33:%d\n", rc);
|
||||
|
||||
put_vdda33_lpm:
|
||||
rc = regulator_set_load(aux_pu_vreg, 0);
|
||||
if (!rc)
|
||||
DP_INFO("[AUX_PU] off success\n");
|
||||
else
|
||||
DP_ERR("Unable to set 0 HPM of vdda33:%d\n", rc);
|
||||
|
||||
power->aux_pullup_on = false;
|
||||
}
|
||||
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void dp_power_phy_gdsc(struct dp_power *dp_power, bool on)
|
||||
{
|
||||
int rc = 0;
|
||||
@ -139,6 +265,11 @@ static int dp_power_regulator_ctrl(struct dp_power_private *power, bool enable)
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
secdp_aux_pullup_vreg_enable(power, enable);
|
||||
#endif
|
||||
|
||||
error:
|
||||
return rc;
|
||||
}
|
||||
@ -149,6 +280,10 @@ static int dp_power_pinctrl_set(struct dp_power_private *power, bool active)
|
||||
struct pinctrl_state *pin_state;
|
||||
struct dp_parser *parser;
|
||||
|
||||
#if IS_ENABLED(CONFIG_SBU_SWITCH_CONTROL)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
parser = power->parser;
|
||||
|
||||
if (IS_ERR_OR_NULL(parser->pinctrl.pin))
|
||||
@ -363,7 +498,11 @@ static int dp_power_clk_set_rate(struct dp_power_private *power,
|
||||
{
|
||||
int rc = 0;
|
||||
struct dss_module_power *mp;
|
||||
#if defined(CONFIG_SECDP)
|
||||
static bool prev[DP_MAX_PM];
|
||||
|
||||
mutex_lock(&power->dp_clk_lock);
|
||||
#endif
|
||||
if (!power) {
|
||||
DP_ERR("invalid power data\n");
|
||||
rc = -EINVAL;
|
||||
@ -372,6 +511,13 @@ static int dp_power_clk_set_rate(struct dp_power_private *power,
|
||||
|
||||
mp = &power->parser->mp[module];
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
if (prev[module] == enable) {
|
||||
DP_DEBUG("%d clk already %s\n", module, enable ? "enabled" : "disabled");
|
||||
goto exit;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (enable) {
|
||||
rc = msm_dss_clk_set_rate(mp->clk_config, mp->num_clk);
|
||||
if (rc) {
|
||||
@ -393,7 +539,14 @@ static int dp_power_clk_set_rate(struct dp_power_private *power,
|
||||
|
||||
dp_power_park_module(power, module);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
prev[module] = enable;
|
||||
#endif
|
||||
exit:
|
||||
#if defined(CONFIG_SECDP)
|
||||
mutex_unlock(&power->dp_clk_lock);
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -561,6 +714,7 @@ static bool dp_power_find_gpio(const char *gpio1, const char *gpio2)
|
||||
return !!strnstr(gpio1, gpio2, strlen(gpio1));
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_SECDP)
|
||||
static void dp_power_set_gpio(struct dp_power_private *power, bool flip)
|
||||
{
|
||||
int i;
|
||||
@ -586,10 +740,465 @@ static void dp_power_set_gpio(struct dp_power_private *power, bool flip)
|
||||
config++;
|
||||
}
|
||||
}
|
||||
#else
|
||||
int secdp_power_request_gpios(struct dp_power *dp_power)
|
||||
{
|
||||
int rc;
|
||||
struct dp_power_private *power;
|
||||
|
||||
if (!dp_power) {
|
||||
DP_ERR("invalid power data\n");
|
||||
rc = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
power = container_of(dp_power, struct dp_power_private, dp_power);
|
||||
rc = dp_power_request_gpios(power);
|
||||
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_COMBO_REDRIVER_PTN36502) || IS_ENABLED(CONFIG_COMBO_REDRIVER_PS5169)
|
||||
static inline char *secdp_redriver_switch_to_string(int event)
|
||||
{
|
||||
switch (event) {
|
||||
case REDRIVER_SWITCH_UNKNOWN:
|
||||
return DP_ENUM_STR(REDRIVER_SWITCH_UNKNOWN);
|
||||
case REDRIVER_SWITCH_RESET:
|
||||
return DP_ENUM_STR(REDRIVER_SWITCH_RESET);
|
||||
case REDRIVER_SWITCH_CROSS:
|
||||
return DP_ENUM_STR(REDRIVER_SWITCH_CROSS);
|
||||
case REDRIVER_SWITCH_THROU:
|
||||
return DP_ENUM_STR(REDRIVER_SWITCH_THROU);
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_COMBO_REDRIVER_PTN36502)
|
||||
static void secdp_ptn36502_aux_ctrl(struct dp_power_private *power, int cross)
|
||||
{
|
||||
DP_DEBUG("cross:%s\n", secdp_redriver_switch_to_string(cross));
|
||||
|
||||
switch (cross) {
|
||||
case REDRIVER_SWITCH_CROSS:
|
||||
ptn36502_config(AUX_CROSS_MODE, 0);
|
||||
break;
|
||||
case REDRIVER_SWITCH_THROU:
|
||||
ptn36502_config(AUX_THRU_MODE, 0);
|
||||
break;
|
||||
case REDRIVER_SWITCH_RESET:
|
||||
ptn36502_config(SAFE_STATE, 0);
|
||||
break;
|
||||
default:
|
||||
DP_INFO("unknown: %d\n", cross);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void secdp_ptn36502_onoff(struct dp_power_private *power, bool enable, int lane)
|
||||
{
|
||||
DP_DEBUG("en:%d, lane:%d\n", enable, lane);
|
||||
|
||||
if (enable) {
|
||||
int val = -1;
|
||||
|
||||
if (lane == 2)
|
||||
ptn36502_config(DP2_LANE_USB3_MODE, 1);
|
||||
else if (lane == 4)
|
||||
ptn36502_config(DP4_LANE_MODE, 1);
|
||||
else {
|
||||
DP_ERR("error! unknown lane: %d\n", lane);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
val = ptn36502_i2c_read(Chip_ID);
|
||||
DP_INFO("Chip_ID: 0x%x\n", val);
|
||||
val = ptn36502_i2c_read(Chip_Rev);
|
||||
DP_INFO("Chip_Rev: 0x%x\n", val);
|
||||
} else {
|
||||
ptn36502_config(SAFE_STATE, 0);
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
static void secdp_ptn36502_notify_linkinfo(struct dp_power_private *power, u32 bw_code, u8 v_level, u8 p_level)
|
||||
{
|
||||
DP_ENTER("0x%x,%d,%d, do nothing!\n", bw_code, v_level, p_level);
|
||||
|
||||
//.TODO:
|
||||
}
|
||||
#elif IS_ENABLED(CONFIG_COMBO_REDRIVER_PS5169)
|
||||
static void secdp_ps5169_aux_ctrl(struct dp_power_private *power, int cross)
|
||||
{
|
||||
/*
|
||||
* ps5169 does not support AUX switching function.
|
||||
* It needs to be done by AUX switch IC
|
||||
*/
|
||||
DP_ENTER("cross: %s, do nothing!\n",
|
||||
secdp_redriver_switch_to_string(cross));
|
||||
}
|
||||
|
||||
static void secdp_ps5169_onoff(struct dp_power_private *power, bool enable, int lane)
|
||||
{
|
||||
DP_DEBUG("en:%d, lane:%d\n", enable, lane);
|
||||
|
||||
if (enable) {
|
||||
if (lane == 2)
|
||||
ps5169_config(DP2_LANE_USB_MODE, 1);
|
||||
else if (lane == 4)
|
||||
ps5169_config(DP_ONLY_MODE, 1);
|
||||
else {
|
||||
DP_ERR("error! unknown lane: %d\n", lane);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
DP_INFO("Chip_ID1: 0x%x, Chip_Rev1: 0x%x\n",
|
||||
ps5169_i2c_read(Chip_ID1), ps5169_i2c_read(Chip_Rev1));
|
||||
DP_INFO("Chip_ID2: 0x%x, Chip_Rev2: 0x%x\n",
|
||||
ps5169_i2c_read(Chip_ID2), ps5169_i2c_read(Chip_Rev2));
|
||||
} else {
|
||||
ps5169_config(CLEAR_STATE, 0);
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
static void secdp_ps5169_notify_linkinfo(struct dp_power_private *power,
|
||||
u32 bw_code, u8 v_level, u8 p_level)
|
||||
{
|
||||
struct dp_parser *parser = power->parser;
|
||||
u8 eq0, eq1;
|
||||
|
||||
switch (bw_code) {
|
||||
case DP_LINK_BW_RBR:
|
||||
eq0 = parser->ps5169_rbr_eq0[v_level][p_level];
|
||||
eq1 = parser->ps5169_rbr_eq1[v_level][p_level];
|
||||
break;
|
||||
case DP_LINK_BW_HBR:
|
||||
eq0 = parser->ps5169_hbr_eq0[v_level][p_level];
|
||||
eq1 = parser->ps5169_hbr_eq1[v_level][p_level];
|
||||
break;
|
||||
case DP_LINK_BW_HBR2:
|
||||
eq0 = parser->ps5169_hbr2_eq0[v_level][p_level];
|
||||
eq1 = parser->ps5169_hbr2_eq1[v_level][p_level];
|
||||
break;
|
||||
case DP_LINK_BW_HBR3:
|
||||
default:
|
||||
eq0 = parser->ps5169_hbr3_eq0[v_level][p_level];
|
||||
eq1 = parser->ps5169_hbr3_eq1[v_level][p_level];
|
||||
break;
|
||||
}
|
||||
|
||||
DP_DEBUG("bw:0x%x, v:%d, p:%d, eq0:0x%x, eq1:0x%x\n",
|
||||
bw_code, v_level, p_level, eq0, eq1);
|
||||
ps5169_notify_dplink(eq0, eq1);
|
||||
}
|
||||
#endif
|
||||
|
||||
void secdp_redriver_onoff(struct dp_power *dp_power,
|
||||
bool enable, int lane)
|
||||
{
|
||||
struct dp_power_private *power;
|
||||
|
||||
power = container_of(dp_power, struct dp_power_private, dp_power);
|
||||
if (power && power->redrv_onoff)
|
||||
power->redrv_onoff(power, enable, lane);
|
||||
}
|
||||
|
||||
void secdp_redriver_linkinfo(struct dp_power *dp_power,
|
||||
u32 rate, u8 v_level, u8 p_level)
|
||||
{
|
||||
struct dp_power_private *power;
|
||||
|
||||
power = container_of(dp_power, struct dp_power_private, dp_power);
|
||||
if (power && power->redrv_notify_linkinfo)
|
||||
power->redrv_notify_linkinfo(power, rate, v_level, p_level);
|
||||
}
|
||||
|
||||
static void secdp_redriver_register(struct dp_power_private *power)
|
||||
{
|
||||
int use_redrv;
|
||||
|
||||
if (!power || !power->parser) {
|
||||
DP_ERR("invalid power!\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
use_redrv = power->parser->use_redrv;
|
||||
DP_DEBUG("++ use_redrv(%d)\n", use_redrv);
|
||||
|
||||
if (!use_redrv) {
|
||||
DP_INFO("nothing registered!\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_COMBO_REDRIVER_PTN36502)
|
||||
power->redrv_onoff = secdp_ptn36502_onoff;
|
||||
power->redrv_aux_ctrl = secdp_ptn36502_aux_ctrl;
|
||||
power->redrv_notify_linkinfo = secdp_ptn36502_notify_linkinfo;
|
||||
DP_INFO("ptn36502 API registered!\n");
|
||||
#elif IS_ENABLED(CONFIG_COMBO_REDRIVER_PS5169)
|
||||
power->redrv_onoff = secdp_ps5169_onoff;
|
||||
power->redrv_aux_ctrl = secdp_ps5169_aux_ctrl;
|
||||
power->redrv_notify_linkinfo = secdp_ps5169_notify_linkinfo;
|
||||
DP_INFO("ps5169 API registered!\n");
|
||||
#endif
|
||||
|
||||
end:
|
||||
return;
|
||||
}
|
||||
|
||||
#if !IS_ENABLED(CONFIG_SBU_SWITCH_CONTROL)
|
||||
/* turn on EDP_AUX switch
|
||||
* ===================================================
|
||||
* | usbplug-cc(dir) | orientation | flip | aux-sel |
|
||||
* ===================================================
|
||||
* | 0 | CC1 | false | 0 |
|
||||
* | 1 | CC2 | true | 1 |
|
||||
* ===================================================
|
||||
*/
|
||||
static void _secdp_power_set_gpio(struct dp_power_private *power, bool flip)
|
||||
{
|
||||
int i, rc = 0;
|
||||
/*int dir = (flip == false) ? 0 : 1;*/
|
||||
struct dss_module_power *mp = &power->parser->mp[DP_CORE_PM];
|
||||
struct dss_gpio *config = mp->gpio_config;
|
||||
struct dp_parser *parser = power->parser;
|
||||
bool sel_val = false;
|
||||
|
||||
// DP_DEBUG("flip:%d, aux_inv:%d, redrv:%d\n",
|
||||
// flip, parser->aux_sel_inv, parser->use_redrv);
|
||||
|
||||
if (parser->aux_sel_inv)
|
||||
sel_val = true;
|
||||
|
||||
for (i = 0; i < mp->num_gpio; i++) {
|
||||
if (gpio_is_valid(config->gpio)) {
|
||||
if (dp_power_find_gpio(config->gpio_name, "aux-sel")) {
|
||||
if (parser->use_redrv == SECDP_REDRV_PTN36502) {
|
||||
rc = gpio_direction_output(config->gpio, 0);
|
||||
} else {
|
||||
/* SECDP_REDRV_PS5169 or SECDP_REDRV_NONE */
|
||||
bool val = (bool)gpio_get_value(config->gpio);
|
||||
|
||||
if ((!flip && (val == sel_val)) ||
|
||||
(flip && (val == !sel_val))) {
|
||||
DP_DEBUG("%s: already %d %d, skip\n",
|
||||
config->gpio_name, flip, val);
|
||||
break;
|
||||
}
|
||||
rc = gpio_direction_output(config->gpio,
|
||||
(!flip ? sel_val : !sel_val));
|
||||
}
|
||||
usleep_range(100, 120);
|
||||
DP_INFO("[aux-sel] set %d (f:%d,i:%d,r:%d) %d\n",
|
||||
gpio_get_value(config->gpio),
|
||||
flip, parser->aux_sel_inv, parser->use_redrv, rc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
config++;
|
||||
}
|
||||
|
||||
usleep_range(100, 120);
|
||||
config = mp->gpio_config;
|
||||
for (i = 0; i < mp->num_gpio; i++) {
|
||||
if (gpio_is_valid(config->gpio)) {
|
||||
if (dp_power_find_gpio(config->gpio_name, "aux-en")) {
|
||||
if (!gpio_get_value(config->gpio)) {
|
||||
DP_DEBUG("%s: already enabled, skip\n",
|
||||
config->gpio_name);
|
||||
break;
|
||||
}
|
||||
rc = gpio_direction_output(config->gpio, 0);
|
||||
usleep_range(100, 120);
|
||||
DP_INFO("[aux-en] set %d (f:%d,i:%d,r:%d) %d\n",
|
||||
gpio_get_value(config->gpio),
|
||||
flip, parser->aux_sel_inv, parser->use_redrv, rc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
config++;
|
||||
}
|
||||
}
|
||||
|
||||
/* turn off EDP_AUX switch */
|
||||
static void _secdp_power_unset_gpio(struct dp_power_private *power)
|
||||
{
|
||||
int i, rc = 0;
|
||||
struct dss_module_power *mp = &power->parser->mp[DP_CORE_PM];
|
||||
struct dss_gpio *config = mp->gpio_config;
|
||||
|
||||
DP_ENTER("\n");
|
||||
|
||||
for (i = 0; i < mp->num_gpio; i++) {
|
||||
if (gpio_is_valid(config->gpio)) {
|
||||
if (dp_power_find_gpio(config->gpio_name, "aux-en")) {
|
||||
if (gpio_get_value(config->gpio)) {
|
||||
DP_DEBUG("%s: already disabled, skip\n",
|
||||
config->gpio_name);
|
||||
break;
|
||||
}
|
||||
rc = gpio_direction_output(config->gpio, 1);
|
||||
usleep_range(100, 120);
|
||||
DP_INFO("[aux-en] set %d, %d\n",
|
||||
gpio_get_value(config->gpio), rc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
config++;
|
||||
}
|
||||
|
||||
config = mp->gpio_config;
|
||||
for (i = 0; i < mp->num_gpio; i++) {
|
||||
if (gpio_is_valid(config->gpio)) {
|
||||
if (dp_power_find_gpio(config->gpio_name, "aux-sel")) {
|
||||
if (!gpio_get_value(config->gpio)) {
|
||||
DP_DEBUG("%s: already 0, skip\n",
|
||||
config->gpio_name);
|
||||
break;
|
||||
}
|
||||
rc = gpio_direction_output(config->gpio, 0);
|
||||
usleep_range(100, 120);
|
||||
DP_INFO("[aux-sel] set %d, %d\n",
|
||||
gpio_get_value(config->gpio), rc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
config++;
|
||||
}
|
||||
}
|
||||
#else/*CONFIG_SBU_SWITCH_CONTROL*/
|
||||
static void _secdp_sbu_switch_on(struct dp_power_private *power, bool flip)
|
||||
{
|
||||
int cc_sbu = !flip ? CLOSE_SBU_CC1_ACTIVE : CLOSE_SBU_CC2_ACTIVE;
|
||||
|
||||
if (power->sbu_status == cc_sbu)
|
||||
return;
|
||||
|
||||
usbpd_sbu_switch_control(cc_sbu);
|
||||
power->sbu_status = cc_sbu;
|
||||
}
|
||||
|
||||
static void _secdp_sbu_switch_off(struct dp_power_private *power)
|
||||
{
|
||||
if (power->sbu_status == OPEN_SBU)
|
||||
return;
|
||||
|
||||
usbpd_sbu_switch_control(OPEN_SBU);
|
||||
power->sbu_status = OPEN_SBU;
|
||||
}
|
||||
#endif
|
||||
|
||||
void secdp_power_set_gpio(struct dp_power *dp_power, bool flip)
|
||||
{
|
||||
struct dp_power_private *power;
|
||||
|
||||
power = container_of(dp_power, struct dp_power_private, dp_power);
|
||||
|
||||
#if !IS_ENABLED(CONFIG_SBU_SWITCH_CONTROL)
|
||||
_secdp_power_set_gpio(power, flip);
|
||||
#else
|
||||
_secdp_sbu_switch_on(power, flip);
|
||||
#endif
|
||||
}
|
||||
|
||||
void secdp_power_unset_gpio(struct dp_power *dp_power)
|
||||
{
|
||||
struct dp_power_private *power;
|
||||
|
||||
power = container_of(dp_power, struct dp_power_private, dp_power);
|
||||
|
||||
#if !IS_ENABLED(CONFIG_SBU_SWITCH_CONTROL)
|
||||
_secdp_power_unset_gpio(power);
|
||||
#else
|
||||
_secdp_sbu_switch_off(power);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECDP_FACTORY_DPSWITCH_TEST)
|
||||
static void secdp_redriver_aux_ctrl(struct dp_power_private *power,
|
||||
int cross)
|
||||
{
|
||||
if (power && power->redrv_aux_ctrl)
|
||||
power->redrv_aux_ctrl(power, cross);
|
||||
}
|
||||
|
||||
/*
|
||||
* @aux_sel : 1 or 0
|
||||
*/
|
||||
void secdp_config_gpios_factory(struct dp_power *dp_power, int aux_sel, bool on)
|
||||
{
|
||||
struct dp_power_private *power;
|
||||
|
||||
power = container_of(dp_power, struct dp_power_private, dp_power);
|
||||
|
||||
DP_DEBUG("sel:%d, on:%d\n", aux_sel, on);
|
||||
|
||||
if (on) {
|
||||
secdp_aux_pullup_vreg_enable(power, true);
|
||||
secdp_power_set_gpio(dp_power, aux_sel);
|
||||
|
||||
if (aux_sel == 1)
|
||||
secdp_redriver_aux_ctrl(power, REDRIVER_SWITCH_CROSS);
|
||||
else if (aux_sel == 0)
|
||||
secdp_redriver_aux_ctrl(power, REDRIVER_SWITCH_THROU);
|
||||
else
|
||||
DP_ERR("unknown <%d>\n", aux_sel);
|
||||
} else {
|
||||
secdp_redriver_aux_ctrl(power, REDRIVER_SWITCH_RESET);
|
||||
secdp_power_unset_gpio(dp_power);
|
||||
secdp_aux_pullup_vreg_enable(power, false);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
enum dp_hpd_plug_orientation secdp_get_plug_orientation(struct dp_power *dp_power)
|
||||
{
|
||||
struct dp_power_private *power;
|
||||
struct dp_parser *parser;
|
||||
struct dss_module_power *mp;
|
||||
struct dss_gpio *config;
|
||||
int i, dir;
|
||||
|
||||
power = container_of(dp_power, struct dp_power_private, dp_power);
|
||||
parser = power->parser;
|
||||
mp = &power->parser->mp[DP_CORE_PM];
|
||||
config = mp->gpio_config;
|
||||
|
||||
for (i = 0; i < mp->num_gpio; i++) {
|
||||
if (gpio_is_valid(config->gpio)) {
|
||||
if (dp_power_find_gpio(config->gpio_name,
|
||||
"usbplug-cc")) {
|
||||
dir = gpio_get_value(config->gpio);
|
||||
if (parser->cc_dir_inv)
|
||||
dir = !dir;
|
||||
DP_INFO("cc_dir_inv:%d, orientation:%s\n",
|
||||
parser->cc_dir_inv, !dir ? "CC1" : "CC2");
|
||||
if (dir == 0)
|
||||
return ORIENTATION_CC1;
|
||||
else /* if (dir == 1) */
|
||||
return ORIENTATION_CC2;
|
||||
}
|
||||
}
|
||||
config++;
|
||||
}
|
||||
|
||||
/*cannot be here*/
|
||||
return ORIENTATION_NONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int dp_power_config_gpios(struct dp_power_private *power, bool flip,
|
||||
bool enable)
|
||||
{
|
||||
#if !defined(CONFIG_SECDP)
|
||||
int rc = 0, i;
|
||||
struct dss_module_power *mp;
|
||||
struct dss_gpio *config;
|
||||
@ -613,6 +1222,14 @@ static int dp_power_config_gpios(struct dp_power_private *power, bool flip,
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
struct dp_power *dp_power = &power->dp_power;
|
||||
|
||||
if (enable)
|
||||
secdp_power_set_gpio(dp_power, flip);
|
||||
else
|
||||
secdp_power_unset_gpio(dp_power);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -666,8 +1283,19 @@ static int dp_power_client_init(struct dp_power *dp_power,
|
||||
dp_power->phandle = phandle;
|
||||
dp_power->drm_dev = drm_dev;
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
rc = dp_power_pinctrl_set(power, false);
|
||||
if (rc) {
|
||||
DP_ERR("failed to set pinctrl state\n");
|
||||
goto error_client;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
error_client:
|
||||
dp_power_clk_init(power, false);
|
||||
#endif
|
||||
error_clk:
|
||||
dp_power_regulator_deinit(power);
|
||||
error_power:
|
||||
@ -920,6 +1548,11 @@ struct dp_power *dp_power_get(struct dp_parser *parser, struct dp_pll *pll)
|
||||
DP_DEBUG("Optional GDSC regulator is missing\n");
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
secdp_redriver_register(power);
|
||||
mutex_init(&power->dp_clk_lock);
|
||||
#endif
|
||||
|
||||
return dp_power;
|
||||
error:
|
||||
return ERR_PTR(rc);
|
||||
|
@ -66,4 +66,20 @@ struct dp_power *dp_power_get(struct dp_parser *parser, struct dp_pll *pll);
|
||||
* @power: pointer to the power module's data
|
||||
*/
|
||||
void dp_power_put(struct dp_power *power);
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
enum dp_hpd_plug_orientation secdp_get_plug_orientation(struct dp_power *dp_power);
|
||||
|
||||
int secdp_power_request_gpios(struct dp_power *dp_power);
|
||||
void secdp_power_set_gpio(struct dp_power *dp_power, bool flip);
|
||||
void secdp_power_unset_gpio(struct dp_power *dp_power);
|
||||
|
||||
#if defined(CONFIG_SECDP_FACTORY_DPSWITCH_TEST)
|
||||
void secdp_config_gpios_factory(struct dp_power *dp_power, int aux_sel, bool out_en);
|
||||
#endif
|
||||
|
||||
void secdp_redriver_onoff(struct dp_power *dp_power, bool enable, int lane);
|
||||
void secdp_redriver_linkinfo(struct dp_power *dp_power, u32 rate, u8 v_level, u8 p_level);
|
||||
#endif/*CONFIG_SECDP*/
|
||||
|
||||
#endif /* _DP_POWER_H_ */
|
||||
|
432
qcom/opensource/display-drivers/msm/dp/secdp.h
Normal file
432
qcom/opensource/display-drivers/msm/dp/secdp.h
Normal file
@ -0,0 +1,432 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2017-2021, 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 __SECDP_H
|
||||
#define __SECDP_H
|
||||
|
||||
#if IS_ENABLED(CONFIG_USB_TYPEC_MANAGER_NOTIFIER)
|
||||
#include <linux/usb/typec/manager/usb_typec_manager_notifier.h>
|
||||
#endif
|
||||
#if IS_ENABLED(CONFIG_PDIC_NOTIFIER)
|
||||
#include <linux/usb/typec/common/pdic_notifier.h>
|
||||
#endif
|
||||
#include <linux/secdp_logger.h>
|
||||
#include <linux/pm_wakeup.h>
|
||||
#include <linux/sched/clock.h>
|
||||
|
||||
/*#define MODEM_RF_INFO*/
|
||||
#if defined(MODEM_RF_INFO) && IS_ENABLED(CONFIG_DEV_RIL_BRIDGE)
|
||||
#include <linux/dev_ril_bridge.h>
|
||||
|
||||
struct rf_information {
|
||||
u8 rat;
|
||||
u32 band;
|
||||
u32 arfcn;
|
||||
} __packed;
|
||||
#endif
|
||||
|
||||
#include "dp_hpd.h"
|
||||
#include "dp_power.h"
|
||||
#include "dp_panel.h"
|
||||
#include "dp_catalog.h"
|
||||
#include "dp_parser.h"
|
||||
#include "dp_link.h"
|
||||
#include "secdp_sysfs.h"
|
||||
|
||||
/*defined at kmodule/usb/typec/common/pdic_core.h*/
|
||||
#define SAMSUNG_VENDOR_ID 0x04E8
|
||||
|
||||
#define DEXDOCK_PRODUCT_ID 0xA020 /* EE-MG950 DeX Station */
|
||||
#define DEXPAD_PRODUCT_ID 0xA029 /* EE-M5100 DeX Pad */
|
||||
#define DEXCABLE_PRODUCT_ID 0xA048 /* EE-I3100 DeX Cable */
|
||||
#define HG950_PRODUCT_ID 0xA025 /* EE-HG950 HDMI Adapter */
|
||||
#define MPA2_PRODUCT_ID 0xA027 /* EE-P5000 Multiport Adapter */
|
||||
#define MPA3_PRODUCT_ID 0xA056 /* EE-P3200 Multiport Adapter */
|
||||
#define MPA4_PRODUCT_ID 0xA066 /* EE-P5400 Multiport Adapter */
|
||||
|
||||
#define SECDP_ENUM_STR(x) #x
|
||||
|
||||
#define SECDP_USB_CONCURRENCY
|
||||
#define SECDP_USE_WAKELOCK
|
||||
#define SECDP_MAX_HBR2
|
||||
/*#define SECDP_AUDIO_CTS*/
|
||||
/*#define SECDP_HDCP_DISABLE*/
|
||||
/*#define SECDP_TEST_HDCP2P2_REAUTH*/
|
||||
/*#define NOT_SUPPORT_DEX_RES_CHANGE*/
|
||||
#define REMOVE_YUV420_AT_PREFER
|
||||
#define SYSFS_BW_CODE
|
||||
|
||||
#define DPCD_IEEE_OUI 0x500
|
||||
#define DPCD_DEVID_STR 0x503
|
||||
|
||||
#define LEN_BRANCH_REV 3
|
||||
#define DPCD_BRANCH_HW_REV 0x509
|
||||
#define DPCD_BRANCH_SW_REV_MAJOR 0x50A
|
||||
#define DPCD_BRANCH_SW_REV_MINOR 0x50B
|
||||
|
||||
#define MAX_CNT_LINK_STATUS_UPDATE 4
|
||||
#define MAX_CNT_HDCP_RETRY 10
|
||||
|
||||
/* MST: max resolution, max refresh rate, max pclk */
|
||||
#define MST_MAX_COLS 3840
|
||||
#define MST_MAX_ROWS 2160
|
||||
#define MST_MAX_FPS 30
|
||||
#define MST_MAX_PCLK 300000
|
||||
|
||||
#define PDIC_DP_NOTI_REG_DELAY 1000
|
||||
|
||||
/* displayport self test */
|
||||
#if defined(CONFIG_SECDP_DBG)
|
||||
#define SECDP_SELF_TEST
|
||||
#endif
|
||||
|
||||
#ifdef SECDP_SELF_TEST
|
||||
#define ST_EDID_SIZE 256
|
||||
#define ST_ARG_CNT 20
|
||||
#define ST_TEST_EXIT 555
|
||||
|
||||
enum {
|
||||
ST_CLEAR_CMD,
|
||||
ST_LANE_CNT,
|
||||
ST_LINK_RATE,
|
||||
ST_CONNECTION_TEST,
|
||||
ST_HDCP_TEST,
|
||||
ST_PREEM_TUN,
|
||||
ST_VOLTAGE_TUN,
|
||||
ST_MAX,
|
||||
};
|
||||
|
||||
struct secdp_sef_test_item {
|
||||
char cmd_str[20];
|
||||
int arg[ST_ARG_CNT];
|
||||
int arg_cnt;
|
||||
char arg_str[100];
|
||||
bool enabled;
|
||||
void (*clear)(void);
|
||||
};
|
||||
|
||||
int secdp_self_test_status(int cmd);
|
||||
void secdp_self_test_start_reconnect(struct secdp_sysfs *dp_sysfs, void (*func)(struct secdp_misc *sec));
|
||||
void secdp_self_test_start_hdcp_test(struct secdp_sysfs *dp_sysfs, void (*func_on)(void),
|
||||
void (*func_off)(void));
|
||||
//void secdp_self_register_clear_func(int cmd, void (*func)(void));
|
||||
int *secdp_self_test_get_arg(int cmd);
|
||||
#endif/*SECDP_SELF_TEST*/
|
||||
|
||||
/* monitor aspect ratio */
|
||||
enum mon_aspect_ratio_t {
|
||||
MON_RATIO_NA = -1,
|
||||
MON_RATIO_3_2,
|
||||
MON_RATIO_4_3,
|
||||
MON_RATIO_5_3,
|
||||
MON_RATIO_5_4,
|
||||
MON_RATIO_8_5,
|
||||
MON_RATIO_10P5_9,
|
||||
MON_RATIO_11_10,
|
||||
MON_RATIO_16_9,
|
||||
MON_RATIO_16_10,
|
||||
MON_RATIO_21_9,
|
||||
MON_RATIO_21_10,
|
||||
MON_RATIO_32_9,
|
||||
MON_RATIO_32_10,
|
||||
};
|
||||
|
||||
static inline char *secdp_aspect_ratio_to_string(enum mon_aspect_ratio_t ratio)
|
||||
{
|
||||
switch (ratio) {
|
||||
case MON_RATIO_3_2: return DP_ENUM_STR(MON_RATIO_3_2);
|
||||
case MON_RATIO_4_3: return DP_ENUM_STR(MON_RATIO_4_3);
|
||||
case MON_RATIO_5_3: return DP_ENUM_STR(MON_RATIO_5_3);
|
||||
case MON_RATIO_5_4: return DP_ENUM_STR(MON_RATIO_5_4);
|
||||
case MON_RATIO_8_5: return DP_ENUM_STR(MON_RATIO_8_5);
|
||||
case MON_RATIO_10P5_9: return DP_ENUM_STR(MON_RATIO_10P5_9);
|
||||
case MON_RATIO_11_10: return DP_ENUM_STR(MON_RATIO_11_10);
|
||||
case MON_RATIO_16_9: return DP_ENUM_STR(MON_RATIO_16_9);
|
||||
case MON_RATIO_16_10: return DP_ENUM_STR(MON_RATIO_16_10);
|
||||
case MON_RATIO_21_9: return DP_ENUM_STR(MON_RATIO_21_9);
|
||||
case MON_RATIO_21_10: return DP_ENUM_STR(MON_RATIO_21_10);
|
||||
case MON_RATIO_32_9: return DP_ENUM_STR(MON_RATIO_32_9);
|
||||
case MON_RATIO_32_10: return DP_ENUM_STR(MON_RATIO_32_10);
|
||||
case MON_RATIO_NA: return DP_ENUM_STR(MON_RATIO_NA);
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
/* adapter type : SST or MST */
|
||||
enum secdp_adapter_t {
|
||||
SECDP_ADT_UNKNOWN = -1,
|
||||
SECDP_ADT_SST = 10,
|
||||
SECDP_ADT_MST = 11,
|
||||
};
|
||||
|
||||
/* dex supported resolutions */
|
||||
enum dex_support_res_t {
|
||||
DEX_RES_NOT_SUPPORT = 0,
|
||||
DEX_RES_1600X900, /* HD+ */
|
||||
DEX_RES_1920X1080, /* FHD */
|
||||
DEX_RES_1920X1200, /* WUXGA */
|
||||
DEX_RES_2560X1080, /* UW-UXGA */
|
||||
DEX_RES_2560X1440, /* QHD */
|
||||
DEX_RES_2560X1600, /* WQXGA */
|
||||
DEX_RES_3440X1440, /* UW-QHD */
|
||||
DEX_RES_END,
|
||||
};
|
||||
#define DEX_RES_DFT DEX_RES_1920X1080 /* DeX default timing */
|
||||
#define DEX_DFT_COL 1920
|
||||
#define DEX_DFT_ROW 1080
|
||||
#define DEX_RES_MAX DEX_RES_3440X1440 /* DeX max timing */
|
||||
#define DEX_MAX_COL 3440
|
||||
#define DEX_MAX_ROW 1440
|
||||
|
||||
#define DEX_REFRESH_MIN 50
|
||||
#define DEX_REFRESH_MAX 60
|
||||
#define MIRROR_REFRESH_MIN 24
|
||||
|
||||
static inline char *secdp_dex_res_to_string(int res)
|
||||
{
|
||||
switch (res) {
|
||||
case DEX_RES_NOT_SUPPORT:
|
||||
return DP_ENUM_STR(DEX_RES_NOT_SUPPORT);
|
||||
case DEX_RES_1600X900:
|
||||
return DP_ENUM_STR(DEX_RES_1600X900);
|
||||
case DEX_RES_1920X1080:
|
||||
return DP_ENUM_STR(DEX_RES_1920X1080);
|
||||
case DEX_RES_1920X1200:
|
||||
return DP_ENUM_STR(DEX_RES_1920X1200);
|
||||
case DEX_RES_2560X1080:
|
||||
return DP_ENUM_STR(DEX_RES_2560X1080);
|
||||
case DEX_RES_2560X1440:
|
||||
return DP_ENUM_STR(DEX_RES_2560X1440);
|
||||
case DEX_RES_2560X1600:
|
||||
return DP_ENUM_STR(DEX_RES_2560X1600);
|
||||
case DEX_RES_3440X1440:
|
||||
return DP_ENUM_STR(DEX_RES_3440X1440);
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
enum DEX_STATUS {
|
||||
DEX_DISABLED = 0,
|
||||
DEX_ENABLED,
|
||||
DEX_MODE_CHANGING,
|
||||
};
|
||||
|
||||
/** redriver devices */
|
||||
enum secdp_redrv_dev {
|
||||
SECDP_REDRV_NONE = 0,
|
||||
SECDP_REDRV_PTN36502, /* don't need AUX_SEL control */
|
||||
SECDP_REDRV_PS5169, /* need AUX_SEL control */
|
||||
};
|
||||
|
||||
static inline char *secdp_redrv_to_string(int res)
|
||||
{
|
||||
switch (res) {
|
||||
case SECDP_REDRV_NONE:
|
||||
return DP_ENUM_STR(SECDP_REDRV_NONE);
|
||||
case SECDP_REDRV_PTN36502:
|
||||
return DP_ENUM_STR(SECDP_REDRV_PTN36502);
|
||||
case SECDP_REDRV_PS5169:
|
||||
return DP_ENUM_STR(SECDP_REDRV_PS5169);
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
struct secdp_adapter {
|
||||
uint ven_id;
|
||||
uint prod_id;
|
||||
char ieee_oui[4]; /* DPCD 500h ~ 502h */
|
||||
char devid_str[7]; /* DPCD 503h ~ 508h */
|
||||
char fw_ver[10]; /* firmware ver, 0:h/w, 1:s/w major, 2:s/w minor */
|
||||
|
||||
bool ss_genuine;
|
||||
bool ss_legacy;
|
||||
enum dex_support_res_t dex_type;
|
||||
};
|
||||
|
||||
#define MON_NAME_LEN 14 /* monitor name length, max 13 chars + null */
|
||||
|
||||
#define MAX_NUM_HMD 32
|
||||
#define DEX_TAG_HMD "HMD"
|
||||
|
||||
struct secdp_sink_dev {
|
||||
uint ven_id; /* vendor id from PDIC */
|
||||
uint prod_id; /* product id from PDIC */
|
||||
char monitor_name[MON_NAME_LEN]; /* from EDID */
|
||||
};
|
||||
|
||||
struct secdp_pdic_noti {
|
||||
struct delayed_work reg_work;
|
||||
struct notifier_block nb;
|
||||
bool registered;
|
||||
bool reset; /* true if PDIC or SSUSB get reset after DP connection */
|
||||
};
|
||||
|
||||
struct secdp_prefer {
|
||||
enum mon_aspect_ratio_t ratio;
|
||||
|
||||
bool exist; /* true if preferred resolution */
|
||||
int hdisp; /* horizontal pixel of preferred resolution */
|
||||
int vdisp; /* vertical pixel of preferred resolution */
|
||||
int refresh; /* refresh rate of preferred resolution */
|
||||
};
|
||||
|
||||
struct secdp_dex {
|
||||
struct class *sysfs_class;
|
||||
enum dex_support_res_t res; /* dex supported resolution */
|
||||
|
||||
enum DEX_STATUS prev; /* previously known as "dex_now" */
|
||||
enum DEX_STATUS curr; /* previously known as "dex_en" */
|
||||
int setting_ui; /* "dex_set", true if setting has Dex mode */
|
||||
|
||||
bool ignore_prefer_ratio; /* true if prefer ratio does not match to dex ratio */
|
||||
bool adapter_check_skip;
|
||||
|
||||
/*
|
||||
* 2 if resolution is changed during dex mode change.
|
||||
* And once dex framework reads the dex_node_stauts using dex node,
|
||||
* it's assigned to same value with curr.
|
||||
*/
|
||||
enum DEX_STATUS status; /* previously known as "dex_node_status" */
|
||||
|
||||
bool reconnecting; /* true if dex is under reconnecting */
|
||||
};
|
||||
|
||||
struct secdp_display_timing {
|
||||
u32 active_h;
|
||||
u32 active_v;
|
||||
u32 refresh_rate;
|
||||
bool interlaced;
|
||||
int clock; /* pixel clock, refer to "struct drm_display_mode" */
|
||||
enum dex_support_res_t dex_res; /* dex supported resolution */
|
||||
enum mon_aspect_ratio_t mon_ratio; /* monitor aspect ratio */
|
||||
int supported; /* for unit test */
|
||||
u64 total;
|
||||
};
|
||||
|
||||
struct secdp_hmd {
|
||||
struct secdp_sink_dev list[MAX_NUM_HMD]; /* supported HMD dev list */
|
||||
struct mutex lock;
|
||||
bool exist; /* true if connected sink is known HMD device */
|
||||
};
|
||||
|
||||
struct secdp_hdcp {
|
||||
struct delayed_work start_work;
|
||||
int retry; /* count if dp link is unstable during hdcp */
|
||||
};
|
||||
|
||||
struct secdp_hpd {
|
||||
struct delayed_work noti_work;
|
||||
bool noti_deferred;
|
||||
atomic_t val; /* 1 if hpd high, 0 if hpd low" */
|
||||
bool prev_evt;
|
||||
};
|
||||
|
||||
struct secdp_debug {
|
||||
bool prefer_check_skip;
|
||||
};
|
||||
|
||||
struct secdp_misc {
|
||||
struct delayed_work link_status_work;
|
||||
struct delayed_work link_backoff_work;
|
||||
bool backoff_start;
|
||||
struct delayed_work poor_discon_work;
|
||||
|
||||
struct device *uevent_dev;
|
||||
#ifdef MODEM_RF_INFO
|
||||
struct rf_information rf_info;
|
||||
struct notifier_block modem_rfinfo_nb;
|
||||
#endif
|
||||
|
||||
bool extdisp_off;
|
||||
bool cable_connected; /* previously known as "cable_connected_phy" */
|
||||
bool link_conf; /* previously known as "sec_link_conf" */
|
||||
struct secdp_hpd hpd;
|
||||
int mode_cnt;
|
||||
|
||||
struct secdp_adapter adapter;
|
||||
struct secdp_pdic_noti pdic_noti;
|
||||
|
||||
struct secdp_display_timing prf_timing; /* preferred timing */
|
||||
struct secdp_display_timing mrr_timing; /* max "mirror" timing */
|
||||
struct secdp_display_timing dex_timing; /* max "dex" timing */
|
||||
|
||||
struct secdp_prefer prefer;
|
||||
struct secdp_hdcp hdcp;
|
||||
struct secdp_debug debug;
|
||||
struct secdp_sysfs *sysfs;
|
||||
struct secdp_dex dex;
|
||||
struct secdp_hmd hmd;
|
||||
|
||||
struct completion dp_off_comp;
|
||||
struct completion dp_discon_comp;
|
||||
bool dp_disconnecting;
|
||||
bool lpm_booting;
|
||||
|
||||
struct mutex notify_lock;
|
||||
struct mutex attention_lock;
|
||||
struct mutex notifier_lock;
|
||||
atomic_t noti_status;
|
||||
|
||||
struct notifier_block reboot_nb;
|
||||
bool reboot; /* true if rebooted or shutdown */
|
||||
|
||||
#ifdef SECDP_USE_WAKELOCK
|
||||
struct wakeup_source *ws;
|
||||
#endif
|
||||
#ifdef SECDP_SELF_TEST
|
||||
struct delayed_work self_test_reconnect_work;
|
||||
struct delayed_work self_test_hdcp_test_work;
|
||||
|
||||
void (*self_test_reconnect_cb)(struct secdp_misc *sec);
|
||||
void (*self_test_hdcp_on_cb)(void);
|
||||
void (*self_test_hdcp_off_cb)(void);
|
||||
#endif
|
||||
};
|
||||
|
||||
bool secdp_adapter_check_parade(struct secdp_misc *sec);
|
||||
bool secdp_adapter_check_ps176(struct secdp_misc *sec);
|
||||
bool secdp_adapter_check_ps176_legacy(struct secdp_misc *sec);
|
||||
bool secdp_adapter_check_realtek(struct secdp_misc *sec);
|
||||
|
||||
bool secdp_get_lpm_mode(struct secdp_misc *sec);
|
||||
int secdp_send_deferred_hpd_noti(struct secdp_misc *sec);
|
||||
|
||||
int secdp_pdic_noti_register_ex(struct secdp_misc *sec, bool retry);
|
||||
bool secdp_phy_reset_check(void);
|
||||
bool secdp_get_power_status(void);
|
||||
bool secdp_get_cable_status(void);
|
||||
bool secdp_get_hpd_irq_status(void);
|
||||
int secdp_get_hpd_status(void);
|
||||
struct drm_connector *secdp_get_connector(void);
|
||||
|
||||
bool secdp_get_reboot_status(void);
|
||||
|
||||
bool secdp_check_hmd_dev(struct secdp_misc *sec, const char *name_to_search);
|
||||
int secdp_store_hmd_dev(struct secdp_misc *sec, char *buf, size_t len, int num);
|
||||
|
||||
void secdp_timing_init(struct secdp_misc *sec);
|
||||
void secdp_extdisp_on(struct secdp_misc *sec);
|
||||
void secdp_extdisp_off(struct secdp_misc *sec);
|
||||
void secdp_reconnect(struct secdp_misc *sec);
|
||||
bool secdp_check_reconnect(struct secdp_misc *sec);
|
||||
|
||||
void secdp_link_backoff_start(void);
|
||||
void secdp_link_backoff_stop(void);
|
||||
bool secdp_adapter_is_legacy(void);
|
||||
|
||||
bool secdp_panel_hdr_supported(void);
|
||||
|
||||
#endif/*__SECDP_H*/
|
360
qcom/opensource/display-drivers/msm/dp/secdp_bigdata.c
Normal file
360
qcom/opensource/display-drivers/msm/dp/secdp_bigdata.c
Normal file
@ -0,0 +1,360 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2017-2021 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com
|
||||
*
|
||||
* DP bigdata
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/secdp_bigdata.h>
|
||||
|
||||
#define EDID_BUF_SIZE 512
|
||||
#define ERR_DATA_BUF_SIZE 1024
|
||||
#define COL_NAME_SIZE 20
|
||||
|
||||
enum DP_ITEM_TYPE {
|
||||
INT = 1,
|
||||
HEX = 2,
|
||||
STR = 4,
|
||||
CHR = 8,
|
||||
ERR = 16,
|
||||
};
|
||||
|
||||
enum DP_STATUS {
|
||||
STATUS_NO_CONNECTION,
|
||||
STATUS_CONNECTION,
|
||||
STATUS_ERROR_OCCURRED,
|
||||
};
|
||||
|
||||
struct bd_item_info {
|
||||
char name[COL_NAME_SIZE];
|
||||
char type;
|
||||
void *data;
|
||||
int str_max_len;
|
||||
};
|
||||
|
||||
struct bd_error_data {
|
||||
int limit;
|
||||
int count;
|
||||
};
|
||||
|
||||
static char err_data_buf[ERR_DATA_BUF_SIZE];
|
||||
static struct bd_item_info item_to_column[BD_ITEM_MAX];
|
||||
static enum DP_STATUS dp_status;
|
||||
|
||||
static void secdp_bigdata_save_data(void);
|
||||
static void secdp_bigdata_init_item(enum DP_BD_ITEM_LIST item, char *col_name, enum DP_ITEM_TYPE type, ...);
|
||||
static void secdp_bigdata_init_error(enum DP_BD_ITEM_LIST item, char *col_name, int err_limit);
|
||||
static void secdp_bigdata_save_item_int(enum DP_BD_ITEM_LIST item, int val);
|
||||
static void secdp_bigdata_save_item_hex(enum DP_BD_ITEM_LIST item, int val);
|
||||
static void secdp_bigdata_save_item_char(enum DP_BD_ITEM_LIST item, char val);
|
||||
static void secdp_bigdata_save_item_str(enum DP_BD_ITEM_LIST item, char *val);
|
||||
|
||||
ssize_t _secdp_bigdata_show(struct class *class,
|
||||
struct class_attribute *attr, char *buf)
|
||||
{
|
||||
if (dp_status == STATUS_NO_CONNECTION)
|
||||
return 0;
|
||||
|
||||
return scnprintf(buf, ERR_DATA_BUF_SIZE, "%s", err_data_buf);
|
||||
}
|
||||
|
||||
ssize_t _secdp_bigdata_store(struct class *dev,
|
||||
struct class_attribute *attr, const char *buf, size_t size)
|
||||
{
|
||||
if ((buf[0] | 0x20) == 'c')
|
||||
dp_status = STATUS_NO_CONNECTION;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void secdp_bigdata_init(struct class *dp_class)
|
||||
{
|
||||
secdp_bigdata_init_item(BD_LINK_CONFIGURE, "LINK_CFG", CHR);
|
||||
secdp_bigdata_init_item(BD_ADAPTER_HWID, "ADT_HWID", HEX);
|
||||
secdp_bigdata_init_item(BD_ADAPTER_FWVER, "ADT_FWVER", HEX);
|
||||
secdp_bigdata_init_item(BD_ADAPTER_TYPE, "ADT_TYPE", STR, 20);
|
||||
secdp_bigdata_init_item(BD_MAX_LANE_COUNT, "MLANE_CNT", INT);
|
||||
secdp_bigdata_init_item(BD_MAX_LINK_RATE, "MLINK_RATE", INT);
|
||||
secdp_bigdata_init_item(BD_CUR_LANE_COUNT, "CLANE_CNT", INT);
|
||||
secdp_bigdata_init_item(BD_CUR_LINK_RATE, "CLINK_RATE", INT);
|
||||
secdp_bigdata_init_item(BD_HDCP_VER, "HDCP_VER", STR, 10);
|
||||
secdp_bigdata_init_item(BD_ORIENTATION, "ORIENTATION", STR, 10);
|
||||
secdp_bigdata_init_item(BD_RESOLUTION, "RESOLUTION", STR, 20);
|
||||
secdp_bigdata_init_item(BD_EDID, "EDID", STR, EDID_BUF_SIZE);
|
||||
secdp_bigdata_init_item(BD_ADT_VID, "ADT_VID", HEX);
|
||||
secdp_bigdata_init_item(BD_ADT_PID, "ADT_PID", HEX);
|
||||
secdp_bigdata_init_item(BD_DP_MODE, "DP_MODE", STR, 10);
|
||||
secdp_bigdata_init_item(BD_SINK_NAME, "SINK_NAME", STR, 14);
|
||||
secdp_bigdata_init_item(BD_AUD_CH, "AUD_CH", INT);
|
||||
secdp_bigdata_init_item(BD_AUD_FREQ, "AUD_FREQ", INT);
|
||||
secdp_bigdata_init_item(BD_AUD_BIT, "AUD_BIT", INT);
|
||||
|
||||
secdp_bigdata_init_error(ERR_AUX, "ERR_AUX", 3);
|
||||
secdp_bigdata_init_error(ERR_EDID, "ERR_EDID", 1);
|
||||
secdp_bigdata_init_error(ERR_HDCP_AUTH, "ERR_HDCP", 5);
|
||||
secdp_bigdata_init_error(ERR_LINK_TRAIN, "ERR_LT_TRAIN", 1);
|
||||
secdp_bigdata_init_error(ERR_INF_IRQHPD, "ERR_INF_IRQHPD", 10);
|
||||
}
|
||||
|
||||
static void secdp_bigdata_init_item_str(enum DP_BD_ITEM_LIST item, char *val, int max_len)
|
||||
{
|
||||
kfree(item_to_column[item].data);
|
||||
|
||||
item_to_column[item].data = kzalloc(max_len + 1, GFP_KERNEL);
|
||||
if (!item_to_column[item].data)
|
||||
return;
|
||||
|
||||
item_to_column[item].str_max_len = max_len;
|
||||
strlcpy((char *)item_to_column[item].data, val, max_len + 1);
|
||||
}
|
||||
|
||||
static void secdp_bigdata_init_item(enum DP_BD_ITEM_LIST item, char *col_name, enum DP_ITEM_TYPE type, ...)
|
||||
{
|
||||
va_list vl;
|
||||
|
||||
va_start(vl, type);
|
||||
|
||||
strlcpy(item_to_column[item].name, col_name, COL_NAME_SIZE);
|
||||
item_to_column[item].type = type;
|
||||
|
||||
switch (type) {
|
||||
case INT:
|
||||
case HEX:
|
||||
secdp_bigdata_save_item_int(item, -1);
|
||||
break;
|
||||
case STR:
|
||||
secdp_bigdata_init_item_str(item, "X", (int)va_arg(vl, int));
|
||||
break;
|
||||
case CHR:
|
||||
secdp_bigdata_save_item_char(item, 'X');
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
va_end(vl);
|
||||
}
|
||||
|
||||
static void secdp_bigdata_init_error(enum DP_BD_ITEM_LIST item, char *col_name, int err_limit)
|
||||
{
|
||||
struct bd_error_data *err = kzalloc(sizeof(struct bd_error_data), GFP_KERNEL);
|
||||
|
||||
if (err)
|
||||
err->limit = err_limit;
|
||||
|
||||
strlcpy(item_to_column[item].name, col_name, COL_NAME_SIZE);
|
||||
item_to_column[item].type = ERR;
|
||||
item_to_column[item].data = err;
|
||||
}
|
||||
|
||||
static void secdp_bigdata_save_item_int(enum DP_BD_ITEM_LIST item, int val)
|
||||
{
|
||||
if (!item_to_column[item].data) {
|
||||
item_to_column[item].data = kzalloc(sizeof(int), GFP_KERNEL);
|
||||
if (!item_to_column[item].data)
|
||||
return;
|
||||
}
|
||||
|
||||
*((int *)item_to_column[item].data) = val;
|
||||
}
|
||||
|
||||
static void secdp_bigdata_save_item_hex(enum DP_BD_ITEM_LIST item, int val)
|
||||
{
|
||||
secdp_bigdata_save_item_int(item, val);
|
||||
}
|
||||
|
||||
static void secdp_bigdata_save_item_char(enum DP_BD_ITEM_LIST item, char val)
|
||||
{
|
||||
if (!item_to_column[item].data) {
|
||||
item_to_column[item].data = kzalloc(sizeof(char), GFP_KERNEL);
|
||||
if (!item_to_column[item].data)
|
||||
return;
|
||||
}
|
||||
|
||||
*((char *)item_to_column[item].data) = val;
|
||||
}
|
||||
|
||||
static void secdp_bigdata_save_item_str(enum DP_BD_ITEM_LIST item, char *val)
|
||||
{
|
||||
if (!item_to_column[item].data || !val)
|
||||
return;
|
||||
|
||||
if (item == BD_EDID && val[0] != 'X') {
|
||||
int ret = 0;
|
||||
int i;
|
||||
int ext_blk_cnt = val[0x7e] ? 1 : 0;
|
||||
int edid_size = 128 * (ext_blk_cnt + 1);
|
||||
|
||||
for (i = 0; i < edid_size; i++) {
|
||||
ret += scnprintf(((char *)item_to_column[item].data) + ret,
|
||||
EDID_BUF_SIZE + 1 - ret, "%02x",
|
||||
val[i]);
|
||||
}
|
||||
|
||||
} else {
|
||||
strlcpy((char *)item_to_column[item].data, val,
|
||||
item_to_column[item].str_max_len + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void secdp_bigdata_save_item(enum DP_BD_ITEM_LIST item, ...)
|
||||
{
|
||||
va_list vl;
|
||||
|
||||
if (item >= BD_ITEM_MAX || item < 0)
|
||||
return;
|
||||
|
||||
va_start(vl, item);
|
||||
|
||||
switch (item_to_column[item].type) {
|
||||
case INT:
|
||||
secdp_bigdata_save_item_hex(item, (int)va_arg(vl, int));
|
||||
break;
|
||||
case HEX:
|
||||
secdp_bigdata_save_item_int(item, (int)va_arg(vl, int));
|
||||
break;
|
||||
case STR:
|
||||
secdp_bigdata_save_item_str(item, (char *)va_arg(vl, char *));
|
||||
break;
|
||||
case CHR:
|
||||
secdp_bigdata_save_item_char(item, (char)va_arg(vl, int));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
va_end(vl);
|
||||
}
|
||||
|
||||
void secdp_bigdata_inc_error_cnt(enum DP_BD_ITEM_LIST err)
|
||||
{
|
||||
if (err >= BD_ITEM_MAX || err < 0)
|
||||
return;
|
||||
|
||||
if (item_to_column[err].data && item_to_column[err].type == ERR)
|
||||
((struct bd_error_data *)item_to_column[err].data)->count++;
|
||||
}
|
||||
|
||||
void secdp_bigdata_clr_error_cnt(enum DP_BD_ITEM_LIST err)
|
||||
{
|
||||
if (err >= BD_ITEM_MAX || err < 0)
|
||||
return;
|
||||
|
||||
if (item_to_column[err].data && item_to_column[err].type == ERR)
|
||||
((struct bd_error_data *)item_to_column[err].data)->count = 0;
|
||||
}
|
||||
|
||||
static void secdp_bigdata_save_data(void)
|
||||
{
|
||||
int i;
|
||||
int ret = 0;
|
||||
|
||||
for (i = 0; i < BD_ITEM_MAX; i++) {
|
||||
switch (item_to_column[i].type) {
|
||||
case INT:
|
||||
ret += scnprintf(err_data_buf + ret, ERR_DATA_BUF_SIZE - ret,
|
||||
"\"%s\":\"%d\",",
|
||||
item_to_column[i].name,
|
||||
(item_to_column[i].data != NULL) ?
|
||||
*((int *)item_to_column[i].data) : -1);
|
||||
break;
|
||||
case HEX:
|
||||
ret += scnprintf(err_data_buf + ret, ERR_DATA_BUF_SIZE - ret,
|
||||
"\"%s\":\"0x%x\",",
|
||||
item_to_column[i].name,
|
||||
(item_to_column[i].data != NULL) ?
|
||||
*((int *)item_to_column[i].data) : -1);
|
||||
break;
|
||||
case STR:
|
||||
ret += scnprintf(err_data_buf + ret, ERR_DATA_BUF_SIZE - ret,
|
||||
"\"%s\":\"%s\",",
|
||||
item_to_column[i].name,
|
||||
(item_to_column[i].data != NULL) ?
|
||||
(char *)item_to_column[i].data : "X");
|
||||
break;
|
||||
case CHR:
|
||||
ret += scnprintf(err_data_buf + ret, ERR_DATA_BUF_SIZE - ret,
|
||||
"\"%s\":\"%c\",",
|
||||
item_to_column[i].name,
|
||||
(item_to_column[i].data != NULL) ?
|
||||
*((char *)item_to_column[i].data) : 'X');
|
||||
break;
|
||||
case ERR:
|
||||
ret += scnprintf(err_data_buf + ret, ERR_DATA_BUF_SIZE - ret,
|
||||
"\"%s\":\"%d\",",
|
||||
item_to_column[i].name,
|
||||
(item_to_column[i].data != NULL) ?
|
||||
((struct bd_error_data *)item_to_column[i].data)->count : 0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret > 0)
|
||||
err_data_buf[ret - 1] = '\n';
|
||||
}
|
||||
|
||||
static int secdp_bigdata_check_err(void)
|
||||
{
|
||||
int i;
|
||||
struct bd_error_data *e_data;
|
||||
|
||||
for (i = 0; i < BD_ITEM_MAX; i++) {
|
||||
if (item_to_column[i].type == ERR) {
|
||||
e_data = item_to_column[i].data;
|
||||
if (e_data != NULL && e_data->count >= e_data->limit)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void secdp_bigdata_connection(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (dp_status != STATUS_ERROR_OCCURRED)
|
||||
dp_status = STATUS_CONNECTION;
|
||||
|
||||
for (i = 0; i < BD_ITEM_MAX; i++) {
|
||||
switch (item_to_column[i].type) {
|
||||
case INT:
|
||||
case HEX:
|
||||
secdp_bigdata_save_item_int(i, -1);
|
||||
break;
|
||||
case STR:
|
||||
secdp_bigdata_save_item_str(i, "X");
|
||||
break;
|
||||
case CHR:
|
||||
secdp_bigdata_save_item_char(i, 'X');
|
||||
break;
|
||||
case ERR:
|
||||
secdp_bigdata_clr_error_cnt(i);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void secdp_bigdata_disconnection(void)
|
||||
{
|
||||
if (secdp_bigdata_check_err()) {
|
||||
dp_status = STATUS_ERROR_OCCURRED;
|
||||
secdp_bigdata_save_data();
|
||||
}
|
||||
|
||||
if (dp_status != STATUS_ERROR_OCCURRED)
|
||||
secdp_bigdata_save_data();
|
||||
|
||||
}
|
257
qcom/opensource/display-drivers/msm/dp/secdp_logger.c
Normal file
257
qcom/opensource/display-drivers/msm/dp/secdp_logger.c
Normal file
@ -0,0 +1,257 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2017-2022 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com
|
||||
*
|
||||
* SECDP logger
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/version.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/ktime.h>
|
||||
#if LINUX_VERSION_CODE > KERNEL_VERSION(4, 10, 0)
|
||||
#include <linux/sched/clock.h>
|
||||
#else
|
||||
#include <linux/sched.h>
|
||||
#endif
|
||||
#include <linux/secdp_logger.h>
|
||||
|
||||
#include "secdp_unit_test.h"
|
||||
|
||||
#define BUF_SIZE SZ_64K
|
||||
#define MAX_STR_LEN 160
|
||||
#define PROC_FILE_NAME "dplog"
|
||||
#define LOG_PREFIX "secdp"
|
||||
|
||||
static char log_buf[BUF_SIZE];
|
||||
static unsigned int g_curpos;
|
||||
static int is_secdp_logger_init;
|
||||
static int is_buf_full;
|
||||
static int log_max_count = -1;
|
||||
static unsigned int max_mode_count;
|
||||
static struct mutex dplog_lock;
|
||||
static struct proc_dir_entry *g_entry;
|
||||
|
||||
static void dp_logger_print_date_time(void)
|
||||
{
|
||||
char tmp[64] = {0x0, };
|
||||
struct tm tm;
|
||||
struct timespec64 ts;
|
||||
unsigned long sec;
|
||||
|
||||
ktime_get_real_ts64(&ts);
|
||||
sec = ts.tv_sec - (sys_tz.tz_minuteswest * 60);
|
||||
time64_to_tm(sec, 0, &tm);
|
||||
snprintf(tmp, sizeof(tmp), "!@[%02d-%02d %02d:%02d:%02d.%03lu]",
|
||||
tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
|
||||
ts.tv_nsec / 1000000);
|
||||
|
||||
secdp_logger_print("%s\n", tmp);
|
||||
}
|
||||
|
||||
/* set max log count, if count is -1, no limit */
|
||||
void secdp_logger_set_max_count(int count)
|
||||
{
|
||||
log_max_count = count;
|
||||
dp_logger_print_date_time();
|
||||
}
|
||||
|
||||
static void _secdp_logger_print(const char *fmt, va_list args)
|
||||
{
|
||||
int len;
|
||||
char buf[MAX_STR_LEN] = {0, };
|
||||
u64 time;
|
||||
unsigned long nsec;
|
||||
volatile unsigned int curpos;
|
||||
|
||||
mutex_lock(&dplog_lock);
|
||||
|
||||
time = local_clock();
|
||||
nsec = do_div(time, 1000000000);
|
||||
len = snprintf(buf, sizeof(buf), "[%5lu.%06ld] ",
|
||||
(unsigned long)time, nsec / 1000);
|
||||
|
||||
len += vsnprintf(buf + len, MAX_STR_LEN - len, fmt, args);
|
||||
if (len > MAX_STR_LEN)
|
||||
len = MAX_STR_LEN;
|
||||
|
||||
curpos = g_curpos;
|
||||
if (curpos + len >= BUF_SIZE) {
|
||||
g_curpos = curpos = 0;
|
||||
is_buf_full = 1;
|
||||
}
|
||||
memcpy(log_buf + curpos, buf, len);
|
||||
g_curpos += len;
|
||||
|
||||
mutex_unlock(&dplog_lock);
|
||||
}
|
||||
|
||||
void secdp_logger_print(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
if (!is_secdp_logger_init)
|
||||
return;
|
||||
|
||||
if (!log_max_count)
|
||||
return;
|
||||
|
||||
if (log_max_count > 0)
|
||||
log_max_count--;
|
||||
|
||||
va_start(args, fmt);
|
||||
_secdp_logger_print(fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/* set max num of modes print */
|
||||
void secdp_logger_set_mode_max_count(unsigned int num)
|
||||
{
|
||||
max_mode_count = num + 1;
|
||||
}
|
||||
|
||||
void secdp_logger_dec_mode_count(void)
|
||||
{
|
||||
if (!is_secdp_logger_init)
|
||||
return;
|
||||
|
||||
if (max_mode_count > 0)
|
||||
max_mode_count--;
|
||||
}
|
||||
|
||||
void secdp_logger_print_mode(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
if (!is_secdp_logger_init)
|
||||
return;
|
||||
|
||||
if (!max_mode_count)
|
||||
return;
|
||||
|
||||
va_start(args, fmt);
|
||||
_secdp_logger_print(fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void secdp_logger_hex_dump(void *buf, void *pref, size_t size)
|
||||
{
|
||||
uint8_t *ptr = buf;
|
||||
size_t i;
|
||||
char tmp[128] = {0x0, };
|
||||
char *ptmp = tmp;
|
||||
int len;
|
||||
|
||||
if (!is_secdp_logger_init)
|
||||
return;
|
||||
|
||||
if (!log_max_count)
|
||||
return;
|
||||
|
||||
if (log_max_count > 0)
|
||||
log_max_count--;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
len = snprintf(ptmp, 4, "%02x ", *ptr++);
|
||||
ptmp = ptmp + len;
|
||||
if (((i+1)%16) == 0) {
|
||||
secdp_logger_print("%s%s\n", (char *)pref, tmp);
|
||||
ptmp = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
if (i % 16) {
|
||||
len = ptmp - tmp;
|
||||
tmp[len] = 0x0;
|
||||
secdp_logger_print("%s%s\n", (char *)pref, tmp);
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t secdp_logger_read(struct file *file, char __user *buf,
|
||||
size_t len, loff_t *offset)
|
||||
{
|
||||
loff_t pos = *offset;
|
||||
ssize_t count;
|
||||
size_t size;
|
||||
volatile unsigned int curpos = g_curpos;
|
||||
|
||||
if (is_buf_full || BUF_SIZE <= curpos)
|
||||
size = BUF_SIZE;
|
||||
else
|
||||
size = (size_t)curpos;
|
||||
|
||||
if (pos >= size)
|
||||
return 0;
|
||||
|
||||
count = min(len, size);
|
||||
|
||||
if ((pos + count) > size)
|
||||
count = size - pos;
|
||||
|
||||
if (copy_to_user(buf, log_buf + pos, count))
|
||||
return -EFAULT;
|
||||
|
||||
*offset += count;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
#if KERNEL_VERSION(5, 6, 0) <= LINUX_VERSION_CODE
|
||||
static const struct proc_ops secdp_logger_ops = {
|
||||
.proc_read = secdp_logger_read,
|
||||
.proc_lseek = default_llseek,
|
||||
};
|
||||
#else
|
||||
static const struct file_operations secdp_logger_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.read = secdp_logger_read,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
#endif
|
||||
|
||||
int secdp_logger_init(void)
|
||||
{
|
||||
struct proc_dir_entry *entry;
|
||||
|
||||
if (is_secdp_logger_init)
|
||||
return 0;
|
||||
|
||||
entry = proc_create(PROC_FILE_NAME, 0444, NULL, &secdp_logger_ops);
|
||||
if (!entry) {
|
||||
pr_err("%s: failed to create proc entry\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
proc_set_size(entry, BUF_SIZE);
|
||||
is_secdp_logger_init = 1;
|
||||
g_entry = entry;
|
||||
|
||||
mutex_init(&dplog_lock);
|
||||
secdp_logger_print("dp logger init ok\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void secdp_logger_deinit(void)
|
||||
{
|
||||
if (!g_entry)
|
||||
return;
|
||||
|
||||
proc_remove(g_entry);
|
||||
is_secdp_logger_init = 0;
|
||||
g_entry = NULL;
|
||||
|
||||
mutex_destroy(&dplog_lock);
|
||||
secdp_logger_print("dp logger deinit ok\n");
|
||||
}
|
1671
qcom/opensource/display-drivers/msm/dp/secdp_sysfs.c
Normal file
1671
qcom/opensource/display-drivers/msm/dp/secdp_sysfs.c
Normal file
File diff suppressed because it is too large
Load Diff
51
qcom/opensource/display-drivers/msm/dp/secdp_sysfs.h
Normal file
51
qcom/opensource/display-drivers/msm/dp/secdp_sysfs.h
Normal file
@ -0,0 +1,51 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2017-2021, 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 __SECDP_SYSFS_H
|
||||
#define __SECDP_SYSFS_H
|
||||
|
||||
#include "secdp.h"
|
||||
|
||||
struct secdp_sysfs_in {
|
||||
struct device *dev;
|
||||
struct dp_parser *parser;
|
||||
struct dp_ctrl *ctrl;
|
||||
struct dp_link *link;
|
||||
struct dp_panel *panel;
|
||||
struct dp_power *power;
|
||||
struct dp_catalog *catalog;
|
||||
struct secdp_misc *sec;
|
||||
};
|
||||
|
||||
struct secdp_sysfs {
|
||||
struct class dp_class;
|
||||
};
|
||||
|
||||
/**
|
||||
* secdp_sysfs_get() - get the functionalities of secdp sysfs module
|
||||
*
|
||||
*
|
||||
* return: a pointer to dp_link struct
|
||||
*/
|
||||
struct secdp_sysfs *secdp_sysfs_get(struct secdp_sysfs_in *in);
|
||||
|
||||
/**
|
||||
* secdp_sysfs_put() - releases the dp test module's resources
|
||||
*
|
||||
* @dp_link: an instance of dp_link module
|
||||
*
|
||||
*/
|
||||
void secdp_sysfs_put(struct device *dev, struct secdp_sysfs *dp_sysfs);
|
||||
|
||||
#endif /*__SECDP_SYSFS_H*/
|
162
qcom/opensource/display-drivers/msm/dp/secdp_unit_test.c
Normal file
162
qcom/opensource/display-drivers/msm/dp/secdp_unit_test.c
Normal file
@ -0,0 +1,162 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2017-2021, 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.
|
||||
*
|
||||
*/
|
||||
#include "dp_debug.h"
|
||||
#include "dp_display.h"
|
||||
#include "sde_edid_parser.h"
|
||||
#include "secdp.h"
|
||||
|
||||
static u8 g_test_edid[] = {
|
||||
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x09, 0xD1, 0x54, 0x7F, 0x45, 0x54, 0x00, 0x00,
|
||||
0x14, 0x1B, 0x01, 0x03, 0x80, 0x46, 0x28, 0x78, 0x2E, 0xDF, 0x50, 0xA3, 0x54, 0x35, 0xB5, 0x26,
|
||||
0x0F, 0x50, 0x54, 0xA5, 0x6B, 0x80, 0xD1, 0xC0, 0x81, 0xC0, 0x81, 0x00, 0x81, 0x80, 0xA9, 0xC0,
|
||||
0xB3, 0x00, 0x01, 0x01, 0x01, 0x01, 0x51, 0xD0, 0x00, 0xA0, 0xF0, 0x70, 0x3E, 0x80, 0x30, 0x20,
|
||||
0x35, 0x00, 0xBA, 0x89, 0x21, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x53, 0x35, 0x48,
|
||||
0x30, 0x31, 0x38, 0x39, 0x31, 0x53, 0x4C, 0x30, 0x0A, 0x20, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x18,
|
||||
0x4C, 0x1E, 0x8C, 0x3C, 0x00, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xFC,
|
||||
0x00, 0x42, 0x65, 0x6E, 0x51, 0x20, 0x53, 0x57, 0x33, 0x32, 0x30, 0x0A, 0x20, 0x20, 0x01, 0x42,
|
||||
0x02, 0x03, 0x45, 0xF1, 0x56, 0x61, 0x60, 0x5D, 0x5E, 0x5F, 0x10, 0x05, 0x04, 0x03, 0x02, 0x07,
|
||||
0x06, 0x0F, 0x1F, 0x20, 0x21, 0x22, 0x14, 0x13, 0x12, 0x16, 0x01, 0x23, 0x09, 0x07, 0x07, 0xE6,
|
||||
0x06, 0x05, 0x01, 0x60, 0x5A, 0x44, 0x6D, 0x03, 0x0C, 0x00, 0x10, 0x00, 0x38, 0x44, 0x20, 0x00,
|
||||
0x60, 0x01, 0x02, 0x03, 0x67, 0xD8, 0x5D, 0xC4, 0x01, 0x78, 0x80, 0x01, 0xE4, 0x0F, 0x03, 0x00,
|
||||
0x00, 0xE3, 0x05, 0xC3, 0x00, 0x02, 0x3A, 0x80, 0x18, 0x71, 0x38, 0x2D, 0x40, 0x58, 0x2C, 0x45,
|
||||
0x00, 0xBA, 0x89, 0x21, 0x00, 0x00, 0x1E, 0x56, 0x5E, 0x00, 0xA0, 0xA0, 0xA0, 0x29, 0x50, 0x30,
|
||||
0x20, 0x35, 0x00, 0xBA, 0x89, 0x21, 0x00, 0x00, 0x1A, 0xF4, 0x51, 0x00, 0xA0, 0xF0, 0x70, 0x19,
|
||||
0x80, 0x30, 0x20, 0x35, 0x00, 0xBA, 0x89, 0x21, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0xAB,
|
||||
};
|
||||
|
||||
static struct secdp_display_timing g_parsed_res[] = {
|
||||
/* active_h, active_v, refresh_rate, interlaced */
|
||||
{0, 640, 480, 60, false}, /* 640x480 60hz */
|
||||
{0, 640, 480, 75, false}, /* 640x480 75hz */
|
||||
{0, 720, 400, 70, false}, /* 720x400 70hz */
|
||||
{0, 720, 480, 60, true}, /* 720x480i 60hz */
|
||||
{0, 720, 480, 60, false}, /* 720x480 60hz */
|
||||
|
||||
{0, 720, 576, 50, true}, /* 720x576i 50hz */
|
||||
{0, 720, 576, 50, false}, /* 720x576 50hz */
|
||||
{0, 800, 600, 60, false}, /* 800x600 60hz */
|
||||
{0, 800, 600, 75, false}, /* 800x600 75hz */
|
||||
{0, 832, 624, 75, false}, /* 832x624 75hz */
|
||||
|
||||
{0, 1024, 768, 60, false}, /* 1024x768 60hz */
|
||||
{0, 1024, 768, 75, false}, /* 1024x768 75hz */
|
||||
{0, 1152, 864, 75, false}, /* 1152x864 75hz */
|
||||
{0, 1280, 720, 50, false}, /* 1280x720 50hz */
|
||||
{0, 1280, 720, 60, false}, /* 1280x720 60hz */
|
||||
|
||||
{0, 1280, 800, 60, false}, /* 1280x800 60hz */
|
||||
{0, 1280, 1024, 60, false}, /* 1280x1024 60hz */
|
||||
{0, 1280, 1024, 75, false}, /* 1280x1024 75hz */
|
||||
{0, 1440, 480, 60, false}, /* 1440x480 60hz */
|
||||
{0, 1600, 900, 60, false}, /* 1600x900 60hz */
|
||||
|
||||
{0, 1680, 1050, 60, false}, /* 1680x1050 60hz */
|
||||
{0, 1920, 1080, 50, true}, /* 1920x1080i 50hz */
|
||||
{0, 1920, 1080, 60, true}, /* 1920x1080i 60hz */
|
||||
{0, 1920, 1080, 24, false}, /* 1920x1080 24hz */
|
||||
{0, 1920, 1080, 25, false}, /* 1920x1080 25hz */
|
||||
|
||||
{0, 1920, 1080, 30, false}, /* 1920x1080 30hz */
|
||||
{0, 1920, 1080, 50, false}, /* 1920x1080 50hz */
|
||||
{0, 1920, 1080, 60, false}, /* 1920x1080 60hz */
|
||||
{0, 2560, 1440, 60, false}, /* 2560x1440 60hz */
|
||||
{0, 3840, 2160, 24, false}, /* 3840x2160 24hz */
|
||||
|
||||
{0, 3840, 2160, 25, false}, /* 3840x2160 25hz */
|
||||
{0, 3840, 2160, 30, false}, /* 3840x2160 30hz */
|
||||
{0, 3840, 2160, 50, false}, /* 3840x2160 50hz */
|
||||
{0, 3840, 2160, 60, false}, /* 3840x2160 60hz */
|
||||
};
|
||||
|
||||
static void drm_mode_remove(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
list_del(&mode->head);
|
||||
drm_mode_destroy(connector->dev, mode);
|
||||
}
|
||||
|
||||
bool secdp_unit_test_edid_parse(void)
|
||||
{
|
||||
int rc, i, parsed_res_cnt = 0, table_size;
|
||||
bool ret = false;
|
||||
struct sde_edid_ctrl *edid_ctrl = NULL;
|
||||
struct drm_display_mode *mode, *t;
|
||||
struct drm_connector *connector;
|
||||
|
||||
connector = secdp_get_connector();
|
||||
if (!connector) {
|
||||
DP_ERR("fail to get connector\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
table_size = ARRAY_SIZE(g_parsed_res);
|
||||
|
||||
edid_ctrl = sde_edid_init();
|
||||
if (!edid_ctrl) {
|
||||
DP_ERR("edid_ctrl alloc failed\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
mutex_lock(&connector->dev->mode_config.mutex);
|
||||
|
||||
edid_ctrl->edid = (struct edid *)g_test_edid;
|
||||
rc = _sde_edid_update_modes(connector, edid_ctrl);
|
||||
DP_INFO("_sde_edid_update_modes, rc: %d\n", rc);
|
||||
|
||||
/* init g_parsed_res */
|
||||
for (i = 0; i < table_size; i++)
|
||||
g_parsed_res[i].supported = false;
|
||||
|
||||
/* check resolutions */
|
||||
list_for_each_entry(mode, &connector->probed_modes, head) {
|
||||
DP_INFO("checking %s @ %d Hz..\n", mode->name, drm_mode_vrefresh(mode));
|
||||
for (i = 0; i < table_size; i++) {
|
||||
bool interlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
|
||||
|
||||
if (g_parsed_res[i].active_h == mode->hdisplay &&
|
||||
g_parsed_res[i].active_v == mode->vdisplay &&
|
||||
g_parsed_res[i].refresh_rate == drm_mode_vrefresh(mode) &&
|
||||
g_parsed_res[i].interlaced == interlaced) {
|
||||
|
||||
/*all conditions are met, mark it as supported*/
|
||||
g_parsed_res[i].supported = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
list_for_each_entry_safe(mode, t, &connector->probed_modes, head)
|
||||
drm_mode_remove(connector, mode);
|
||||
|
||||
mutex_unlock(&connector->dev->mode_config.mutex);
|
||||
kfree(edid_ctrl);
|
||||
|
||||
/* count how many resolutions are marked as supported */
|
||||
for (i = 0; i < table_size; i++) {
|
||||
if (g_parsed_res[i].supported)
|
||||
parsed_res_cnt++;
|
||||
}
|
||||
|
||||
/* check if num of supported resolutions are found without errors */
|
||||
if (parsed_res_cnt != table_size) {
|
||||
DP_ERR("count is not matched! res_cnt: %d, table_size: %d\n",
|
||||
parsed_res_cnt, table_size);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = true;
|
||||
exit:
|
||||
DP_INFO("returns %s\n", ret ? "true" : "false");
|
||||
return ret;
|
||||
}
|
20
qcom/opensource/display-drivers/msm/dp/secdp_unit_test.h
Normal file
20
qcom/opensource/display-drivers/msm/dp/secdp_unit_test.h
Normal file
@ -0,0 +1,20 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2017-2021, 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 __SECDP_UNIT_TEST_H
|
||||
#define __SECDP_UNIT_TEST_H
|
||||
|
||||
bool secdp_unit_test_edid_parse(void);
|
||||
|
||||
#endif/*__SECDP_UNIT_TEST_H*/
|
@ -267,6 +267,14 @@ static void dsi_catalog_phy_5_0_init(struct dsi_phy_hw *phy)
|
||||
phy->ops.set_continuous_clk = dsi_phy_hw_v5_0_set_continuous_clk;
|
||||
phy->ops.commit_phy_timing = dsi_phy_hw_v5_0_commit_phy_timing;
|
||||
phy->ops.phy_idle_off = dsi_phy_hw_v5_0_phy_idle_off;
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
phy->ops.store_str = dsi_phy_hw_v5_0_store_str;
|
||||
phy->ops.show_str = dsi_phy_hw_v5_0_show_str;
|
||||
phy->ops.store_vreg = dsi_phy_hw_v5_0_store_vreg;
|
||||
phy->ops.show_vreg = dsi_phy_hw_v5_0_show_vreg;
|
||||
phy->ops.store_emphasis = dsi_phy_hw_v5_0_store_emphasis;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -127,6 +127,14 @@ void dsi_phy_hw_v4_0_set_continuous_clk(struct dsi_phy_hw *phy, bool enable);
|
||||
void dsi_phy_hw_v4_0_commit_phy_timing(struct dsi_phy_hw *phy,
|
||||
struct dsi_phy_per_lane_cfgs *timing);
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
void dsi_phy_hw_v5_0_store_str(struct dsi_phy_hw *phy, u32 *val);
|
||||
u32 dsi_phy_hw_v5_0_show_str(struct dsi_phy_hw *phy);
|
||||
void dsi_phy_hw_v5_0_store_vreg(struct dsi_phy_hw *phy, u32 *val);
|
||||
u32 dsi_phy_hw_v5_0_show_vreg(struct dsi_phy_hw *phy);
|
||||
void dsi_phy_hw_v5_0_store_emphasis(struct dsi_phy_hw *phy, u32 *val);
|
||||
#endif
|
||||
|
||||
/* Definitions for 4nm PHY hardware driver */
|
||||
void dsi_phy_hw_v5_0_enable(struct dsi_phy_hw *phy, struct dsi_phy_cfg *cfg);
|
||||
void dsi_phy_hw_v5_0_disable(struct dsi_phy_hw *phy, struct dsi_phy_cfg *cfg);
|
||||
|
@ -11,6 +11,12 @@
|
||||
#include "dsi_clk.h"
|
||||
#include "dsi_defs.h"
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
#include "sde_dbg.h"
|
||||
#include "ss_dsi_panel_common.h"
|
||||
#include "ss_panel_power.h"
|
||||
#endif
|
||||
|
||||
struct dsi_core_clks {
|
||||
struct dsi_core_clk_info clks;
|
||||
};
|
||||
@ -211,12 +217,18 @@ int dsi_clk_update_parent(struct dsi_clk_link_set *parent,
|
||||
rc = clk_set_parent(child->byte_clk, parent->byte_clk);
|
||||
if (rc) {
|
||||
DSI_ERR("failed to set byte clk parent\n");
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
SDE_DBG_DUMP(SDE_DBG_BUILT_IN_ALL, "panic");
|
||||
#endif
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = clk_set_parent(child->pixel_clk, parent->pixel_clk);
|
||||
if (rc) {
|
||||
DSI_ERR("failed to set pixel clk parent\n");
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
SDE_DBG_DUMP(SDE_DBG_BUILT_IN_ALL, "panic");
|
||||
#endif
|
||||
goto error;
|
||||
}
|
||||
error:
|
||||
@ -672,6 +684,11 @@ static int dsi_display_link_clk_enable(struct dsi_link_clks *clks,
|
||||
}
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
if ((l_type & DSI_LINK_LP_CLK) && (ctrl_count == 1))
|
||||
ss_panel_power_on_middle_lp_hs_clk();
|
||||
#endif
|
||||
|
||||
if (l_type & DSI_LINK_HS_CLK) {
|
||||
if (!mngr->is_cont_splash_enabled) {
|
||||
mngr->phy_config_cb(mngr->priv_data, true);
|
||||
@ -698,6 +715,9 @@ static int dsi_display_link_clk_enable(struct dsi_link_clks *clks,
|
||||
rc);
|
||||
goto error_disable_master;
|
||||
}
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
ss_panel_power_on_middle_lp_hs_clk();
|
||||
#endif
|
||||
}
|
||||
|
||||
if (l_type & DSI_LINK_HS_CLK) {
|
||||
@ -786,6 +806,9 @@ static int dsi_display_link_clk_disable(struct dsi_link_clks *clks,
|
||||
continue;
|
||||
|
||||
if (l_type & DSI_LINK_LP_CLK) {
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
ss_panel_power_off_middle_lp_hs_clk();
|
||||
#endif
|
||||
rc = dsi_link_lp_clk_stop(&clk->lp_clks);
|
||||
if (rc)
|
||||
DSI_ERR("failed to turn off lp link clocks, rc=%d\n",
|
||||
@ -1255,6 +1278,12 @@ int dsi_clk_req_state(void *client, enum dsi_clk_type clk,
|
||||
}
|
||||
|
||||
mutex_unlock(&mngr->clk_mutex);
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
if (clk & DSI_LINK_CLK)
|
||||
ss_dct_update_ref(mngr->master_ndx, DCT_TAG_LINK_CLK, state);
|
||||
#endif
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,11 @@
|
||||
|
||||
#include "sde_dbg.h"
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
#include "ss_dsi_panel_common.h"
|
||||
#include "sde_trace.h"
|
||||
#endif
|
||||
|
||||
#define DSI_CTRL_DEFAULT_LABEL "MDSS DSI CTRL"
|
||||
|
||||
#define DSI_CTRL_TX_TO_MS 1200
|
||||
@ -392,6 +397,22 @@ static void dsi_ctrl_dma_cmd_wait_for_done(struct dsi_ctrl *dsi_ctrl)
|
||||
DSI_CTRL_WARN(dsi_ctrl,
|
||||
"dma_tx done but irq not triggered\n");
|
||||
} else {
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
struct samsung_display_driver_data *vdd = ss_get_vdd(dsi_ctrl->hw.display_index);
|
||||
|
||||
LCD_ERR(vdd, "dsi_ctrl_dma_cmd_wait_for_done Timeout!!\n");
|
||||
|
||||
/* check physical display connection */
|
||||
if (gpio_is_valid(vdd->ub_con_det.gpio)) {
|
||||
pr_err("[SDE] ub_con_det.gpio(%d) level=%d\n",
|
||||
vdd->ub_con_det.gpio,
|
||||
gpio_get_value(vdd->ub_con_det.gpio));
|
||||
}
|
||||
|
||||
// case 03745287
|
||||
//if (!dsi_ctrl->esd_check_underway && !vdd->panel_dead)
|
||||
// SDE_DBG_DUMP(SDE_DBG_BUILT_IN_ALL, "panic");
|
||||
#endif
|
||||
SDE_EVT32(dsi_ctrl->cell_index, SDE_EVTLOG_ERROR);
|
||||
DSI_CTRL_ERR(dsi_ctrl,
|
||||
"Command transfer failed\n");
|
||||
@ -847,6 +868,10 @@ static int dsi_ctrl_clocks_init(struct platform_device *pdev,
|
||||
|
||||
xo->pixel_clk = xo->byte_clk;
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
ss_dct_update_clk(ctrl->hw.display_index, DCT_TAG_LINK_CLK, hs_link->byte_clk);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
dsi_ctrl_clocks_deinit(ctrl);
|
||||
@ -1272,14 +1297,22 @@ int dsi_message_validate_tx_mode(struct dsi_ctrl *dsi_ctrl,
|
||||
DSI_CTRL_ERR(dsi_ctrl, " Cannot transfer command,ops not defined\n");
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
if ((cmd_len + 4) > SZ_1M) {
|
||||
#else
|
||||
if ((cmd_len + 4) > SZ_4K) {
|
||||
#endif
|
||||
DSI_CTRL_ERR(dsi_ctrl, "Cannot transfer,size is greater than 4096\n");
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
if (*flags & DSI_CTRL_CMD_FETCH_MEMORY) {
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
if ((dsi_ctrl->cmd_len + cmd_len + 4) > SZ_1M) {
|
||||
#else
|
||||
if ((dsi_ctrl->cmd_len + cmd_len + 4) > SZ_4K) {
|
||||
#endif
|
||||
DSI_CTRL_ERR(dsi_ctrl, "Cannot transfer,size is greater than 4096\n");
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
@ -1369,6 +1402,9 @@ static void dsi_kickoff_msg_tx(struct dsi_ctrl *dsi_ctrl,
|
||||
u32 hw_flags = 0;
|
||||
struct dsi_ctrl_hw_ops dsi_hw_ops = dsi_ctrl->hw.ops;
|
||||
struct dsi_split_link_config *split_link;
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
u8 *tx_buf = (u8 *)msg->tx_buf;
|
||||
#endif
|
||||
|
||||
split_link = &(dsi_ctrl->host_config.common_config.split_link);
|
||||
|
||||
@ -1416,10 +1452,19 @@ static void dsi_kickoff_msg_tx(struct dsi_ctrl *dsi_ctrl,
|
||||
cmd_mem,
|
||||
hw_flags);
|
||||
} else {
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
if (tx_buf[0] == 0x2a || tx_buf[0] == 0x2b)
|
||||
SDE_ATRACE_BEGIN("dsi_message_tx_flush");
|
||||
#endif
|
||||
|
||||
dsi_hw_ops.kickoff_command(
|
||||
&dsi_ctrl->hw,
|
||||
cmd_mem,
|
||||
hw_flags);
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
if (tx_buf[0] == 0x2a || tx_buf[0] == 0x2b)
|
||||
SDE_ATRACE_END("dsi_message_tx_flush");
|
||||
#endif
|
||||
}
|
||||
} else if (flags & DSI_CTRL_CMD_FIFO_STORE) {
|
||||
dsi_hw_ops.kickoff_fifo_command(&dsi_ctrl->hw,
|
||||
@ -1462,6 +1507,12 @@ static void dsi_kickoff_msg_tx(struct dsi_ctrl *dsi_ctrl,
|
||||
dsi_ctrl->cmd_trigger_frame);
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
// TODO : this should be called in dsi_ctrl_dma_cmd_wait_for_done()..
|
||||
// but there is no msg struct... fix this later... (CSP3)
|
||||
if (tx_buf[0] == 0x2a || tx_buf[0] == 0x2b)
|
||||
SDE_ATRACE_END("dsi_message_tx_wait");
|
||||
#endif
|
||||
|
||||
dsi_hw_ops.reset_cmd_fifo(&dsi_ctrl->hw);
|
||||
|
||||
@ -1490,6 +1541,12 @@ static int dsi_message_tx(struct dsi_ctrl *dsi_ctrl, struct dsi_cmd_desc *cmd_de
|
||||
u32 cnt = 0;
|
||||
u8 *cmdbuf;
|
||||
u32 *flags;
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
struct samsung_display_driver_data *vdd = ss_get_vdd(dsi_ctrl->hw.display_index);
|
||||
|
||||
ss_print_cmd_desc(cmd_desc, vdd);
|
||||
ss_print_cmd_desc_evtlog(cmd_desc, vdd);
|
||||
#endif
|
||||
|
||||
msg = &cmd_desc->msg;
|
||||
flags = &cmd_desc->ctrl_flags;
|
||||
@ -2072,6 +2129,10 @@ static int dsi_ctrl_dev_probe(struct platform_device *pdev)
|
||||
enum dsi_ctrl_version version;
|
||||
int rc = 0;
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
LCD_INFO_CRITICAL(0, "+++\n");
|
||||
#endif
|
||||
|
||||
id = of_match_node(msm_dsi_of_match, pdev->dev.of_node);
|
||||
if (!id)
|
||||
return -ENODEV;
|
||||
@ -2145,6 +2206,10 @@ static int dsi_ctrl_dev_probe(struct platform_device *pdev)
|
||||
platform_set_drvdata(pdev, dsi_ctrl);
|
||||
DSI_CTRL_INFO(dsi_ctrl, "Probe successful\n");
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
LCD_INFO_CRITICAL(0, "---\n");
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
fail_clks:
|
||||
@ -2715,6 +2780,9 @@ static void dsi_ctrl_handle_error_status(struct dsi_ctrl *dsi_ctrl,
|
||||
struct dsi_event_cb_info cb_info;
|
||||
struct dsi_display *display;
|
||||
bool skip_irq_enable = false;
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG) && IS_ENABLED(CONFIG_SEC_DEBUG)
|
||||
struct samsung_display_driver_data *vdd = ss_get_vdd(dsi_ctrl->hw.display_index);
|
||||
#endif
|
||||
bool is_spurious_interrupt = false;
|
||||
|
||||
cb_info = dsi_ctrl->irq_info.irq_err_cb;
|
||||
@ -2760,6 +2828,12 @@ static void dsi_ctrl_handle_error_status(struct dsi_ctrl *dsi_ctrl,
|
||||
if (error & 0xF0000) {
|
||||
u32 mask = 0;
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG) && IS_ENABLED(CONFIG_SEC_DEBUG)
|
||||
if (sec_debug_is_enabled() && ss_panel_attach_get(vdd)) {
|
||||
pr_err("dsi FIFO OVERFLOW error: 0x%lx\n", error);
|
||||
SDE_DBG_DUMP_WQ(SDE_DBG_BUILT_IN_ALL, "panic");
|
||||
}
|
||||
#endif
|
||||
if (dsi_ctrl->hw.ops.get_error_mask)
|
||||
mask = dsi_ctrl->hw.ops.get_error_mask(&dsi_ctrl->hw);
|
||||
/* no need to report FIFO overflow if already masked */
|
||||
@ -2777,6 +2851,12 @@ static void dsi_ctrl_handle_error_status(struct dsi_ctrl *dsi_ctrl,
|
||||
|
||||
/* DSI FIFO UNDERFLOW error */
|
||||
if (error & 0xF00000) {
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG) && IS_ENABLED(CONFIG_SEC_DEBUG)
|
||||
if (sec_debug_is_enabled() && ss_panel_attach_get(vdd) && !vdd->panel_dead) { // check panel dead
|
||||
pr_err("dsi FIFO UNDERFLOW error: 0x%lx\n", error);
|
||||
SDE_DBG_DUMP_WQ(SDE_DBG_BUILT_IN_ALL, "panic");
|
||||
}
|
||||
#endif
|
||||
if (cb_info.event_cb) {
|
||||
cb_info.event_idx = DSI_FIFO_UNDERFLOW;
|
||||
display = cb_info.event_usr_ptr;
|
||||
@ -2812,6 +2892,11 @@ static void dsi_ctrl_handle_error_status(struct dsi_ctrl *dsi_ctrl,
|
||||
/* enable back DSI interrupts */
|
||||
if (dsi_ctrl->hw.ops.error_intr_ctrl && !skip_irq_enable)
|
||||
dsi_ctrl->hw.ops.error_intr_ctrl(&dsi_ctrl->hw, true);
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
inc_dpui_u32_field_nolock(DPUI_KEY_QCT_DSIE, 1);
|
||||
ss_get_vdd(dsi_ctrl->hw.display_index)->dsi_errors = error;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2865,6 +2950,9 @@ static irqreturn_t dsi_ctrl_isr(int irq, void *ptr)
|
||||
atomic_set(&dsi_ctrl->dma_irq_trig, 1);
|
||||
dsi_ctrl_disable_status_interrupt(dsi_ctrl,
|
||||
DSI_SINT_CMD_MODE_DMA_DONE);
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
LCD_INFO_IF(ss_get_vdd(dsi_ctrl->hw.display_index), "DMA_DONE\n");
|
||||
#endif
|
||||
complete_all(&dsi_ctrl->irq_info.cmd_dma_done);
|
||||
}
|
||||
|
||||
@ -3734,6 +3822,44 @@ int dsi_ctrl_get_host_engine_init_state(struct dsi_ctrl *dsi_ctrl,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
/**
|
||||
* dsi_ctrl_update_host_engine_state_for_cont_splash() -
|
||||
* set engine state for dsi controller during continuous splash
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
* @state: Engine state.
|
||||
*
|
||||
* Set host engine state for DSI controller during continuous splash.
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int dsi_ctrl_update_host_engine_state_for_cont_splash(struct dsi_ctrl *dsi_ctrl,
|
||||
enum dsi_engine_state state)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (!dsi_ctrl || (state >= DSI_CTRL_ENGINE_MAX)) {
|
||||
DSI_CTRL_ERR(dsi_ctrl, "Invalid params\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&dsi_ctrl->ctrl_lock);
|
||||
|
||||
rc = dsi_ctrl_check_state(dsi_ctrl, DSI_CTRL_OP_HOST_ENGINE, state);
|
||||
if (rc) {
|
||||
DSI_CTRL_ERR(dsi_ctrl, "Controller state check failed, rc=%d\n",
|
||||
rc);
|
||||
goto error;
|
||||
}
|
||||
|
||||
DSI_CTRL_DEBUG(dsi_ctrl, "Set host engine state = %d\n", state);
|
||||
dsi_ctrl_update_state(dsi_ctrl, DSI_CTRL_OP_HOST_ENGINE, state);
|
||||
error:
|
||||
mutex_unlock(&dsi_ctrl->ctrl_lock);
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* dsi_ctrl_set_power_state() - set power state for dsi controller
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
@ -4272,6 +4398,9 @@ int dsi_ctrl_wait4dynamic_refresh_done(struct dsi_ctrl *ctrl)
|
||||
*/
|
||||
void dsi_ctrl_drv_register(void)
|
||||
{
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
LCD_INFO_CRITICAL(0, "+++\n");
|
||||
#endif
|
||||
platform_driver_register(&dsi_ctrl_driver);
|
||||
}
|
||||
|
||||
|
@ -61,6 +61,11 @@
|
||||
/*Default tearcheck window size as programmed by MDP*/
|
||||
#define TEARCHECK_WINDOW_SIZE 5
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
/* max size supported for dsi cmd transfer using DMA */
|
||||
#define DSI_CTRL_MAX_CMD_FET_MEMORY_SIZE 200
|
||||
#endif
|
||||
|
||||
/**
|
||||
* enum dsi_power_state - defines power states for dsi controller.
|
||||
* @DSI_CTRL_POWER_VREG_OFF: Digital and analog supplies for DSI controller
|
||||
@ -651,6 +656,19 @@ void dsi_ctrl_transfer_unprepare(struct dsi_ctrl *dsi_ctrl, u32 flags);
|
||||
*/
|
||||
int dsi_ctrl_cmd_tx_trigger(struct dsi_ctrl *dsi_ctrl, u32 flags);
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
/**
|
||||
* dsi_ctrl_update_host_engine_state_for_cont_splash() - update engine
|
||||
* states for cont splash usecase
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
* @state: DSI engine state
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int dsi_ctrl_update_host_engine_state_for_cont_splash(struct dsi_ctrl *dsi_ctrl,
|
||||
enum dsi_engine_state state);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* dsi_ctrl_set_power_state() - set power state for dsi controller
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
|
@ -985,6 +985,9 @@ struct dsi_ctrl_hw {
|
||||
bool null_insertion_enabled;
|
||||
bool widebus_support;
|
||||
bool reset_trig_ctrl;
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
int display_index; /* primary display or secondary display */
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif /* _DSI_CTRL_HW_H_ */
|
||||
|
@ -377,6 +377,10 @@ struct dsi_cmd_desc {
|
||||
u32 ctrl;
|
||||
u32 ctrl_flags;
|
||||
ktime_t ts;
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
u8 *ss_txbuf;
|
||||
void *ss_cmd; /* struct ss_cmd_desc *ss_cmd */
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
@ -393,6 +397,21 @@ struct dsi_panel_cmd_set {
|
||||
u32 count;
|
||||
u32 ctrl_idx;
|
||||
struct dsi_cmd_desc *cmds;
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
#define SUPPORT_PANEL_REVISION 20
|
||||
int ss_cmd_type;
|
||||
char *name;
|
||||
int exclusive_pass;
|
||||
|
||||
/* cmd_set_rev[panel_rev] is pointer to
|
||||
* describe "struct dsi_panel_cmd_set *set" for each panel revision.
|
||||
* If you want get cmd_set for panel revision A, get like below.
|
||||
* struct dsi_panel_cmd_set *set = set->cmd_set_rev[panel_rev];
|
||||
*/
|
||||
void *cmd_set_rev[SUPPORT_PANEL_REVISION];
|
||||
|
||||
void *self_disp_cmd_set_rev;
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
@ -450,6 +469,24 @@ struct dsi_mode_info {
|
||||
struct msm_roi_caps roi_caps;
|
||||
u32 qsync_min_fps;
|
||||
u32 avr_step_fps;
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
/* Identify VRR HS by drm_mode's name.
|
||||
* drm_mode's name is defined by dsi_mode->timing.sot_hs_mode parsed
|
||||
* from samsung,mdss-dsi-sot-hs-mode in panel dtsi file.
|
||||
* ex) drm_mode->name is "1080x2316x60x193345cmdHS" for HS mode.
|
||||
* drm_mode->name is "1080x2316x60x193345cmdNS" for NS mode.
|
||||
* To use this feature, declare different porch between HS and NS modes,
|
||||
* in panel dtsi file.
|
||||
* Refer to ss_is_sot_hs_from_drm_mode().
|
||||
*/
|
||||
bool sot_hs_mode;
|
||||
|
||||
/* DDI Passive mode.
|
||||
* ex) DDI 120hz + TE(AP) is 60hz.
|
||||
*/
|
||||
bool phs_mode;
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -23,6 +23,10 @@
|
||||
#include "dsi_pwr.h"
|
||||
#include "sde_dbg.h"
|
||||
#include "dsi_parser.h"
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
#include "ss_dsi_panel_common.h"
|
||||
#include "ss_panel_power.h"
|
||||
#endif
|
||||
|
||||
#define to_dsi_display(x) container_of(x, struct dsi_display, host)
|
||||
#define INT_BASE_10 10
|
||||
@ -40,12 +44,21 @@
|
||||
#define SEC_PANEL_NAME_MAX_LEN 256
|
||||
|
||||
u8 dbgfs_tx_cmd_buf[SZ_4K];
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
char dsi_display_primary[MAX_CMDLINE_PARAM_LEN];
|
||||
char dsi_display_secondary[MAX_CMDLINE_PARAM_LEN];
|
||||
struct dsi_display_boot_param boot_displays[MAX_DSI_ACTIVE_DISPLAY] = {
|
||||
{.boot_param = dsi_display_primary},
|
||||
{.boot_param = dsi_display_secondary},
|
||||
};
|
||||
#else
|
||||
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] = {
|
||||
{.boot_param = dsi_display_primary},
|
||||
{.boot_param = dsi_display_secondary},
|
||||
};
|
||||
#endif
|
||||
|
||||
static void dsi_display_panel_id_notification(struct dsi_display *display);
|
||||
|
||||
@ -361,6 +374,9 @@ static void dsi_display_aspace_cb_locked(void *cb_data, bool is_detach)
|
||||
struct dsi_display *display;
|
||||
struct dsi_display_ctrl *display_ctrl;
|
||||
int rc, cnt;
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
struct samsung_display_driver_data *vdd;
|
||||
#endif
|
||||
|
||||
if (!cb_data) {
|
||||
DSI_ERR("aspace cb called with invalid cb_data\n");
|
||||
@ -373,6 +389,10 @@ static void dsi_display_aspace_cb_locked(void *cb_data, bool is_detach)
|
||||
* while detaching the non-secure context banks
|
||||
*/
|
||||
dsi_panel_acquire_panel_lock(display->panel);
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
vdd = display->panel->panel_private;
|
||||
mutex_lock(&vdd->cmd_lock);
|
||||
#endif
|
||||
|
||||
if (is_detach) {
|
||||
/* invalidate the stored iova */
|
||||
@ -408,6 +428,9 @@ static void dsi_display_aspace_cb_locked(void *cb_data, bool is_detach)
|
||||
}
|
||||
|
||||
end:
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
mutex_unlock(&vdd->cmd_lock);
|
||||
#endif
|
||||
/* release panel_lock */
|
||||
dsi_panel_release_panel_lock(display->panel);
|
||||
}
|
||||
@ -510,7 +533,11 @@ static int dsi_host_alloc_cmd_tx_buffer(struct dsi_display *display)
|
||||
struct dsi_display_ctrl *display_ctrl;
|
||||
|
||||
display->tx_cmd_buf = msm_gem_new(display->drm_dev,
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
SZ_1M,
|
||||
#else
|
||||
SZ_4K,
|
||||
#endif
|
||||
MSM_BO_UNCACHED);
|
||||
|
||||
if ((display->tx_cmd_buf) == NULL) {
|
||||
@ -519,8 +546,11 @@ static int dsi_host_alloc_cmd_tx_buffer(struct dsi_display *display)
|
||||
goto error;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
display->cmd_buffer_size = SZ_1M;
|
||||
#else
|
||||
display->cmd_buffer_size = SZ_4K;
|
||||
|
||||
#endif
|
||||
display->aspace = msm_gem_smmu_address_space_get(
|
||||
display->drm_dev, MSM_SMMU_DOMAIN_UNSECURE);
|
||||
|
||||
@ -559,7 +589,11 @@ static int dsi_host_alloc_cmd_tx_buffer(struct dsi_display *display)
|
||||
|
||||
display_for_each_ctrl(cnt, display) {
|
||||
display_ctrl = &display->ctrl[cnt];
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
display_ctrl->ctrl->cmd_buffer_size = SZ_1M;
|
||||
#else
|
||||
display_ctrl->ctrl->cmd_buffer_size = SZ_4K;
|
||||
#endif
|
||||
display_ctrl->ctrl->cmd_buffer_iova =
|
||||
display->cmd_buffer_iova;
|
||||
display_ctrl->ctrl->vaddr = display->vaddr;
|
||||
@ -1007,6 +1041,11 @@ int dsi_display_check_status(struct drm_connector *connector, void *display,
|
||||
} else if (status_mode == ESD_MODE_PANEL_TE) {
|
||||
rc = dsi_display_status_check_te(dsi_display, te_rechecks);
|
||||
te_check_override = false;
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
} else if (status_mode == ESD_MODE_PANEL_IRQ) {
|
||||
/* In SS ESD_MODE_PANEL_IRQ mode, always report panel_dead. */
|
||||
rc = 0;
|
||||
#endif
|
||||
} else {
|
||||
DSI_WARN("Unsupported check status mode: %d\n", status_mode);
|
||||
panel->esd_config.esd_enabled = false;
|
||||
@ -1350,12 +1389,23 @@ int dsi_display_set_power(struct drm_connector *connector,
|
||||
{
|
||||
struct dsi_display *display = disp;
|
||||
int rc = 0;
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
struct samsung_display_driver_data *vdd;
|
||||
#endif
|
||||
|
||||
if (!display || !display->panel) {
|
||||
DSI_ERR("invalid display/panel\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
vdd = display->panel->panel_private;
|
||||
LCD_INFO(vdd, "%s ++\n", power_mode == SDE_MODE_DPMS_LP1 ? "LP1" :
|
||||
power_mode == SDE_MODE_DPMS_LP2 ? "LP2" :
|
||||
power_mode == SDE_MODE_DPMS_ON ? "ON" :
|
||||
power_mode == SDE_MODE_DPMS_OFF ? "OFF" : "UNKNOWN_POWER_MODE");
|
||||
#endif
|
||||
|
||||
switch (power_mode) {
|
||||
case SDE_MODE_DPMS_LP1:
|
||||
rc = dsi_panel_set_lp1(display->panel);
|
||||
@ -1380,6 +1430,13 @@ int dsi_display_set_power(struct drm_connector *connector,
|
||||
if (!rc)
|
||||
display->panel->power_mode = power_mode;
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
LCD_INFO(vdd, "%s %s --\n", power_mode == SDE_MODE_DPMS_LP1 ? "LP1" :
|
||||
power_mode == SDE_MODE_DPMS_LP2 ? "LP2" :
|
||||
power_mode == SDE_MODE_DPMS_ON ? "ON" :
|
||||
power_mode == SDE_MODE_DPMS_OFF ? "OFF" : "UNKNOWN_POWER_MODE",
|
||||
rc ? "failed" : "successful");
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -2526,6 +2583,32 @@ void dsi_display_enable_event(struct drm_connector *connector,
|
||||
}
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
/**
|
||||
* dsi_config_host_engine_state_for_cont_splash()- update host engine state
|
||||
* during continuous splash.
|
||||
* @display: Handle to dsi display
|
||||
*
|
||||
*/
|
||||
static void dsi_config_host_engine_state_for_cont_splash
|
||||
(struct dsi_display *display, bool enable)
|
||||
{
|
||||
int i;
|
||||
struct dsi_display_ctrl *ctrl;
|
||||
enum dsi_engine_state host_state = enable ? DSI_CTRL_ENGINE_ON : DSI_CTRL_ENGINE_OFF;
|
||||
|
||||
/* Sequence does not matter for split dsi usecases */
|
||||
display_for_each_ctrl(i, display) {
|
||||
ctrl = &display->ctrl[i];
|
||||
if (!ctrl->ctrl)
|
||||
continue;
|
||||
|
||||
dsi_ctrl_update_host_engine_state_for_cont_splash(ctrl->ctrl,
|
||||
host_state);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static int dsi_display_ctrl_power_on(struct dsi_display *display)
|
||||
{
|
||||
int rc = 0;
|
||||
@ -2606,6 +2689,11 @@ static void dsi_display_parse_cmdline_topology(struct dsi_display *display,
|
||||
if (sw_te)
|
||||
display->sw_te_using_wd = true;
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
/* In case of no ":config" option in command line, it should set NO_OVERRIDE. */
|
||||
display->cmdline_topology = NO_OVERRIDE;
|
||||
#endif
|
||||
|
||||
str = strnstr(boot_str, ":config", strlen(boot_str));
|
||||
if (str) {
|
||||
if (sscanf(str, ":config%lu", &cmdline_topology) != 1) {
|
||||
@ -2950,7 +3038,11 @@ error_host_deinit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
int dsi_display_ctrl_init(struct dsi_display *display)
|
||||
#else
|
||||
static int dsi_display_ctrl_init(struct dsi_display *display)
|
||||
#endif
|
||||
{
|
||||
int rc = 0;
|
||||
int i;
|
||||
@ -2996,7 +3088,11 @@ error_host_deinit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
int dsi_display_ctrl_deinit(struct dsi_display *display)
|
||||
#else
|
||||
static int dsi_display_ctrl_deinit(struct dsi_display *display)
|
||||
#endif
|
||||
{
|
||||
int rc = 0;
|
||||
int i;
|
||||
@ -3407,6 +3503,9 @@ int dsi_host_transfer_sub(struct mipi_dsi_host *host, struct dsi_cmd_desc *cmd)
|
||||
struct dsi_display *display;
|
||||
struct dsi_display_ctrl *ctrl;
|
||||
int i, rc = 0;
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
struct samsung_display_driver_data *vdd;
|
||||
#endif
|
||||
|
||||
if (!host || !cmd) {
|
||||
DSI_ERR("Invalid params\n");
|
||||
@ -3477,8 +3576,21 @@ int dsi_host_transfer_sub(struct mipi_dsi_host *host, struct dsi_cmd_desc *cmd)
|
||||
}
|
||||
|
||||
rc = dsi_ctrl_cmd_transfer(display->ctrl[idx].ctrl, cmd);
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
/* TX: rc means error code, so rc=0 means no error.
|
||||
* RX: rc means length of received data, so rc=0 means error.
|
||||
*/
|
||||
vdd = display->panel->panel_private;
|
||||
if (((cmd->ctrl_flags & DSI_CTRL_CMD_READ) && rc <= 0) ||
|
||||
(!(cmd->ctrl_flags & DSI_CTRL_CMD_READ) && rc)) {
|
||||
LCD_ERR(vdd, "[%s] cmd transfer failed, rc=%d, cmd_flags=%x cmd = %x\n",
|
||||
ss_get_cmd_name(vdd->cmd_type), rc, cmd->ctrl_flags, (u8 *)cmd->msg.tx_buf + 0);
|
||||
rc = -EINVAL;
|
||||
}
|
||||
#else
|
||||
if (rc)
|
||||
DSI_ERR("[%s] cmd transfer failed, rc=%d\n", display->name, rc);
|
||||
#endif
|
||||
|
||||
dsi_ctrl_transfer_unprepare(display->ctrl[idx].ctrl, cmd->ctrl_flags);
|
||||
}
|
||||
@ -3589,6 +3701,10 @@ static int dsi_display_clocks_init(struct dsi_display *display)
|
||||
dsi_clock_name = "qcom,dsi-select-sec-clocks";
|
||||
|
||||
num_clk = dsi_display_get_clocks_count(display, dsi_clock_name);
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
if (num_clk < 1)
|
||||
DSI_ERR("^^^^^^^^^^ No dsi clock, Check panel_common.MODEL.dtsi!\n");
|
||||
#endif
|
||||
|
||||
for (i = 0; i < num_clk; i++) {
|
||||
dsi_display_get_clock_name(display, dsi_clock_name, i,
|
||||
@ -4225,6 +4341,10 @@ error:
|
||||
|
||||
static bool dsi_display_validate_panel_resources(struct dsi_display *display)
|
||||
{
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
return true;
|
||||
#endif
|
||||
|
||||
if (!is_sim_panel(display)) {
|
||||
if (!display->panel->host_config.ext_bridge_mode &&
|
||||
!gpio_is_valid(display->panel->reset_config.reset_gpio)) {
|
||||
@ -4260,6 +4380,20 @@ static int dsi_display_res_init(struct dsi_display *display)
|
||||
ctrl->phy = NULL;
|
||||
goto error_ctrl_put;
|
||||
}
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
if (!strcmp(display->display_type, "primary")) {
|
||||
ctrl->phy->hw.display_index = PRIMARY_DISPLAY_NDX;
|
||||
ctrl->ctrl->hw.display_index = PRIMARY_DISPLAY_NDX;
|
||||
LCD_INFO_CRITICAL(0, "phy->hw.index[%d] & ctrl->hw.index[%d] are map to SS PRIMARY_DISPLAY_NDX\n",
|
||||
ctrl->phy->hw.index, ctrl->ctrl->hw.index);
|
||||
}
|
||||
else if (!strcmp(display->display_type, "secondary")) {
|
||||
ctrl->phy->hw.display_index = SECONDARY_DISPLAY_NDX;
|
||||
ctrl->ctrl->hw.display_index = SECONDARY_DISPLAY_NDX;
|
||||
LCD_INFO_CRITICAL(0, "phy->hw.index[%d] & ctrl->hw.index[%d] are map to SS SECONDARY_DISPLAY_NDX\n",
|
||||
ctrl->phy->hw.index, ctrl->ctrl->hw.index);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
display->panel = dsi_panel_get(&display->pdev->dev,
|
||||
@ -5131,6 +5265,16 @@ static void dsi_display_validate_dms_fps(struct dsi_display_mode *cur_mode,
|
||||
u32 cur_fps, to_fps;
|
||||
u32 cur_h_active, to_h_active;
|
||||
u32 cur_v_active, to_v_active;
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
u32 cur_sot_hs, to_sot_hs;
|
||||
u32 cur_phs, to_phs;
|
||||
|
||||
cur_sot_hs = cur_mode->timing.sot_hs_mode;
|
||||
to_sot_hs = to_mode->timing.sot_hs_mode;
|
||||
|
||||
cur_phs = cur_mode->timing.phs_mode;
|
||||
to_phs = to_mode->timing.phs_mode;
|
||||
#endif
|
||||
|
||||
cur_fps = cur_mode->timing.refresh_rate;
|
||||
to_fps = to_mode->timing.refresh_rate;
|
||||
@ -5140,7 +5284,11 @@ static void dsi_display_validate_dms_fps(struct dsi_display_mode *cur_mode,
|
||||
to_v_active = to_mode->timing.v_active;
|
||||
|
||||
if ((cur_h_active == to_h_active) && (cur_v_active == to_v_active) &&
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
((cur_phs != to_phs) || (cur_sot_hs != to_sot_hs) || (cur_fps != to_fps))) {
|
||||
#else
|
||||
(cur_fps != to_fps)) {
|
||||
#endif
|
||||
to_mode->dsi_mode_flags |= DSI_MODE_FLAG_DMS_FPS;
|
||||
DSI_DEBUG("DMS Modeset with FPS change\n");
|
||||
} else {
|
||||
@ -5396,6 +5544,10 @@ int dsi_display_cont_splash_res_disable(void *dsi_display)
|
||||
struct dsi_display *display = dsi_display;
|
||||
int rc = 0;
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
ss_panel_power_pmic_vote(display->panel->panel_private, false);
|
||||
#endif
|
||||
|
||||
/* Remove the panel vote that was added during dsi display probe */
|
||||
rc = dsi_pwr_enable_regulator(&display->panel->power_info, false);
|
||||
if (rc)
|
||||
@ -5414,6 +5566,12 @@ int dsi_display_cont_splash_config(void *dsi_display)
|
||||
{
|
||||
struct dsi_display *display = dsi_display;
|
||||
int rc = 0;
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
struct samsung_display_driver_data *vdd;
|
||||
struct drm_encoder *drm_enc;
|
||||
struct dsi_display_ctrl *ctrl;
|
||||
int i;
|
||||
#endif
|
||||
|
||||
/* Vote for gdsc required to read register address space */
|
||||
if (!display) {
|
||||
@ -5432,6 +5590,15 @@ int dsi_display_cont_splash_config(void *dsi_display)
|
||||
|
||||
display->is_cont_splash_enabled = true;
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
vdd = display->panel->panel_private;
|
||||
if (display->is_cont_splash_enabled) {
|
||||
vdd->samsung_splash_enabled = true;
|
||||
vdd->display_status_dsi.first_commit_disp_on = true;
|
||||
LCD_INFO(vdd, "set samsung splash (%d)\n", vdd->samsung_splash_enabled);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Update splash status for clock manager */
|
||||
dsi_display_clk_mngr_update_splash_status(display->clk_mngr,
|
||||
display->is_cont_splash_enabled);
|
||||
@ -5456,6 +5623,44 @@ int dsi_display_cont_splash_config(void *dsi_display)
|
||||
/* Set the current brightness level */
|
||||
dsi_panel_bl_handoff(display->panel);
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
if (vdd->support_early_id_read) {
|
||||
drm_enc = display->bridge->base.encoder;
|
||||
|
||||
/* disable autorefresh to prevent DSI FIFO underflow */
|
||||
sde_encoder_prepare_commit(drm_enc);
|
||||
|
||||
/*
|
||||
* To do dsi related work (rx/tx),
|
||||
* need to set enable flags for dsi state (host_initialized, controller_state) first.
|
||||
*/
|
||||
mutex_lock(&display->display_lock);
|
||||
dsi_config_host_engine_state_for_cont_splash(display, true);
|
||||
dsi_display_ctrl_init(display);
|
||||
|
||||
display_for_each_ctrl(i, display) {
|
||||
ctrl = &display->ctrl[i];
|
||||
if (!ctrl || !ctrl->ctrl)
|
||||
continue;
|
||||
|
||||
/* Copy dma_cmd_trigger of panel (parsed from dtsi) of dma_cmd_trigger of dsi_ctrl
|
||||
* dma_cmd_trigger of dsi_ctrl will be copied at set_mode.
|
||||
* to read opertaion before that, we have to copy the value by force.
|
||||
*/
|
||||
|
||||
LCD_INFO(vdd, "assign ctrl : dma_cmd_trigger %d <- panel dma_cmd_trigger : %d\n",
|
||||
ctrl->ctrl->host_config.common_config.dma_cmd_trigger, display->panel->host_config.dma_cmd_trigger);
|
||||
ctrl->ctrl->host_config.common_config.dma_cmd_trigger = display->panel->host_config.dma_cmd_trigger;
|
||||
}
|
||||
|
||||
ss_early_display_init(display->panel->panel_private);
|
||||
|
||||
dsi_display_ctrl_deinit(display);
|
||||
dsi_config_host_engine_state_for_cont_splash(display, false);
|
||||
mutex_unlock(&display->display_lock);
|
||||
}
|
||||
#endif
|
||||
|
||||
return rc;
|
||||
|
||||
clk_manager_update:
|
||||
@ -5503,6 +5708,28 @@ static int dsi_display_force_update_dsi_clk(struct dsi_display *display)
|
||||
int rc = 0, i = 0;
|
||||
struct dsi_display_ctrl *ctrl;
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
struct samsung_display_driver_data *vdd = display->panel->panel_private;
|
||||
|
||||
if (vdd->panel_func.samsung_dyn_mipi_pre)
|
||||
vdd->panel_func.samsung_dyn_mipi_pre(vdd);
|
||||
|
||||
/* prevent below race condition which causes dsi interrupt storm.
|
||||
* 1) TASK#1: start to transmit mipi cmd. (e.g.: brightness, mdnie, copr, and etc..
|
||||
* 2) TASK#2: dynamic mipi clock: call dsi_display_link_clk_force_update_ctrl(),
|
||||
* and stop link clock.
|
||||
* 3) TASK#1: keep trying to send mipi cmd even link clock is off
|
||||
* --> dsi interrupt storm occurs...
|
||||
* MIPI DSI link clock has vote system, so link clock has refcount value more than 1.
|
||||
* But its value never reach to 0 during display on due to QCT architecture,
|
||||
* may be to prevent frequent display clock on/off overhead...
|
||||
* So, QCT dynamic mipi clock ignores above vote system, and force to reset link clock...
|
||||
*
|
||||
* To prevent above race condition, add vdd->cmd_lock in this function.
|
||||
*/
|
||||
mutex_lock(&vdd->cmd_lock);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 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,
|
||||
@ -5519,11 +5746,20 @@ static int dsi_display_force_update_dsi_clk(struct dsi_display *display)
|
||||
|
||||
rc = dsi_display_link_clk_force_update_ctrl(display->dsi_clk_handle);
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
mutex_unlock(&vdd->cmd_lock);
|
||||
#endif
|
||||
|
||||
if (!rc) {
|
||||
DSI_DEBUG("dsi bit clk has been configured to %d\n",
|
||||
display->cached_clk_rate);
|
||||
|
||||
atomic_set(&display->clkrate_change_pending, 0);
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
#if IS_ENABLED(CONFIG_DEV_RIL_BRIDGE)
|
||||
ss_dyn_mipi_clk_tx_ffc(vdd);
|
||||
#endif
|
||||
#endif
|
||||
} else {
|
||||
DSI_ERR("Failed to configure dsi bit clock '%d'. rc = %d\n",
|
||||
display->cached_clk_rate, rc);
|
||||
@ -5959,6 +6195,12 @@ static const struct component_ops dsi_display_comp_ops = {
|
||||
.unbind = dsi_display_unbind,
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
static const struct dev_pm_ops dsi_display_pm_ops = {
|
||||
.suspend = ss_dsi_display_suspend,
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct platform_driver dsi_display_driver = {
|
||||
.probe = dsi_display_dev_probe,
|
||||
.remove = dsi_display_dev_remove,
|
||||
@ -5966,6 +6208,9 @@ static struct platform_driver dsi_display_driver = {
|
||||
.name = "msm-dsi-display",
|
||||
.of_match_table = dsi_display_dt_match,
|
||||
.suppress_bind_attrs = true,
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
.pm = &dsi_display_pm_ops
|
||||
#endif
|
||||
},
|
||||
};
|
||||
|
||||
@ -6058,6 +6303,10 @@ int dsi_display_dev_probe(struct platform_device *pdev)
|
||||
goto end;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
DSI_INFO("dsi_display_dev_probe ++\n");
|
||||
#endif
|
||||
|
||||
display->post_cmd_tx_workq = create_singlethread_workqueue(
|
||||
"dsi_post_cmd_tx_workq");
|
||||
if (!display->post_cmd_tx_workq) {
|
||||
@ -6097,6 +6346,17 @@ int dsi_display_dev_probe(struct platform_device *pdev)
|
||||
if (!panel_node)
|
||||
DSI_WARN("%s panel_node %s not found\n", display->display_type,
|
||||
boot_disp->name);
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
pr_err("[SDE] %s boot_disp_en True, boot_disp->name=%s\n", display->display_type, boot_disp->name);
|
||||
if (panel_node)
|
||||
samsung_panel_initialize(boot_disp->name, index);
|
||||
else {
|
||||
pr_err("[SDE] Display Panel is not found. Failed to probe\n");
|
||||
rc = -EPROBE_DEFER;
|
||||
goto end;
|
||||
}
|
||||
#endif
|
||||
|
||||
} else {
|
||||
panel_node = of_parse_phandle(node,
|
||||
"qcom,dsi-default-panel", 0);
|
||||
@ -6143,6 +6403,9 @@ int dsi_display_dev_probe(struct platform_device *pdev)
|
||||
if (rc)
|
||||
goto end;
|
||||
}
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
DSI_INFO("dsi_display_dev_probe --\n");
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
end:
|
||||
@ -7084,6 +7347,22 @@ int dsi_display_restore_bit_clk(struct dsi_display *display, struct dsi_display_
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
{
|
||||
struct samsung_display_driver_data *vdd = display->panel->panel_private;
|
||||
|
||||
if (vdd->dyn_mipi_clk.is_support) {
|
||||
clk_rate_hz = display->cached_clk_rate;
|
||||
|
||||
mode->timing.clk_rate_hz = clk_rate_hz;
|
||||
mode->priv_info->clk_rate_hz = clk_rate_hz;
|
||||
|
||||
LCD_DEBUG(vdd, "restore byte clock [%d] \n", display->cached_clk_rate);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* avoid updating bit_clk for dyn clk feature disbaled usecase */
|
||||
if (!display->panel->dyn_clk_caps.dyn_clk_support)
|
||||
return 0;
|
||||
@ -7578,6 +7857,10 @@ static bool dsi_display_match_timings(const struct dsi_display_mode *mode1,
|
||||
mode1->timing.h_skew == mode2->timing.h_skew &&
|
||||
mode1->timing.v_back_porch == mode2->timing.v_back_porch &&
|
||||
mode1->timing.v_front_porch == mode2->timing.v_front_porch &&
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
mode1->timing.sot_hs_mode == mode2->timing.sot_hs_mode &&
|
||||
mode1->timing.phs_mode == mode2->timing.phs_mode &&
|
||||
#endif
|
||||
mode1->timing.v_sync_width == mode2->timing.v_sync_width;
|
||||
|
||||
end:
|
||||
@ -7983,6 +8266,11 @@ static int dsi_display_pre_switch(struct dsi_display *display)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
struct samsung_display_driver_data *vdd = display->panel->panel_private;
|
||||
LCD_DEBUG(vdd, "DMS : update dsi ctrl for new mode\n");
|
||||
#endif
|
||||
|
||||
rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
|
||||
DSI_CORE_CLK, DSI_CLK_ON);
|
||||
if (rc) {
|
||||
@ -8169,6 +8457,57 @@ static void dsi_display_handle_lp_rx_timeout(struct work_struct *work)
|
||||
u32 version = 0;
|
||||
|
||||
display = container_of(work, struct dsi_display, lp_rx_timeout_work);
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
if (display && display->panel &&
|
||||
(display->panel->panel_mode == DSI_OP_CMD_MODE) &&
|
||||
!atomic_read(&display->panel->esd_recovery_pending)) {
|
||||
struct samsung_display_driver_data *vdd;
|
||||
struct sde_connector *conn;
|
||||
|
||||
vdd = display->panel->panel_private;
|
||||
if (!vdd) {
|
||||
LCD_ERR(vdd, "LP RX timeout: invalid vdd\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!vdd->support_lp_rx_err_recovery) {
|
||||
LCD_ERR(vdd, "LP RX timeout: do not support LP RX timeout recovery\n");
|
||||
return;
|
||||
}
|
||||
|
||||
conn = GET_SDE_CONNECTOR(vdd);
|
||||
if (!conn) {
|
||||
LCD_ERR(vdd, "LP RX timeout: invalid conn\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Increase feild cnt only once because we retry 5 times for one mipi fail */
|
||||
if (++vdd->lp_rx_fail_cnt == 1) {
|
||||
if (vdd->ndx == PRIMARY_DISPLAY_NDX)
|
||||
inc_dpui_u32_field(DPUI_KEY_QCT_MAIN_RX_FAIL_CNT, 1);
|
||||
else
|
||||
inc_dpui_u32_field(DPUI_KEY_QCT_SUB_RX_FAIL_CNT, 1);
|
||||
}
|
||||
|
||||
if (display->enabled == false) { // dsi_bridge_enable, dsi_bridge_disable
|
||||
LCD_ERR(vdd, "LP RX timeout: skip panel recovery, trial count = %d\n",
|
||||
vdd->panel_recovery_cnt);
|
||||
return;
|
||||
}
|
||||
LCD_ERR(vdd, "LP RX timeout: panel recovery for cmd panel, trial count = %d\n",
|
||||
vdd->panel_recovery_cnt);
|
||||
|
||||
vdd->esd_recovery.esd_irq_enable(false, true, (void *)vdd, ESD_MASK_DEFAULT);
|
||||
vdd->panel_lpm.esd_recovery = true;
|
||||
|
||||
vdd->panel_recovery_cnt++;
|
||||
SS_XLOG(vdd->panel_recovery_cnt);
|
||||
inc_dpui_u32_field(DPUI_KEY_QCT_RCV_CNT, 1);
|
||||
|
||||
schedule_work(&conn->status_work.work);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (!display || !display->panel ||
|
||||
(display->panel->panel_mode != DSI_OP_VIDEO_MODE) ||
|
||||
atomic_read(&display->panel->esd_recovery_pending)) {
|
||||
@ -8321,6 +8660,9 @@ int dsi_display_prepare(struct dsi_display *display)
|
||||
{
|
||||
int rc = 0;
|
||||
struct dsi_display_mode *mode;
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
struct samsung_display_driver_data *vdd;
|
||||
#endif
|
||||
|
||||
if (!display) {
|
||||
DSI_ERR("Invalid params\n");
|
||||
@ -8332,6 +8674,12 @@ int dsi_display_prepare(struct dsi_display *display)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
vdd = display->panel->panel_private;
|
||||
if (!(display->panel->cur_mode->dsi_mode_flags & DSI_MODE_FLAG_DMS))
|
||||
LCD_INFO(vdd, "++\n");
|
||||
#endif
|
||||
|
||||
SDE_EVT32(SDE_EVTLOG_FUNC_ENTRY);
|
||||
mutex_lock(&display->display_lock);
|
||||
|
||||
@ -8456,6 +8804,17 @@ int dsi_display_prepare(struct dsi_display *display)
|
||||
}
|
||||
}
|
||||
}
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
else if (ss_panel_attach_get(display->panel->panel_private)) {
|
||||
/* In case of cont. splash on mode, it skips pinctrl setting
|
||||
* included in dsi_panel_prepare(). Some display pins,
|
||||
* which are not configured in bootloader, would be unpredictable state.
|
||||
* Configure display pins here, in case of cont. splash on mode.
|
||||
*/
|
||||
LCD_INFO(vdd, "set display pinctrl in con_splash on mode\n");
|
||||
rc = dsi_panel_set_pinctrl_state(display->panel, true);
|
||||
}
|
||||
#endif
|
||||
goto error;
|
||||
|
||||
error_ctrl_link_off:
|
||||
@ -8475,6 +8834,11 @@ error_panel_post_unprep:
|
||||
error:
|
||||
mutex_unlock(&display->display_lock);
|
||||
SDE_EVT32(SDE_EVTLOG_FUNC_EXIT);
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
if (!(display->panel->cur_mode->dsi_mode_flags & DSI_MODE_FLAG_DMS))
|
||||
LCD_INFO(vdd, "%s --\n", display->display_type);
|
||||
#endif
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -8539,6 +8903,10 @@ static int dsi_display_qsync(struct dsi_display *display, bool enable)
|
||||
mutex_lock(&display->display_lock);
|
||||
display->queue_cmd_waits = true;
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
SDE_ATRACE_BEGIN(enable ? "qsync_on" : "qsync_off");
|
||||
#endif
|
||||
|
||||
display_for_each_ctrl(i, display) {
|
||||
if (enable) {
|
||||
/* send the commands to enable qsync */
|
||||
@ -8561,6 +8929,9 @@ static int dsi_display_qsync(struct dsi_display *display, bool enable)
|
||||
|
||||
exit:
|
||||
display->queue_cmd_waits = false;
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
SDE_ATRACE_END(enable ? "qsync_on" : "qsync_off");
|
||||
#endif
|
||||
SDE_EVT32(enable, display->panel->qsync_caps.qsync_min_fps, rc);
|
||||
mutex_unlock(&display->display_lock);
|
||||
return rc;
|
||||
@ -8630,13 +9001,28 @@ int dsi_display_pre_kickoff(struct drm_connector *connector,
|
||||
struct dsi_display_mode *mode;
|
||||
int rc = 0, ret = 0;
|
||||
int i;
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
struct samsung_display_driver_data *vdd;
|
||||
#endif
|
||||
mode = display->panel->cur_mode;
|
||||
|
||||
/* check and setup MISR */
|
||||
if (display->misr_enable)
|
||||
_dsi_display_setup_misr(display);
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
/* SAMSUNG_FINGERPRINT */
|
||||
vdd = display->panel->panel_private;
|
||||
|
||||
mutex_lock(&vdd->dyn_mipi_clk.dyn_mipi_lock);
|
||||
/* configure dynamic clk rate */
|
||||
if (vdd->dyn_mipi_clk.requested_clk_rate) {
|
||||
if (display->panel->panel_mode == DSI_OP_CMD_MODE)
|
||||
dsi_display_dynamic_clk_configure_cmd(display, vdd->dyn_mipi_clk.requested_clk_rate);
|
||||
vdd->dyn_mipi_clk.requested_clk_rate = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* dynamic DSI clock setting */
|
||||
if (atomic_read(&display->clkrate_change_pending)) {
|
||||
mutex_lock(&display->display_lock);
|
||||
@ -8689,6 +9075,9 @@ wait_failure:
|
||||
mutex_unlock(&display->display_lock);
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
mutex_unlock(&vdd->dyn_mipi_clk.dyn_mipi_lock);
|
||||
#endif
|
||||
if (!ret)
|
||||
rc = dsi_display_set_roi(display, params->rois);
|
||||
|
||||
@ -8771,6 +9160,9 @@ int dsi_display_enable(struct dsi_display *display)
|
||||
{
|
||||
int rc = 0;
|
||||
struct dsi_display_mode *mode;
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
struct samsung_display_driver_data *vdd = display->panel->panel_private;
|
||||
#endif
|
||||
|
||||
if (!display || !display->panel) {
|
||||
DSI_ERR("Invalid params\n");
|
||||
@ -8798,13 +9190,56 @@ int dsi_display_enable(struct dsi_display *display)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
/* Initialize samsung display driver in continuous splash mode,
|
||||
* like smart dimming, mdnie, and etc.
|
||||
*/
|
||||
LCD_INFO(vdd, "is_cont_splash_enabled, support_vrr_based_bl: %d, vrr_change: %d, multi_res_change: %d\n",
|
||||
vdd->vrr.support_vrr_based_bl, vdd->vrr.is_vrr_changing,
|
||||
vdd->vrr.is_multi_resolution_changing);
|
||||
|
||||
mutex_lock(&display->display_lock);
|
||||
|
||||
dsi_panel_enable(display->panel);
|
||||
|
||||
/* In case of that first commit includes VRR, it should handle VRR or multi resolution.
|
||||
* dsi_mode_flags has no DSI_MODE_FLAG_DMS set which is set in
|
||||
* dsi_display_validate_mode_change().
|
||||
*/
|
||||
/* If dsi_panel_switch() is called before dsi_panel_enable()
|
||||
* which transmit qcom,mdss-dsi-on-command, it causes causes
|
||||
* screen noise on HAB DDI.
|
||||
*/
|
||||
if (vdd->vrr.support_vrr_based_bl &&
|
||||
(vdd->vrr.is_vrr_changing || vdd->vrr.is_multi_resolution_changing)) {
|
||||
LCD_INFO(vdd, "DMS: VRR: trigger dms switch in splash on mode\n");
|
||||
dsi_panel_switch(display->panel);
|
||||
}
|
||||
|
||||
mode = display->panel->cur_mode;
|
||||
|
||||
if ((mode->priv_info->dsc_enabled) && (!vdd->mipi_header_modi)) {
|
||||
mode->priv_info->dsc.config.pic_width *= display->ctrl_count;
|
||||
dsi_panel_update_pps(display->panel);
|
||||
}
|
||||
mutex_unlock(&display->display_lock);
|
||||
|
||||
vdd->samsung_splash_enabled = false;
|
||||
LCD_INFO(vdd, "%s : samsung splash disable!!\n", __func__);
|
||||
#else
|
||||
|
||||
display->panel->panel_initialized = true;
|
||||
DSI_DEBUG("cont splash enabled, display enable not required\n");
|
||||
dsi_display_panel_id_notification(display);
|
||||
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
if (!(display->panel->cur_mode->dsi_mode_flags & DSI_MODE_FLAG_DMS))
|
||||
LCD_INFO(vdd, "++\n");
|
||||
#endif
|
||||
|
||||
mutex_lock(&display->display_lock);
|
||||
|
||||
mode = display->panel->cur_mode;
|
||||
@ -8875,12 +9310,21 @@ error_disable_panel:
|
||||
error:
|
||||
mutex_unlock(&display->display_lock);
|
||||
SDE_EVT32(SDE_EVTLOG_FUNC_EXIT);
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
if (!(display->panel->cur_mode->dsi_mode_flags & DSI_MODE_FLAG_DMS))
|
||||
LCD_INFO(vdd, "--\n");
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
int dsi_display_post_enable(struct dsi_display *display)
|
||||
{
|
||||
int rc = 0;
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
struct samsung_display_driver_data *vdd = display->panel->panel_private;
|
||||
if (!(display->panel->cur_mode->dsi_mode_flags & DSI_MODE_FLAG_DMS))
|
||||
LCD_INFO(vdd, "++\n");
|
||||
#endif
|
||||
|
||||
if (!display) {
|
||||
DSI_ERR("Invalid params\n");
|
||||
@ -8902,18 +9346,36 @@ int dsi_display_post_enable(struct dsi_display *display)
|
||||
display->name, rc);
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
if (!vdd->dtsi_data.samsung_tcon_clk_on_support) {
|
||||
/* remove the clk vote for CMD mode panels */
|
||||
if (display->config.panel_mode == DSI_OP_CMD_MODE) {
|
||||
SDE_EVT32(SDE_EVTLOG_FUNC_CASE1); // case 04627046
|
||||
dsi_display_clk_ctrl(display->dsi_clk_handle,
|
||||
DSI_ALL_CLKS, DSI_CLK_OFF);
|
||||
}
|
||||
}
|
||||
#else
|
||||
/* remove the clk vote for CMD mode panels */
|
||||
if (display->config.panel_mode == DSI_OP_CMD_MODE)
|
||||
dsi_display_clk_ctrl(display->dsi_clk_handle,
|
||||
DSI_ALL_CLKS, DSI_CLK_OFF);
|
||||
#endif
|
||||
|
||||
mutex_unlock(&display->display_lock);
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
if (!(display->panel->cur_mode->dsi_mode_flags & DSI_MODE_FLAG_DMS))
|
||||
LCD_INFO(vdd, "-- \n");
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
int dsi_display_pre_disable(struct dsi_display *display)
|
||||
{
|
||||
int rc = 0;
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
struct samsung_display_driver_data *vdd = display->panel->panel_private;
|
||||
#endif
|
||||
|
||||
if (!display) {
|
||||
DSI_ERR("Invalid params\n");
|
||||
@ -8922,10 +9384,21 @@ int dsi_display_pre_disable(struct dsi_display *display)
|
||||
|
||||
mutex_lock(&display->display_lock);
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
if (!vdd->dtsi_data.samsung_tcon_clk_on_support) {
|
||||
/* enable the clk vote for CMD mode panels */
|
||||
if (display->config.panel_mode == DSI_OP_CMD_MODE) {
|
||||
SDE_EVT32(SDE_EVTLOG_FUNC_CASE1); // case 04627046
|
||||
dsi_display_clk_ctrl(display->dsi_clk_handle,
|
||||
DSI_ALL_CLKS, DSI_CLK_ON);
|
||||
}
|
||||
}
|
||||
#else
|
||||
/* enable the clk vote for CMD mode panels */
|
||||
if (display->config.panel_mode == DSI_OP_CMD_MODE)
|
||||
dsi_display_clk_ctrl(display->dsi_clk_handle,
|
||||
DSI_ALL_CLKS, DSI_CLK_ON);
|
||||
#endif
|
||||
if (display->poms_pending) {
|
||||
if (display->config.panel_mode == DSI_OP_CMD_MODE)
|
||||
dsi_panel_switch_cmd_mode_out(display->panel);
|
||||
@ -8976,12 +9449,18 @@ error:
|
||||
int dsi_display_disable(struct dsi_display *display)
|
||||
{
|
||||
int rc = 0;
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
struct samsung_display_driver_data *vdd = display->panel->panel_private;
|
||||
#endif
|
||||
|
||||
if (!display) {
|
||||
DSI_ERR("Invalid params\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
LCD_INFO(vdd, "++\n");
|
||||
#endif
|
||||
SDE_EVT32(SDE_EVTLOG_FUNC_ENTRY);
|
||||
mutex_lock(&display->display_lock);
|
||||
|
||||
@ -9036,6 +9515,9 @@ int dsi_display_disable(struct dsi_display *display)
|
||||
}
|
||||
mutex_unlock(&display->display_lock);
|
||||
SDE_EVT32(SDE_EVTLOG_FUNC_EXIT);
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
LCD_INFO(vdd, "--\n");
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -9151,12 +9633,19 @@ end:
|
||||
int dsi_display_unprepare(struct dsi_display *display)
|
||||
{
|
||||
int rc = 0;
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
struct samsung_display_driver_data *vdd;
|
||||
#endif
|
||||
|
||||
if (!display) {
|
||||
DSI_ERR("Invalid params\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
vdd = display->panel->panel_private;
|
||||
LCD_INFO(vdd, "++\n");
|
||||
#endif
|
||||
SDE_EVT32(SDE_EVTLOG_FUNC_ENTRY);
|
||||
mutex_lock(&display->display_lock);
|
||||
|
||||
@ -9217,6 +9706,9 @@ int dsi_display_unprepare(struct dsi_display *display)
|
||||
dsi_display_unregister_error_handler(display);
|
||||
|
||||
SDE_EVT32(SDE_EVTLOG_FUNC_EXIT);
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
LCD_INFO(vdd, "--\n");
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,9 @@
|
||||
#include "sde_dbg.h"
|
||||
#include "msm_drv.h"
|
||||
#include "sde_encoder.h"
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
#include "ss_dsi_panel_common.h"
|
||||
#endif
|
||||
|
||||
#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)
|
||||
@ -59,6 +62,11 @@ static void convert_to_dsi_mode(const struct drm_display_mode *drm_mode,
|
||||
!!(drm_mode->flags & DRM_MODE_FLAG_PHSYNC);
|
||||
dsi_mode->timing.v_sync_polarity =
|
||||
!!(drm_mode->flags & DRM_MODE_FLAG_PVSYNC);
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
dsi_mode->timing.sot_hs_mode = ss_is_sot_hs_from_drm_mode(drm_mode);
|
||||
dsi_mode->timing.phs_mode = ss_is_phs_from_drm_mode(drm_mode);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void msm_parse_mode_priv_info(const struct msm_display_mode *msm_mode,
|
||||
@ -134,10 +142,17 @@ void dsi_convert_to_drm_mode(const struct dsi_display_mode *dsi_mode,
|
||||
if (dsi_mode->timing.v_sync_polarity)
|
||||
drm_mode->flags |= DRM_MODE_FLAG_PVSYNC;
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
snprintf(drm_mode->name, DRM_DISPLAY_MODE_LEN, "%dx%dx%dx%s%s",
|
||||
drm_mode->hdisplay, drm_mode->vdisplay,
|
||||
drm_mode_vrefresh(drm_mode), panel_caps,
|
||||
dsi_mode->timing.sot_hs_mode ? (dsi_mode->timing.phs_mode ? "PHS" : "HS") : "NS");
|
||||
#else
|
||||
/* set mode name */
|
||||
snprintf(drm_mode->name, DRM_DISPLAY_MODE_LEN, "%dx%dx%d%s",
|
||||
drm_mode->hdisplay, drm_mode->vdisplay,
|
||||
drm_mode_vrefresh(drm_mode), panel_caps);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void dsi_convert_to_msm_mode(const struct dsi_display_mode *dsi_mode,
|
||||
@ -454,7 +469,25 @@ static bool _dsi_bridge_mode_validate_and_fixup(struct drm_bridge *bridge,
|
||||
(!(adj_mode->dsi_mode_flags & DSI_MODE_FLAG_POMS_TO_CMD)) &&
|
||||
(!crtc_state->active_changed ||
|
||||
display->is_cont_splash_enabled)) {
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
rc = ss_vrr_apply_dsi_bridge_mode_fixup(display, cur_mode,
|
||||
cur_dsi_mode, adj_mode);
|
||||
|
||||
SDE_EVT32(SDE_EVTLOG_FUNC_CASE2,
|
||||
cur_dsi_mode.timing.refresh_rate,
|
||||
cur_dsi_mode.timing.sot_hs_mode,
|
||||
cur_dsi_mode.timing.phs_mode,
|
||||
adj_mode->timing.refresh_rate,
|
||||
adj_mode->timing.sot_hs_mode,
|
||||
adj_mode->timing.phs_mode);
|
||||
|
||||
} else if (!dsi_display_mode_match(&cur_dsi_mode, adj_mode,
|
||||
DSI_MODE_MATCH_FULL_TIMINGS)) {
|
||||
rc = ss_vrr_save_dsi_bridge_mode_fixup(display, cur_mode,
|
||||
cur_dsi_mode, adj_mode, crtc_state);
|
||||
#else
|
||||
adj_mode->dsi_mode_flags |= DSI_MODE_FLAG_DMS;
|
||||
#endif
|
||||
|
||||
SDE_EVT32(SDE_EVTLOG_FUNC_CASE2,
|
||||
adj_mode->timing.h_active,
|
||||
@ -676,6 +709,10 @@ int dsi_conn_get_mode_info(struct drm_connector *connector,
|
||||
dsi_display->panel->host_config.line_insertion_enable = 0;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
mode_info->frame_rate_org = mode_info->frame_rate;
|
||||
#endif
|
||||
|
||||
memcpy(&mode_info->topology, &dsi_mode->priv_info->topology,
|
||||
sizeof(struct msm_display_topology));
|
||||
|
||||
@ -769,6 +806,9 @@ int dsi_conn_get_avr_step_fps(struct drm_connector_state *conn_state)
|
||||
return -EINVAL;
|
||||
|
||||
priv_info = (struct dsi_display_mode_priv_info *)(msm_mode->private);
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
DSI_DEBUG("avr_step_fps (%d)\n", priv_info->avr_step_fps);
|
||||
#endif
|
||||
return priv_info->avr_step_fps;
|
||||
}
|
||||
|
||||
@ -1192,6 +1232,32 @@ int dsi_connector_get_modes(struct drm_connector *connector, void *data,
|
||||
for (i = 0; i < count; i++) {
|
||||
struct drm_display_mode *m;
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
struct samsung_display_driver_data *vdd = NULL;
|
||||
|
||||
if (display && display->panel)
|
||||
vdd = display->panel->panel_private;
|
||||
|
||||
if (vdd) {
|
||||
u32 fps = modes[i].timing.refresh_rate;
|
||||
bool hs = modes[i].timing.sot_hs_mode;
|
||||
bool phs = modes[i].timing.phs_mode;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < vdd->disable_vrr_modes_count; i++) {
|
||||
if (vdd->disable_vrr_modes[i].fps == fps &&
|
||||
vdd->disable_vrr_modes[i].hs == hs &&
|
||||
vdd->disable_vrr_modes[i].phs == phs) {
|
||||
DSI_INFO("disable vrr modes: %d%s\n",
|
||||
fps, phs ? "PHS" : hs ? "HS" : "NS");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i != vdd->disable_vrr_modes_count)
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
memset(&drm_mode, 0x0, sizeof(drm_mode));
|
||||
dsi_convert_to_drm_mode(&modes[i], &drm_mode);
|
||||
m = drm_mode_duplicate(connector->dev, &drm_mode);
|
||||
|
@ -18,6 +18,12 @@
|
||||
#include "sde_dsc_helper.h"
|
||||
#include "sde_vdc_helper.h"
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
#include "ss_dsi_panel_common.h"
|
||||
#include "ss_panel_power.h"
|
||||
#include "sde_trace.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* topology is currently defined by a set of following 3 values:
|
||||
* 1. num of layer mixers
|
||||
@ -78,6 +84,11 @@ static int dsi_panel_vreg_get(struct dsi_panel *panel)
|
||||
int i;
|
||||
struct regulator *vreg = NULL;
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
return ss_panel_parse_powers(ss_get_vdd_from_panel_name(panel->name),
|
||||
panel->panel_of_node, panel->parent);
|
||||
#endif
|
||||
|
||||
for (i = 0; i < panel->power_info.count; i++) {
|
||||
vreg = devm_regulator_get(panel->parent,
|
||||
panel->power_info.vregs[i].vreg_name);
|
||||
@ -115,6 +126,10 @@ static int dsi_panel_gpio_request(struct dsi_panel *panel)
|
||||
int rc = 0;
|
||||
struct dsi_panel_reset_config *r_config = &panel->reset_config;
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
if (gpio_is_valid(r_config->reset_gpio)) {
|
||||
rc = gpio_request(r_config->reset_gpio, "reset_gpio");
|
||||
if (rc) {
|
||||
@ -259,6 +274,10 @@ static int dsi_panel_reset(struct dsi_panel *panel)
|
||||
struct dsi_panel_reset_config *r_config = &panel->reset_config;
|
||||
int i;
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
if (!gpio_is_valid(r_config->reset_gpio))
|
||||
goto skip_reset_gpio;
|
||||
|
||||
@ -326,7 +345,11 @@ exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
int dsi_panel_set_pinctrl_state(struct dsi_panel *panel, bool enable)
|
||||
#else
|
||||
static int dsi_panel_set_pinctrl_state(struct dsi_panel *panel, bool enable)
|
||||
#endif
|
||||
{
|
||||
int rc = 0;
|
||||
struct pinctrl_state *state;
|
||||
@ -355,6 +378,10 @@ static int dsi_panel_power_on(struct dsi_panel *panel)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
rc = dsi_pwr_enable_regulator(&panel->power_info, true);
|
||||
if (rc) {
|
||||
DSI_ERR("[%s] failed to enable vregs, rc=%d\n",
|
||||
@ -396,6 +423,10 @@ static int dsi_panel_power_off(struct dsi_panel *panel)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
return ss_panel_power_off_post_lp11(panel->panel_private);
|
||||
#endif
|
||||
|
||||
if (gpio_is_valid(panel->reset_config.disp_en_gpio))
|
||||
gpio_set_value(panel->reset_config.disp_en_gpio, 0);
|
||||
|
||||
@ -426,16 +457,51 @@ static int dsi_panel_power_off(struct dsi_panel *panel)
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
int dsi_panel_tx_cmd_set(struct dsi_panel *panel,
|
||||
int type)
|
||||
#else
|
||||
static int dsi_panel_tx_cmd_set(struct dsi_panel *panel,
|
||||
enum dsi_cmd_set_type type)
|
||||
#endif
|
||||
{
|
||||
int rc = 0, i = 0;
|
||||
ssize_t len;
|
||||
struct dsi_cmd_desc *cmds;
|
||||
u32 count;
|
||||
enum dsi_cmd_set_state state;
|
||||
#if !IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
struct dsi_display_mode *mode;
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
struct samsung_display_driver_data *vdd = panel->panel_private;
|
||||
struct dsi_panel_cmd_set *set;
|
||||
struct dsi_display *display = container_of(panel->host, struct dsi_display, host);
|
||||
size_t tot_tx_len = 0;
|
||||
int retry = 5;
|
||||
|
||||
if (ss_check_panel_connection(vdd)) {
|
||||
LCD_INFO(vdd, "skip to send command(type: %d)\n", type);
|
||||
dump_stack();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ss_get_cmds() gets proper QCT cmds or SS cmds for panel revision. */
|
||||
set = ss_get_cmds(vdd, type);
|
||||
if (!set) {
|
||||
LCD_INFO(vdd, "fail to get commands(%d)\n", type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
cmds = set->cmds;
|
||||
count = set->count;
|
||||
state = set->state;
|
||||
|
||||
SDE_EVT32(type, state, count);
|
||||
mutex_lock(&vdd->cmd_lock);
|
||||
#else
|
||||
if (!panel || !panel->cur_mode)
|
||||
return -EINVAL;
|
||||
|
||||
@ -445,6 +511,23 @@ static int dsi_panel_tx_cmd_set(struct dsi_panel *panel,
|
||||
count = mode->priv_info->cmd_sets[type].count;
|
||||
state = mode->priv_info->cmd_sets[type].state;
|
||||
SDE_EVT32(type, state, count);
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
if (cmds && (display->ctrl[0].ctrl->secure_mode)) {
|
||||
for (i = 0 ; i < count ; i++) {
|
||||
if (cmds->msg.tx_len > DSI_CTRL_MAX_CMD_FIFO_STORE_SIZE) {
|
||||
LCD_ERR(vdd, "Over DSI_CTRL_MAX_CMD_FIFO_STORE_SIZE at secure_mode type = %d\n", type);
|
||||
if (type != TX_MDNIE_TUNE)
|
||||
WARN(1, "unexpected cmd type = %d\n", type);
|
||||
goto error;
|
||||
}
|
||||
cmds++;
|
||||
}
|
||||
for (i = 0 ; i < count ; i++)
|
||||
cmds--;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (count == 0) {
|
||||
DSI_DEBUG("[%s] No commands to be sent for state(%d)\n",
|
||||
@ -455,24 +538,99 @@ static int dsi_panel_tx_cmd_set(struct dsi_panel *panel,
|
||||
for (i = 0; i < count; i++) {
|
||||
cmds->ctrl_flags = 0;
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
if (is_ss_cmd_op_skip(vdd, cmds->ss_cmd)) {
|
||||
DSI_DEBUG("skip tx cmd\n");
|
||||
cmds++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* set last_command if total size is over than MAX DSI FIFO SIZE */
|
||||
cmds->msg.flags |= MIPI_DSI_MSG_BATCH_COMMAND;
|
||||
|
||||
if (tot_tx_len == 0)
|
||||
tot_tx_len = ALIGN((cmds->msg.tx_len + 4), 4);
|
||||
|
||||
if (i < count - 1)
|
||||
tot_tx_len += ALIGN(((cmds + 1)->msg.tx_len + 4), 4);
|
||||
|
||||
/* set last_command if next cmd is read cmd */
|
||||
if (i < count - 1 && (cmds + 1)->msg.rx_len && (cmds + 1)->msg.rx_buf)
|
||||
cmds->msg.flags &= ~(MIPI_DSI_MSG_BATCH_COMMAND);
|
||||
|
||||
if ((tot_tx_len > DSI_CTRL_MAX_CMD_FET_MEMORY_SIZE) || (i == count-1) || (cmds->post_wait_ms) ||
|
||||
(cmds->last_command == true)) {
|
||||
pr_debug("tot %zd is over than max || last cmd set, set last_command", tot_tx_len);
|
||||
cmds->msg.flags &= ~(MIPI_DSI_MSG_BATCH_COMMAND);
|
||||
tot_tx_len = 0;
|
||||
}
|
||||
|
||||
if (vdd->not_support_single_tx) /* Some DDI does not support single tx */
|
||||
cmds->msg.flags &= ~(MIPI_DSI_MSG_BATCH_COMMAND);
|
||||
|
||||
if (vdd->dtsi_data.samsung_cmds_unicast)
|
||||
cmds->msg.flags |= MIPI_DSI_MSG_UNICAST_COMMAND;
|
||||
|
||||
/*
|
||||
Single dsi display uses unicast by default.
|
||||
Force Broadcast(dual dsi) dispaly use main only read operation,
|
||||
even if samsung_cmds_unicast is not set.
|
||||
|
||||
*/
|
||||
if (cmds->msg.rx_len && cmds->msg.rx_buf) {
|
||||
cmds->msg.flags |= MIPI_DSI_MSG_UNICAST_COMMAND; /* Vendor QC uses this flag now */
|
||||
cmds->ctrl_flags |= DSI_CTRL_CMD_READ;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (state == DSI_CMD_SET_STATE_LP)
|
||||
cmds->msg.flags |= MIPI_DSI_MSG_USE_LPM;
|
||||
|
||||
if (type == DSI_CMD_SET_VID_SWITCH_OUT)
|
||||
cmds->msg.flags |= MIPI_DSI_MSG_ASYNC_OVERRIDE;
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
while (retry-- >= 0) {
|
||||
#endif
|
||||
|
||||
len = dsi_host_transfer_sub(panel->host, cmds);
|
||||
if (len < 0) {
|
||||
rc = len;
|
||||
DSI_ERR("failed to set cmds(%d), rc=%d\n", type, rc);
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
DSI_ERR("transfer retry!(%d)\n", retry);
|
||||
continue;
|
||||
#endif
|
||||
goto error;
|
||||
}
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
else {
|
||||
retry = 5;
|
||||
break;
|
||||
}
|
||||
} /* while end */
|
||||
|
||||
if (retry < 0) {
|
||||
if (!vdd->panel_dead)
|
||||
SDE_DBG_DUMP(SDE_DBG_BUILT_IN_ALL, "panic");
|
||||
else
|
||||
DSI_ERR("Skip dump register & panic in ESD\n");
|
||||
}
|
||||
|
||||
/* reset lp_rx_fail_cnt if mipi read is successful */
|
||||
vdd->lp_rx_fail_cnt = 0;
|
||||
#endif
|
||||
|
||||
if (cmds->post_wait_ms)
|
||||
usleep_range(cmds->post_wait_ms*1000,
|
||||
((cmds->post_wait_ms*1000)+10));
|
||||
cmds++;
|
||||
}
|
||||
error:
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
mutex_unlock(&vdd->cmd_lock);
|
||||
#endif
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -554,6 +712,9 @@ static int dsi_panel_update_backlight(struct dsi_panel *panel,
|
||||
int rc = 0;
|
||||
unsigned long mode_flags = 0;
|
||||
struct mipi_dsi_device *dsi = NULL;
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
struct samsung_display_driver_data *vdd;
|
||||
#endif
|
||||
|
||||
if (!panel || (bl_lvl > 0xffff)) {
|
||||
DSI_ERR("invalid params\n");
|
||||
@ -569,9 +730,16 @@ static int dsi_panel_update_backlight(struct dsi_panel *panel,
|
||||
if (panel->bl_config.bl_inverted_dbv)
|
||||
bl_lvl = (((bl_lvl & 0xff) << 8) | (bl_lvl >> 8));
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
vdd = panel->panel_private;
|
||||
rc = ss_brightness_dcs(panel->panel_private, bl_lvl, BACKLIGHT_NORMAL);
|
||||
if (rc < 0)
|
||||
LCD_ERR(vdd, "failed to update dcs backlight:%d\n", bl_lvl);
|
||||
#else
|
||||
rc = mipi_dsi_dcs_set_display_brightness(dsi, bl_lvl);
|
||||
if (rc < 0)
|
||||
DSI_ERR("failed to update dcs backlight:%d\n", bl_lvl);
|
||||
#endif
|
||||
|
||||
if (unlikely(panel->bl_config.lp_mode))
|
||||
dsi->mode_flags = mode_flags;
|
||||
@ -935,6 +1103,11 @@ static int dsi_panel_parse_timing(struct dsi_mode_info *mode,
|
||||
mode->v_active, mode->v_front_porch, mode->v_back_porch,
|
||||
mode->v_sync_width);
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
mode->sot_hs_mode = utils->read_bool(utils->data, "samsung,mdss-dsi-sot-hs-mode");
|
||||
mode->phs_mode = utils->read_bool(utils->data, "samsung,mdss-dsi-phs-mode");
|
||||
#endif
|
||||
|
||||
error:
|
||||
return rc;
|
||||
}
|
||||
@ -1977,6 +2150,10 @@ int dsi_panel_create_cmd_packets(const char *data,
|
||||
goto error_free_payloads;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
cmd[i].ss_txbuf = payload;
|
||||
#endif
|
||||
|
||||
for (j = 0; j < cmd[i].msg.tx_len; j++)
|
||||
payload[j] = data[7 + j];
|
||||
|
||||
@ -2044,7 +2221,9 @@ static int dsi_panel_parse_cmd_sets_sub(struct dsi_panel_cmd_set *cmd,
|
||||
|
||||
DSI_DEBUG("type=%d, name=%s, length=%d\n", type, cmd_set_prop_map[type], length);
|
||||
|
||||
#if !IS_ENABLED(CONFIG_DISPLAY_SAMSUNG) /* prevent log flood */
|
||||
print_hex_dump_debug("", DUMP_PREFIX_NONE, 8, 1, data, length, false);
|
||||
#endif
|
||||
|
||||
rc = dsi_panel_get_cmd_pkt_count(data, length, &packet_count);
|
||||
if (rc) {
|
||||
@ -2354,6 +2533,10 @@ static int dsi_panel_parse_power_cfg(struct dsi_panel *panel)
|
||||
int rc = 0;
|
||||
char *supply_name;
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
if (panel->host_config.ext_bridge_mode)
|
||||
return 0;
|
||||
|
||||
@ -2402,6 +2585,10 @@ static int dsi_panel_parse_gpios(struct dsi_panel *panel)
|
||||
struct dsi_parser_utils *utils = &panel->utils;
|
||||
char *reset_gpio_name, *mode_set_gpio_name;
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
if (!strcmp(panel->type, "primary")) {
|
||||
reset_gpio_name = "qcom,platform-reset-gpio";
|
||||
mode_set_gpio_name = "qcom,panel-mode-gpio";
|
||||
@ -2576,6 +2763,18 @@ static int dsi_panel_parse_bl_config(struct dsi_panel *panel)
|
||||
panel->bl_config.brightness_max_level = val;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
rc = utils->read_u32(utils->data, "qcom,mdss-brightness-default-level",
|
||||
&val);
|
||||
if (rc) {
|
||||
pr_debug("[%s] brigheness-default-level unspecified, defaulting to 255\n",
|
||||
panel->name);
|
||||
panel->bl_config.bl_level = 255;
|
||||
} else {
|
||||
panel->bl_config.bl_level = val;
|
||||
}
|
||||
#endif
|
||||
|
||||
panel->bl_config.bl_inverted_dbv = utils->read_bool(utils->data,
|
||||
"qcom,mdss-dsi-bl-inverted-dbv");
|
||||
|
||||
@ -3561,6 +3760,11 @@ static int dsi_panel_parse_esd_config(struct dsi_panel *panel)
|
||||
esd_config->status_mode = ESD_MODE_SW_BTA;
|
||||
} else if (!strcmp(string, "reg_read")) {
|
||||
esd_config->status_mode = ESD_MODE_REG_READ;
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
} else if (!strcmp(string, "irq_check")) {
|
||||
esd_config->status_mode = ESD_MODE_PANEL_IRQ;
|
||||
DSI_INFO("%s : irq_check!!\n", __func__);
|
||||
#endif
|
||||
} else if (!strcmp(string, "te_signal_check")) {
|
||||
if (panel->panel_mode == DSI_OP_CMD_MODE) {
|
||||
esd_config->status_mode = ESD_MODE_PANEL_TE;
|
||||
@ -3590,6 +3794,10 @@ static int dsi_panel_parse_esd_config(struct dsi_panel *panel)
|
||||
esd_mode = "register_read";
|
||||
} else if (panel->esd_config.status_mode == ESD_MODE_SW_BTA) {
|
||||
esd_mode = "bta_trigger";
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
} else if (panel->esd_config.status_mode == ESD_MODE_PANEL_IRQ) {
|
||||
esd_mode = "panel_irq";
|
||||
#endif
|
||||
} else if (panel->esd_config.status_mode == ESD_MODE_PANEL_TE) {
|
||||
esd_mode = "te_check";
|
||||
}
|
||||
@ -3607,6 +3815,10 @@ static void dsi_panel_update_util(struct dsi_panel *panel,
|
||||
struct device_node *parser_node)
|
||||
{
|
||||
struct dsi_parser_utils *utils = &panel->utils;
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
struct dsi_parser_utils *self_disp_utils = &panel->self_display_utils;
|
||||
struct dsi_parser_utils *mafpc_utils = &panel->mafpc_utils;
|
||||
#endif
|
||||
|
||||
if (parser_node) {
|
||||
*utils = *dsi_parser_get_parser_utils();
|
||||
@ -3621,6 +3833,15 @@ static void dsi_panel_update_util(struct dsi_panel *panel,
|
||||
utils->data = panel->panel_of_node;
|
||||
end:
|
||||
utils->node = panel->panel_of_node;
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
*self_disp_utils = *dsi_parser_get_of_utils();
|
||||
self_disp_utils->data = panel->self_display_of_node;
|
||||
self_disp_utils->node = panel->self_display_of_node;
|
||||
*mafpc_utils = *dsi_parser_get_of_utils();
|
||||
mafpc_utils->data = panel->mafpc_of_node;
|
||||
mafpc_utils->node = panel->mafpc_of_node;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int dsi_panel_vm_stub(struct dsi_panel *panel)
|
||||
@ -3664,6 +3885,10 @@ struct dsi_panel *dsi_panel_get(struct device *parent,
|
||||
struct dsi_parser_utils *utils;
|
||||
const char *panel_physical_type;
|
||||
int rc = 0;
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
struct device_node *self_display_node = of_parse_phandle(of_node, "ss,self_display", 0);
|
||||
struct device_node *mafpc_node = of_parse_phandle(of_node, "ss,mafpc", 0);
|
||||
#endif
|
||||
|
||||
panel = kzalloc(sizeof(*panel), GFP_KERNEL);
|
||||
if (!panel)
|
||||
@ -3672,6 +3897,10 @@ struct dsi_panel *dsi_panel_get(struct device *parent,
|
||||
dsi_panel_setup_vm_ops(panel, trusted_vm_env);
|
||||
|
||||
panel->panel_of_node = of_node;
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
panel->self_display_of_node = self_display_node;
|
||||
panel->mafpc_of_node = mafpc_node;
|
||||
#endif
|
||||
panel->parent = parent;
|
||||
panel->type = type;
|
||||
|
||||
@ -3848,6 +4077,10 @@ int dsi_panel_drv_init(struct dsi_panel *panel,
|
||||
goto error_gpio_release;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
ss_panel_init(panel);
|
||||
#endif
|
||||
|
||||
goto exit;
|
||||
|
||||
error_gpio_release:
|
||||
@ -4208,6 +4441,9 @@ int dsi_panel_get_mode(struct dsi_panel *panel,
|
||||
int rc = 0, num_timings;
|
||||
int traffic_mode;
|
||||
void *utils_data = NULL;
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
struct samsung_display_driver_data *vdd;
|
||||
#endif
|
||||
|
||||
if (!panel || !mode) {
|
||||
DSI_ERR("invalid params\n");
|
||||
@ -4321,6 +4557,17 @@ int dsi_panel_get_mode(struct dsi_panel *panel,
|
||||
if (rc)
|
||||
DSI_ERR("failed to partial update caps, rc=%d\n", rc);
|
||||
}
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
vdd = panel->panel_private;
|
||||
vdd->num_of_intf = mode->priv_info->topology.num_intf;
|
||||
LCD_INFO_ONCE(vdd, "vdd->num_of_intf = %d\n", vdd->num_of_intf);
|
||||
if (mode->timing.qsync_min_fps) {
|
||||
LCD_INFO(vdd, "index(%d) : mdp_transfer_time_us(%d), qsync fs(%d)\n",
|
||||
index, mode->priv_info->mdp_transfer_time_us,
|
||||
mode->timing.qsync_min_fps);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
parse_fail:
|
||||
utils->data = utils_data;
|
||||
@ -4334,6 +4581,9 @@ int dsi_panel_get_host_cfg_for_mode(struct dsi_panel *panel,
|
||||
{
|
||||
int rc = 0;
|
||||
struct dsi_dyn_clk_caps *dyn_clk_caps = &panel->dyn_clk_caps;
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
struct samsung_display_driver_data *vdd;
|
||||
#endif
|
||||
|
||||
if (!panel || !mode || !config) {
|
||||
DSI_ERR("invalid params\n");
|
||||
@ -4370,6 +4620,12 @@ int dsi_panel_get_host_cfg_for_mode(struct dsi_panel *panel,
|
||||
config->bit_clk_rate_hz_override = mode->priv_info->clk_rate_hz;
|
||||
|
||||
config->esc_clk_rate_hz = 19200000;
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
vdd = panel->panel_private;
|
||||
if (vdd->dtsi_data.samsung_esc_clk_128M)
|
||||
config->esc_clk_rate_hz = 12800000;
|
||||
#endif
|
||||
|
||||
mutex_unlock(&panel->panel_lock);
|
||||
return rc;
|
||||
}
|
||||
@ -4406,6 +4662,11 @@ int dsi_panel_update_pps(struct dsi_panel *panel)
|
||||
struct dsi_panel_cmd_set *set = NULL;
|
||||
struct dsi_display_mode_priv_info *priv_info = NULL;
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
/* Do not use QC PPS -> add PPS cmds in on_seq */
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
if (!panel || !panel->cur_mode) {
|
||||
DSI_ERR("invalid params\n");
|
||||
return -EINVAL;
|
||||
@ -4475,6 +4736,9 @@ int dsi_panel_set_lp1(struct dsi_panel *panel)
|
||||
if (rc)
|
||||
DSI_ERR("[%s] failed to send DSI_CMD_SET_LP1 cmd, rc=%d\n",
|
||||
panel->name, rc);
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
ss_panel_low_power_config(panel->panel_private, true);
|
||||
#endif
|
||||
exit:
|
||||
mutex_unlock(&panel->panel_lock);
|
||||
return rc;
|
||||
@ -4497,6 +4761,9 @@ int dsi_panel_set_lp2(struct dsi_panel *panel)
|
||||
if (rc)
|
||||
DSI_ERR("[%s] failed to send DSI_CMD_SET_LP2 cmd, rc=%d\n",
|
||||
panel->name, rc);
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
ss_panel_low_power_config(panel->panel_private, true);
|
||||
#endif
|
||||
exit:
|
||||
mutex_unlock(&panel->panel_lock);
|
||||
return rc;
|
||||
@ -4527,6 +4794,9 @@ int dsi_panel_set_nolp(struct dsi_panel *panel)
|
||||
if (rc)
|
||||
DSI_ERR("[%s] failed to send DSI_CMD_SET_NOLP cmd, rc=%d\n",
|
||||
panel->name, rc);
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
ss_panel_low_power_config(panel->panel_private, false);
|
||||
#endif
|
||||
exit:
|
||||
mutex_unlock(&panel->panel_lock);
|
||||
return rc;
|
||||
@ -4543,6 +4813,10 @@ int dsi_panel_prepare(struct dsi_panel *panel)
|
||||
|
||||
mutex_lock(&panel->panel_lock);
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
ss_panel_power_on_post_lp11(panel->panel_private);
|
||||
#endif
|
||||
|
||||
if (panel->lp11_init) {
|
||||
rc = dsi_panel_power_on(panel);
|
||||
if (rc) {
|
||||
@ -4644,6 +4918,9 @@ int dsi_panel_send_qsync_on_dcs(struct dsi_panel *panel,
|
||||
int ctrl_idx)
|
||||
{
|
||||
int rc = 0;
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
struct samsung_display_driver_data *vdd;
|
||||
#endif
|
||||
|
||||
if (!panel) {
|
||||
DSI_ERR("invalid params\n");
|
||||
@ -4652,11 +4929,24 @@ int dsi_panel_send_qsync_on_dcs(struct dsi_panel *panel,
|
||||
|
||||
mutex_lock(&panel->panel_lock);
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
DSI_INFO("ctrl:%d qsync on\n", ctrl_idx);
|
||||
vdd = panel->panel_private;
|
||||
if (vdd) {
|
||||
if (!SS_IS_CMDS_NULL(ss_get_cmds(vdd, TX_EARLY_TE))) {
|
||||
vdd->early_te = true;
|
||||
vdd->check_early_te = CHECK_EARLY_TE_COUNT;
|
||||
if (vdd->panel_state != PANEL_PWR_LPM)
|
||||
ss_send_cmd(vdd, TX_EARLY_TE);
|
||||
}
|
||||
}
|
||||
#else
|
||||
DSI_DEBUG("ctrl:%d qsync on\n", ctrl_idx);
|
||||
rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_QSYNC_ON);
|
||||
if (rc)
|
||||
DSI_ERR("[%s] failed to send DSI_CMD_SET_QSYNC_ON cmds rc=%d\n",
|
||||
panel->name, rc);
|
||||
#endif
|
||||
|
||||
mutex_unlock(&panel->panel_lock);
|
||||
return rc;
|
||||
@ -4666,6 +4956,9 @@ int dsi_panel_send_qsync_off_dcs(struct dsi_panel *panel,
|
||||
int ctrl_idx)
|
||||
{
|
||||
int rc = 0;
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
struct samsung_display_driver_data *vdd;
|
||||
#endif
|
||||
|
||||
if (!panel) {
|
||||
DSI_ERR("invalid params\n");
|
||||
@ -4674,11 +4967,24 @@ int dsi_panel_send_qsync_off_dcs(struct dsi_panel *panel,
|
||||
|
||||
mutex_lock(&panel->panel_lock);
|
||||
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
DSI_INFO("ctrl:%d qsync off\n", ctrl_idx);
|
||||
vdd = panel->panel_private;
|
||||
if (vdd) {
|
||||
if (!SS_IS_CMDS_NULL(ss_get_cmds(vdd, TX_EARLY_TE))) {
|
||||
vdd->early_te = false;
|
||||
if (vdd->panel_state != PANEL_PWR_LPM)
|
||||
ss_send_cmd(vdd, TX_EARLY_TE);
|
||||
}
|
||||
}
|
||||
#else
|
||||
DSI_DEBUG("ctrl:%d qsync off\n", ctrl_idx);
|
||||
rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_QSYNC_OFF);
|
||||
if (rc)
|
||||
DSI_ERR("[%s] failed to send DSI_CMD_SET_QSYNC_OFF cmds rc=%d\n",
|
||||
panel->name, rc);
|
||||
#endif
|
||||
|
||||
mutex_unlock(&panel->panel_lock);
|
||||
return rc;
|
||||
@ -4813,6 +5119,35 @@ int dsi_panel_switch(struct dsi_panel *panel)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
if (panel->panel_private) {
|
||||
struct samsung_display_driver_data *vdd = panel->panel_private;
|
||||
|
||||
if (vdd->vrr.support_vrr_based_bl) {
|
||||
/* Sometimes, GFX HAL sends DMS that inlcudes multi resolution and VRR,
|
||||
* at one DMS commands. So, always handler DMS here.
|
||||
*/
|
||||
ss_panel_dms_switch(vdd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* In QCT original VRR mode, below variables is meaningless..
|
||||
* But, to keep latest information for debugging,
|
||||
* update current vrr variables.
|
||||
*/
|
||||
vdd->vrr.cur_refresh_rate = vdd->vrr.adjusted_refresh_rate;
|
||||
vdd->vrr.cur_sot_hs_mode = vdd->vrr.adjusted_sot_hs_mode;
|
||||
vdd->vrr.cur_phs_mode = vdd->vrr.adjusted_phs_mode;
|
||||
vdd->vrr.cur_h_active = vdd->vrr.adjusted_h_active;
|
||||
vdd->vrr.cur_v_active = vdd->vrr.adjusted_v_active;
|
||||
|
||||
/* Do we have to change param only when the HS<->NORMAL be changed?
|
||||
* No problem to notify VRR change in panel not supporting VRR?
|
||||
*/
|
||||
ss_set_vrr_switch(vdd, true);
|
||||
}
|
||||
#endif
|
||||
|
||||
mutex_lock(&panel->panel_lock);
|
||||
|
||||
rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_TIMING_SWITCH);
|
||||
@ -4821,6 +5156,11 @@ int dsi_panel_switch(struct dsi_panel *panel)
|
||||
panel->name, rc);
|
||||
|
||||
mutex_unlock(&panel->panel_lock);
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
ss_send_cmd(panel->panel_private, TX_TIMING_SWITCH);
|
||||
#endif
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -4880,6 +5220,9 @@ int dsi_panel_enable(struct dsi_panel *panel)
|
||||
panel->panel_initialized = true;
|
||||
|
||||
error:
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
ss_panel_on(panel->panel_private);
|
||||
#endif
|
||||
mutex_unlock(&panel->panel_lock);
|
||||
return rc;
|
||||
}
|
||||
@ -4920,6 +5263,10 @@ int dsi_panel_pre_disable(struct dsi_panel *panel)
|
||||
if (gpio_is_valid(panel->bl_config.en_gpio))
|
||||
gpio_set_value(panel->bl_config.en_gpio, 0);
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
ss_panel_off_pre(panel->panel_private);
|
||||
#endif
|
||||
|
||||
rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_PRE_OFF);
|
||||
if (rc) {
|
||||
DSI_ERR("[%s] failed to send DSI_CMD_SET_PRE_OFF cmds, rc=%d\n",
|
||||
@ -4935,14 +5282,28 @@ error:
|
||||
int dsi_panel_disable(struct dsi_panel *panel)
|
||||
{
|
||||
int rc = 0;
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
struct samsung_display_driver_data *vdd;
|
||||
#endif
|
||||
|
||||
if (!panel) {
|
||||
DSI_ERR("invalid params\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
vdd = panel->panel_private;
|
||||
LCD_INFO(vdd, "++\n");
|
||||
#endif
|
||||
mutex_lock(&panel->panel_lock);
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
if (!ss_panel_attach_get(panel->panel_private)) {
|
||||
LCD_INFO(vdd, "PBA booting, skip to disable panel\n");
|
||||
goto skip_cmd_tx;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Avoid sending panel off commands when ESD recovery is underway */
|
||||
if (!atomic_read(&panel->esd_recovery_pending)) {
|
||||
/*
|
||||
@ -4967,10 +5328,18 @@ int dsi_panel_disable(struct dsi_panel *panel)
|
||||
rc = 0;
|
||||
}
|
||||
}
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
skip_cmd_tx:
|
||||
ss_panel_off_post(panel->panel_private);
|
||||
#endif
|
||||
|
||||
panel->panel_initialized = false;
|
||||
panel->power_mode = SDE_MODE_DPMS_OFF;
|
||||
|
||||
mutex_unlock(&panel->panel_lock);
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
LCD_INFO(vdd, "--\n");
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -4993,6 +5362,11 @@ int dsi_panel_unprepare(struct dsi_panel *panel)
|
||||
}
|
||||
|
||||
error:
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
ss_panel_power_off_pre_lp11(panel->panel_private);
|
||||
#endif
|
||||
|
||||
mutex_unlock(&panel->panel_lock);
|
||||
return rc;
|
||||
}
|
||||
|
@ -177,6 +177,9 @@ enum esd_check_status_mode {
|
||||
ESD_MODE_PANEL_TE,
|
||||
ESD_MODE_SW_SIM_SUCCESS,
|
||||
ESD_MODE_SW_SIM_FAILURE,
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
ESD_MODE_PANEL_IRQ,
|
||||
#endif
|
||||
ESD_MODE_MAX
|
||||
};
|
||||
|
||||
@ -275,6 +278,14 @@ struct dsi_panel {
|
||||
enum dsi_panel_physical_type panel_type;
|
||||
|
||||
struct dsi_panel_ops panel_ops;
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
void *panel_private;
|
||||
struct device_node *self_display_of_node;
|
||||
struct dsi_parser_utils self_display_utils;
|
||||
struct device_node *mafpc_of_node;
|
||||
struct dsi_parser_utils mafpc_utils;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
static inline bool dsi_panel_ulps_feature_enabled(struct dsi_panel *panel)
|
||||
@ -411,4 +422,12 @@ int dsi_panel_create_cmd_packets(const char *data, u32 length, u32 count,
|
||||
void dsi_panel_destroy_cmd_packets(struct dsi_panel_cmd_set *set);
|
||||
|
||||
void dsi_panel_dealloc_cmd_packets(struct dsi_panel_cmd_set *set);
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
#define SS_CMD_PROP_STR_LEN (100)
|
||||
|
||||
int dsi_panel_set_pinctrl_state(struct dsi_panel *panel, bool enable);
|
||||
int dsi_panel_tx_cmd_set(struct dsi_panel *panel, int type);
|
||||
#endif
|
||||
|
||||
#endif /* _DSI_PANEL_H_ */
|
||||
|
@ -1444,6 +1444,42 @@ void dsi_phy_set_continuous_clk(struct msm_dsi_phy *phy, bool enable)
|
||||
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
void dsi_phy_store_str(struct msm_dsi_phy *phy, u32 *val)
|
||||
{
|
||||
if (phy->hw.ops.store_str)
|
||||
phy->hw.ops.store_str(&phy->hw, val);
|
||||
}
|
||||
u32 dsi_phy_show_str(struct msm_dsi_phy *phy)
|
||||
{
|
||||
u32 ret = 0;
|
||||
|
||||
if (phy->hw.ops.show_str)
|
||||
ret = phy->hw.ops.show_str(&phy->hw);
|
||||
|
||||
return ret;
|
||||
}
|
||||
void dsi_phy_store_vreg(struct msm_dsi_phy *phy, u32 *val)
|
||||
{
|
||||
if (phy->hw.ops.store_vreg)
|
||||
phy->hw.ops.store_vreg(&phy->hw, val);
|
||||
}
|
||||
u32 dsi_phy_show_vreg(struct msm_dsi_phy *phy)
|
||||
{
|
||||
u32 ret = 0;
|
||||
|
||||
if (phy->hw.ops.show_vreg)
|
||||
ret = phy->hw.ops.show_vreg(&phy->hw);
|
||||
|
||||
return ret;
|
||||
}
|
||||
void dsi_phy_store_emphasis(struct msm_dsi_phy *phy, u32 *val)
|
||||
{
|
||||
if (phy->hw.ops.store_emphasis)
|
||||
phy->hw.ops.store_emphasis(&phy->hw, val);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* dsi_phy_pll_parse_dfps_data() - parse dfps data for PLL
|
||||
* @phy: DSI PHY handle
|
||||
|
@ -419,4 +419,13 @@ int dsi_phy_dynclk_configure(struct msm_dsi_phy *phy);
|
||||
* @phy: DSI PHY handle
|
||||
*/
|
||||
void dsi_phy_pll_parse_dfps_data(struct msm_dsi_phy *phy);
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
void dsi_phy_store_str(struct msm_dsi_phy *phy, u32 *val);
|
||||
u32 dsi_phy_show_str(struct msm_dsi_phy *phy);
|
||||
void dsi_phy_store_vreg(struct msm_dsi_phy *phy, u32 *val);
|
||||
u32 dsi_phy_show_vreg(struct msm_dsi_phy *phy);
|
||||
void dsi_phy_store_emphasis(struct msm_dsi_phy *phy, u32 *val);
|
||||
#endif
|
||||
|
||||
#endif /* _DSI_PHY_H_ */
|
||||
|
@ -385,6 +385,13 @@ struct dsi_phy_hw_ops {
|
||||
*/
|
||||
int (*pll_toggle)(void *pll, bool prepare);
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
void (*store_str)(struct dsi_phy_hw *phy, u32 *val);
|
||||
u32 (*show_str)(struct dsi_phy_hw *phy);
|
||||
void (*store_vreg)(struct dsi_phy_hw *phy, u32 *val);
|
||||
u32 (*show_vreg)(struct dsi_phy_hw *phy);
|
||||
void (*store_emphasis)(struct dsi_phy_hw *phy, u32 *val);
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
@ -413,6 +420,10 @@ struct dsi_phy_hw {
|
||||
|
||||
DECLARE_BITMAP(feature_map, DSI_PHY_MAX_FEATURES);
|
||||
struct dsi_phy_hw_ops ops;
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
int display_index; /* primary display or secondary display */
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -12,6 +12,10 @@
|
||||
#include "dsi_phy_hw.h"
|
||||
#include "dsi_catalog.h"
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
#include "ss_dsi_panel_common.h"
|
||||
#endif
|
||||
|
||||
#define DSIPHY_CMN_REVISION_ID0 0x000
|
||||
#define DSIPHY_CMN_REVISION_ID1 0x004
|
||||
#define DSIPHY_CMN_REVISION_ID2 0x008
|
||||
@ -229,6 +233,118 @@ void dsi_phy_hw_v5_0_commit_phy_timing(struct dsi_phy_hw *phy,
|
||||
DSI_W32(phy, DSIPHY_CMN_TIMING_CTRL_13, timing->lane_v4[13]);
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
/* To store driving streng for Motto tool */
|
||||
void dsi_phy_hw_v5_0_store_str(struct dsi_phy_hw *phy, u32 *val)
|
||||
{
|
||||
u32 hstx_str = 0;
|
||||
u32 cal_sel = 0;
|
||||
|
||||
/* The register setting range is from 'b0000 (weakest) to 'b1111 (strongest). */
|
||||
DSI_PHY_INFO(phy, "base : 0x%X, val : 0x%X\n", phy->base, *val);
|
||||
DSI_W32(phy, DSIPHY_CMN_GLBL_HSTX_STR_CTRL_0, *val);
|
||||
hstx_str = DSI_R32(phy, DSIPHY_CMN_GLBL_HSTX_STR_CTRL_0);
|
||||
|
||||
/* DSIPHY_CMN_GLBL_STR_SWI_CAL_SEL_CTRL[0] needs to be set to bit1
|
||||
* to select strength override value from DSIPHY_CMN_GLBL_HSTX_STR_CTRL_0.
|
||||
*/
|
||||
cal_sel = DSI_R32(phy, DSIPHY_CMN_GLBL_STR_SWI_CAL_SEL_CTRL);
|
||||
cal_sel |= BIT(0);
|
||||
DSI_W32(phy, DSIPHY_CMN_GLBL_STR_SWI_CAL_SEL_CTRL, cal_sel);
|
||||
|
||||
DSI_PHY_INFO(phy, "applied hstx : 0x%X, cal_sel : 0x%X\n", hstx_str, cal_sel);
|
||||
}
|
||||
|
||||
u32 dsi_phy_hw_v5_0_show_str(struct dsi_phy_hw *phy)
|
||||
{
|
||||
u32 hstx_str = 0;
|
||||
|
||||
hstx_str = DSI_R32(phy, DSIPHY_CMN_GLBL_HSTX_STR_CTRL_0);
|
||||
DSI_PHY_INFO(phy, "cur base : 0x%X, hstx_str : 0x%X (0x00 ~ 0xFF)\n", phy->base, hstx_str);
|
||||
|
||||
return hstx_str;
|
||||
}
|
||||
|
||||
/* CMN_VREG_CTRL_0[1:0]: For D-PHY, it adjusts the Tx DC level of Vhigh and Vlow -> cotrol whole */
|
||||
void dsi_phy_hw_v5_0_store_vreg(struct dsi_phy_hw *phy, u32 *val)
|
||||
{
|
||||
u32 vreg_ctrl_0_rd, vreg_ctrl_0_str;
|
||||
|
||||
vreg_ctrl_0_rd = DSI_R32(phy, DSIPHY_CMN_VREG_CTRL_0); // | BIT(2) | BIT(5);
|
||||
vreg_ctrl_0_str = *val;
|
||||
DSI_PHY_INFO(phy, "base : 0x%X, val:0x%X, vreg_ctrl_0:0x%X->0x%X\n",
|
||||
phy->base, *val, vreg_ctrl_0_rd, vreg_ctrl_0_str);
|
||||
DSI_W32(phy, DSIPHY_CMN_VREG_CTRL_0, vreg_ctrl_0_str);
|
||||
}
|
||||
|
||||
/* CMN_VREG_CTRL_0[1:0]: For D-PHY, it adjusts the Tx DC level of Vhigh and Vlow -> whole control */
|
||||
u32 dsi_phy_hw_v5_0_show_vreg(struct dsi_phy_hw *phy)
|
||||
{
|
||||
u32 val = 0;
|
||||
|
||||
val = DSI_R32(phy, DSIPHY_CMN_VREG_CTRL_0);
|
||||
DSI_PHY_INFO(phy, "cur base : 0x%X, vreg_ctrl_0 : 0x%02X \n", phy->base, val);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/* To store de-emphasis adjusted for Motto tool */
|
||||
void dsi_phy_hw_v5_0_store_emphasis(struct dsi_phy_hw *phy, u32 *val)
|
||||
{
|
||||
u32 cal_sel = 0;
|
||||
u32 cmn_ctrl_2 = 0;
|
||||
u32 read[2];
|
||||
struct samsung_display_driver_data *vdd = ss_get_vdd(phy->index);
|
||||
|
||||
DSI_PHY_INFO(phy, "val:0x%x (ndx:%x)\n", *val, phy->index);
|
||||
|
||||
if ((!vdd->motto_info.motto_emphasis) && (!vdd->motto_info.init_backup)) {
|
||||
/* backup default data */
|
||||
vdd->motto_info.cal_sel_init =
|
||||
DSI_R32(phy, DSIPHY_CMN_GLBL_STR_SWI_CAL_SEL_CTRL);
|
||||
vdd->motto_info.cmn_ctrl2_init = DSI_R32(phy, DSIPHY_CMN_CTRL_2);
|
||||
|
||||
DSI_PHY_INFO(phy, "backup sel:%x(0), cmn:%x(40)\n",
|
||||
vdd->motto_info.cal_sel_init, vdd->motto_info.cmn_ctrl2_init);
|
||||
vdd->motto_info.init_backup = true;
|
||||
}
|
||||
|
||||
/* Common for both DSI_PHY_VERSION_4_0~4_3 */
|
||||
cal_sel = DSI_R32(phy, DSIPHY_CMN_GLBL_STR_SWI_CAL_SEL_CTRL);
|
||||
if (*val == 0x01) {
|
||||
/* Use DSIPHY_CMN_CTRL_2 to enable de-emphasis, by asserting bit[2] and bit[5].
|
||||
* To use precalibrated values,adjust DSIPHY_CMN_GLBL_STR_SWI_CAL_SEL_CTRL bit[2]
|
||||
* to change between low (bit0) and high (bit1) EQ.
|
||||
*/
|
||||
/* cmn_ctrl_2 : assert [2],[5] */
|
||||
cmn_ctrl_2 = vdd->motto_info.cmn_ctrl2_init | BIT(2) | BIT(5);
|
||||
/* cal_sel : assert [2] */
|
||||
cal_sel |= BIT(2);
|
||||
} else if (*val == 0) { /* restore init(set 0) value */
|
||||
if (!vdd->motto_info.init_backup) {
|
||||
DSI_PHY_ERR(phy, "no init backed up.\n");
|
||||
} else {
|
||||
cmn_ctrl_2 = vdd->motto_info.cmn_ctrl2_init;
|
||||
cal_sel &= ~(BIT(2) | BIT(5));
|
||||
}
|
||||
vdd->motto_info.init_backup = false;
|
||||
DSI_PHY_INFO(phy, "restore cmn_ctrl2:%x, cal_sel:%x\n", cmn_ctrl_2, cal_sel);
|
||||
} else
|
||||
DSI_PHY_ERR(phy, "invalid val:%x\n", *val);
|
||||
|
||||
DSI_W32(phy, DSIPHY_CMN_GLBL_STR_SWI_CAL_SEL_CTRL, cal_sel);
|
||||
DSI_W32(phy, DSIPHY_CMN_CTRL_2, cmn_ctrl_2);
|
||||
|
||||
read[0] = DSI_R32(phy, DSIPHY_CMN_GLBL_STR_SWI_CAL_SEL_CTRL);
|
||||
read[1] = DSI_R32(phy, DSIPHY_CMN_CTRL_2);
|
||||
DSI_PHY_INFO(phy, "applied sel:%x, cmn:%x\n", read[0], read[1]);
|
||||
|
||||
/* store curr to use enable fc if modified */
|
||||
vdd->motto_info.cal_sel_curr = read[0];
|
||||
vdd->motto_info.cmn_ctrl2_curr = read[1];
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* calc_cmn_lane_ctrl0() - Calculate the value to be set for
|
||||
* DSIPHY_CMN_LANE_CTRL0 register.
|
||||
@ -293,6 +409,64 @@ static void dsi_phy_hw_cphy_enable(struct dsi_phy_hw *phy, struct dsi_phy_cfg *c
|
||||
DSI_W32(phy, DSIPHY_CMN_GLBL_RESCODE_OFFSET_BOT_CTRL, 0x00);
|
||||
DSI_W32(phy, DSIPHY_CMN_GLBL_LPTX_STR_CTRL, 0x55);
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
if (phy->version == DSI_PHY_VERSION_4_1) {
|
||||
struct samsung_display_driver_data *vdd;
|
||||
|
||||
if (phy->display_index == PRIMARY_DISPLAY_NDX)
|
||||
vdd = ss_get_vdd(PRIMARY_DISPLAY_NDX);
|
||||
else
|
||||
vdd = ss_get_vdd(SECONDARY_DISPLAY_NDX);
|
||||
|
||||
if (test_bit(SS_PHY_CMN_VREG_CTRL_0, vdd->ss_phy_ctrl_bit)) {
|
||||
DSI_W32(phy, DSIPHY_CMN_VREG_CTRL_0,
|
||||
vdd->ss_phy_ctrl_data[SS_PHY_CMN_VREG_CTRL_0]);
|
||||
|
||||
LCD_DEBUG(vdd, "DSIPHY_CMN_VREG_CTRL_0 : 0x%x\n", DSI_R32(phy, DSIPHY_CMN_VREG_CTRL_0));
|
||||
}
|
||||
|
||||
if (test_bit(SS_PHY_CMN_CTRL_2, vdd->ss_phy_ctrl_bit)) {
|
||||
DSI_W32(phy, DSIPHY_CMN_CTRL_2,
|
||||
vdd->ss_phy_ctrl_data[SS_PHY_CMN_CTRL_2]);
|
||||
|
||||
LCD_DEBUG(vdd, "DSIPHY_CMN_CTRL_2 : 0x%x\n", DSI_R32(phy, DSIPHY_CMN_CTRL_2));
|
||||
}
|
||||
|
||||
if (test_bit(SS_PHY_CMN_GLBL_RESCODE_OFFSET_TOP_CTRL, vdd->ss_phy_ctrl_bit)) {
|
||||
DSI_W32(phy, DSIPHY_CMN_GLBL_RESCODE_OFFSET_TOP_CTRL,
|
||||
vdd->ss_phy_ctrl_data[SS_PHY_CMN_GLBL_RESCODE_OFFSET_TOP_CTRL]);
|
||||
|
||||
LCD_DEBUG(vdd, "DSIPHY_CMN_GLBL_RESCODE_OFFSET_TOP_CTRL : 0x%x\n",
|
||||
DSI_R32(phy, DSIPHY_CMN_GLBL_RESCODE_OFFSET_TOP_CTRL));
|
||||
}
|
||||
|
||||
if (test_bit(SS_PHY_CMN_GLBL_RESCODE_OFFSET_BOT_CTRL, vdd->ss_phy_ctrl_bit)) {
|
||||
DSI_W32(phy, DSIPHY_CMN_GLBL_RESCODE_OFFSET_BOT_CTRL,
|
||||
vdd->ss_phy_ctrl_data[SS_PHY_CMN_GLBL_RESCODE_OFFSET_BOT_CTRL]);
|
||||
|
||||
LCD_DEBUG(vdd, "DSIPHY_CMN_GLBL_RESCODE_OFFSET_BOT_CTRL : 0x%x\n",
|
||||
DSI_R32(phy, DSIPHY_CMN_GLBL_RESCODE_OFFSET_BOT_CTRL));
|
||||
}
|
||||
|
||||
if (test_bit(SS_PHY_CMN_GLBL_RESCODE_OFFSET_MID_CTRL, vdd->ss_phy_ctrl_bit)) {
|
||||
DSI_W32(phy, DSIPHY_CMN_GLBL_RESCODE_OFFSET_MID_CTRL,
|
||||
vdd->ss_phy_ctrl_data[SS_PHY_CMN_GLBL_RESCODE_OFFSET_MID_CTRL]);
|
||||
|
||||
LCD_DEBUG(vdd, "DSIPHY_CMN_GLBL_RESCODE_OFFSET_MID_CTRL : 0x%x\n",
|
||||
DSI_R32(phy, DSIPHY_CMN_GLBL_RESCODE_OFFSET_MID_CTRL));
|
||||
}
|
||||
|
||||
if (test_bit(SS_PHY_CMN_GLBL_STR_SWI_CAL_SEL_CTRL, vdd->ss_phy_ctrl_bit)) {
|
||||
DSI_W32(phy, DSIPHY_CMN_GLBL_STR_SWI_CAL_SEL_CTRL,
|
||||
vdd->ss_phy_ctrl_data[SS_PHY_CMN_GLBL_STR_SWI_CAL_SEL_CTRL]);
|
||||
|
||||
LCD_DEBUG(vdd, "DSIPHY_CMN_GLBL_STR_SWI_CAL_SEL_CTRL : 0x%x\n",
|
||||
DSI_R32(phy, DSIPHY_CMN_GLBL_STR_SWI_CAL_SEL_CTRL));
|
||||
}
|
||||
}
|
||||
//TODO Add 4_3 version (5)
|
||||
#endif
|
||||
|
||||
/* Remove power down from all blocks */
|
||||
DSI_W32(phy, DSIPHY_CMN_CTRL_0, 0x7f);
|
||||
|
||||
@ -348,6 +522,16 @@ static void dsi_phy_hw_dphy_enable(struct dsi_phy_hw *phy, struct dsi_phy_cfg *c
|
||||
bool split_link_enabled;
|
||||
u32 lanes_per_sublink;
|
||||
u32 cmn_lane_ctrl0 = 0;
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
struct samsung_display_driver_data *vdd = ss_get_vdd(phy->display_index);
|
||||
if (!vdd) {
|
||||
LCD_ERR(vdd, "inavlid vdd idx %d\n", phy->display_index);
|
||||
return ;
|
||||
}
|
||||
|
||||
LCD_INFO_ONCE(vdd, "PHY_%d (%X), display_index:%d ver : %d, bit_clk : %d\n",
|
||||
phy->index, phy->base, phy->display_index , phy->version, cfg->bit_clk_rate_hz);
|
||||
#endif
|
||||
|
||||
/* Alter PHY configurations if data rate less than 1.5GHZ*/
|
||||
if (cfg->bit_clk_rate_hz <= 1500000000)
|
||||
@ -359,6 +543,28 @@ static void dsi_phy_hw_dphy_enable(struct dsi_phy_hw *phy, struct dsi_phy_cfg *c
|
||||
glbl_str_swi_cal_sel_ctrl = 0x00;
|
||||
glbl_hstx_str_ctrl_0 = 0x88;
|
||||
|
||||
/* SM8550 TODO:Compare with 8650 phy tune guide */
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
/* Set if Motto values had set */
|
||||
if (vdd->motto_info.motto_swing) {
|
||||
glbl_hstx_str_ctrl_0 = vdd->motto_info.motto_swing;
|
||||
/* DSIPHY_CMN_GLBL_STR_SWI_CAL_SEL_CTRL[0] needs to be set to 'b1
|
||||
* to select strength override value from DSIPHY_CMN_GLBL_HSTX_STR_CTRL_0.
|
||||
*/
|
||||
glbl_str_swi_cal_sel_ctrl |= 0x01;
|
||||
LCD_INFO_ONCE(vdd, "motto_swing : 0x%X, cal_sel : %X\n",
|
||||
vdd->motto_info.motto_swing, glbl_str_swi_cal_sel_ctrl);
|
||||
}
|
||||
|
||||
if (vdd->motto_info.motto_emphasis) {
|
||||
/* To use precalibrated values,adjust DSIPHY_CMN_GLBL_STR_SWI_CAL_SEL_CTRL bit[2]
|
||||
* to change between low (bit0) and high (bit1) EQ.
|
||||
*/
|
||||
glbl_str_swi_cal_sel_ctrl |= BIT(2);
|
||||
LCD_INFO_ONCE(vdd, "motto_emphasis cmn_ctrl2 : 0x%X cal_sel : %X\n",
|
||||
vdd->motto_info.cmn_ctrl2_curr, glbl_str_swi_cal_sel_ctrl);
|
||||
}
|
||||
#endif
|
||||
|
||||
split_link_enabled = cfg->split_link.enabled;
|
||||
lanes_per_sublink = cfg->split_link.lanes_per_sublink;
|
||||
@ -383,6 +589,15 @@ static void dsi_phy_hw_dphy_enable(struct dsi_phy_hw *phy, struct dsi_phy_cfg *c
|
||||
/* Configure PHY lane swap */
|
||||
dsi_phy_hw_v5_0_lane_swap_config(phy, &cfg->lane_map);
|
||||
|
||||
/* SM8550 TODO:Compare with 8650 phy tune guide */
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
/* CMN_VREG_CTRL_0[1:0]: For D-PHY */
|
||||
if (vdd->motto_info.vreg_ctrl_0) {
|
||||
LCD_INFO_ONCE(vdd, "vreg_ctrl_0 : 0x%02X -> 0x%02X\n", vreg_ctrl_0, vdd->motto_info.vreg_ctrl_0);
|
||||
vreg_ctrl_0 = vdd->motto_info.vreg_ctrl_0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Enable LDO */
|
||||
DSI_W32(phy, DSIPHY_CMN_VREG_CTRL_0, vreg_ctrl_0);
|
||||
DSI_W32(phy, DSIPHY_CMN_VREG_CTRL_1, 0x19);
|
||||
@ -416,8 +631,18 @@ static void dsi_phy_hw_dphy_enable(struct dsi_phy_hw *phy, struct dsi_phy_cfg *c
|
||||
DSI_W32(phy, DSIPHY_CMN_LANE_CTRL0, cmn_lane_ctrl0);
|
||||
}
|
||||
|
||||
/* SM8550 TODO:Compare with 8650 phy tune guide */
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
/* Set if Motto values had set */
|
||||
if (vdd->motto_info.motto_emphasis) {
|
||||
DSI_W32(phy, DSIPHY_CMN_CTRL_2, vdd->motto_info.cmn_ctrl2_curr);
|
||||
} else
|
||||
/* Select full-rate mode */
|
||||
DSI_W32(phy, DSIPHY_CMN_CTRL_2, 0x40);
|
||||
#else
|
||||
/* Select full-rate mode */
|
||||
DSI_W32(phy, DSIPHY_CMN_CTRL_2, 0x40);
|
||||
#endif
|
||||
|
||||
switch (cfg->pll_source) {
|
||||
case DSI_PLL_SOURCE_STANDALONE:
|
||||
|
@ -206,6 +206,10 @@ static void dsi_pll_config_slave(struct dsi_pll_resource *rsc)
|
||||
rsc->slave ? "configured" : "absent");
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
extern int vdd_pll_ssc_disabled;
|
||||
#endif
|
||||
|
||||
static void dsi_pll_setup_config(struct dsi_pll_4nm *pll, struct dsi_pll_resource *rsc)
|
||||
{
|
||||
struct dsi_pll_config *config = &pll->pll_configuration;
|
||||
@ -233,6 +237,13 @@ static void dsi_pll_setup_config(struct dsi_pll_4nm *pll, struct dsi_pll_resourc
|
||||
if (rsc->ssc_ppm)
|
||||
config->ssc_offset = rsc->ssc_ppm;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
if (vdd_pll_ssc_disabled) {
|
||||
pr_err_once("[5nm] disable pll ssc %d\n", vdd_pll_ssc_disabled);
|
||||
config->enable_ssc = false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void dsi_pll_calc_dec_frac(struct dsi_pll_4nm *pll, struct dsi_pll_resource *rsc)
|
||||
|
@ -29,6 +29,10 @@
|
||||
#include <linux/dma-fence-chain.h>
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
#include "ss_dsi_panel_common.h"
|
||||
#endif
|
||||
|
||||
#define MULTIPLE_CONN_DETECTED(x) (x > 1)
|
||||
|
||||
struct msm_commit {
|
||||
@ -251,6 +255,23 @@ msm_disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
|
||||
else
|
||||
funcs->dpms(encoder, DRM_MODE_DPMS_OFF);
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
{
|
||||
/*
|
||||
notify registered clients about suspend event
|
||||
This noti is triggered before panel power off & DSI_CMD_SET_OFF.
|
||||
*/
|
||||
int blank = FB_BLANK_POWERDOWN;
|
||||
|
||||
if (encoder->encoder_type == DRM_MODE_ENCODER_DSI &&
|
||||
(connector->state->crtc &&
|
||||
connector->state->crtc->state->active_changed))
|
||||
__msm_drm_notifier_call_chain(FB_EVENT_BLANK, &blank);
|
||||
else
|
||||
pr_debug("%s %d\n", __func__, encoder->encoder_type);
|
||||
}
|
||||
#endif
|
||||
|
||||
drm_bridge_chain_post_disable(bridge);
|
||||
}
|
||||
|
||||
@ -494,6 +515,24 @@ static void msm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
|
||||
funcs->enable(encoder);
|
||||
else
|
||||
funcs->commit(encoder);
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
{
|
||||
/*
|
||||
notify registered clients about resume event.
|
||||
This noti is triggered after panel power on & DSI_CMD_SET_ON.
|
||||
*/
|
||||
int blank = FB_BLANK_UNBLANK;
|
||||
|
||||
/* notify only in case state is changed (off -> on) */
|
||||
if (encoder->encoder_type == DRM_MODE_ENCODER_DSI &&
|
||||
(connector->state->crtc &&
|
||||
connector->state->crtc->state->active_changed))
|
||||
__msm_drm_notifier_call_chain(FB_EVENT_BLANK, &blank);
|
||||
else
|
||||
pr_debug("%s %d\n", __func__, encoder->encoder_type);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (kms && kms->funcs && kms->funcs->commit) {
|
||||
@ -613,6 +652,10 @@ int msm_atomic_prepare_fb(struct drm_plane *plane,
|
||||
return msm_framebuffer_prepare(new_state->fb, kms->aspace);
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
int ss_get_vdd_ndx_from_state(struct drm_atomic_state *old_state);
|
||||
#endif
|
||||
|
||||
/* The (potentially) asynchronous part of the commit. At this point
|
||||
* nothing can fail short of armageddon.
|
||||
*/
|
||||
@ -622,6 +665,10 @@ static void complete_commit(struct msm_commit *c)
|
||||
struct drm_device *dev = state->dev;
|
||||
struct msm_drm_private *priv = dev->dev_private;
|
||||
struct msm_kms *kms = priv->kms;
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
int ndx;
|
||||
struct samsung_display_driver_data *vdd;
|
||||
#endif
|
||||
|
||||
drm_atomic_helper_wait_for_fences(dev, state, false);
|
||||
|
||||
@ -649,6 +696,13 @@ static void complete_commit(struct msm_commit *c)
|
||||
|
||||
msm_atomic_wait_for_commit_done(dev, state);
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
ndx = ss_get_vdd_ndx_from_state(state);
|
||||
vdd = ss_get_vdd(ndx);
|
||||
if (vdd)
|
||||
ss_event_frame_update_post(vdd);
|
||||
#endif
|
||||
|
||||
drm_atomic_helper_cleanup_planes(dev, state);
|
||||
|
||||
kms->funcs->complete_commit(kms, state);
|
||||
@ -778,12 +832,23 @@ int msm_atomic_commit(struct drm_device *dev,
|
||||
struct drm_plane *plane;
|
||||
struct drm_plane_state *old_plane_state, *new_plane_state;
|
||||
int i, ret;
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
struct samsung_display_driver_data *vdd;
|
||||
int ndx;
|
||||
#endif
|
||||
|
||||
if (!priv || priv->shutdown_in_progress) {
|
||||
DRM_ERROR("priv is null or shutdwon is in-progress\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
ndx = ss_get_vdd_ndx_from_state(state);
|
||||
vdd = ss_get_vdd(ndx);
|
||||
if (vdd)
|
||||
ss_event_frame_update_pre(vdd);
|
||||
#endif
|
||||
|
||||
SDE_ATRACE_BEGIN("atomic_commit");
|
||||
ret = drm_atomic_helper_prepare_planes(dev, state);
|
||||
if (ret) {
|
||||
|
@ -92,6 +92,27 @@
|
||||
} while (0)
|
||||
|
||||
static DEFINE_MUTEX(msm_release_lock);
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
static BLOCKING_NOTIFIER_HEAD(msm_drm_notifier_list);
|
||||
|
||||
int msm_drm_register_notifier_client(struct notifier_block *nb)
|
||||
{
|
||||
return blocking_notifier_chain_register(&msm_drm_notifier_list, nb);
|
||||
}
|
||||
EXPORT_SYMBOL(msm_drm_register_notifier_client);
|
||||
|
||||
int msm_drm_unregister_notifier_client(struct notifier_block *nb)
|
||||
{
|
||||
return blocking_notifier_chain_unregister(&msm_drm_notifier_list, nb);
|
||||
}
|
||||
EXPORT_SYMBOL(msm_drm_unregister_notifier_client);
|
||||
|
||||
int __msm_drm_notifier_call_chain(unsigned long event, void *data)
|
||||
{
|
||||
return blocking_notifier_call_chain(&msm_drm_notifier_list,
|
||||
event, data);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void msm_fb_output_poll_changed(struct drm_device *dev)
|
||||
{
|
||||
@ -1064,6 +1085,10 @@ void msm_atomic_flush_display_threads(struct msm_drm_private *priv)
|
||||
/*
|
||||
* DRM operations:
|
||||
*/
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
struct msm_file_private *msm_ioctl_power_ctrl_ctx;
|
||||
DEFINE_MUTEX(msm_ioctl_power_ctrl_ctx_lock);
|
||||
#endif
|
||||
|
||||
static int context_init(struct drm_device *dev, struct drm_file *file)
|
||||
{
|
||||
@ -1096,6 +1121,13 @@ static int msm_open(struct drm_device *dev, struct drm_file *file)
|
||||
|
||||
static void context_close(struct msm_file_private *ctx)
|
||||
{
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
mutex_lock(&msm_ioctl_power_ctrl_ctx_lock);
|
||||
if (msm_ioctl_power_ctrl_ctx == ctx)
|
||||
msm_ioctl_power_ctrl_ctx = NULL;
|
||||
mutex_unlock(&msm_ioctl_power_ctrl_ctx_lock);
|
||||
#endif
|
||||
|
||||
kfree(ctx);
|
||||
}
|
||||
|
||||
@ -1696,6 +1728,12 @@ int msm_ioctl_power_ctrl(struct drm_device *dev, void *data,
|
||||
|
||||
priv = dev->dev_private;
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
mutex_lock(&msm_ioctl_power_ctrl_ctx_lock);
|
||||
msm_ioctl_power_ctrl_ctx = ctx;
|
||||
mutex_unlock(&msm_ioctl_power_ctrl_ctx_lock);
|
||||
#endif
|
||||
|
||||
mutex_lock(&ctx->power_lock);
|
||||
|
||||
old_cnt = ctx->enable_refcnt;
|
||||
@ -2040,6 +2078,12 @@ static int add_display_components(struct device *dev,
|
||||
node = of_parse_phandle(np, "connectors", i);
|
||||
if (!node)
|
||||
break;
|
||||
#ifndef CONFIG_SECDP
|
||||
if (!strncmp(node->name, "qcom,dp_display", 15)) {
|
||||
pr_info("[drm-dp] disabled displayport!\n");
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
component_match_add(dev, matchptr, compare_of, node);
|
||||
}
|
||||
@ -2388,6 +2432,18 @@ static void __exit msm_drm_unregister(void)
|
||||
module_init(msm_drm_register);
|
||||
module_exit(msm_drm_unregister);
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
#if IS_ENABLED(CONFIG_REGULATOR_S2DOS05)
|
||||
MODULE_SOFTDEP("pre: s2dos05-regulator");
|
||||
#endif
|
||||
#if IS_ENABLED(CONFIG_REGULATOR_S2DOS07)
|
||||
MODULE_SOFTDEP("pre: s2dos07");
|
||||
#endif
|
||||
#if IS_ENABLED(CONFIG_REGULATOR_S2MPB03)
|
||||
MODULE_SOFTDEP("pre: s2mpb03");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
MODULE_AUTHOR("Rob Clark <robdclark@gmail.com");
|
||||
MODULE_DESCRIPTION("MSM DRM Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -20,6 +20,10 @@
|
||||
#ifndef __MSM_DRV_H__
|
||||
#define __MSM_DRV_H__
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG) && IS_ENABLED(CONFIG_UML)
|
||||
#include "samsung/kunit_test/ss_kunit_test_garbage_macro.h"
|
||||
#endif
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/cpufreq.h>
|
||||
@ -257,6 +261,10 @@ enum msm_mdp_conn_property {
|
||||
CONNECTOR_PROP_WB_ROT_TYPE,
|
||||
CONNECTOR_PROP_WB_ROT_BYTES_PER_CLK,
|
||||
CONNECTOR_PROP_BPP_MODE,
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
/* SAMSUNG_FINGERPRINT */
|
||||
CONNECTOR_PROP_FINGERPRINT_MASK,
|
||||
#endif
|
||||
|
||||
/* total # of properties */
|
||||
CONNECTOR_PROP_COUNT
|
||||
@ -849,6 +857,9 @@ struct msm_display_wd_jitter_config {
|
||||
*/
|
||||
struct msm_mode_info {
|
||||
uint32_t frame_rate;
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
uint32_t frame_rate_org;
|
||||
#endif
|
||||
uint32_t vtotal;
|
||||
uint32_t prefill_lines;
|
||||
uint32_t jitter_numer;
|
||||
@ -1373,6 +1384,10 @@ int msm_framebuffer_get_cache_hint(struct drm_framebuffer *fb,
|
||||
struct drm_fb_helper *msm_fbdev_init(struct drm_device *dev);
|
||||
void msm_fbdev_free(struct drm_device *dev);
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
int __msm_drm_notifier_call_chain(unsigned long event, void *data);
|
||||
#endif
|
||||
|
||||
struct hdmi;
|
||||
#if IS_ENABLED(CONFIG_DRM_MSM_HDMI)
|
||||
int msm_hdmi_modeset_init(struct hdmi *hdmi, struct drm_device *dev,
|
||||
|
@ -32,6 +32,10 @@
|
||||
#include "msm_mmu.h"
|
||||
#include "sde_dbg.h"
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
#include "ss_dsi_panel_common.h"
|
||||
#endif
|
||||
|
||||
struct msm_smmu_client {
|
||||
struct device *dev;
|
||||
const char *compat;
|
||||
@ -255,6 +259,9 @@ static int msm_smmu_map_dma_buf(struct msm_mmu *mmu, struct sg_table *sgt,
|
||||
struct msm_smmu_client *client = msm_smmu_to_client(smmu);
|
||||
unsigned long attrs = 0x0;
|
||||
int ret;
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
int retry_cnt;
|
||||
#endif
|
||||
|
||||
if (!sgt || !client) {
|
||||
DRM_ERROR("sg table is invalid\n");
|
||||
@ -268,6 +275,23 @@ static int msm_smmu_map_dma_buf(struct msm_mmu *mmu, struct sg_table *sgt,
|
||||
if (!(flags & MSM_BO_EXTBUF)) {
|
||||
ret = dma_map_sg_attrs(client->dev, sgt->sgl, sgt->nents, dir,
|
||||
attrs);
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
if (!in_interrupt()) {
|
||||
if (!ret) {
|
||||
for (retry_cnt = 0; retry_cnt < 62 ; retry_cnt++) {
|
||||
/* To wait free page by memory reclaim*/
|
||||
usleep_range(16000, 16000);
|
||||
|
||||
pr_err("dma map sg failed : retry (%d)\n", retry_cnt);
|
||||
ret = dma_map_sg_attrs(client->dev, sgt->sgl, sgt->nents, dir,
|
||||
attrs);
|
||||
if (!ret)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!ret) {
|
||||
DRM_ERROR("dma map sg failed\n");
|
||||
return -ENOMEM;
|
||||
@ -282,6 +306,11 @@ static int msm_smmu_map_dma_buf(struct msm_mmu *mmu, struct sg_table *sgt,
|
||||
dir, attrs, client->secure, flags);
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG) && IS_ENABLED(CONFIG_SEC_DEBUG)
|
||||
if (sec_debug_is_enabled() && sgt && sgt->sgl)
|
||||
ss_smmu_debug_map(SMMU_RT_DISPLAY_DEBUG, sgt);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -305,6 +334,11 @@ static void msm_smmu_unmap_dma_buf(struct msm_mmu *mmu, struct sg_table *sgt,
|
||||
dir, client->secure, flags);
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG) && IS_ENABLED(CONFIG_SEC_DEBUG)
|
||||
if (sec_debug_is_enabled() && sgt && sgt->sgl)
|
||||
ss_smmu_debug_unmap(SMMU_RT_DISPLAY_DEBUG, sgt);
|
||||
#endif
|
||||
|
||||
if (!(flags & MSM_BO_EXTBUF))
|
||||
dma_unmap_sg(client->dev, sgt->sgl, sgt->nents, dir);
|
||||
}
|
||||
@ -465,6 +499,11 @@ static int msm_smmu_fault_handler(struct iommu_domain *domain,
|
||||
DRM_ERROR("trigger dump, iova=0x%08lx, flags=0x%x\n", iova, flags);
|
||||
DRM_ERROR("SMMU device:%s", client->dev ? client->dev->kobj.name : "");
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
//ss_smmu_debug_log();
|
||||
SDE_DBG_DUMP(SDE_DBG_BUILT_IN_ALL, "panic"); // case 03250922
|
||||
#endif
|
||||
|
||||
/*
|
||||
* return -ENOSYS to allow smmu driver to dump out useful
|
||||
* debug info.
|
||||
@ -528,6 +567,9 @@ static int msm_smmu_probe(struct platform_device *pdev)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
pr_err("msm_smmu_probe ++ \n");
|
||||
#endif
|
||||
DRM_INFO("probing device %s\n", match->compatible);
|
||||
|
||||
client = devm_kzalloc(&pdev->dev, sizeof(*client), GFP_KERNEL);
|
||||
@ -566,6 +608,10 @@ static int msm_smmu_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
pr_err("component add failed\n");
|
||||
|
||||
#if IS_ENABLED(CONFIG_DISPLAY_SAMSUNG)
|
||||
pr_err("msm_smmu_probe -- \n");
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,8 @@
|
||||
XXD := /usr/bin/xxd
|
||||
SED := /bin/sed
|
||||
|
||||
#Translate .dat file to .h to cover the case which can not use request_firmware(Recovery Mode)
|
||||
CLEAR_TMP := $(shell rm -f E3_S6E3HAE_AMB681AZ01_PDF_DATA)
|
||||
COPY_TO_HERE := $(shell cp -vf $(DISPLAY_BLD_DIR)/msm/samsung/panel_data_file/E3_S6E3HAE_AMB681AZ01.dat E3_S6E3HAE_AMB681AZ01_PDF_DATA)
|
||||
DATA_TO_HEX := $(shell $(XXD) -i E3_S6E3HAE_AMB681AZ01_PDF_DATA > $(DISPLAY_BLD_DIR)/msm/samsung/E3_S6E3HAE_AMB681AZ01/E3_S6E3HAE_AMB681AZ01_PDF.h)
|
||||
ADD_NULL_CHR := $(shell $(SED) -i -e 's/\([0-9a-f]\)$$/\0, 0x00/' $(DISPLAY_BLD_DIR)/msm/samsung/E3_S6E3HAE_AMB681AZ01/E3_S6E3HAE_AMB681AZ01_PDF.h)
|
@ -0,0 +1 @@
|
||||
export CONFIG_PANEL_E3_S6E3HAE_AMB681AZ01_WQHD=y
|
@ -0,0 +1 @@
|
||||
#define CONFIG_PANEL_E3_S6E3HAE_AMB681AZ01_WQHD 1
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* =================================================================
|
||||
*
|
||||
*
|
||||
* Description: samsung display panel file
|
||||
* Company: Samsung Electronics
|
||||
*
|
||||
* ================================================================
|
||||
*/
|
||||
/*
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) 2023, Samsung Electronics. 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 E3_S6E3HAE_AMB681AZ01_HW_PARAM_H
|
||||
#define E3_S6E3HAE_AMB681AZ01_HW_PARAM_H
|
||||
|
||||
static int GLUT_OFFSET_night_dim_V_revA[GAMMA_OFFSET_SIZE * GLUT_SIZE] = { };
|
||||
static int GLUT_OFFSET_48_96HS_V_revA[GAMMA_OFFSET_SIZE * GLUT_SIZE] = { };
|
||||
|
||||
#endif
|
@ -0,0 +1,8 @@
|
||||
XXD := /usr/bin/xxd
|
||||
SED := /bin/sed
|
||||
|
||||
#Translate .dat file to .h to cover the case which can not use request_firmware(Recovery Mode)
|
||||
CLEAR_TMP := $(shell rm -f E3_S6E3HAF_AMB679FN01_PDF_DATA)
|
||||
COPY_TO_HERE := $(shell cp -vf $(DISPLAY_BLD_DIR)/msm/samsung/panel_data_file/E3_S6E3HAF_AMB679FN01.dat E3_S6E3HAF_AMB679FN01_PDF_DATA)
|
||||
DATA_TO_HEX := $(shell $(XXD) -i E3_S6E3HAF_AMB679FN01_PDF_DATA > $(DISPLAY_BLD_DIR)/msm/samsung/E3_S6E3HAF_AMB679FN01/E3_S6E3HAF_AMB679FN01_PDF.h)
|
||||
ADD_NULL_CHR := $(shell $(SED) -i -e 's/\([0-9a-f]\)$$/\0, 0x00/' $(DISPLAY_BLD_DIR)/msm/samsung/E3_S6E3HAF_AMB679FN01/E3_S6E3HAF_AMB679FN01_PDF.h)
|
@ -0,0 +1 @@
|
||||
export CONFIG_PANEL_E3_S6E3HAF_AMB679FN01_WQHD=y
|
@ -0,0 +1 @@
|
||||
#define CONFIG_PANEL_E3_S6E3HAF_AMB679FN01_WQHD 1
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
576
qcom/opensource/display-drivers/msm/samsung/MAFPC/ss_dsi_mafpc.c
Normal file
576
qcom/opensource/display-drivers/msm/samsung/MAFPC/ss_dsi_mafpc.c
Normal file
@ -0,0 +1,576 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com/
|
||||
*
|
||||
* DDI ABC operation
|
||||
* Author: Samsung Display Driver Team <cj1225.jang@samsung.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include "ss_dsi_panel_common.h"
|
||||
#include "ss_dsi_mafpc.h"
|
||||
|
||||
static int ss_mafpc_make_img_mass_cmds(struct samsung_display_driver_data *vdd,
|
||||
char *data, u32 data_size, struct ss_cmd_desc *ss_cmd)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
SDE_ATRACE_BEGIN("mafpc_mass_cmd_generation");
|
||||
mutex_lock(&vdd->mafpc.vdd_mafpc_lock);
|
||||
|
||||
ret = ss_convert_img_to_mass_cmds(vdd, data, data_size, ss_cmd);
|
||||
|
||||
mutex_unlock(&vdd->mafpc.vdd_mafpc_lock);
|
||||
SDE_ATRACE_END("mafpc_mass_cmd_generation");
|
||||
|
||||
LCD_INFO(vdd, "tx_len: %d\n", ss_cmd->tx_len);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define WAIT_FRAME (1)
|
||||
|
||||
static int ss_mafpc_img_write(struct samsung_display_driver_data *vdd, bool is_instant)
|
||||
{
|
||||
if (!vdd->mafpc.is_support) {
|
||||
LCD_ERR(vdd, "mafpc is not supported..(%d) \n", vdd->mafpc.is_support);
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
LCD_INFO(vdd, "++(%d)\n", is_instant);
|
||||
|
||||
mutex_lock(&vdd->self_disp.vdd_self_display_ioctl_lock);
|
||||
mutex_lock(&vdd->mafpc.vdd_mafpc_lock);
|
||||
|
||||
atomic_inc(&vdd->block_commit_cnt);
|
||||
ss_wait_for_kickoff_done(vdd);
|
||||
ss_send_cmd(vdd, TX_MAFPC_SETTING);
|
||||
ss_release_commit(vdd);
|
||||
|
||||
mutex_unlock(&vdd->mafpc.vdd_mafpc_lock);
|
||||
mutex_unlock(&vdd->self_disp.vdd_self_display_ioctl_lock);
|
||||
|
||||
LCD_INFO(vdd, "--(%d)\n", is_instant);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ss_mafpc_enable(struct samsung_display_driver_data *vdd, int enable)
|
||||
{
|
||||
if (IS_ERR_OR_NULL(vdd)) {
|
||||
LCD_ERR(vdd, "vdd is null or error\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!vdd->mafpc.is_support) {
|
||||
LCD_ERR(vdd, "mafpc is not supported..(%d) \n", vdd->mafpc.is_support);
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
mutex_lock(&vdd->mafpc.vdd_mafpc_lock);
|
||||
|
||||
if (enable) {
|
||||
ss_send_cmd(vdd, TX_MAFPC_ON);
|
||||
|
||||
/* To update mAFPC brightness scale factor */
|
||||
ss_brightness_dcs(vdd, USE_CURRENT_BL_LEVEL, BACKLIGHT_NORMAL);
|
||||
} else
|
||||
ss_send_cmd(vdd, TX_MAFPC_OFF);
|
||||
|
||||
mutex_unlock(&vdd->mafpc.vdd_mafpc_lock);
|
||||
|
||||
LCD_INFO(vdd, "%s\n", enable ? "Enable" : "Disable");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ss_mafpc_crc_check(struct samsung_display_driver_data *vdd)
|
||||
{
|
||||
int rx_len;
|
||||
int ret = 0;
|
||||
|
||||
if (IS_ERR_OR_NULL(vdd)) {
|
||||
LCD_ERR(vdd, "vdd is null or error\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!vdd->mafpc.is_support) {
|
||||
LCD_ERR(vdd, "mafpc is not supported..(%d) \n", vdd->mafpc.is_support);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
||||
if (!vdd->mafpc.crc_size) {
|
||||
LCD_ERR(vdd, "mAFPC crc size is zero..\n\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
LCD_INFO(vdd, "++\n");
|
||||
mutex_lock(&vdd->mafpc.vdd_mafpc_crc_check_lock);
|
||||
|
||||
/* prevent sw reset to trigger esd recovery */
|
||||
LCD_INFO(vdd, "disable esd interrupt\n");
|
||||
if (vdd->esd_recovery.esd_irq_enable)
|
||||
vdd->esd_recovery.esd_irq_enable(false, true, (void *)vdd, ESD_MASK_MAFPC_CRC);
|
||||
|
||||
ss_block_commit(vdd);
|
||||
rx_len = ss_send_cmd_get_rx(vdd, TX_MAFPC_CRC_CHECK, vdd->mafpc.crc_read_data);
|
||||
ss_release_commit(vdd);
|
||||
|
||||
if (rx_len <= 0) {
|
||||
LCD_ERR(vdd, "fail to read ddi id(%d)\n", rx_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (rx_len != vdd->mafpc.crc_size) {
|
||||
LCD_ERR(vdd, "rx_len(%d) != crc_size(%d)\n", rx_len, vdd->mafpc.crc_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (memcmp(vdd->mafpc.crc_read_data, vdd->mafpc.crc_pass_data, vdd->mafpc.crc_size)) {
|
||||
LCD_ERR(vdd, "mAFPC CRC check fail !!\n");
|
||||
ret = -EFAULT;
|
||||
}
|
||||
|
||||
/* enable esd interrupt */
|
||||
LCD_INFO(vdd, "enable esd interrupt\n");
|
||||
if (vdd->esd_recovery.esd_irq_enable)
|
||||
vdd->esd_recovery.esd_irq_enable(true, true, (void *)vdd, ESD_MASK_MAFPC_CRC);
|
||||
|
||||
mutex_unlock(&vdd->mafpc.vdd_mafpc_crc_check_lock);
|
||||
LCD_INFO(vdd, "-- \n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int ss_mafpc_debug(struct samsung_display_driver_data *vdd)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int update_mafpc_scale(struct samsung_display_driver_data *vdd,
|
||||
char *val, struct ss_cmd_desc *cmd)
|
||||
{
|
||||
int idx;
|
||||
int i = -1, j;
|
||||
int ret;
|
||||
|
||||
cmd->skip_by_cond = false;
|
||||
|
||||
if (!vdd->mafpc.en) {
|
||||
LCD_DEBUG(vdd, "mAFPC is not enabled\n");
|
||||
ret = -EPERM;
|
||||
goto err_skip;
|
||||
}
|
||||
|
||||
if (!vdd->mafpc.is_br_table_updated) {
|
||||
LCD_ERR(vdd, "Brightness Table for mAFPC is not updated yet\n");
|
||||
ret = -EPERM;
|
||||
goto err_skip;
|
||||
}
|
||||
|
||||
while (!cmd->pos_0xXX[++i] && i < cmd->tx_len);
|
||||
|
||||
if (i + vdd->mafpc_scale_table.col_size > cmd->tx_len) {
|
||||
LCD_ERR(vdd, "fail to find proper 0xXX position(%d, %d)\n",
|
||||
i, cmd->tx_len);
|
||||
ret = -EINVAL;
|
||||
goto err_skip;
|
||||
}
|
||||
|
||||
idx = vdd->mafpc.scale_idx;
|
||||
if (idx < 0 || idx >= vdd->mafpc_scale_table.row_size) {
|
||||
LCD_ERR(vdd, "Invalid index for mAFPC scale table: %d/%d\n",
|
||||
idx, vdd->mafpc_scale_table.row_size);
|
||||
ret = -EINVAL;
|
||||
goto err_skip;
|
||||
}
|
||||
|
||||
for (j = 0; j < vdd->mafpc_scale_table.col_size; j++)
|
||||
cmd->txbuf[i + j] = vdd->mafpc_scale_table.cmds[idx][j];
|
||||
|
||||
LCD_DEBUG(vdd, "idx [%d] : %x %x %x\n", idx,
|
||||
cmd->txbuf[i], cmd->txbuf[i + 1], cmd->txbuf[i + 2]);
|
||||
|
||||
return 0;
|
||||
|
||||
err_skip:
|
||||
cmd->skip_by_cond = true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int update_abc_data(struct samsung_display_driver_data *vdd,
|
||||
char *val, struct ss_cmd_desc *cmd)
|
||||
{
|
||||
struct cmd_ref_state *state = &vdd->cmd_ref_state;
|
||||
bool is_factory_mode = state->is_factory_mode;
|
||||
struct ss_cmd_desc *src_ss_cmd;
|
||||
struct dsi_cmd_desc *tmp_qc_cmd;
|
||||
|
||||
if (is_factory_mode)
|
||||
src_ss_cmd = &vdd->mafpc_crc_img_cmd;
|
||||
else
|
||||
src_ss_cmd = &vdd->mafpc_img_cmd;
|
||||
|
||||
/* update target ss cmd except qc_cmd pointer */
|
||||
tmp_qc_cmd = cmd->qc_cmd;
|
||||
cmd = src_ss_cmd;
|
||||
cmd->qc_cmd = tmp_qc_cmd;
|
||||
|
||||
/* update target qc cmd except ss_cmd pointer */
|
||||
cmd->qc_cmd = src_ss_cmd->qc_cmd;
|
||||
cmd->qc_cmd->ss_cmd = cmd;
|
||||
|
||||
/* data pass of ss_bridge_qc_cmd_update */
|
||||
if (is_factory_mode) {
|
||||
cmd->qc_cmd->msg.tx_buf = vdd->mafpc_crc_img_cmd.txbuf;
|
||||
cmd->qc_cmd->msg.tx_len = vdd->mafpc_crc_img_cmd.tx_len;
|
||||
} else {
|
||||
cmd->qc_cmd->msg.tx_buf = vdd->mafpc_img_cmd.txbuf;
|
||||
cmd->qc_cmd->msg.tx_len = vdd->mafpc_img_cmd.tx_len;
|
||||
}
|
||||
|
||||
LCD_INFO(vdd, "cmd->tx_len:%d, tx_buf:[0x%x, 0x%x, 0x%x..\n",
|
||||
cmd->qc_cmd->msg.tx_len, vdd->mafpc_img_cmd.txbuf[0],
|
||||
vdd->mafpc_img_cmd.txbuf[1], vdd->mafpc_img_cmd.txbuf[2]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int update_abc_ctrl_data(struct samsung_display_driver_data *vdd,
|
||||
char *val, struct ss_cmd_desc *cmd)
|
||||
{
|
||||
u32 ctrl_cmd_size = vdd->mafpc.enable_cmd_size;
|
||||
char *ctrl_cmd_buf = vdd->mafpc.enable_cmd_buf;
|
||||
int i = -1, j, pos = 0;
|
||||
char show_buf[200] = {0, };
|
||||
|
||||
if (!ctrl_cmd_buf) {
|
||||
LCD_ERR(vdd, "ctrl_cmd_buf is NULL\n");
|
||||
goto err_skip;
|
||||
}
|
||||
|
||||
while (!cmd->pos_0xXX[++i] && i < cmd->tx_len);
|
||||
|
||||
if (i + 1 >= cmd->tx_len) {
|
||||
LCD_ERR(vdd, "fail to find proper 0xXX position\n");
|
||||
goto err_skip;
|
||||
}
|
||||
|
||||
memcpy(&cmd->txbuf[i], ctrl_cmd_buf, ctrl_cmd_size);
|
||||
|
||||
for (j = 0; j < ctrl_cmd_size; j++)
|
||||
pos += scnprintf(show_buf + pos, sizeof(show_buf) - pos, "%02x ", ctrl_cmd_buf[j]);
|
||||
|
||||
LCD_INFO(vdd, "update ABC enable cmd [%d] = %s\n", ctrl_cmd_size, show_buf);
|
||||
|
||||
return 0;
|
||||
|
||||
err_skip:
|
||||
cmd->skip_by_cond = true;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* ss_mafpc_ioctl() : get ioctl from mdnie framework.
|
||||
*/
|
||||
static long ss_mafpc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct miscdevice *c = file->private_data;
|
||||
struct dsi_display *display = dev_get_drvdata(c->parent);
|
||||
struct dsi_panel *panel = display->panel;
|
||||
struct samsung_display_driver_data *vdd = panel->panel_private;
|
||||
int ret = 0;
|
||||
|
||||
if (IS_ERR_OR_NULL(vdd)) {
|
||||
LCD_ERR(vdd, "vdd is null or error\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if ((_IOC_TYPE(cmd) != MAFPC_IOCTL_MAGIC) ||
|
||||
(_IOC_NR(cmd) >= IOCTL_MAFPC_MAX)) {
|
||||
LCD_ERR(vdd, "TYPE(%u) NR(%u) is wrong..\n",
|
||||
_IOC_TYPE(cmd), _IOC_NR(cmd));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
LCD_INFO(vdd, "cmd = %s\n", cmd == IOCTL_MAFPC_ON ? "IOCTL_MAFPC_ON" :
|
||||
cmd == IOCTL_MAFPC_OFF ? "IOCTL_MAFPC_OFF" :
|
||||
cmd == IOCTL_MAFPC_ON_INSTANT ? "IOCTL_MAFPC_ON_INSTANT" :
|
||||
cmd == IOCTL_MAFPC_OFF_INSTANT ? "IOCTL_MAFPC_OFF_INSTANT" : "IOCTL_ERR");
|
||||
|
||||
switch (cmd) {
|
||||
case IOCTL_MAFPC_ON:
|
||||
vdd->mafpc.en = true;
|
||||
break;
|
||||
case IOCTL_MAFPC_ON_INSTANT:
|
||||
vdd->mafpc.en = true;
|
||||
if (!ss_is_ready_to_send_cmd(vdd)) {
|
||||
LCD_INFO(vdd, "Panel is not ready(%d), will apply next display on\n",
|
||||
vdd->panel_state);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ss_mafpc_img_write(vdd, true);
|
||||
ss_mafpc_enable(vdd, true);
|
||||
break;
|
||||
case IOCTL_MAFPC_OFF:
|
||||
vdd->mafpc.en = false;
|
||||
break;
|
||||
case IOCTL_MAFPC_OFF_INSTANT:
|
||||
if (!ss_is_ready_to_send_cmd(vdd)) {
|
||||
LCD_ERR(vdd, "Panel is not ready. Panel State(%d)\n", vdd->panel_state);
|
||||
return -ENODEV;
|
||||
}
|
||||
vdd->mafpc.en = false;
|
||||
ss_mafpc_enable(vdd, false);
|
||||
break;
|
||||
default:
|
||||
LCD_ERR(vdd, "invalid cmd : %u \n", cmd);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* ss_mafpc_write_from_user() : get mfapc image data from mdnie framework.
|
||||
* prepare for dsi_panel_cmds.
|
||||
*/
|
||||
static ssize_t ss_mafpc_write_from_user(struct file *file, const char __user *user_buf,
|
||||
size_t total_count, loff_t *ppos)
|
||||
{
|
||||
struct miscdevice *c = file->private_data;
|
||||
struct dsi_display *display = dev_get_drvdata(c->parent);
|
||||
struct dsi_panel *panel = display->panel;
|
||||
struct samsung_display_driver_data *vdd = panel->panel_private;
|
||||
int i, j, k = 0;
|
||||
int ret = 0;
|
||||
|
||||
u32 enable_cmd_size = vdd->mafpc.enable_cmd_size;
|
||||
char *enable_cmd_buf = vdd->mafpc.enable_cmd_buf;
|
||||
u32 img_size = vdd->mafpc.img_size;
|
||||
char *img_buf = vdd->mafpc.img_buf;
|
||||
u32 br_table_size = vdd->mafpc.scale_table_size;
|
||||
char *scale_tbl_buf = vdd->mafpc.scale_table_buf;
|
||||
u32 hdr_size = vdd->mafpc.header_cmd_size;
|
||||
|
||||
if (IS_ERR_OR_NULL(vdd)) {
|
||||
LCD_ERR(vdd, "no vdd");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (unlikely(!enable_cmd_buf)) {
|
||||
LCD_ERR(vdd, "No mafpc Enable cmd Buffer\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (unlikely(!img_buf)) {
|
||||
LCD_ERR(vdd, "No mafpc Image Buffer\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (unlikely(!scale_tbl_buf)) {
|
||||
LCD_ERR(vdd, "No mafpc scale tbl Buffer\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (unlikely(!user_buf)) {
|
||||
LCD_ERR(vdd, "invalid user buffer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (total_count != (enable_cmd_size + hdr_size + img_size + br_table_size)) {
|
||||
LCD_ERR(vdd, "Invalid size %zu, should be %u\n",
|
||||
total_count, (enable_cmd_size + hdr_size + img_size + br_table_size));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
LCD_INFO(vdd, "Total_Count(%zu), hdr_size (%u) cmd_size(%u), img_size(%u), br_table_size(%u)\n",
|
||||
total_count, hdr_size, enable_cmd_size, img_size, br_table_size);
|
||||
|
||||
/*
|
||||
* Get 67bytes Enable Command to match with mafpc image data
|
||||
(1Byte(Header) + 66Byte(Control Data))
|
||||
*/
|
||||
ret = copy_from_user(enable_cmd_buf, user_buf + hdr_size, enable_cmd_size);
|
||||
if (unlikely(ret < 0)) {
|
||||
LCD_ERR(vdd, "failed to copy_from_user (Enable Command)\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Get ABC Compensation Image Data from user space (mDNIE Service) */
|
||||
ret = copy_from_user(img_buf, user_buf + enable_cmd_size + hdr_size, img_size);
|
||||
if (unlikely(ret < 0)) {
|
||||
LCD_ERR(vdd, "failed to copy_from_user (Image Data)\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Get 225(75 x 3)Bytes for brightness scale cmd table from user space (mDNIE Service) */
|
||||
ret = copy_from_user(scale_tbl_buf, user_buf + enable_cmd_size + hdr_size + img_size, br_table_size);
|
||||
if (unlikely(ret < 0)) {
|
||||
LCD_ERR(vdd, "failed to copy_from_user (Brightness Scale Table)\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < vdd->mafpc_scale_table.row_size; i++) {
|
||||
for (j = 0; j < vdd->mafpc_scale_table.col_size; j++)
|
||||
vdd->mafpc_scale_table.cmds[i][j] = scale_tbl_buf[k++];
|
||||
|
||||
LCD_INFO(vdd, "[%02d] %X %X %X\n", i,
|
||||
vdd->mafpc_scale_table.cmds[i][0],
|
||||
vdd->mafpc_scale_table.cmds[i][1],
|
||||
vdd->mafpc_scale_table.cmds[i][2]);
|
||||
}
|
||||
|
||||
vdd->mafpc.is_br_table_updated = true;
|
||||
|
||||
ss_mafpc_make_img_mass_cmds(vdd, vdd->mafpc.img_buf, vdd->mafpc.img_size, &vdd->mafpc_img_cmd);
|
||||
|
||||
return total_count;
|
||||
}
|
||||
|
||||
static int ss_mafpc_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct miscdevice *c = file->private_data;
|
||||
struct dsi_display *display = dev_get_drvdata(c->parent);
|
||||
struct dsi_panel *panel = display->panel;
|
||||
struct samsung_display_driver_data *vdd = panel->panel_private;
|
||||
|
||||
if (IS_ERR_OR_NULL(vdd)) {
|
||||
LCD_ERR(vdd, "vdd is null or error\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
vdd->mafpc.file_open = true;
|
||||
|
||||
LCD_DEBUG(vdd, "[OPEN]\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ss_mafpc_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct miscdevice *c = file->private_data;
|
||||
struct dsi_display *display = dev_get_drvdata(c->parent);
|
||||
struct dsi_panel *panel = display->panel;
|
||||
struct samsung_display_driver_data *vdd = panel->panel_private;
|
||||
|
||||
if (IS_ERR_OR_NULL(vdd)) {
|
||||
LCD_ERR(vdd, "vdd is null or error\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
vdd->mafpc.file_open = false;
|
||||
|
||||
LCD_DEBUG(vdd, "[RELEASE]\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations mafpc_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.unlocked_ioctl = ss_mafpc_ioctl,
|
||||
.open = ss_mafpc_open,
|
||||
.release = ss_mafpc_release,
|
||||
.write = ss_mafpc_write_from_user,
|
||||
};
|
||||
|
||||
#define DEV_NAME_SIZE 24
|
||||
int ss_mafpc_init(struct samsung_display_driver_data *vdd)
|
||||
{
|
||||
int ret = 0;
|
||||
static char devname[DEV_NAME_SIZE] = {'\0', };
|
||||
struct dsi_panel_cmd_set *pcmds;
|
||||
|
||||
struct dsi_panel *panel = NULL;
|
||||
struct mipi_dsi_host *host = NULL;
|
||||
struct dsi_display *display = NULL;
|
||||
|
||||
if (IS_ERR_OR_NULL(vdd)) {
|
||||
LCD_ERR(vdd, "vdd is null or error\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!vdd->mafpc.is_support) {
|
||||
LCD_ERR(vdd, "mAFPC is not supported\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
panel = (struct dsi_panel *)vdd->msm_private;
|
||||
host = panel->mipi_device.host;
|
||||
display = container_of(host, struct dsi_display, host);
|
||||
|
||||
mutex_init(&vdd->mafpc.vdd_mafpc_lock);
|
||||
mutex_init(&vdd->mafpc.vdd_mafpc_crc_check_lock);
|
||||
|
||||
if (vdd->ndx == PRIMARY_DISPLAY_NDX)
|
||||
snprintf(devname, DEV_NAME_SIZE, "mafpc");
|
||||
else
|
||||
snprintf(devname, DEV_NAME_SIZE, "mafpc%d", vdd->ndx);
|
||||
|
||||
vdd->mafpc.dev.minor = MISC_DYNAMIC_MINOR;
|
||||
vdd->mafpc.dev.name = devname;
|
||||
vdd->mafpc.dev.fops = &mafpc_fops;
|
||||
vdd->mafpc.dev.parent = &display->pdev->dev;;
|
||||
|
||||
vdd->mafpc.enable = ss_mafpc_enable;
|
||||
vdd->mafpc.crc_check = ss_mafpc_crc_check;
|
||||
vdd->mafpc.make_img_mass_cmds = ss_mafpc_make_img_mass_cmds;
|
||||
vdd->mafpc.img_write = ss_mafpc_img_write;
|
||||
vdd->mafpc.debug = ss_mafpc_debug;
|
||||
|
||||
/* Alloc the memory for ABC scale table */
|
||||
vdd->mafpc.scale_table_size = vdd->mafpc_scale_table.row_size * vdd->mafpc_scale_table.col_size;
|
||||
if (vdd->mafpc.scale_table_size) {
|
||||
vdd->mafpc.scale_table_buf = kzalloc(vdd->mafpc.scale_table_size, GFP_KERNEL);
|
||||
if (IS_ERR_OR_NULL(vdd->mafpc.scale_table_buf))
|
||||
LCD_ERR(vdd, "fail to allocate scale_table_buf(%d)\n", vdd->mafpc.scale_table_size);
|
||||
}
|
||||
|
||||
LCD_INFO(vdd, "scale_table_size [%d] = (%d) x (%d)\n", vdd->mafpc.scale_table_size,
|
||||
vdd->mafpc_scale_table.row_size, vdd->mafpc_scale_table.col_size);
|
||||
|
||||
/* Alloc the memory for ABC enable cmd */
|
||||
if (vdd->mafpc.enable_cmd_size) {
|
||||
vdd->mafpc.enable_cmd_buf = kzalloc(vdd->mafpc.enable_cmd_size, GFP_KERNEL);
|
||||
if (IS_ERR_OR_NULL(vdd->mafpc.enable_cmd_buf)) {
|
||||
LCD_ERR(vdd, "Failed to alloc mafpc enable cmd buffer\n");
|
||||
} else {
|
||||
/* initialize mafpc enable cmd to default control data */
|
||||
pcmds = ss_get_cmds(vdd, TX_MAFPC_CTRL_DATA);
|
||||
if (pcmds->count <= 0) {
|
||||
LCD_ERR(vdd, "no mafpc_default_enable_cmd cmds\n");
|
||||
} else {
|
||||
memcpy(vdd->mafpc.enable_cmd_buf, &pcmds->cmds[0].ss_txbuf[1],
|
||||
vdd->mafpc.enable_cmd_size);
|
||||
LCD_INFO(vdd, "initialize mafpc enable cmd\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LCD_INFO(vdd, "enable_cmd_size [%d]\n", vdd->mafpc.enable_cmd_size);
|
||||
|
||||
ret = ss_wrapper_misc_register(vdd, &vdd->mafpc.dev);
|
||||
if (ret) {
|
||||
LCD_ERR(vdd, "failed to register driver : %d\n", ret);
|
||||
vdd->mafpc.is_support = false;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
register_op_sym_cb(vdd, "MAFPC", update_mafpc_scale, true);
|
||||
register_op_sym_cb(vdd, "ABC_DATA", update_abc_data, true);
|
||||
register_op_sym_cb(vdd, "UPDATE_ABC_CTRL_DATA", update_abc_ctrl_data, true);
|
||||
|
||||
LCD_INFO(vdd, "Success to register mafpc device..(%d)\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
MODULE_DESCRIPTION("mAFPC driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
172
qcom/opensource/display-drivers/msm/samsung/MAFPC/ss_dsi_mafpc.h
Normal file
172
qcom/opensource/display-drivers/msm/samsung/MAFPC/ss_dsi_mafpc.h
Normal file
@ -0,0 +1,172 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com/
|
||||
*
|
||||
* DDI ABC operation
|
||||
* Author: Samsung Display Driver Team <cj1225.jang@samsung.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef __SS_DSI_MAFPC_H__
|
||||
#define __SS_DSI_MAFPC_H__
|
||||
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/file.h>
|
||||
|
||||
/* Align & Paylod Size for Embedded mode Transfer */
|
||||
#define MAFPC_CMD_ALIGN 16
|
||||
#define MAFPC_MAX_PAYLOAD_SIZE 200
|
||||
|
||||
/* Align & Paylod Size for Non-Embedded mode(Mass) Command Transfer */
|
||||
#define MAFPC_MASS_CMD_ALIGN 256
|
||||
#define MAFPC_MAX_PAYLOAD_SIZE_MASS 0xFFFF0 /* 983,024 */
|
||||
|
||||
/*
|
||||
* ioctl
|
||||
*/
|
||||
#define MAFPC_IOCTL_MAGIC 'M'
|
||||
#define IOCTL_MAFPC_ON _IOW(MAFPC_IOCTL_MAGIC, 1, int)
|
||||
#define IOCTL_MAFPC_ON_INSTANT _IOW(MAFPC_IOCTL_MAGIC, 2, int)
|
||||
#define IOCTL_MAFPC_OFF _IOW(MAFPC_IOCTL_MAGIC, 3, int)
|
||||
#define IOCTL_MAFPC_OFF_INSTANT _IOW(MAFPC_IOCTL_MAGIC, 4, int)
|
||||
#define IOCTL_MAFPC_MAX 10
|
||||
|
||||
struct ss_cmd_desc;
|
||||
|
||||
struct MAFPC {
|
||||
struct miscdevice dev;
|
||||
|
||||
int is_support;
|
||||
int factory_support;
|
||||
int file_open;
|
||||
int need_to_write;
|
||||
int is_br_table_updated;
|
||||
int force_delay;
|
||||
|
||||
int en;
|
||||
|
||||
char *enable_cmd_buf;
|
||||
u32 enable_cmd_size;
|
||||
u32 header_cmd_size;
|
||||
char *img_buf;
|
||||
u32 img_size;
|
||||
char *scale_table_buf;
|
||||
u32 scale_table_size;
|
||||
|
||||
int scale_idx;
|
||||
|
||||
u32 wpos;
|
||||
u64 wsize;
|
||||
|
||||
int img_checksum;
|
||||
u32 img_checksum_cal;
|
||||
|
||||
struct mutex vdd_mafpc_lock;
|
||||
struct mutex vdd_mafpc_crc_check_lock;
|
||||
|
||||
char *crc_img_buf;
|
||||
u32 crc_img_size;
|
||||
|
||||
u8 crc_pass_data[2]; /*implemented in dtsi */
|
||||
u8 crc_read_data[2];
|
||||
int crc_size;
|
||||
|
||||
/* mafpc Function */
|
||||
int (*init)(struct samsung_display_driver_data *vdd);
|
||||
int (*data_init)(struct samsung_display_driver_data *vdd);
|
||||
int (*make_img_cmds)(struct samsung_display_driver_data *vdd, char *data, u32 data_size, int cmd_type);
|
||||
int (*make_img_mass_cmds)(struct samsung_display_driver_data *vdd, char *data, u32 data_size, struct ss_cmd_desc *ss_cmd);
|
||||
int (*img_write)(struct samsung_display_driver_data *vdd, bool is_instant);
|
||||
int (*enable)(struct samsung_display_driver_data *vdd, int enable);
|
||||
int (*crc_check)(struct samsung_display_driver_data *vdd);
|
||||
int (*debug)(struct samsung_display_driver_data *vdd);
|
||||
};
|
||||
|
||||
int ss_mafpc_init(struct samsung_display_driver_data *vdd);
|
||||
|
||||
/* 2551 (Normal: 0~2550) + 1 (HBM) */
|
||||
#define MAX_MAFPC_BL_SCALE 2552
|
||||
|
||||
static int brightness_scale_idx[MAX_MAFPC_BL_SCALE] = {
|
||||
[0 ... 9] = 0,
|
||||
[10 ... 19] = 1,
|
||||
[20 ... 30] = 2,
|
||||
[31 ... 40] = 3,
|
||||
[41 ... 50] = 4,
|
||||
[51 ... 59] = 5,
|
||||
[60 ... 68] = 6,
|
||||
[69 ... 79] = 7,
|
||||
[80 ... 90] = 8,
|
||||
[91 ... 100] = 9,
|
||||
[101 ... 120] = 10,
|
||||
[121 ... 129] = 11,
|
||||
[130 ... 139] = 12,
|
||||
[140 ... 158] = 13,
|
||||
[159 ... 178] = 14,
|
||||
[179 ... 188] = 15,
|
||||
[189 ... 200] = 16,
|
||||
[201 ... 210] = 17,
|
||||
[211 ... 229] = 18,
|
||||
[230 ... 249] = 19,
|
||||
[250 ... 258] = 20,
|
||||
[259 ... 269] = 21,
|
||||
[270 ... 299] = 22,
|
||||
[300 ... 319] = 23,
|
||||
[320 ... 339] = 24,
|
||||
[340 ... 359] = 25,
|
||||
[360 ... 379] = 26,
|
||||
[380 ... 409] = 27,
|
||||
[410 ... 439] = 28,
|
||||
[440 ... 459] = 29,
|
||||
[460 ... 499] = 30,
|
||||
[500 ... 530] = 31,
|
||||
[531 ... 570] = 32,
|
||||
[571 ... 599] = 33,
|
||||
[600 ... 639] = 34,
|
||||
[640 ... 678] = 35,
|
||||
[679 ... 729] = 36,
|
||||
[730 ... 769] = 37,
|
||||
[770 ... 829] = 38,
|
||||
[830 ... 880] = 39,
|
||||
[881 ... 930] = 40,
|
||||
[931 ... 999] = 41,
|
||||
[1000 ... 1059] = 42,
|
||||
[1060 ... 1129] = 43,
|
||||
[1130 ... 1199] = 44,
|
||||
[1200 ... 1280] = 45,
|
||||
[1281 ... 1339] = 46,
|
||||
[1340 ... 1409] = 47,
|
||||
[1410 ... 1479] = 48,
|
||||
[1480 ... 1559] = 49,
|
||||
[1560 ... 1599] = 50,
|
||||
[1600 ... 1640] = 51,
|
||||
[1641 ... 1679] = 52,
|
||||
[1680 ... 1729] = 53,
|
||||
[1730 ... 1769] = 54,
|
||||
[1770 ... 1819] = 55,
|
||||
[1820 ... 1919] = 56,
|
||||
[1920 ... 2000] = 57,
|
||||
[2001 ... 2099] = 58,
|
||||
[2100 ... 2179] = 59,
|
||||
[2180 ... 2189] = 60,
|
||||
[2190 ... 2209] = 61,
|
||||
[2210 ... 2229] = 62,
|
||||
[2230 ... 2249] = 63,
|
||||
[2250 ... 2269] = 64,
|
||||
[2270 ... 2289] = 65,
|
||||
[2290 ... 2309] = 66,
|
||||
[2310 ... 2329] = 67,
|
||||
[2330 ... 2350] = 68,
|
||||
[2351 ... 2400] = 69,
|
||||
[2401 ... 2449] = 70,
|
||||
[2450 ... 2499] = 71,
|
||||
[2500 ... 2549] = 72,
|
||||
[2550] = 73,
|
||||
[2551] = 74, /* for HBM */
|
||||
};
|
||||
|
||||
#endif /* __SELF_DISPLAY_H__ */
|
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* =================================================================
|
||||
*
|
||||
*
|
||||
* Description: samsung display panel file
|
||||
*
|
||||
* Author: jb09.kim
|
||||
* Company: Samsung Electronics
|
||||
*
|
||||
* ================================================================
|
||||
*/
|
||||
/*
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) 2012, Samsung Electronics. 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.
|
||||
*
|
||||
*/
|
||||
#include "ss_dsi_panel_PBA_BOOTING_fhd.h"
|
||||
|
||||
void PBA_BOOTING_FHD_init(struct samsung_display_driver_data *vdd)
|
||||
{
|
||||
LCD_INFO(vdd, "%s\n", ss_get_panel_name(vdd));
|
||||
|
||||
vdd->mdnie.support_mdnie = false;
|
||||
vdd->dtsi_data.tft_common_support = true;
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* =================================================================
|
||||
*
|
||||
*
|
||||
* Description: samsung display panel file
|
||||
*
|
||||
* Author: jb09.kim
|
||||
* Company: Samsung Electronics
|
||||
*
|
||||
* ================================================================
|
||||
*/
|
||||
/*
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) 2012, Samsung Electronics. 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 SAMSUNG_DSI_PANEL_EA8061V_AMS391DT01_H
|
||||
#define SAMSUNG_DSI_PANEL_EA8061V_AMS391DT01_H
|
||||
|
||||
#include "ss_dsi_panel_common.h"
|
||||
|
||||
#endif
|
@ -0,0 +1,619 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com/
|
||||
*
|
||||
* DDI operation : self clock, self mask, self icon.. etc.
|
||||
* Author: QC LCD driver <cj1225.jang@samsung.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include "ss_dsi_panel_common.h"
|
||||
#include "self_display.h"
|
||||
|
||||
int make_mass_self_display_img_cmds(struct samsung_display_driver_data *vdd,
|
||||
enum self_display_data_flag op, struct ss_cmd_desc *ss_cmd)
|
||||
{
|
||||
char *data = vdd->self_disp.operation[op].img_buf;
|
||||
u32 data_size = vdd->self_disp.operation[op].img_size;
|
||||
int ret = 0;
|
||||
|
||||
u32 check_sum_0 = 0;
|
||||
u32 check_sum_1 = 0;
|
||||
u32 check_sum_2 = 0;
|
||||
u32 check_sum_3 = 0;
|
||||
int i;
|
||||
|
||||
if (!data) {
|
||||
LCD_ERR(vdd, "data is null..\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!data_size) {
|
||||
LCD_ERR(vdd, "data size is zero..\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
SDE_ATRACE_BEGIN("mass_cmd_generation");
|
||||
ret = ss_convert_img_to_mass_cmds(vdd, data, data_size, ss_cmd);
|
||||
|
||||
/* Image Check Sum Calculation */
|
||||
for (i = 0; i < data_size; i += 4)
|
||||
check_sum_0 += data[i];
|
||||
|
||||
for (i = 1; i < data_size; i += 4)
|
||||
check_sum_1 += data[i];
|
||||
|
||||
for (i = 2; i < data_size; i += 4)
|
||||
check_sum_2 += data[i];
|
||||
|
||||
for (i = 3; i < data_size; i += 4)
|
||||
check_sum_3 += data[i];
|
||||
|
||||
vdd->self_disp.operation[op].img_checksum_cal = (check_sum_3 & 0xFF);
|
||||
vdd->self_disp.operation[op].img_checksum_cal |= ((check_sum_2 & 0xFF) << 8);
|
||||
vdd->self_disp.operation[op].img_checksum_cal |= ((check_sum_1 & 0xFF) << 16);
|
||||
vdd->self_disp.operation[op].img_checksum_cal |= ((check_sum_0 & 0xFF) << 24);
|
||||
|
||||
SDE_ATRACE_END("mass_cmd_generation");
|
||||
|
||||
LCD_INFO(vdd, "[checksum] op=%d, checksum: 0x%X, 0x%X, 0x%X, 0x%X\n",
|
||||
op, check_sum_0, check_sum_1, check_sum_2, check_sum_3);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* TODO: set last_cmd for cmd[cur-1] and cmd[cur+1] */
|
||||
static int update_self_mask_image(struct samsung_display_driver_data *vdd,
|
||||
char *val, struct ss_cmd_desc *cmd)
|
||||
{
|
||||
struct ss_cmd_desc *src_ss_cmd;
|
||||
struct dsi_cmd_desc *tmp_qc_cmd;
|
||||
int ret;
|
||||
|
||||
cmd->skip_by_cond = false;
|
||||
|
||||
if (!vdd->self_disp.is_support) {
|
||||
LCD_INFO(vdd, "self_disp is not enabled\n");
|
||||
ret = -EPERM;
|
||||
goto err_skip;
|
||||
}
|
||||
|
||||
src_ss_cmd = &vdd->self_disp.self_mask_cmd;
|
||||
|
||||
/* update target ss cmd except qc_cmd pointer */
|
||||
tmp_qc_cmd = cmd->qc_cmd;
|
||||
cmd = src_ss_cmd;
|
||||
cmd->qc_cmd = tmp_qc_cmd;
|
||||
|
||||
/* update target qc cmd except ss_cmd pointer */
|
||||
cmd->qc_cmd = src_ss_cmd->qc_cmd;
|
||||
cmd->qc_cmd->ss_cmd = cmd;
|
||||
|
||||
/* data pass of ss_bridge_qc_cmd_update */
|
||||
cmd->qc_cmd->msg.tx_buf = vdd->self_disp.self_mask_cmd.txbuf;
|
||||
cmd->qc_cmd->msg.tx_len = vdd->self_disp.self_mask_cmd.tx_len;
|
||||
|
||||
LCD_INFO(vdd, "cmd->tx_len:%d, tx_buf:[0x%x, 0x%x..\n",
|
||||
cmd->qc_cmd->msg.tx_len, vdd->self_disp.self_mask_cmd.txbuf[0],
|
||||
vdd->self_disp.self_mask_cmd.txbuf[1]);
|
||||
|
||||
return 0;
|
||||
|
||||
err_skip:
|
||||
cmd->skip_by_cond = true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int update_self_mask_crc_image(struct samsung_display_driver_data *vdd,
|
||||
char *val, struct ss_cmd_desc *cmd)
|
||||
{
|
||||
struct ss_cmd_desc *src_ss_cmd;
|
||||
struct dsi_cmd_desc *tmp_qc_cmd;
|
||||
int ret;
|
||||
|
||||
cmd->skip_by_cond = false;
|
||||
|
||||
if (!vdd->self_disp.is_support) {
|
||||
LCD_INFO(vdd, "self_disp is not enabled\n");
|
||||
ret = -EPERM;
|
||||
goto err_skip;
|
||||
}
|
||||
|
||||
src_ss_cmd = &vdd->self_disp.self_mask_crc_cmd;
|
||||
|
||||
/* update target ss cmd except qc_cmd pointer */
|
||||
tmp_qc_cmd = cmd->qc_cmd;
|
||||
cmd = src_ss_cmd;
|
||||
cmd->qc_cmd = tmp_qc_cmd;
|
||||
|
||||
/* update target qc cmd except ss_cmd pointer */
|
||||
cmd->qc_cmd = src_ss_cmd->qc_cmd;
|
||||
cmd->qc_cmd->ss_cmd = cmd;
|
||||
|
||||
/* data pass of ss_bridge_qc_cmd_update */
|
||||
cmd->qc_cmd->msg.tx_buf = vdd->self_disp.self_mask_crc_cmd.txbuf;
|
||||
cmd->qc_cmd->msg.tx_len = vdd->self_disp.self_mask_crc_cmd.tx_len;
|
||||
|
||||
LCD_INFO(vdd, "cmd->tx_len:%d, tx_buf:[0x%x, 0x%x..\n",
|
||||
cmd->qc_cmd->msg.tx_len, vdd->self_disp.self_mask_crc_cmd.txbuf[0],
|
||||
vdd->self_disp.self_mask_crc_cmd.txbuf[1]);
|
||||
|
||||
return 0;
|
||||
|
||||
err_skip:
|
||||
cmd->skip_by_cond = true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int self_display_debug(struct samsung_display_driver_data *vdd)
|
||||
{
|
||||
int rx_len;
|
||||
char buf[4];
|
||||
|
||||
rx_len = ss_send_cmd_get_rx(vdd, RX_SELF_DISP_DEBUG, buf);
|
||||
if (rx_len < 0) {
|
||||
LCD_ERR(vdd, "invalid rx_len(%d)\n", rx_len);
|
||||
return false;
|
||||
}
|
||||
|
||||
vdd->self_disp.debug.SM_SUM_O = ((buf[0] & 0xFF) << 24);
|
||||
vdd->self_disp.debug.SM_SUM_O |= ((buf[1] & 0xFF) << 16);
|
||||
vdd->self_disp.debug.SM_SUM_O |= ((buf[2] & 0xFF) << 8);
|
||||
vdd->self_disp.debug.SM_SUM_O |= (buf[3] & 0xFF);
|
||||
|
||||
if (vdd->self_disp.operation[FLAG_SELF_MASK].img_checksum != vdd->self_disp.debug.SM_SUM_O) {
|
||||
LCD_ERR(vdd, "self mask img checksum fail!! %X %X\n",
|
||||
vdd->self_disp.operation[FLAG_SELF_MASK].img_checksum, vdd->self_disp.debug.SM_SUM_O);
|
||||
SS_XLOG(vdd->self_disp.debug.SM_SUM_O);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void self_mask_img_write(struct samsung_display_driver_data *vdd)
|
||||
{
|
||||
if (!vdd->self_disp.is_support) {
|
||||
LCD_ERR(vdd, "self display is not supported..(%d) \n",
|
||||
vdd->self_disp.is_support);
|
||||
return;
|
||||
}
|
||||
|
||||
LCD_INFO(vdd, "tx self mask\n");
|
||||
|
||||
atomic_inc(&vdd->block_commit_cnt);
|
||||
ss_wait_for_kickoff_done(vdd);
|
||||
ss_send_cmd(vdd, TX_SELF_MASK_SETTING);
|
||||
ss_release_commit(vdd);
|
||||
}
|
||||
|
||||
static int self_mask_on(struct samsung_display_driver_data *vdd, int enable)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (IS_ERR_OR_NULL(vdd)) {
|
||||
LCD_ERR(vdd, "vdd is null or error\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!vdd->self_disp.is_support) {
|
||||
LCD_ERR(vdd, "self display is not supported..(%d) \n",
|
||||
vdd->self_disp.is_support);
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
LCD_INFO(vdd, "++ (%d)\n", enable);
|
||||
|
||||
mutex_lock(&vdd->self_disp.vdd_self_display_lock);
|
||||
|
||||
if (enable) {
|
||||
if (vdd->is_factory_mode && vdd->self_disp.factory_support)
|
||||
ss_send_cmd(vdd, TX_SELF_MASK_ON_FACTORY);
|
||||
else
|
||||
ss_send_cmd(vdd, TX_SELF_MASK_ON);
|
||||
} else {
|
||||
ss_send_cmd(vdd, TX_SELF_MASK_OFF);
|
||||
}
|
||||
|
||||
mutex_unlock(&vdd->self_disp.vdd_self_display_lock);
|
||||
|
||||
LCD_INFO(vdd, "-- \n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int self_mask_udc_on(struct samsung_display_driver_data *vdd, int enable)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (IS_ERR_OR_NULL(vdd)) {
|
||||
LCD_ERR(vdd, "vdd is null or error\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!vdd->self_disp.is_support) {
|
||||
LCD_ERR(vdd, "self display is not supported..(%d) \n",
|
||||
vdd->self_disp.is_support);
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
LCD_INFO(vdd, "++ (%d)\n", enable);
|
||||
|
||||
mutex_lock(&vdd->self_disp.vdd_self_display_lock);
|
||||
|
||||
if (enable)
|
||||
ss_send_cmd(vdd, TX_SELF_MASK_UDC_ON);
|
||||
else
|
||||
ss_send_cmd(vdd, TX_SELF_MASK_UDC_OFF);
|
||||
|
||||
mutex_unlock(&vdd->self_disp.vdd_self_display_lock);
|
||||
|
||||
LCD_INFO(vdd, "-- \n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define WAIT_FRAME (2)
|
||||
|
||||
static int self_mask_check(struct samsung_display_driver_data *vdd)
|
||||
{
|
||||
int rx_len;
|
||||
|
||||
if (IS_ERR_OR_NULL(vdd)) {
|
||||
LCD_ERR(vdd, "vdd is null or error\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!vdd->self_disp.is_support) {
|
||||
LCD_ERR(vdd, "self display is not supported..(%d) \n",
|
||||
vdd->self_disp.is_support);
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
|
||||
LCD_INFO(vdd, "++ \n");
|
||||
|
||||
mutex_lock(&vdd->self_disp.vdd_self_display_lock);
|
||||
|
||||
ss_block_commit(vdd);
|
||||
rx_len = ss_send_cmd_get_rx(vdd, TX_SELF_MASK_CHECK, vdd->self_disp.mask_crc_read_data);
|
||||
ss_release_commit(vdd);
|
||||
|
||||
mutex_unlock(&vdd->self_disp.vdd_self_display_lock);
|
||||
|
||||
if (memcmp(vdd->self_disp.mask_crc_read_data,
|
||||
vdd->self_disp.mask_crc_pass_data,
|
||||
vdd->self_disp.mask_crc_size)) {
|
||||
LCD_ERR(vdd, "self mask check fail !!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
LCD_INFO(vdd, "-- \n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int self_partial_hlpm_scan_set(struct samsung_display_driver_data *vdd)
|
||||
{
|
||||
u8 *cmd_pload;
|
||||
struct self_partial_hlpm_scan sphs_info;
|
||||
struct dsi_panel_cmd_set *pcmds;
|
||||
|
||||
if (IS_ERR_OR_NULL(vdd)) {
|
||||
LCD_ERR(vdd, "vdd is null or error\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
LCD_INFO(vdd, "++\n");
|
||||
|
||||
sphs_info = vdd->self_disp.sphs_info;
|
||||
|
||||
LCD_INFO(vdd, "Self Partial HLPM hlpm_en(%d) \n", sphs_info.hlpm_en);
|
||||
|
||||
pcmds = ss_get_cmds(vdd, TX_SELF_PARTIAL_HLPM_SCAN_SET);
|
||||
if (SS_IS_CMDS_NULL(pcmds)) {
|
||||
LCD_ERR(vdd, "No cmds for TX_SELF_PARTIAL_HLPM_SCAN_SET..\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
cmd_pload = pcmds->cmds[1].ss_txbuf;
|
||||
|
||||
/* Partial HLPM */
|
||||
if (sphs_info.hlpm_en)
|
||||
cmd_pload[1] = 0x03;
|
||||
else
|
||||
cmd_pload[1] = 0x00;
|
||||
|
||||
ss_send_cmd(vdd, TX_SELF_PARTIAL_HLPM_SCAN_SET);
|
||||
|
||||
LCD_INFO(vdd, "--\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int self_display_aod_enter(struct samsung_display_driver_data *vdd)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (IS_ERR_OR_NULL(vdd)) {
|
||||
LCD_ERR(vdd, "vdd is null or error\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!vdd->self_disp.is_support) {
|
||||
LCD_DEBUG(vdd, "self display is not supported..(%d) \n",
|
||||
vdd->self_disp.is_support);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
LCD_INFO(vdd, "++\n");
|
||||
|
||||
if (!vdd->self_disp.on) {
|
||||
/* Self display on */
|
||||
ss_send_cmd(vdd, TX_SELF_DISP_ON);
|
||||
self_mask_on(vdd, false);
|
||||
}
|
||||
|
||||
vdd->self_disp.on = true;
|
||||
|
||||
LCD_INFO(vdd, "--\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int self_display_aod_exit(struct samsung_display_driver_data *vdd)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (IS_ERR_OR_NULL(vdd)) {
|
||||
LCD_ERR(vdd, "vdd is null or error\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!vdd->self_disp.is_support) {
|
||||
LCD_DEBUG(vdd, "self display is not supported..(%d) \n",
|
||||
vdd->self_disp.is_support);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
LCD_INFO(vdd, "++\n");
|
||||
|
||||
/* self display off */
|
||||
ss_send_cmd(vdd, TX_SELF_DISP_OFF);
|
||||
|
||||
ret = self_display_debug(vdd);
|
||||
if (!ret)
|
||||
self_mask_on(vdd, true);
|
||||
else
|
||||
LCD_ERR(vdd, "Self Mask CheckSum Error! Skip Self Mask On\n");
|
||||
|
||||
LCD_INFO(vdd, "write self_mask_udc %s cmd \n",
|
||||
vdd->self_disp.udc_mask_enable ? "enable" : "disable");
|
||||
|
||||
if (vdd->self_disp.udc_mask_enable)
|
||||
ss_send_cmd(vdd, TX_SELF_MASK_UDC_ON);
|
||||
else
|
||||
ss_send_cmd(vdd, TX_SELF_MASK_UDC_OFF);
|
||||
|
||||
if (vdd->self_disp.reset_status)
|
||||
vdd->self_disp.reset_status(vdd);
|
||||
|
||||
LCD_INFO(vdd, "--\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void self_display_reset_status(struct samsung_display_driver_data *vdd)
|
||||
{
|
||||
if (IS_ERR_OR_NULL(vdd)) {
|
||||
LCD_ERR(vdd, "vdd is null or error\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!vdd->self_disp.is_support) {
|
||||
LCD_DEBUG(vdd, "self display is not supported..(%d) \n",
|
||||
vdd->self_disp.is_support);
|
||||
return;
|
||||
}
|
||||
|
||||
vdd->self_disp.sa_info.en = false;
|
||||
vdd->self_disp.sd_info.en = false;
|
||||
vdd->self_disp.si_info.en = false;
|
||||
vdd->self_disp.sg_info.en = false;
|
||||
vdd->self_disp.time_set = false;
|
||||
vdd->self_disp.on = false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* self_display_ioctl() : get ioctl from aod framework.
|
||||
* set self display related registers.
|
||||
*/
|
||||
static long self_display_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct miscdevice *c = file->private_data;
|
||||
struct dsi_display *display = dev_get_drvdata(c->parent);
|
||||
struct dsi_panel *panel = display->panel;
|
||||
struct samsung_display_driver_data *vdd = panel->panel_private;
|
||||
void __user *argp = (void __user *)arg;
|
||||
int ret = 0;
|
||||
|
||||
if (IS_ERR_OR_NULL(vdd)) {
|
||||
LCD_ERR(vdd, "vdd is null or error\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!ss_is_ready_to_send_cmd(vdd)) {
|
||||
LCD_ERR(vdd, "Panel is not ready. Panel State(%d)\n", vdd->panel_state);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!vdd->self_disp.on) {
|
||||
LCD_ERR(vdd, "self_display was turned off\n");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
if ((_IOC_TYPE(cmd) != SELF_DISPLAY_IOCTL_MAGIC) ||
|
||||
(_IOC_NR(cmd) >= IOCTL_SELF_MAX)) {
|
||||
LCD_ERR(vdd, "TYPE(%u) NR(%u) is wrong..\n",
|
||||
_IOC_TYPE(cmd), _IOC_NR(cmd));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&vdd->self_disp.vdd_self_display_ioctl_lock);
|
||||
|
||||
LCD_INFO(vdd, "cmd = %s\n", cmd == IOCTL_SELF_MOVE_EN ? "IOCTL_SELF_MOVE_EN" :
|
||||
cmd == IOCTL_SELF_MOVE_OFF ? "IOCTL_SELF_MOVE_OFF" :
|
||||
cmd == IOCTL_SET_ICON ? "IOCTL_SET_ICON" :
|
||||
cmd == IOCTL_SET_GRID ? "IOCTL_SET_GRID" :
|
||||
cmd == IOCTL_SET_ANALOG_CLK ? "IOCTL_SET_ANALOG_CLK" :
|
||||
cmd == IOCTL_SET_DIGITAL_CLK ? "IOCTL_SET_DIGITAL_CLK" :
|
||||
cmd == IOCTL_SET_TIME ? "IOCTL_SET_TIME" :
|
||||
cmd == IOCTL_SET_PARTIAL_HLPM_SCAN ? "IOCTL_PARTIAL_HLPM_SCAN" : "IOCTL_ERR");
|
||||
|
||||
switch (cmd) {
|
||||
case IOCTL_SET_PARTIAL_HLPM_SCAN:
|
||||
ret = copy_from_user(&vdd->self_disp.sphs_info, argp,
|
||||
sizeof(vdd->self_disp.sphs_info));
|
||||
if (ret) {
|
||||
LCD_ERR(vdd, "fail to copy_from_user.. (%d)\n", ret);
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = self_partial_hlpm_scan_set(vdd);
|
||||
break;
|
||||
default:
|
||||
LCD_ERR(vdd, "invalid cmd : %u \n", cmd);
|
||||
break;
|
||||
}
|
||||
error:
|
||||
mutex_unlock(&vdd->self_disp.vdd_self_display_ioctl_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* self_display_write() : get image data from aod framework.
|
||||
* prepare for dsi_panel_cmds.
|
||||
*/
|
||||
static ssize_t self_display_write(struct file *file, const char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int self_display_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct miscdevice *c = file->private_data;
|
||||
struct dsi_display *display = dev_get_drvdata(c->parent);
|
||||
struct dsi_panel *panel = display->panel;
|
||||
struct samsung_display_driver_data *vdd = panel->panel_private;
|
||||
|
||||
if (IS_ERR_OR_NULL(vdd)) {
|
||||
LCD_ERR(vdd, "vdd is null or error\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
vdd->self_disp.file_open = 1;
|
||||
|
||||
LCD_DEBUG(vdd, "[open]\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int self_display_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct miscdevice *c = file->private_data;
|
||||
struct dsi_display *display = dev_get_drvdata(c->parent);
|
||||
struct dsi_panel *panel = display->panel;
|
||||
struct samsung_display_driver_data *vdd = panel->panel_private;
|
||||
|
||||
if (IS_ERR_OR_NULL(vdd)) {
|
||||
LCD_ERR(vdd, "vdd is null or error\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
vdd->self_disp.file_open = 0;
|
||||
|
||||
LCD_DEBUG(vdd, "[release]\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations self_display_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.unlocked_ioctl = self_display_ioctl,
|
||||
.open = self_display_open,
|
||||
.release = self_display_release,
|
||||
.write = self_display_write,
|
||||
};
|
||||
|
||||
#define DEV_NAME_SIZE 24
|
||||
int self_display_init(struct samsung_display_driver_data *vdd)
|
||||
{
|
||||
int ret = 0;
|
||||
static char devname[DEV_NAME_SIZE] = {'\0', };
|
||||
|
||||
struct dsi_panel *panel = NULL;
|
||||
struct mipi_dsi_host *host = NULL;
|
||||
struct dsi_display *display = NULL;
|
||||
|
||||
if (IS_ERR_OR_NULL(vdd)) {
|
||||
LCD_ERR(vdd, "vdd is null or error\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!vdd->self_disp.is_support) {
|
||||
LCD_ERR(vdd, "Self Display is not supported\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
panel = (struct dsi_panel *)vdd->msm_private;
|
||||
host = panel->mipi_device.host;
|
||||
display = container_of(host, struct dsi_display, host);
|
||||
|
||||
mutex_init(&vdd->self_disp.vdd_self_display_lock);
|
||||
mutex_init(&vdd->self_disp.vdd_self_display_ioctl_lock);
|
||||
|
||||
if (vdd->ndx == PRIMARY_DISPLAY_NDX)
|
||||
snprintf(devname, DEV_NAME_SIZE, "self_display");
|
||||
else
|
||||
snprintf(devname, DEV_NAME_SIZE, "self_display%d", vdd->ndx);
|
||||
|
||||
vdd->self_disp.dev.minor = MISC_DYNAMIC_MINOR;
|
||||
vdd->self_disp.dev.name = devname;
|
||||
vdd->self_disp.dev.fops = &self_display_fops;
|
||||
vdd->self_disp.dev.parent = &display->pdev->dev;
|
||||
|
||||
vdd->self_disp.reset_status = self_display_reset_status;
|
||||
vdd->self_disp.aod_enter = self_display_aod_enter;
|
||||
vdd->self_disp.aod_exit = self_display_aod_exit;
|
||||
vdd->self_disp.self_mask_img_write = self_mask_img_write;
|
||||
vdd->self_disp.self_mask_on = self_mask_on;
|
||||
vdd->self_disp.self_mask_udc_on = self_mask_udc_on;
|
||||
vdd->self_disp.self_mask_check = self_mask_check;
|
||||
vdd->self_disp.self_partial_hlpm_scan_set = self_partial_hlpm_scan_set;
|
||||
vdd->self_disp.self_display_debug = self_display_debug;
|
||||
|
||||
vdd->self_disp.debug.SM_SUM_O = 0xFF; /* initial value */
|
||||
|
||||
ret = ss_wrapper_misc_register(vdd, &vdd->self_disp.dev);
|
||||
if (ret) {
|
||||
LCD_ERR(vdd, "failed to register driver : %d\n", ret);
|
||||
vdd->self_disp.is_support = false;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
register_op_sym_cb(vdd, "SELF_MASK_IMAGE", update_self_mask_image, true);
|
||||
register_op_sym_cb(vdd, "SELF_MASK_CRC_IMAGE", update_self_mask_crc_image, true);
|
||||
|
||||
LCD_INFO(vdd, "Success to register self_disp device..(%d)\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
MODULE_DESCRIPTION("Self Display driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -0,0 +1,197 @@
|
||||
/*
|
||||
*
|
||||
* Source file for Self Display Driver
|
||||
*
|
||||
* Copyright (c) 2019 Samsung Electronics
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* SELF DISLAY interface
|
||||
*
|
||||
* Author: Samsung display driver team
|
||||
* Company: Samsung Electronics
|
||||
*/
|
||||
|
||||
#ifndef _SELF_DISPLAY_H_
|
||||
#define _SELF_DISPLAY_H_
|
||||
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/file.h>
|
||||
|
||||
/* Align & Paylod Size for Embedded mode Transfer */
|
||||
#define CMD_ALIGN 16
|
||||
#define MAX_PAYLOAD_SIZE 200
|
||||
|
||||
/* Align & Paylod Size for Non-Embedded mode(Mass) Command Transfer */
|
||||
#define MASS_CMD_ALIGN 256
|
||||
#define MAX_PAYLOAD_SIZE_MASS 0xFFFF0 /* 983,024 */
|
||||
|
||||
/*
|
||||
* ioctl
|
||||
*/
|
||||
#define SELF_DISPLAY_IOCTL_MAGIC 'S'
|
||||
#define IOCTL_SELF_MOVE_EN _IOW(SELF_DISPLAY_IOCTL_MAGIC, 1, int)
|
||||
#define IOCTL_SELF_MOVE_OFF _IOW(SELF_DISPLAY_IOCTL_MAGIC, 2, int)
|
||||
#define IOCTL_SELF_MOVE_RESET _IOW(SELF_DISPLAY_IOCTL_MAGIC, 3, int)
|
||||
#define IOCTL_SET_TIME _IOW(SELF_DISPLAY_IOCTL_MAGIC, 11, struct self_time_info)
|
||||
#define IOCTL_SET_ICON _IOW(SELF_DISPLAY_IOCTL_MAGIC, 21, struct self_icon_info)
|
||||
#define IOCTL_SET_GRID _IOW(SELF_DISPLAY_IOCTL_MAGIC, 31, struct self_grid_info)
|
||||
#define IOCTL_SET_ANALOG_CLK _IOW(SELF_DISPLAY_IOCTL_MAGIC, 41, struct self_analog_clk_info)
|
||||
#define IOCTL_SET_DIGITAL_CLK _IOW(SELF_DISPLAY_IOCTL_MAGIC, 51, struct self_digital_clk_info)
|
||||
#define IOCTL_SET_PARTIAL_HLPM_SCAN _IOW(SELF_DISPLAY_IOCTL_MAGIC, 61, struct self_partial_hlpm_scan)
|
||||
#define IOCTL_SELF_MAX 70
|
||||
|
||||
|
||||
#define IMAGE_HEADER_SIZE 2
|
||||
#define IMAGE_HEADER_SELF_ICON "IC"
|
||||
#define IMAGE_HEADER_ANALOG_CLK "AC"
|
||||
#define IMAGE_HEADER_DIGITAL_CLK "DC"
|
||||
|
||||
#define ROTATE_0 0
|
||||
#define ROTATE_90 1
|
||||
#define ROTATE_180 2
|
||||
#define ROTATE_270 3
|
||||
|
||||
#define INTERVAL_100 0
|
||||
#define INTERVAL_200 1
|
||||
#define INTERVAL_500 2
|
||||
#define INTERVAL_1000 3
|
||||
#define INTERVAL_DEBUG 999
|
||||
|
||||
/*
|
||||
* data flag
|
||||
* This flag is used to distinguish what data will be passed and added at first 2byte of data.
|
||||
* ex ) ioctl write data : flag (2byte) + data (bytes)
|
||||
*/
|
||||
enum self_display_data_flag {
|
||||
FLAG_SELF_MOVE = 1,
|
||||
FLAG_SELF_MASK = 2,
|
||||
FLAG_SELF_ICON = 3,
|
||||
FLAG_SELF_GRID = 4,
|
||||
FLAG_SELF_ACLK = 5,
|
||||
FLAG_SELF_DCLK = 6,
|
||||
FLAG_SELF_VIDEO = 7,
|
||||
FLAG_SELF_MAFPC = 8,
|
||||
FLAG_SELF_MASK_CRC = 9,
|
||||
FLAG_SELF_DISP_MAX,
|
||||
};
|
||||
|
||||
struct self_time_info {
|
||||
u32 cur_h;
|
||||
u32 cur_m;
|
||||
u32 cur_s;
|
||||
u32 cur_ms;
|
||||
u32 disp_24h;
|
||||
u32 interval;
|
||||
};
|
||||
|
||||
struct self_icon_info {
|
||||
u32 en;
|
||||
u32 pos_x;
|
||||
u32 pos_y;
|
||||
u32 width;
|
||||
u32 height;
|
||||
u32 color;
|
||||
};
|
||||
|
||||
struct self_grid_info {
|
||||
u32 en;
|
||||
u32 s_pos_x;
|
||||
u32 s_pos_y;
|
||||
u32 e_pos_x;
|
||||
u32 e_pos_y;
|
||||
};
|
||||
|
||||
struct self_analog_clk_info {
|
||||
u32 en;
|
||||
u32 pos_x;
|
||||
u32 pos_y;
|
||||
u32 rotate;
|
||||
u32 mem_mask_en;
|
||||
u32 mem_reuse_en;
|
||||
};
|
||||
|
||||
struct self_digital_clk_info {
|
||||
u32 en;
|
||||
u32 en_hh;
|
||||
u32 en_mm;
|
||||
u32 pos1_x;
|
||||
u32 pos1_y;
|
||||
u32 pos2_x;
|
||||
u32 pos2_y;
|
||||
u32 pos3_x;
|
||||
u32 pos3_y;
|
||||
u32 pos4_x;
|
||||
u32 pos4_y;
|
||||
u32 img_width;
|
||||
u32 img_height;
|
||||
u32 color;
|
||||
u32 unicode_attr;
|
||||
u32 unicode_width;
|
||||
};
|
||||
|
||||
struct self_partial_hlpm_scan {
|
||||
u32 hlpm_en;
|
||||
u32 hlpm_mode_sel;
|
||||
u32 hlpm_area_1;
|
||||
u32 hlpm_area_2;
|
||||
u32 hlpm_area_3;
|
||||
u32 hlpm_area_4;
|
||||
u32 scan_en;
|
||||
u32 scan_sl;
|
||||
u32 scan_el;
|
||||
};
|
||||
|
||||
enum self_move {
|
||||
SELF_MOVE_OFF,
|
||||
SELF_MOVE_ON,
|
||||
SELF_MOVE_RESET,
|
||||
SELF_MOVE_MAX,
|
||||
};
|
||||
|
||||
struct self_display_op {
|
||||
bool select;
|
||||
bool on;
|
||||
u32 wpos;
|
||||
u64 wsize;
|
||||
|
||||
char *img_buf;
|
||||
u32 img_size;
|
||||
|
||||
int img_checksum;
|
||||
u32 img_checksum_cal;
|
||||
};
|
||||
|
||||
struct self_display_debug {
|
||||
u32 SI_X_O;
|
||||
u32 SI_Y_O;
|
||||
u32 MEM_SUM_O; /* sum of image data from side memory */
|
||||
u32 SM_SUM_O; /* sum of image data from self mask */
|
||||
u32 MEM_WR_DONE_O;
|
||||
u32 mem_wr_icon_pk_err_o;
|
||||
u32 mem_wr_var_pk_err_o;
|
||||
u32 sv_dec_err_fg_o;
|
||||
u32 scd_dec_err_fg_o;
|
||||
u32 si_dec_err_fg_o;
|
||||
u32 CUR_HH_O;
|
||||
u32 CUR_MM_O;
|
||||
u32 CUR_MSS_O;
|
||||
u32 CUR_SS_O;
|
||||
u32 SM_WR_DONE_O;
|
||||
u32 SM_PK_ERR_O;
|
||||
u32 SM_DEC_ERR_O;
|
||||
};
|
||||
|
||||
struct ss_cmd_desc;
|
||||
int self_display_init(struct samsung_display_driver_data *vdd);
|
||||
void make_self_dispaly_img_cmds(struct samsung_display_driver_data *vdd,
|
||||
int cmd, u32 op);
|
||||
int make_mass_self_display_img_cmds(struct samsung_display_driver_data *vdd,
|
||||
enum self_display_data_flag op, struct ss_cmd_desc *ss_cmd);
|
||||
#endif
|
@ -0,0 +1 @@
|
||||
export CONFIG_DISPLAY_SAMSUNG=y
|
@ -0,0 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#define CONFIG_DISPLAY_SAMSUNG 1
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1 @@
|
||||
Dummy
|
51
qcom/opensource/display-drivers/msm/samsung/ss_copr_common.c
Normal file
51
qcom/opensource/display-drivers/msm/samsung/ss_copr_common.c
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com/
|
||||
*
|
||||
* COPR :
|
||||
* Author: QC LCD driver <kr0124.cho@samsung.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include "ss_dsi_panel_common.h"
|
||||
#include "ss_copr_common.h"
|
||||
|
||||
void ss_set_copr_sum(struct samsung_display_driver_data *vdd, enum COPR_CD_INDEX idx)
|
||||
{
|
||||
s64 delta;
|
||||
|
||||
mutex_lock(&vdd->copr.copr_val_lock);
|
||||
vdd->copr.copr_cd[idx].last_t = vdd->copr.copr_cd[idx].cur_t;
|
||||
vdd->copr.copr_cd[idx].cur_t = ktime_get();
|
||||
delta = ktime_ms_delta(vdd->copr.copr_cd[idx].cur_t, vdd->copr.copr_cd[idx].last_t);
|
||||
vdd->copr.copr_cd[idx].total_t += delta;
|
||||
if (vdd->br_info.common_br.gamma_mode2_support)
|
||||
vdd->copr.copr_cd[idx].cd_sum += (vdd->br_info.common_br.cd_level * delta);
|
||||
|
||||
mutex_unlock(&vdd->copr.copr_val_lock);
|
||||
|
||||
LCD_DEBUG(vdd, "[%d] cd (%d) delta (%lld) cd_sum (%lld) total_t (%lld)\n",
|
||||
idx,
|
||||
vdd->br_info.common_br.cd_level,
|
||||
delta,
|
||||
vdd->copr.copr_cd[idx].cd_sum,
|
||||
vdd->copr.copr_cd[idx].total_t);
|
||||
}
|
||||
|
||||
int ss_copr_init(struct samsung_display_driver_data *vdd)
|
||||
{
|
||||
if (IS_ERR_OR_NULL(vdd)) {
|
||||
LCD_ERR(vdd, "vdd is null or error\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
mutex_init(&vdd->copr.copr_val_lock);
|
||||
mutex_init(&vdd->copr.copr_lock);
|
||||
|
||||
LCD_INFO(vdd, "Success to initialized copr\n");
|
||||
|
||||
return 0;
|
||||
}
|
46
qcom/opensource/display-drivers/msm/samsung/ss_copr_common.h
Normal file
46
qcom/opensource/display-drivers/msm/samsung/ss_copr_common.h
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com/
|
||||
*
|
||||
* COPR :
|
||||
* Author: QC LCD driver <kr0124.cho@samsung.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef __SS_COPR_COMMON_H__
|
||||
#define __SS_COPR_COMMON_H__
|
||||
|
||||
/* MAX COPR ROI is from copr ver. 3.0 */
|
||||
#define MAX_COPR_ROI_CNT 6
|
||||
|
||||
enum COPR_CD_INDEX {
|
||||
COPR_CD_INDEX_0, /* for copr show - SSRM */
|
||||
COPR_CD_INDEX_1, /* for brt_avg show - mDNIe */
|
||||
MAX_COPR_CD_INDEX,
|
||||
};
|
||||
|
||||
struct COPR_CD {
|
||||
s64 cd_sum;
|
||||
int cd_avr;
|
||||
|
||||
ktime_t cur_t;
|
||||
ktime_t last_t;
|
||||
s64 total_t;
|
||||
};
|
||||
|
||||
struct COPR {
|
||||
/* read data */
|
||||
struct mutex copr_lock;
|
||||
struct mutex copr_val_lock;
|
||||
|
||||
struct COPR_CD copr_cd[MAX_COPR_CD_INDEX];
|
||||
};
|
||||
|
||||
void ss_set_copr_sum(struct samsung_display_driver_data *vdd, enum COPR_CD_INDEX idx);
|
||||
|
||||
int ss_copr_init(struct samsung_display_driver_data *vdd);
|
||||
|
||||
#endif /* __SS_COPR_COMMON_H__ */
|
769
qcom/opensource/display-drivers/msm/samsung/ss_ddi_poc_common.c
Normal file
769
qcom/opensource/display-drivers/msm/samsung/ss_ddi_poc_common.c
Normal file
@ -0,0 +1,769 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com/
|
||||
*
|
||||
* Samsung's POC Driver
|
||||
* Author: ChangJae Jang <cj1225.jang@samsung.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include "ss_dsi_panel_common.h"
|
||||
#include "ss_ddi_poc_common.h"
|
||||
|
||||
/*
|
||||
* ERASE (SECTOR)
|
||||
* Erase operation is not a misc device file operation.
|
||||
* This is called from sysfs.
|
||||
*/
|
||||
static int ss_poc_erase_sector(struct samsung_display_driver_data *vdd, int start, int len)
|
||||
{
|
||||
// int pos = 0;
|
||||
int image_size = 0;
|
||||
int ret = 0;
|
||||
// int erase_size = 0;
|
||||
int target_pos = 0;
|
||||
|
||||
image_size = vdd->poc_driver.image_size;
|
||||
if(!start)
|
||||
start = vdd->poc_driver.start_addr;
|
||||
target_pos = start + len;
|
||||
|
||||
if (!ss_is_ready_to_send_cmd(vdd)) {
|
||||
LCD_INFO(vdd, "Panel is not ready. Panel State(%d)\n", vdd->panel_state);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (start < 0 || len <= 0) {
|
||||
LCD_INFO(vdd, "invalid sector erase params.. start(%d), len(%d)\n", start, len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((target_pos - start) > vdd->poc_driver.image_size) {
|
||||
LCD_INFO(vdd, "sould not erase over %d, start(%d) len(%d) target_pos(%d)\n",
|
||||
vdd->poc_driver.image_size, start, len, target_pos);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
LCD_INFO(vdd, "start(%d) len(%d) target(%d)\n", start, len, target_pos);
|
||||
|
||||
#if 0
|
||||
for (pos = start; pos < target_pos; pos += erase_size) {
|
||||
if (unlikely(atomic_read(&vdd->poc_driver.cancel))) {
|
||||
LCD_INFO(vdd, "cancel poc read by user\n");
|
||||
ret = -EIO;
|
||||
goto cancel_poc;
|
||||
}
|
||||
|
||||
if (vdd->poc_driver.poc_erase) {
|
||||
if (!(pos % POC_ERASE_64KB) && (pos + POC_ERASE_64KB <= target_pos))
|
||||
erase_size = POC_ERASE_64KB;
|
||||
else if (!(pos % POC_ERASE_32KB) && (pos + POC_ERASE_32KB <= target_pos))
|
||||
erase_size = POC_ERASE_32KB;
|
||||
else
|
||||
erase_size = POC_ERASE_4KB;
|
||||
|
||||
ret = vdd->poc_driver.poc_erase(vdd, pos, erase_size, target_pos);
|
||||
if (ret) {
|
||||
LCD_INFO(vdd, "fail to erase, pos(%d)\n", pos);
|
||||
return -EIO;
|
||||
}
|
||||
} else {
|
||||
LCD_INFO(vdd, "No poc_erase function. \n");
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (vdd->poc_driver.poc_erase)
|
||||
ret = vdd->poc_driver.poc_erase(vdd, start, len, target_pos);
|
||||
else
|
||||
LCD_ERR(vdd, "No poc_erase function..\n");
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
cancel_poc:
|
||||
if (unlikely(atomic_read(&vdd->poc_driver.cancel))) {
|
||||
LCD_INFO(vdd, "cancel poc read by user\n");
|
||||
atomic_set(&vdd->poc_driver.cancel, 0);
|
||||
ret = -EIO;
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ss_poc_write(struct samsung_display_driver_data *vdd, u8 *data, u32 write_pos, u32 write_size)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (!ss_is_ready_to_send_cmd(vdd)) {
|
||||
LCD_INFO(vdd, "Panel is not ready. Panel State(%d)\n", vdd->panel_state);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (vdd->poc_driver.poc_write) {
|
||||
ret = vdd->poc_driver.poc_write(vdd, data, write_pos, write_size);
|
||||
}
|
||||
else {
|
||||
LCD_INFO(vdd, "No poc_write function. \n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ss_poc_read(struct samsung_display_driver_data *vdd, u8 *buf, u32 read_pos, u32 read_size)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (!ss_is_ready_to_send_cmd(vdd)) {
|
||||
LCD_INFO(vdd, "Panel is not ready. Panel State(%d)\n", vdd->panel_state);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (vdd->poc_driver.poc_read) {
|
||||
ret = vdd->poc_driver.poc_read(vdd, buf, read_pos, read_size);
|
||||
}
|
||||
else {
|
||||
LCD_INFO(vdd, "No poc_read function. \n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if 0
|
||||
int ss_poc_read_mca(struct samsung_display_driver_data *vdd)
|
||||
{
|
||||
struct dsi_panel_cmd_set *mca_rx_cmds = NULL;
|
||||
int rx_len;
|
||||
|
||||
if (!vdd->poc_driver.is_support) {
|
||||
LCD_INFO(vdd, "Not Support POC Driver!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
mca_rx_cmds = ss_get_cmds(vdd, RX_POC_MCA_CHECK);
|
||||
if (SS_IS_CMDS_NULL(mca_rx_cmds)) {
|
||||
LCD_INFO(vdd, "no cmds for RX_POC_MCA_CHECK..\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
vdd->poc_driver.mca_size = mca_rx_cmds->cmds->msg.rx_len;
|
||||
LCD_INFO(vdd, "mca rx size (%d)\n", vdd->poc_driver.mca_size);
|
||||
|
||||
if (vdd->poc_driver.mca_size) {
|
||||
if (vdd->poc_driver.mca_data == NULL) {
|
||||
vdd->poc_driver.mca_data = kmalloc(vdd->poc_driver.mca_size, GFP_KERNEL);
|
||||
if (!vdd->poc_driver.mca_data) {
|
||||
LCD_INFO(vdd, "fail to kmalloc for mca_data\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LCD_INFO(vdd, "No rx size!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rx_len = ss_send_cmd_get_rx(vdd, RX_POC_MCA_CHECK, vdd->poc_driver.mca_data);
|
||||
if (rx_len < 0) {
|
||||
LCD_ERR(vdd, "failed to read_mca\n");
|
||||
return rx_len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void ss_poc_comp(struct samsung_display_driver_data *vdd)
|
||||
{
|
||||
if (vdd->poc_driver.poc_comp)
|
||||
vdd->poc_driver.poc_comp(vdd);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int ss_poc_checksum(struct samsung_display_driver_data *vdd)
|
||||
{
|
||||
LCD_INFO(vdd, "POC: checksum\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ss_poc_check_flash(struct samsung_display_driver_data *vdd)
|
||||
{
|
||||
LCD_INFO(vdd, "POC: check flash\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ss_dsi_poc_ctrl(struct samsung_display_driver_data *vdd, u32 cmd, const char *buf)
|
||||
{
|
||||
int ret = 0;
|
||||
int erase_start = 0;
|
||||
int erase_len = 0;
|
||||
|
||||
if (cmd >= MAX_POC_OP) {
|
||||
LCD_INFO(vdd, "invalid poc_op %d\n", cmd);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!vdd->poc_driver.is_support) {
|
||||
LCD_INFO(vdd, "Not Support POC Driver!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
LCD_INFO(vdd, " cmd = %d ++\n", cmd);
|
||||
switch (cmd) {
|
||||
case POC_OP_ERASE:
|
||||
break;
|
||||
case POC_OP_ERASE_SECTOR:
|
||||
if (buf == NULL) {
|
||||
LCD_INFO(vdd, "buf is null..\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = sscanf(buf, "%*d %d %d", &erase_start, &erase_len);
|
||||
if (unlikely(ret < 2)) {
|
||||
LCD_INFO(vdd, "fail to get erase param..\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
vdd->poc_driver.er_try_cnt++;
|
||||
ret = ss_poc_erase_sector(vdd, erase_start, erase_len);
|
||||
if (unlikely(ret < 0)) {
|
||||
LCD_INFO(vdd, "failed to poc-erase-sector-seq\n");
|
||||
vdd->poc_driver.er_fail_cnt++;
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
case POC_OP_WRITE:
|
||||
if (vdd->poc_driver.wbuf == NULL) {
|
||||
LCD_INFO(vdd, "poc_driver.wbuf is NULL\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = ss_poc_write(vdd,
|
||||
vdd->poc_driver.wbuf,
|
||||
POC_IMG_ADDR + vdd->poc_driver.wpos,
|
||||
vdd->poc_driver.wsize);
|
||||
if (unlikely(ret < 0)) {
|
||||
LCD_INFO(vdd, "failed to write poc-write-seq\n");
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
case POC_OP_READ:
|
||||
if (vdd->poc_driver.rbuf == NULL) {
|
||||
LCD_INFO(vdd, "poc_driver.rbuf is NULL\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = ss_poc_read(vdd,
|
||||
vdd->poc_driver.rbuf,
|
||||
POC_IMG_ADDR + vdd->poc_driver.rpos,
|
||||
vdd->poc_driver.rsize);
|
||||
if (unlikely(ret < 0)) {
|
||||
LCD_INFO(vdd, "failed to write poc-read-seq\n");
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
case POC_OP_ERASE_WRITE_IMG:
|
||||
break;
|
||||
case POC_OP_ERASE_WRITE_TEST:
|
||||
break;
|
||||
case POC_OP_BACKUP:
|
||||
break;
|
||||
case POC_OP_CHECKSUM:
|
||||
ss_poc_checksum(vdd);
|
||||
break;
|
||||
case POC_OP_CHECK_FLASH:
|
||||
ss_poc_check_flash(vdd);
|
||||
break;
|
||||
case POC_OP_SET_FLASH_WRITE:
|
||||
break;
|
||||
case POC_OP_SET_FLASH_EMPTY:
|
||||
break;
|
||||
case POC_OP_NONE:
|
||||
break;
|
||||
default:
|
||||
LCD_INFO(vdd, "%s invalid poc_op %d\n", __func__, cmd);
|
||||
break;
|
||||
}
|
||||
LCD_INFO(vdd, " cmd = %d --\n", cmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static long ss_dsi_poc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct miscdevice *c = file->private_data;
|
||||
struct dsi_display *display = dev_get_drvdata(c->parent);
|
||||
struct dsi_panel *panel = display->panel;
|
||||
struct samsung_display_driver_data *vdd = panel->panel_private;
|
||||
int ret = 0;
|
||||
|
||||
if (IS_ERR_OR_NULL(vdd)) {
|
||||
LCD_INFO(vdd, "no vdd\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!vdd->poc_driver.is_support) {
|
||||
LCD_INFO(vdd, "Not Support POC Driver!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!ss_is_ready_to_send_cmd(vdd)) {
|
||||
LCD_INFO(vdd, "Panel is not ready. Panel State(%d)\n", vdd->panel_state);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
LCD_INFO(vdd, "POC IOCTL CMD=%d\n", cmd);
|
||||
|
||||
switch (cmd) {
|
||||
case IOC_GET_POC_CHKSUM:
|
||||
ret = ss_dsi_poc_ctrl(vdd, POC_OP_CHECKSUM, NULL);
|
||||
if (ret) {
|
||||
LCD_INFO(vdd, "%s error set_panel_poc\n", __func__);
|
||||
ret = -EFAULT;
|
||||
}
|
||||
if (copy_to_user((u8 __user *)arg,
|
||||
&vdd->poc_driver.chksum_res,
|
||||
sizeof(vdd->poc_driver.chksum_res))) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case IOC_GET_POC_CSDATA:
|
||||
ret = ss_dsi_poc_ctrl(vdd, POC_OP_CHECKSUM, NULL);
|
||||
if (ret) {
|
||||
LCD_INFO(vdd, "%s error set_panel_poc\n", __func__);
|
||||
ret = -EFAULT;
|
||||
}
|
||||
if (copy_to_user((u8 __user *)arg,
|
||||
vdd->poc_driver.chksum_data,
|
||||
sizeof(vdd->poc_driver.chksum_data))) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
static atomic_t poc_open_check = ATOMIC_INIT(1); /* OPEN/RELEASE CHECK */
|
||||
|
||||
static int ss_dsi_poc_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct miscdevice *c = file->private_data;
|
||||
struct dsi_display *display = dev_get_drvdata(c->parent);
|
||||
struct dsi_panel *panel = display->panel;
|
||||
struct samsung_display_driver_data *vdd = panel->panel_private;
|
||||
int ret = 0;
|
||||
int image_size = 0;
|
||||
|
||||
LCD_INFO(vdd, "POC Open !!\n");
|
||||
|
||||
if (IS_ERR_OR_NULL(vdd)) {
|
||||
LCD_INFO(vdd, "no vdd\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (!vdd->poc_driver.is_support) {
|
||||
LCD_INFO(vdd, "Not Support POC Driver! \n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!atomic_dec_and_test (&poc_open_check)) {
|
||||
atomic_inc(&poc_open_check);
|
||||
LCD_INFO(vdd, "Already open_ongoing : counter (%d)\n", poc_open_check.counter);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
image_size = vdd->poc_driver.image_size;
|
||||
|
||||
if (likely(!vdd->poc_driver.wbuf)) {
|
||||
vdd->poc_driver.wbuf = vmalloc(image_size);
|
||||
if (unlikely(!vdd->poc_driver.wbuf)) {
|
||||
LCD_INFO(vdd, "%s: fail to allocate poc wbuf\n", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
vdd->poc_driver.wpos = 0;
|
||||
vdd->poc_driver.wsize = 0;
|
||||
|
||||
if (likely(!vdd->poc_driver.rbuf)) {
|
||||
vdd->poc_driver.rbuf = vmalloc(image_size);
|
||||
if (unlikely(!vdd->poc_driver.rbuf)) {
|
||||
vfree(vdd->poc_driver.wbuf);
|
||||
vdd->poc_driver.wbuf = NULL;
|
||||
LCD_INFO(vdd, "%s: fail to allocate poc rbuf\n", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
vdd->poc_driver.rpos = 0;
|
||||
vdd->poc_driver.rsize = 0;
|
||||
atomic_set(&vdd->poc_driver.cancel, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ss_dsi_poc_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct miscdevice *c = file->private_data;
|
||||
struct dsi_display *display = dev_get_drvdata(c->parent);
|
||||
struct dsi_panel *panel = display->panel;
|
||||
struct samsung_display_driver_data *vdd = panel->panel_private;
|
||||
int ret = 0;
|
||||
|
||||
LCD_INFO(vdd, "POC Release\n");
|
||||
|
||||
if (IS_ERR_OR_NULL(vdd)) {
|
||||
LCD_INFO(vdd, "no vdd\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (!vdd->poc_driver.is_support) {
|
||||
LCD_INFO(vdd, "Not Support POC Driver! \n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (unlikely(vdd->poc_driver.wbuf)) {
|
||||
vfree(vdd->poc_driver.wbuf);
|
||||
}
|
||||
|
||||
if (unlikely(vdd->poc_driver.rbuf)) {
|
||||
vfree(vdd->poc_driver.rbuf);
|
||||
}
|
||||
|
||||
vdd->poc_driver.wbuf = NULL;
|
||||
vdd->poc_driver.wpos = 0;
|
||||
vdd->poc_driver.wsize = 0;
|
||||
|
||||
vdd->poc_driver.rbuf = NULL;
|
||||
vdd->poc_driver.rpos = 0;
|
||||
vdd->poc_driver.rsize = 0;
|
||||
atomic_set(&vdd->poc_driver.cancel, 0);
|
||||
|
||||
atomic_inc(&poc_open_check);
|
||||
LCD_INFO(vdd, "poc_open counter (%d)\n", poc_open_check.counter); /* 1 */
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _ss_dsi_poc_read(struct samsung_display_driver_data *vdd, char __user *buf, size_t count,
|
||||
loff_t *ppos)
|
||||
{
|
||||
int image_size = 0;
|
||||
int ret = 0;
|
||||
|
||||
LCD_DEBUG(vdd, "ss_dsi_poc_read \n");
|
||||
|
||||
if (IS_ERR_OR_NULL(vdd)) {
|
||||
LCD_INFO(vdd, "no vdd");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!vdd->poc_driver.is_support) {
|
||||
LCD_INFO(vdd, "Not Support POC Driver! \n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (IS_ERR_OR_NULL(vdd->poc_driver.rbuf)) {
|
||||
LCD_INFO(vdd, "poc_driver.rbuf is NULL\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (unlikely(!buf)) {
|
||||
LCD_INFO(vdd, "invalid read buffer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
image_size = vdd->poc_driver.rx_size;
|
||||
|
||||
if (unlikely(*ppos == image_size)) {
|
||||
LCD_INFO(vdd, "read is done.. pos (%d), size (%d)\n", (int)*ppos, image_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (unlikely(*ppos < 0 || *ppos >= image_size)) {
|
||||
LCD_INFO(vdd, "invalid read pos (%d), size (%d)\n", (int)*ppos, image_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (unlikely(*ppos + count > image_size)) {
|
||||
LCD_INFO(vdd, "invalid read size, pos %d, count %d, size %d\n",
|
||||
(int)*ppos, (int)count, image_size);
|
||||
count = image_size - (int)*ppos;
|
||||
LCD_INFO(vdd, "resizing: pos %d, count %d, size %d",
|
||||
(int)*ppos, (int)count, image_size);
|
||||
}
|
||||
|
||||
vdd->poc_driver.rpos = *ppos + vdd->poc_driver.rx_addr;
|
||||
vdd->poc_driver.rsize = (u32)count;
|
||||
|
||||
LCD_INFO(vdd, "rpos 0x%X (%X + %X) rsize %d\n",
|
||||
vdd->poc_driver.rpos, (int)*ppos, vdd->poc_driver.rx_addr, vdd->poc_driver.rsize);
|
||||
|
||||
ret = ss_dsi_poc_ctrl(vdd, POC_OP_READ, NULL);
|
||||
if (ret) {
|
||||
LCD_INFO(vdd, "fail to read poc (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return simple_read_from_buffer(buf, count, ppos, vdd->poc_driver.rbuf, image_size);
|
||||
}
|
||||
|
||||
static ssize_t ss_dsi_poc_read(struct file *file, char __user *buf, size_t count,
|
||||
loff_t *ppos)
|
||||
{
|
||||
struct miscdevice *c = file->private_data;
|
||||
struct dsi_display *display = dev_get_drvdata(c->parent);
|
||||
struct dsi_panel *panel = display->panel;
|
||||
struct samsung_display_driver_data *vdd = panel->panel_private;
|
||||
int ret;
|
||||
|
||||
vdd->poc_driver.rd_try_cnt++;
|
||||
|
||||
ret = _ss_dsi_poc_read(vdd, buf, count, ppos);
|
||||
if (ret < 0) {
|
||||
LCD_INFO(vdd, "fail to poc read..\n");
|
||||
vdd->poc_driver.rd_fail_cnt++;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t _ss_dsi_poc_write(struct samsung_display_driver_data *vdd, const char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
int image_size = 0;
|
||||
int pos, ret = 0;
|
||||
|
||||
LCD_INFO(vdd, "ss_dsi_poc_write : count (%d), ppos(%d)\n", (int)count, (int)*ppos);
|
||||
|
||||
if (IS_ERR_OR_NULL(vdd)) {
|
||||
LCD_INFO(vdd, "no vdd");
|
||||
return -ENODEV;;
|
||||
}
|
||||
|
||||
if (!vdd->poc_driver.is_support) {
|
||||
LCD_INFO(vdd, "Not Support POC Driver! \n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (IS_ERR_OR_NULL(vdd->poc_driver.wbuf)) {
|
||||
LCD_INFO(vdd, "poc_driver.wbuf is NULL\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (unlikely(!buf)) {
|
||||
LCD_INFO(vdd, "invalid read buffer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
image_size = vdd->poc_driver.image_size;
|
||||
|
||||
if (unlikely(*ppos < 0 || *ppos >= image_size)) {
|
||||
LCD_INFO(vdd, "invalid write pos (%d) - size (%d)\n", (int)*ppos, image_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (unlikely(*ppos + count > image_size)) {
|
||||
LCD_INFO(vdd, "invalid write size pos %d, count %d, size %d\n",
|
||||
(int)*ppos, (int)count, image_size);
|
||||
count = image_size - (int)*ppos;
|
||||
LCD_INFO(vdd, "resizing: pos %d, count %d, size %d",
|
||||
(int)*ppos, (int)count, image_size);
|
||||
}
|
||||
|
||||
pos = (int)*ppos;
|
||||
vdd->poc_driver.wpos = *ppos + vdd->poc_driver.start_addr;
|
||||
vdd->poc_driver.wsize = (u32)count;
|
||||
|
||||
LCD_INFO(vdd, "wpos 0x%X (ppos 0x%X)/ wsize %d (0x%X) / total_image_size (%d)\n",
|
||||
vdd->poc_driver.wpos, (int)*ppos, vdd->poc_driver.wsize, vdd->poc_driver.wsize, image_size);
|
||||
|
||||
ret = simple_write_to_buffer(vdd->poc_driver.wbuf, image_size, ppos, buf, count);
|
||||
if (unlikely(ret < 0)) {
|
||||
LCD_INFO(vdd, "failed to simple_write_to_buffer \n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ss_dsi_poc_ctrl(vdd, POC_OP_WRITE, NULL);
|
||||
if (ret) {
|
||||
LCD_INFO(vdd, "fail to write poc (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
static ssize_t ss_dsi_poc_write(struct file *file, const char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct miscdevice *c = file->private_data;
|
||||
struct dsi_display *display = dev_get_drvdata(c->parent);
|
||||
struct dsi_panel *panel = display->panel;
|
||||
struct samsung_display_driver_data *vdd = panel->panel_private;
|
||||
int ret = 0;
|
||||
|
||||
vdd->poc_driver.wr_try_cnt++;
|
||||
|
||||
ret = _ss_dsi_poc_write(vdd, buf, count, ppos);
|
||||
if (ret < 0) {
|
||||
LCD_INFO(vdd, "fail to poc write..\n");
|
||||
vdd->poc_driver.wr_fail_cnt++;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
static const struct file_operations poc_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.read = ss_dsi_poc_read,
|
||||
.write = ss_dsi_poc_write,
|
||||
.unlocked_ioctl = ss_dsi_poc_ioctl,
|
||||
.open = ss_dsi_poc_open,
|
||||
.release = ss_dsi_poc_release,
|
||||
.llseek = generic_file_llseek,
|
||||
};
|
||||
|
||||
#define EPOCEFS_IMGIDX (100)
|
||||
enum {
|
||||
EPOCEFS_NOENT = 1, /* No such file or directory */
|
||||
EPOCEFS_EMPTY = 2, /* Empty file */
|
||||
EPOCEFS_READ = 3, /* Read failed */
|
||||
MAX_EPOCEFS,
|
||||
};
|
||||
|
||||
#define POC_TOTAL_TRY_COUNT_FILE_PATH ("/efs/afc/apply_count")
|
||||
#define POC_TOTAL_FAIL_COUNT_FILE_PATH ("/efs/afc/fail_count")
|
||||
#define POC_INFO_FILE_PATH ("/efs/FactoryApp/poc_info")
|
||||
#define POC_USER_FILE_PATH ("/efs/FactoryApp/poc_user")
|
||||
|
||||
__visible_for_testing int poc_dpui_notifier_callback(struct notifier_block *self,
|
||||
unsigned long event, void *data)
|
||||
{
|
||||
struct POC *poc = container_of(self, struct POC, dpui_notif);
|
||||
struct samsung_display_driver_data *vdd = container_of(poc, struct samsung_display_driver_data, poc_driver);
|
||||
char tbuf[MAX_DPUI_VAL_LEN];
|
||||
int total_fail_cnt = 0;
|
||||
int total_try_cnt = 0;
|
||||
int size = 0, poci = 0, poci_org = 0;
|
||||
|
||||
if (poc == NULL) {
|
||||
LCD_INFO(vdd, "err: poc is null\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!vdd->poc_driver.is_support) {
|
||||
LCD_INFO(vdd, "Not Support POC Driver!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
size = scnprintf(tbuf, MAX_DPUI_VAL_LEN, "%d", total_try_cnt);
|
||||
set_dpui_field(DPUI_KEY_PNPOCT, tbuf, size);
|
||||
|
||||
size = scnprintf(tbuf, MAX_DPUI_VAL_LEN, "%d", total_fail_cnt);
|
||||
set_dpui_field(DPUI_KEY_PNPOCF, tbuf, size);
|
||||
|
||||
size = scnprintf(tbuf, MAX_DPUI_VAL_LEN, "%d", poci_org);
|
||||
set_dpui_field(DPUI_KEY_PNPOCI_ORG, tbuf, size);
|
||||
|
||||
size = scnprintf(tbuf, MAX_DPUI_VAL_LEN, "%d", poci);
|
||||
set_dpui_field(DPUI_KEY_PNPOCI, tbuf, size);
|
||||
|
||||
inc_dpui_u32_field(DPUI_KEY_PNPOC_ER_TRY, poc->er_try_cnt);
|
||||
inc_dpui_u32_field(DPUI_KEY_PNPOC_ER_FAIL, poc->er_fail_cnt);
|
||||
inc_dpui_u32_field(DPUI_KEY_PNPOC_WR_TRY, poc->wr_try_cnt);
|
||||
inc_dpui_u32_field(DPUI_KEY_PNPOC_WR_FAIL, poc->wr_fail_cnt);
|
||||
inc_dpui_u32_field(DPUI_KEY_PNPOC_RD_TRY, poc->rd_try_cnt);
|
||||
inc_dpui_u32_field(DPUI_KEY_PNPOC_RD_FAIL, poc->rd_fail_cnt);
|
||||
|
||||
LCD_INFO(vdd, "poc dpui: try=%d, fail=%d, id=%d, %d\n",
|
||||
total_try_cnt, total_fail_cnt, poci, poci_org);
|
||||
LCD_INFO(vdd, "poc dpui: er (%d/%d), wr (%d/%d), rd (%d/%d)\n",
|
||||
poc->er_try_cnt, poc->er_fail_cnt,
|
||||
poc->wr_try_cnt, poc->wr_fail_cnt,
|
||||
poc->rd_try_cnt, poc->rd_fail_cnt);
|
||||
|
||||
poc->er_try_cnt = 0;
|
||||
poc->er_fail_cnt = 0;
|
||||
poc->wr_try_cnt = 0;
|
||||
poc->wr_fail_cnt = 0;
|
||||
poc->rd_try_cnt = 0;
|
||||
poc->rd_fail_cnt = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ss_dsi_poc_register_dpui(struct POC *poc)
|
||||
{
|
||||
memset(&poc->dpui_notif, 0,
|
||||
sizeof(poc->dpui_notif));
|
||||
poc->dpui_notif.notifier_call = poc_dpui_notifier_callback;
|
||||
|
||||
return dpui_logging_register(&poc->dpui_notif, DPUI_TYPE_PANEL);
|
||||
}
|
||||
|
||||
#define POC_DEV_NAME_SIZE 10
|
||||
int ss_dsi_poc_init(struct samsung_display_driver_data *vdd)
|
||||
{
|
||||
int ret;
|
||||
static char devname[POC_DEV_NAME_SIZE] = {'\0', };
|
||||
|
||||
struct dsi_panel *panel = NULL;
|
||||
struct mipi_dsi_host *host = NULL;
|
||||
struct dsi_display *display = NULL;
|
||||
|
||||
if (IS_ERR_OR_NULL(vdd)) {
|
||||
LCD_INFO(vdd, "no vdd");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!vdd->poc_driver.is_support) {
|
||||
LCD_INFO(vdd, "Not Support POC Driver!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
LCD_INFO(vdd, "++\n");
|
||||
|
||||
panel = (struct dsi_panel *)vdd->msm_private;
|
||||
host = panel->mipi_device.host;
|
||||
display = container_of(host, struct dsi_display, host);
|
||||
|
||||
if (vdd->ndx == PRIMARY_DISPLAY_NDX)
|
||||
snprintf(devname, POC_DEV_NAME_SIZE, "poc");
|
||||
else
|
||||
snprintf(devname, POC_DEV_NAME_SIZE, "poc%d", vdd->ndx);
|
||||
|
||||
vdd->poc_driver.dev.minor = MISC_DYNAMIC_MINOR;
|
||||
vdd->poc_driver.dev.name = devname;
|
||||
vdd->poc_driver.dev.fops = &poc_fops;
|
||||
vdd->poc_driver.dev.parent = &display->pdev->dev;
|
||||
|
||||
vdd->poc_driver.wbuf = NULL;
|
||||
vdd->poc_driver.rbuf = NULL;
|
||||
atomic_set(&vdd->poc_driver.cancel, 0);
|
||||
|
||||
/* Drvier level big data for POC operation */
|
||||
vdd->poc_driver.er_try_cnt = 0;
|
||||
vdd->poc_driver.er_fail_cnt = 0;
|
||||
vdd->poc_driver.wr_try_cnt = 0;
|
||||
vdd->poc_driver.wr_fail_cnt = 0;
|
||||
vdd->poc_driver.rd_try_cnt = 0;
|
||||
vdd->poc_driver.rd_fail_cnt = 0;
|
||||
|
||||
vdd->panel_func.samsung_poc_ctrl = ss_dsi_poc_ctrl;
|
||||
|
||||
ret = ss_wrapper_misc_register(vdd, &vdd->poc_driver.dev);
|
||||
if (ret) {
|
||||
LCD_INFO(vdd, "failed to register POC driver : %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ss_dsi_poc_register_dpui(&vdd->poc_driver);
|
||||
|
||||
LCD_INFO(vdd, "--\n");
|
||||
return ret;
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com/
|
||||
*
|
||||
* Samsung's POC Driver
|
||||
* Author: ChangJae Jang <cj1225.jang@samsung.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#ifndef SAMSUNG_POC_COMMON_H
|
||||
#define SAMSUNG_POC_COMMON_H
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#define POC_IMG_ADDR (0x000000)
|
||||
#define POC_ERASE_4KB (4096)
|
||||
#define POC_ERASE_32KB (32768)
|
||||
#define POC_ERASE_64KB (65536)
|
||||
|
||||
#define DEBUG_POC_CNT 4096
|
||||
|
||||
int ss_dsi_poc_init(struct samsung_display_driver_data *vdd);
|
||||
int ss_poc_read_mca(struct samsung_display_driver_data *vdd);
|
||||
void ss_poc_comp(struct samsung_display_driver_data *vdd);
|
||||
|
||||
#endif
|
362
qcom/opensource/display-drivers/msm/samsung/ss_dpui_common.c
Normal file
362
qcom/opensource/display-drivers/msm/samsung/ss_dpui_common.c
Normal file
@ -0,0 +1,362 @@
|
||||
/*
|
||||
* Samsung Common LCD DPUI(display use info) LOGGING Driver.
|
||||
*
|
||||
* Copyright (c) 2017 Samsung Electronics
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/fb.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/export.h>
|
||||
#include "ss_dpui_common.h"
|
||||
|
||||
/*
|
||||
* DPUI : display use info (panel common info)
|
||||
* DPCI : display controller info (ap dependent info)
|
||||
*/
|
||||
static BLOCKING_NOTIFIER_HEAD(dpui_notifier_list);
|
||||
static BLOCKING_NOTIFIER_HEAD(dpci_notifier_list);
|
||||
static DEFINE_MUTEX(dpui_lock);
|
||||
|
||||
/**
|
||||
* dpui_logging_notify - notify clients of fb_events
|
||||
* @val: dpui log type
|
||||
* @v : data
|
||||
*
|
||||
*/
|
||||
void dpui_logging_notify(unsigned long val, enum dpui_type type, void *v)
|
||||
{
|
||||
if (type == DPUI_TYPE_CTRL)
|
||||
blocking_notifier_call_chain(&dpci_notifier_list, val, v);
|
||||
else
|
||||
blocking_notifier_call_chain(&dpui_notifier_list, val, v);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dpui_logging_notify);
|
||||
|
||||
/**
|
||||
* dpui_logging_register - register a client notifier
|
||||
* @n: notifier block to callback on events
|
||||
*/
|
||||
int dpui_logging_register(struct notifier_block *n, enum dpui_type type)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (type <= DPUI_TYPE_NONE || type >= MAX_DPUI_TYPE) {
|
||||
pr_err("%s out of dpui_type range (%d)\n", __func__, type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (type == DPUI_TYPE_CTRL)
|
||||
ret = blocking_notifier_chain_register(&dpci_notifier_list, n);
|
||||
else
|
||||
ret = blocking_notifier_chain_register(&dpui_notifier_list, n);
|
||||
if (ret < 0) {
|
||||
pr_err("%s: blocking_notifier_chain_register error(%d)\n",
|
||||
__func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
pr_info("%s register type %s\n", __func__, dpui_type_name[type]);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dpui_logging_register);
|
||||
|
||||
/**
|
||||
* dpui_logging_unregister - unregister a client notifier
|
||||
* @n: notifier block to callback on events
|
||||
*/
|
||||
int dpui_logging_unregister(struct notifier_block *n)
|
||||
{
|
||||
return blocking_notifier_chain_unregister(&dpui_notifier_list, n);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dpui_logging_unregister);
|
||||
|
||||
static bool is_dpui_var_u32(enum dpui_key key)
|
||||
{
|
||||
return (dpui.field[key].var_type == DPUI_VAR_U32);
|
||||
}
|
||||
|
||||
void update_dpui_log(enum dpui_log_level level, enum dpui_type type)
|
||||
{
|
||||
if (level < 0 || level >= MAX_DPUI_LOG_LEVEL) {
|
||||
pr_err("%s invalid log level %d\n", __func__, level);
|
||||
return;
|
||||
}
|
||||
|
||||
dpui_logging_notify(level, type, &dpui);
|
||||
pr_info("%s update dpui log(%d) done\n",
|
||||
__func__, level);
|
||||
}
|
||||
|
||||
int clear_dpui_log(enum dpui_log_level level, enum dpui_type type)
|
||||
{
|
||||
int i;
|
||||
int ret = 0;
|
||||
|
||||
if (level < 0 || level >= MAX_DPUI_LOG_LEVEL) {
|
||||
pr_err("%s invalid log level %d\n", __func__, level);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&dpui_lock);
|
||||
for (i = 0; i < ARRAY_SIZE(dpui.field); i++) {
|
||||
if (dpui.field[i].type != type)
|
||||
continue;
|
||||
if (dpui.field[i].auto_clear)
|
||||
dpui.field[i].initialized = false;
|
||||
}
|
||||
mutex_unlock(&dpui_lock);
|
||||
|
||||
pr_info("%s clear dpui log(%d) done\n",
|
||||
__func__, level);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __get_dpui_field(enum dpui_key key, char *buf)
|
||||
{
|
||||
if (!buf) {
|
||||
pr_err("%s buf is null\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!DPUI_VALID_KEY(key)) {
|
||||
pr_err("%s out of dpui_key range (%d)\n", __func__, key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!dpui.field[key].initialized) {
|
||||
pr_debug("%s DPUI:%s not initialized, so use default value\n",
|
||||
__func__, dpui_key_name[key]);
|
||||
return snprintf(buf, MAX_DPUI_KEY_LEN + MAX_DPUI_VAL_LEN,
|
||||
"\"%s\":\"%s\"", dpui_key_name[key], dpui.field[key].default_value);
|
||||
}
|
||||
|
||||
return snprintf(buf, MAX_DPUI_KEY_LEN + MAX_DPUI_VAL_LEN,
|
||||
"\"%s\":\"%s\"", dpui_key_name[key], dpui.field[key].buf);
|
||||
}
|
||||
|
||||
void print_dpui_field(enum dpui_key key)
|
||||
{
|
||||
char tbuf[MAX_DPUI_KEY_LEN + MAX_DPUI_VAL_LEN];
|
||||
|
||||
if (!DPUI_VALID_KEY(key)) {
|
||||
pr_err("%s out of dpui_key range (%d)\n", __func__, key);
|
||||
return;
|
||||
}
|
||||
|
||||
__get_dpui_field(key, tbuf);
|
||||
pr_info("DPUI: %s\n", tbuf);
|
||||
}
|
||||
|
||||
static int __set_dpui_field(enum dpui_key key, char *buf, int size)
|
||||
{
|
||||
if (!buf) {
|
||||
pr_err("%s buf is null\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!DPUI_VALID_KEY(key)) {
|
||||
pr_err("%s out of dpui_key range (%d)\n", __func__, key);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (size > MAX_DPUI_VAL_LEN - 1) {
|
||||
pr_err("%s exceed dpui value size (%d)\n", __func__, size);
|
||||
return -EINVAL;
|
||||
}
|
||||
memcpy(dpui.field[key].buf, buf, size);
|
||||
dpui.field[key].buf[size] = '\0';
|
||||
dpui.field[key].initialized = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __get_dpui_u32_field(enum dpui_key key, u32 *value)
|
||||
{
|
||||
int rc, cur_val;
|
||||
|
||||
if (value == NULL) {
|
||||
pr_err("%s invalid value pointer\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!DPUI_VALID_KEY(key)) {
|
||||
pr_err("%s out of dpui_key range (%d)\n", __func__, key);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = kstrtouint(dpui.field[key].buf, (unsigned int)0, &cur_val);
|
||||
if (rc < 0) {
|
||||
pr_err("%s failed to get value\n", __func__);
|
||||
return rc;
|
||||
}
|
||||
|
||||
*value = cur_val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __set_dpui_u32_field(enum dpui_key key, u32 value)
|
||||
{
|
||||
char tbuf[MAX_DPUI_VAL_LEN];
|
||||
int size;
|
||||
|
||||
if (!DPUI_VALID_KEY(key)) {
|
||||
pr_err("%s out of dpui_key range (%d)\n", __func__, key);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!is_dpui_var_u32(key)) {
|
||||
pr_err("%s invalid type %d\n", __func__, dpui.field[key].var_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
size = snprintf(tbuf, MAX_DPUI_VAL_LEN, "%u", value);
|
||||
if (size > MAX_DPUI_VAL_LEN) {
|
||||
pr_err("%s exceed dpui value size (%d)\n", __func__, size);
|
||||
return -EINVAL;
|
||||
}
|
||||
__set_dpui_field(key, tbuf, size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __inc_dpui_u32_field(enum dpui_key key, u32 value)
|
||||
{
|
||||
int ret;
|
||||
u32 cur_val = 0;
|
||||
|
||||
if (!DPUI_VALID_KEY(key)) {
|
||||
pr_err("%s out of dpui_key range (%d)\n", __func__, key);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!is_dpui_var_u32(key)) {
|
||||
pr_err("%s invalid type %d\n", __func__, dpui.field[key].var_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (dpui.field[key].initialized) {
|
||||
ret = __get_dpui_u32_field(key, &cur_val);
|
||||
if (ret < 0) {
|
||||
pr_err("%s failed to get u32 field (%d)\n", __func__, ret);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
__set_dpui_u32_field(key, cur_val + value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_dpui_field(enum dpui_key key, char *buf)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&dpui_lock);
|
||||
ret = __get_dpui_field(key, buf);
|
||||
mutex_unlock(&dpui_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int set_dpui_field(enum dpui_key key, char *buf, int size)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&dpui_lock);
|
||||
ret = __set_dpui_field(key, buf, size);
|
||||
mutex_unlock(&dpui_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int get_dpui_u32_field(enum dpui_key key, u32 *value)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&dpui_lock);
|
||||
ret = __get_dpui_u32_field(key, value);
|
||||
mutex_unlock(&dpui_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int set_dpui_u32_field(enum dpui_key key, u32 value)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&dpui_lock);
|
||||
ret = __set_dpui_u32_field(key, value);
|
||||
mutex_unlock(&dpui_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int inc_dpui_u32_field(enum dpui_key key, u32 value)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&dpui_lock);
|
||||
ret = __inc_dpui_u32_field(key, value);
|
||||
mutex_unlock(&dpui_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(inc_dpui_u32_field);
|
||||
|
||||
int inc_dpui_u32_field_nolock(enum dpui_key key, u32 value)
|
||||
{
|
||||
return __inc_dpui_u32_field(key, value);
|
||||
}
|
||||
|
||||
int __get_dpui_log(char *buf, enum dpui_log_level level, enum dpui_type type)
|
||||
{
|
||||
int i, ret, len = 0;
|
||||
char tbuf[MAX_DPUI_KEY_LEN + MAX_DPUI_VAL_LEN];
|
||||
|
||||
if (!buf) {
|
||||
pr_err("%s buf is null\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (level < 0 || level >= MAX_DPUI_LOG_LEVEL) {
|
||||
pr_err("%s invalid log level %d\n", __func__, level);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&dpui_lock);
|
||||
for (i = DPUI_KEY_NONE + 1; i < MAX_DPUI_KEY; i++) {
|
||||
if (level != DPUI_LOG_LEVEL_ALL && dpui.field[i].level != level) {
|
||||
pr_warn("%s DPUI:%s different log level %d %d\n",
|
||||
__func__, dpui_key_name[dpui.field[i].key],
|
||||
dpui.field[i].level, level);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (type != dpui.field[i].type)
|
||||
continue;
|
||||
|
||||
ret = __get_dpui_field(i, tbuf);
|
||||
if (ret == 0)
|
||||
continue;
|
||||
|
||||
if (len)
|
||||
len += snprintf(buf + len, 3, ",");
|
||||
len += snprintf(buf + len, MAX_DPUI_KEY_LEN + MAX_DPUI_VAL_LEN,
|
||||
"%s", tbuf);
|
||||
}
|
||||
mutex_unlock(&dpui_lock);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int get_dpui_log(char *buf, enum dpui_log_level level, enum dpui_type type)
|
||||
{
|
||||
return __get_dpui_log(buf, level, type);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(get_dpui_log);
|
322
qcom/opensource/display-drivers/msm/samsung/ss_dpui_common.h
Normal file
322
qcom/opensource/display-drivers/msm/samsung/ss_dpui_common.h
Normal file
@ -0,0 +1,322 @@
|
||||
/*
|
||||
* Header file for Samsung Common LCD Driver.
|
||||
*
|
||||
* Copyright (c) 2017 Samsung Electronics
|
||||
* Gwanghui Lee <gwanghui.lee@samsung.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef __DPUI_H__
|
||||
#define __DPUI_H__
|
||||
|
||||
#define MAX_DPUI_KEY_LEN (20)
|
||||
/* Increase buf size for SS LOG.
|
||||
* TODO: Instead of fixed length, allocate buf dynamically using kmalloc.
|
||||
*/
|
||||
#define MAX_DPUI_VAL_LEN (700) // (128)
|
||||
|
||||
enum {
|
||||
DPUI_AUTO_CLEAR_OFF,
|
||||
DPUI_AUTO_CLEAR_ON,
|
||||
MAX_DPUI_AUTO_CLEAR,
|
||||
};
|
||||
|
||||
enum dpui_log_level {
|
||||
DPUI_LOG_LEVEL_DEBUG,
|
||||
DPUI_LOG_LEVEL_INFO,
|
||||
DPUI_LOG_LEVEL_ALL,
|
||||
MAX_DPUI_LOG_LEVEL,
|
||||
};
|
||||
|
||||
enum dpui_type {
|
||||
DPUI_TYPE_NONE,
|
||||
DPUI_TYPE_PANEL,
|
||||
DPUI_TYPE_CTRL,
|
||||
MAX_DPUI_TYPE,
|
||||
};
|
||||
|
||||
enum dpui_var_type {
|
||||
DPUI_VAR_BOOL,
|
||||
DPUI_VAR_S32,
|
||||
DPUI_VAR_S64,
|
||||
DPUI_VAR_U32,
|
||||
DPUI_VAR_U64,
|
||||
DPUI_VAR_STR,
|
||||
MAX_DPUI_VAR_TYPE,
|
||||
};
|
||||
|
||||
#define DPUI_VALID_VAR_TYPE(_vtype_) \
|
||||
(((_vtype_) >= DPUI_VAR_BOOL) && ((_vtype_) < MAX_DPUI_VAR_TYPE))
|
||||
|
||||
enum dpui_key {
|
||||
DPUI_KEY_NONE,
|
||||
DPUI_KEY_WCRD_X, /* white color x-coordinate */
|
||||
DPUI_KEY_WCRD_Y, /* white color y-coordinate */
|
||||
DPUI_KEY_WOFS_R, /* mdnie whiteRGB red offset from user and factory */
|
||||
DPUI_KEY_WOFS_G, /* mdnie whiteRGB green offset from user and factory */
|
||||
DPUI_KEY_WOFS_B, /* mdnie whiteRGB blue offset from user and factory */
|
||||
DPUI_KEY_WOFS_R_ORG, /* mdnie whiteRGB red offset from factory */
|
||||
DPUI_KEY_WOFS_G_ORG, /* mdnie whiteRGB green offset from factory */
|
||||
DPUI_KEY_WOFS_B_ORG, /* mdnie whiteRGB blue offset from factory */
|
||||
DPUI_KEY_LCDID1, /* panel id 1 */
|
||||
DPUI_KEY_LCDID2, /* panel id 2 */
|
||||
DPUI_KEY_LCDID3, /* panel id 3 */
|
||||
DPUI_KEY_MAID_DATE, /* panel manufacture date */
|
||||
DPUI_KEY_CELLID, /* panel cell id */
|
||||
DPUI_KEY_OCTAID, /* panel octa id */
|
||||
DPUI_KEY_PNDSIE, /* panel dsi error count */
|
||||
DPUI_KEY_PNELVDE, /* panel ELVDD error count */
|
||||
DPUI_KEY_PNVLI1E, /* panel VLIN1 error count */
|
||||
DPUI_KEY_PNVLO3E, /* panel VLOUT3 error count */
|
||||
DPUI_KEY_PNSDRE, /* panel OTP loading error count */
|
||||
/* POC */
|
||||
DPUI_KEY_PNPOCT, /* panel POC try count */
|
||||
DPUI_KEY_PNPOCF, /* panel POC fail count */
|
||||
DPUI_KEY_PNPOCI, /* panel POC image index */
|
||||
DPUI_KEY_PNPOCI_ORG, /* panel POC image index in factory */
|
||||
DPUI_KEY_PNPOC_ER_TRY, /* panel POC erase try count */
|
||||
DPUI_KEY_PNPOC_ER_FAIL, /* panel POC erase fail count */
|
||||
DPUI_KEY_PNPOC_WR_TRY, /* panel POC write try count */
|
||||
DPUI_KEY_PNPOC_WR_FAIL, /* panel POC write fail count */
|
||||
DPUI_KEY_PNPOC_RD_TRY, /* panel POC read try count */
|
||||
DPUI_KEY_PNPOC_RD_FAIL, /* panel POC read fail count */
|
||||
/* GAMMA FLASH */
|
||||
DPUI_KEY_PNGFLS, /* panel gamma flash loading result */
|
||||
/* dependent on processor */
|
||||
DPUI_KEY_QCT_DSIE, /* display controller dsi error count */
|
||||
DPUI_KEY_QCT_PPTO, /* display controller pingpong timeout count */
|
||||
DPUI_KEY_QCT_NO_TE, /* display controller no TE response count */
|
||||
DPUI_KEY_QCT_RCV_CNT, /* display controller ESD recovery count */
|
||||
DPUI_KEY_QCT_SSLOG, /* display controller ss debugging log */
|
||||
DPUI_KEY_QCT_MAIN_RX_FAIL_CNT, /* main display mipi rx fail count */
|
||||
DPUI_KEY_QCT_SUB_RX_FAIL_CNT, /* sub display mipi rx fail count */
|
||||
|
||||
/* GPU */
|
||||
DPUI_KEY_QCT_GPU_PF, /* GPU Page Fault Count */
|
||||
|
||||
DPUI_KEY_UB_CON, /* UB con detect */
|
||||
DPUI_KEY_SUB_UB_CON, /* SUB UB con detect */
|
||||
|
||||
DPUI_KEY_ECC_ERR, /* ECC Error */
|
||||
DPUI_KEY_FLASH_LOAD, /* Flash loading failure count */
|
||||
|
||||
MAX_DPUI_KEY,
|
||||
};
|
||||
|
||||
|
||||
#define DPUI_VALID_KEY(_key_) \
|
||||
(((_key_) > DPUI_KEY_NONE) && ((_key_) < MAX_DPUI_KEY))
|
||||
|
||||
struct dpui_field {
|
||||
enum dpui_type type;
|
||||
enum dpui_var_type var_type;
|
||||
bool auto_clear;
|
||||
bool initialized;
|
||||
enum dpui_key key;
|
||||
enum dpui_log_level level;
|
||||
char *default_value;
|
||||
char buf[MAX_DPUI_VAL_LEN];
|
||||
};
|
||||
|
||||
#define DPUI_FIELD_INIT(_level_, _type_, _var_type_, _auto_clr_, _default_val_, _key_) \
|
||||
[(_key_)] = { \
|
||||
.type = (_type_), \
|
||||
.var_type = (_var_type_), \
|
||||
.auto_clear = (_auto_clr_), \
|
||||
.initialized = (false), \
|
||||
.key = (_key_), \
|
||||
.level = (_level_), \
|
||||
.default_value = (_default_val_), \
|
||||
.buf[0] = ('\0'), \
|
||||
}
|
||||
|
||||
struct dpui_info {
|
||||
void *pdata;
|
||||
struct dpui_field field[MAX_DPUI_KEY];
|
||||
};
|
||||
|
||||
static const char * const dpui_key_name[] = {
|
||||
[DPUI_KEY_NONE] = "NONE",
|
||||
/* common hw parameter */
|
||||
[DPUI_KEY_WCRD_X] = "WCRD_X",
|
||||
[DPUI_KEY_WCRD_Y] = "WCRD_Y",
|
||||
[DPUI_KEY_WOFS_R] = "WOFS_R",
|
||||
[DPUI_KEY_WOFS_G] = "WOFS_G",
|
||||
[DPUI_KEY_WOFS_B] = "WOFS_B",
|
||||
[DPUI_KEY_WOFS_R_ORG] = "WOFS_R_ORG",
|
||||
[DPUI_KEY_WOFS_G_ORG] = "WOFS_G_ORG",
|
||||
[DPUI_KEY_WOFS_B_ORG] = "WOFS_B_ORG",
|
||||
[DPUI_KEY_LCDID1] = "LCDM_ID1",
|
||||
[DPUI_KEY_LCDID2] = "LCDM_ID2",
|
||||
[DPUI_KEY_LCDID3] = "LCDM_ID3",
|
||||
[DPUI_KEY_MAID_DATE] = "MAID_DATE",
|
||||
[DPUI_KEY_CELLID] = "CELLID",
|
||||
[DPUI_KEY_OCTAID] = "OCTAID",
|
||||
[DPUI_KEY_PNDSIE] = "PNDSIE",
|
||||
[DPUI_KEY_PNELVDE] = "PNELVDE",
|
||||
[DPUI_KEY_PNVLI1E] = "PNVLI1E",
|
||||
[DPUI_KEY_PNVLO3E] = "PNVLO3E",
|
||||
[DPUI_KEY_PNSDRE] = "PNSDRE",
|
||||
[DPUI_KEY_PNPOCT] = "PNPOCT",
|
||||
[DPUI_KEY_PNPOCF] = "PNPOCF",
|
||||
[DPUI_KEY_PNPOCI] = "PNPOCI",
|
||||
[DPUI_KEY_PNPOCI_ORG] = "PNPOCI_ORG",
|
||||
[DPUI_KEY_PNPOC_ER_TRY] = "PNPOC_ER_T",
|
||||
[DPUI_KEY_PNPOC_ER_FAIL] = "PNPOC_ER_F",
|
||||
[DPUI_KEY_PNPOC_WR_TRY] = "PNPOC_WR_T",
|
||||
[DPUI_KEY_PNPOC_WR_FAIL] = "PNPOC_WR_F",
|
||||
[DPUI_KEY_PNPOC_RD_TRY] = "PNPOC_RD_T",
|
||||
[DPUI_KEY_PNPOC_RD_FAIL] = "PNPOC_RD_F",
|
||||
|
||||
[DPUI_KEY_PNGFLS] = "PNGFLS",
|
||||
|
||||
/* dependent on processor */
|
||||
[DPUI_KEY_QCT_DSIE] = "QCT_DSIE",
|
||||
[DPUI_KEY_QCT_PPTO] = "QCT_PPTO",
|
||||
[DPUI_KEY_QCT_NO_TE] = "QCT_NO_TE",
|
||||
[DPUI_KEY_QCT_RCV_CNT] = "QCT_RCV_CNT",
|
||||
[DPUI_KEY_QCT_SSLOG] = "QCT_SSLOG",
|
||||
[DPUI_KEY_QCT_MAIN_RX_FAIL_CNT] = "QCT_MAIN_RX_FAIL_CNT",
|
||||
[DPUI_KEY_QCT_SUB_RX_FAIL_CNT] = "QCT_SUB_RX_FAIL_CNT",
|
||||
|
||||
/* GPU */
|
||||
[DPUI_KEY_QCT_GPU_PF] = "QCT_GPU_PF",
|
||||
|
||||
/* ub con detect */
|
||||
[DPUI_KEY_UB_CON] = "UB_CON",
|
||||
[DPUI_KEY_SUB_UB_CON] = "SUB_UB_CON",
|
||||
|
||||
[DPUI_KEY_ECC_ERR] = "ECC_ERR",
|
||||
|
||||
/* Flash loading failure count */
|
||||
[DPUI_KEY_FLASH_LOAD] = "FLASH_LOAD",
|
||||
};
|
||||
|
||||
static const char * const dpui_type_name[] = {
|
||||
[DPUI_TYPE_NONE] = "NONE",
|
||||
/* common hw parameter */
|
||||
[DPUI_TYPE_PANEL] = "PANEL",
|
||||
/* dependent on processor */
|
||||
[DPUI_TYPE_CTRL] = "CTRL",
|
||||
};
|
||||
|
||||
static struct dpui_info dpui = {
|
||||
.pdata = NULL,
|
||||
.field = {
|
||||
/* common hw parameter */
|
||||
DPUI_FIELD_INIT(DPUI_LOG_LEVEL_INFO, DPUI_TYPE_PANEL,
|
||||
DPUI_VAR_U32, DPUI_AUTO_CLEAR_OFF, "0", DPUI_KEY_WCRD_X),
|
||||
DPUI_FIELD_INIT(DPUI_LOG_LEVEL_INFO, DPUI_TYPE_PANEL,
|
||||
DPUI_VAR_U32, DPUI_AUTO_CLEAR_OFF, "0", DPUI_KEY_WCRD_Y),
|
||||
DPUI_FIELD_INIT(DPUI_LOG_LEVEL_INFO, DPUI_TYPE_PANEL,
|
||||
DPUI_VAR_S32, DPUI_AUTO_CLEAR_OFF, "0", DPUI_KEY_WOFS_R),
|
||||
DPUI_FIELD_INIT(DPUI_LOG_LEVEL_INFO, DPUI_TYPE_PANEL,
|
||||
DPUI_VAR_S32, DPUI_AUTO_CLEAR_OFF, "0", DPUI_KEY_WOFS_G),
|
||||
DPUI_FIELD_INIT(DPUI_LOG_LEVEL_INFO, DPUI_TYPE_PANEL,
|
||||
DPUI_VAR_S32, DPUI_AUTO_CLEAR_OFF, "0", DPUI_KEY_WOFS_B),
|
||||
DPUI_FIELD_INIT(DPUI_LOG_LEVEL_INFO, DPUI_TYPE_PANEL,
|
||||
DPUI_VAR_S32, DPUI_AUTO_CLEAR_OFF, "0", DPUI_KEY_WOFS_R_ORG),
|
||||
DPUI_FIELD_INIT(DPUI_LOG_LEVEL_INFO, DPUI_TYPE_PANEL,
|
||||
DPUI_VAR_S32, DPUI_AUTO_CLEAR_OFF, "0", DPUI_KEY_WOFS_G_ORG),
|
||||
DPUI_FIELD_INIT(DPUI_LOG_LEVEL_INFO, DPUI_TYPE_PANEL,
|
||||
DPUI_VAR_S32, DPUI_AUTO_CLEAR_OFF, "0", DPUI_KEY_WOFS_B_ORG),
|
||||
DPUI_FIELD_INIT(DPUI_LOG_LEVEL_INFO, DPUI_TYPE_PANEL,
|
||||
DPUI_VAR_S32, DPUI_AUTO_CLEAR_OFF, "-1", DPUI_KEY_LCDID1),
|
||||
DPUI_FIELD_INIT(DPUI_LOG_LEVEL_INFO, DPUI_TYPE_PANEL,
|
||||
DPUI_VAR_S32, DPUI_AUTO_CLEAR_OFF, "-1", DPUI_KEY_LCDID2),
|
||||
DPUI_FIELD_INIT(DPUI_LOG_LEVEL_INFO, DPUI_TYPE_PANEL,
|
||||
DPUI_VAR_S32, DPUI_AUTO_CLEAR_OFF, "-1", DPUI_KEY_LCDID3),
|
||||
DPUI_FIELD_INIT(DPUI_LOG_LEVEL_INFO, DPUI_TYPE_PANEL,
|
||||
DPUI_VAR_STR, DPUI_AUTO_CLEAR_OFF, "19000000 000000", DPUI_KEY_MAID_DATE),
|
||||
DPUI_FIELD_INIT(DPUI_LOG_LEVEL_INFO, DPUI_TYPE_PANEL, DPUI_VAR_STR, DPUI_AUTO_CLEAR_OFF, "0000000000000000000000", DPUI_KEY_CELLID),
|
||||
DPUI_FIELD_INIT(DPUI_LOG_LEVEL_INFO, DPUI_TYPE_PANEL, DPUI_VAR_STR, DPUI_AUTO_CLEAR_OFF, "00000000000000000000000", DPUI_KEY_OCTAID),
|
||||
DPUI_FIELD_INIT(DPUI_LOG_LEVEL_INFO, DPUI_TYPE_PANEL,
|
||||
DPUI_VAR_U32, DPUI_AUTO_CLEAR_ON, "0", DPUI_KEY_PNDSIE),
|
||||
DPUI_FIELD_INIT(DPUI_LOG_LEVEL_INFO, DPUI_TYPE_PANEL,
|
||||
DPUI_VAR_U32, DPUI_AUTO_CLEAR_ON, "0", DPUI_KEY_PNELVDE),
|
||||
DPUI_FIELD_INIT(DPUI_LOG_LEVEL_INFO, DPUI_TYPE_PANEL,
|
||||
DPUI_VAR_U32, DPUI_AUTO_CLEAR_ON, "0", DPUI_KEY_PNVLI1E),
|
||||
DPUI_FIELD_INIT(DPUI_LOG_LEVEL_INFO, DPUI_TYPE_PANEL,
|
||||
DPUI_VAR_U32, DPUI_AUTO_CLEAR_ON, "0", DPUI_KEY_PNVLO3E),
|
||||
DPUI_FIELD_INIT(DPUI_LOG_LEVEL_INFO, DPUI_TYPE_PANEL,
|
||||
DPUI_VAR_U32, DPUI_AUTO_CLEAR_ON, "0", DPUI_KEY_PNSDRE),
|
||||
|
||||
/* POC */
|
||||
DPUI_FIELD_INIT(DPUI_LOG_LEVEL_INFO, DPUI_TYPE_PANEL,
|
||||
DPUI_VAR_S32, DPUI_AUTO_CLEAR_OFF, "-1", DPUI_KEY_PNPOCT),
|
||||
DPUI_FIELD_INIT(DPUI_LOG_LEVEL_INFO, DPUI_TYPE_PANEL,
|
||||
DPUI_VAR_S32, DPUI_AUTO_CLEAR_OFF, "-1", DPUI_KEY_PNPOCF),
|
||||
DPUI_FIELD_INIT(DPUI_LOG_LEVEL_INFO, DPUI_TYPE_PANEL,
|
||||
DPUI_VAR_S32, DPUI_AUTO_CLEAR_OFF, "-100", DPUI_KEY_PNPOCI),
|
||||
DPUI_FIELD_INIT(DPUI_LOG_LEVEL_INFO, DPUI_TYPE_PANEL,
|
||||
DPUI_VAR_S32, DPUI_AUTO_CLEAR_OFF, "-100", DPUI_KEY_PNPOCI_ORG),
|
||||
|
||||
DPUI_FIELD_INIT(DPUI_LOG_LEVEL_INFO, DPUI_TYPE_PANEL,
|
||||
DPUI_VAR_U32, DPUI_AUTO_CLEAR_ON, "0", DPUI_KEY_PNPOC_ER_TRY),
|
||||
DPUI_FIELD_INIT(DPUI_LOG_LEVEL_INFO, DPUI_TYPE_PANEL,
|
||||
DPUI_VAR_U32, DPUI_AUTO_CLEAR_ON, "0", DPUI_KEY_PNPOC_ER_FAIL),
|
||||
DPUI_FIELD_INIT(DPUI_LOG_LEVEL_INFO, DPUI_TYPE_PANEL,
|
||||
DPUI_VAR_U32, DPUI_AUTO_CLEAR_ON, "0", DPUI_KEY_PNPOC_WR_TRY),
|
||||
DPUI_FIELD_INIT(DPUI_LOG_LEVEL_INFO, DPUI_TYPE_PANEL,
|
||||
DPUI_VAR_U32, DPUI_AUTO_CLEAR_ON, "0", DPUI_KEY_PNPOC_WR_FAIL),
|
||||
DPUI_FIELD_INIT(DPUI_LOG_LEVEL_INFO, DPUI_TYPE_PANEL,
|
||||
DPUI_VAR_U32, DPUI_AUTO_CLEAR_ON, "0", DPUI_KEY_PNPOC_RD_TRY),
|
||||
DPUI_FIELD_INIT(DPUI_LOG_LEVEL_INFO, DPUI_TYPE_PANEL,
|
||||
DPUI_VAR_U32, DPUI_AUTO_CLEAR_ON, "0", DPUI_KEY_PNPOC_RD_FAIL),
|
||||
|
||||
/* Gamma Flash */
|
||||
DPUI_FIELD_INIT(DPUI_LOG_LEVEL_INFO, DPUI_TYPE_PANEL,
|
||||
DPUI_VAR_S32, DPUI_AUTO_CLEAR_OFF, "0", DPUI_KEY_PNGFLS),
|
||||
|
||||
/* dependent on processor */
|
||||
DPUI_FIELD_INIT(DPUI_LOG_LEVEL_INFO, DPUI_TYPE_CTRL,
|
||||
DPUI_VAR_U32, DPUI_AUTO_CLEAR_ON, "0", DPUI_KEY_QCT_DSIE),
|
||||
DPUI_FIELD_INIT(DPUI_LOG_LEVEL_INFO, DPUI_TYPE_CTRL,
|
||||
DPUI_VAR_U32, DPUI_AUTO_CLEAR_ON, "0", DPUI_KEY_QCT_PPTO),
|
||||
DPUI_FIELD_INIT(DPUI_LOG_LEVEL_INFO, DPUI_TYPE_CTRL,
|
||||
DPUI_VAR_U32, DPUI_AUTO_CLEAR_ON, "0", DPUI_KEY_QCT_NO_TE),
|
||||
DPUI_FIELD_INIT(DPUI_LOG_LEVEL_INFO, DPUI_TYPE_CTRL,
|
||||
DPUI_VAR_U32, DPUI_AUTO_CLEAR_ON, "0", DPUI_KEY_QCT_RCV_CNT),
|
||||
DPUI_FIELD_INIT(DPUI_LOG_LEVEL_INFO, DPUI_TYPE_CTRL,
|
||||
DPUI_VAR_U32, DPUI_AUTO_CLEAR_OFF, "0", DPUI_KEY_QCT_SSLOG),
|
||||
DPUI_FIELD_INIT(DPUI_LOG_LEVEL_INFO, DPUI_TYPE_CTRL,
|
||||
DPUI_VAR_U32, DPUI_AUTO_CLEAR_ON, "0", DPUI_KEY_QCT_MAIN_RX_FAIL_CNT),
|
||||
DPUI_FIELD_INIT(DPUI_LOG_LEVEL_INFO, DPUI_TYPE_CTRL,
|
||||
DPUI_VAR_U32, DPUI_AUTO_CLEAR_ON, "0", DPUI_KEY_QCT_SUB_RX_FAIL_CNT),
|
||||
|
||||
/* GPU */
|
||||
DPUI_FIELD_INIT(DPUI_LOG_LEVEL_INFO, DPUI_TYPE_CTRL,
|
||||
DPUI_VAR_U32, DPUI_AUTO_CLEAR_ON, "0", DPUI_KEY_QCT_GPU_PF),
|
||||
|
||||
/* UB CON */
|
||||
DPUI_FIELD_INIT(DPUI_LOG_LEVEL_INFO, DPUI_TYPE_PANEL,
|
||||
DPUI_VAR_U32, DPUI_AUTO_CLEAR_ON, "0", DPUI_KEY_UB_CON),
|
||||
|
||||
/* SUB UB CON */
|
||||
DPUI_FIELD_INIT(DPUI_LOG_LEVEL_INFO, DPUI_TYPE_PANEL,
|
||||
DPUI_VAR_U32, DPUI_AUTO_CLEAR_ON, "0", DPUI_KEY_SUB_UB_CON),
|
||||
|
||||
/* ECC Error */
|
||||
DPUI_FIELD_INIT(DPUI_LOG_LEVEL_INFO, DPUI_TYPE_PANEL,
|
||||
DPUI_VAR_U32, DPUI_AUTO_CLEAR_ON, "0", DPUI_KEY_ECC_ERR),
|
||||
|
||||
/* Flash loading failure count */
|
||||
DPUI_FIELD_INIT(DPUI_LOG_LEVEL_INFO, DPUI_TYPE_PANEL,
|
||||
DPUI_VAR_U32, DPUI_AUTO_CLEAR_ON, "0", DPUI_KEY_FLASH_LOAD),
|
||||
},
|
||||
};
|
||||
int dpui_logging_register(struct notifier_block *n, enum dpui_type type);
|
||||
int dpui_logging_unregister(struct notifier_block *n);
|
||||
void update_dpui_log(enum dpui_log_level level, enum dpui_type type);
|
||||
int clear_dpui_log(enum dpui_log_level level, enum dpui_type type);
|
||||
int get_dpui_log(char *buf, enum dpui_log_level level, enum dpui_type type);
|
||||
int set_dpui_field(enum dpui_key key, char *buf, int size);
|
||||
int get_dpui_field(enum dpui_key key, char *buf);
|
||||
int set_dpui_u32_field(enum dpui_key key, u32 value);
|
||||
int get_dpui_u32_field(enum dpui_key key, u32 *value);
|
||||
int inc_dpui_u32_field(enum dpui_key key, u32 value);
|
||||
int inc_dpui_u32_field_nolock(enum dpui_key key, u32 value);
|
||||
#endif /* __DPUI_H__ */
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user