Add 'techpack/display/' from tag 'LA.UM.9.14.r1-18300-LAHAINA.0'
git-subtree-dir: techpack/display git-subtree-mainline:2d46776923
git-subtree-split:64f31403b4
Change-Id: I7f4c42a3ba6b11a8db861cdd171a52d8f58f2e06
This commit is contained in:
commit
23b65c3a24
40
techpack/display/Android.bp
Normal file
40
techpack/display/Android.bp
Normal file
@ -0,0 +1,40 @@
|
||||
headers_src = [
|
||||
"include/uapi/*/**/*.h",
|
||||
]
|
||||
|
||||
display_headers_out = [
|
||||
"display/drm/msm_drm_pp.h",
|
||||
"display/drm/sde_drm.h",
|
||||
"display/hdcp/msm_hdmi_hdcp_mgr.h",
|
||||
"display/media/mmm_color_fmt.h",
|
||||
"display/media/msm_sde_rotator.h",
|
||||
]
|
||||
|
||||
display_kernel_headers_verbose = "--verbose "
|
||||
genrule {
|
||||
name: "qti_generate_display_kernel_headers",
|
||||
tools: [
|
||||
"headers_install.sh",
|
||||
"unifdef"
|
||||
],
|
||||
tool_files: [
|
||||
"display_kernel_headers.py",
|
||||
],
|
||||
srcs: headers_src,
|
||||
cmd: "python3 $(location display_kernel_headers.py) " +
|
||||
display_kernel_headers_verbose +
|
||||
"--header_arch arm64 " +
|
||||
"--gen_dir $(genDir) " +
|
||||
"--display_include_uapi $(locations include/uapi/*/**/*.h) " +
|
||||
"--unifdef $(location unifdef) " +
|
||||
"--headers_install $(location headers_install.sh)",
|
||||
out: display_headers_out,
|
||||
}
|
||||
|
||||
cc_library_headers {
|
||||
name: "qti_display_kernel_headers",
|
||||
generated_headers: ["qti_generate_display_kernel_headers"],
|
||||
export_generated_headers: ["qti_generate_display_kernel_headers"],
|
||||
vendor: true,
|
||||
recovery_available: true
|
||||
}
|
71
techpack/display/Makefile
Normal file
71
techpack/display/Makefile
Normal file
@ -0,0 +1,71 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
# auto-detect subdirs
|
||||
ifeq ($(CONFIG_ARCH_KONA), y)
|
||||
include $(srctree)/techpack/display/config/konadisp.conf
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_ARCH_KONA), y)
|
||||
LINUXINCLUDE += -include $(srctree)/techpack/display/config/konadispconf.h
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_ARCH_LAHAINA), y)
|
||||
ifeq ($(CONFIG_QGKI), y)
|
||||
include $(srctree)/techpack/display/config/lahainadisp.conf
|
||||
LINUXINCLUDE += -include $(srctree)/techpack/display/config/lahainadispconf.h
|
||||
else
|
||||
include $(srctree)/techpack/display/config/gki_lahainadisp.conf
|
||||
LINUXINCLUDE += -include $(srctree)/techpack/display/config/gki_lahainadispconf.h
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_ARCH_HOLI), y)
|
||||
ifeq ($(CONFIG_QGKI), y)
|
||||
include $(srctree)/techpack/display/config/holidisp.conf
|
||||
LINUXINCLUDE += -include $(srctree)/techpack/display/config/holidispconf.h
|
||||
else
|
||||
include $(srctree)/techpack/display/config/gki_holidisp.conf
|
||||
LINUXINCLUDE += -include $(srctree)/techpack/display/config/gki_holidispconf.h
|
||||
endif
|
||||
endif
|
||||
|
||||
LINUXINCLUDE += \
|
||||
-I$(srctree)/techpack/display/include/uapi/display \
|
||||
-I$(srctree)/techpack/display/include
|
||||
USERINCLUDE += -I$(srctree)/techpack/display/include/uapi/display
|
||||
|
||||
ifeq ($(CONFIG_ARCH_LITO), y)
|
||||
include $(srctree)/techpack/display/config/saipdisp.conf
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_ARCH_LITO), y)
|
||||
LINUXINCLUDE += -include $(srctree)/techpack/display/config/saipdispconf.h
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_ARCH_BENGAL), y)
|
||||
include $(srctree)/techpack/display/config/bengaldisp.conf
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_ARCH_BENGAL), y)
|
||||
LINUXINCLUDE += -include $(srctree)/techpack/display/config/bengaldispconf.h
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_ARCH_MONACO), y)
|
||||
include $(srctree)/techpack/display/config/monacodisp.conf
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_ARCH_MONACO), y)
|
||||
LINUXINCLUDE += -include $(srctree)/techpack/display/config/monacodispconf.h
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_DRM_MSM) += msm/
|
||||
|
||||
ifeq ($(CONFIG_ARCH_SDXLEMUR), y)
|
||||
include $(srctree)/techpack/display/config/sdxlemurdisp.conf
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_ARCH_SDXLEMUR), y)
|
||||
LINUXINCLUDE += -include $(srctree)/techpack/display/config/sdxlemurdispconf.h
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_DRM_QPIC_DISPLAY) += tinydrm/
|
47
techpack/display/NOTICE
Normal file
47
techpack/display/NOTICE
Normal file
@ -0,0 +1,47 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2014-2019, The Linux Foundation. All rights reserved.
|
||||
* Copyright (C) 2013 Red Hat
|
||||
* Copyright (C) 2014 Red Hat
|
||||
* Copyright (C) 2016 Red Hat
|
||||
* Author: Rob Clark <robdclark@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright © 2014 Red Hatt.
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
* the above copyright notice appear in all copies and that both that copyright
|
||||
* notice and this permission notice appear in supporting documentation, and
|
||||
* that the name of the copyright holders not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without specific,
|
||||
* written prior permission. The copyright holders make no representations
|
||||
* about the suitability of this software for any purpose. It is provided "as
|
||||
* is" without express or implied warranty.
|
||||
*
|
||||
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
||||
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
||||
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
* OF THIS SOFTWARE.
|
||||
*/
|
16
techpack/display/config/bengaldisp.conf
Normal file
16
techpack/display/config/bengaldisp.conf
Normal file
@ -0,0 +1,16 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# Copyright (c) 2019, The Linux Foundation. All rights reserved.
|
||||
|
||||
export CONFIG_DRM_MSM=y
|
||||
export CONFIG_DRM_MSM_SDE=y
|
||||
export CONFIG_SYNC_FILE=y
|
||||
export CONFIG_DRM_MSM_DSI=y
|
||||
export CONFIG_DRM_MSM_DP=n
|
||||
export CONFIG_QCOM_MDSS_DP_PLL=n
|
||||
export CONFIG_DSI_PARSER=y
|
||||
export CONFIG_DRM_SDE_WB=n
|
||||
export CONFIG_DRM_MSM_REGISTER_LOGGING=y
|
||||
export CONFIG_QCOM_MDSS_PLL=y
|
||||
export CONFIG_MSM_SDE_ROTATOR=y
|
||||
export CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y
|
||||
export CONFIG_DRM_SDE_RSC=n
|
15
techpack/display/config/bengaldispconf.h
Normal file
15
techpack/display/config/bengaldispconf.h
Normal file
@ -0,0 +1,15 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#define CONFIG_DRM_MSM 1
|
||||
#define CONFIG_DRM_MSM_SDE 1
|
||||
#define CONFIG_SYNC_FILE 1
|
||||
#define CONFIG_DRM_MSM_DSI 1
|
||||
#define CONFIG_DSI_PARSER 1
|
||||
#define CONFIG_DRM_MSM_REGISTER_LOGGING 1
|
||||
#define CONFIG_DRM_SDE_EVTLOG_DEBUG 1
|
||||
#define CONFIG_QCOM_MDSS_PLL 1
|
||||
#define CONFIG_MSM_SDE_ROTATOR 1
|
||||
#define CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG 1
|
17
techpack/display/config/gki_holidisp.conf
Normal file
17
techpack/display/config/gki_holidisp.conf
Normal file
@ -0,0 +1,17 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
|
||||
|
||||
export CONFIG_DRM_MSM=y
|
||||
export CONFIG_DRM_MSM_SDE=y
|
||||
export CONFIG_DRM_MSM_DP=n
|
||||
export CONFIG_DRM_MSM_DP_MST=n
|
||||
export CONFIG_SYNC_FILE=y
|
||||
export CONFIG_DRM_MSM_DSI=y
|
||||
export CONFIG_DSI_PARSER=y
|
||||
export CONFIG_DRM_SDE_WB=n
|
||||
export CONFIG_DRM_MSM_REGISTER_LOGGING=y
|
||||
export CONFIG_QCOM_MDSS_PLL=y
|
||||
export CONFIG_DRM_SDE_RSC=n
|
||||
export CONFIG_DISPLAY_BUILD=m
|
||||
export CONFIG_MSM_SDE_ROTATOR=y
|
||||
export CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y
|
16
techpack/display/config/gki_holidispconf.h
Normal file
16
techpack/display/config/gki_holidispconf.h
Normal file
@ -0,0 +1,16 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#define CONFIG_DRM_MSM 1
|
||||
#define CONFIG_DRM_MSM_SDE 1
|
||||
#define CONFIG_SYNC_FILE 1
|
||||
#define CONFIG_DRM_MSM_DSI 1
|
||||
#define CONFIG_DSI_PARSER 1
|
||||
#define CONFIG_DRM_MSM_REGISTER_LOGGING 1
|
||||
#define CONFIG_DRM_SDE_EVTLOG_DEBUG 1
|
||||
#define CONFIG_QCOM_MDSS_PLL 1
|
||||
#define CONFIG_GKI_DISPLAY 1
|
||||
#define CONFIG_MSM_SDE_ROTATOR 1
|
||||
#define CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG 1
|
12
techpack/display/config/gki_lahainadisp.conf
Normal file
12
techpack/display/config/gki_lahainadisp.conf
Normal file
@ -0,0 +1,12 @@
|
||||
export CONFIG_DRM_MSM=y
|
||||
export CONFIG_DRM_MSM_SDE=y
|
||||
export CONFIG_SYNC_FILE=y
|
||||
export CONFIG_DRM_MSM_DSI=y
|
||||
export CONFIG_DRM_MSM_DP=y
|
||||
export CONFIG_DRM_MSM_DP_MST=y
|
||||
export CONFIG_DSI_PARSER=y
|
||||
export CONFIG_QCOM_MDSS_PLL=y
|
||||
export CONFIG_DRM_SDE_WB=y
|
||||
export CONFIG_DRM_MSM_REGISTER_LOGGING=y
|
||||
export CONFIG_DRM_SDE_RSC=y
|
||||
export CONFIG_DISPLAY_BUILD=m
|
19
techpack/display/config/gki_lahainadispconf.h
Normal file
19
techpack/display/config/gki_lahainadispconf.h
Normal file
@ -0,0 +1,19 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#define CONFIG_DRM_MSM 1
|
||||
#define CONFIG_DRM_MSM_SDE 1
|
||||
#define CONFIG_SYNC_FILE 1
|
||||
#define CONFIG_DRM_MSM_DSI 1
|
||||
#define CONFIG_DRM_MSM_DP 1
|
||||
#define CONFIG_DRM_MSM_DP_MST 1
|
||||
#define CONFIG_DSI_PARSER 1
|
||||
#define CONFIG_DRM_SDE_WB 1
|
||||
#define CONFIG_DRM_MSM_REGISTER_LOGGING 1
|
||||
#define CONFIG_DRM_SDE_EVTLOG_DEBUG 1
|
||||
#define CONFIG_QCOM_MDSS_PLL 1
|
||||
#define CONFIG_GKI_DISPLAY 1
|
||||
#define CONFIG_DRM_SDE_RSC 1
|
||||
|
17
techpack/display/config/holidisp.conf
Normal file
17
techpack/display/config/holidisp.conf
Normal file
@ -0,0 +1,17 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
|
||||
export CONFIG_DRM_MSM=y
|
||||
export CONFIG_DRM_MSM_SDE=y
|
||||
export CONFIG_DRM_MSM_DP=n
|
||||
export CONFIG_DRM_MSM_DP_MST=n
|
||||
export CONFIG_SYNC_FILE=y
|
||||
export CONFIG_DRM_MSM_DSI=y
|
||||
export CONFIG_DSI_PARSER=y
|
||||
export CONFIG_DRM_SDE_WB=n
|
||||
export CONFIG_DRM_MSM_REGISTER_LOGGING=y
|
||||
export CONFIG_QCOM_MDSS_PLL=y
|
||||
export CONFIG_DRM_SDE_RSC=n
|
||||
export CONFIG_MSM_SDE_ROTATOR=y
|
||||
export CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y
|
||||
export CONFIG_DISPLAY_BUILD=y
|
15
techpack/display/config/holidispconf.h
Normal file
15
techpack/display/config/holidispconf.h
Normal file
@ -0,0 +1,15 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#define CONFIG_DRM_MSM 1
|
||||
#define CONFIG_DRM_MSM_SDE 1
|
||||
#define CONFIG_SYNC_FILE 1
|
||||
#define CONFIG_DRM_MSM_DSI 1
|
||||
#define CONFIG_DSI_PARSER 1
|
||||
#define CONFIG_DRM_MSM_REGISTER_LOGGING 1
|
||||
#define CONFIG_DRM_SDE_EVTLOG_DEBUG 1
|
||||
#define CONFIG_QCOM_MDSS_PLL 1
|
||||
#define CONFIG_MSM_SDE_ROTATOR 1
|
||||
#define CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG 1
|
13
techpack/display/config/konadisp.conf
Normal file
13
techpack/display/config/konadisp.conf
Normal file
@ -0,0 +1,13 @@
|
||||
export CONFIG_DRM_MSM=y
|
||||
export CONFIG_DRM_MSM_SDE=y
|
||||
export CONFIG_SYNC_FILE=y
|
||||
export CONFIG_DRM_MSM_DSI=y
|
||||
export CONFIG_DRM_MSM_DP=y
|
||||
export CONFIG_QCOM_MDSS_DP_PLL=y
|
||||
export CONFIG_DSI_PARSER=y
|
||||
export CONFIG_DRM_SDE_WB=y
|
||||
export CONFIG_DRM_MSM_REGISTER_LOGGING=y
|
||||
export CONFIG_QCOM_MDSS_PLL=y
|
||||
export CONFIG_MSM_SDE_ROTATOR=y
|
||||
export CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y
|
||||
export CONFIG_DRM_SDE_RSC=y
|
20
techpack/display/config/konadispconf.h
Normal file
20
techpack/display/config/konadispconf.h
Normal file
@ -0,0 +1,20 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#define CONFIG_DRM_MSM 1
|
||||
#define CONFIG_DRM_MSM_SDE 1
|
||||
#define CONFIG_SYNC_FILE 1
|
||||
#define CONFIG_DRM_MSM_DSI 1
|
||||
#define CONFIG_DRM_MSM_DP 1
|
||||
#define CONFIG_QCOM_MDSS_DP_PLL 1
|
||||
#define CONFIG_DSI_PARSER 1
|
||||
#define CONFIG_DRM_SDE_WB 1
|
||||
#define CONFIG_DRM_MSM_REGISTER_LOGGING 1
|
||||
#define CONFIG_DRM_SDE_EVTLOG_DEBUG 1
|
||||
#define CONFIG_QCOM_MDSS_PLL 1
|
||||
#define CONFIG_MSM_SDE_ROTATOR 1
|
||||
#define CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG 1
|
||||
#define CONFIG_DRM_SDE_RSC 1
|
||||
|
13
techpack/display/config/lahainadisp.conf
Normal file
13
techpack/display/config/lahainadisp.conf
Normal file
@ -0,0 +1,13 @@
|
||||
export CONFIG_DRM_MSM=y
|
||||
export CONFIG_DRM_MSM_SDE=y
|
||||
export CONFIG_DRM_MSM_DP=y
|
||||
export CONFIG_DRM_MSM_DP_MST=y
|
||||
export CONFIG_SYNC_FILE=y
|
||||
export CONFIG_DRM_MSM_DSI=y
|
||||
export CONFIG_DSI_PARSER=y
|
||||
export CONFIG_DRM_SDE_WB=y
|
||||
export CONFIG_DRM_MSM_REGISTER_LOGGING=y
|
||||
export CONFIG_QCOM_MDSS_PLL=y
|
||||
export CONFIG_DRM_SDE_RSC=y
|
||||
export CONFIG_DISPLAY_BUILD=m
|
||||
export CONFIG_DRM_SDE_VM=y
|
18
techpack/display/config/lahainadispconf.h
Normal file
18
techpack/display/config/lahainadispconf.h
Normal file
@ -0,0 +1,18 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#define CONFIG_DRM_MSM 1
|
||||
#define CONFIG_DRM_MSM_DP 1
|
||||
#define CONFIG_DRM_MSM_DP_MST 1
|
||||
#define CONFIG_DRM_MSM_SDE 1
|
||||
#define CONFIG_SYNC_FILE 1
|
||||
#define CONFIG_DRM_MSM_DSI 1
|
||||
#define CONFIG_DSI_PARSER 1
|
||||
#define CONFIG_DRM_SDE_WB 1
|
||||
#define CONFIG_DRM_MSM_REGISTER_LOGGING 1
|
||||
#define CONFIG_DRM_SDE_EVTLOG_DEBUG 1
|
||||
#define CONFIG_QCOM_MDSS_PLL 1
|
||||
#define CONFIG_DRM_SDE_RSC 1
|
||||
#define CONFIG_DRM_SDE_VM 1
|
15
techpack/display/config/monacodisp.conf
Normal file
15
techpack/display/config/monacodisp.conf
Normal file
@ -0,0 +1,15 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# Copyright (c) 2021, The Linux Foundation. All rights reserved.
|
||||
|
||||
export CONFIG_DRM_MSM=y
|
||||
export CONFIG_DRM_MSM_SDE=y
|
||||
export CONFIG_SYNC_FILE=y
|
||||
export CONFIG_DRM_MSM_DSI=y
|
||||
export CONFIG_DSI_PARSER=y
|
||||
export CONFIG_DRM_SDE_WB=n
|
||||
export CONFIG_DRM_MSM_REGISTER_LOGGING=y
|
||||
export CONFIG_QCOM_MDSS_PLL=y
|
||||
export CONFIG_MSM_SDE_ROTATOR=n
|
||||
export CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=n
|
||||
export CONFIG_DRM_SDE_RSC=n
|
||||
export CONFIG_DISPLAY_BUILD=y
|
12
techpack/display/config/monacodispconf.h
Normal file
12
techpack/display/config/monacodispconf.h
Normal file
@ -0,0 +1,12 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#define CONFIG_DRM_MSM 1
|
||||
#define CONFIG_DRM_MSM_SDE 1
|
||||
#define CONFIG_SYNC_FILE 1
|
||||
#define CONFIG_DRM_MSM_DSI 1
|
||||
#define CONFIG_DSI_PARSER 1
|
||||
#define CONFIG_DRM_MSM_REGISTER_LOGGING 1
|
||||
#define CONFIG_QCOM_MDSS_PLL 1
|
13
techpack/display/config/saipdisp.conf
Normal file
13
techpack/display/config/saipdisp.conf
Normal file
@ -0,0 +1,13 @@
|
||||
export CONFIG_DRM_MSM=y
|
||||
export CONFIG_DRM_MSM_SDE=y
|
||||
export CONFIG_SYNC_FILE=y
|
||||
export CONFIG_DRM_MSM_DSI=y
|
||||
export CONFIG_DRM_MSM_DP=y
|
||||
export CONFIG_QCOM_MDSS_DP_PLL=y
|
||||
export CONFIG_DSI_PARSER=y
|
||||
export CONFIG_DRM_SDE_WB=y
|
||||
export CONFIG_DRM_MSM_REGISTER_LOGGING=y
|
||||
export CONFIG_QCOM_MDSS_PLL=y
|
||||
export CONFIG_MSM_SDE_ROTATOR=y
|
||||
export CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y
|
||||
export CONFIG_DRM_SDE_RSC=y
|
19
techpack/display/config/saipdispconf.h
Normal file
19
techpack/display/config/saipdispconf.h
Normal file
@ -0,0 +1,19 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#define CONFIG_DRM_MSM 1
|
||||
#define CONFIG_DRM_MSM_SDE 1
|
||||
#define CONFIG_SYNC_FILE 1
|
||||
#define CONFIG_DRM_MSM_DSI 1
|
||||
#define CONFIG_DRM_MSM_DP 1
|
||||
#define CONFIG_QCOM_MDSS_DP_PLL 1
|
||||
#define CONFIG_DSI_PARSER 1
|
||||
#define CONFIG_DRM_SDE_WB 1
|
||||
#define CONFIG_DRM_MSM_REGISTER_LOGGING 1
|
||||
#define CONFIG_DRM_SDE_EVTLOG_DEBUG 1
|
||||
#define CONFIG_QCOM_MDSS_PLL 1
|
||||
#define CONFIG_MSM_SDE_ROTATOR 1
|
||||
#define CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG 1
|
||||
#define CONFIG_DRM_SDE_RSC 1
|
4
techpack/display/config/sdxlemurdisp.conf
Normal file
4
techpack/display/config/sdxlemurdisp.conf
Normal file
@ -0,0 +1,4 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# Copyright (c) 2021, The Linux Foundation. All rights reserved.
|
||||
|
||||
export CONFIG_DRM_QPIC_DISPLAY=y
|
6
techpack/display/config/sdxlemurdispconf.h
Normal file
6
techpack/display/config/sdxlemurdispconf.h
Normal file
@ -0,0 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#define CONFIG_DRM_QPIC_DISPLAY 1
|
92
techpack/display/display_kernel_headers.py
Normal file
92
techpack/display/display_kernel_headers.py
Normal file
@ -0,0 +1,92 @@
|
||||
# Copyright (c) 2020, 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 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.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import argparse
|
||||
import filecmp
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
def run_headers_install(verbose, gen_dir, headers_install, unifdef, prefix, h):
|
||||
if not h.startswith(prefix):
|
||||
print('error: expected prefix [%s] on header [%s]' % (prefix, h))
|
||||
return False
|
||||
|
||||
out_h = os.path.join(gen_dir, h[len(prefix):])
|
||||
(out_h_dirname, out_h_basename) = os.path.split(out_h)
|
||||
env = os.environ.copy()
|
||||
env["LOC_UNIFDEF"] = unifdef
|
||||
cmd = ["sh", headers_install, h, out_h]
|
||||
|
||||
if verbose:
|
||||
print('run_headers_install: cmd is %s' % cmd)
|
||||
|
||||
result = subprocess.call(cmd, env=env)
|
||||
|
||||
if result != 0:
|
||||
print('error: run_headers_install: cmd %s failed %d' % (cmd, result))
|
||||
return False
|
||||
return True
|
||||
|
||||
def gen_display_headers(verbose, gen_dir, headers_install, unifdef, display_include_uapi):
|
||||
error_count = 0
|
||||
for h in display_include_uapi:
|
||||
display_uapi_include_prefix = os.path.join(h.split('/include/uapi')[0], 'include', 'uapi') + os.sep
|
||||
if not run_headers_install(
|
||||
verbose, gen_dir, headers_install, unifdef,
|
||||
display_uapi_include_prefix, h): error_count += 1
|
||||
return error_count
|
||||
|
||||
def main():
|
||||
"""Parse command line arguments and perform top level control."""
|
||||
parser = argparse.ArgumentParser(
|
||||
description=__doc__,
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||
|
||||
# Arguments that apply to every invocation of this script.
|
||||
parser.add_argument(
|
||||
'--verbose', action='store_true',
|
||||
help='Print output that describes the workings of this script.')
|
||||
parser.add_argument(
|
||||
'--header_arch', required=True,
|
||||
help='The arch for which to generate headers.')
|
||||
parser.add_argument(
|
||||
'--gen_dir', required=True,
|
||||
help='Where to place the generated files.')
|
||||
parser.add_argument(
|
||||
'--display_include_uapi', required=True, nargs='*',
|
||||
help='The list of techpack/*/include/uapi header files.')
|
||||
parser.add_argument(
|
||||
'--headers_install', required=True,
|
||||
help='The headers_install tool to process input headers.')
|
||||
parser.add_argument(
|
||||
'--unifdef',
|
||||
required=True,
|
||||
help='The unifdef tool used by headers_install.')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.verbose:
|
||||
print('header_arch [%s]' % args.header_arch)
|
||||
print('gen_dir [%s]' % args.gen_dir)
|
||||
print('display_include_uapi [%s]' % args.display_include_uapi)
|
||||
print('headers_install [%s]' % args.headers_install)
|
||||
print('unifdef [%s]' % args.unifdef)
|
||||
|
||||
return gen_display_headers(args.verbose, args.gen_dir,
|
||||
args.headers_install, args.unifdef, args.display_include_uapi)
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
|
339
techpack/display/hdcp/msm_hdcp.c
Normal file
339
techpack/display/hdcp/msm_hdcp.c
Normal file
@ -0,0 +1,339 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "[msm-hdcp] %s: " fmt, __func__
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/msm_hdcp.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#define CLASS_NAME "hdcp"
|
||||
#define DRIVER_NAME "msm_hdcp"
|
||||
|
||||
struct msm_hdcp {
|
||||
struct platform_device *pdev;
|
||||
dev_t dev_num;
|
||||
struct cdev cdev;
|
||||
struct class *class;
|
||||
struct device *device;
|
||||
struct HDCP_V2V1_MSG_TOPOLOGY cached_tp;
|
||||
u32 tp_msgid;
|
||||
void *client_ctx;
|
||||
void (*cb)(void *ctx, u8 data);
|
||||
};
|
||||
|
||||
void msm_hdcp_register_cb(struct device *dev, void *ctx,
|
||||
void (*cb)(void *ctx, u8 data))
|
||||
{
|
||||
struct msm_hdcp *hdcp = NULL;
|
||||
|
||||
if (!dev) {
|
||||
pr_err("invalid device pointer\n");
|
||||
return;
|
||||
}
|
||||
|
||||
hdcp = dev_get_drvdata(dev);
|
||||
if (!hdcp) {
|
||||
pr_err("invalid driver pointer\n");
|
||||
return;
|
||||
}
|
||||
|
||||
hdcp->cb = cb;
|
||||
hdcp->client_ctx = ctx;
|
||||
}
|
||||
EXPORT_SYMBOL(msm_hdcp_register_cb);
|
||||
|
||||
void msm_hdcp_notify_topology(struct device *dev)
|
||||
{
|
||||
char *envp[4];
|
||||
char tp[SZ_16];
|
||||
char ver[SZ_16];
|
||||
struct msm_hdcp *hdcp = NULL;
|
||||
|
||||
if (!dev) {
|
||||
pr_err("invalid device pointer\n");
|
||||
return;
|
||||
}
|
||||
|
||||
hdcp = dev_get_drvdata(dev);
|
||||
if (!hdcp) {
|
||||
pr_err("invalid driver pointer\n");
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(tp, SZ_16, "%d", DOWN_CHECK_TOPOLOGY);
|
||||
snprintf(ver, SZ_16, "%d", HDCP_V1_TX);
|
||||
|
||||
envp[0] = "HDCP_MGR_EVENT=MSG_READY";
|
||||
envp[1] = tp;
|
||||
envp[2] = ver;
|
||||
envp[3] = NULL;
|
||||
|
||||
kobject_uevent_env(&hdcp->device->kobj, KOBJ_CHANGE, envp);
|
||||
}
|
||||
EXPORT_SYMBOL(msm_hdcp_notify_topology);
|
||||
|
||||
void msm_hdcp_cache_repeater_topology(struct device *dev,
|
||||
struct HDCP_V2V1_MSG_TOPOLOGY *tp)
|
||||
{
|
||||
struct msm_hdcp *hdcp = NULL;
|
||||
|
||||
if (!dev || !tp) {
|
||||
pr_err("invalid input\n");
|
||||
return;
|
||||
}
|
||||
|
||||
hdcp = dev_get_drvdata(dev);
|
||||
if (!hdcp) {
|
||||
pr_err("invalid driver pointer\n");
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&hdcp->cached_tp, tp,
|
||||
sizeof(struct HDCP_V2V1_MSG_TOPOLOGY));
|
||||
}
|
||||
EXPORT_SYMBOL(msm_hdcp_cache_repeater_topology);
|
||||
|
||||
static ssize_t tp_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
ssize_t ret = 0;
|
||||
struct msm_hdcp *hdcp = NULL;
|
||||
|
||||
if (!dev) {
|
||||
pr_err("invalid device pointer\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
hdcp = dev_get_drvdata(dev);
|
||||
if (!hdcp) {
|
||||
pr_err("invalid driver pointer\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
switch (hdcp->tp_msgid) {
|
||||
case DOWN_CHECK_TOPOLOGY:
|
||||
case DOWN_REQUEST_TOPOLOGY:
|
||||
buf[MSG_ID_IDX] = hdcp->tp_msgid;
|
||||
buf[RET_CODE_IDX] = HDCP_AUTHED;
|
||||
ret = HEADER_LEN;
|
||||
|
||||
memcpy(buf + HEADER_LEN, &hdcp->cached_tp,
|
||||
sizeof(struct HDCP_V2V1_MSG_TOPOLOGY));
|
||||
|
||||
ret += sizeof(struct HDCP_V2V1_MSG_TOPOLOGY);
|
||||
|
||||
/* clear the flag once data is read back to user space*/
|
||||
hdcp->tp_msgid = -1;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t tp_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int msgid = 0;
|
||||
ssize_t ret = count;
|
||||
struct msm_hdcp *hdcp = NULL;
|
||||
|
||||
if (!dev) {
|
||||
pr_err("invalid device pointer\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
hdcp = dev_get_drvdata(dev);
|
||||
if (!hdcp) {
|
||||
pr_err("invalid driver pointer\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
msgid = buf[0];
|
||||
|
||||
switch (msgid) {
|
||||
case DOWN_CHECK_TOPOLOGY:
|
||||
case DOWN_REQUEST_TOPOLOGY:
|
||||
hdcp->tp_msgid = msgid;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t min_level_change_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
int rc;
|
||||
int min_enc_lvl;
|
||||
ssize_t ret = count;
|
||||
struct msm_hdcp *hdcp = NULL;
|
||||
|
||||
if (!dev) {
|
||||
pr_err("invalid device pointer\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
hdcp = dev_get_drvdata(dev);
|
||||
if (!hdcp) {
|
||||
pr_err("invalid driver pointer\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
rc = kstrtoint(buf, 10, &min_enc_lvl);
|
||||
if (rc) {
|
||||
pr_err("kstrtoint failed. rc=%d\n", rc);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (hdcp->cb && hdcp->client_ctx)
|
||||
hdcp->cb(hdcp->client_ctx, min_enc_lvl);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RW(tp);
|
||||
|
||||
static DEVICE_ATTR_WO(min_level_change);
|
||||
|
||||
static struct attribute *msm_hdcp_fs_attrs[] = {
|
||||
&dev_attr_tp.attr,
|
||||
&dev_attr_min_level_change.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group msm_hdcp_fs_attr_group = {
|
||||
.attrs = msm_hdcp_fs_attrs
|
||||
};
|
||||
|
||||
static int msm_hdcp_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_hdcp_close(struct inode *inode, struct file *file)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations msm_hdcp_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = msm_hdcp_open,
|
||||
.release = msm_hdcp_close,
|
||||
};
|
||||
|
||||
static const struct of_device_id msm_hdcp_dt_match[] = {
|
||||
{ .compatible = "qcom,msm-hdcp",},
|
||||
{}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, msm_hdcp_dt_match);
|
||||
|
||||
static int msm_hdcp_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
struct msm_hdcp *hdcp;
|
||||
|
||||
hdcp = devm_kzalloc(&pdev->dev, sizeof(struct msm_hdcp), GFP_KERNEL);
|
||||
if (!hdcp)
|
||||
return -ENOMEM;
|
||||
|
||||
hdcp->pdev = pdev;
|
||||
|
||||
platform_set_drvdata(pdev, hdcp);
|
||||
|
||||
ret = alloc_chrdev_region(&hdcp->dev_num, 0, 1, DRIVER_NAME);
|
||||
if (ret < 0) {
|
||||
pr_err("alloc_chrdev_region failed ret = %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
hdcp->class = class_create(THIS_MODULE, CLASS_NAME);
|
||||
if (IS_ERR(hdcp->class)) {
|
||||
ret = PTR_ERR(hdcp->class);
|
||||
pr_err("couldn't create class rc = %d\n", ret);
|
||||
goto error_class_create;
|
||||
}
|
||||
|
||||
hdcp->device = device_create(hdcp->class, NULL,
|
||||
hdcp->dev_num, hdcp, DRIVER_NAME);
|
||||
if (IS_ERR(hdcp->device)) {
|
||||
ret = PTR_ERR(hdcp->device);
|
||||
pr_err("device_create failed %d\n", ret);
|
||||
goto error_class_device_create;
|
||||
}
|
||||
|
||||
cdev_init(&hdcp->cdev, &msm_hdcp_fops);
|
||||
ret = cdev_add(&hdcp->cdev, MKDEV(MAJOR(hdcp->dev_num), 0), 1);
|
||||
if (ret < 0) {
|
||||
pr_err("cdev_add failed %d\n", ret);
|
||||
goto error_cdev_add;
|
||||
}
|
||||
|
||||
ret = sysfs_create_group(&hdcp->device->kobj, &msm_hdcp_fs_attr_group);
|
||||
if (ret)
|
||||
pr_err("unable to register msm_hdcp sysfs nodes\n");
|
||||
|
||||
return 0;
|
||||
error_cdev_add:
|
||||
device_destroy(hdcp->class, hdcp->dev_num);
|
||||
error_class_device_create:
|
||||
class_destroy(hdcp->class);
|
||||
error_class_create:
|
||||
unregister_chrdev_region(hdcp->dev_num, 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int msm_hdcp_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct msm_hdcp *hdcp;
|
||||
|
||||
hdcp = platform_get_drvdata(pdev);
|
||||
if (!hdcp)
|
||||
return -ENODEV;
|
||||
|
||||
sysfs_remove_group(&hdcp->device->kobj,
|
||||
&msm_hdcp_fs_attr_group);
|
||||
cdev_del(&hdcp->cdev);
|
||||
device_destroy(hdcp->class, hdcp->dev_num);
|
||||
class_destroy(hdcp->class);
|
||||
unregister_chrdev_region(hdcp->dev_num, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver msm_hdcp_driver = {
|
||||
.probe = msm_hdcp_probe,
|
||||
.remove = msm_hdcp_remove,
|
||||
.driver = {
|
||||
.name = "msm_hdcp",
|
||||
.of_match_table = msm_hdcp_dt_match,
|
||||
.pm = NULL,
|
||||
}
|
||||
};
|
||||
|
||||
void __init msm_hdcp_register(void)
|
||||
{
|
||||
platform_driver_register(&msm_hdcp_driver);
|
||||
}
|
||||
|
||||
void __exit msm_hdcp_unregister(void)
|
||||
{
|
||||
platform_driver_unregister(&msm_hdcp_driver);
|
||||
}
|
2
techpack/display/include/Kbuild
Normal file
2
techpack/display/include/Kbuild
Normal file
@ -0,0 +1,2 @@
|
||||
# Top-level Makefile calls into asm-$(ARCH)
|
||||
# List only non-arch directories below
|
6
techpack/display/include/linux/Kbuild
Normal file
6
techpack/display/include/linux/Kbuild
Normal file
@ -0,0 +1,6 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note
|
||||
|
||||
header-y += msm_hdcp.h
|
||||
header-y += sde_io_util.h
|
||||
header-y += sde_rsc.h
|
||||
|
33
techpack/display/include/linux/msm_hdcp.h
Normal file
33
techpack/display/include/linux/msm_hdcp.h
Normal file
@ -0,0 +1,33 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef __MSM_HDCP_H
|
||||
#define __MSM_HDCP_H
|
||||
#include <linux/types.h>
|
||||
#include "hdcp/msm_hdmi_hdcp_mgr.h"
|
||||
|
||||
#if IS_ENABLED(CONFIG_HDCP_QSEECOM)
|
||||
void msm_hdcp_notify_topology(struct device *dev);
|
||||
void msm_hdcp_cache_repeater_topology(struct device *dev,
|
||||
struct HDCP_V2V1_MSG_TOPOLOGY *tp);
|
||||
void msm_hdcp_register_cb(struct device *dev, void *ctx,
|
||||
void (*cb)(void *ctx, u8 data));
|
||||
#else
|
||||
static inline void msm_hdcp_notify_topology(struct device *dev)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void msm_hdcp_cache_repeater_topology(struct device *dev,
|
||||
struct HDCP_V2V1_MSG_TOPOLOGY *tp)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void msm_hdcp_register_cb(struct device *dev, void *ctx,
|
||||
void (*cb)(void *ctx, u8 data))
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_HDCP_QSEECOM*/
|
||||
|
||||
#endif /* __MSM_HDCP_H */
|
114
techpack/display/include/linux/sde_io_util.h
Normal file
114
techpack/display/include/linux/sde_io_util.h
Normal file
@ -0,0 +1,114 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2012, 2017-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef __SDE_IO_UTIL_H__
|
||||
#define __SDE_IO_UTIL_H__
|
||||
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DEV_DBG(fmt, args...) pr_err(fmt, ##args)
|
||||
#else
|
||||
#define DEV_DBG(fmt, args...) pr_debug(fmt, ##args)
|
||||
#endif
|
||||
#define DEV_INFO(fmt, args...) pr_info(fmt, ##args)
|
||||
#define DEV_WARN(fmt, args...) pr_warn(fmt, ##args)
|
||||
#define DEV_ERR(fmt, args...) pr_err(fmt, ##args)
|
||||
|
||||
struct dss_io_data {
|
||||
u32 len;
|
||||
void __iomem *base;
|
||||
};
|
||||
|
||||
void dss_reg_w(struct dss_io_data *io, u32 offset, u32 value, u32 debug);
|
||||
u32 dss_reg_r(struct dss_io_data *io, u32 offset, u32 debug);
|
||||
void dss_reg_dump(void __iomem *base, u32 len, const char *prefix, u32 debug);
|
||||
|
||||
#define DSS_REG_W_ND(io, offset, val) dss_reg_w(io, offset, val, false)
|
||||
#define DSS_REG_W(io, offset, val) dss_reg_w(io, offset, val, true)
|
||||
#define DSS_REG_R_ND(io, offset) dss_reg_r(io, offset, false)
|
||||
#define DSS_REG_R(io, offset) dss_reg_r(io, offset, true)
|
||||
|
||||
enum dss_vreg_type {
|
||||
DSS_REG_LDO,
|
||||
DSS_REG_VS,
|
||||
};
|
||||
|
||||
struct dss_vreg {
|
||||
struct regulator *vreg; /* vreg handle */
|
||||
char vreg_name[32];
|
||||
int min_voltage;
|
||||
int max_voltage;
|
||||
int enable_load;
|
||||
int disable_load;
|
||||
int pre_on_sleep;
|
||||
int post_on_sleep;
|
||||
int pre_off_sleep;
|
||||
int post_off_sleep;
|
||||
};
|
||||
|
||||
struct dss_gpio {
|
||||
unsigned int gpio;
|
||||
unsigned int value;
|
||||
char gpio_name[32];
|
||||
};
|
||||
|
||||
enum dss_clk_type {
|
||||
DSS_CLK_AHB, /* no set rate. rate controlled through rpm */
|
||||
DSS_CLK_PCLK,
|
||||
DSS_CLK_OTHER,
|
||||
};
|
||||
|
||||
struct dss_clk {
|
||||
struct clk *clk; /* clk handle */
|
||||
char clk_name[32];
|
||||
enum dss_clk_type type;
|
||||
unsigned long rate;
|
||||
unsigned long max_rate;
|
||||
};
|
||||
|
||||
struct dss_module_power {
|
||||
unsigned int num_vreg;
|
||||
struct dss_vreg *vreg_config;
|
||||
unsigned int num_gpio;
|
||||
struct dss_gpio *gpio_config;
|
||||
unsigned int num_clk;
|
||||
struct dss_clk *clk_config;
|
||||
};
|
||||
|
||||
int msm_dss_ioremap_byname(struct platform_device *pdev,
|
||||
struct dss_io_data *io_data, const char *name);
|
||||
void msm_dss_iounmap(struct dss_io_data *io_data);
|
||||
int msm_dss_get_io_mem(struct platform_device *pdev,
|
||||
struct list_head *mem_list);
|
||||
void msm_dss_clean_io_mem(struct list_head *mem_list);
|
||||
int msm_dss_get_pmic_io_mem(struct platform_device *pdev,
|
||||
struct list_head *mem_list);
|
||||
int msm_dss_get_io_irq(struct platform_device *pdev,
|
||||
struct list_head *irq_list, u32 label);
|
||||
void msm_dss_clean_io_irq(struct list_head *irq_list);
|
||||
int msm_dss_enable_gpio(struct dss_gpio *in_gpio, int num_gpio, int enable);
|
||||
int msm_dss_gpio_enable(struct dss_gpio *in_gpio, int num_gpio, int enable);
|
||||
|
||||
int msm_dss_get_vreg(struct device *dev, struct dss_vreg *in_vreg,
|
||||
int num_vreg, int enable);
|
||||
int msm_dss_enable_vreg(struct dss_vreg *in_vreg, int num_vreg, int enable);
|
||||
|
||||
int msm_dss_get_clk(struct device *dev, struct dss_clk *clk_arry, int num_clk);
|
||||
void msm_dss_put_clk(struct dss_clk *clk_arry, int num_clk);
|
||||
int msm_dss_clk_set_rate(struct dss_clk *clk_arry, int num_clk);
|
||||
int msm_dss_single_clk_set_rate(struct dss_clk *clk);
|
||||
int msm_dss_enable_clk(struct dss_clk *clk_arry, int num_clk, int enable);
|
||||
|
||||
int sde_i2c_byte_read(struct i2c_client *client, uint8_t slave_addr,
|
||||
uint8_t reg_offset, uint8_t *read_buf);
|
||||
int sde_i2c_byte_write(struct i2c_client *client, uint8_t slave_addr,
|
||||
uint8_t reg_offset, uint8_t *value);
|
||||
|
||||
#endif /* __SDE_IO_UTIL_H__ */
|
360
techpack/display/include/linux/sde_rsc.h
Normal file
360
techpack/display/include/linux/sde_rsc.h
Normal file
@ -0,0 +1,360 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _SDE_RSC_H_
|
||||
#define _SDE_RSC_H_
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
||||
/* primary display rsc index */
|
||||
#define SDE_RSC_INDEX 0
|
||||
|
||||
#define MAX_RSC_CLIENT_NAME_LEN 128
|
||||
#define NUM_RSC_PROFILING_COUNTERS 3
|
||||
|
||||
/* DRM Object IDs are numbered excluding 0, use 0 to indicate invalid CRTC */
|
||||
#define SDE_RSC_INVALID_CRTC_ID 0
|
||||
|
||||
/**
|
||||
* event will be triggered before sde core power collapse,
|
||||
* mdss gdsc is still on
|
||||
*/
|
||||
#define SDE_RSC_EVENT_PRE_CORE_PC 0x1
|
||||
/**
|
||||
* event will be triggered after sde core collapse complete,
|
||||
* mdss gdsc is off now
|
||||
*/
|
||||
#define SDE_RSC_EVENT_POST_CORE_PC 0x2
|
||||
/**
|
||||
* event will be triggered before restoring the sde core from power collapse,
|
||||
* mdss gdsc is still off
|
||||
*/
|
||||
#define SDE_RSC_EVENT_PRE_CORE_RESTORE 0x4
|
||||
/**
|
||||
* event will be triggered after restoring the sde core from power collapse,
|
||||
* mdss gdsc is on now
|
||||
*/
|
||||
#define SDE_RSC_EVENT_POST_CORE_RESTORE 0x8
|
||||
/**
|
||||
* event attached with solver state enabled
|
||||
* all clients in clk_state or cmd_state
|
||||
*/
|
||||
#define SDE_RSC_EVENT_SOLVER_ENABLED 0x10
|
||||
/**
|
||||
* event attached with solver state disabled
|
||||
* one of the client requested for vid state
|
||||
*/
|
||||
#define SDE_RSC_EVENT_SOLVER_DISABLED 0x20
|
||||
|
||||
/**
|
||||
* sde_rsc_client_type: sde rsc client type information
|
||||
* SDE_RSC_PRIMARY_DISP_CLIENT: A primary display client which can request
|
||||
* vid or cmd state switch.
|
||||
* SDE_RSC_EXTERNAL_DISPLAY_CLIENT:An external display client which can
|
||||
* request only clk state switch.
|
||||
* SDE_RSC_CLK_CLIENT: A clk client request for only rsc clocks
|
||||
* enabled and mode_2 exit state.
|
||||
*/
|
||||
enum sde_rsc_client_type {
|
||||
SDE_RSC_PRIMARY_DISP_CLIENT,
|
||||
SDE_RSC_EXTERNAL_DISP_CLIENT,
|
||||
SDE_RSC_CLK_CLIENT,
|
||||
SDE_RSC_INVALID_CLIENT,
|
||||
};
|
||||
|
||||
/**
|
||||
* sde_rsc_state: sde rsc state information
|
||||
* SDE_RSC_IDLE_STATE: A client requests for idle state when there is no
|
||||
* pixel or cmd transfer expected. An idle vote from
|
||||
* all clients lead to power collapse state.
|
||||
* SDE_RSC_CLK_STATE: A client requests for clk state when it wants to
|
||||
* only avoid mode-2 entry/exit. For ex: V4L2 driver,
|
||||
* sde power handle, etc.
|
||||
* SDE_RSC_CMD_STATE: A client requests for cmd state when it wants to
|
||||
* enable the solver mode.
|
||||
* SDE_RSC_VID_STATE: A client requests for vid state it wants to avoid
|
||||
* solver enable because client is fetching data from
|
||||
* continuously.
|
||||
*/
|
||||
enum sde_rsc_state {
|
||||
SDE_RSC_IDLE_STATE,
|
||||
SDE_RSC_CLK_STATE,
|
||||
SDE_RSC_CMD_STATE,
|
||||
SDE_RSC_VID_STATE,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct sde_rsc_client: stores the rsc client for sde driver
|
||||
* @name: name of the client
|
||||
* @current_state: current client state
|
||||
* @crtc_id: crtc_id associated with this rsc client.
|
||||
* @rsc_index: rsc index of a client - only index "0" valid.
|
||||
* @id: Index of client. It will be assigned during client_create call
|
||||
* @client_type: check sde_rsc_client_type information
|
||||
* @list: list to attach client master list
|
||||
*/
|
||||
struct sde_rsc_client {
|
||||
char name[MAX_RSC_CLIENT_NAME_LEN];
|
||||
short current_state;
|
||||
int crtc_id;
|
||||
u32 rsc_index;
|
||||
u32 id;
|
||||
enum sde_rsc_client_type client_type;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct sde_rsc_event: local event registration entry structure
|
||||
* @cb_func: Pointer to desired callback function
|
||||
* @usr: User pointer to pass to callback on event trigger
|
||||
* @rsc_index: rsc index of a client - only index "0" valid.
|
||||
* @event_type: refer comments in event_register
|
||||
* @list: list to attach event master list
|
||||
*/
|
||||
struct sde_rsc_event {
|
||||
void (*cb_func)(uint32_t event_type, void *usr);
|
||||
void *usr;
|
||||
u32 rsc_index;
|
||||
uint32_t event_type;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct sde_rsc_cmd_config: provides panel configuration to rsc
|
||||
* when client is command mode. It is not required to set it during
|
||||
* video mode.
|
||||
*
|
||||
* @fps: panel te interval
|
||||
* @vtotal: current vertical total (height + vbp + vfp)
|
||||
* @jitter_numer: panel jitter numerator value. This config causes rsc/solver
|
||||
* early before te. Default is 0.8% jitter.
|
||||
* @jitter_denom: panel jitter denominator.
|
||||
* @prefill_lines: max prefill lines based on panel
|
||||
*/
|
||||
struct sde_rsc_cmd_config {
|
||||
u32 fps;
|
||||
u32 vtotal;
|
||||
u32 jitter_numer;
|
||||
u32 jitter_denom;
|
||||
u32 prefill_lines;
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_DRM_SDE_RSC)
|
||||
/**
|
||||
* sde_rsc_client_create() - create the client for sde rsc.
|
||||
* Different displays like DSI, HDMI, DP, WB, etc should call this
|
||||
* api to register their vote for rpmh. They still need to vote for
|
||||
* power handle to get the clocks.
|
||||
|
||||
* @rsc_index: A client will be created on this RSC. As of now only
|
||||
* SDE_RSC_INDEX is valid rsc index.
|
||||
* @name: Caller needs to provide some valid string to identify
|
||||
* the client. "primary", "dp", "hdmi" are suggested name.
|
||||
* @client_type: check client_type enum for information
|
||||
* @vsync_source: This parameter is only valid for primary display. It provides
|
||||
* vsync source information
|
||||
*
|
||||
* Return: client node pointer.
|
||||
*/
|
||||
struct sde_rsc_client *sde_rsc_client_create(u32 rsc_index, char *name,
|
||||
enum sde_rsc_client_type client_type, u32 vsync_source);
|
||||
|
||||
/**
|
||||
* sde_rsc_client_destroy() - Destroy the sde rsc client.
|
||||
*
|
||||
* @client: Client pointer provided by sde_rsc_client_create().
|
||||
*
|
||||
* Return: none
|
||||
*/
|
||||
void sde_rsc_client_destroy(struct sde_rsc_client *client);
|
||||
|
||||
/**
|
||||
* sde_rsc_client_state_update() - rsc client state update
|
||||
* Video mode, cmd mode and clk state are supported as modes. A client need to
|
||||
* set this property during panel time. A switching client can set the
|
||||
* property to change the state
|
||||
*
|
||||
* @client: Client pointer provided by sde_rsc_client_create().
|
||||
* @state: Client state - video/cmd
|
||||
* @config: fps, vtotal, porches, etc configuration for command mode
|
||||
* panel
|
||||
* @crtc_id: current client's crtc id
|
||||
* @wait_vblank_crtc_id: Output parameter. If set to non-zero, rsc hw
|
||||
* state update requires a wait for one vblank on
|
||||
* the primary crtc. In that case, this output
|
||||
* param will be set to the crtc on which to wait.
|
||||
* If SDE_RSC_INVALID_CRTC_ID, no wait necessary
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int sde_rsc_client_state_update(struct sde_rsc_client *client,
|
||||
enum sde_rsc_state state,
|
||||
struct sde_rsc_cmd_config *config, int crtc_id,
|
||||
int *wait_vblank_crtc_id);
|
||||
|
||||
/**
|
||||
* sde_rsc_client_get_vsync_refcount() - returns the status of the vsync
|
||||
* refcount, to signal if the client needs to reset the refcounting logic
|
||||
* @client: Client pointer provided by sde_rsc_client_create().
|
||||
*
|
||||
* Return: true if the state update has completed.
|
||||
*/
|
||||
int sde_rsc_client_get_vsync_refcount(
|
||||
struct sde_rsc_client *caller_client);
|
||||
|
||||
/**
|
||||
* sde_rsc_client_reset_vsync_refcount() - reduces the refcounting
|
||||
* logic that waits for the vsync.
|
||||
* @client: Client pointer provided by sde_rsc_client_create().
|
||||
*
|
||||
* Return: true if the state update has completed.
|
||||
*/
|
||||
int sde_rsc_client_reset_vsync_refcount(
|
||||
struct sde_rsc_client *caller_client);
|
||||
|
||||
/**
|
||||
* sde_rsc_client_is_state_update_complete() - check if state update is complete
|
||||
* RSC state transition is not complete until HW receives VBLANK signal. This
|
||||
* function checks RSC HW to determine whether that signal has been received.
|
||||
* @client: Client pointer provided by sde_rsc_client_create().
|
||||
*
|
||||
* Return: true if the state update has completed.
|
||||
*/
|
||||
bool sde_rsc_client_is_state_update_complete(
|
||||
struct sde_rsc_client *caller_client);
|
||||
|
||||
/**
|
||||
* sde_rsc_client_vote() - stores ab/ib vote for rsc client
|
||||
*
|
||||
* @client: Client pointer provided by sde_rsc_client_create().
|
||||
* @bus_id: data bus identifier
|
||||
* @ab: aggregated bandwidth vote from client.
|
||||
* @ib: instant bandwidth vote from client.
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int sde_rsc_client_vote(struct sde_rsc_client *caller_client,
|
||||
u32 bus_id, u64 ab_vote, u64 ib_vote);
|
||||
|
||||
/**
|
||||
* sde_rsc_register_event - register a callback function for an event
|
||||
* @rsc_index: A client will be created on this RSC. As of now only
|
||||
* SDE_RSC_INDEX is valid rsc index.
|
||||
* @event_type: event type to register; client sets 0x3 if it wants
|
||||
* to register for CORE_PC and CORE_RESTORE - both events.
|
||||
* @cb_func: Pointer to desired callback function
|
||||
* @usr: User pointer to pass to callback on event trigger
|
||||
* Returns: sde_rsc_event pointer on success
|
||||
*/
|
||||
struct sde_rsc_event *sde_rsc_register_event(int rsc_index, uint32_t event_type,
|
||||
void (*cb_func)(uint32_t event_type, void *usr), void *usr);
|
||||
|
||||
/**
|
||||
* sde_rsc_unregister_event - unregister callback for an event
|
||||
* @sde_rsc_event: event returned by sde_rsc_register_event
|
||||
*/
|
||||
void sde_rsc_unregister_event(struct sde_rsc_event *event);
|
||||
|
||||
/**
|
||||
* is_sde_rsc_available - check if display rsc available.
|
||||
* @rsc_index: A client will be created on this RSC. As of now only
|
||||
* SDE_RSC_INDEX is valid rsc index.
|
||||
* Returns: true if rsc is available; false in all other cases
|
||||
*/
|
||||
bool is_sde_rsc_available(int rsc_index);
|
||||
|
||||
/**
|
||||
* get_sde_rsc_current_state - gets the current state of sde rsc.
|
||||
* @rsc_index: A client will be created on this RSC. As of now only
|
||||
* SDE_RSC_INDEX is valid rsc index.
|
||||
* Returns: current state if rsc available; SDE_RSC_IDLE_STATE for
|
||||
* all other cases
|
||||
*/
|
||||
enum sde_rsc_state get_sde_rsc_current_state(int rsc_index);
|
||||
|
||||
/**
|
||||
* sde_rsc_client_trigger_vote() - triggers ab/ib vote for rsc client
|
||||
*
|
||||
* @client: Client pointer provided by sde_rsc_client_create().
|
||||
* @delta_vote: if bw vote is increased or decreased
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int sde_rsc_client_trigger_vote(struct sde_rsc_client *caller_client,
|
||||
bool delta_vote);
|
||||
|
||||
#else
|
||||
|
||||
static inline struct sde_rsc_client *sde_rsc_client_create(u32 rsc_index,
|
||||
char *name, enum sde_rsc_client_type client_type, u32 vsync_source)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void sde_rsc_client_destroy(struct sde_rsc_client *client)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int sde_rsc_client_state_update(struct sde_rsc_client *client,
|
||||
enum sde_rsc_state state,
|
||||
struct sde_rsc_cmd_config *config, int crtc_id,
|
||||
int *wait_vblank_crtc_id)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int sde_rsc_client_get_vsync_refcount(
|
||||
struct sde_rsc_client *caller_client)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int sde_rsc_client_reset_vsync_refcount(
|
||||
struct sde_rsc_client *caller_client)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline bool sde_rsc_client_is_state_update_complete(
|
||||
struct sde_rsc_client *caller_client)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline int sde_rsc_client_vote(struct sde_rsc_client *caller_client,
|
||||
u32 bus_id, u64 ab_vote, u64 ib_vote)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline struct sde_rsc_event *sde_rsc_register_event(int rsc_index,
|
||||
uint32_t event_type,
|
||||
void (*cb_func)(uint32_t event_type, void *usr), void *usr)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void sde_rsc_unregister_event(struct sde_rsc_event *event)
|
||||
{
|
||||
}
|
||||
|
||||
static inline bool is_sde_rsc_available(int rsc_index)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline enum sde_rsc_state get_sde_rsc_current_state(int rsc_index)
|
||||
{
|
||||
return SDE_RSC_IDLE_STATE;
|
||||
}
|
||||
|
||||
static inline int sde_rsc_client_trigger_vote(
|
||||
struct sde_rsc_client *caller_client, bool delta_vote)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_DRM_SDE_RSC */
|
||||
|
||||
#endif /* _SDE_RSC_H_ */
|
97
techpack/display/include/linux/sde_vm_event.h
Normal file
97
techpack/display/include/linux/sde_vm_event.h
Normal file
@ -0,0 +1,97 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef __SDE_VM_EVENT_H__
|
||||
#define __SDE_VM_EVENT_H__
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <drm/drm_device.h>
|
||||
|
||||
/**
|
||||
* struct - msm_io_irq_entry - define irq item
|
||||
* @label: hh_irq_label for the irq
|
||||
* @irq_num: linux mapped irq num
|
||||
* @list: list head pointer
|
||||
*/
|
||||
struct msm_io_irq_entry {
|
||||
u32 label;
|
||||
u32 irq_num;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct - msm_io_mem_entry - define io memory item
|
||||
* @base: reg base
|
||||
* @size: size of the reg range
|
||||
* @list: list head pointer
|
||||
*/
|
||||
struct msm_io_mem_entry {
|
||||
phys_addr_t base;
|
||||
phys_addr_t size;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct - msm_io_res - represents the hw resources for vm sharing
|
||||
* @irq: list of IRQ's of all the dislay sub-devices
|
||||
* @mem: list of IO memory ranges of all the display sub-devices
|
||||
*/
|
||||
struct msm_io_res {
|
||||
struct list_head irq;
|
||||
struct list_head mem;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct msm_vm_ops - hooks for communication with vm clients
|
||||
* @vm_pre_hw_release: invoked before releasing the HW
|
||||
* @vm_post_hw_acquire: invoked before pushing the first commit
|
||||
* @vm_check: invoked to check the readiness of the vm_clients
|
||||
* before releasing the HW
|
||||
* @vm_get_io_resources: invoked to collect HW resources
|
||||
*/
|
||||
struct msm_vm_ops {
|
||||
int (*vm_pre_hw_release)(void *priv_data);
|
||||
int (*vm_post_hw_acquire)(void *priv_data);
|
||||
int (*vm_check)(void *priv_data);
|
||||
int (*vm_get_io_resources)(struct msm_io_res *io_res, void *priv_data);
|
||||
};
|
||||
|
||||
/**
|
||||
* msm_vm_client_entry - defines the vm client info
|
||||
* @ops: client vm_ops
|
||||
* @dev: clients device id. Used in unregister
|
||||
* @data: client custom data
|
||||
* @list: linked list entry
|
||||
*/
|
||||
struct msm_vm_client_entry {
|
||||
struct msm_vm_ops ops;
|
||||
struct device *dev;
|
||||
void *data;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
/**
|
||||
* msm_register_vm_event - api for display dependent drivers(clients) to
|
||||
* register for vm events
|
||||
* @dev: msm device
|
||||
* @client_dev: client device
|
||||
* @ops: vm event hooks
|
||||
* @priv_data: client custom data
|
||||
*/
|
||||
int msm_register_vm_event(struct device *dev, struct device *client_dev,
|
||||
struct msm_vm_ops *ops, void *priv_data);
|
||||
|
||||
/**
|
||||
* msm_unregister_vm_event - api for display dependent drivers(clients) to
|
||||
* unregister from vm events
|
||||
* @dev: msm device
|
||||
* @client_dev: client device
|
||||
*/
|
||||
void msm_unregister_vm_event(struct device *dev, struct device *client_dev);
|
||||
|
||||
#endif //__SDE_VM_EVENT_H__
|
4
techpack/display/include/uapi/Kbuild
Normal file
4
techpack/display/include/uapi/Kbuild
Normal file
@ -0,0 +1,4 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note
|
||||
|
||||
# Top-level Makefile calls into asm-$(ARCH)
|
||||
# List only non-arch directories below
|
5
techpack/display/include/uapi/display/Kbuild
Normal file
5
techpack/display/include/uapi/display/Kbuild
Normal file
@ -0,0 +1,5 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note
|
||||
|
||||
header-y += media/
|
||||
header-y += drm/
|
||||
header-y += hdcp/
|
5
techpack/display/include/uapi/display/drm/Kbuild
Normal file
5
techpack/display/include/uapi/display/drm/Kbuild
Normal file
@ -0,0 +1,5 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note
|
||||
|
||||
header-y += msm_drm_pp.h
|
||||
header-y += sde_drm.h
|
||||
|
686
techpack/display/include/uapi/display/drm/msm_drm_pp.h
Normal file
686
techpack/display/include/uapi/display/drm/msm_drm_pp.h
Normal file
@ -0,0 +1,686 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
|
||||
/*
|
||||
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _MSM_DRM_PP_H_
|
||||
#define _MSM_DRM_PP_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
/**
|
||||
* struct drm_msm_pcc_coeff - PCC coefficient structure for each color
|
||||
* component.
|
||||
* @c: constant coefficient.
|
||||
* @r: red coefficient.
|
||||
* @g: green coefficient.
|
||||
* @b: blue coefficient.
|
||||
* @rg: red green coefficient.
|
||||
* @gb: green blue coefficient.
|
||||
* @rb: red blue coefficient.
|
||||
* @rgb: red blue green coefficient.
|
||||
*/
|
||||
|
||||
struct drm_msm_pcc_coeff {
|
||||
__u32 c;
|
||||
__u32 r;
|
||||
__u32 g;
|
||||
__u32 b;
|
||||
__u32 rg;
|
||||
__u32 gb;
|
||||
__u32 rb;
|
||||
__u32 rgb;
|
||||
};
|
||||
|
||||
#define PCC_BEFORE (1 << 0)
|
||||
|
||||
/**
|
||||
* struct drm_msm_pcc - pcc feature structure
|
||||
* @flags: for customizing operations. Values can be
|
||||
* - PCC_BEFORE: Operate PCC using a 'before' arrangement
|
||||
* @r: red coefficients.
|
||||
* @g: green coefficients.
|
||||
* @b: blue coefficients.
|
||||
* @r_rr: second order coefficients
|
||||
* @r_gg: second order coefficients
|
||||
* @r_bb: second order coefficients
|
||||
* @g_rr: second order coefficients
|
||||
* @g_gg: second order coefficients
|
||||
* @g_bb: second order coefficients
|
||||
* @b_rr: second order coefficients
|
||||
* @b_gg: second order coefficients
|
||||
* @b_bb: second order coefficients
|
||||
*/
|
||||
#define DRM_MSM_PCC3
|
||||
struct drm_msm_pcc {
|
||||
__u64 flags;
|
||||
struct drm_msm_pcc_coeff r;
|
||||
struct drm_msm_pcc_coeff g;
|
||||
struct drm_msm_pcc_coeff b;
|
||||
__u32 r_rr;
|
||||
__u32 r_gg;
|
||||
__u32 r_bb;
|
||||
__u32 g_rr;
|
||||
__u32 g_gg;
|
||||
__u32 g_bb;
|
||||
__u32 b_rr;
|
||||
__u32 b_gg;
|
||||
__u32 b_bb;
|
||||
};
|
||||
|
||||
/* struct drm_msm_pa_vlut - picture adjustment vLUT structure
|
||||
* flags: for customizing vlut operation
|
||||
* val: vLUT values
|
||||
*/
|
||||
#define PA_VLUT_SIZE 256
|
||||
struct drm_msm_pa_vlut {
|
||||
__u64 flags;
|
||||
__u32 val[PA_VLUT_SIZE];
|
||||
};
|
||||
|
||||
#define PA_HSIC_HUE_ENABLE (1 << 0)
|
||||
#define PA_HSIC_SAT_ENABLE (1 << 1)
|
||||
#define PA_HSIC_VAL_ENABLE (1 << 2)
|
||||
#define PA_HSIC_CONT_ENABLE (1 << 3)
|
||||
/**
|
||||
* struct drm_msm_pa_hsic - pa hsic feature structure
|
||||
* @flags: flags for the feature customization, values can be:
|
||||
* - PA_HSIC_HUE_ENABLE: Enable hue adjustment
|
||||
* - PA_HSIC_SAT_ENABLE: Enable saturation adjustment
|
||||
* - PA_HSIC_VAL_ENABLE: Enable value adjustment
|
||||
* - PA_HSIC_CONT_ENABLE: Enable contrast adjustment
|
||||
*
|
||||
* @hue: hue setting
|
||||
* @saturation: saturation setting
|
||||
* @value: value setting
|
||||
* @contrast: contrast setting
|
||||
*/
|
||||
#define DRM_MSM_PA_HSIC
|
||||
struct drm_msm_pa_hsic {
|
||||
__u64 flags;
|
||||
__u32 hue;
|
||||
__u32 saturation;
|
||||
__u32 value;
|
||||
__u32 contrast;
|
||||
};
|
||||
|
||||
#define MEMCOL_PROT_HUE (1 << 0)
|
||||
#define MEMCOL_PROT_SAT (1 << 1)
|
||||
#define MEMCOL_PROT_VAL (1 << 2)
|
||||
#define MEMCOL_PROT_CONT (1 << 3)
|
||||
#define MEMCOL_PROT_SIXZONE (1 << 4)
|
||||
#define MEMCOL_PROT_BLEND (1 << 5)
|
||||
/* struct drm_msm_memcol - Memory color feature structure.
|
||||
* Skin, sky, foliage features are supported.
|
||||
* @prot_flags: Bit mask for enabling protection feature.
|
||||
* @color_adjust_p0: Adjustment curve.
|
||||
* @color_adjust_p1: Adjustment curve.
|
||||
* @color_adjust_p2: Adjustment curve.
|
||||
* @blend_gain: Blend gain weightage from othe PA features.
|
||||
* @sat_hold: Saturation hold value.
|
||||
* @val_hold: Value hold info.
|
||||
* @hue_region: Hue qualifier.
|
||||
* @sat_region: Saturation qualifier.
|
||||
* @val_region: Value qualifier.
|
||||
*/
|
||||
#define DRM_MSM_MEMCOL
|
||||
struct drm_msm_memcol {
|
||||
__u64 prot_flags;
|
||||
__u32 color_adjust_p0;
|
||||
__u32 color_adjust_p1;
|
||||
__u32 color_adjust_p2;
|
||||
__u32 blend_gain;
|
||||
__u32 sat_hold;
|
||||
__u32 val_hold;
|
||||
__u32 hue_region;
|
||||
__u32 sat_region;
|
||||
__u32 val_region;
|
||||
};
|
||||
|
||||
#define DRM_MSM_SIXZONE
|
||||
#define SIXZONE_LUT_SIZE 384
|
||||
#define SIXZONE_HUE_ENABLE (1 << 0)
|
||||
#define SIXZONE_SAT_ENABLE (1 << 1)
|
||||
#define SIXZONE_VAL_ENABLE (1 << 2)
|
||||
/* struct drm_msm_sixzone_curve - Sixzone HSV adjustment curve structure.
|
||||
* @p0: Hue adjustment.
|
||||
* @p1: Saturation/Value adjustment.
|
||||
*/
|
||||
struct drm_msm_sixzone_curve {
|
||||
__u32 p1;
|
||||
__u32 p0;
|
||||
};
|
||||
|
||||
/* struct drm_msm_sixzone - Sixzone feature structure.
|
||||
* @flags: for feature customization, values can be:
|
||||
* - SIXZONE_HUE_ENABLE: Enable hue adjustment
|
||||
* - SIXZONE_SAT_ENABLE: Enable saturation adjustment
|
||||
* - SIXZONE_VAL_ENABLE: Enable value adjustment
|
||||
* @threshold: threshold qualifier.
|
||||
* @adjust_p0: Adjustment curve.
|
||||
* @adjust_p1: Adjustment curve.
|
||||
* @sat_hold: Saturation hold info.
|
||||
* @val_hold: Value hold info.
|
||||
* @curve: HSV adjustment curve lut.
|
||||
*/
|
||||
struct drm_msm_sixzone {
|
||||
__u64 flags;
|
||||
__u32 threshold;
|
||||
__u32 adjust_p0;
|
||||
__u32 adjust_p1;
|
||||
__u32 sat_hold;
|
||||
__u32 val_hold;
|
||||
struct drm_msm_sixzone_curve curve[SIXZONE_LUT_SIZE];
|
||||
};
|
||||
|
||||
#define GAMUT_3D_MODE_17 1
|
||||
#define GAMUT_3D_MODE_5 2
|
||||
#define GAMUT_3D_MODE_13 3
|
||||
|
||||
#define GAMUT_3D_MODE17_TBL_SZ 1229
|
||||
#define GAMUT_3D_MODE5_TBL_SZ 32
|
||||
#define GAMUT_3D_MODE13_TBL_SZ 550
|
||||
#define GAMUT_3D_SCALE_OFF_SZ 16
|
||||
#define GAMUT_3D_SCALEB_OFF_SZ 12
|
||||
#define GAMUT_3D_TBL_NUM 4
|
||||
#define GAMUT_3D_SCALE_OFF_TBL_NUM 3
|
||||
#define GAMUT_3D_MAP_EN (1 << 0)
|
||||
|
||||
/**
|
||||
* struct drm_msm_3d_col - 3d gamut color component structure
|
||||
* @c0: Holds c0 value
|
||||
* @c2_c1: Holds c2/c1 values
|
||||
*/
|
||||
struct drm_msm_3d_col {
|
||||
__u32 c2_c1;
|
||||
__u32 c0;
|
||||
};
|
||||
/**
|
||||
* struct drm_msm_3d_gamut - 3d gamut feature structure
|
||||
* @flags: flags for the feature values are:
|
||||
* 0 - no map
|
||||
* GAMUT_3D_MAP_EN - enable map
|
||||
* @mode: lut mode can take following values:
|
||||
* - GAMUT_3D_MODE_17
|
||||
* - GAMUT_3D_MODE_5
|
||||
* - GAMUT_3D_MODE_13
|
||||
* @scale_off: Scale offset table
|
||||
* @col: Color component tables
|
||||
*/
|
||||
struct drm_msm_3d_gamut {
|
||||
__u64 flags;
|
||||
__u32 mode;
|
||||
__u32 scale_off[GAMUT_3D_SCALE_OFF_TBL_NUM][GAMUT_3D_SCALE_OFF_SZ];
|
||||
struct drm_msm_3d_col col[GAMUT_3D_TBL_NUM][GAMUT_3D_MODE17_TBL_SZ];
|
||||
};
|
||||
|
||||
#define PGC_TBL_LEN 512
|
||||
#define PGC_8B_ROUND (1 << 0)
|
||||
/**
|
||||
* struct drm_msm_pgc_lut - pgc lut feature structure
|
||||
* @flags: flags for the featue values can be:
|
||||
* - PGC_8B_ROUND
|
||||
* @c0: color0 component lut
|
||||
* @c1: color1 component lut
|
||||
* @c2: color2 component lut
|
||||
*/
|
||||
struct drm_msm_pgc_lut {
|
||||
__u64 flags;
|
||||
__u32 c0[PGC_TBL_LEN];
|
||||
__u32 c1[PGC_TBL_LEN];
|
||||
__u32 c2[PGC_TBL_LEN];
|
||||
};
|
||||
|
||||
#define IGC_TBL_LEN 256
|
||||
#define IGC_DITHER_ENABLE (1 << 0)
|
||||
/**
|
||||
* struct drm_msm_igc_lut - igc lut feature structure
|
||||
* @flags: flags for the feature customization, values can be:
|
||||
* - IGC_DITHER_ENABLE: Enable dither functionality
|
||||
* @c0: color0 component lut
|
||||
* @c1: color1 component lut
|
||||
* @c2: color2 component lut
|
||||
* @strength: dither strength, considered valid when IGC_DITHER_ENABLE
|
||||
* is set in flags. Strength value based on source bit width.
|
||||
* @c0_last: color0 lut_last component
|
||||
* @c1_last: color1 lut_last component
|
||||
* @c2_last: color2 lut_last component
|
||||
*/
|
||||
struct drm_msm_igc_lut {
|
||||
__u64 flags;
|
||||
__u32 c0[IGC_TBL_LEN];
|
||||
__u32 c1[IGC_TBL_LEN];
|
||||
__u32 c2[IGC_TBL_LEN];
|
||||
__u32 strength;
|
||||
__u32 c0_last;
|
||||
__u32 c1_last;
|
||||
__u32 c2_last;
|
||||
};
|
||||
#define LAST_LUT 2
|
||||
|
||||
#define HIST_V_SIZE 256
|
||||
/**
|
||||
* struct drm_msm_hist - histogram feature structure
|
||||
* @flags: for customizing operations
|
||||
* @data: histogram data
|
||||
*/
|
||||
struct drm_msm_hist {
|
||||
__u64 flags;
|
||||
__u32 data[HIST_V_SIZE];
|
||||
};
|
||||
|
||||
#define AD4_LUT_GRP0_SIZE 33
|
||||
#define AD4_LUT_GRP1_SIZE 32
|
||||
/*
|
||||
* struct drm_msm_ad4_init - ad4 init structure set by user-space client.
|
||||
* Init param values can change based on tuning
|
||||
* hence it is passed by user-space clients.
|
||||
*/
|
||||
struct drm_msm_ad4_init {
|
||||
__u32 init_param_001[AD4_LUT_GRP0_SIZE];
|
||||
__u32 init_param_002[AD4_LUT_GRP0_SIZE];
|
||||
__u32 init_param_003[AD4_LUT_GRP0_SIZE];
|
||||
__u32 init_param_004[AD4_LUT_GRP0_SIZE];
|
||||
__u32 init_param_005[AD4_LUT_GRP1_SIZE];
|
||||
__u32 init_param_006[AD4_LUT_GRP1_SIZE];
|
||||
__u32 init_param_007[AD4_LUT_GRP0_SIZE];
|
||||
__u32 init_param_008[AD4_LUT_GRP0_SIZE];
|
||||
__u32 init_param_009;
|
||||
__u32 init_param_010;
|
||||
__u32 init_param_011;
|
||||
__u32 init_param_012;
|
||||
__u32 init_param_013;
|
||||
__u32 init_param_014;
|
||||
__u32 init_param_015;
|
||||
__u32 init_param_016;
|
||||
__u32 init_param_017;
|
||||
__u32 init_param_018;
|
||||
__u32 init_param_019;
|
||||
__u32 init_param_020;
|
||||
__u32 init_param_021;
|
||||
__u32 init_param_022;
|
||||
__u32 init_param_023;
|
||||
__u32 init_param_024;
|
||||
__u32 init_param_025;
|
||||
__u32 init_param_026;
|
||||
__u32 init_param_027;
|
||||
__u32 init_param_028;
|
||||
__u32 init_param_029;
|
||||
__u32 init_param_030;
|
||||
__u32 init_param_031;
|
||||
__u32 init_param_032;
|
||||
__u32 init_param_033;
|
||||
__u32 init_param_034;
|
||||
__u32 init_param_035;
|
||||
__u32 init_param_036;
|
||||
__u32 init_param_037;
|
||||
__u32 init_param_038;
|
||||
__u32 init_param_039;
|
||||
__u32 init_param_040;
|
||||
__u32 init_param_041;
|
||||
__u32 init_param_042;
|
||||
__u32 init_param_043;
|
||||
__u32 init_param_044;
|
||||
__u32 init_param_045;
|
||||
__u32 init_param_046;
|
||||
__u32 init_param_047;
|
||||
__u32 init_param_048;
|
||||
__u32 init_param_049;
|
||||
__u32 init_param_050;
|
||||
__u32 init_param_051;
|
||||
__u32 init_param_052;
|
||||
__u32 init_param_053;
|
||||
__u32 init_param_054;
|
||||
__u32 init_param_055;
|
||||
__u32 init_param_056;
|
||||
__u32 init_param_057;
|
||||
__u32 init_param_058;
|
||||
__u32 init_param_059;
|
||||
__u32 init_param_060;
|
||||
__u32 init_param_061;
|
||||
__u32 init_param_062;
|
||||
__u32 init_param_063;
|
||||
__u32 init_param_064;
|
||||
__u32 init_param_065;
|
||||
__u32 init_param_066;
|
||||
__u32 init_param_067;
|
||||
__u32 init_param_068;
|
||||
__u32 init_param_069;
|
||||
__u32 init_param_070;
|
||||
__u32 init_param_071;
|
||||
__u32 init_param_072;
|
||||
__u32 init_param_073;
|
||||
__u32 init_param_074;
|
||||
__u32 init_param_075;
|
||||
};
|
||||
|
||||
/*
|
||||
* struct drm_msm_ad4_cfg - ad4 config structure set by user-space client.
|
||||
* Config param values can vary based on tuning,
|
||||
* hence it is passed by user-space clients.
|
||||
*/
|
||||
struct drm_msm_ad4_cfg {
|
||||
__u32 cfg_param_001;
|
||||
__u32 cfg_param_002;
|
||||
__u32 cfg_param_003;
|
||||
__u32 cfg_param_004;
|
||||
__u32 cfg_param_005;
|
||||
__u32 cfg_param_006;
|
||||
__u32 cfg_param_007;
|
||||
__u32 cfg_param_008;
|
||||
__u32 cfg_param_009;
|
||||
__u32 cfg_param_010;
|
||||
__u32 cfg_param_011;
|
||||
__u32 cfg_param_012;
|
||||
__u32 cfg_param_013;
|
||||
__u32 cfg_param_014;
|
||||
__u32 cfg_param_015;
|
||||
__u32 cfg_param_016;
|
||||
__u32 cfg_param_017;
|
||||
__u32 cfg_param_018;
|
||||
__u32 cfg_param_019;
|
||||
__u32 cfg_param_020;
|
||||
__u32 cfg_param_021;
|
||||
__u32 cfg_param_022;
|
||||
__u32 cfg_param_023;
|
||||
__u32 cfg_param_024;
|
||||
__u32 cfg_param_025;
|
||||
__u32 cfg_param_026;
|
||||
__u32 cfg_param_027;
|
||||
__u32 cfg_param_028;
|
||||
__u32 cfg_param_029;
|
||||
__u32 cfg_param_030;
|
||||
__u32 cfg_param_031;
|
||||
__u32 cfg_param_032;
|
||||
__u32 cfg_param_033;
|
||||
__u32 cfg_param_034;
|
||||
__u32 cfg_param_035;
|
||||
__u32 cfg_param_036;
|
||||
__u32 cfg_param_037;
|
||||
__u32 cfg_param_038;
|
||||
__u32 cfg_param_039;
|
||||
__u32 cfg_param_040;
|
||||
__u32 cfg_param_041;
|
||||
__u32 cfg_param_042;
|
||||
__u32 cfg_param_043;
|
||||
__u32 cfg_param_044;
|
||||
__u32 cfg_param_045;
|
||||
__u32 cfg_param_046;
|
||||
__u32 cfg_param_047;
|
||||
__u32 cfg_param_048;
|
||||
__u32 cfg_param_049;
|
||||
__u32 cfg_param_050;
|
||||
__u32 cfg_param_051;
|
||||
__u32 cfg_param_052;
|
||||
__u32 cfg_param_053;
|
||||
};
|
||||
|
||||
#define DITHER_MATRIX_SZ 16
|
||||
#define DITHER_LUMA_MODE (1 << 0)
|
||||
|
||||
/**
|
||||
* struct drm_msm_dither - dither feature structure
|
||||
* @flags: flags for the feature customization, values can be:
|
||||
-DITHER_LUMA_MODE: Enable LUMA dither mode
|
||||
* @temporal_en: temperal dither enable
|
||||
* @c0_bitdepth: c0 component bit depth
|
||||
* @c1_bitdepth: c1 component bit depth
|
||||
* @c2_bitdepth: c2 component bit depth
|
||||
* @c3_bitdepth: c2 component bit depth
|
||||
* @matrix: dither strength matrix
|
||||
*/
|
||||
struct drm_msm_dither {
|
||||
__u64 flags;
|
||||
__u32 temporal_en;
|
||||
__u32 c0_bitdepth;
|
||||
__u32 c1_bitdepth;
|
||||
__u32 c2_bitdepth;
|
||||
__u32 c3_bitdepth;
|
||||
__u32 matrix[DITHER_MATRIX_SZ];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct drm_msm_pa_dither - dspp dither feature structure
|
||||
* @flags: for customizing operations
|
||||
* @strength: dither strength
|
||||
* @offset_en: offset enable bit
|
||||
* @matrix: dither data matrix
|
||||
*/
|
||||
#define DRM_MSM_PA_DITHER
|
||||
struct drm_msm_pa_dither {
|
||||
__u64 flags;
|
||||
__u32 strength;
|
||||
__u32 offset_en;
|
||||
__u32 matrix[DITHER_MATRIX_SZ];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct drm_msm_ad4_roi_cfg - ad4 roi params config set
|
||||
* by user-space client.
|
||||
* @h_x - hotizontal direction start
|
||||
* @h_y - hotizontal direction end
|
||||
* @v_x - vertical direction start
|
||||
* @v_y - vertical direction end
|
||||
* @factor_in - the alpha value for inside roi region
|
||||
* @factor_out - the alpha value for outside roi region
|
||||
*/
|
||||
#define DRM_MSM_AD4_ROI
|
||||
struct drm_msm_ad4_roi_cfg {
|
||||
__u32 h_x;
|
||||
__u32 h_y;
|
||||
__u32 v_x;
|
||||
__u32 v_y;
|
||||
__u32 factor_in;
|
||||
__u32 factor_out;
|
||||
};
|
||||
|
||||
#define LTM_FEATURE_DEF 1
|
||||
#define LTM_DATA_SIZE_0 32
|
||||
#define LTM_DATA_SIZE_1 128
|
||||
#define LTM_DATA_SIZE_2 256
|
||||
#define LTM_DATA_SIZE_3 33
|
||||
#define LTM_BUFFER_SIZE 5
|
||||
#define LTM_GUARD_BYTES 255
|
||||
#define LTM_BLOCK_SIZE 2
|
||||
|
||||
#define LTM_STATS_SAT (1 << 1)
|
||||
#define LTM_STATS_MERGE_SAT (1 << 2)
|
||||
#define LTM_HIST_CHECKSUM_SUPPORT (1 << 0)
|
||||
|
||||
/*
|
||||
* struct drm_msm_ltm_stats_data - LTM stats data structure
|
||||
*/
|
||||
struct drm_msm_ltm_stats_data {
|
||||
__u32 stats_01[LTM_DATA_SIZE_0][LTM_DATA_SIZE_1];
|
||||
__u32 stats_02[LTM_DATA_SIZE_2];
|
||||
__u32 stats_03[LTM_DATA_SIZE_0];
|
||||
__u32 stats_04[LTM_DATA_SIZE_0];
|
||||
__u32 stats_05[LTM_DATA_SIZE_0];
|
||||
__u32 status_flag;
|
||||
__u32 display_h;
|
||||
__u32 display_v;
|
||||
__u32 init_h[LTM_BLOCK_SIZE];
|
||||
__u32 init_v;
|
||||
__u32 inc_h;
|
||||
__u32 inc_v;
|
||||
__u32 portrait_en;
|
||||
__u32 merge_en;
|
||||
__u32 cfg_param_01;
|
||||
__u32 cfg_param_02;
|
||||
__u32 cfg_param_03;
|
||||
__u32 cfg_param_04;
|
||||
__u32 feature_flag;
|
||||
__u32 checksum;
|
||||
};
|
||||
|
||||
/*
|
||||
* struct drm_msm_ltm_init_param - LTM init param structure
|
||||
*/
|
||||
struct drm_msm_ltm_init_param {
|
||||
__u32 init_param_01;
|
||||
__u32 init_param_02;
|
||||
__u32 init_param_03;
|
||||
__u32 init_param_04;
|
||||
};
|
||||
|
||||
/*
|
||||
* struct drm_msm_ltm_cfg_param - LTM config param structure
|
||||
*/
|
||||
struct drm_msm_ltm_cfg_param {
|
||||
__u32 cfg_param_01;
|
||||
__u32 cfg_param_02;
|
||||
__u32 cfg_param_03;
|
||||
__u32 cfg_param_04;
|
||||
__u32 cfg_param_05;
|
||||
__u32 cfg_param_06;
|
||||
};
|
||||
|
||||
/*
|
||||
* struct drm_msm_ltm_data - LTM data structure
|
||||
*/
|
||||
struct drm_msm_ltm_data {
|
||||
__u32 data[LTM_DATA_SIZE_0][LTM_DATA_SIZE_3];
|
||||
};
|
||||
|
||||
/*
|
||||
* struct drm_msm_ltm_buffers_crtl - LTM buffer control structure.
|
||||
* This struct will be used to init and
|
||||
* de-init the LTM buffers in driver.
|
||||
* @num_of_buffers: valid number of buffers used
|
||||
* @fds: fd array to for all the valid buffers
|
||||
*/
|
||||
struct drm_msm_ltm_buffers_ctrl {
|
||||
__u32 num_of_buffers;
|
||||
__u32 fds[LTM_BUFFER_SIZE];
|
||||
};
|
||||
|
||||
/*
|
||||
* struct drm_msm_ltm_buffer - LTM buffer structure.
|
||||
* This struct will be passed from driver to user
|
||||
* space for LTM stats data notification.
|
||||
* @fd: fd assicated with the buffer that has LTM stats data
|
||||
* @offset: offset from base address that used for alignment
|
||||
* @status status flag for error indication
|
||||
*/
|
||||
struct drm_msm_ltm_buffer {
|
||||
__u32 fd;
|
||||
__u32 offset;
|
||||
__u32 status;
|
||||
};
|
||||
|
||||
#define SPR_INIT_PARAM_SIZE_1 4
|
||||
#define SPR_INIT_PARAM_SIZE_2 5
|
||||
#define SPR_INIT_PARAM_SIZE_3 16
|
||||
#define SPR_INIT_PARAM_SIZE_4 24
|
||||
#define SPR_INIT_PARAM_SIZE_5 32
|
||||
|
||||
/**
|
||||
* struct drm_msm_spr_init_cfg - SPR initial configuration structure
|
||||
*
|
||||
*/
|
||||
struct drm_msm_spr_init_cfg {
|
||||
__u64 flags;
|
||||
__u16 cfg0;
|
||||
__u16 cfg1;
|
||||
__u16 cfg2;
|
||||
__u16 cfg3;
|
||||
__u16 cfg4;
|
||||
__u16 cfg5;
|
||||
__u16 cfg6;
|
||||
__u16 cfg7;
|
||||
__u16 cfg8;
|
||||
__u16 cfg9;
|
||||
__u32 cfg10;
|
||||
__u16 cfg11[SPR_INIT_PARAM_SIZE_1];
|
||||
__u16 cfg12[SPR_INIT_PARAM_SIZE_1];
|
||||
__u16 cfg13[SPR_INIT_PARAM_SIZE_1];
|
||||
__u16 cfg14[SPR_INIT_PARAM_SIZE_2];
|
||||
__u16 cfg15[SPR_INIT_PARAM_SIZE_5];
|
||||
int cfg16[SPR_INIT_PARAM_SIZE_3];
|
||||
int cfg17[SPR_INIT_PARAM_SIZE_4];
|
||||
};
|
||||
|
||||
#define FEATURE_DEM
|
||||
#define CFG0_PARAM_LEN 8
|
||||
#define CFG1_PARAM_LEN 8
|
||||
#define CFG1_PARAM0_LEN 153
|
||||
#define CFG0_PARAM2_LEN 256
|
||||
#define CFG5_PARAM01_LEN 4
|
||||
#define CFG3_PARAM01_LEN 4
|
||||
|
||||
struct drm_msm_dem_cfg {
|
||||
__u64 flags;
|
||||
__u32 pentile;
|
||||
__u32 cfg0_en;
|
||||
__u32 cfg0_param0_len;
|
||||
__u32 cfg0_param0[CFG0_PARAM_LEN];
|
||||
__u32 cfg0_param1_len;
|
||||
__u32 cfg0_param1[CFG0_PARAM_LEN];
|
||||
__u32 cfg0_param2_len;
|
||||
__u64 cfg0_param2_c0[CFG0_PARAM2_LEN];
|
||||
__u64 cfg0_param2_c1[CFG0_PARAM2_LEN];
|
||||
__u64 cfg0_param2_c2[CFG0_PARAM2_LEN];
|
||||
__u32 cfg0_param3_len;
|
||||
__u32 cfg0_param3_c0[CFG0_PARAM_LEN];
|
||||
__u32 cfg0_param3_c1[CFG0_PARAM_LEN];
|
||||
__u32 cfg0_param3_c2[CFG0_PARAM_LEN];
|
||||
__u32 cfg0_param4_len;
|
||||
__u32 cfg0_param4[CFG0_PARAM_LEN];
|
||||
|
||||
__u32 cfg1_en;
|
||||
__u32 cfg1_high_idx;
|
||||
__u32 cfg1_low_idx;
|
||||
__u32 cfg01_param0_len;
|
||||
__u32 cfg01_param0[CFG1_PARAM_LEN];
|
||||
__u32 cfg1_param0_len;
|
||||
__u32 cfg1_param0_c0[CFG1_PARAM0_LEN];
|
||||
__u32 cfg1_param0_c1[CFG1_PARAM0_LEN];
|
||||
__u32 cfg1_param0_c2[CFG1_PARAM0_LEN];
|
||||
|
||||
__u32 cfg2_en;
|
||||
__u32 cfg3_en;
|
||||
__u32 cfg3_param0_len;
|
||||
__u32 cfg3_param0_a[CFG3_PARAM01_LEN];
|
||||
__u32 cfg3_param0_b[CFG3_PARAM01_LEN];
|
||||
__u32 cfg3_ab_adj;
|
||||
__u32 cfg4_en;
|
||||
__u32 cfg5_en;
|
||||
__u32 cfg5_param0_len;
|
||||
__u32 cfg5_param0[CFG5_PARAM01_LEN];
|
||||
__u32 cfg5_param1_len;
|
||||
__u32 cfg5_param1[CFG5_PARAM01_LEN];
|
||||
|
||||
__u32 c0_depth;
|
||||
__u32 c1_depth;
|
||||
__u32 c2_depth;
|
||||
__u32 src_id;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct drm_msm_ad4_manual_str_cfg - ad4 manual strength config set
|
||||
* by user-space client.
|
||||
* @in_str - strength for inside roi region
|
||||
* @out_str - strength for outside roi region
|
||||
*/
|
||||
#define DRM_MSM_AD4_MANUAL_STRENGTH
|
||||
struct drm_msm_ad4_manual_str_cfg {
|
||||
__u32 in_str;
|
||||
__u32 out_str;
|
||||
};
|
||||
|
||||
#define RC_DATA_SIZE_MAX 2720
|
||||
#define RC_CFG_SIZE_MAX 4
|
||||
|
||||
struct drm_msm_rc_mask_cfg {
|
||||
__u64 flags;
|
||||
__u32 cfg_param_01;
|
||||
__u32 cfg_param_02;
|
||||
__u32 cfg_param_03;
|
||||
__u32 cfg_param_04[RC_CFG_SIZE_MAX];
|
||||
__u32 cfg_param_05[RC_CFG_SIZE_MAX];
|
||||
__u32 cfg_param_06[RC_CFG_SIZE_MAX];
|
||||
__u64 cfg_param_07;
|
||||
__u32 cfg_param_08;
|
||||
__u64 cfg_param_09[RC_DATA_SIZE_MAX];
|
||||
};
|
||||
|
||||
#endif /* _MSM_DRM_PP_H_ */
|
697
techpack/display/include/uapi/display/drm/sde_drm.h
Normal file
697
techpack/display/include/uapi/display/drm/sde_drm.h
Normal file
@ -0,0 +1,697 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
|
||||
/*
|
||||
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _SDE_DRM_H_
|
||||
#define _SDE_DRM_H_
|
||||
|
||||
#include <drm/drm.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Total number of supported color planes */
|
||||
#define SDE_MAX_PLANES 4
|
||||
|
||||
/* Total number of parameterized detail enhancer mapping curves */
|
||||
#define SDE_MAX_DE_CURVES 3
|
||||
|
||||
/* Y/RGB and UV filter configuration */
|
||||
#define FILTER_EDGE_DIRECTED_2D 0x0
|
||||
#define FILTER_CIRCULAR_2D 0x1
|
||||
#define FILTER_SEPARABLE_1D 0x2
|
||||
#define FILTER_BILINEAR 0x3
|
||||
|
||||
/* Alpha filters */
|
||||
#define FILTER_ALPHA_DROP_REPEAT 0x0
|
||||
#define FILTER_ALPHA_BILINEAR 0x1
|
||||
#define FILTER_ALPHA_2D 0x3
|
||||
|
||||
/* Blend filters */
|
||||
#define FILTER_BLEND_CIRCULAR_2D 0x0
|
||||
#define FILTER_BLEND_SEPARABLE_1D 0x1
|
||||
|
||||
/* LUT configuration flags */
|
||||
#define SCALER_LUT_SWAP 0x1
|
||||
#define SCALER_LUT_DIR_WR 0x2
|
||||
#define SCALER_LUT_Y_CIR_WR 0x4
|
||||
#define SCALER_LUT_UV_CIR_WR 0x8
|
||||
#define SCALER_LUT_Y_SEP_WR 0x10
|
||||
#define SCALER_LUT_UV_SEP_WR 0x20
|
||||
|
||||
/**
|
||||
* Blend operations for "blend_op" property
|
||||
*
|
||||
* @SDE_DRM_BLEND_OP_NOT_DEFINED: No blend operation defined for the layer.
|
||||
* @SDE_DRM_BLEND_OP_OPAQUE: Apply a constant blend operation. The layer
|
||||
* would appear opaque in case fg plane alpha
|
||||
* is 0xff.
|
||||
* @SDE_DRM_BLEND_OP_PREMULTIPLIED: Apply source over blend rule. Layer already
|
||||
* has alpha pre-multiplication done. If the fg
|
||||
* plane alpha is less than 0xff, apply
|
||||
* modulation as well. This operation is
|
||||
* intended on layers having alpha channel.
|
||||
* @SDE_DRM_BLEND_OP_COVERAGE: Apply source over blend rule. Layer is not
|
||||
* alpha pre-multiplied. Apply
|
||||
* pre-multiplication. If fg plane alpha is
|
||||
* less than 0xff, apply modulation as well.
|
||||
* @SDE_DRM_BLEND_OP_MAX: Used to track maximum blend operation
|
||||
* possible by mdp.
|
||||
* @SDE_DRM_BLEND_OP_SKIP: Skip staging the layer in the layer mixer.
|
||||
*/
|
||||
#define SDE_DRM_BLEND_OP_NOT_DEFINED 0
|
||||
#define SDE_DRM_BLEND_OP_OPAQUE 1
|
||||
#define SDE_DRM_BLEND_OP_PREMULTIPLIED 2
|
||||
#define SDE_DRM_BLEND_OP_COVERAGE 3
|
||||
#define SDE_DRM_BLEND_OP_MAX 4
|
||||
#define SDE_DRM_BLEND_OP_SKIP 5
|
||||
|
||||
/**
|
||||
* Bit masks for "src_config" property
|
||||
* construct bitmask via (1UL << SDE_DRM_<flag>)
|
||||
*/
|
||||
#define SDE_DRM_DEINTERLACE 0 /* Specifies interlaced input */
|
||||
|
||||
/* DRM bitmasks are restricted to 0..63 */
|
||||
#define SDE_DRM_BITMASK_COUNT 64
|
||||
|
||||
/**
|
||||
* Framebuffer modes for "fb_translation_mode" PLANE and CONNECTOR property
|
||||
*
|
||||
* @SDE_DRM_FB_NON_SEC: IOMMU configuration for this framebuffer mode
|
||||
* is non-secure domain and requires
|
||||
* both stage I and stage II translations when
|
||||
* this buffer is accessed by the display HW.
|
||||
* This is the default mode of all frambuffers.
|
||||
* @SDE_DRM_FB_SEC: IOMMU configuration for this framebuffer mode
|
||||
* is secure domain and requires
|
||||
* both stage I and stage II translations when
|
||||
* this buffer is accessed by the display HW.
|
||||
* @SDE_DRM_FB_NON_SEC_DIR_TRANS: IOMMU configuration for this framebuffer mode
|
||||
* is non-secure domain and requires
|
||||
* only stage II translation when
|
||||
* this buffer is accessed by the display HW.
|
||||
* @SDE_DRM_FB_SEC_DIR_TRANS: IOMMU configuration for this framebuffer mode
|
||||
* is secure domain and requires
|
||||
* only stage II translation when
|
||||
* this buffer is accessed by the display HW.
|
||||
*/
|
||||
|
||||
#define SDE_DRM_FB_NON_SEC 0
|
||||
#define SDE_DRM_FB_SEC 1
|
||||
#define SDE_DRM_FB_NON_SEC_DIR_TRANS 2
|
||||
#define SDE_DRM_FB_SEC_DIR_TRANS 3
|
||||
|
||||
/**
|
||||
* Secure levels for "security_level" CRTC property.
|
||||
* CRTC property which specifies what plane types
|
||||
* can be attached to this CRTC. Plane component
|
||||
* derives the plane type based on the FB_MODE.
|
||||
* @ SDE_DRM_SEC_NON_SEC: Both Secure and non-secure plane types can be
|
||||
* attached to this CRTC. This is the default state of
|
||||
* the CRTC.
|
||||
* @ SDE_DRM_SEC_ONLY: Only secure planes can be added to this CRTC. If a
|
||||
* CRTC is instructed to be in this mode it follows the
|
||||
* platform dependent restrictions.
|
||||
*/
|
||||
#define SDE_DRM_SEC_NON_SEC 0
|
||||
#define SDE_DRM_SEC_ONLY 1
|
||||
|
||||
/**
|
||||
* struct sde_drm_pix_ext_v1 - version 1 of pixel ext structure
|
||||
* @num_ext_pxls_lr: Number of total horizontal pixels
|
||||
* @num_ext_pxls_tb: Number of total vertical lines
|
||||
* @left_ftch: Number of extra pixels to overfetch from left
|
||||
* @right_ftch: Number of extra pixels to overfetch from right
|
||||
* @top_ftch: Number of extra lines to overfetch from top
|
||||
* @btm_ftch: Number of extra lines to overfetch from bottom
|
||||
* @left_rpt: Number of extra pixels to repeat from left
|
||||
* @right_rpt: Number of extra pixels to repeat from right
|
||||
* @top_rpt: Number of extra lines to repeat from top
|
||||
* @btm_rpt: Number of extra lines to repeat from bottom
|
||||
*/
|
||||
struct sde_drm_pix_ext_v1 {
|
||||
/*
|
||||
* Number of pixels ext in left, right, top and bottom direction
|
||||
* for all color components.
|
||||
*/
|
||||
__s32 num_ext_pxls_lr[SDE_MAX_PLANES];
|
||||
__s32 num_ext_pxls_tb[SDE_MAX_PLANES];
|
||||
|
||||
/*
|
||||
* Number of pixels needs to be overfetched in left, right, top
|
||||
* and bottom directions from source image for scaling.
|
||||
*/
|
||||
__s32 left_ftch[SDE_MAX_PLANES];
|
||||
__s32 right_ftch[SDE_MAX_PLANES];
|
||||
__s32 top_ftch[SDE_MAX_PLANES];
|
||||
__s32 btm_ftch[SDE_MAX_PLANES];
|
||||
/*
|
||||
* Number of pixels needs to be repeated in left, right, top and
|
||||
* bottom directions for scaling.
|
||||
*/
|
||||
__s32 left_rpt[SDE_MAX_PLANES];
|
||||
__s32 right_rpt[SDE_MAX_PLANES];
|
||||
__s32 top_rpt[SDE_MAX_PLANES];
|
||||
__s32 btm_rpt[SDE_MAX_PLANES];
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* struct sde_drm_scaler_v1 - version 1 of struct sde_drm_scaler
|
||||
* @lr: Pixel extension settings for left/right
|
||||
* @tb: Pixel extension settings for top/botton
|
||||
* @init_phase_x: Initial scaler phase values for x
|
||||
* @phase_step_x: Phase step values for x
|
||||
* @init_phase_y: Initial scaler phase values for y
|
||||
* @phase_step_y: Phase step values for y
|
||||
* @horz_filter: Horizontal filter array
|
||||
* @vert_filter: Vertical filter array
|
||||
*/
|
||||
struct sde_drm_scaler_v1 {
|
||||
/*
|
||||
* Pix ext settings
|
||||
*/
|
||||
struct sde_drm_pix_ext_v1 pe;
|
||||
/*
|
||||
* Phase settings
|
||||
*/
|
||||
__s32 init_phase_x[SDE_MAX_PLANES];
|
||||
__s32 phase_step_x[SDE_MAX_PLANES];
|
||||
__s32 init_phase_y[SDE_MAX_PLANES];
|
||||
__s32 phase_step_y[SDE_MAX_PLANES];
|
||||
|
||||
/*
|
||||
* Filter type to be used for scaling in horizontal and vertical
|
||||
* directions
|
||||
*/
|
||||
__u32 horz_filter[SDE_MAX_PLANES];
|
||||
__u32 vert_filter[SDE_MAX_PLANES];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct sde_drm_de_v1 - version 1 of detail enhancer structure
|
||||
* @enable: Enables/disables detail enhancer
|
||||
* @sharpen_level1: Sharpening strength for noise
|
||||
* @sharpen_level2: Sharpening strength for context
|
||||
* @clip: Clip coefficient
|
||||
* @limit: Detail enhancer limit factor
|
||||
* @thr_quiet: Quite zone threshold
|
||||
* @thr_dieout: Die-out zone threshold
|
||||
* @thr_low: Linear zone left threshold
|
||||
* @thr_high: Linear zone right threshold
|
||||
* @prec_shift: Detail enhancer precision
|
||||
* @adjust_a: Mapping curves A coefficients
|
||||
* @adjust_b: Mapping curves B coefficients
|
||||
* @adjust_c: Mapping curves C coefficients
|
||||
*/
|
||||
struct sde_drm_de_v1 {
|
||||
__u32 enable;
|
||||
__s16 sharpen_level1;
|
||||
__s16 sharpen_level2;
|
||||
__u16 clip;
|
||||
__u16 limit;
|
||||
__u16 thr_quiet;
|
||||
__u16 thr_dieout;
|
||||
__u16 thr_low;
|
||||
__u16 thr_high;
|
||||
__u16 prec_shift;
|
||||
__s16 adjust_a[SDE_MAX_DE_CURVES];
|
||||
__s16 adjust_b[SDE_MAX_DE_CURVES];
|
||||
__s16 adjust_c[SDE_MAX_DE_CURVES];
|
||||
};
|
||||
|
||||
/*
|
||||
* Scaler configuration flags
|
||||
*/
|
||||
|
||||
/* Disable dynamic expansion */
|
||||
#define SDE_DYN_EXP_DISABLE 0x1
|
||||
|
||||
#define SDE_DRM_QSEED3LITE
|
||||
#define SDE_DRM_QSEED4
|
||||
#define SDE_DRM_INLINE_PREDOWNSCALE
|
||||
|
||||
/**
|
||||
* struct sde_drm_scaler_v2 - version 2 of struct sde_drm_scaler
|
||||
* @enable: Scaler enable
|
||||
* @dir_en: Detail enhancer enable
|
||||
* @pe: Pixel extension settings
|
||||
* @horz_decimate: Horizontal decimation factor
|
||||
* @vert_decimate: Vertical decimation factor
|
||||
* @init_phase_x: Initial scaler phase values for x
|
||||
* @phase_step_x: Phase step values for x
|
||||
* @init_phase_y: Initial scaler phase values for y
|
||||
* @phase_step_y: Phase step values for y
|
||||
* @preload_x: Horizontal preload value
|
||||
* @preload_y: Vertical preload value
|
||||
* @src_width: Source width
|
||||
* @src_height: Source height
|
||||
* @dst_width: Destination width
|
||||
* @dst_height: Destination height
|
||||
* @y_rgb_filter_cfg: Y/RGB plane filter configuration
|
||||
* @uv_filter_cfg: UV plane filter configuration
|
||||
* @alpha_filter_cfg: Alpha filter configuration
|
||||
* @blend_cfg: Selection of blend coefficients
|
||||
* @lut_flag: LUT configuration flags
|
||||
* @dir_lut_idx: 2d 4x4 LUT index
|
||||
* @y_rgb_cir_lut_idx: Y/RGB circular LUT index
|
||||
* @uv_cir_lut_idx: UV circular LUT index
|
||||
* @y_rgb_sep_lut_idx: Y/RGB separable LUT index
|
||||
* @uv_sep_lut_idx: UV separable LUT index
|
||||
* @de: Detail enhancer settings
|
||||
* @dir_weight: Directional Weight
|
||||
* @unsharp_mask_blend: Unsharp Blend Filter Ratio
|
||||
* @de_blend: Ratio of two unsharp mask filters
|
||||
* @flags: Scaler configuration flags
|
||||
* @pre_downscale_x_0 Pre-downscale ratio, x-direction, plane 0(Y/RGB)
|
||||
* @pre_downscale_x_1 Pre-downscale ratio, x-direction, plane 1(UV)
|
||||
* @pre_downscale_y_0 Pre-downscale ratio, y-direction, plane 0(Y/RGB)
|
||||
* @pre_downscale_y_1 Pre-downscale ratio, y-direction, plane 1(UV)
|
||||
*/
|
||||
struct sde_drm_scaler_v2 {
|
||||
/*
|
||||
* General definitions
|
||||
*/
|
||||
__u32 enable;
|
||||
__u32 dir_en;
|
||||
|
||||
/*
|
||||
* Pix ext settings
|
||||
*/
|
||||
struct sde_drm_pix_ext_v1 pe;
|
||||
|
||||
/*
|
||||
* Decimation settings
|
||||
*/
|
||||
__u32 horz_decimate;
|
||||
__u32 vert_decimate;
|
||||
|
||||
/*
|
||||
* Phase settings
|
||||
*/
|
||||
__s32 init_phase_x[SDE_MAX_PLANES];
|
||||
__s32 phase_step_x[SDE_MAX_PLANES];
|
||||
__s32 init_phase_y[SDE_MAX_PLANES];
|
||||
__s32 phase_step_y[SDE_MAX_PLANES];
|
||||
|
||||
__u32 preload_x[SDE_MAX_PLANES];
|
||||
__u32 preload_y[SDE_MAX_PLANES];
|
||||
__u32 src_width[SDE_MAX_PLANES];
|
||||
__u32 src_height[SDE_MAX_PLANES];
|
||||
|
||||
__u32 dst_width;
|
||||
__u32 dst_height;
|
||||
|
||||
__u32 y_rgb_filter_cfg;
|
||||
__u32 uv_filter_cfg;
|
||||
__u32 alpha_filter_cfg;
|
||||
__u32 blend_cfg;
|
||||
|
||||
__u32 lut_flag;
|
||||
__u32 dir_lut_idx;
|
||||
|
||||
/* for Y(RGB) and UV planes*/
|
||||
__u32 y_rgb_cir_lut_idx;
|
||||
__u32 uv_cir_lut_idx;
|
||||
__u32 y_rgb_sep_lut_idx;
|
||||
__u32 uv_sep_lut_idx;
|
||||
|
||||
/*
|
||||
* Detail enhancer settings
|
||||
*/
|
||||
struct sde_drm_de_v1 de;
|
||||
__u32 dir_weight;
|
||||
__u32 unsharp_mask_blend;
|
||||
__u32 de_blend;
|
||||
__u32 flags;
|
||||
|
||||
/*
|
||||
* Inline pre-downscale settings
|
||||
*/
|
||||
__u32 pre_downscale_x_0;
|
||||
__u32 pre_downscale_x_1;
|
||||
__u32 pre_downscale_y_0;
|
||||
__u32 pre_downscale_y_1;
|
||||
};
|
||||
|
||||
/* Number of dest scalers supported */
|
||||
#define SDE_MAX_DS_COUNT 2
|
||||
|
||||
/*
|
||||
* Destination scaler flag config
|
||||
*/
|
||||
#define SDE_DRM_DESTSCALER_ENABLE 0x1
|
||||
#define SDE_DRM_DESTSCALER_SCALE_UPDATE 0x2
|
||||
#define SDE_DRM_DESTSCALER_ENHANCER_UPDATE 0x4
|
||||
#define SDE_DRM_DESTSCALER_PU_ENABLE 0x8
|
||||
|
||||
/**
|
||||
* struct sde_drm_dest_scaler_cfg - destination scaler config structure
|
||||
* @flags: Flag to switch between mode for destination scaler
|
||||
* refer to destination scaler flag config
|
||||
* @index: Destination scaler selection index
|
||||
* @lm_width: Layer mixer width configuration
|
||||
* @lm_height: Layer mixer height configuration
|
||||
* @scaler_cfg: The scaling parameters for all the mode except disable
|
||||
* Userspace pointer to struct sde_drm_scaler_v2
|
||||
*/
|
||||
struct sde_drm_dest_scaler_cfg {
|
||||
__u32 flags;
|
||||
__u32 index;
|
||||
__u32 lm_width;
|
||||
__u32 lm_height;
|
||||
__u64 scaler_cfg;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct sde_drm_dest_scaler_data - destination scaler data struct
|
||||
* @num_dest_scaler: Number of dest scalers to be configured
|
||||
* @ds_cfg: Destination scaler block configuration
|
||||
*/
|
||||
struct sde_drm_dest_scaler_data {
|
||||
__u32 num_dest_scaler;
|
||||
struct sde_drm_dest_scaler_cfg ds_cfg[SDE_MAX_DS_COUNT];
|
||||
};
|
||||
|
||||
/*
|
||||
* Define constants for struct sde_drm_csc
|
||||
*/
|
||||
#define SDE_CSC_MATRIX_COEFF_SIZE 9
|
||||
#define SDE_CSC_CLAMP_SIZE 6
|
||||
#define SDE_CSC_BIAS_SIZE 3
|
||||
|
||||
/**
|
||||
* struct sde_drm_csc_v1 - version 1 of struct sde_drm_csc
|
||||
* @ctm_coeff: Matrix coefficients, in S31.32 format
|
||||
* @pre_bias: Pre-bias array values
|
||||
* @post_bias: Post-bias array values
|
||||
* @pre_clamp: Pre-clamp array values
|
||||
* @post_clamp: Post-clamp array values
|
||||
*/
|
||||
struct sde_drm_csc_v1 {
|
||||
__s64 ctm_coeff[SDE_CSC_MATRIX_COEFF_SIZE];
|
||||
__u32 pre_bias[SDE_CSC_BIAS_SIZE];
|
||||
__u32 post_bias[SDE_CSC_BIAS_SIZE];
|
||||
__u32 pre_clamp[SDE_CSC_CLAMP_SIZE];
|
||||
__u32 post_clamp[SDE_CSC_CLAMP_SIZE];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct sde_drm_color - struct to store the color and alpha values
|
||||
* @color_0: Color 0 value
|
||||
* @color_1: Color 1 value
|
||||
* @color_2: Color 2 value
|
||||
* @color_3: Color 3 value
|
||||
*/
|
||||
struct sde_drm_color {
|
||||
__u32 color_0;
|
||||
__u32 color_1;
|
||||
__u32 color_2;
|
||||
__u32 color_3;
|
||||
};
|
||||
|
||||
/* Total number of supported dim layers */
|
||||
#define SDE_MAX_DIM_LAYERS 7
|
||||
|
||||
/* SDE_DRM_DIM_LAYER_CONFIG_FLAG - flags for Dim Layer */
|
||||
/* Color fill inside of the rect, including border */
|
||||
#define SDE_DRM_DIM_LAYER_INCLUSIVE 0x1
|
||||
/* Color fill outside of the rect, excluding border */
|
||||
#define SDE_DRM_DIM_LAYER_EXCLUSIVE 0x2
|
||||
|
||||
/**
|
||||
* struct sde_drm_dim_layer - dim layer cfg struct
|
||||
* @flags: Refer SDE_DRM_DIM_LAYER_CONFIG_FLAG for possible values
|
||||
* @stage: Blending stage of the dim layer
|
||||
* @color_fill: Color fill for dim layer
|
||||
* @rect: Dim layer coordinates
|
||||
*/
|
||||
struct sde_drm_dim_layer_cfg {
|
||||
__u32 flags;
|
||||
__u32 stage;
|
||||
struct sde_drm_color color_fill;
|
||||
struct drm_clip_rect rect;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct sde_drm_dim_layer_v1 - version 1 of dim layer struct
|
||||
* @num_layers: Numer of Dim Layers
|
||||
* @layer: Dim layer user cfgs ptr for the num_layers
|
||||
*/
|
||||
struct sde_drm_dim_layer_v1 {
|
||||
__u32 num_layers;
|
||||
struct sde_drm_dim_layer_cfg layer_cfg[SDE_MAX_DIM_LAYERS];
|
||||
};
|
||||
|
||||
/* Writeback Config version definition */
|
||||
#define SDE_DRM_WB_CFG 0x1
|
||||
|
||||
/* SDE_DRM_WB_CONFIG_FLAGS - Writeback configuration flags */
|
||||
#define SDE_DRM_WB_CFG_FLAGS_CONNECTED (1<<0)
|
||||
|
||||
/**
|
||||
* struct sde_drm_wb_cfg - Writeback configuration structure
|
||||
* @flags: see DRM_MSM_WB_CONFIG_FLAGS
|
||||
* @connector_id: writeback connector identifier
|
||||
* @count_modes: Count of modes in modes_ptr
|
||||
* @modes: Pointer to struct drm_mode_modeinfo
|
||||
*/
|
||||
struct sde_drm_wb_cfg {
|
||||
__u32 flags;
|
||||
__u32 connector_id;
|
||||
__u32 count_modes;
|
||||
__u64 modes;
|
||||
};
|
||||
|
||||
#define SDE_MAX_ROI_V1 4
|
||||
|
||||
/**
|
||||
* struct sde_drm_roi_v1 - list of regions of interest for a drm object
|
||||
* @num_rects: number of valid rectangles in the roi array
|
||||
* @roi: list of roi rectangles
|
||||
*/
|
||||
struct sde_drm_roi_v1 {
|
||||
__u32 num_rects;
|
||||
struct drm_clip_rect roi[SDE_MAX_ROI_V1];
|
||||
};
|
||||
|
||||
/**
|
||||
* Define extended power modes supported by the SDE connectors.
|
||||
*/
|
||||
#define SDE_MODE_DPMS_ON 0
|
||||
#define SDE_MODE_DPMS_LP1 1
|
||||
#define SDE_MODE_DPMS_LP2 2
|
||||
#define SDE_MODE_DPMS_STANDBY 3
|
||||
#define SDE_MODE_DPMS_SUSPEND 4
|
||||
#define SDE_MODE_DPMS_OFF 5
|
||||
|
||||
/**
|
||||
* sde recovery events for notifying client
|
||||
*/
|
||||
#define SDE_RECOVERY_SUCCESS 0
|
||||
#define SDE_RECOVERY_CAPTURE 1
|
||||
#define SDE_RECOVERY_HARD_RESET 2
|
||||
|
||||
/*
|
||||
* Colorimetry Data Block values
|
||||
* These bit nums are defined as per the CTA spec
|
||||
* and indicate the colorspaces supported by the sink
|
||||
*/
|
||||
#define DRM_EDID_CLRMETRY_xvYCC_601 (1 << 0)
|
||||
#define DRM_EDID_CLRMETRY_xvYCC_709 (1 << 1)
|
||||
#define DRM_EDID_CLRMETRY_sYCC_601 (1 << 2)
|
||||
#define DRM_EDID_CLRMETRY_ADOBE_YCC_601 (1 << 3)
|
||||
#define DRM_EDID_CLRMETRY_ADOBE_RGB (1 << 4)
|
||||
#define DRM_EDID_CLRMETRY_BT2020_CYCC (1 << 5)
|
||||
#define DRM_EDID_CLRMETRY_BT2020_YCC (1 << 6)
|
||||
#define DRM_EDID_CLRMETRY_BT2020_RGB (1 << 7)
|
||||
#define DRM_EDID_CLRMETRY_DCI_P3 (1 << 15)
|
||||
|
||||
/*
|
||||
* HDR Metadata
|
||||
* These are defined as per EDID spec and shall be used by the sink
|
||||
* to set the HDR metadata for playback from userspace.
|
||||
*/
|
||||
|
||||
#define HDR_PRIMARIES_COUNT 3
|
||||
|
||||
/* HDR EOTF */
|
||||
#define HDR_EOTF_SDR_LUM_RANGE 0x0
|
||||
#define HDR_EOTF_HDR_LUM_RANGE 0x1
|
||||
#define HDR_EOTF_SMTPE_ST2084 0x2
|
||||
#define HDR_EOTF_HLG 0x3
|
||||
|
||||
#define DRM_MSM_EXT_HDR_METADATA
|
||||
#define DRM_MSM_EXT_HDR_PLUS_METADATA
|
||||
struct drm_msm_ext_hdr_metadata {
|
||||
__u32 hdr_state; /* HDR state */
|
||||
__u32 eotf; /* electro optical transfer function */
|
||||
__u32 hdr_supported; /* HDR supported */
|
||||
__u32 display_primaries_x[HDR_PRIMARIES_COUNT]; /* Primaries x */
|
||||
__u32 display_primaries_y[HDR_PRIMARIES_COUNT]; /* Primaries y */
|
||||
__u32 white_point_x; /* white_point_x */
|
||||
__u32 white_point_y; /* white_point_y */
|
||||
__u32 max_luminance; /* Max luminance */
|
||||
__u32 min_luminance; /* Min Luminance */
|
||||
__u32 max_content_light_level; /* max content light level */
|
||||
__u32 max_average_light_level; /* max average light level */
|
||||
|
||||
__u64 hdr_plus_payload; /* user pointer to dynamic HDR payload */
|
||||
__u32 hdr_plus_payload_size;/* size of dynamic HDR payload data */
|
||||
};
|
||||
|
||||
/**
|
||||
* HDR sink properties
|
||||
* These are defined as per EDID spec and shall be used by the userspace
|
||||
* to determine the HDR properties to be set to the sink.
|
||||
*/
|
||||
#define DRM_MSM_EXT_HDR_PROPERTIES
|
||||
#define DRM_MSM_EXT_HDR_PLUS_PROPERTIES
|
||||
struct drm_msm_ext_hdr_properties {
|
||||
__u8 hdr_metadata_type_one; /* static metadata type one */
|
||||
__u32 hdr_supported; /* HDR supported */
|
||||
__u32 hdr_eotf; /* electro optical transfer function */
|
||||
__u32 hdr_max_luminance; /* Max luminance */
|
||||
__u32 hdr_avg_luminance; /* Avg luminance */
|
||||
__u32 hdr_min_luminance; /* Min Luminance */
|
||||
|
||||
__u32 hdr_plus_supported; /* HDR10+ supported */
|
||||
};
|
||||
|
||||
/* HDR WRGB x and y index */
|
||||
#define DISPLAY_PRIMARIES_WX 0
|
||||
#define DISPLAY_PRIMARIES_WY 1
|
||||
#define DISPLAY_PRIMARIES_RX 2
|
||||
#define DISPLAY_PRIMARIES_RY 3
|
||||
#define DISPLAY_PRIMARIES_GX 4
|
||||
#define DISPLAY_PRIMARIES_GY 5
|
||||
#define DISPLAY_PRIMARIES_BX 6
|
||||
#define DISPLAY_PRIMARIES_BY 7
|
||||
#define DISPLAY_PRIMARIES_MAX 8
|
||||
|
||||
struct drm_panel_hdr_properties {
|
||||
__u32 hdr_enabled;
|
||||
|
||||
/* WRGB X and y values arrayed in format */
|
||||
/* [WX, WY, RX, RY, GX, GY, BX, BY] */
|
||||
__u32 display_primaries[DISPLAY_PRIMARIES_MAX];
|
||||
|
||||
/* peak brightness supported by panel */
|
||||
__u32 peak_brightness;
|
||||
/* Blackness level supported by panel */
|
||||
__u32 blackness_level;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct drm_msm_event_req - Payload to event enable/disable ioctls.
|
||||
* @object_id: DRM object id. e.g.: for crtc pass crtc id.
|
||||
* @object_type: DRM object type. e.g.: for crtc set it to DRM_MODE_OBJECT_CRTC.
|
||||
* @event: Event for which notification is being enabled/disabled.
|
||||
* e.g.: for Histogram set - DRM_EVENT_HISTOGRAM.
|
||||
* @client_context: Opaque pointer that will be returned during event response
|
||||
* notification.
|
||||
* @index: Object index(e.g.: crtc index), optional for user-space to set.
|
||||
* Driver will override value based on object_id and object_type.
|
||||
*/
|
||||
struct drm_msm_event_req {
|
||||
__u32 object_id;
|
||||
__u32 object_type;
|
||||
__u32 event;
|
||||
__u64 client_context;
|
||||
__u32 index;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct drm_msm_event_resp - payload returned when read is called for
|
||||
* custom notifications.
|
||||
* @base: Event type and length of complete notification payload.
|
||||
* @info: Contains information about DRM that which raised this event.
|
||||
* @data: Custom payload that driver returns for event type.
|
||||
* size of data = base.length - (sizeof(base) + sizeof(info))
|
||||
*/
|
||||
struct drm_msm_event_resp {
|
||||
struct drm_event base;
|
||||
struct drm_msm_event_req info;
|
||||
__u8 data[];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct drm_msm_power_ctrl: Payload to enable/disable the power vote
|
||||
* @enable: enable/disable the power vote
|
||||
* @flags: operation control flags, for future use
|
||||
*/
|
||||
struct drm_msm_power_ctrl {
|
||||
__u32 enable;
|
||||
__u32 flags;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct drm_msm_early_wakeup: Payload to early wake up display
|
||||
* @wakeup_hint: early wakeup hint.
|
||||
* @connector_id: connector id. e.g.: for connector pass connector id.
|
||||
*/
|
||||
struct drm_msm_early_wakeup {
|
||||
__u32 wakeup_hint;
|
||||
__u32 connector_id;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct drm_msm_display_hint: Payload for display hint
|
||||
* @hint_flags: display hint flags.
|
||||
* @data: data struct. e.g.: for display hint parameter.
|
||||
* Userspace pointer to struct base on hint flags.
|
||||
*/
|
||||
struct drm_msm_display_hint {
|
||||
__u64 data;
|
||||
__u32 hint_flags;
|
||||
};
|
||||
|
||||
#define DRM_SDE_WB_CONFIG 0x40
|
||||
#define DRM_MSM_REGISTER_EVENT 0x41
|
||||
#define DRM_MSM_DEREGISTER_EVENT 0x42
|
||||
#define DRM_MSM_RMFB2 0x43
|
||||
#define DRM_MSM_POWER_CTRL 0x44
|
||||
#define DRM_MSM_DISPLAY_HINT 0x45
|
||||
|
||||
/* sde custom events */
|
||||
#define DRM_EVENT_HISTOGRAM 0x80000000
|
||||
#define DRM_EVENT_AD_BACKLIGHT 0x80000001
|
||||
#define DRM_EVENT_CRTC_POWER 0x80000002
|
||||
#define DRM_EVENT_SYS_BACKLIGHT 0x80000003
|
||||
#define DRM_EVENT_SDE_POWER 0x80000004
|
||||
#define DRM_EVENT_IDLE_NOTIFY 0x80000005
|
||||
#define DRM_EVENT_PANEL_DEAD 0x80000006 /* ESD event */
|
||||
#define DRM_EVENT_SDE_HW_RECOVERY 0X80000007
|
||||
#define DRM_EVENT_LTM_HIST 0X80000008
|
||||
#define DRM_EVENT_LTM_WB_PB 0X80000009
|
||||
#define DRM_EVENT_LTM_OFF 0X8000000A
|
||||
|
||||
/* display hint flags*/
|
||||
#define DRM_MSM_DISPLAY_EARLY_WAKEUP_HINT 0x01
|
||||
#define DRM_MSM_DISPLAY_POWER_COLLAPSE_HINT 0x02
|
||||
#define DRM_MSM_DISPLAY_IDLE_TIMEOUT_HINT 0x04
|
||||
#define DRM_MSM_DISPLAY_MODE_CHANGE_HINT 0x08
|
||||
|
||||
#define DRM_MSM_WAKE_UP_ALL_DISPLAYS 0xFFFFFFFF
|
||||
|
||||
#define DRM_IOCTL_SDE_WB_CONFIG \
|
||||
DRM_IOW((DRM_COMMAND_BASE + DRM_SDE_WB_CONFIG), struct sde_drm_wb_cfg)
|
||||
#define DRM_IOCTL_MSM_REGISTER_EVENT DRM_IOW((DRM_COMMAND_BASE + \
|
||||
DRM_MSM_REGISTER_EVENT), struct drm_msm_event_req)
|
||||
#define DRM_IOCTL_MSM_DEREGISTER_EVENT DRM_IOW((DRM_COMMAND_BASE + \
|
||||
DRM_MSM_DEREGISTER_EVENT), struct drm_msm_event_req)
|
||||
#define DRM_IOCTL_MSM_RMFB2 DRM_IOW((DRM_COMMAND_BASE + \
|
||||
DRM_MSM_RMFB2), unsigned int)
|
||||
#define DRM_IOCTL_MSM_POWER_CTRL DRM_IOW((DRM_COMMAND_BASE + \
|
||||
DRM_MSM_POWER_CTRL), struct drm_msm_power_ctrl)
|
||||
#define DRM_IOCTL_MSM_DISPLAY_HINT DRM_IOW((DRM_COMMAND_BASE + \
|
||||
DRM_MSM_DISPLAY_HINT), struct drm_msm_display_hint)
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _SDE_DRM_H_ */
|
3
techpack/display/include/uapi/display/hdcp/Kbuild
Normal file
3
techpack/display/include/uapi/display/hdcp/Kbuild
Normal file
@ -0,0 +1,3 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note
|
||||
|
||||
header-y += msm_hdmi_hdcp_mgr.h
|
@ -0,0 +1,61 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
|
||||
/*
|
||||
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _UAPI__MSM_HDMI_HDCP_MGR_H
|
||||
#define _UAPI__MSM_HDMI_HDCP_MGR_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
enum DS_TYPE { /* type of downstream device */
|
||||
DS_UNKNOWN,
|
||||
DS_RECEIVER,
|
||||
DS_REPEATER,
|
||||
};
|
||||
|
||||
enum {
|
||||
MSG_ID_IDX,
|
||||
RET_CODE_IDX,
|
||||
HEADER_LEN,
|
||||
};
|
||||
|
||||
enum RET_CODE {
|
||||
HDCP_NOT_AUTHED,
|
||||
HDCP_AUTHED,
|
||||
HDCP_DISABLE,
|
||||
};
|
||||
|
||||
enum MSG_ID { /* List of functions expected to be called after it */
|
||||
DOWN_CHECK_TOPOLOGY,
|
||||
UP_REQUEST_TOPOLOGY,
|
||||
UP_SEND_TOPOLOGY,
|
||||
DOWN_REQUEST_TOPOLOGY,
|
||||
MSG_NUM,
|
||||
};
|
||||
|
||||
enum SOURCE_ID {
|
||||
HDCP_V1_TX,
|
||||
HDCP_V1_RX,
|
||||
HDCP_V2_RX,
|
||||
HDCP_V2_TX,
|
||||
SRC_NUM,
|
||||
};
|
||||
|
||||
/*
|
||||
* how to parse sysfs params buffer
|
||||
* from hdcp_tx driver.
|
||||
*/
|
||||
|
||||
struct HDCP_V2V1_MSG_TOPOLOGY {
|
||||
/* indicates downstream's type */
|
||||
__u32 ds_type;
|
||||
__u8 bksv[5];
|
||||
__u8 dev_count;
|
||||
__u8 depth;
|
||||
__u8 ksv_list[5 * 127];
|
||||
__u32 max_cascade_exceeded;
|
||||
__u32 max_dev_exceeded;
|
||||
};
|
||||
|
||||
#endif /* _UAPI__MSM_HDMI_HDCP_MGR_H */
|
4
techpack/display/include/uapi/display/media/Kbuild
Normal file
4
techpack/display/include/uapi/display/media/Kbuild
Normal file
@ -0,0 +1,4 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note
|
||||
|
||||
header-y += msm_sde_rotator.h
|
||||
header-y += mmm_color_fmt.h
|
1368
techpack/display/include/uapi/display/media/mmm_color_fmt.h
Normal file
1368
techpack/display/include/uapi/display/media/mmm_color_fmt.h
Normal file
File diff suppressed because it is too large
Load Diff
180
techpack/display/include/uapi/display/media/msm_sde_rotator.h
Normal file
180
techpack/display/include/uapi/display/media/msm_sde_rotator.h
Normal file
@ -0,0 +1,180 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
|
||||
/*
|
||||
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef __UAPI_MSM_SDE_ROTATOR_H__
|
||||
#define __UAPI_MSM_SDE_ROTATOR_H__
|
||||
|
||||
#include <linux/videodev2.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/ioctl.h>
|
||||
|
||||
/* SDE Rotator pixel format definitions */
|
||||
#define SDE_PIX_FMT_XRGB_8888 \
|
||||
v4l2_fourcc('X', 'R', '2', '4') /* 32 BGRX-8-8-8-8 */
|
||||
#define SDE_PIX_FMT_ARGB_8888 \
|
||||
v4l2_fourcc('A', 'R', '2', '4') /* 32 BGRA-8-8-8-8 */
|
||||
#define SDE_PIX_FMT_ABGR_8888 \
|
||||
v4l2_fourcc('R', 'A', '2', '4') /* 32-bit ABGR 8:8:8:8 */
|
||||
#define SDE_PIX_FMT_RGBA_8888 \
|
||||
v4l2_fourcc('A', 'B', '2', '4') /* 32-bit RGBA 8:8:8:8 */
|
||||
#define SDE_PIX_FMT_BGRA_8888 \
|
||||
v4l2_fourcc('B', 'A', '2', '4') /* 32 ARGB-8-8-8-8 */
|
||||
#define SDE_PIX_FMT_RGBX_8888 \
|
||||
v4l2_fourcc('X', 'B', '2', '4') /* 32-bit RGBX 8:8:8:8 */
|
||||
#define SDE_PIX_FMT_BGRX_8888 \
|
||||
v4l2_fourcc('B', 'X', '2', '4') /* 32 XRGB-8-8-8-8 */
|
||||
#define SDE_PIX_FMT_XBGR_8888 \
|
||||
v4l2_fourcc('R', 'X', '2', '4') /* 32-bit XBGR 8:8:8:8 */
|
||||
#define SDE_PIX_FMT_RGBA_5551 \
|
||||
v4l2_fourcc('R', 'A', '1', '5') /* 16-bit RGBA 5:5:5:1 */
|
||||
#define SDE_PIX_FMT_ARGB_1555 \
|
||||
v4l2_fourcc('A', 'R', '1', '5') /* 16 ARGB-1-5-5-5 */
|
||||
#define SDE_PIX_FMT_ABGR_1555 \
|
||||
v4l2_fourcc('A', 'B', '1', '5') /* 16-bit ABGR 1:5:5:5 */
|
||||
#define SDE_PIX_FMT_BGRA_5551 \
|
||||
v4l2_fourcc('B', 'A', '1', '5') /* 16-bit BGRA 5:5:5:1 */
|
||||
#define SDE_PIX_FMT_BGRX_5551 \
|
||||
v4l2_fourcc('B', 'X', '1', '5') /* 16-bit BGRX 5:5:5:1 */
|
||||
#define SDE_PIX_FMT_RGBX_5551 \
|
||||
v4l2_fourcc('R', 'X', '1', '5') /* 16-bit RGBX 5:5:5:1 */
|
||||
#define SDE_PIX_FMT_XBGR_1555 \
|
||||
v4l2_fourcc('X', 'B', '1', '5') /* 16-bit XBGR 1:5:5:5 */
|
||||
#define SDE_PIX_FMT_XRGB_1555 \
|
||||
v4l2_fourcc('X', 'R', '1', '5') /* 16 XRGB-1-5-5-5 */
|
||||
#define SDE_PIX_FMT_ARGB_4444 \
|
||||
v4l2_fourcc('A', 'R', '1', '2') /* 16 aaaarrrr ggggbbbb */
|
||||
#define SDE_PIX_FMT_RGBA_4444 \
|
||||
v4l2_fourcc('R', 'A', '1', '2') /* 16-bit RGBA 4:4:4:4 */
|
||||
#define SDE_PIX_FMT_BGRA_4444 \
|
||||
v4l2_fourcc('b', 'A', '1', '2') /* 16-bit BGRA 4:4:4:4 */
|
||||
#define SDE_PIX_FMT_ABGR_4444 \
|
||||
v4l2_fourcc('A', 'B', '1', '2') /* 16-bit ABGR 4:4:4:4 */
|
||||
#define SDE_PIX_FMT_RGBX_4444 \
|
||||
v4l2_fourcc('R', 'X', '1', '2') /* 16-bit RGBX 4:4:4:4 */
|
||||
#define SDE_PIX_FMT_XRGB_4444 \
|
||||
v4l2_fourcc('X', 'R', '1', '2') /* 16 xxxxrrrr ggggbbbb */
|
||||
#define SDE_PIX_FMT_BGRX_4444 \
|
||||
v4l2_fourcc('B', 'X', '1', '2') /* 16-bit BGRX 4:4:4:4 */
|
||||
#define SDE_PIX_FMT_XBGR_4444 \
|
||||
v4l2_fourcc('X', 'B', '1', '2') /* 16-bit XBGR 4:4:4:4 */
|
||||
#define SDE_PIX_FMT_RGB_888 \
|
||||
v4l2_fourcc('R', 'G', 'B', '3') /* 24 RGB-8-8-8 */
|
||||
#define SDE_PIX_FMT_BGR_888 \
|
||||
v4l2_fourcc('B', 'G', 'R', '3') /* 24 BGR-8-8-8 */
|
||||
#define SDE_PIX_FMT_RGB_565 \
|
||||
v4l2_fourcc('R', 'G', 'B', 'P') /* 16 RGB-5-6-5 */
|
||||
#define SDE_PIX_FMT_BGR_565 \
|
||||
v4l2_fourcc('B', 'G', '1', '6') /* 16-bit BGR 5:6:5 */
|
||||
#define SDE_PIX_FMT_Y_CB_CR_H2V2 \
|
||||
v4l2_fourcc('Y', 'U', '1', '2') /* 12 YUV 4:2:0 */
|
||||
#define SDE_PIX_FMT_Y_CR_CB_H2V2 \
|
||||
v4l2_fourcc('Y', 'V', '1', '2') /* 12 YVU 4:2:0 */
|
||||
#define SDE_PIX_FMT_Y_CR_CB_GH2V2 \
|
||||
v4l2_fourcc('Y', 'U', '4', '2') /* Planar YVU 4:2:0 A16 */
|
||||
#define SDE_PIX_FMT_Y_CBCR_H2V2 \
|
||||
v4l2_fourcc('N', 'V', '1', '2') /* 12 Y/CbCr 4:2:0 */
|
||||
#define SDE_PIX_FMT_Y_CRCB_H2V2 \
|
||||
v4l2_fourcc('N', 'V', '2', '1') /* 12 Y/CrCb 4:2:0 */
|
||||
#define SDE_PIX_FMT_Y_CBCR_H1V2 \
|
||||
v4l2_fourcc('N', 'H', '1', '6') /* Y/CbCr 4:2:2 */
|
||||
#define SDE_PIX_FMT_Y_CRCB_H1V2 \
|
||||
v4l2_fourcc('N', 'H', '6', '1') /* Y/CrCb 4:2:2 */
|
||||
#define SDE_PIX_FMT_Y_CBCR_H2V1 \
|
||||
v4l2_fourcc('N', 'V', '1', '6') /* 16 Y/CbCr 4:2:2 */
|
||||
#define SDE_PIX_FMT_Y_CRCB_H2V1 \
|
||||
v4l2_fourcc('N', 'V', '6', '1') /* 16 Y/CrCb 4:2:2 */
|
||||
#define SDE_PIX_FMT_YCBYCR_H2V1 \
|
||||
v4l2_fourcc('Y', 'U', 'Y', 'V') /* 16 YUV 4:2:2 */
|
||||
#define SDE_PIX_FMT_Y_CBCR_H2V2_VENUS \
|
||||
v4l2_fourcc('Q', 'N', 'V', '2') /* Y/CbCr 4:2:0 Venus */
|
||||
#define SDE_PIX_FMT_Y_CRCB_H2V2_VENUS \
|
||||
v4l2_fourcc('Q', 'N', 'V', '1') /* Y/CrCb 4:2:0 Venus */
|
||||
#define SDE_PIX_FMT_RGBA_8888_UBWC \
|
||||
v4l2_fourcc('Q', 'R', 'G', 'B') /* RGBA 8:8:8:8 UBWC */
|
||||
#define SDE_PIX_FMT_RGBX_8888_UBWC \
|
||||
v4l2_fourcc('Q', 'X', 'B', '4') /* RGBX 8:8:8:8 UBWC */
|
||||
#define SDE_PIX_FMT_RGB_565_UBWC \
|
||||
v4l2_fourcc('Q', 'R', 'G', '6') /* RGB 5:6:5 UBWC */
|
||||
#define SDE_PIX_FMT_Y_CBCR_H2V2_UBWC \
|
||||
v4l2_fourcc('Q', '1', '2', '8') /* UBWC 8-bit Y/CbCr 4:2:0 */
|
||||
#define SDE_PIX_FMT_RGBA_1010102 \
|
||||
v4l2_fourcc('A', 'B', '3', '0') /* RGBA 10:10:10:2 */
|
||||
#define SDE_PIX_FMT_RGBX_1010102 \
|
||||
v4l2_fourcc('X', 'B', '3', '0') /* RGBX 10:10:10:2 */
|
||||
#define SDE_PIX_FMT_ARGB_2101010 \
|
||||
v4l2_fourcc('A', 'R', '3', '0') /* ARGB 2:10:10:10 */
|
||||
#define SDE_PIX_FMT_XRGB_2101010 \
|
||||
v4l2_fourcc('X', 'R', '3', '0') /* XRGB 2:10:10:10 */
|
||||
#define SDE_PIX_FMT_BGRA_1010102 \
|
||||
v4l2_fourcc('B', 'A', '3', '0') /* BGRA 10:10:10:2 */
|
||||
#define SDE_PIX_FMT_BGRX_1010102 \
|
||||
v4l2_fourcc('B', 'X', '3', '0') /* BGRX 10:10:10:2 */
|
||||
#define SDE_PIX_FMT_ABGR_2101010 \
|
||||
v4l2_fourcc('R', 'A', '3', '0') /* ABGR 2:10:10:10 */
|
||||
#define SDE_PIX_FMT_XBGR_2101010 \
|
||||
v4l2_fourcc('R', 'X', '3', '0') /* XBGR 2:10:10:10 */
|
||||
#define SDE_PIX_FMT_RGBA_1010102_UBWC \
|
||||
v4l2_fourcc('Q', 'R', 'B', 'A') /* RGBA 10:10:10:2 UBWC */
|
||||
#define SDE_PIX_FMT_RGBX_1010102_UBWC \
|
||||
v4l2_fourcc('Q', 'X', 'B', 'A') /* RGBX 10:10:10:2 UBWC */
|
||||
#define SDE_PIX_FMT_Y_CBCR_H2V2_P010 \
|
||||
v4l2_fourcc('P', '0', '1', '0') /* Y/CbCr 4:2:0 P10 */
|
||||
#define SDE_PIX_FMT_Y_CBCR_H2V2_P010_VENUS \
|
||||
v4l2_fourcc('Q', 'P', '1', '0') /* Y/CbCr 4:2:0 P10 Venus*/
|
||||
#define SDE_PIX_FMT_Y_CBCR_H2V2_TP10 \
|
||||
v4l2_fourcc('T', 'P', '1', '0') /* Y/CbCr 4:2:0 TP10 */
|
||||
#define SDE_PIX_FMT_Y_CBCR_H2V2_TP10_UBWC \
|
||||
v4l2_fourcc('Q', '1', '2', 'A') /* UBWC Y/CbCr 4:2:0 TP10 */
|
||||
#define SDE_PIX_FMT_Y_CBCR_H2V2_P010_UBWC \
|
||||
v4l2_fourcc('Q', '1', '2', 'B') /* UBWC Y/CbCr 4:2:0 P10 */
|
||||
|
||||
/*
|
||||
* struct msm_sde_rotator_fence - v4l2 buffer fence info
|
||||
* @index: id number of the buffer
|
||||
* @type: enum v4l2_buf_type; buffer type
|
||||
* @fd: file descriptor of the fence associated with this buffer
|
||||
*/
|
||||
struct msm_sde_rotator_fence {
|
||||
__u32 index;
|
||||
__u32 type;
|
||||
__s32 fd;
|
||||
__u32 reserved[5];
|
||||
};
|
||||
|
||||
/*
|
||||
* struct msm_sde_rotator_comp_ratio - v4l2 buffer compression ratio
|
||||
* @index: id number of the buffer
|
||||
* @type: enum v4l2_buf_type; buffer type
|
||||
* @numer: numerator of the ratio
|
||||
* @denom: denominator of the ratio
|
||||
*/
|
||||
struct msm_sde_rotator_comp_ratio {
|
||||
__u32 index;
|
||||
__u32 type;
|
||||
__u32 numer;
|
||||
__u32 denom;
|
||||
__u32 reserved[4];
|
||||
};
|
||||
|
||||
/* SDE Rotator private ioctl ID */
|
||||
#define VIDIOC_G_SDE_ROTATOR_FENCE \
|
||||
_IOWR('V', BASE_VIDIOC_PRIVATE + 10, struct msm_sde_rotator_fence)
|
||||
#define VIDIOC_S_SDE_ROTATOR_FENCE \
|
||||
_IOWR('V', BASE_VIDIOC_PRIVATE + 11, struct msm_sde_rotator_fence)
|
||||
#define VIDIOC_G_SDE_ROTATOR_COMP_RATIO \
|
||||
_IOWR('V', BASE_VIDIOC_PRIVATE + 12, struct msm_sde_rotator_comp_ratio)
|
||||
#define VIDIOC_S_SDE_ROTATOR_COMP_RATIO \
|
||||
_IOWR('V', BASE_VIDIOC_PRIVATE + 13, struct msm_sde_rotator_comp_ratio)
|
||||
|
||||
/* SDE Rotator private control ID's */
|
||||
#define V4L2_CID_SDE_ROTATOR_SECURE (V4L2_CID_USER_BASE + 0x1000)
|
||||
|
||||
/*
|
||||
* This control Id indicates this context is associated with the
|
||||
* secure camera.
|
||||
*/
|
||||
#define V4L2_CID_SDE_ROTATOR_SECURE_CAMERA (V4L2_CID_USER_BASE + 0x2000)
|
||||
|
||||
#endif /* __UAPI_MSM_SDE_ROTATOR_H__ */
|
160
techpack/display/msm/Makefile
Normal file
160
techpack/display/msm/Makefile
Normal file
@ -0,0 +1,160 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
ccflags-y := -I$(srctree)/include/drm -I$(srctree)/techpack/display/msm -I$(srctree)/techpack/display/msm/dsi -I$(srctree)/techpack/display/msm/dp
|
||||
ccflags-y += -I$(srctree)/techpack/display/msm/sde
|
||||
ccflags-y += -I$(srctree)/techpack/display/rotator
|
||||
ccflags-y += -I$(srctree)/techpack/display/hdcp
|
||||
ccflags-y += -I$(srctree)/drivers/clk/qcom/
|
||||
|
||||
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_gpio_hpd.o \
|
||||
dp/dp_lphw_hpd.o \
|
||||
dp/dp_display.o \
|
||||
dp/dp_drm.o \
|
||||
dp/dp_hdcp2p2.o \
|
||||
sde_hdcp_1x.o \
|
||||
sde_hdcp_2x.o \
|
||||
dp/dp_pll.o \
|
||||
dp/dp_pll_5nm.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
|
||||
|
||||
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_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_hw_blk.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_rc.o \
|
||||
sde_dbg.o \
|
||||
sde_dbg_evtlog.o \
|
||||
|
||||
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_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_v2_0.o \
|
||||
dsi/dsi_phy_hw_v3_0.o \
|
||||
dsi/dsi_phy_hw_v4_0.o \
|
||||
dsi/dsi_phy_timing_calc.o \
|
||||
dsi/dsi_phy_timing_v2_0.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_10nm.o \
|
||||
dsi/dsi_ctrl_hw_cmn.o \
|
||||
dsi/dsi_ctrl_hw_1_4.o \
|
||||
dsi/dsi_ctrl_hw_2_0.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_DRM_MSM) += \
|
||||
msm_atomic.o \
|
||||
msm_fb.o \
|
||||
msm_iommu.o \
|
||||
msm_drv.o \
|
||||
msm_gem.o \
|
||||
msm_gem_prime.o \
|
||||
msm_gem_vma.o \
|
||||
msm_smmu.o \
|
||||
msm_cooling_device.o \
|
||||
msm_prop.o
|
||||
|
||||
msm_drm-$(CONFIG_HDCP_QSEECOM) += ../hdcp/msm_hdcp.o \
|
||||
|
||||
msm_drm-$(CONFIG_MSM_SDE_ROTATOR) += ../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 \
|
||||
../rotator/sde_rotator_sync.o \
|
||||
../rotator/sde_rotator_debug.o \
|
||||
../rotator/sde_rotator_r1_debug.o \
|
||||
../rotator/sde_rotator_r3_debug.o
|
||||
|
||||
obj-$(CONFIG_DISPLAY_BUILD) += msm_drm.o
|
||||
|
||||
obj-$(CONFIG_DRM_FBDEV_EMULATION) += msm_fbdev.o
|
317
techpack/display/msm/dp/dp_altmode.c
Normal file
317
techpack/display/msm/dp/dp_altmode.c
Normal file
@ -0,0 +1,317 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2012-2021, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/soc/qcom/altmode-glink.h>
|
||||
#include <linux/usb/dwc3-msm.h>
|
||||
#include <linux/usb/pd_vdo.h>
|
||||
|
||||
#include "dp_altmode.h"
|
||||
#include "dp_debug.h"
|
||||
#include "sde_dbg.h"
|
||||
|
||||
|
||||
#define ALTMODE_CONFIGURE_MASK (0x3f)
|
||||
#define ALTMODE_HPD_STATE_MASK (0x40)
|
||||
#define ALTMODE_HPD_IRQ_MASK (0x80)
|
||||
|
||||
struct dp_altmode_private {
|
||||
bool forced_disconnect;
|
||||
struct device *dev;
|
||||
struct dp_hpd_cb *dp_cb;
|
||||
struct dp_altmode dp_altmode;
|
||||
struct altmode_client *amclient;
|
||||
bool connected;
|
||||
};
|
||||
|
||||
enum dp_altmode_pin_assignment {
|
||||
DPAM_HPD_OUT,
|
||||
DPAM_HPD_A,
|
||||
DPAM_HPD_B,
|
||||
DPAM_HPD_C,
|
||||
DPAM_HPD_D,
|
||||
DPAM_HPD_E,
|
||||
DPAM_HPD_F,
|
||||
};
|
||||
|
||||
static int dp_altmode_release_ss_lanes(struct dp_altmode_private *altmode,
|
||||
bool multi_func)
|
||||
{
|
||||
int rc;
|
||||
struct device_node *np;
|
||||
struct device_node *usb_node;
|
||||
struct platform_device *usb_pdev;
|
||||
int timeout = 250;
|
||||
|
||||
if (!altmode || !altmode->dev) {
|
||||
DP_ERR("invalid args\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
np = altmode->dev->of_node;
|
||||
|
||||
usb_node = of_parse_phandle(np, "usb-controller", 0);
|
||||
if (!usb_node) {
|
||||
DP_ERR("unable to get usb node\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
usb_pdev = of_find_device_by_node(usb_node);
|
||||
if (!usb_pdev) {
|
||||
of_node_put(usb_node);
|
||||
DP_ERR("unable to get usb pdev\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
while (timeout) {
|
||||
rc = dwc3_msm_release_ss_lane(&usb_pdev->dev, multi_func);
|
||||
if (rc != -EBUSY)
|
||||
break;
|
||||
|
||||
DP_WARN("USB busy, retry\n");
|
||||
|
||||
/* wait for hw recommended delay for usb */
|
||||
msleep(20);
|
||||
timeout--;
|
||||
}
|
||||
of_node_put(usb_node);
|
||||
platform_device_put(usb_pdev);
|
||||
|
||||
if (rc)
|
||||
DP_ERR("Error releasing SS lanes: %d\n", rc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void dp_altmode_send_pan_ack(struct altmode_client *amclient,
|
||||
u8 port_index)
|
||||
{
|
||||
int rc;
|
||||
struct altmode_pan_ack_msg ack;
|
||||
|
||||
ack.cmd_type = ALTMODE_PAN_ACK;
|
||||
ack.port_index = port_index;
|
||||
|
||||
rc = altmode_send_data(amclient, &ack, sizeof(ack));
|
||||
if (rc < 0) {
|
||||
DP_ERR("failed: %d\n", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
DP_DEBUG("port=%d\n", port_index);
|
||||
}
|
||||
|
||||
static int dp_altmode_notify(void *priv, void *data, size_t len)
|
||||
{
|
||||
int rc = 0;
|
||||
struct dp_altmode_private *altmode =
|
||||
(struct dp_altmode_private *) priv;
|
||||
u8 port_index, dp_data, orientation;
|
||||
u8 *payload = (u8 *) data;
|
||||
u8 pin, hpd_state, hpd_irq;
|
||||
bool force_multi_func = altmode->dp_altmode.base.force_multi_func;
|
||||
|
||||
port_index = payload[0];
|
||||
orientation = payload[1];
|
||||
dp_data = payload[8];
|
||||
|
||||
pin = dp_data & ALTMODE_CONFIGURE_MASK;
|
||||
hpd_state = (dp_data & ALTMODE_HPD_STATE_MASK) >> 6;
|
||||
hpd_irq = (dp_data & ALTMODE_HPD_IRQ_MASK) >> 7;
|
||||
|
||||
altmode->dp_altmode.base.hpd_high = !!hpd_state;
|
||||
altmode->dp_altmode.base.hpd_irq = !!hpd_irq;
|
||||
altmode->dp_altmode.base.multi_func = force_multi_func ? true :
|
||||
!(pin == DPAM_HPD_C || pin == DPAM_HPD_E ||
|
||||
pin == DPAM_HPD_OUT);
|
||||
|
||||
DP_DEBUG("payload=0x%x\n", dp_data);
|
||||
DP_DEBUG("port_index=%d, orientation=%d, pin=%d, hpd_state=%d\n",
|
||||
port_index, orientation, pin, hpd_state);
|
||||
DP_DEBUG("multi_func=%d, hpd_high=%d, hpd_irq=%d\n",
|
||||
altmode->dp_altmode.base.multi_func,
|
||||
altmode->dp_altmode.base.hpd_high,
|
||||
altmode->dp_altmode.base.hpd_irq);
|
||||
DP_DEBUG("connected=%d\n", altmode->connected);
|
||||
SDE_EVT32_EXTERNAL(dp_data, port_index, orientation, pin, hpd_state,
|
||||
altmode->dp_altmode.base.multi_func,
|
||||
altmode->dp_altmode.base.hpd_high,
|
||||
altmode->dp_altmode.base.hpd_irq, altmode->connected);
|
||||
|
||||
if (!pin) {
|
||||
/* Cable detach */
|
||||
if (altmode->connected) {
|
||||
altmode->connected = false;
|
||||
altmode->dp_altmode.base.alt_mode_cfg_done = false;
|
||||
altmode->dp_altmode.base.orientation = ORIENTATION_NONE;
|
||||
if (altmode->dp_cb && altmode->dp_cb->disconnect)
|
||||
altmode->dp_cb->disconnect(altmode->dev);
|
||||
}
|
||||
goto ack;
|
||||
}
|
||||
|
||||
/* Configure */
|
||||
if (!altmode->connected) {
|
||||
altmode->connected = true;
|
||||
altmode->dp_altmode.base.alt_mode_cfg_done = true;
|
||||
altmode->forced_disconnect = false;
|
||||
|
||||
switch (orientation) {
|
||||
case 0:
|
||||
orientation = ORIENTATION_CC1;
|
||||
break;
|
||||
case 1:
|
||||
orientation = ORIENTATION_CC2;
|
||||
break;
|
||||
case 2:
|
||||
orientation = ORIENTATION_NONE;
|
||||
break;
|
||||
default:
|
||||
orientation = ORIENTATION_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
altmode->dp_altmode.base.orientation = orientation;
|
||||
|
||||
rc = dp_altmode_release_ss_lanes(altmode,
|
||||
altmode->dp_altmode.base.multi_func);
|
||||
if (rc)
|
||||
goto ack;
|
||||
|
||||
if (altmode->dp_cb && altmode->dp_cb->configure)
|
||||
altmode->dp_cb->configure(altmode->dev);
|
||||
goto ack;
|
||||
}
|
||||
|
||||
/* Attention */
|
||||
if (altmode->forced_disconnect)
|
||||
goto ack;
|
||||
|
||||
if (altmode->dp_cb && altmode->dp_cb->attention)
|
||||
altmode->dp_cb->attention(altmode->dev);
|
||||
ack:
|
||||
dp_altmode_send_pan_ack(altmode->amclient, port_index);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void dp_altmode_register(void *priv)
|
||||
{
|
||||
struct dp_altmode_private *altmode = priv;
|
||||
struct altmode_client_data cd = {
|
||||
.callback = &dp_altmode_notify,
|
||||
};
|
||||
|
||||
cd.name = "displayport";
|
||||
cd.svid = USB_SID_DISPLAYPORT;
|
||||
cd.priv = altmode;
|
||||
|
||||
altmode->amclient = altmode_register_client(altmode->dev, &cd);
|
||||
if (IS_ERR_OR_NULL(altmode->amclient))
|
||||
DP_ERR("failed to register as client: %d\n",
|
||||
PTR_ERR(altmode->amclient));
|
||||
else
|
||||
DP_DEBUG("success\n");
|
||||
}
|
||||
|
||||
static int dp_altmode_simulate_connect(struct dp_hpd *dp_hpd, bool hpd)
|
||||
{
|
||||
struct dp_altmode *dp_altmode;
|
||||
struct dp_altmode_private *altmode;
|
||||
|
||||
dp_altmode = container_of(dp_hpd, struct dp_altmode, base);
|
||||
altmode = container_of(dp_altmode, struct dp_altmode_private,
|
||||
dp_altmode);
|
||||
|
||||
dp_altmode->base.hpd_high = hpd;
|
||||
altmode->forced_disconnect = !hpd;
|
||||
altmode->dp_altmode.base.alt_mode_cfg_done = hpd;
|
||||
|
||||
if (hpd)
|
||||
altmode->dp_cb->configure(altmode->dev);
|
||||
else
|
||||
altmode->dp_cb->disconnect(altmode->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dp_altmode_simulate_attention(struct dp_hpd *dp_hpd, int vdo)
|
||||
{
|
||||
struct dp_altmode *dp_altmode;
|
||||
struct dp_altmode_private *altmode;
|
||||
struct dp_altmode *status;
|
||||
|
||||
dp_altmode = container_of(dp_hpd, struct dp_altmode, base);
|
||||
altmode = container_of(dp_altmode, struct dp_altmode_private,
|
||||
dp_altmode);
|
||||
|
||||
status = &altmode->dp_altmode;
|
||||
|
||||
status->base.hpd_high = (vdo & BIT(7)) ? true : false;
|
||||
status->base.hpd_irq = (vdo & BIT(8)) ? true : false;
|
||||
|
||||
if (altmode->dp_cb && altmode->dp_cb->attention)
|
||||
altmode->dp_cb->attention(altmode->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dp_hpd *dp_altmode_get(struct device *dev, struct dp_hpd_cb *cb)
|
||||
{
|
||||
int rc = 0;
|
||||
struct dp_altmode_private *altmode;
|
||||
struct dp_altmode *dp_altmode;
|
||||
|
||||
if (!cb) {
|
||||
DP_ERR("invalid cb data\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
altmode = kzalloc(sizeof(*altmode), GFP_KERNEL);
|
||||
if (!altmode)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
altmode->dev = dev;
|
||||
altmode->dp_cb = cb;
|
||||
|
||||
dp_altmode = &altmode->dp_altmode;
|
||||
dp_altmode->base.register_hpd = NULL;
|
||||
dp_altmode->base.simulate_connect = dp_altmode_simulate_connect;
|
||||
dp_altmode->base.simulate_attention = dp_altmode_simulate_attention;
|
||||
|
||||
rc = altmode_register_notifier(dev, dp_altmode_register, altmode);
|
||||
if (rc < 0) {
|
||||
DP_ERR("altmode probe notifier registration failed: %d\n", rc);
|
||||
goto error;
|
||||
}
|
||||
|
||||
DP_DEBUG("success\n");
|
||||
|
||||
return &dp_altmode->base;
|
||||
error:
|
||||
kfree(altmode);
|
||||
return ERR_PTR(rc);
|
||||
}
|
||||
|
||||
void dp_altmode_put(struct dp_hpd *dp_hpd)
|
||||
{
|
||||
struct dp_altmode *dp_altmode;
|
||||
struct dp_altmode_private *altmode;
|
||||
|
||||
dp_altmode = container_of(dp_hpd, struct dp_altmode, base);
|
||||
if (!dp_altmode)
|
||||
return;
|
||||
|
||||
altmode = container_of(dp_altmode, struct dp_altmode_private,
|
||||
dp_altmode);
|
||||
|
||||
altmode_deregister_client(altmode->amclient);
|
||||
altmode_deregister_notifier(altmode->dev, altmode);
|
||||
|
||||
kfree(altmode);
|
||||
}
|
22
techpack/display/msm/dp/dp_altmode.h
Normal file
22
techpack/display/msm/dp/dp_altmode.h
Normal file
@ -0,0 +1,22 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _DP_ALTMODE_H_
|
||||
#define _DP_ALTMODE_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
#include "dp_hpd.h"
|
||||
|
||||
struct device;
|
||||
|
||||
struct dp_altmode {
|
||||
struct dp_hpd base;
|
||||
};
|
||||
|
||||
struct dp_hpd *dp_altmode_get(struct device *dev, struct dp_hpd_cb *cb);
|
||||
|
||||
void dp_altmode_put(struct dp_hpd *pd);
|
||||
#endif /* _DP_ALTMODE_H_ */
|
||||
|
899
techpack/display/msm/dp/dp_audio.c
Normal file
899
techpack/display/msm/dp/dp_audio.c
Normal file
@ -0,0 +1,899 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/msm_ext_display.h>
|
||||
|
||||
#include <drm/drm_dp_helper.h>
|
||||
|
||||
#include "dp_catalog.h"
|
||||
#include "dp_audio.h"
|
||||
#include "dp_panel.h"
|
||||
#include "dp_debug.h"
|
||||
|
||||
struct dp_audio_private {
|
||||
struct platform_device *ext_pdev;
|
||||
struct platform_device *pdev;
|
||||
struct dp_catalog_audio *catalog;
|
||||
struct msm_ext_disp_init_data ext_audio_data;
|
||||
struct dp_panel *panel;
|
||||
|
||||
bool ack_enabled;
|
||||
atomic_t session_on;
|
||||
bool engine_on;
|
||||
|
||||
u32 channels;
|
||||
|
||||
struct completion hpd_comp;
|
||||
struct workqueue_struct *notify_workqueue;
|
||||
struct delayed_work notify_delayed_work;
|
||||
struct mutex ops_lock;
|
||||
|
||||
struct dp_audio dp_audio;
|
||||
|
||||
atomic_t acked;
|
||||
};
|
||||
|
||||
static u32 dp_audio_get_header(struct dp_catalog_audio *catalog,
|
||||
enum dp_catalog_audio_sdp_type sdp,
|
||||
enum dp_catalog_audio_header_type header)
|
||||
{
|
||||
catalog->sdp_type = sdp;
|
||||
catalog->sdp_header = header;
|
||||
catalog->get_header(catalog);
|
||||
|
||||
return catalog->data;
|
||||
}
|
||||
|
||||
static void dp_audio_set_header(struct dp_catalog_audio *catalog,
|
||||
u32 data,
|
||||
enum dp_catalog_audio_sdp_type sdp,
|
||||
enum dp_catalog_audio_header_type header)
|
||||
{
|
||||
catalog->sdp_type = sdp;
|
||||
catalog->sdp_header = header;
|
||||
catalog->data = data;
|
||||
catalog->set_header(catalog);
|
||||
}
|
||||
|
||||
static void dp_audio_stream_sdp(struct dp_audio_private *audio)
|
||||
{
|
||||
struct dp_catalog_audio *catalog = audio->catalog;
|
||||
u32 value, new_value;
|
||||
u8 parity_byte;
|
||||
|
||||
/* Config header and parity byte 1 */
|
||||
value = dp_audio_get_header(catalog,
|
||||
DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_1);
|
||||
value &= 0x0000ffff;
|
||||
|
||||
new_value = 0x02;
|
||||
parity_byte = dp_header_get_parity(new_value);
|
||||
value |= ((new_value << HEADER_BYTE_1_BIT)
|
||||
| (parity_byte << PARITY_BYTE_1_BIT));
|
||||
DP_DEBUG("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",
|
||||
value, parity_byte);
|
||||
dp_audio_set_header(catalog, value,
|
||||
DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_1);
|
||||
|
||||
/* Config header and parity byte 2 */
|
||||
value = dp_audio_get_header(catalog,
|
||||
DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_2);
|
||||
value &= 0xffff0000;
|
||||
new_value = 0x0;
|
||||
parity_byte = dp_header_get_parity(new_value);
|
||||
value |= ((new_value << HEADER_BYTE_2_BIT)
|
||||
| (parity_byte << PARITY_BYTE_2_BIT));
|
||||
DP_DEBUG("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",
|
||||
value, parity_byte);
|
||||
|
||||
dp_audio_set_header(catalog, value,
|
||||
DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_2);
|
||||
|
||||
/* Config header and parity byte 3 */
|
||||
value = dp_audio_get_header(catalog,
|
||||
DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_3);
|
||||
value &= 0x0000ffff;
|
||||
|
||||
new_value = audio->channels - 1;
|
||||
parity_byte = dp_header_get_parity(new_value);
|
||||
value |= ((new_value << HEADER_BYTE_3_BIT)
|
||||
| (parity_byte << PARITY_BYTE_3_BIT));
|
||||
DP_DEBUG("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n",
|
||||
value, parity_byte);
|
||||
|
||||
dp_audio_set_header(catalog, value,
|
||||
DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_3);
|
||||
}
|
||||
|
||||
static void dp_audio_timestamp_sdp(struct dp_audio_private *audio)
|
||||
{
|
||||
struct dp_catalog_audio *catalog = audio->catalog;
|
||||
u32 value, new_value;
|
||||
u8 parity_byte;
|
||||
|
||||
/* Config header and parity byte 1 */
|
||||
value = dp_audio_get_header(catalog,
|
||||
DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_1);
|
||||
value &= 0x0000ffff;
|
||||
|
||||
new_value = 0x1;
|
||||
parity_byte = dp_header_get_parity(new_value);
|
||||
value |= ((new_value << HEADER_BYTE_1_BIT)
|
||||
| (parity_byte << PARITY_BYTE_1_BIT));
|
||||
DP_DEBUG("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",
|
||||
value, parity_byte);
|
||||
dp_audio_set_header(catalog, value,
|
||||
DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_1);
|
||||
|
||||
/* Config header and parity byte 2 */
|
||||
value = dp_audio_get_header(catalog,
|
||||
DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_2);
|
||||
value &= 0xffff0000;
|
||||
|
||||
new_value = 0x17;
|
||||
parity_byte = dp_header_get_parity(new_value);
|
||||
value |= ((new_value << HEADER_BYTE_2_BIT)
|
||||
| (parity_byte << PARITY_BYTE_2_BIT));
|
||||
DP_DEBUG("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",
|
||||
value, parity_byte);
|
||||
dp_audio_set_header(catalog, value,
|
||||
DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_2);
|
||||
|
||||
/* Config header and parity byte 3 */
|
||||
value = dp_audio_get_header(catalog,
|
||||
DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_3);
|
||||
value &= 0x0000ffff;
|
||||
|
||||
new_value = (0x0 | (0x11 << 2));
|
||||
parity_byte = dp_header_get_parity(new_value);
|
||||
value |= ((new_value << HEADER_BYTE_3_BIT)
|
||||
| (parity_byte << PARITY_BYTE_3_BIT));
|
||||
DP_DEBUG("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n",
|
||||
value, parity_byte);
|
||||
dp_audio_set_header(catalog, value,
|
||||
DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_3);
|
||||
}
|
||||
|
||||
static void dp_audio_infoframe_sdp(struct dp_audio_private *audio)
|
||||
{
|
||||
struct dp_catalog_audio *catalog = audio->catalog;
|
||||
u32 value, new_value;
|
||||
u8 parity_byte;
|
||||
|
||||
/* Config header and parity byte 1 */
|
||||
value = dp_audio_get_header(catalog,
|
||||
DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_1);
|
||||
value &= 0x0000ffff;
|
||||
|
||||
new_value = 0x84;
|
||||
parity_byte = dp_header_get_parity(new_value);
|
||||
value |= ((new_value << HEADER_BYTE_1_BIT)
|
||||
| (parity_byte << PARITY_BYTE_1_BIT));
|
||||
DP_DEBUG("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",
|
||||
value, parity_byte);
|
||||
dp_audio_set_header(catalog, value,
|
||||
DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_1);
|
||||
|
||||
/* Config header and parity byte 2 */
|
||||
value = dp_audio_get_header(catalog,
|
||||
DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_2);
|
||||
value &= 0xffff0000;
|
||||
|
||||
new_value = 0x1b;
|
||||
parity_byte = dp_header_get_parity(new_value);
|
||||
value |= ((new_value << HEADER_BYTE_2_BIT)
|
||||
| (parity_byte << PARITY_BYTE_2_BIT));
|
||||
DP_DEBUG("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",
|
||||
value, parity_byte);
|
||||
dp_audio_set_header(catalog, value,
|
||||
DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_2);
|
||||
|
||||
/* Config header and parity byte 3 */
|
||||
value = dp_audio_get_header(catalog,
|
||||
DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_3);
|
||||
value &= 0x0000ffff;
|
||||
|
||||
new_value = (0x0 | (0x11 << 2));
|
||||
parity_byte = dp_header_get_parity(new_value);
|
||||
value |= ((new_value << HEADER_BYTE_3_BIT)
|
||||
| (parity_byte << PARITY_BYTE_3_BIT));
|
||||
DP_DEBUG("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n",
|
||||
new_value, parity_byte);
|
||||
dp_audio_set_header(catalog, value,
|
||||
DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_3);
|
||||
}
|
||||
|
||||
static void dp_audio_copy_management_sdp(struct dp_audio_private *audio)
|
||||
{
|
||||
struct dp_catalog_audio *catalog = audio->catalog;
|
||||
u32 value, new_value;
|
||||
u8 parity_byte;
|
||||
|
||||
/* Config header and parity byte 1 */
|
||||
value = dp_audio_get_header(catalog,
|
||||
DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_1);
|
||||
value &= 0x0000ffff;
|
||||
|
||||
new_value = 0x05;
|
||||
parity_byte = dp_header_get_parity(new_value);
|
||||
value |= ((new_value << HEADER_BYTE_1_BIT)
|
||||
| (parity_byte << PARITY_BYTE_1_BIT));
|
||||
DP_DEBUG("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",
|
||||
value, parity_byte);
|
||||
dp_audio_set_header(catalog, value,
|
||||
DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_1);
|
||||
|
||||
/* Config header and parity byte 2 */
|
||||
value = dp_audio_get_header(catalog,
|
||||
DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_2);
|
||||
value &= 0xffff0000;
|
||||
|
||||
new_value = 0x0F;
|
||||
parity_byte = dp_header_get_parity(new_value);
|
||||
value |= ((new_value << HEADER_BYTE_2_BIT)
|
||||
| (parity_byte << PARITY_BYTE_2_BIT));
|
||||
DP_DEBUG("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",
|
||||
value, parity_byte);
|
||||
dp_audio_set_header(catalog, value,
|
||||
DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_2);
|
||||
|
||||
/* Config header and parity byte 3 */
|
||||
value = dp_audio_get_header(catalog,
|
||||
DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_3);
|
||||
value &= 0x0000ffff;
|
||||
|
||||
new_value = 0x0;
|
||||
parity_byte = dp_header_get_parity(new_value);
|
||||
value |= ((new_value << HEADER_BYTE_3_BIT)
|
||||
| (parity_byte << PARITY_BYTE_3_BIT));
|
||||
DP_DEBUG("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n",
|
||||
value, parity_byte);
|
||||
dp_audio_set_header(catalog, value,
|
||||
DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_3);
|
||||
}
|
||||
|
||||
static void dp_audio_isrc_sdp(struct dp_audio_private *audio)
|
||||
{
|
||||
struct dp_catalog_audio *catalog = audio->catalog;
|
||||
u32 value, new_value;
|
||||
u8 parity_byte;
|
||||
|
||||
/* Config header and parity byte 1 */
|
||||
value = dp_audio_get_header(catalog,
|
||||
DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_1);
|
||||
value &= 0x0000ffff;
|
||||
|
||||
new_value = 0x06;
|
||||
parity_byte = dp_header_get_parity(new_value);
|
||||
value |= ((new_value << HEADER_BYTE_1_BIT)
|
||||
| (parity_byte << PARITY_BYTE_1_BIT));
|
||||
DP_DEBUG("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",
|
||||
value, parity_byte);
|
||||
dp_audio_set_header(catalog, value,
|
||||
DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_1);
|
||||
|
||||
/* Config header and parity byte 2 */
|
||||
value = dp_audio_get_header(catalog,
|
||||
DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_2);
|
||||
value &= 0xffff0000;
|
||||
|
||||
new_value = 0x0F;
|
||||
parity_byte = dp_header_get_parity(new_value);
|
||||
value |= ((new_value << HEADER_BYTE_2_BIT)
|
||||
| (parity_byte << PARITY_BYTE_2_BIT));
|
||||
DP_DEBUG("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",
|
||||
value, parity_byte);
|
||||
dp_audio_set_header(catalog, value,
|
||||
DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_2);
|
||||
}
|
||||
|
||||
static void dp_audio_setup_sdp(struct dp_audio_private *audio)
|
||||
{
|
||||
if (!atomic_read(&audio->session_on)) {
|
||||
DP_WARN("session inactive\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* always program stream 0 first before actual stream cfg */
|
||||
audio->catalog->stream_id = DP_STREAM_0;
|
||||
audio->catalog->config_sdp(audio->catalog);
|
||||
|
||||
if (audio->panel->stream_id == DP_STREAM_1) {
|
||||
audio->catalog->stream_id = DP_STREAM_1;
|
||||
audio->catalog->config_sdp(audio->catalog);
|
||||
}
|
||||
|
||||
dp_audio_stream_sdp(audio);
|
||||
dp_audio_timestamp_sdp(audio);
|
||||
dp_audio_infoframe_sdp(audio);
|
||||
dp_audio_copy_management_sdp(audio);
|
||||
dp_audio_isrc_sdp(audio);
|
||||
}
|
||||
|
||||
static void dp_audio_setup_acr(struct dp_audio_private *audio)
|
||||
{
|
||||
u32 select = 0;
|
||||
struct dp_catalog_audio *catalog = audio->catalog;
|
||||
|
||||
if (!atomic_read(&audio->session_on)) {
|
||||
DP_WARN("session inactive\n");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (audio->dp_audio.bw_code) {
|
||||
case DP_LINK_BW_1_62:
|
||||
select = 0;
|
||||
break;
|
||||
case DP_LINK_BW_2_7:
|
||||
select = 1;
|
||||
break;
|
||||
case DP_LINK_BW_5_4:
|
||||
select = 2;
|
||||
break;
|
||||
case DP_LINK_BW_8_1:
|
||||
select = 3;
|
||||
break;
|
||||
default:
|
||||
DP_DEBUG("Unknown link rate\n");
|
||||
select = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
catalog->data = select;
|
||||
catalog->config_acr(catalog);
|
||||
}
|
||||
|
||||
static void dp_audio_enable(struct dp_audio_private *audio, bool enable)
|
||||
{
|
||||
struct dp_catalog_audio *catalog = audio->catalog;
|
||||
|
||||
audio->engine_on = enable;
|
||||
if (!atomic_read(&audio->session_on)) {
|
||||
DP_WARN("session inactive. enable=%d\n", enable);
|
||||
return;
|
||||
}
|
||||
catalog->data = enable;
|
||||
catalog->enable(catalog);
|
||||
|
||||
}
|
||||
|
||||
static struct dp_audio_private *dp_audio_get_data(struct platform_device *pdev)
|
||||
{
|
||||
struct msm_ext_disp_data *ext_data;
|
||||
struct dp_audio *dp_audio;
|
||||
|
||||
if (!pdev) {
|
||||
DP_ERR("invalid input\n");
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
ext_data = platform_get_drvdata(pdev);
|
||||
if (!ext_data) {
|
||||
DP_ERR("invalid ext disp data\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
dp_audio = ext_data->intf_data;
|
||||
if (!dp_audio) {
|
||||
DP_ERR("invalid intf data\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
return container_of(dp_audio, struct dp_audio_private, dp_audio);
|
||||
}
|
||||
|
||||
static int dp_audio_info_setup(struct platform_device *pdev,
|
||||
struct msm_ext_disp_audio_setup_params *params)
|
||||
{
|
||||
int rc = 0;
|
||||
struct dp_audio_private *audio;
|
||||
|
||||
audio = dp_audio_get_data(pdev);
|
||||
if (IS_ERR(audio)) {
|
||||
rc = PTR_ERR(audio);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (audio->dp_audio.tui_active) {
|
||||
DP_DEBUG("TUI session active\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
mutex_lock(&audio->ops_lock);
|
||||
|
||||
audio->channels = params->num_of_channels;
|
||||
|
||||
if (audio->panel->stream_id >= DP_STREAM_MAX) {
|
||||
DP_ERR("invalid stream id: %d\n",
|
||||
audio->panel->stream_id);
|
||||
rc = -EINVAL;
|
||||
mutex_unlock(&audio->ops_lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
dp_audio_setup_sdp(audio);
|
||||
dp_audio_setup_acr(audio);
|
||||
dp_audio_enable(audio, true);
|
||||
|
||||
mutex_unlock(&audio->ops_lock);
|
||||
|
||||
DP_DEBUG("audio stream configured\n");
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int dp_audio_get_edid_blk(struct platform_device *pdev,
|
||||
struct msm_ext_disp_audio_edid_blk *blk)
|
||||
{
|
||||
int rc = 0;
|
||||
struct dp_audio_private *audio;
|
||||
struct sde_edid_ctrl *edid;
|
||||
|
||||
if (!blk) {
|
||||
DP_ERR("invalid input\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
audio = dp_audio_get_data(pdev);
|
||||
if (IS_ERR(audio)) {
|
||||
rc = PTR_ERR(audio);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!audio->panel || !audio->panel->edid_ctrl) {
|
||||
DP_ERR("invalid panel data\n");
|
||||
rc = -EINVAL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
edid = audio->panel->edid_ctrl;
|
||||
|
||||
blk->audio_data_blk = edid->audio_data_block;
|
||||
blk->audio_data_blk_size = edid->adb_size;
|
||||
|
||||
blk->spk_alloc_data_blk = edid->spkr_alloc_data_block;
|
||||
blk->spk_alloc_data_blk_size = edid->sadb_size;
|
||||
end:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int dp_audio_get_cable_status(struct platform_device *pdev, u32 vote)
|
||||
{
|
||||
int rc = 0;
|
||||
struct dp_audio_private *audio;
|
||||
|
||||
audio = dp_audio_get_data(pdev);
|
||||
if (IS_ERR(audio)) {
|
||||
rc = PTR_ERR(audio);
|
||||
goto end;
|
||||
}
|
||||
|
||||
return atomic_read(&audio->session_on);
|
||||
end:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int dp_audio_get_intf_id(struct platform_device *pdev)
|
||||
{
|
||||
int rc = 0;
|
||||
struct dp_audio_private *audio;
|
||||
|
||||
audio = dp_audio_get_data(pdev);
|
||||
if (IS_ERR(audio)) {
|
||||
rc = PTR_ERR(audio);
|
||||
goto end;
|
||||
}
|
||||
|
||||
return EXT_DISPLAY_TYPE_DP;
|
||||
end:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void dp_audio_teardown_done(struct platform_device *pdev)
|
||||
{
|
||||
struct dp_audio_private *audio;
|
||||
|
||||
audio = dp_audio_get_data(pdev);
|
||||
if (IS_ERR(audio))
|
||||
return;
|
||||
|
||||
if (audio->dp_audio.tui_active) {
|
||||
DP_DEBUG("TUI session active\n");
|
||||
return;
|
||||
}
|
||||
|
||||
mutex_lock(&audio->ops_lock);
|
||||
dp_audio_enable(audio, false);
|
||||
mutex_unlock(&audio->ops_lock);
|
||||
|
||||
atomic_set(&audio->acked, 1);
|
||||
complete_all(&audio->hpd_comp);
|
||||
|
||||
DP_DEBUG("audio engine disabled\n");
|
||||
}
|
||||
|
||||
static int dp_audio_ack_done(struct platform_device *pdev, u32 ack)
|
||||
{
|
||||
int rc = 0, ack_hpd;
|
||||
struct dp_audio_private *audio;
|
||||
|
||||
audio = dp_audio_get_data(pdev);
|
||||
if (IS_ERR(audio)) {
|
||||
rc = PTR_ERR(audio);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (ack & AUDIO_ACK_SET_ENABLE) {
|
||||
audio->ack_enabled = ack & AUDIO_ACK_ENABLE ?
|
||||
true : false;
|
||||
|
||||
DP_DEBUG("audio ack feature %s\n",
|
||||
audio->ack_enabled ? "enabled" : "disabled");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!audio->ack_enabled)
|
||||
goto end;
|
||||
|
||||
ack_hpd = ack & AUDIO_ACK_CONNECT;
|
||||
|
||||
DP_DEBUG("acknowledging audio (%d)\n", ack_hpd);
|
||||
|
||||
if (!audio->engine_on) {
|
||||
atomic_set(&audio->acked, 1);
|
||||
complete_all(&audio->hpd_comp);
|
||||
}
|
||||
end:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int dp_audio_codec_ready(struct platform_device *pdev)
|
||||
{
|
||||
int rc = 0;
|
||||
struct dp_audio_private *audio;
|
||||
|
||||
audio = dp_audio_get_data(pdev);
|
||||
if (IS_ERR(audio)) {
|
||||
DP_ERR("invalid input\n");
|
||||
rc = PTR_ERR(audio);
|
||||
goto end;
|
||||
}
|
||||
|
||||
queue_delayed_work(audio->notify_workqueue,
|
||||
&audio->notify_delayed_work, HZ/4);
|
||||
end:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int dp_audio_register_ext_disp(struct dp_audio_private *audio)
|
||||
{
|
||||
int rc = 0;
|
||||
struct device_node *pd = NULL;
|
||||
const char *phandle = "qcom,ext-disp";
|
||||
struct msm_ext_disp_init_data *ext;
|
||||
struct msm_ext_disp_audio_codec_ops *ops;
|
||||
|
||||
ext = &audio->ext_audio_data;
|
||||
ops = &ext->codec_ops;
|
||||
|
||||
ext->codec.type = EXT_DISPLAY_TYPE_DP;
|
||||
ext->codec.ctrl_id = 0;
|
||||
ext->codec.stream_id = audio->panel->stream_id;
|
||||
ext->pdev = audio->pdev;
|
||||
ext->intf_data = &audio->dp_audio;
|
||||
|
||||
ops->audio_info_setup = dp_audio_info_setup;
|
||||
ops->get_audio_edid_blk = dp_audio_get_edid_blk;
|
||||
ops->cable_status = dp_audio_get_cable_status;
|
||||
ops->get_intf_id = dp_audio_get_intf_id;
|
||||
ops->teardown_done = dp_audio_teardown_done;
|
||||
ops->acknowledge = dp_audio_ack_done;
|
||||
ops->ready = dp_audio_codec_ready;
|
||||
|
||||
if (!audio->pdev->dev.of_node) {
|
||||
DP_ERR("cannot find audio dev.of_node\n");
|
||||
rc = -ENODEV;
|
||||
goto end;
|
||||
}
|
||||
|
||||
pd = of_parse_phandle(audio->pdev->dev.of_node, phandle, 0);
|
||||
if (!pd) {
|
||||
DP_ERR("cannot parse %s handle\n", phandle);
|
||||
rc = -ENODEV;
|
||||
goto end;
|
||||
}
|
||||
|
||||
audio->ext_pdev = of_find_device_by_node(pd);
|
||||
if (!audio->ext_pdev) {
|
||||
DP_ERR("cannot find %s pdev\n", phandle);
|
||||
rc = -ENODEV;
|
||||
goto end;
|
||||
}
|
||||
#if defined(CONFIG_MSM_EXT_DISPLAY)
|
||||
rc = msm_ext_disp_register_intf(audio->ext_pdev, ext);
|
||||
if (rc)
|
||||
DP_ERR("failed to register disp\n");
|
||||
#endif
|
||||
end:
|
||||
if (pd)
|
||||
of_node_put(pd);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int dp_audio_deregister_ext_disp(struct dp_audio_private *audio)
|
||||
{
|
||||
int rc = 0;
|
||||
struct device_node *pd = NULL;
|
||||
const char *phandle = "qcom,ext-disp";
|
||||
struct msm_ext_disp_init_data *ext;
|
||||
|
||||
ext = &audio->ext_audio_data;
|
||||
|
||||
if (!audio->pdev->dev.of_node) {
|
||||
DP_ERR("cannot find audio dev.of_node\n");
|
||||
rc = -ENODEV;
|
||||
goto end;
|
||||
}
|
||||
|
||||
pd = of_parse_phandle(audio->pdev->dev.of_node, phandle, 0);
|
||||
if (!pd) {
|
||||
DP_ERR("cannot parse %s handle\n", phandle);
|
||||
rc = -ENODEV;
|
||||
goto end;
|
||||
}
|
||||
|
||||
audio->ext_pdev = of_find_device_by_node(pd);
|
||||
if (!audio->ext_pdev) {
|
||||
DP_ERR("cannot find %s pdev\n", phandle);
|
||||
rc = -ENODEV;
|
||||
goto end;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_MSM_EXT_DISPLAY)
|
||||
rc = msm_ext_disp_deregister_intf(audio->ext_pdev, ext);
|
||||
if (rc)
|
||||
DP_ERR("failed to deregister disp\n");
|
||||
#endif
|
||||
|
||||
end:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int dp_audio_notify(struct dp_audio_private *audio, u32 state)
|
||||
{
|
||||
int rc = 0;
|
||||
struct msm_ext_disp_init_data *ext = &audio->ext_audio_data;
|
||||
|
||||
atomic_set(&audio->acked, 0);
|
||||
|
||||
if (!ext->intf_ops.audio_notify) {
|
||||
DP_ERR("audio notify not defined\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
reinit_completion(&audio->hpd_comp);
|
||||
rc = ext->intf_ops.audio_notify(audio->ext_pdev,
|
||||
&ext->codec, state);
|
||||
if (rc)
|
||||
goto end;
|
||||
|
||||
if (atomic_read(&audio->acked))
|
||||
goto end;
|
||||
|
||||
if (state == EXT_DISPLAY_CABLE_DISCONNECT && !audio->engine_on)
|
||||
goto end;
|
||||
|
||||
if (state == EXT_DISPLAY_CABLE_CONNECT)
|
||||
goto end;
|
||||
|
||||
rc = wait_for_completion_timeout(&audio->hpd_comp, HZ * 4);
|
||||
if (!rc) {
|
||||
DP_ERR("timeout. state=%d err=%d\n", state, rc);
|
||||
rc = -ETIMEDOUT;
|
||||
goto end;
|
||||
}
|
||||
|
||||
DP_DEBUG("success\n");
|
||||
end:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int dp_audio_config(struct dp_audio_private *audio, u32 state)
|
||||
{
|
||||
int rc = 0;
|
||||
struct msm_ext_disp_init_data *ext = &audio->ext_audio_data;
|
||||
|
||||
if (!ext || !ext->intf_ops.audio_config) {
|
||||
DP_ERR("audio_config not defined\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/*
|
||||
* DP Audio sets default STREAM_0 only, other streams are
|
||||
* set by audio driver based on the hardware/software support.
|
||||
*/
|
||||
if (audio->panel->stream_id == DP_STREAM_0) {
|
||||
rc = ext->intf_ops.audio_config(audio->ext_pdev,
|
||||
&ext->codec, state);
|
||||
if (rc)
|
||||
DP_ERR("failed to config audio, err=%d\n",
|
||||
rc);
|
||||
}
|
||||
end:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int dp_audio_on(struct dp_audio *dp_audio)
|
||||
{
|
||||
int rc = 0;
|
||||
struct dp_audio_private *audio;
|
||||
struct msm_ext_disp_init_data *ext;
|
||||
|
||||
if (!dp_audio) {
|
||||
DP_ERR("invalid input\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
audio = container_of(dp_audio, struct dp_audio_private, dp_audio);
|
||||
if (IS_ERR(audio)) {
|
||||
DP_ERR("invalid input\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dp_audio_register_ext_disp(audio);
|
||||
|
||||
ext = &audio->ext_audio_data;
|
||||
|
||||
atomic_set(&audio->session_on, 1);
|
||||
|
||||
rc = dp_audio_config(audio, EXT_DISPLAY_CABLE_CONNECT);
|
||||
if (rc)
|
||||
goto end;
|
||||
|
||||
rc = dp_audio_notify(audio, EXT_DISPLAY_CABLE_CONNECT);
|
||||
if (rc)
|
||||
goto end;
|
||||
|
||||
DP_DEBUG("success\n");
|
||||
end:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int dp_audio_off(struct dp_audio *dp_audio)
|
||||
{
|
||||
int rc = 0;
|
||||
struct dp_audio_private *audio;
|
||||
struct msm_ext_disp_init_data *ext;
|
||||
bool work_pending = false;
|
||||
|
||||
if (!dp_audio) {
|
||||
DP_ERR("invalid input\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
audio = container_of(dp_audio, struct dp_audio_private, dp_audio);
|
||||
|
||||
if (!atomic_read(&audio->session_on)) {
|
||||
DP_DEBUG("audio already off\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
ext = &audio->ext_audio_data;
|
||||
|
||||
work_pending = cancel_delayed_work_sync(&audio->notify_delayed_work);
|
||||
if (work_pending)
|
||||
DP_DEBUG("pending notification work completed\n");
|
||||
|
||||
rc = dp_audio_notify(audio, EXT_DISPLAY_CABLE_DISCONNECT);
|
||||
if (rc)
|
||||
goto end;
|
||||
|
||||
DP_DEBUG("success\n");
|
||||
end:
|
||||
dp_audio_config(audio, EXT_DISPLAY_CABLE_DISCONNECT);
|
||||
|
||||
atomic_set(&audio->session_on, 0);
|
||||
audio->engine_on = false;
|
||||
|
||||
dp_audio_deregister_ext_disp(audio);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void dp_audio_notify_work_fn(struct work_struct *work)
|
||||
{
|
||||
struct dp_audio_private *audio;
|
||||
struct delayed_work *dw = to_delayed_work(work);
|
||||
|
||||
audio = container_of(dw, struct dp_audio_private, notify_delayed_work);
|
||||
|
||||
dp_audio_notify(audio, EXT_DISPLAY_CABLE_CONNECT);
|
||||
}
|
||||
|
||||
static int dp_audio_create_notify_workqueue(struct dp_audio_private *audio)
|
||||
{
|
||||
audio->notify_workqueue = create_workqueue("sdm_dp_audio_notify");
|
||||
if (IS_ERR_OR_NULL(audio->notify_workqueue)) {
|
||||
DP_ERR("Error creating notify_workqueue\n");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
INIT_DELAYED_WORK(&audio->notify_delayed_work, dp_audio_notify_work_fn);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dp_audio_destroy_notify_workqueue(struct dp_audio_private *audio)
|
||||
{
|
||||
if (audio->notify_workqueue)
|
||||
destroy_workqueue(audio->notify_workqueue);
|
||||
}
|
||||
|
||||
struct dp_audio *dp_audio_get(struct platform_device *pdev,
|
||||
struct dp_panel *panel,
|
||||
struct dp_catalog_audio *catalog)
|
||||
{
|
||||
int rc = 0;
|
||||
struct dp_audio_private *audio;
|
||||
struct dp_audio *dp_audio;
|
||||
|
||||
if (!pdev || !panel || !catalog) {
|
||||
DP_ERR("invalid input\n");
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
audio = devm_kzalloc(&pdev->dev, sizeof(*audio), GFP_KERNEL);
|
||||
if (!audio) {
|
||||
rc = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = dp_audio_create_notify_workqueue(audio);
|
||||
if (rc)
|
||||
goto error_notify_workqueue;
|
||||
|
||||
init_completion(&audio->hpd_comp);
|
||||
|
||||
audio->pdev = pdev;
|
||||
audio->panel = panel;
|
||||
audio->catalog = catalog;
|
||||
|
||||
atomic_set(&audio->acked, 0);
|
||||
|
||||
dp_audio = &audio->dp_audio;
|
||||
|
||||
mutex_init(&audio->ops_lock);
|
||||
|
||||
dp_audio->on = dp_audio_on;
|
||||
dp_audio->off = dp_audio_off;
|
||||
|
||||
catalog->init(catalog);
|
||||
|
||||
return dp_audio;
|
||||
|
||||
error_notify_workqueue:
|
||||
devm_kfree(&pdev->dev, audio);
|
||||
error:
|
||||
return ERR_PTR(rc);
|
||||
}
|
||||
|
||||
void dp_audio_put(struct dp_audio *dp_audio)
|
||||
{
|
||||
struct dp_audio_private *audio;
|
||||
|
||||
if (!dp_audio)
|
||||
return;
|
||||
|
||||
audio = container_of(dp_audio, struct dp_audio_private, dp_audio);
|
||||
|
||||
mutex_destroy(&audio->ops_lock);
|
||||
|
||||
dp_audio_destroy_notify_workqueue(audio);
|
||||
|
||||
devm_kfree(&audio->pdev->dev, audio);
|
||||
}
|
74
techpack/display/msm/dp/dp_audio.h
Normal file
74
techpack/display/msm/dp/dp_audio.h
Normal file
@ -0,0 +1,74 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _DP_AUDIO_H_
|
||||
#define _DP_AUDIO_H_
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "dp_panel.h"
|
||||
#include "dp_catalog.h"
|
||||
|
||||
/**
|
||||
* struct dp_audio
|
||||
* @lane_count: number of lanes configured in current session
|
||||
* @bw_code: link rate's bandwidth code for current session
|
||||
* @tui_active: set to true if TUI is active in the system
|
||||
*/
|
||||
struct dp_audio {
|
||||
u32 lane_count;
|
||||
u32 bw_code;
|
||||
bool tui_active;
|
||||
|
||||
/**
|
||||
* on()
|
||||
*
|
||||
* Notifies user mode clients that DP is powered on, and that audio
|
||||
* playback can start on the external display.
|
||||
*
|
||||
* @dp_audio: an instance of struct dp_audio.
|
||||
*
|
||||
* Returns the error code in case of failure, 0 in success case.
|
||||
*/
|
||||
int (*on)(struct dp_audio *dp_audio);
|
||||
|
||||
/**
|
||||
* off()
|
||||
*
|
||||
* Notifies user mode clients that DP is shutting down, and audio
|
||||
* playback should be stopped on the external display.
|
||||
*
|
||||
* @dp_audio: an instance of struct dp_audio.
|
||||
*
|
||||
* Returns the error code in case of failure, 0 in success case.
|
||||
*/
|
||||
int (*off)(struct dp_audio *dp_audio);
|
||||
};
|
||||
|
||||
/**
|
||||
* dp_audio_get()
|
||||
*
|
||||
* Creates and instance of dp audio.
|
||||
*
|
||||
* @pdev: caller's platform device instance.
|
||||
* @panel: an instance of dp_panel module.
|
||||
* @catalog: an instance of dp_catalog_audio module.
|
||||
*
|
||||
* Returns the error code in case of failure, otherwize
|
||||
* an instance of newly created dp_module.
|
||||
*/
|
||||
struct dp_audio *dp_audio_get(struct platform_device *pdev,
|
||||
struct dp_panel *panel,
|
||||
struct dp_catalog_audio *catalog);
|
||||
|
||||
/**
|
||||
* dp_audio_put()
|
||||
*
|
||||
* Cleans the dp_audio instance.
|
||||
*
|
||||
* @dp_audio: an instance of dp_audio.
|
||||
*/
|
||||
void dp_audio_put(struct dp_audio *dp_audio);
|
||||
#endif /* _DP_AUDIO_H_ */
|
867
techpack/display/msm/dp/dp_aux.c
Normal file
867
techpack/display/msm/dp/dp_aux.c
Normal file
@ -0,0 +1,867 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/soc/qcom/fsa4480-i2c.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "dp_aux.h"
|
||||
#include "dp_hpd.h"
|
||||
#include "dp_debug.h"
|
||||
|
||||
#define DP_AUX_ENUM_STR(x) #x
|
||||
|
||||
enum {
|
||||
DP_AUX_DATA_INDEX_WRITE = BIT(31),
|
||||
};
|
||||
|
||||
struct dp_aux_private {
|
||||
struct device *dev;
|
||||
struct dp_aux dp_aux;
|
||||
struct dp_catalog_aux *catalog;
|
||||
struct dp_aux_cfg *cfg;
|
||||
struct device_node *aux_switch_node;
|
||||
struct mutex mutex;
|
||||
struct completion comp;
|
||||
struct drm_dp_aux drm_aux;
|
||||
|
||||
bool cmd_busy;
|
||||
bool native;
|
||||
bool read;
|
||||
bool no_send_addr;
|
||||
bool no_send_stop;
|
||||
bool enabled;
|
||||
|
||||
u32 offset;
|
||||
u32 segment;
|
||||
u32 aux_error_num;
|
||||
u32 retry_cnt;
|
||||
|
||||
atomic_t aborted;
|
||||
|
||||
u8 *dpcd;
|
||||
u8 *edid;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DYNAMIC_DEBUG
|
||||
static void dp_aux_hex_dump(struct drm_dp_aux *drm_aux,
|
||||
struct drm_dp_aux_msg *msg)
|
||||
{
|
||||
char prefix[64];
|
||||
int i, linelen, remaining = msg->size;
|
||||
const int rowsize = 16;
|
||||
u8 linebuf[64];
|
||||
struct dp_aux_private *aux = container_of(drm_aux,
|
||||
struct dp_aux_private, drm_aux);
|
||||
|
||||
snprintf(prefix, sizeof(prefix), "%s %s %4xh(%2zu): ",
|
||||
aux->native ? "NAT" : "I2C",
|
||||
aux->read ? "RD" : "WR",
|
||||
msg->address, msg->size);
|
||||
|
||||
for (i = 0; i < msg->size; i += rowsize) {
|
||||
linelen = min(remaining, rowsize);
|
||||
remaining -= rowsize;
|
||||
|
||||
hex_dump_to_buffer(msg->buffer + i, linelen, rowsize, 1,
|
||||
linebuf, sizeof(linebuf), false);
|
||||
|
||||
DP_DEBUG("%s%s\n", prefix, linebuf);
|
||||
}
|
||||
}
|
||||
#else
|
||||
static void dp_aux_hex_dump(struct drm_dp_aux *drm_aux,
|
||||
struct drm_dp_aux_msg *msg)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
static char *dp_aux_get_error(u32 aux_error)
|
||||
{
|
||||
switch (aux_error) {
|
||||
case DP_AUX_ERR_NONE:
|
||||
return DP_AUX_ENUM_STR(DP_AUX_ERR_NONE);
|
||||
case DP_AUX_ERR_ADDR:
|
||||
return DP_AUX_ENUM_STR(DP_AUX_ERR_ADDR);
|
||||
case DP_AUX_ERR_TOUT:
|
||||
return DP_AUX_ENUM_STR(DP_AUX_ERR_TOUT);
|
||||
case DP_AUX_ERR_NACK:
|
||||
return DP_AUX_ENUM_STR(DP_AUX_ERR_NACK);
|
||||
case DP_AUX_ERR_DEFER:
|
||||
return DP_AUX_ENUM_STR(DP_AUX_ERR_DEFER);
|
||||
case DP_AUX_ERR_NACK_DEFER:
|
||||
return DP_AUX_ENUM_STR(DP_AUX_ERR_NACK_DEFER);
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static u32 dp_aux_write(struct dp_aux_private *aux,
|
||||
struct drm_dp_aux_msg *msg)
|
||||
{
|
||||
u32 data[4], reg, len;
|
||||
u8 *msgdata = msg->buffer;
|
||||
int const aux_cmd_fifo_len = 128;
|
||||
int i = 0;
|
||||
|
||||
if (aux->read)
|
||||
len = 4;
|
||||
else
|
||||
len = msg->size + 4;
|
||||
|
||||
/*
|
||||
* cmd fifo only has depth of 144 bytes
|
||||
* limit buf length to 128 bytes here
|
||||
*/
|
||||
if (len > aux_cmd_fifo_len) {
|
||||
DP_ERR("buf len error\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Pack cmd and write to HW */
|
||||
data[0] = (msg->address >> 16) & 0xf; /* addr[19:16] */
|
||||
if (aux->read)
|
||||
data[0] |= BIT(4); /* R/W */
|
||||
|
||||
data[1] = (msg->address >> 8) & 0xff; /* addr[15:8] */
|
||||
data[2] = msg->address & 0xff; /* addr[7:0] */
|
||||
data[3] = (msg->size - 1) & 0xff; /* len[7:0] */
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
reg = (i < 4) ? data[i] : msgdata[i - 4];
|
||||
reg = ((reg) << 8) & 0x0000ff00; /* index = 0, write */
|
||||
if (i == 0)
|
||||
reg |= DP_AUX_DATA_INDEX_WRITE;
|
||||
aux->catalog->data = reg;
|
||||
aux->catalog->write_data(aux->catalog);
|
||||
}
|
||||
|
||||
aux->catalog->clear_trans(aux->catalog, false);
|
||||
aux->catalog->clear_hw_interrupts(aux->catalog);
|
||||
|
||||
reg = 0; /* Transaction number == 1 */
|
||||
if (!aux->native) { /* i2c */
|
||||
reg |= BIT(8);
|
||||
|
||||
if (aux->no_send_addr)
|
||||
reg |= BIT(10);
|
||||
|
||||
if (aux->no_send_stop)
|
||||
reg |= BIT(11);
|
||||
}
|
||||
|
||||
reg |= BIT(9);
|
||||
aux->catalog->data = reg;
|
||||
aux->catalog->write_trans(aux->catalog);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int dp_aux_cmd_fifo_tx(struct dp_aux_private *aux,
|
||||
struct drm_dp_aux_msg *msg)
|
||||
{
|
||||
u32 ret = 0, len = 0, timeout;
|
||||
int const aux_timeout_ms = HZ/4;
|
||||
|
||||
reinit_completion(&aux->comp);
|
||||
|
||||
len = dp_aux_write(aux, msg);
|
||||
if (len == 0) {
|
||||
DP_ERR("DP AUX write failed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
timeout = wait_for_completion_timeout(&aux->comp, aux_timeout_ms);
|
||||
if (!timeout) {
|
||||
DP_ERR("aux %s timeout\n", (aux->read ? "read" : "write"));
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
if (aux->aux_error_num == DP_AUX_ERR_NONE) {
|
||||
ret = len;
|
||||
} else {
|
||||
pr_err_ratelimited("aux err: %s\n",
|
||||
dp_aux_get_error(aux->aux_error_num));
|
||||
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void dp_aux_cmd_fifo_rx(struct dp_aux_private *aux,
|
||||
struct drm_dp_aux_msg *msg)
|
||||
{
|
||||
u32 data;
|
||||
u8 *dp;
|
||||
u32 i, actual_i;
|
||||
u32 len = msg->size;
|
||||
|
||||
aux->catalog->clear_trans(aux->catalog, true);
|
||||
|
||||
data = 0;
|
||||
data |= DP_AUX_DATA_INDEX_WRITE; /* INDEX_WRITE */
|
||||
data |= BIT(0); /* read */
|
||||
|
||||
aux->catalog->data = data;
|
||||
aux->catalog->write_data(aux->catalog);
|
||||
|
||||
dp = msg->buffer;
|
||||
|
||||
/* discard first byte */
|
||||
data = aux->catalog->read_data(aux->catalog);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
data = aux->catalog->read_data(aux->catalog);
|
||||
*dp++ = (u8)((data >> 8) & 0xff);
|
||||
|
||||
actual_i = (data >> 16) & 0xFF;
|
||||
if (i != actual_i)
|
||||
DP_WARN("Index mismatch: expected %d, found %d\n",
|
||||
i, actual_i);
|
||||
}
|
||||
}
|
||||
|
||||
static void dp_aux_native_handler(struct dp_aux_private *aux)
|
||||
{
|
||||
u32 isr = aux->catalog->isr;
|
||||
|
||||
if (isr & DP_INTR_AUX_I2C_DONE)
|
||||
aux->aux_error_num = DP_AUX_ERR_NONE;
|
||||
else if (isr & DP_INTR_WRONG_ADDR)
|
||||
aux->aux_error_num = DP_AUX_ERR_ADDR;
|
||||
else if (isr & DP_INTR_TIMEOUT)
|
||||
aux->aux_error_num = DP_AUX_ERR_TOUT;
|
||||
if (isr & DP_INTR_NACK_DEFER)
|
||||
aux->aux_error_num = DP_AUX_ERR_NACK;
|
||||
if (isr & DP_INTR_AUX_ERROR) {
|
||||
aux->aux_error_num = DP_AUX_ERR_PHY;
|
||||
aux->catalog->clear_hw_interrupts(aux->catalog);
|
||||
}
|
||||
|
||||
complete(&aux->comp);
|
||||
}
|
||||
|
||||
static void dp_aux_i2c_handler(struct dp_aux_private *aux)
|
||||
{
|
||||
u32 isr = aux->catalog->isr;
|
||||
|
||||
if (isr & DP_INTR_AUX_I2C_DONE) {
|
||||
if (isr & (DP_INTR_I2C_NACK | DP_INTR_I2C_DEFER))
|
||||
aux->aux_error_num = DP_AUX_ERR_NACK;
|
||||
else
|
||||
aux->aux_error_num = DP_AUX_ERR_NONE;
|
||||
} else {
|
||||
if (isr & DP_INTR_WRONG_ADDR)
|
||||
aux->aux_error_num = DP_AUX_ERR_ADDR;
|
||||
else if (isr & DP_INTR_TIMEOUT)
|
||||
aux->aux_error_num = DP_AUX_ERR_TOUT;
|
||||
if (isr & DP_INTR_NACK_DEFER)
|
||||
aux->aux_error_num = DP_AUX_ERR_NACK_DEFER;
|
||||
if (isr & DP_INTR_I2C_NACK)
|
||||
aux->aux_error_num = DP_AUX_ERR_NACK;
|
||||
if (isr & DP_INTR_I2C_DEFER)
|
||||
aux->aux_error_num = DP_AUX_ERR_DEFER;
|
||||
if (isr & DP_INTR_AUX_ERROR) {
|
||||
aux->aux_error_num = DP_AUX_ERR_PHY;
|
||||
aux->catalog->clear_hw_interrupts(aux->catalog);
|
||||
}
|
||||
}
|
||||
|
||||
complete(&aux->comp);
|
||||
}
|
||||
|
||||
static void dp_aux_isr(struct dp_aux *dp_aux)
|
||||
{
|
||||
struct dp_aux_private *aux;
|
||||
|
||||
if (!dp_aux) {
|
||||
DP_ERR("invalid input\n");
|
||||
return;
|
||||
}
|
||||
|
||||
aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
|
||||
|
||||
aux->catalog->get_irq(aux->catalog, aux->cmd_busy);
|
||||
|
||||
if (!aux->cmd_busy)
|
||||
return;
|
||||
|
||||
if (aux->native)
|
||||
dp_aux_native_handler(aux);
|
||||
else
|
||||
dp_aux_i2c_handler(aux);
|
||||
}
|
||||
|
||||
static void dp_aux_reconfig(struct dp_aux *dp_aux)
|
||||
{
|
||||
struct dp_aux_private *aux;
|
||||
|
||||
if (!dp_aux) {
|
||||
DP_ERR("invalid input\n");
|
||||
return;
|
||||
}
|
||||
|
||||
aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
|
||||
|
||||
aux->catalog->update_aux_cfg(aux->catalog,
|
||||
aux->cfg, PHY_AUX_CFG1);
|
||||
aux->catalog->reset(aux->catalog);
|
||||
}
|
||||
|
||||
static void dp_aux_abort_transaction(struct dp_aux *dp_aux, bool abort)
|
||||
{
|
||||
struct dp_aux_private *aux;
|
||||
|
||||
if (!dp_aux) {
|
||||
DP_ERR("invalid input\n");
|
||||
return;
|
||||
}
|
||||
|
||||
aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
|
||||
|
||||
atomic_set(&aux->aborted, abort);
|
||||
}
|
||||
|
||||
static void dp_aux_update_offset_and_segment(struct dp_aux_private *aux,
|
||||
struct drm_dp_aux_msg *input_msg)
|
||||
{
|
||||
u32 const edid_address = 0x50;
|
||||
u32 const segment_address = 0x30;
|
||||
bool i2c_read = input_msg->request &
|
||||
(DP_AUX_I2C_READ & DP_AUX_NATIVE_READ);
|
||||
u8 *data = NULL;
|
||||
|
||||
if (aux->native || i2c_read || ((input_msg->address != edid_address) &&
|
||||
(input_msg->address != segment_address)))
|
||||
return;
|
||||
|
||||
|
||||
data = input_msg->buffer;
|
||||
if (input_msg->address == segment_address)
|
||||
aux->segment = *data;
|
||||
else
|
||||
aux->offset = *data;
|
||||
}
|
||||
|
||||
/**
|
||||
* dp_aux_transfer_helper() - helper function for EDID read transactions
|
||||
*
|
||||
* @aux: DP AUX private structure
|
||||
* @input_msg: input message from DRM upstream APIs
|
||||
* @send_seg: send the seg to sink
|
||||
*
|
||||
* return: void
|
||||
*
|
||||
* This helper function is used to fix EDID reads for non-compliant
|
||||
* sinks that do not handle the i2c middle-of-transaction flag correctly.
|
||||
*/
|
||||
static void dp_aux_transfer_helper(struct dp_aux_private *aux,
|
||||
struct drm_dp_aux_msg *input_msg, bool send_seg)
|
||||
{
|
||||
struct drm_dp_aux_msg helper_msg;
|
||||
u32 const message_size = 0x10;
|
||||
u32 const segment_address = 0x30;
|
||||
u32 const edid_block_length = 0x80;
|
||||
bool i2c_mot = input_msg->request & DP_AUX_I2C_MOT;
|
||||
bool i2c_read = input_msg->request &
|
||||
(DP_AUX_I2C_READ & DP_AUX_NATIVE_READ);
|
||||
|
||||
if (!i2c_mot || !i2c_read || (input_msg->size == 0))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Sending the segment value and EDID offset will be performed
|
||||
* from the DRM upstream EDID driver for each block. Avoid
|
||||
* duplicate AUX transactions related to this while reading the
|
||||
* first 16 bytes of each block.
|
||||
*/
|
||||
if (!(aux->offset % edid_block_length) || !send_seg)
|
||||
goto end;
|
||||
|
||||
aux->read = false;
|
||||
aux->cmd_busy = true;
|
||||
aux->no_send_addr = true;
|
||||
aux->no_send_stop = true;
|
||||
|
||||
/*
|
||||
* Send the segment address for i2c reads for segment > 0 and for which
|
||||
* the middle-of-transaction flag is set. This is required to support
|
||||
* EDID reads of more than 2 blocks as the segment address is reset to 0
|
||||
* since we are overriding the middle-of-transaction flag for read
|
||||
* transactions.
|
||||
*/
|
||||
if (aux->segment) {
|
||||
memset(&helper_msg, 0, sizeof(helper_msg));
|
||||
helper_msg.address = segment_address;
|
||||
helper_msg.buffer = &aux->segment;
|
||||
helper_msg.size = 1;
|
||||
dp_aux_cmd_fifo_tx(aux, &helper_msg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Send the offset address for every i2c read in which the
|
||||
* middle-of-transaction flag is set. This will ensure that the sink
|
||||
* will update its read pointer and return the correct portion of the
|
||||
* EDID buffer in the subsequent i2c read trasntion triggered in the
|
||||
* native AUX transfer function.
|
||||
*/
|
||||
memset(&helper_msg, 0, sizeof(helper_msg));
|
||||
helper_msg.address = input_msg->address;
|
||||
helper_msg.buffer = &aux->offset;
|
||||
helper_msg.size = 1;
|
||||
dp_aux_cmd_fifo_tx(aux, &helper_msg);
|
||||
end:
|
||||
aux->offset += message_size;
|
||||
if (aux->offset == 0x80 || aux->offset == 0x100)
|
||||
aux->segment = 0x0; /* reset segment at end of block */
|
||||
}
|
||||
|
||||
static int dp_aux_transfer_ready(struct dp_aux_private *aux,
|
||||
struct drm_dp_aux_msg *msg, bool send_seg)
|
||||
{
|
||||
int ret = 0;
|
||||
int const aux_cmd_native_max = 16;
|
||||
int const aux_cmd_i2c_max = 128;
|
||||
|
||||
if (atomic_read(&aux->aborted)) {
|
||||
ret = -ETIMEDOUT;
|
||||
goto error;
|
||||
}
|
||||
|
||||
aux->native = msg->request & (DP_AUX_NATIVE_WRITE & DP_AUX_NATIVE_READ);
|
||||
|
||||
/* Ignore address only message */
|
||||
if ((msg->size == 0) || (msg->buffer == NULL)) {
|
||||
msg->reply = aux->native ?
|
||||
DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* msg sanity check */
|
||||
if ((aux->native && (msg->size > aux_cmd_native_max)) ||
|
||||
(msg->size > aux_cmd_i2c_max)) {
|
||||
DP_ERR("%s: invalid msg: size(%zu), request(%x)\n",
|
||||
__func__, msg->size, msg->request);
|
||||
ret = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
dp_aux_update_offset_and_segment(aux, msg);
|
||||
|
||||
dp_aux_transfer_helper(aux, msg, send_seg);
|
||||
|
||||
aux->read = msg->request & (DP_AUX_I2C_READ & DP_AUX_NATIVE_READ);
|
||||
|
||||
if (aux->read) {
|
||||
aux->no_send_addr = true;
|
||||
aux->no_send_stop = false;
|
||||
} else {
|
||||
aux->no_send_addr = true;
|
||||
aux->no_send_stop = true;
|
||||
}
|
||||
|
||||
aux->cmd_busy = true;
|
||||
error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t dp_aux_transfer_debug(struct drm_dp_aux *drm_aux,
|
||||
struct drm_dp_aux_msg *msg)
|
||||
{
|
||||
u32 timeout;
|
||||
ssize_t ret;
|
||||
struct dp_aux_private *aux = container_of(drm_aux,
|
||||
struct dp_aux_private, drm_aux);
|
||||
|
||||
mutex_lock(&aux->mutex);
|
||||
|
||||
ret = dp_aux_transfer_ready(aux, msg, false);
|
||||
if (ret)
|
||||
goto end;
|
||||
|
||||
aux->aux_error_num = DP_AUX_ERR_NONE;
|
||||
|
||||
if (!aux->dpcd || !aux->edid) {
|
||||
DP_ERR("invalid aux/dpcd structure\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if ((msg->address + msg->size) > SZ_4K) {
|
||||
DP_DEBUG("invalid dpcd access: addr=0x%x, size=0x%lx\n",
|
||||
msg->address, msg->size);
|
||||
goto address_error;
|
||||
}
|
||||
|
||||
if (aux->native) {
|
||||
mutex_lock(aux->dp_aux.access_lock);
|
||||
aux->dp_aux.reg = msg->address;
|
||||
aux->dp_aux.read = aux->read;
|
||||
aux->dp_aux.size = msg->size;
|
||||
|
||||
if (!aux->read)
|
||||
memcpy(aux->dpcd + msg->address,
|
||||
msg->buffer, msg->size);
|
||||
|
||||
reinit_completion(&aux->comp);
|
||||
mutex_unlock(aux->dp_aux.access_lock);
|
||||
|
||||
timeout = wait_for_completion_timeout(&aux->comp, HZ * 2);
|
||||
if (!timeout) {
|
||||
DP_ERR("%s timeout: 0x%x\n",
|
||||
aux->read ? "read" : "write",
|
||||
msg->address);
|
||||
atomic_set(&aux->aborted, 1);
|
||||
ret = -ETIMEDOUT;
|
||||
goto end;
|
||||
}
|
||||
|
||||
mutex_lock(aux->dp_aux.access_lock);
|
||||
if (aux->read)
|
||||
memcpy(msg->buffer, aux->dpcd + msg->address,
|
||||
msg->size);
|
||||
mutex_unlock(aux->dp_aux.access_lock);
|
||||
|
||||
aux->aux_error_num = DP_AUX_ERR_NONE;
|
||||
} else {
|
||||
if (aux->read && msg->address == 0x50) {
|
||||
memcpy(msg->buffer,
|
||||
aux->edid + aux->offset - 16,
|
||||
msg->size);
|
||||
}
|
||||
}
|
||||
|
||||
if (aux->aux_error_num == DP_AUX_ERR_NONE) {
|
||||
dp_aux_hex_dump(drm_aux, msg);
|
||||
|
||||
if (!aux->read)
|
||||
memset(msg->buffer, 0, msg->size);
|
||||
|
||||
msg->reply = aux->native ?
|
||||
DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK;
|
||||
} else {
|
||||
/* Reply defer to retry */
|
||||
msg->reply = aux->native ?
|
||||
DP_AUX_NATIVE_REPLY_DEFER : DP_AUX_I2C_REPLY_DEFER;
|
||||
}
|
||||
|
||||
ret = msg->size;
|
||||
goto end;
|
||||
|
||||
address_error:
|
||||
memset(msg->buffer, 0, msg->size);
|
||||
ret = msg->size;
|
||||
end:
|
||||
if (ret == -ETIMEDOUT)
|
||||
aux->dp_aux.state |= DP_STATE_AUX_TIMEOUT;
|
||||
aux->dp_aux.reg = 0xFFFF;
|
||||
aux->dp_aux.read = true;
|
||||
aux->dp_aux.size = 0;
|
||||
|
||||
mutex_unlock(&aux->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function does the real job to process an AUX transaction.
|
||||
* It will call aux_reset() function to reset the AUX channel,
|
||||
* if the waiting is timeout.
|
||||
*/
|
||||
static ssize_t dp_aux_transfer(struct drm_dp_aux *drm_aux,
|
||||
struct drm_dp_aux_msg *msg)
|
||||
{
|
||||
ssize_t ret;
|
||||
int const retry_count = 5;
|
||||
struct dp_aux_private *aux = container_of(drm_aux,
|
||||
struct dp_aux_private, drm_aux);
|
||||
|
||||
mutex_lock(&aux->mutex);
|
||||
|
||||
ret = dp_aux_transfer_ready(aux, msg, true);
|
||||
if (ret)
|
||||
goto unlock_exit;
|
||||
|
||||
if (!aux->cmd_busy) {
|
||||
ret = msg->size;
|
||||
goto unlock_exit;
|
||||
}
|
||||
|
||||
ret = dp_aux_cmd_fifo_tx(aux, msg);
|
||||
if ((ret < 0) && !atomic_read(&aux->aborted)) {
|
||||
aux->retry_cnt++;
|
||||
if (!(aux->retry_cnt % retry_count))
|
||||
aux->catalog->update_aux_cfg(aux->catalog,
|
||||
aux->cfg, PHY_AUX_CFG1);
|
||||
aux->catalog->reset(aux->catalog);
|
||||
goto unlock_exit;
|
||||
} else if (ret < 0) {
|
||||
goto unlock_exit;
|
||||
}
|
||||
|
||||
if (aux->aux_error_num == DP_AUX_ERR_NONE) {
|
||||
if (aux->read)
|
||||
dp_aux_cmd_fifo_rx(aux, msg);
|
||||
|
||||
dp_aux_hex_dump(drm_aux, msg);
|
||||
|
||||
msg->reply = aux->native ?
|
||||
DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK;
|
||||
} else {
|
||||
/* Reply defer to retry */
|
||||
msg->reply = aux->native ?
|
||||
DP_AUX_NATIVE_REPLY_DEFER : DP_AUX_I2C_REPLY_DEFER;
|
||||
}
|
||||
|
||||
/* Return requested size for success or retry */
|
||||
ret = msg->size;
|
||||
aux->retry_cnt = 0;
|
||||
|
||||
unlock_exit:
|
||||
aux->cmd_busy = false;
|
||||
mutex_unlock(&aux->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void dp_aux_reset_phy_config_indices(struct dp_aux_cfg *aux_cfg)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < PHY_AUX_CFG_MAX; i++)
|
||||
aux_cfg[i].current_index = 0;
|
||||
}
|
||||
|
||||
static void dp_aux_init(struct dp_aux *dp_aux, struct dp_aux_cfg *aux_cfg)
|
||||
{
|
||||
struct dp_aux_private *aux;
|
||||
|
||||
if (!dp_aux || !aux_cfg) {
|
||||
DP_ERR("invalid input\n");
|
||||
return;
|
||||
}
|
||||
|
||||
aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
|
||||
|
||||
if (aux->enabled)
|
||||
return;
|
||||
|
||||
dp_aux_reset_phy_config_indices(aux_cfg);
|
||||
aux->catalog->setup(aux->catalog, aux_cfg);
|
||||
aux->catalog->reset(aux->catalog);
|
||||
aux->catalog->enable(aux->catalog, true);
|
||||
atomic_set(&aux->aborted, 0);
|
||||
aux->retry_cnt = 0;
|
||||
aux->enabled = true;
|
||||
}
|
||||
|
||||
static void dp_aux_deinit(struct dp_aux *dp_aux)
|
||||
{
|
||||
struct dp_aux_private *aux;
|
||||
|
||||
if (!dp_aux) {
|
||||
DP_ERR("invalid input\n");
|
||||
return;
|
||||
}
|
||||
|
||||
aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
|
||||
|
||||
if (!aux->enabled)
|
||||
return;
|
||||
|
||||
atomic_set(&aux->aborted, 1);
|
||||
aux->catalog->enable(aux->catalog, false);
|
||||
aux->enabled = false;
|
||||
}
|
||||
|
||||
static int dp_aux_register(struct dp_aux *dp_aux)
|
||||
{
|
||||
struct dp_aux_private *aux;
|
||||
int ret = 0;
|
||||
|
||||
if (!dp_aux) {
|
||||
DP_ERR("invalid input\n");
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
|
||||
|
||||
aux->drm_aux.name = "sde_dp_aux";
|
||||
aux->drm_aux.dev = aux->dev;
|
||||
aux->drm_aux.transfer = dp_aux_transfer;
|
||||
atomic_set(&aux->aborted, 1);
|
||||
ret = drm_dp_aux_register(&aux->drm_aux);
|
||||
if (ret) {
|
||||
DP_ERR("%s: failed to register drm aux: %d\n", __func__, ret);
|
||||
goto exit;
|
||||
}
|
||||
dp_aux->drm_aux = &aux->drm_aux;
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void dp_aux_deregister(struct dp_aux *dp_aux)
|
||||
{
|
||||
struct dp_aux_private *aux;
|
||||
|
||||
if (!dp_aux) {
|
||||
DP_ERR("invalid input\n");
|
||||
return;
|
||||
}
|
||||
|
||||
aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
|
||||
drm_dp_aux_unregister(&aux->drm_aux);
|
||||
}
|
||||
|
||||
static void dp_aux_dpcd_updated(struct dp_aux *dp_aux)
|
||||
{
|
||||
struct dp_aux_private *aux;
|
||||
|
||||
if (!dp_aux) {
|
||||
DP_ERR("invalid input\n");
|
||||
return;
|
||||
}
|
||||
|
||||
aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
|
||||
|
||||
/* make sure wait has started */
|
||||
usleep_range(20, 30);
|
||||
complete(&aux->comp);
|
||||
}
|
||||
|
||||
static void dp_aux_set_sim_mode(struct dp_aux *dp_aux, bool en,
|
||||
u8 *edid, u8 *dpcd)
|
||||
{
|
||||
struct dp_aux_private *aux;
|
||||
|
||||
if (!dp_aux) {
|
||||
DP_ERR("invalid input\n");
|
||||
return;
|
||||
}
|
||||
|
||||
aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
|
||||
|
||||
mutex_lock(&aux->mutex);
|
||||
|
||||
aux->edid = edid;
|
||||
aux->dpcd = dpcd;
|
||||
|
||||
if (en) {
|
||||
atomic_set(&aux->aborted, 0);
|
||||
aux->drm_aux.transfer = dp_aux_transfer_debug;
|
||||
} else {
|
||||
aux->drm_aux.transfer = dp_aux_transfer;
|
||||
}
|
||||
|
||||
mutex_unlock(&aux->mutex);
|
||||
}
|
||||
|
||||
static int dp_aux_configure_aux_switch(struct dp_aux *dp_aux,
|
||||
bool enable, int orientation)
|
||||
{
|
||||
struct dp_aux_private *aux;
|
||||
int rc = 0;
|
||||
enum fsa_function event = FSA_USBC_DISPLAYPORT_DISCONNECTED;
|
||||
|
||||
if (!dp_aux) {
|
||||
DP_ERR("invalid input\n");
|
||||
rc = -EINVAL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
|
||||
|
||||
if (!aux->aux_switch_node) {
|
||||
DP_DEBUG("undefined fsa4480 handle\n");
|
||||
rc = -EINVAL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (enable) {
|
||||
switch (orientation) {
|
||||
case ORIENTATION_CC1:
|
||||
event = FSA_USBC_ORIENTATION_CC1;
|
||||
break;
|
||||
case ORIENTATION_CC2:
|
||||
event = FSA_USBC_ORIENTATION_CC2;
|
||||
break;
|
||||
default:
|
||||
DP_ERR("invalid orientation\n");
|
||||
rc = -EINVAL;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
DP_DEBUG("enable=%d, orientation=%d, event=%d\n",
|
||||
enable, orientation, event);
|
||||
|
||||
rc = fsa4480_switch_event(aux->aux_switch_node, event);
|
||||
if (rc)
|
||||
DP_ERR("failed to configure fsa4480 i2c device (%d)\n", rc);
|
||||
end:
|
||||
return rc;
|
||||
}
|
||||
|
||||
struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog,
|
||||
struct dp_parser *parser, struct device_node *aux_switch)
|
||||
{
|
||||
int rc = 0;
|
||||
struct dp_aux_private *aux;
|
||||
struct dp_aux *dp_aux;
|
||||
|
||||
if (!catalog || !parser ||
|
||||
(!parser->no_aux_switch &&
|
||||
!aux_switch &&
|
||||
!parser->gpio_aux_switch)) {
|
||||
DP_ERR("invalid input\n");
|
||||
rc = -ENODEV;
|
||||
goto error;
|
||||
}
|
||||
|
||||
aux = devm_kzalloc(dev, sizeof(*aux), GFP_KERNEL);
|
||||
if (!aux) {
|
||||
rc = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
init_completion(&aux->comp);
|
||||
aux->cmd_busy = false;
|
||||
mutex_init(&aux->mutex);
|
||||
|
||||
aux->dev = dev;
|
||||
aux->catalog = catalog;
|
||||
aux->cfg = parser->aux_cfg;
|
||||
aux->aux_switch_node = aux_switch;
|
||||
dp_aux = &aux->dp_aux;
|
||||
aux->retry_cnt = 0;
|
||||
aux->dp_aux.reg = 0xFFFF;
|
||||
|
||||
dp_aux->isr = dp_aux_isr;
|
||||
dp_aux->init = dp_aux_init;
|
||||
dp_aux->deinit = dp_aux_deinit;
|
||||
dp_aux->drm_aux_register = dp_aux_register;
|
||||
dp_aux->drm_aux_deregister = dp_aux_deregister;
|
||||
dp_aux->reconfig = dp_aux_reconfig;
|
||||
dp_aux->abort = dp_aux_abort_transaction;
|
||||
dp_aux->dpcd_updated = dp_aux_dpcd_updated;
|
||||
dp_aux->set_sim_mode = dp_aux_set_sim_mode;
|
||||
dp_aux->aux_switch = dp_aux_configure_aux_switch;
|
||||
|
||||
return dp_aux;
|
||||
error:
|
||||
return ERR_PTR(rc);
|
||||
}
|
||||
|
||||
void dp_aux_put(struct dp_aux *dp_aux)
|
||||
{
|
||||
struct dp_aux_private *aux;
|
||||
|
||||
if (!dp_aux)
|
||||
return;
|
||||
|
||||
aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
|
||||
|
||||
mutex_destroy(&aux->mutex);
|
||||
|
||||
devm_kfree(aux->dev, aux);
|
||||
}
|
63
techpack/display/msm/dp/dp_aux.h
Normal file
63
techpack/display/msm/dp/dp_aux.h
Normal file
@ -0,0 +1,63 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _DP_AUX_H_
|
||||
#define _DP_AUX_H_
|
||||
|
||||
#include "dp_catalog.h"
|
||||
#include "drm_dp_helper.h"
|
||||
|
||||
#define DP_STATE_NOTIFICATION_SENT BIT(0)
|
||||
#define DP_STATE_TRAIN_1_STARTED BIT(1)
|
||||
#define DP_STATE_TRAIN_1_SUCCEEDED BIT(2)
|
||||
#define DP_STATE_TRAIN_1_FAILED BIT(3)
|
||||
#define DP_STATE_TRAIN_2_STARTED BIT(4)
|
||||
#define DP_STATE_TRAIN_2_SUCCEEDED BIT(5)
|
||||
#define DP_STATE_TRAIN_2_FAILED BIT(6)
|
||||
#define DP_STATE_CTRL_POWERED_ON BIT(7)
|
||||
#define DP_STATE_CTRL_POWERED_OFF BIT(8)
|
||||
#define DP_STATE_LINK_MAINTENANCE_STARTED BIT(9)
|
||||
#define DP_STATE_LINK_MAINTENANCE_COMPLETED BIT(10)
|
||||
#define DP_STATE_LINK_MAINTENANCE_FAILED BIT(11)
|
||||
#define DP_STATE_AUX_TIMEOUT BIT(12)
|
||||
#define DP_STATE_PLL_LOCKED BIT(13)
|
||||
|
||||
enum dp_aux_error {
|
||||
DP_AUX_ERR_NONE = 0,
|
||||
DP_AUX_ERR_ADDR = -1,
|
||||
DP_AUX_ERR_TOUT = -2,
|
||||
DP_AUX_ERR_NACK = -3,
|
||||
DP_AUX_ERR_DEFER = -4,
|
||||
DP_AUX_ERR_NACK_DEFER = -5,
|
||||
DP_AUX_ERR_PHY = -6,
|
||||
};
|
||||
|
||||
struct dp_aux {
|
||||
u32 reg;
|
||||
u32 size;
|
||||
u32 state;
|
||||
|
||||
bool read;
|
||||
|
||||
struct mutex *access_lock;
|
||||
|
||||
struct drm_dp_aux *drm_aux;
|
||||
int (*drm_aux_register)(struct dp_aux *aux);
|
||||
void (*drm_aux_deregister)(struct dp_aux *aux);
|
||||
void (*isr)(struct dp_aux *aux);
|
||||
void (*init)(struct dp_aux *aux, struct dp_aux_cfg *aux_cfg);
|
||||
void (*deinit)(struct dp_aux *aux);
|
||||
void (*reconfig)(struct dp_aux *aux);
|
||||
void (*abort)(struct dp_aux *aux, bool abort);
|
||||
void (*dpcd_updated)(struct dp_aux *aux);
|
||||
void (*set_sim_mode)(struct dp_aux *aux, bool en, u8 *edid, u8 *dpcd);
|
||||
int (*aux_switch)(struct dp_aux *aux, bool enable, int orientation);
|
||||
};
|
||||
|
||||
struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog,
|
||||
struct dp_parser *parser, struct device_node *aux_switch);
|
||||
void dp_aux_put(struct dp_aux *aux);
|
||||
|
||||
#endif /*__DP_AUX_H_*/
|
2903
techpack/display/msm/dp/dp_catalog.c
Normal file
2903
techpack/display/msm/dp/dp_catalog.c
Normal file
File diff suppressed because it is too large
Load Diff
339
techpack/display/msm/dp/dp_catalog.h
Normal file
339
techpack/display/msm/dp/dp_catalog.h
Normal file
@ -0,0 +1,339 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _DP_CATALOG_H_
|
||||
#define _DP_CATALOG_H_
|
||||
|
||||
#include <drm/drm_dp_helper.h>
|
||||
#include <drm/sde_drm.h>
|
||||
|
||||
#include "dp_parser.h"
|
||||
|
||||
/* interrupts */
|
||||
#define DP_INTR_HPD BIT(0)
|
||||
#define DP_INTR_AUX_I2C_DONE BIT(3)
|
||||
#define DP_INTR_WRONG_ADDR BIT(6)
|
||||
#define DP_INTR_TIMEOUT BIT(9)
|
||||
#define DP_INTR_NACK_DEFER BIT(12)
|
||||
#define DP_INTR_WRONG_DATA_CNT BIT(15)
|
||||
#define DP_INTR_I2C_NACK BIT(18)
|
||||
#define DP_INTR_I2C_DEFER BIT(21)
|
||||
#define DP_INTR_PLL_UNLOCKED BIT(24)
|
||||
#define DP_INTR_AUX_ERROR BIT(27)
|
||||
|
||||
#define DP_INTR_READY_FOR_VIDEO BIT(0)
|
||||
#define DP_INTR_IDLE_PATTERN_SENT BIT(3)
|
||||
#define DP_INTR_FRAME_END BIT(6)
|
||||
#define DP_INTR_CRC_UPDATED BIT(9)
|
||||
|
||||
#define DP_INTR_MST_DP0_VCPF_SENT BIT(0)
|
||||
#define DP_INTR_MST_DP1_VCPF_SENT BIT(3)
|
||||
|
||||
#define DP_MAX_TIME_SLOTS 64
|
||||
|
||||
/* stream id */
|
||||
enum dp_stream_id {
|
||||
DP_STREAM_0,
|
||||
DP_STREAM_1,
|
||||
DP_STREAM_MAX,
|
||||
};
|
||||
|
||||
struct dp_catalog_vsc_sdp_colorimetry {
|
||||
struct dp_sdp_header header;
|
||||
u8 data[32];
|
||||
};
|
||||
|
||||
struct dp_catalog_aux {
|
||||
u32 data;
|
||||
u32 isr;
|
||||
|
||||
u32 (*read_data)(struct dp_catalog_aux *aux);
|
||||
int (*write_data)(struct dp_catalog_aux *aux);
|
||||
int (*write_trans)(struct dp_catalog_aux *aux);
|
||||
int (*clear_trans)(struct dp_catalog_aux *aux, bool read);
|
||||
void (*reset)(struct dp_catalog_aux *aux);
|
||||
void (*enable)(struct dp_catalog_aux *aux, bool enable);
|
||||
void (*update_aux_cfg)(struct dp_catalog_aux *aux,
|
||||
struct dp_aux_cfg *cfg, enum dp_phy_aux_config_type type);
|
||||
void (*setup)(struct dp_catalog_aux *aux,
|
||||
struct dp_aux_cfg *aux_cfg);
|
||||
void (*get_irq)(struct dp_catalog_aux *aux, bool cmd_busy);
|
||||
void (*clear_hw_interrupts)(struct dp_catalog_aux *aux);
|
||||
};
|
||||
|
||||
struct dp_catalog_ctrl {
|
||||
u32 isr;
|
||||
u32 isr5;
|
||||
|
||||
void (*state_ctrl)(struct dp_catalog_ctrl *ctrl, u32 state);
|
||||
void (*config_ctrl)(struct dp_catalog_ctrl *ctrl, u8 ln_cnt);
|
||||
void (*lane_mapping)(struct dp_catalog_ctrl *ctrl, bool flipped,
|
||||
char *lane_map);
|
||||
void (*lane_pnswap)(struct dp_catalog_ctrl *ctrl, u8 ln_pnswap);
|
||||
void (*mainlink_ctrl)(struct dp_catalog_ctrl *ctrl, bool enable);
|
||||
void (*set_pattern)(struct dp_catalog_ctrl *ctrl, u32 pattern);
|
||||
void (*reset)(struct dp_catalog_ctrl *ctrl);
|
||||
void (*usb_reset)(struct dp_catalog_ctrl *ctrl, bool flip);
|
||||
bool (*mainlink_ready)(struct dp_catalog_ctrl *ctrl);
|
||||
void (*enable_irq)(struct dp_catalog_ctrl *ctrl, bool enable);
|
||||
void (*phy_reset)(struct dp_catalog_ctrl *ctrl);
|
||||
void (*phy_lane_cfg)(struct dp_catalog_ctrl *ctrl, bool flipped,
|
||||
u8 lane_cnt);
|
||||
void (*update_vx_px)(struct dp_catalog_ctrl *ctrl, u8 v_level,
|
||||
u8 p_level, bool high);
|
||||
void (*get_interrupt)(struct dp_catalog_ctrl *ctrl);
|
||||
u32 (*read_hdcp_status)(struct dp_catalog_ctrl *ctrl);
|
||||
void (*send_phy_pattern)(struct dp_catalog_ctrl *ctrl,
|
||||
u32 pattern);
|
||||
u32 (*read_phy_pattern)(struct dp_catalog_ctrl *ctrl);
|
||||
void (*mst_config)(struct dp_catalog_ctrl *ctrl, bool enable);
|
||||
void (*trigger_act)(struct dp_catalog_ctrl *ctrl);
|
||||
void (*read_act_complete_sts)(struct dp_catalog_ctrl *ctrl, bool *sts);
|
||||
void (*channel_alloc)(struct dp_catalog_ctrl *ctrl,
|
||||
u32 ch, u32 ch_start_timeslot, u32 tot_ch_cnt);
|
||||
void (*update_rg)(struct dp_catalog_ctrl *ctrl, u32 ch, u32 x_int,
|
||||
u32 y_frac_enum);
|
||||
void (*channel_dealloc)(struct dp_catalog_ctrl *ctrl,
|
||||
u32 ch, u32 ch_start_timeslot, u32 tot_ch_cnt);
|
||||
void (*fec_config)(struct dp_catalog_ctrl *ctrl, bool enable);
|
||||
void (*mainlink_levels)(struct dp_catalog_ctrl *ctrl, u8 lane_cnt);
|
||||
|
||||
int (*late_phy_init)(struct dp_catalog_ctrl *ctrl,
|
||||
u8 lane_cnt, bool flipped);
|
||||
};
|
||||
|
||||
struct dp_catalog_hpd {
|
||||
void (*config_hpd)(struct dp_catalog_hpd *hpd, bool en);
|
||||
u32 (*get_interrupt)(struct dp_catalog_hpd *hpd);
|
||||
};
|
||||
|
||||
#define HEADER_BYTE_2_BIT 0
|
||||
#define PARITY_BYTE_2_BIT 8
|
||||
#define HEADER_BYTE_1_BIT 16
|
||||
#define PARITY_BYTE_1_BIT 24
|
||||
#define HEADER_BYTE_3_BIT 16
|
||||
#define PARITY_BYTE_3_BIT 24
|
||||
|
||||
enum dp_catalog_audio_sdp_type {
|
||||
DP_AUDIO_SDP_STREAM,
|
||||
DP_AUDIO_SDP_TIMESTAMP,
|
||||
DP_AUDIO_SDP_INFOFRAME,
|
||||
DP_AUDIO_SDP_COPYMANAGEMENT,
|
||||
DP_AUDIO_SDP_ISRC,
|
||||
DP_AUDIO_SDP_MAX,
|
||||
};
|
||||
|
||||
enum dp_catalog_audio_header_type {
|
||||
DP_AUDIO_SDP_HEADER_1,
|
||||
DP_AUDIO_SDP_HEADER_2,
|
||||
DP_AUDIO_SDP_HEADER_3,
|
||||
DP_AUDIO_SDP_HEADER_MAX,
|
||||
};
|
||||
|
||||
struct dp_catalog_audio {
|
||||
enum dp_catalog_audio_sdp_type sdp_type;
|
||||
enum dp_catalog_audio_header_type sdp_header;
|
||||
u32 data;
|
||||
|
||||
enum dp_stream_id stream_id;
|
||||
|
||||
void (*init)(struct dp_catalog_audio *audio);
|
||||
void (*enable)(struct dp_catalog_audio *audio);
|
||||
void (*config_acr)(struct dp_catalog_audio *audio);
|
||||
void (*config_sdp)(struct dp_catalog_audio *audio);
|
||||
void (*set_header)(struct dp_catalog_audio *audio);
|
||||
void (*get_header)(struct dp_catalog_audio *audio);
|
||||
};
|
||||
|
||||
struct dp_dsc_cfg_data {
|
||||
bool dsc_en;
|
||||
bool continuous_pps;
|
||||
char pps[128];
|
||||
u32 pps_len;
|
||||
u32 pps_word[32];
|
||||
u32 pps_word_len;
|
||||
u8 parity[32];
|
||||
u8 parity_len;
|
||||
u32 parity_word[8];
|
||||
u32 parity_word_len;
|
||||
u32 slice_per_pkt;
|
||||
u32 bytes_per_pkt;
|
||||
u32 eol_byte_num;
|
||||
u32 be_in_lane;
|
||||
u32 dto_en;
|
||||
u32 dto_n;
|
||||
u32 dto_d;
|
||||
u32 dto_count;
|
||||
};
|
||||
|
||||
struct dp_catalog_panel {
|
||||
u32 total;
|
||||
u32 sync_start;
|
||||
u32 width_blanking;
|
||||
u32 dp_active;
|
||||
u8 *spd_vendor_name;
|
||||
u8 *spd_product_description;
|
||||
|
||||
struct dp_catalog_vsc_sdp_colorimetry vsc_colorimetry;
|
||||
struct dp_sdp_header dhdr_vsif_sdp;
|
||||
struct dp_sdp_header shdr_if_sdp;
|
||||
struct drm_msm_ext_hdr_metadata hdr_meta;
|
||||
|
||||
/* TPG */
|
||||
u32 hsync_period;
|
||||
u32 vsync_period;
|
||||
u32 display_v_start;
|
||||
u32 display_v_end;
|
||||
u32 v_sync_width;
|
||||
u32 hsync_ctl;
|
||||
u32 display_hctl;
|
||||
|
||||
/* TU */
|
||||
u32 dp_tu;
|
||||
u32 valid_boundary;
|
||||
u32 valid_boundary2;
|
||||
|
||||
u32 misc_val;
|
||||
|
||||
enum dp_stream_id stream_id;
|
||||
|
||||
bool widebus_en;
|
||||
struct dp_dsc_cfg_data dsc;
|
||||
|
||||
int (*timing_cfg)(struct dp_catalog_panel *panel);
|
||||
void (*config_hdr)(struct dp_catalog_panel *panel, bool en,
|
||||
u32 dhdr_max_pkts, bool flush);
|
||||
void (*config_sdp)(struct dp_catalog_panel *panel, bool en);
|
||||
int (*set_colorspace)(struct dp_catalog_panel *panel,
|
||||
bool vsc_supported);
|
||||
void (*tpg_config)(struct dp_catalog_panel *panel, bool enable);
|
||||
void (*config_spd)(struct dp_catalog_panel *panel);
|
||||
void (*config_misc)(struct dp_catalog_panel *panel);
|
||||
void (*config_msa)(struct dp_catalog_panel *panel,
|
||||
u32 rate, u32 stream_rate_khz);
|
||||
void (*update_transfer_unit)(struct dp_catalog_panel *panel);
|
||||
void (*config_ctrl)(struct dp_catalog_panel *panel, u32 cfg);
|
||||
void (*config_dto)(struct dp_catalog_panel *panel, bool ack);
|
||||
void (*dsc_cfg)(struct dp_catalog_panel *panel);
|
||||
void (*pps_flush)(struct dp_catalog_panel *panel);
|
||||
void (*dhdr_flush)(struct dp_catalog_panel *panel);
|
||||
bool (*dhdr_busy)(struct dp_catalog_panel *panel);
|
||||
};
|
||||
|
||||
struct dp_catalog;
|
||||
struct dp_catalog_sub {
|
||||
u32 (*read)(struct dp_catalog *dp_catalog,
|
||||
struct dp_io_data *io_data, u32 offset);
|
||||
void (*write)(struct dp_catalog *dp_catalog,
|
||||
struct dp_io_data *io_data, u32 offset, u32 data);
|
||||
|
||||
void (*put)(struct dp_catalog *catalog);
|
||||
};
|
||||
|
||||
struct dp_catalog_io {
|
||||
struct dp_io_data *dp_ahb;
|
||||
struct dp_io_data *dp_aux;
|
||||
struct dp_io_data *dp_link;
|
||||
struct dp_io_data *dp_p0;
|
||||
struct dp_io_data *dp_phy;
|
||||
struct dp_io_data *dp_ln_tx0;
|
||||
struct dp_io_data *dp_ln_tx1;
|
||||
struct dp_io_data *dp_mmss_cc;
|
||||
struct dp_io_data *dp_pll;
|
||||
struct dp_io_data *usb3_dp_com;
|
||||
struct dp_io_data *hdcp_physical;
|
||||
struct dp_io_data *dp_p1;
|
||||
struct dp_io_data *dp_tcsr;
|
||||
};
|
||||
|
||||
struct dp_catalog {
|
||||
struct dp_catalog_aux aux;
|
||||
struct dp_catalog_ctrl ctrl;
|
||||
struct dp_catalog_audio audio;
|
||||
struct dp_catalog_panel panel;
|
||||
struct dp_catalog_hpd hpd;
|
||||
|
||||
struct dp_catalog_sub *sub;
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
static inline u8 dp_ecc_get_g0_value(u8 data)
|
||||
{
|
||||
u8 c[4];
|
||||
u8 g[4];
|
||||
u8 ret_data = 0;
|
||||
u8 i;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
c[i] = (data >> i) & 0x01;
|
||||
|
||||
g[0] = c[3];
|
||||
g[1] = c[0] ^ c[3];
|
||||
g[2] = c[1];
|
||||
g[3] = c[2];
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
ret_data = ((g[i] & 0x01) << i) | ret_data;
|
||||
|
||||
return ret_data;
|
||||
}
|
||||
|
||||
static inline u8 dp_ecc_get_g1_value(u8 data)
|
||||
{
|
||||
u8 c[4];
|
||||
u8 g[4];
|
||||
u8 ret_data = 0;
|
||||
u8 i;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
c[i] = (data >> i) & 0x01;
|
||||
|
||||
g[0] = c[0] ^ c[3];
|
||||
g[1] = c[0] ^ c[1] ^ c[3];
|
||||
g[2] = c[1] ^ c[2];
|
||||
g[3] = c[2] ^ c[3];
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
ret_data = ((g[i] & 0x01) << i) | ret_data;
|
||||
|
||||
return ret_data;
|
||||
}
|
||||
|
||||
static inline u8 dp_header_get_parity(u32 data)
|
||||
{
|
||||
u8 x0 = 0;
|
||||
u8 x1 = 0;
|
||||
u8 ci = 0;
|
||||
u8 iData = 0;
|
||||
u8 i = 0;
|
||||
u8 parity_byte;
|
||||
u8 num_byte = (data > 0xFF) ? 8 : 2;
|
||||
|
||||
for (i = 0; i < num_byte; i++) {
|
||||
iData = (data >> i*4) & 0xF;
|
||||
|
||||
ci = iData ^ x1;
|
||||
x1 = x0 ^ dp_ecc_get_g1_value(ci);
|
||||
x0 = dp_ecc_get_g0_value(ci);
|
||||
}
|
||||
|
||||
parity_byte = x1 | (x0 << 4);
|
||||
|
||||
return parity_byte;
|
||||
}
|
||||
|
||||
struct dp_catalog *dp_catalog_get(struct device *dev, struct dp_parser *parser);
|
||||
void dp_catalog_put(struct dp_catalog *catalog);
|
||||
|
||||
struct dp_catalog_sub *dp_catalog_get_v420(struct device *dev,
|
||||
struct dp_catalog *catalog, struct dp_catalog_io *io);
|
||||
|
||||
struct dp_catalog_sub *dp_catalog_get_v200(struct device *dev,
|
||||
struct dp_catalog *catalog, struct dp_catalog_io *io);
|
||||
|
||||
#endif /* _DP_CATALOG_H_ */
|
272
techpack/display/msm/dp/dp_catalog_v200.c
Normal file
272
techpack/display/msm/dp/dp_catalog_v200.c
Normal file
@ -0,0 +1,272 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "dp_catalog.h"
|
||||
#include "dp_reg.h"
|
||||
#include "dp_debug.h"
|
||||
|
||||
#define dp_catalog_get_priv_v200(x) ({ \
|
||||
struct dp_catalog *catalog; \
|
||||
catalog = container_of(x, struct dp_catalog, x); \
|
||||
container_of(catalog->sub, \
|
||||
struct dp_catalog_private_v200, sub); \
|
||||
})
|
||||
|
||||
#define dp_read(x) ({ \
|
||||
catalog->sub.read(catalog->dpc, io_data, x); \
|
||||
})
|
||||
|
||||
#define dp_write(x, y) ({ \
|
||||
catalog->sub.write(catalog->dpc, io_data, x, y); \
|
||||
})
|
||||
|
||||
struct dp_catalog_private_v200 {
|
||||
struct device *dev;
|
||||
struct dp_catalog_io *io;
|
||||
struct dp_catalog *dpc;
|
||||
struct dp_catalog_sub sub;
|
||||
};
|
||||
|
||||
static void dp_catalog_aux_clear_hw_int_v200(struct dp_catalog_aux *aux)
|
||||
{
|
||||
struct dp_catalog_private_v200 *catalog;
|
||||
struct dp_io_data *io_data;
|
||||
u32 data = 0;
|
||||
|
||||
if (!aux) {
|
||||
DP_ERR("invalid input\n");
|
||||
return;
|
||||
}
|
||||
|
||||
catalog = dp_catalog_get_priv_v200(aux);
|
||||
io_data = catalog->io->dp_phy;
|
||||
|
||||
data = dp_read(DP_PHY_AUX_INTERRUPT_STATUS_V200);
|
||||
|
||||
dp_write(DP_PHY_AUX_INTERRUPT_CLEAR_V200, 0x1f);
|
||||
wmb(); /* make sure 0x1f is written before next write */
|
||||
|
||||
dp_write(DP_PHY_AUX_INTERRUPT_CLEAR_V200, 0x9f);
|
||||
wmb(); /* make sure 0x9f is written before next write */
|
||||
|
||||
dp_write(DP_PHY_AUX_INTERRUPT_CLEAR_V200, 0);
|
||||
wmb(); /* make sure register is cleared */
|
||||
}
|
||||
|
||||
static void dp_catalog_aux_setup_v200(struct dp_catalog_aux *aux,
|
||||
struct dp_aux_cfg *cfg)
|
||||
{
|
||||
struct dp_catalog_private_v200 *catalog;
|
||||
struct dp_io_data *io_data;
|
||||
int i = 0, sw_reset = 0;
|
||||
|
||||
if (!aux || !cfg) {
|
||||
DP_ERR("invalid input\n");
|
||||
return;
|
||||
}
|
||||
|
||||
catalog = dp_catalog_get_priv_v200(aux);
|
||||
io_data = catalog->io->dp_ahb;
|
||||
|
||||
sw_reset = dp_read(DP_SW_RESET);
|
||||
|
||||
sw_reset |= BIT(0);
|
||||
dp_write(DP_SW_RESET, sw_reset);
|
||||
usleep_range(1000, 1010); /* h/w recommended delay */
|
||||
|
||||
sw_reset &= ~BIT(0);
|
||||
dp_write(DP_SW_RESET, sw_reset);
|
||||
|
||||
dp_write(DP_PHY_CTRL, 0x4); /* bit 2 */
|
||||
udelay(1000);
|
||||
dp_write(DP_PHY_CTRL, 0x0); /* bit 2 */
|
||||
wmb(); /* make sure programming happened */
|
||||
|
||||
io_data = catalog->io->dp_tcsr;
|
||||
dp_write(0x4c, 0x1); /* bit 0 & 2 */
|
||||
wmb(); /* make sure programming happened */
|
||||
|
||||
io_data = catalog->io->dp_phy;
|
||||
dp_write(DP_PHY_PD_CTL, 0x3c);
|
||||
wmb(); /* make sure PD programming happened */
|
||||
dp_write(DP_PHY_PD_CTL, 0x3d);
|
||||
wmb(); /* make sure PD programming happened */
|
||||
|
||||
/* DP AUX CFG register programming */
|
||||
io_data = catalog->io->dp_phy;
|
||||
for (i = 0; i < PHY_AUX_CFG_MAX; i++)
|
||||
dp_write(cfg[i].offset, cfg[i].lut[cfg[i].current_index]);
|
||||
|
||||
dp_write(DP_PHY_AUX_INTERRUPT_MASK_V200, 0x1F);
|
||||
wmb(); /* make sure AUX configuration is done before enabling it */
|
||||
}
|
||||
|
||||
static void dp_catalog_panel_config_msa_v200(struct dp_catalog_panel *panel,
|
||||
u32 rate, u32 stream_rate_khz)
|
||||
{
|
||||
u32 pixel_m, pixel_n;
|
||||
u32 mvid, nvid;
|
||||
u32 const nvid_fixed = 0x8000;
|
||||
u32 const link_rate_hbr2 = 540000;
|
||||
u32 const link_rate_hbr3 = 810000;
|
||||
struct dp_catalog_private_v200 *catalog;
|
||||
struct dp_io_data *io_data;
|
||||
u32 strm_reg_off = 0;
|
||||
u32 mvid_reg_off = 0, nvid_reg_off = 0;
|
||||
|
||||
if (!panel) {
|
||||
DP_ERR("invalid input\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (panel->stream_id >= DP_STREAM_MAX) {
|
||||
DP_ERR("invalid stream_id:%d\n", panel->stream_id);
|
||||
return;
|
||||
}
|
||||
|
||||
catalog = dp_catalog_get_priv_v200(panel);
|
||||
io_data = catalog->io->dp_mmss_cc;
|
||||
|
||||
if (panel->stream_id == DP_STREAM_1)
|
||||
strm_reg_off = MMSS_DP_PIXEL1_M_V200 -
|
||||
MMSS_DP_PIXEL_M_V200;
|
||||
|
||||
pixel_m = dp_read(MMSS_DP_PIXEL_M_V200 + strm_reg_off);
|
||||
pixel_n = dp_read(MMSS_DP_PIXEL_N_V200 + strm_reg_off);
|
||||
DP_DEBUG("pixel_m=0x%x, pixel_n=0x%x\n", pixel_m, pixel_n);
|
||||
|
||||
mvid = (pixel_m & 0xFFFF) * 5;
|
||||
nvid = (0xFFFF & (~pixel_n)) + (pixel_m & 0xFFFF);
|
||||
|
||||
if (nvid < nvid_fixed) {
|
||||
u32 temp;
|
||||
|
||||
temp = (nvid_fixed / nvid) * nvid;
|
||||
mvid = (nvid_fixed / nvid) * mvid;
|
||||
nvid = temp;
|
||||
}
|
||||
|
||||
DP_DEBUG("rate = %d\n", rate);
|
||||
|
||||
if (panel->widebus_en)
|
||||
mvid <<= 1;
|
||||
|
||||
if (link_rate_hbr2 == rate)
|
||||
nvid *= 2;
|
||||
|
||||
if (link_rate_hbr3 == rate)
|
||||
nvid *= 3;
|
||||
|
||||
io_data = catalog->io->dp_link;
|
||||
|
||||
if (panel->stream_id == DP_STREAM_1) {
|
||||
mvid_reg_off = DP1_SOFTWARE_MVID - DP_SOFTWARE_MVID;
|
||||
nvid_reg_off = DP1_SOFTWARE_NVID - DP_SOFTWARE_NVID;
|
||||
}
|
||||
|
||||
DP_DEBUG("mvid=0x%x, nvid=0x%x\n", mvid, nvid);
|
||||
dp_write(DP_SOFTWARE_MVID + mvid_reg_off, mvid);
|
||||
dp_write(DP_SOFTWARE_NVID + nvid_reg_off, nvid);
|
||||
}
|
||||
|
||||
static void dp_catalog_ctrl_lane_mapping_v200(struct dp_catalog_ctrl *ctrl,
|
||||
bool flipped, char *lane_map)
|
||||
{
|
||||
struct dp_catalog_private_v200 *catalog;
|
||||
struct dp_io_data *io_data;
|
||||
u8 l_map[4] = { 0 }, i = 0, j = 0;
|
||||
u32 lane_map_reg = 0;
|
||||
|
||||
if (!ctrl) {
|
||||
DP_ERR("invalid input\n");
|
||||
return;
|
||||
}
|
||||
|
||||
catalog = dp_catalog_get_priv_v200(ctrl);
|
||||
io_data = catalog->io->dp_link;
|
||||
|
||||
/* For flip case, swap phy lanes with ML0 and ML3, ML1 and ML2 */
|
||||
if (flipped) {
|
||||
for (i = 0; i < DP_MAX_PHY_LN; i++) {
|
||||
if (lane_map[i] == DP_ML0) {
|
||||
for (j = 0; j < DP_MAX_PHY_LN; j++) {
|
||||
if (lane_map[j] == DP_ML3) {
|
||||
l_map[i] = DP_ML3;
|
||||
l_map[j] = DP_ML0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (lane_map[i] == DP_ML1) {
|
||||
for (j = 0; j < DP_MAX_PHY_LN; j++) {
|
||||
if (lane_map[j] == DP_ML2) {
|
||||
l_map[i] = DP_ML2;
|
||||
l_map[j] = DP_ML1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Normal orientation */
|
||||
for (i = 0; i < DP_MAX_PHY_LN; i++)
|
||||
l_map[i] = lane_map[i];
|
||||
}
|
||||
|
||||
lane_map_reg = ((l_map[3]&3)<<6)|((l_map[2]&3)<<4)|((l_map[1]&3)<<2)
|
||||
|(l_map[0]&3);
|
||||
|
||||
dp_write(DP_LOGICAL2PHYSICAL_LANE_MAPPING, lane_map_reg);
|
||||
}
|
||||
|
||||
static void dp_catalog_ctrl_usb_reset_v200(struct dp_catalog_ctrl *ctrl,
|
||||
bool flip)
|
||||
{
|
||||
}
|
||||
|
||||
static void dp_catalog_put_v200(struct dp_catalog *catalog)
|
||||
{
|
||||
struct dp_catalog_private_v200 *catalog_priv;
|
||||
|
||||
if (!catalog)
|
||||
return;
|
||||
|
||||
catalog_priv = container_of(catalog->sub,
|
||||
struct dp_catalog_private_v200, sub);
|
||||
|
||||
devm_kfree(catalog_priv->dev, catalog_priv);
|
||||
}
|
||||
|
||||
struct dp_catalog_sub *dp_catalog_get_v200(struct device *dev,
|
||||
struct dp_catalog *catalog, struct dp_catalog_io *io)
|
||||
{
|
||||
struct dp_catalog_private_v200 *catalog_priv;
|
||||
|
||||
if (!dev || !catalog) {
|
||||
DP_ERR("invalid input\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
catalog_priv = devm_kzalloc(dev, sizeof(*catalog_priv), GFP_KERNEL);
|
||||
if (!catalog_priv)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
catalog_priv->dev = dev;
|
||||
catalog_priv->io = io;
|
||||
catalog_priv->dpc = catalog;
|
||||
|
||||
catalog_priv->sub.put = dp_catalog_put_v200;
|
||||
|
||||
catalog->aux.clear_hw_interrupts = dp_catalog_aux_clear_hw_int_v200;
|
||||
catalog->aux.setup = dp_catalog_aux_setup_v200;
|
||||
|
||||
catalog->panel.config_msa = dp_catalog_panel_config_msa_v200;
|
||||
|
||||
catalog->ctrl.lane_mapping = dp_catalog_ctrl_lane_mapping_v200;
|
||||
catalog->ctrl.usb_reset = dp_catalog_ctrl_usb_reset_v200;
|
||||
|
||||
return &catalog_priv->sub;
|
||||
}
|
362
techpack/display/msm/dp/dp_catalog_v420.c
Normal file
362
techpack/display/msm/dp/dp_catalog_v420.c
Normal file
@ -0,0 +1,362 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
|
||||
#include "dp_catalog.h"
|
||||
#include "dp_reg.h"
|
||||
#include "dp_debug.h"
|
||||
|
||||
#define dp_catalog_get_priv_v420(x) ({ \
|
||||
struct dp_catalog *catalog; \
|
||||
catalog = container_of(x, struct dp_catalog, x); \
|
||||
container_of(catalog->sub, \
|
||||
struct dp_catalog_private_v420, sub); \
|
||||
})
|
||||
|
||||
#define dp_read(x) ({ \
|
||||
catalog->sub.read(catalog->dpc, io_data, x); \
|
||||
})
|
||||
|
||||
#define dp_write(x, y) ({ \
|
||||
catalog->sub.write(catalog->dpc, io_data, x, y); \
|
||||
})
|
||||
|
||||
#define MAX_VOLTAGE_LEVELS 4
|
||||
#define MAX_PRE_EMP_LEVELS 4
|
||||
|
||||
static u8 const vm_pre_emphasis[MAX_VOLTAGE_LEVELS][MAX_PRE_EMP_LEVELS] = {
|
||||
{0x00, 0x0E, 0x16, 0xFF}, /* pe0, 0 db */
|
||||
{0x00, 0x0E, 0x16, 0xFF}, /* pe1, 3.5 db */
|
||||
{0x00, 0x0E, 0xFF, 0xFF}, /* pe2, 6.0 db */
|
||||
{0xFF, 0xFF, 0xFF, 0xFF} /* pe3, 9.5 db */
|
||||
};
|
||||
|
||||
/* voltage swing, 0.2v and 1.0v are not support */
|
||||
static u8 const vm_voltage_swing[MAX_VOLTAGE_LEVELS][MAX_PRE_EMP_LEVELS] = {
|
||||
{0x07, 0x0F, 0x16, 0xFF}, /* sw0, 0.4v */
|
||||
{0x11, 0x1E, 0x1F, 0xFF}, /* sw1, 0.6 v */
|
||||
{0x1A, 0x1F, 0xFF, 0xFF}, /* sw1, 0.8 v */
|
||||
{0xFF, 0xFF, 0xFF, 0xFF} /* sw1, 1.2 v, optional */
|
||||
};
|
||||
|
||||
static u8 const dp_pre_emp_hbr2_hbr3[MAX_VOLTAGE_LEVELS][MAX_PRE_EMP_LEVELS] = {
|
||||
{0x00, 0x0C, 0x15, 0x1B}, /* pe0, 0 db */
|
||||
{0x02, 0x0E, 0x16, 0xFF}, /* pe1, 3.5 db */
|
||||
{0x02, 0x11, 0xFF, 0xFF}, /* pe2, 6.0 db */
|
||||
{0x04, 0xFF, 0xFF, 0xFF} /* pe3, 9.5 db */
|
||||
};
|
||||
|
||||
static u8 const dp_swing_hbr2_hbr3[MAX_VOLTAGE_LEVELS][MAX_PRE_EMP_LEVELS] = {
|
||||
{0x02, 0x12, 0x16, 0x1A}, /* sw0, 0.4v */
|
||||
{0x09, 0x19, 0x1F, 0xFF}, /* sw1, 0.6v */
|
||||
{0x10, 0x1F, 0xFF, 0xFF}, /* sw1, 0.8v */
|
||||
{0x1F, 0xFF, 0xFF, 0xFF} /* sw1, 1.2v */
|
||||
};
|
||||
|
||||
static u8 const dp_pre_emp_hbr_rbr[MAX_VOLTAGE_LEVELS][MAX_PRE_EMP_LEVELS] = {
|
||||
{0x00, 0x0E, 0x15, 0x1B}, /* pe0, 0 db */
|
||||
{0x00, 0x0E, 0x15, 0xFF}, /* pe1, 3.5 db */
|
||||
{0x00, 0x0E, 0xFF, 0xFF}, /* pe2, 6.0 db */
|
||||
{0x04, 0xFF, 0xFF, 0xFF} /* pe3, 9.5 db */
|
||||
};
|
||||
|
||||
static u8 const dp_swing_hbr_rbr[MAX_VOLTAGE_LEVELS][MAX_PRE_EMP_LEVELS] = {
|
||||
{0x08, 0x0F, 0x16, 0x1F}, /* sw0, 0.4v */
|
||||
{0x11, 0x1E, 0x1F, 0xFF}, /* sw1, 0.6v */
|
||||
{0x16, 0x1F, 0xFF, 0xFF}, /* sw1, 0.8v */
|
||||
{0x1F, 0xFF, 0xFF, 0xFF} /* sw1, 1.2v */
|
||||
};
|
||||
|
||||
struct dp_catalog_private_v420 {
|
||||
struct device *dev;
|
||||
struct dp_catalog_sub sub;
|
||||
struct dp_catalog_io *io;
|
||||
struct dp_catalog *dpc;
|
||||
};
|
||||
|
||||
static void dp_catalog_aux_setup_v420(struct dp_catalog_aux *aux,
|
||||
struct dp_aux_cfg *cfg)
|
||||
{
|
||||
struct dp_catalog_private_v420 *catalog;
|
||||
struct dp_io_data *io_data;
|
||||
int i = 0;
|
||||
|
||||
if (!aux || !cfg) {
|
||||
DP_ERR("invalid input\n");
|
||||
return;
|
||||
}
|
||||
|
||||
catalog = dp_catalog_get_priv_v420(aux);
|
||||
|
||||
io_data = catalog->io->dp_phy;
|
||||
dp_write(DP_PHY_PD_CTL, 0x67);
|
||||
wmb(); /* make sure PD programming happened */
|
||||
|
||||
/* Turn on BIAS current for PHY/PLL */
|
||||
io_data = catalog->io->dp_pll;
|
||||
dp_write(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x17);
|
||||
wmb(); /* make sure BIAS programming happened */
|
||||
|
||||
io_data = catalog->io->dp_phy;
|
||||
/* DP AUX CFG register programming */
|
||||
for (i = 0; i < PHY_AUX_CFG_MAX; i++) {
|
||||
DP_DEBUG("%s: offset=0x%08x, value=0x%08x\n",
|
||||
dp_phy_aux_config_type_to_string(i),
|
||||
cfg[i].offset, cfg[i].lut[cfg[i].current_index]);
|
||||
dp_write(cfg[i].offset, cfg[i].lut[cfg[i].current_index]);
|
||||
}
|
||||
wmb(); /* make sure DP AUX CFG programming happened */
|
||||
|
||||
dp_write(DP_PHY_AUX_INTERRUPT_MASK_V420, 0x1F);
|
||||
}
|
||||
|
||||
static void dp_catalog_aux_clear_hw_int_v420(struct dp_catalog_aux *aux)
|
||||
{
|
||||
struct dp_catalog_private_v420 *catalog;
|
||||
struct dp_io_data *io_data;
|
||||
u32 data = 0;
|
||||
|
||||
if (!aux) {
|
||||
DP_ERR("invalid input\n");
|
||||
return;
|
||||
}
|
||||
|
||||
catalog = dp_catalog_get_priv_v420(aux);
|
||||
io_data = catalog->io->dp_phy;
|
||||
|
||||
data = dp_read(DP_PHY_AUX_INTERRUPT_STATUS_V420);
|
||||
|
||||
dp_write(DP_PHY_AUX_INTERRUPT_CLEAR_V420, 0x1f);
|
||||
wmb(); /* make sure 0x1f is written before next write */
|
||||
|
||||
dp_write(DP_PHY_AUX_INTERRUPT_CLEAR_V420, 0x9f);
|
||||
wmb(); /* make sure 0x9f is written before next write */
|
||||
|
||||
dp_write(DP_PHY_AUX_INTERRUPT_CLEAR_V420, 0);
|
||||
wmb(); /* make sure register is cleared */
|
||||
}
|
||||
|
||||
static void dp_catalog_panel_config_msa_v420(struct dp_catalog_panel *panel,
|
||||
u32 rate, u32 stream_rate_khz)
|
||||
{
|
||||
u32 pixel_m, pixel_n;
|
||||
u32 mvid, nvid, reg_off = 0, mvid_off = 0, nvid_off = 0;
|
||||
u32 const nvid_fixed = 0x8000;
|
||||
u32 const link_rate_hbr2 = 540000;
|
||||
u32 const link_rate_hbr3 = 810000;
|
||||
struct dp_catalog_private_v420 *catalog;
|
||||
struct dp_io_data *io_data;
|
||||
|
||||
if (!panel || !rate) {
|
||||
DP_ERR("invalid input\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (panel->stream_id >= DP_STREAM_MAX) {
|
||||
DP_ERR("invalid stream id:%d\n", panel->stream_id);
|
||||
return;
|
||||
}
|
||||
|
||||
catalog = dp_catalog_get_priv_v420(panel);
|
||||
io_data = catalog->io->dp_mmss_cc;
|
||||
|
||||
if (panel->stream_id == DP_STREAM_1)
|
||||
reg_off = MMSS_DP_PIXEL1_M_V420 - MMSS_DP_PIXEL_M_V420;
|
||||
|
||||
pixel_m = dp_read(MMSS_DP_PIXEL_M_V420 + reg_off);
|
||||
pixel_n = dp_read(MMSS_DP_PIXEL_N_V420 + reg_off);
|
||||
DP_DEBUG("pixel_m=0x%x, pixel_n=0x%x\n", pixel_m, pixel_n);
|
||||
|
||||
mvid = (pixel_m & 0xFFFF) * 5;
|
||||
nvid = (0xFFFF & (~pixel_n)) + (pixel_m & 0xFFFF);
|
||||
|
||||
if (nvid < nvid_fixed) {
|
||||
u32 temp;
|
||||
|
||||
temp = (nvid_fixed / nvid) * nvid;
|
||||
mvid = (nvid_fixed / nvid) * mvid;
|
||||
nvid = temp;
|
||||
}
|
||||
|
||||
DP_DEBUG("rate = %d\n", rate);
|
||||
|
||||
if (panel->widebus_en)
|
||||
mvid <<= 1;
|
||||
|
||||
if (link_rate_hbr2 == rate)
|
||||
nvid *= 2;
|
||||
|
||||
if (link_rate_hbr3 == rate)
|
||||
nvid *= 3;
|
||||
|
||||
io_data = catalog->io->dp_link;
|
||||
|
||||
if (panel->stream_id == DP_STREAM_1) {
|
||||
mvid_off = DP1_SOFTWARE_MVID - DP_SOFTWARE_MVID;
|
||||
nvid_off = DP1_SOFTWARE_NVID - DP_SOFTWARE_NVID;
|
||||
}
|
||||
|
||||
DP_DEBUG("mvid=0x%x, nvid=0x%x\n", mvid, nvid);
|
||||
dp_write(DP_SOFTWARE_MVID + mvid_off, mvid);
|
||||
dp_write(DP_SOFTWARE_NVID + nvid_off, nvid);
|
||||
}
|
||||
|
||||
static void dp_catalog_ctrl_phy_lane_cfg_v420(struct dp_catalog_ctrl *ctrl,
|
||||
bool flipped, u8 ln_cnt)
|
||||
{
|
||||
u32 info = 0x0;
|
||||
struct dp_catalog_private_v420 *catalog;
|
||||
struct dp_io_data *io_data;
|
||||
u8 orientation = BIT(!!flipped);
|
||||
|
||||
if (!ctrl) {
|
||||
DP_ERR("invalid input\n");
|
||||
return;
|
||||
}
|
||||
|
||||
catalog = dp_catalog_get_priv_v420(ctrl);
|
||||
io_data = catalog->io->dp_phy;
|
||||
|
||||
info |= (ln_cnt & 0x0F);
|
||||
info |= ((orientation & 0x0F) << 4);
|
||||
DP_DEBUG("Shared Info = 0x%x\n", info);
|
||||
|
||||
dp_write(DP_PHY_SPARE0_V420, info);
|
||||
}
|
||||
|
||||
static void dp_catalog_ctrl_update_vx_px_v420(struct dp_catalog_ctrl *ctrl,
|
||||
u8 v_level, u8 p_level, bool high)
|
||||
{
|
||||
struct dp_catalog_private_v420 *catalog;
|
||||
struct dp_io_data *io_data;
|
||||
u8 value0, value1;
|
||||
u32 version;
|
||||
|
||||
if (!ctrl || !((v_level < MAX_VOLTAGE_LEVELS)
|
||||
&& (p_level < MAX_PRE_EMP_LEVELS))) {
|
||||
DP_ERR("invalid input\n");
|
||||
return;
|
||||
}
|
||||
|
||||
DP_DEBUG("hw: v=%d p=%d, high=%d\n", v_level, p_level, high);
|
||||
|
||||
catalog = dp_catalog_get_priv_v420(ctrl);
|
||||
|
||||
io_data = catalog->io->dp_ahb;
|
||||
version = dp_read(DP_HW_VERSION);
|
||||
DP_DEBUG("version: 0x%x\n", version);
|
||||
|
||||
/*
|
||||
* For DP controller versions >= 1.2.3
|
||||
*/
|
||||
if (version >= 0x10020003) {
|
||||
if (high) {
|
||||
value0 = dp_swing_hbr2_hbr3[v_level][p_level];
|
||||
value1 = dp_pre_emp_hbr2_hbr3[v_level][p_level];
|
||||
} else {
|
||||
value0 = dp_swing_hbr_rbr[v_level][p_level];
|
||||
value1 = dp_pre_emp_hbr_rbr[v_level][p_level];
|
||||
}
|
||||
} else {
|
||||
value0 = vm_voltage_swing[v_level][p_level];
|
||||
value1 = vm_pre_emphasis[v_level][p_level];
|
||||
}
|
||||
|
||||
/* program default setting first */
|
||||
io_data = catalog->io->dp_ln_tx0;
|
||||
dp_write(TXn_TX_DRV_LVL_V420, 0x2A);
|
||||
dp_write(TXn_TX_EMP_POST1_LVL, 0x20);
|
||||
|
||||
io_data = catalog->io->dp_ln_tx1;
|
||||
dp_write(TXn_TX_DRV_LVL_V420, 0x2A);
|
||||
dp_write(TXn_TX_EMP_POST1_LVL, 0x20);
|
||||
|
||||
/* Enable MUX to use Cursor values from these registers */
|
||||
value0 |= BIT(5);
|
||||
value1 |= BIT(5);
|
||||
|
||||
/* Configure host and panel only if both values are allowed */
|
||||
if (value0 != 0xFF && value1 != 0xFF) {
|
||||
io_data = catalog->io->dp_ln_tx0;
|
||||
dp_write(TXn_TX_DRV_LVL_V420, value0);
|
||||
dp_write(TXn_TX_EMP_POST1_LVL, value1);
|
||||
|
||||
io_data = catalog->io->dp_ln_tx1;
|
||||
dp_write(TXn_TX_DRV_LVL_V420, value0);
|
||||
dp_write(TXn_TX_EMP_POST1_LVL, value1);
|
||||
|
||||
DP_DEBUG("hw: vx_value=0x%x px_value=0x%x\n",
|
||||
value0, value1);
|
||||
} else {
|
||||
DP_ERR("invalid vx (0x%x=0x%x), px (0x%x=0x%x\n",
|
||||
v_level, value0, p_level, value1);
|
||||
}
|
||||
}
|
||||
|
||||
static void dp_catalog_ctrl_lane_pnswap_v420(struct dp_catalog_ctrl *ctrl,
|
||||
u8 ln_pnswap)
|
||||
{
|
||||
struct dp_catalog_private_v420 *catalog;
|
||||
struct dp_io_data *io_data;
|
||||
u32 cfg0, cfg1;
|
||||
|
||||
catalog = dp_catalog_get_priv_v420(ctrl);
|
||||
|
||||
cfg0 = 0x0a;
|
||||
cfg1 = 0x0a;
|
||||
|
||||
cfg0 |= ((ln_pnswap >> 0) & 0x1) << 0;
|
||||
cfg0 |= ((ln_pnswap >> 1) & 0x1) << 2;
|
||||
cfg1 |= ((ln_pnswap >> 2) & 0x1) << 0;
|
||||
cfg1 |= ((ln_pnswap >> 3) & 0x1) << 2;
|
||||
|
||||
io_data = catalog->io->dp_ln_tx0;
|
||||
dp_write(TXn_TX_POL_INV_V420, cfg0);
|
||||
|
||||
io_data = catalog->io->dp_ln_tx1;
|
||||
dp_write(TXn_TX_POL_INV_V420, cfg1);
|
||||
}
|
||||
|
||||
static void dp_catalog_put_v420(struct dp_catalog *catalog)
|
||||
{
|
||||
struct dp_catalog_private_v420 *catalog_priv;
|
||||
|
||||
if (!catalog)
|
||||
return;
|
||||
|
||||
catalog_priv = container_of(catalog->sub,
|
||||
struct dp_catalog_private_v420, sub);
|
||||
devm_kfree(catalog_priv->dev, catalog_priv);
|
||||
}
|
||||
|
||||
struct dp_catalog_sub *dp_catalog_get_v420(struct device *dev,
|
||||
struct dp_catalog *catalog, struct dp_catalog_io *io)
|
||||
{
|
||||
struct dp_catalog_private_v420 *catalog_priv;
|
||||
|
||||
if (!dev || !catalog) {
|
||||
DP_ERR("invalid input\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
catalog_priv = devm_kzalloc(dev, sizeof(*catalog_priv), GFP_KERNEL);
|
||||
if (!catalog_priv)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
catalog_priv->dev = dev;
|
||||
catalog_priv->io = io;
|
||||
catalog_priv->dpc = catalog;
|
||||
|
||||
catalog_priv->sub.put = dp_catalog_put_v420;
|
||||
|
||||
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;
|
||||
catalog->ctrl.phy_lane_cfg = dp_catalog_ctrl_phy_lane_cfg_v420;
|
||||
catalog->ctrl.update_vx_px = dp_catalog_ctrl_update_vx_px_v420;
|
||||
catalog->ctrl.lane_pnswap = dp_catalog_ctrl_lane_pnswap_v420;
|
||||
|
||||
return &catalog_priv->sub;
|
||||
}
|
1514
techpack/display/msm/dp/dp_ctrl.c
Normal file
1514
techpack/display/msm/dp/dp_ctrl.c
Normal file
File diff suppressed because it is too large
Load Diff
50
techpack/display/msm/dp/dp_ctrl.h
Normal file
50
techpack/display/msm/dp/dp_ctrl.h
Normal file
@ -0,0 +1,50 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _DP_CTRL_H_
|
||||
#define _DP_CTRL_H_
|
||||
|
||||
#include "dp_aux.h"
|
||||
#include "dp_panel.h"
|
||||
#include "dp_link.h"
|
||||
#include "dp_parser.h"
|
||||
#include "dp_power.h"
|
||||
#include "dp_catalog.h"
|
||||
#include "dp_debug.h"
|
||||
|
||||
struct dp_ctrl {
|
||||
int (*init)(struct dp_ctrl *dp_ctrl, bool flip, bool reset);
|
||||
void (*deinit)(struct dp_ctrl *dp_ctrl);
|
||||
int (*on)(struct dp_ctrl *dp_ctrl, bool mst_mode, bool fec_en,
|
||||
bool dsc_en, bool shallow);
|
||||
void (*off)(struct dp_ctrl *dp_ctrl);
|
||||
void (*abort)(struct dp_ctrl *dp_ctrl, bool abort);
|
||||
void (*isr)(struct dp_ctrl *dp_ctrl);
|
||||
bool (*handle_sink_request)(struct dp_ctrl *dp_ctrl);
|
||||
void (*process_phy_test_request)(struct dp_ctrl *dp_ctrl);
|
||||
int (*link_maintenance)(struct dp_ctrl *dp_ctrl);
|
||||
int (*stream_on)(struct dp_ctrl *dp_ctrl, struct dp_panel *panel);
|
||||
void (*stream_off)(struct dp_ctrl *dp_ctrl, struct dp_panel *panel);
|
||||
void (*stream_pre_off)(struct dp_ctrl *dp_ctrl, struct dp_panel *panel);
|
||||
void (*set_mst_channel_info)(struct dp_ctrl *dp_ctrl,
|
||||
enum dp_stream_id strm,
|
||||
u32 ch_start_slot, u32 ch_tot_slots);
|
||||
void (*set_sim_mode)(struct dp_ctrl *dp_ctrl, bool en);
|
||||
};
|
||||
|
||||
struct dp_ctrl_in {
|
||||
struct device *dev;
|
||||
struct dp_panel *panel;
|
||||
struct dp_aux *aux;
|
||||
struct dp_link *link;
|
||||
struct dp_parser *parser;
|
||||
struct dp_power *power;
|
||||
struct dp_catalog_ctrl *catalog;
|
||||
};
|
||||
|
||||
struct dp_ctrl *dp_ctrl_get(struct dp_ctrl_in *in);
|
||||
void dp_ctrl_put(struct dp_ctrl *dp_ctrl);
|
||||
|
||||
#endif /* _DP_CTRL_H_ */
|
2531
techpack/display/msm/dp/dp_debug.c
Normal file
2531
techpack/display/msm/dp/dp_debug.c
Normal file
File diff suppressed because it is too large
Load Diff
151
techpack/display/msm/dp/dp_debug.h
Normal file
151
techpack/display/msm/dp/dp_debug.h
Normal file
@ -0,0 +1,151 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _DP_DEBUG_H_
|
||||
#define _DP_DEBUG_H_
|
||||
|
||||
#include "dp_panel.h"
|
||||
#include "dp_ctrl.h"
|
||||
#include "dp_link.h"
|
||||
#include "dp_aux.h"
|
||||
#include "dp_display.h"
|
||||
#include "dp_pll.h"
|
||||
|
||||
#define DP_DEBUG(fmt, ...) \
|
||||
do { \
|
||||
if (unlikely(drm_debug & DRM_UT_KMS)) \
|
||||
DRM_DEBUG("[msm-dp-debug][%-4d]"fmt, current->pid, \
|
||||
##__VA_ARGS__); \
|
||||
else \
|
||||
pr_debug("[drm:%s][msm-dp-debug][%-4d]"fmt, __func__,\
|
||||
current->pid, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define DP_INFO(fmt, ...) \
|
||||
do { \
|
||||
if (unlikely(drm_debug & DRM_UT_KMS)) \
|
||||
DRM_INFO("[msm-dp-info][%-4d]"fmt, current->pid, \
|
||||
##__VA_ARGS__); \
|
||||
else \
|
||||
pr_info("[drm:%s][msm-dp-info][%-4d]"fmt, __func__, \
|
||||
current->pid, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define DP_WARN(fmt, ...) \
|
||||
pr_warn("[drm:%s][msm-dp-warn][%-4d]"fmt, __func__, \
|
||||
current->pid, ##__VA_ARGS__)
|
||||
|
||||
#define DP_ERR(fmt, ...) \
|
||||
pr_err("[drm:%s][msm-dp-err][%-4d]"fmt, __func__, \
|
||||
current->pid, ##__VA_ARGS__)
|
||||
|
||||
#define DEFAULT_DISCONNECT_DELAY_MS 0
|
||||
#define MAX_DISCONNECT_DELAY_MS 10000
|
||||
#define DEFAULT_CONNECT_NOTIFICATION_DELAY_MS 150
|
||||
#define MAX_CONNECT_NOTIFICATION_DELAY_MS 5000
|
||||
|
||||
/**
|
||||
* struct dp_debug
|
||||
* @debug_en: specifies whether debug mode enabled
|
||||
* @sim_mode: specifies whether sim mode enabled
|
||||
* @psm_enabled: specifies whether psm enabled
|
||||
* @hdcp_disabled: specifies if hdcp is disabled
|
||||
* @hdcp_wait_sink_sync: used to wait for sink synchronization before HDCP auth
|
||||
* @aspect_ratio: used to filter out aspect_ratio value
|
||||
* @vdisplay: used to filter out vdisplay value
|
||||
* @hdisplay: used to filter out hdisplay value
|
||||
* @vrefresh: used to filter out vrefresh value
|
||||
* @tpg_state: specifies whether tpg feature is enabled
|
||||
* @max_pclk_khz: max pclk supported
|
||||
* @force_encryption: enable/disable forced encryption for HDCP 2.2
|
||||
* @skip_uevent: skip hotplug uevent to the user space
|
||||
* @hdcp_status: string holding hdcp status information
|
||||
* @dp_mst_connector_list: list containing all dp mst connectors
|
||||
* @mst_hpd_sim: specifies whether simulated hpd enabled
|
||||
* @mst_sim_add_con: specifies whether new sim connector is to be added
|
||||
* @mst_sim_remove_con: specifies whether sim connector is to be removed
|
||||
* @mst_sim_remove_con_id: specifies id of sim connector to be removed
|
||||
* @mst_port_cnt: number of mst ports to be added during hpd
|
||||
* @connect_notification_delay_ms: time (in ms) to wait for any attention
|
||||
* messages before sending the connect notification uevent
|
||||
* @disconnect_delay_ms: time (in ms) to wait before turning off the mainlink
|
||||
* in response to HPD low of cable disconnect event
|
||||
*/
|
||||
struct dp_debug {
|
||||
bool debug_en;
|
||||
bool sim_mode;
|
||||
bool psm_enabled;
|
||||
bool hdcp_disabled;
|
||||
bool hdcp_wait_sink_sync;
|
||||
int aspect_ratio;
|
||||
int vdisplay;
|
||||
int hdisplay;
|
||||
int vrefresh;
|
||||
bool tpg_state;
|
||||
u32 max_pclk_khz;
|
||||
bool force_encryption;
|
||||
bool skip_uevent;
|
||||
char hdcp_status[SZ_128];
|
||||
struct dp_mst_connector dp_mst_connector_list;
|
||||
bool mst_hpd_sim;
|
||||
bool mst_sim_add_con;
|
||||
bool mst_sim_remove_con;
|
||||
int mst_sim_remove_con_id;
|
||||
u32 mst_port_cnt;
|
||||
unsigned long connect_notification_delay_ms;
|
||||
u32 disconnect_delay_ms;
|
||||
|
||||
struct dp_mst_connector mst_connector_cache;
|
||||
u8 *(*get_edid)(struct dp_debug *dp_debug);
|
||||
void (*abort)(struct dp_debug *dp_debug);
|
||||
void (*set_mst_con)(struct dp_debug *dp_debug, int con_id);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dp_debug_in
|
||||
* @dev: device instance of the caller
|
||||
* @panel: instance of panel module
|
||||
* @hpd: instance of hpd module
|
||||
* @link: instance of link module
|
||||
* @aux: instance of aux module
|
||||
* @connector: double pointer to display connector
|
||||
* @catalog: instance of catalog module
|
||||
* @parser: instance of parser module
|
||||
* @ctrl: instance of controller module
|
||||
* @pll: instance of pll module
|
||||
*/
|
||||
struct dp_debug_in {
|
||||
struct device *dev;
|
||||
struct dp_panel *panel;
|
||||
struct dp_hpd *hpd;
|
||||
struct dp_link *link;
|
||||
struct dp_aux *aux;
|
||||
struct drm_connector **connector;
|
||||
struct dp_catalog *catalog;
|
||||
struct dp_parser *parser;
|
||||
struct dp_ctrl *ctrl;
|
||||
struct dp_pll *pll;
|
||||
};
|
||||
|
||||
/**
|
||||
* dp_debug_get() - configure and get the DisplayPlot debug module data
|
||||
*
|
||||
* @in: input structure containing data to initialize the debug module
|
||||
* return: pointer to allocated debug module data
|
||||
*
|
||||
* This function sets up the debug module and provides a way
|
||||
* for debugfs input to be communicated with existing modules
|
||||
*/
|
||||
struct dp_debug *dp_debug_get(struct dp_debug_in *in);
|
||||
|
||||
/**
|
||||
* dp_debug_put()
|
||||
*
|
||||
* Cleans up dp_debug instance
|
||||
*
|
||||
* @dp_debug: instance of dp_debug
|
||||
*/
|
||||
void dp_debug_put(struct dp_debug *dp_debug);
|
||||
#endif /* _DP_DEBUG_H_ */
|
3793
techpack/display/msm/dp/dp_display.c
Normal file
3793
techpack/display/msm/dp/dp_display.c
Normal file
File diff suppressed because it is too large
Load Diff
160
techpack/display/msm/dp/dp_display.h
Normal file
160
techpack/display/msm/dp/dp_display.h
Normal file
@ -0,0 +1,160 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _DP_DISPLAY_H_
|
||||
#define _DP_DISPLAY_H_
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/sde_drm.h>
|
||||
|
||||
#include "dp_panel.h"
|
||||
|
||||
#define DP_MST_SIM_MAX_PORTS 8
|
||||
|
||||
enum dp_drv_state {
|
||||
PM_DEFAULT,
|
||||
PM_SUSPEND,
|
||||
};
|
||||
|
||||
struct dp_mst_hpd_info {
|
||||
bool mst_protocol;
|
||||
bool mst_hpd_sim;
|
||||
u32 mst_port_cnt;
|
||||
u8 *edid;
|
||||
bool mst_sim_add_con;
|
||||
bool mst_sim_remove_con;
|
||||
int mst_sim_remove_con_id;
|
||||
};
|
||||
|
||||
struct dp_mst_drm_cbs {
|
||||
void (*hpd)(void *display, bool hpd_status);
|
||||
void (*hpd_irq)(void *display, struct dp_mst_hpd_info *info);
|
||||
void (*set_drv_state)(void *dp_display,
|
||||
enum dp_drv_state mst_state);
|
||||
int (*set_mgr_state)(void *dp_display, bool state,
|
||||
struct dp_mst_hpd_info *info);
|
||||
};
|
||||
|
||||
struct dp_mst_drm_install_info {
|
||||
void *dp_mst_prv_info;
|
||||
const struct dp_mst_drm_cbs *cbs;
|
||||
};
|
||||
|
||||
struct dp_mst_caps {
|
||||
bool has_mst;
|
||||
u32 max_streams_supported;
|
||||
u32 max_dpcd_transaction_bytes;
|
||||
struct drm_dp_aux *drm_aux;
|
||||
};
|
||||
|
||||
struct dp_mst_connector {
|
||||
bool debug_en;
|
||||
int con_id;
|
||||
int hdisplay;
|
||||
int vdisplay;
|
||||
int vrefresh;
|
||||
int aspect_ratio;
|
||||
struct drm_connector *conn;
|
||||
struct mutex lock;
|
||||
struct list_head list;
|
||||
enum drm_connector_status state;
|
||||
};
|
||||
|
||||
struct dp_display {
|
||||
struct drm_device *drm_dev;
|
||||
struct dp_bridge *bridge;
|
||||
struct drm_connector *base_connector;
|
||||
void *base_dp_panel;
|
||||
bool is_sst_connected;
|
||||
bool is_mst_supported;
|
||||
bool dsc_cont_pps;
|
||||
u32 max_pclk_khz;
|
||||
void *dp_mst_prv_info;
|
||||
u32 max_mixer_count;
|
||||
u32 max_dsc_count;
|
||||
|
||||
int (*enable)(struct dp_display *dp_display, void *panel);
|
||||
int (*post_enable)(struct dp_display *dp_display, void *panel);
|
||||
|
||||
int (*pre_disable)(struct dp_display *dp_display, void *panel);
|
||||
int (*disable)(struct dp_display *dp_display, void *panel);
|
||||
|
||||
int (*set_mode)(struct dp_display *dp_display, void *panel,
|
||||
struct dp_display_mode *mode);
|
||||
enum drm_mode_status (*validate_mode)(struct dp_display *dp_display,
|
||||
void *panel, struct drm_display_mode *mode,
|
||||
const struct msm_resource_caps_info *avail_res);
|
||||
int (*get_modes)(struct dp_display *dp_display, void *panel,
|
||||
struct dp_display_mode *dp_mode);
|
||||
int (*prepare)(struct dp_display *dp_display, void *panel);
|
||||
int (*unprepare)(struct dp_display *dp_display, void *panel);
|
||||
int (*request_irq)(struct dp_display *dp_display);
|
||||
struct dp_debug *(*get_debug)(struct dp_display *dp_display);
|
||||
void (*post_open)(struct dp_display *dp_display);
|
||||
int (*config_hdr)(struct dp_display *dp_display, void *panel,
|
||||
struct drm_msm_ext_hdr_metadata *hdr_meta,
|
||||
bool dhdr_update);
|
||||
int (*set_colorspace)(struct dp_display *dp_display, void *panel,
|
||||
u32 colorspace);
|
||||
int (*post_init)(struct dp_display *dp_display);
|
||||
int (*mst_install)(struct dp_display *dp_display,
|
||||
struct dp_mst_drm_install_info *mst_install_info);
|
||||
int (*mst_uninstall)(struct dp_display *dp_display);
|
||||
int (*mst_connector_install)(struct dp_display *dp_display,
|
||||
struct drm_connector *connector);
|
||||
int (*mst_connector_uninstall)(struct dp_display *dp_display,
|
||||
struct drm_connector *connector);
|
||||
int (*mst_connector_update_edid)(struct dp_display *dp_display,
|
||||
struct drm_connector *connector,
|
||||
struct edid *edid);
|
||||
int (*mst_connector_update_link_info)(struct dp_display *dp_display,
|
||||
struct drm_connector *connector);
|
||||
int (*mst_get_connector_info)(struct dp_display *dp_display,
|
||||
struct drm_connector *connector,
|
||||
struct dp_mst_connector *mst_conn);
|
||||
int (*mst_get_fixed_topology_port)(struct dp_display *dp_display,
|
||||
u32 strm_id, u32 *port_num);
|
||||
int (*get_mst_caps)(struct dp_display *dp_display,
|
||||
struct dp_mst_caps *mst_caps);
|
||||
int (*set_stream_info)(struct dp_display *dp_display, void *panel,
|
||||
u32 strm_id, u32 start_slot, u32 num_slots, u32 pbn,
|
||||
int vcpi);
|
||||
void (*convert_to_dp_mode)(struct dp_display *dp_display, void *panel,
|
||||
const struct drm_display_mode *drm_mode,
|
||||
struct dp_display_mode *dp_mode);
|
||||
int (*update_pps)(struct dp_display *dp_display,
|
||||
struct drm_connector *connector, char *pps_cmd);
|
||||
void (*wakeup_phy_layer)(struct dp_display *dp_display,
|
||||
bool wakeup);
|
||||
int (*get_available_dp_resources)(struct dp_display *dp_display,
|
||||
const struct msm_resource_caps_info *avail_res,
|
||||
struct msm_resource_caps_info *max_dp_avail_res);
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_DRM_MSM_DP)
|
||||
int dp_display_get_num_of_displays(void);
|
||||
int dp_display_get_displays(void **displays, int count);
|
||||
int dp_display_get_num_of_streams(void);
|
||||
#else
|
||||
static inline int dp_display_get_num_of_displays(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline int dp_display_get_displays(void **displays, int count)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline int dp_display_get_num_of_streams(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline int dp_connector_update_pps(struct drm_connector *connector,
|
||||
char *pps_cmd, void *display)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_DRM_MSM_DP */
|
||||
#endif /* _DP_DISPLAY_H_ */
|
739
techpack/display/msm/dp/dp_drm.c
Normal file
739
techpack/display/msm/dp/dp_drm.c
Normal file
@ -0,0 +1,739 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_crtc.h>
|
||||
|
||||
#include "msm_drv.h"
|
||||
#include "msm_kms.h"
|
||||
#include "sde_connector.h"
|
||||
#include "dp_drm.h"
|
||||
#include "dp_mst_drm.h"
|
||||
#include "dp_debug.h"
|
||||
|
||||
#define DP_MST_DEBUG(fmt, ...) DP_DEBUG(fmt, ##__VA_ARGS__)
|
||||
|
||||
#define to_dp_bridge(x) container_of((x), struct dp_bridge, base)
|
||||
|
||||
void convert_to_drm_mode(const struct dp_display_mode *dp_mode,
|
||||
struct drm_display_mode *drm_mode)
|
||||
{
|
||||
u32 flags = 0;
|
||||
|
||||
memset(drm_mode, 0, sizeof(*drm_mode));
|
||||
|
||||
drm_mode->hdisplay = dp_mode->timing.h_active;
|
||||
drm_mode->hsync_start = drm_mode->hdisplay +
|
||||
dp_mode->timing.h_front_porch;
|
||||
drm_mode->hsync_end = drm_mode->hsync_start +
|
||||
dp_mode->timing.h_sync_width;
|
||||
drm_mode->htotal = drm_mode->hsync_end + dp_mode->timing.h_back_porch;
|
||||
drm_mode->hskew = dp_mode->timing.h_skew;
|
||||
|
||||
drm_mode->vdisplay = dp_mode->timing.v_active;
|
||||
drm_mode->vsync_start = drm_mode->vdisplay +
|
||||
dp_mode->timing.v_front_porch;
|
||||
drm_mode->vsync_end = drm_mode->vsync_start +
|
||||
dp_mode->timing.v_sync_width;
|
||||
drm_mode->vtotal = drm_mode->vsync_end + dp_mode->timing.v_back_porch;
|
||||
|
||||
drm_mode->vrefresh = dp_mode->timing.refresh_rate;
|
||||
drm_mode->clock = dp_mode->timing.pixel_clk_khz;
|
||||
|
||||
if (dp_mode->timing.h_active_low)
|
||||
flags |= DRM_MODE_FLAG_NHSYNC;
|
||||
else
|
||||
flags |= DRM_MODE_FLAG_PHSYNC;
|
||||
|
||||
if (dp_mode->timing.v_active_low)
|
||||
flags |= DRM_MODE_FLAG_NVSYNC;
|
||||
else
|
||||
flags |= DRM_MODE_FLAG_PVSYNC;
|
||||
|
||||
drm_mode->flags = flags;
|
||||
|
||||
drm_mode->type = 0x48;
|
||||
drm_mode_set_name(drm_mode);
|
||||
}
|
||||
|
||||
static int dp_bridge_attach(struct drm_bridge *dp_bridge)
|
||||
{
|
||||
struct dp_bridge *bridge = to_dp_bridge(dp_bridge);
|
||||
|
||||
if (!dp_bridge) {
|
||||
DP_ERR("Invalid params\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
DP_DEBUG("[%d] attached\n", bridge->id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dp_bridge_pre_enable(struct drm_bridge *drm_bridge)
|
||||
{
|
||||
int rc = 0;
|
||||
struct dp_bridge *bridge;
|
||||
struct dp_display *dp;
|
||||
|
||||
if (!drm_bridge) {
|
||||
DP_ERR("Invalid params\n");
|
||||
return;
|
||||
}
|
||||
|
||||
bridge = to_dp_bridge(drm_bridge);
|
||||
dp = bridge->display;
|
||||
|
||||
if (!bridge->connector) {
|
||||
DP_ERR("Invalid connector\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!bridge->dp_panel) {
|
||||
DP_ERR("Invalid dp_panel\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* By this point mode should have been validated through mode_fixup */
|
||||
rc = dp->set_mode(dp, bridge->dp_panel, &bridge->dp_mode);
|
||||
if (rc) {
|
||||
DP_ERR("[%d] failed to perform a mode set, rc=%d\n",
|
||||
bridge->id, rc);
|
||||
return;
|
||||
}
|
||||
|
||||
rc = dp->prepare(dp, bridge->dp_panel);
|
||||
if (rc) {
|
||||
DP_ERR("[%d] DP display prepare failed, rc=%d\n",
|
||||
bridge->id, rc);
|
||||
return;
|
||||
}
|
||||
|
||||
/* for SST force stream id, start slot and total slots to 0 */
|
||||
dp->set_stream_info(dp, bridge->dp_panel, 0, 0, 0, 0, 0);
|
||||
|
||||
rc = dp->enable(dp, bridge->dp_panel);
|
||||
if (rc)
|
||||
DP_ERR("[%d] DP display enable failed, rc=%d\n",
|
||||
bridge->id, rc);
|
||||
}
|
||||
|
||||
static void dp_bridge_enable(struct drm_bridge *drm_bridge)
|
||||
{
|
||||
int rc = 0;
|
||||
struct dp_bridge *bridge;
|
||||
struct dp_display *dp;
|
||||
|
||||
if (!drm_bridge) {
|
||||
DP_ERR("Invalid params\n");
|
||||
return;
|
||||
}
|
||||
|
||||
bridge = to_dp_bridge(drm_bridge);
|
||||
if (!bridge->connector) {
|
||||
DP_ERR("Invalid connector\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!bridge->dp_panel) {
|
||||
DP_ERR("Invalid dp_panel\n");
|
||||
return;
|
||||
}
|
||||
|
||||
dp = bridge->display;
|
||||
|
||||
rc = dp->post_enable(dp, bridge->dp_panel);
|
||||
if (rc)
|
||||
DP_ERR("[%d] DP display post enable failed, rc=%d\n",
|
||||
bridge->id, rc);
|
||||
}
|
||||
|
||||
static void dp_bridge_disable(struct drm_bridge *drm_bridge)
|
||||
{
|
||||
int rc = 0;
|
||||
struct dp_bridge *bridge;
|
||||
struct dp_display *dp;
|
||||
|
||||
if (!drm_bridge) {
|
||||
DP_ERR("Invalid params\n");
|
||||
return;
|
||||
}
|
||||
|
||||
bridge = to_dp_bridge(drm_bridge);
|
||||
if (!bridge->connector) {
|
||||
DP_ERR("Invalid connector\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!bridge->dp_panel) {
|
||||
DP_ERR("Invalid dp_panel\n");
|
||||
return;
|
||||
}
|
||||
|
||||
dp = bridge->display;
|
||||
|
||||
if (!dp) {
|
||||
DP_ERR("dp is null\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (dp)
|
||||
sde_connector_helper_bridge_disable(bridge->connector);
|
||||
|
||||
rc = dp->pre_disable(dp, bridge->dp_panel);
|
||||
if (rc) {
|
||||
DP_ERR("[%d] DP display pre disable failed, rc=%d\n",
|
||||
bridge->id, rc);
|
||||
}
|
||||
}
|
||||
|
||||
static void dp_bridge_post_disable(struct drm_bridge *drm_bridge)
|
||||
{
|
||||
int rc = 0;
|
||||
struct dp_bridge *bridge;
|
||||
struct dp_display *dp;
|
||||
|
||||
if (!drm_bridge) {
|
||||
DP_ERR("Invalid params\n");
|
||||
return;
|
||||
}
|
||||
|
||||
bridge = to_dp_bridge(drm_bridge);
|
||||
if (!bridge->connector) {
|
||||
DP_ERR("Invalid connector\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!bridge->dp_panel) {
|
||||
DP_ERR("Invalid dp_panel\n");
|
||||
return;
|
||||
}
|
||||
|
||||
dp = bridge->display;
|
||||
|
||||
rc = dp->disable(dp, bridge->dp_panel);
|
||||
if (rc) {
|
||||
DP_ERR("[%d] DP display disable failed, rc=%d\n",
|
||||
bridge->id, rc);
|
||||
return;
|
||||
}
|
||||
|
||||
rc = dp->unprepare(dp, bridge->dp_panel);
|
||||
if (rc) {
|
||||
DP_ERR("[%d] DP display unprepare failed, rc=%d\n",
|
||||
bridge->id, rc);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void dp_bridge_mode_set(struct drm_bridge *drm_bridge,
|
||||
const struct drm_display_mode *mode,
|
||||
const struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
struct dp_bridge *bridge;
|
||||
struct dp_display *dp;
|
||||
|
||||
if (!drm_bridge || !mode || !adjusted_mode) {
|
||||
DP_ERR("Invalid params\n");
|
||||
return;
|
||||
}
|
||||
|
||||
bridge = to_dp_bridge(drm_bridge);
|
||||
if (!bridge->connector) {
|
||||
DP_ERR("Invalid connector\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!bridge->dp_panel) {
|
||||
DP_ERR("Invalid dp_panel\n");
|
||||
return;
|
||||
}
|
||||
|
||||
dp = bridge->display;
|
||||
|
||||
dp->convert_to_dp_mode(dp, bridge->dp_panel, adjusted_mode,
|
||||
&bridge->dp_mode);
|
||||
}
|
||||
|
||||
static bool dp_bridge_mode_fixup(struct drm_bridge *drm_bridge,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
bool ret = true;
|
||||
struct dp_display_mode dp_mode;
|
||||
struct dp_bridge *bridge;
|
||||
struct dp_display *dp;
|
||||
|
||||
if (!drm_bridge || !mode || !adjusted_mode) {
|
||||
DP_ERR("Invalid params\n");
|
||||
ret = false;
|
||||
goto end;
|
||||
}
|
||||
|
||||
bridge = to_dp_bridge(drm_bridge);
|
||||
if (!bridge->connector) {
|
||||
DP_ERR("Invalid connector\n");
|
||||
ret = false;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!bridge->dp_panel) {
|
||||
DP_ERR("Invalid dp_panel\n");
|
||||
ret = false;
|
||||
goto end;
|
||||
}
|
||||
|
||||
dp = bridge->display;
|
||||
|
||||
dp->convert_to_dp_mode(dp, bridge->dp_panel, mode, &dp_mode);
|
||||
convert_to_drm_mode(&dp_mode, adjusted_mode);
|
||||
end:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct drm_bridge_funcs dp_bridge_ops = {
|
||||
.attach = dp_bridge_attach,
|
||||
.mode_fixup = dp_bridge_mode_fixup,
|
||||
.pre_enable = dp_bridge_pre_enable,
|
||||
.enable = dp_bridge_enable,
|
||||
.disable = dp_bridge_disable,
|
||||
.post_disable = dp_bridge_post_disable,
|
||||
.mode_set = dp_bridge_mode_set,
|
||||
};
|
||||
|
||||
int dp_connector_config_hdr(struct drm_connector *connector, void *display,
|
||||
struct sde_connector_state *c_state)
|
||||
{
|
||||
struct dp_display *dp = display;
|
||||
struct sde_connector *sde_conn;
|
||||
|
||||
if (!display || !c_state || !connector) {
|
||||
DP_ERR("invalid params\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sde_conn = to_sde_connector(connector);
|
||||
if (!sde_conn->drv_panel) {
|
||||
DP_ERR("invalid dp panel\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return dp->config_hdr(dp, sde_conn->drv_panel, &c_state->hdr_meta,
|
||||
c_state->dyn_hdr_meta.dynamic_hdr_update);
|
||||
}
|
||||
|
||||
int dp_connector_set_colorspace(struct drm_connector *connector,
|
||||
void *display)
|
||||
{
|
||||
struct dp_display *dp_display = display;
|
||||
struct sde_connector *sde_conn;
|
||||
|
||||
if (!dp_display || !connector)
|
||||
return -EINVAL;
|
||||
|
||||
sde_conn = to_sde_connector(connector);
|
||||
if (!sde_conn->drv_panel) {
|
||||
pr_err("invalid dp panel\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return dp_display->set_colorspace(dp_display,
|
||||
sde_conn->drv_panel, connector->state->colorspace);
|
||||
}
|
||||
|
||||
int dp_connector_post_init(struct drm_connector *connector, void *display)
|
||||
{
|
||||
int rc;
|
||||
struct dp_display *dp_display = display;
|
||||
struct sde_connector *sde_conn;
|
||||
|
||||
if (!dp_display || !connector)
|
||||
return -EINVAL;
|
||||
|
||||
dp_display->base_connector = connector;
|
||||
dp_display->bridge->connector = connector;
|
||||
|
||||
if (dp_display->post_init) {
|
||||
rc = dp_display->post_init(dp_display);
|
||||
if (rc)
|
||||
goto end;
|
||||
}
|
||||
|
||||
sde_conn = to_sde_connector(connector);
|
||||
dp_display->bridge->dp_panel = sde_conn->drv_panel;
|
||||
|
||||
rc = dp_mst_init(dp_display);
|
||||
|
||||
if (dp_display->dsc_cont_pps)
|
||||
sde_conn->ops.update_pps = NULL;
|
||||
|
||||
end:
|
||||
return rc;
|
||||
}
|
||||
|
||||
int dp_connector_get_mode_info(struct drm_connector *connector,
|
||||
const struct drm_display_mode *drm_mode,
|
||||
struct msm_mode_info *mode_info,
|
||||
void *display, const struct msm_resource_caps_info *avail_res)
|
||||
{
|
||||
const u32 single_intf = 1;
|
||||
const u32 no_enc = 0;
|
||||
struct msm_display_topology *topology;
|
||||
struct sde_connector *sde_conn;
|
||||
struct dp_panel *dp_panel;
|
||||
struct dp_display_mode dp_mode;
|
||||
struct dp_display *dp_disp = display;
|
||||
struct msm_drm_private *priv;
|
||||
struct msm_resource_caps_info avail_dp_res;
|
||||
int rc = 0;
|
||||
|
||||
if (!drm_mode || !mode_info || !avail_res ||
|
||||
!avail_res->max_mixer_width || !connector || !display ||
|
||||
!connector->dev || !connector->dev->dev_private) {
|
||||
DP_ERR("invalid params\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(mode_info, 0, sizeof(*mode_info));
|
||||
|
||||
sde_conn = to_sde_connector(connector);
|
||||
dp_panel = sde_conn->drv_panel;
|
||||
priv = connector->dev->dev_private;
|
||||
|
||||
topology = &mode_info->topology;
|
||||
|
||||
rc = dp_disp->get_available_dp_resources(dp_disp, avail_res,
|
||||
&avail_dp_res);
|
||||
if (rc) {
|
||||
DP_ERR("error getting max dp resources. rc:%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = msm_get_mixer_count(priv, drm_mode, &avail_dp_res,
|
||||
&topology->num_lm);
|
||||
if (rc) {
|
||||
DP_ERR("error getting mixer count. rc:%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
topology->num_enc = no_enc;
|
||||
topology->num_intf = single_intf;
|
||||
|
||||
mode_info->frame_rate = drm_mode->vrefresh;
|
||||
mode_info->vtotal = drm_mode->vtotal;
|
||||
|
||||
mode_info->wide_bus_en = dp_panel->widebus_en;
|
||||
|
||||
dp_disp->convert_to_dp_mode(dp_disp, dp_panel, drm_mode, &dp_mode);
|
||||
|
||||
if (dp_mode.timing.comp_info.comp_ratio > 1) {
|
||||
memcpy(&mode_info->comp_info,
|
||||
&dp_mode.timing.comp_info,
|
||||
sizeof(mode_info->comp_info));
|
||||
|
||||
topology->num_enc = topology->num_lm;
|
||||
topology->comp_type = mode_info->comp_info.comp_type;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dp_connector_get_info(struct drm_connector *connector,
|
||||
struct msm_display_info *info, void *data)
|
||||
{
|
||||
struct dp_display *display = data;
|
||||
|
||||
if (!info || !display || !display->drm_dev) {
|
||||
DP_ERR("invalid params\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
info->intf_type = DRM_MODE_CONNECTOR_DisplayPort;
|
||||
|
||||
info->num_of_h_tiles = 1;
|
||||
info->h_tile_instance[0] = 0;
|
||||
info->is_connected = display->is_sst_connected;
|
||||
info->capabilities = MSM_DISPLAY_CAP_VID_MODE | MSM_DISPLAY_CAP_EDID |
|
||||
MSM_DISPLAY_CAP_HOT_PLUG;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum drm_connector_status dp_connector_detect(struct drm_connector *conn,
|
||||
bool force,
|
||||
void *display)
|
||||
{
|
||||
enum drm_connector_status status = connector_status_unknown;
|
||||
struct msm_display_info info;
|
||||
int rc;
|
||||
|
||||
if (!conn || !display)
|
||||
return status;
|
||||
|
||||
/* get display dp_info */
|
||||
memset(&info, 0x0, sizeof(info));
|
||||
rc = dp_connector_get_info(conn, &info, display);
|
||||
if (rc) {
|
||||
DP_ERR("failed to get display info, rc=%d\n", rc);
|
||||
return connector_status_disconnected;
|
||||
}
|
||||
|
||||
if (info.capabilities & MSM_DISPLAY_CAP_HOT_PLUG)
|
||||
status = (info.is_connected ? connector_status_connected :
|
||||
connector_status_disconnected);
|
||||
else
|
||||
status = connector_status_connected;
|
||||
|
||||
conn->display_info.width_mm = info.width_mm;
|
||||
conn->display_info.height_mm = info.height_mm;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void dp_connector_post_open(struct drm_connector *connector, void *display)
|
||||
{
|
||||
struct dp_display *dp;
|
||||
|
||||
if (!display) {
|
||||
DP_ERR("invalid input\n");
|
||||
return;
|
||||
}
|
||||
|
||||
dp = display;
|
||||
|
||||
if (dp->post_open)
|
||||
dp->post_open(dp);
|
||||
}
|
||||
|
||||
int dp_connector_atomic_check(struct drm_connector *connector,
|
||||
void *display,
|
||||
struct drm_atomic_state *a_state)
|
||||
{
|
||||
struct sde_connector *sde_conn;
|
||||
struct drm_connector_state *old_state;
|
||||
struct drm_connector_state *c_state;
|
||||
|
||||
if (!connector || !display || !a_state)
|
||||
return -EINVAL;
|
||||
|
||||
c_state = drm_atomic_get_new_connector_state(a_state, connector);
|
||||
old_state =
|
||||
drm_atomic_get_old_connector_state(a_state, connector);
|
||||
|
||||
if (!old_state || !c_state)
|
||||
return -EINVAL;
|
||||
|
||||
sde_conn = to_sde_connector(connector);
|
||||
|
||||
/*
|
||||
* Marking the colorspace has been changed
|
||||
* the flag shall be checked in the pre_kickoff
|
||||
* to configure the new colorspace in HW
|
||||
*/
|
||||
if (c_state->colorspace != old_state->colorspace) {
|
||||
DP_DEBUG("colorspace has been updated\n");
|
||||
sde_conn->colorspace_updated = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dp_connector_get_modes(struct drm_connector *connector,
|
||||
void *display, const struct msm_resource_caps_info *avail_res)
|
||||
{
|
||||
int rc = 0;
|
||||
struct dp_display *dp;
|
||||
struct dp_display_mode *dp_mode = NULL;
|
||||
struct drm_display_mode *m, drm_mode;
|
||||
struct sde_connector *sde_conn;
|
||||
|
||||
if (!connector || !display)
|
||||
return 0;
|
||||
|
||||
sde_conn = to_sde_connector(connector);
|
||||
if (!sde_conn->drv_panel) {
|
||||
DP_ERR("invalid dp panel\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
dp = display;
|
||||
|
||||
dp_mode = kzalloc(sizeof(*dp_mode), GFP_KERNEL);
|
||||
if (!dp_mode)
|
||||
return 0;
|
||||
|
||||
/* pluggable case assumes EDID is read when HPD */
|
||||
if (dp->is_sst_connected) {
|
||||
rc = dp->get_modes(dp, sde_conn->drv_panel, dp_mode);
|
||||
if (!rc)
|
||||
DP_ERR("failed to get DP sink modes, rc=%d\n", rc);
|
||||
|
||||
if (dp_mode->timing.pixel_clk_khz) { /* valid DP mode */
|
||||
memset(&drm_mode, 0x0, sizeof(drm_mode));
|
||||
convert_to_drm_mode(dp_mode, &drm_mode);
|
||||
m = drm_mode_duplicate(connector->dev, &drm_mode);
|
||||
if (!m) {
|
||||
DP_ERR("failed to add mode %ux%u\n",
|
||||
drm_mode.hdisplay,
|
||||
drm_mode.vdisplay);
|
||||
kfree(dp_mode);
|
||||
return 0;
|
||||
}
|
||||
m->width_mm = connector->display_info.width_mm;
|
||||
m->height_mm = connector->display_info.height_mm;
|
||||
drm_mode_probed_add(connector, m);
|
||||
}
|
||||
} else {
|
||||
DP_ERR("No sink connected\n");
|
||||
}
|
||||
kfree(dp_mode);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int dp_drm_bridge_init(void *data, struct drm_encoder *encoder,
|
||||
u32 max_mixer_count, u32 max_dsc_count)
|
||||
{
|
||||
int rc = 0;
|
||||
struct dp_bridge *bridge;
|
||||
struct drm_device *dev;
|
||||
struct dp_display *display = data;
|
||||
struct msm_drm_private *priv = NULL;
|
||||
|
||||
bridge = kzalloc(sizeof(*bridge), GFP_KERNEL);
|
||||
if (!bridge) {
|
||||
rc = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
dev = display->drm_dev;
|
||||
bridge->display = display;
|
||||
bridge->base.funcs = &dp_bridge_ops;
|
||||
bridge->base.encoder = encoder;
|
||||
|
||||
priv = dev->dev_private;
|
||||
|
||||
rc = drm_bridge_attach(encoder, &bridge->base, NULL);
|
||||
if (rc) {
|
||||
DP_ERR("failed to attach bridge, rc=%d\n", rc);
|
||||
goto error_free_bridge;
|
||||
}
|
||||
|
||||
rc = display->request_irq(display);
|
||||
if (rc) {
|
||||
DP_ERR("request_irq failed, rc=%d\n", rc);
|
||||
goto error_free_bridge;
|
||||
}
|
||||
|
||||
encoder->bridge = &bridge->base;
|
||||
priv->bridges[priv->num_bridges++] = &bridge->base;
|
||||
display->bridge = bridge;
|
||||
display->max_mixer_count = max_mixer_count;
|
||||
display->max_dsc_count = max_dsc_count;
|
||||
|
||||
return 0;
|
||||
error_free_bridge:
|
||||
kfree(bridge);
|
||||
error:
|
||||
return rc;
|
||||
}
|
||||
|
||||
void dp_drm_bridge_deinit(void *data)
|
||||
{
|
||||
struct dp_display *display = data;
|
||||
struct dp_bridge *bridge = display->bridge;
|
||||
|
||||
if (bridge && bridge->base.encoder)
|
||||
bridge->base.encoder->bridge = NULL;
|
||||
|
||||
kfree(bridge);
|
||||
}
|
||||
|
||||
enum drm_mode_status dp_connector_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode, void *display,
|
||||
const struct msm_resource_caps_info *avail_res)
|
||||
{
|
||||
int rc = 0;
|
||||
struct dp_display *dp_disp;
|
||||
struct sde_connector *sde_conn;
|
||||
struct msm_resource_caps_info avail_dp_res;
|
||||
|
||||
if (!mode || !display || !connector) {
|
||||
DP_ERR("invalid params\n");
|
||||
return MODE_ERROR;
|
||||
}
|
||||
|
||||
sde_conn = to_sde_connector(connector);
|
||||
if (!sde_conn->drv_panel) {
|
||||
DP_ERR("invalid dp panel\n");
|
||||
return MODE_ERROR;
|
||||
}
|
||||
|
||||
dp_disp = display;
|
||||
mode->vrefresh = drm_mode_vrefresh(mode);
|
||||
|
||||
rc = dp_disp->get_available_dp_resources(dp_disp, avail_res,
|
||||
&avail_dp_res);
|
||||
if (rc) {
|
||||
DP_ERR("error getting max dp resources. rc:%d\n", rc);
|
||||
return MODE_ERROR;
|
||||
}
|
||||
|
||||
return dp_disp->validate_mode(dp_disp, sde_conn->drv_panel,
|
||||
mode, &avail_dp_res);
|
||||
}
|
||||
|
||||
int dp_connector_update_pps(struct drm_connector *connector,
|
||||
char *pps_cmd, void *display)
|
||||
{
|
||||
struct dp_display *dp_disp;
|
||||
struct sde_connector *sde_conn;
|
||||
|
||||
if (!display || !connector) {
|
||||
DP_ERR("invalid params\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sde_conn = to_sde_connector(connector);
|
||||
if (!sde_conn->drv_panel) {
|
||||
DP_ERR("invalid dp panel\n");
|
||||
return MODE_ERROR;
|
||||
}
|
||||
|
||||
dp_disp = display;
|
||||
return dp_disp->update_pps(dp_disp, connector, pps_cmd);
|
||||
}
|
||||
|
||||
int dp_connector_install_properties(void *display, struct drm_connector *conn)
|
||||
{
|
||||
struct dp_display *dp_display = display;
|
||||
struct drm_connector *base_conn;
|
||||
int rc;
|
||||
|
||||
if (!display || !conn) {
|
||||
DP_ERR("invalid params\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
base_conn = dp_display->base_connector;
|
||||
|
||||
/*
|
||||
* Create the property on the base connector during probe time and then
|
||||
* attach the same property onto new connector objects created for MST
|
||||
*/
|
||||
if (!base_conn->colorspace_property) {
|
||||
/* This is the base connector. create the drm property */
|
||||
rc = drm_mode_create_dp_colorspace_property(base_conn);
|
||||
if (rc)
|
||||
return rc;
|
||||
} else {
|
||||
conn->colorspace_property = base_conn->colorspace_property;
|
||||
}
|
||||
|
||||
drm_object_attach_property(&conn->base, conn->colorspace_property, 0);
|
||||
|
||||
return 0;
|
||||
}
|
258
techpack/display/msm/dp/dp_drm.h
Normal file
258
techpack/display/msm/dp/dp_drm.h
Normal file
@ -0,0 +1,258 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _DP_DRM_H_
|
||||
#define _DP_DRM_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_crtc.h>
|
||||
|
||||
#include "msm_drv.h"
|
||||
#include "dp_display.h"
|
||||
|
||||
struct dp_bridge {
|
||||
struct drm_bridge base;
|
||||
u32 id;
|
||||
|
||||
struct drm_connector *connector;
|
||||
struct dp_display *display;
|
||||
struct dp_display_mode dp_mode;
|
||||
void *dp_panel;
|
||||
};
|
||||
|
||||
|
||||
#if IS_ENABLED(CONFIG_DRM_MSM_DP)
|
||||
/**
|
||||
* dp_connector_config_hdr - callback to configure HDR
|
||||
* @connector: Pointer to drm connector structure
|
||||
* @display: Pointer to private display handle
|
||||
* @c_state: connect state data
|
||||
* Returns: Zero on success
|
||||
*/
|
||||
int dp_connector_config_hdr(struct drm_connector *connector,
|
||||
void *display,
|
||||
struct sde_connector_state *c_state);
|
||||
|
||||
/**
|
||||
* dp_connector_atomic_check - callback to perform atomic
|
||||
* check for DP
|
||||
* @connector: Pointer to drm connector structure
|
||||
* @display: Pointer to private display handle
|
||||
* @c_state: connect state data
|
||||
* Returns: Zero on success
|
||||
*/
|
||||
int dp_connector_atomic_check(struct drm_connector *connector,
|
||||
void *display,
|
||||
struct drm_atomic_state *state);
|
||||
|
||||
/**
|
||||
* dp_connector_set_colorspace - callback to set new colorspace
|
||||
* @connector: Pointer to drm connector structure
|
||||
* @display: Pointer to private display handle
|
||||
* Returns: Zero on success
|
||||
*/
|
||||
int dp_connector_set_colorspace(struct drm_connector *connector,
|
||||
void *display);
|
||||
|
||||
/**
|
||||
* dp_connector_post_init - callback to perform additional initialization steps
|
||||
* @connector: Pointer to drm connector structure
|
||||
* @display: Pointer to private display handle
|
||||
* Returns: Zero on success
|
||||
*/
|
||||
int dp_connector_post_init(struct drm_connector *connector, void *display);
|
||||
|
||||
/**
|
||||
* dp_connector_detect - callback to determine if connector is connected
|
||||
* @connector: Pointer to drm connector structure
|
||||
* @force: Force detect setting from drm framework
|
||||
* @display: Pointer to private display handle
|
||||
* Returns: Connector 'is connected' status
|
||||
*/
|
||||
enum drm_connector_status dp_connector_detect(struct drm_connector *conn,
|
||||
bool force,
|
||||
void *display);
|
||||
|
||||
/**
|
||||
* dp_connector_get_modes - callback to add drm modes via drm_mode_probed_add()
|
||||
* @connector: Pointer to drm connector structure
|
||||
* @display: Pointer to private display handle
|
||||
* @avail_res: Pointer with curr available resources
|
||||
* Returns: Number of modes added
|
||||
*/
|
||||
int dp_connector_get_modes(struct drm_connector *connector,
|
||||
void *display, const struct msm_resource_caps_info *avail_res);
|
||||
|
||||
/**
|
||||
* dp_connector_mode_valid - callback to determine if specified mode is valid
|
||||
* @connector: Pointer to drm connector structure
|
||||
* @mode: Pointer to drm mode structure
|
||||
* @display: Pointer to private display handle
|
||||
* @avail_res: Pointer with curr available resources
|
||||
* Returns: Validity status for specified mode
|
||||
*/
|
||||
enum drm_mode_status dp_connector_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode,
|
||||
void *display, const struct msm_resource_caps_info *avail_res);
|
||||
|
||||
/**
|
||||
* dp_connector_get_mode_info - retrieve information of the mode selected
|
||||
* @connector: Pointer to drm connector structure
|
||||
* @drm_mode: Display mode set for the display
|
||||
* @mode_info: Out parameter. Information of the mode
|
||||
* @display: Pointer to private display structure
|
||||
* @avail_res: Pointer with curr available resources
|
||||
* Returns: zero on success
|
||||
*/
|
||||
int dp_connector_get_mode_info(struct drm_connector *connector,
|
||||
const struct drm_display_mode *drm_mode,
|
||||
struct msm_mode_info *mode_info,
|
||||
void *display, const struct msm_resource_caps_info *avail_res);
|
||||
|
||||
/**
|
||||
* dp_connector_get_info - retrieve connector display info
|
||||
* @connector: Pointer to drm connector structure
|
||||
* @info: Out parameter. Information of the connected display
|
||||
* @display: Pointer to private display structure
|
||||
* Returns: zero on success
|
||||
*/
|
||||
int dp_connector_get_info(struct drm_connector *connector,
|
||||
struct msm_display_info *info, void *display);
|
||||
|
||||
/**
|
||||
* dp_connector_post_open - handle the post open functionalities
|
||||
* @connector: Pointer to drm connector structure
|
||||
* @display: Pointer to private display structure
|
||||
*/
|
||||
void dp_connector_post_open(struct drm_connector *connector, void *display);
|
||||
|
||||
/**
|
||||
* dp_drm_bridge_init- drm dp bridge initialize
|
||||
* @display: Pointer to private display structure
|
||||
* @encoder: encoder for this dp bridge
|
||||
* @max_mixer_count: max available mixers for dp display
|
||||
* @max_dsc_count: max available dsc for dp display
|
||||
*/
|
||||
int dp_drm_bridge_init(void *display, struct drm_encoder *encoder,
|
||||
u32 max_mixer_count, u32 max_dsc_count);
|
||||
|
||||
void dp_drm_bridge_deinit(void *display);
|
||||
|
||||
/**
|
||||
* convert_to_drm_mode - convert dp mode to drm mode
|
||||
* @dp_mode: Point to dp mode
|
||||
* @drm_mode: Pointer to drm mode
|
||||
*/
|
||||
void convert_to_drm_mode(const struct dp_display_mode *dp_mode,
|
||||
struct drm_display_mode *drm_mode);
|
||||
|
||||
/**
|
||||
* dp_connector_update_pps - update pps for given connector
|
||||
* @dp_mode: Point to dp mode
|
||||
* @pps_cmd: PPS packet
|
||||
* @display: Pointer to private display structure
|
||||
*/
|
||||
int dp_connector_update_pps(struct drm_connector *connector,
|
||||
char *pps_cmd, void *display);
|
||||
|
||||
/**
|
||||
* dp_connector_install_properties - install drm properties
|
||||
* @display: Pointer to private display structure
|
||||
* @conn: Pointer to connector
|
||||
*/
|
||||
int dp_connector_install_properties(void *display,
|
||||
struct drm_connector *conn);
|
||||
|
||||
#else
|
||||
static inline int dp_connector_config_hdr(struct drm_connector *connector,
|
||||
void *display, struct sde_connector_state *c_state)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int dp_connector_atomic_check(struct drm_connector *connector,
|
||||
void *display, struct drm_atomic_state *state)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int dp_connector_set_colorspace(struct drm_connector *connector,
|
||||
void *display)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int dp_connector_post_init(struct drm_connector *connector,
|
||||
void *display)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline enum drm_connector_status dp_connector_detect(
|
||||
struct drm_connector *conn,
|
||||
bool force,
|
||||
void *display)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static inline int dp_connector_get_modes(struct drm_connector *connector,
|
||||
void *display, const struct msm_resource_caps_info *avail_res)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline enum drm_mode_status dp_connector_mode_valid(
|
||||
struct drm_connector *connector,
|
||||
struct drm_display_mode *mode,
|
||||
void *display, const struct msm_resource_caps_info *avail_res)
|
||||
{
|
||||
return MODE_OK;
|
||||
}
|
||||
|
||||
static inline int dp_connector_get_mode_info(struct drm_connector *connector,
|
||||
const struct drm_display_mode *drm_mode,
|
||||
struct msm_mode_info *mode_info,
|
||||
void *display, const struct msm_resource_caps_info *avail_res)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int dp_connector_get_info(struct drm_connector *connector,
|
||||
struct msm_display_info *info, void *display)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void dp_connector_post_open(struct drm_connector *connector,
|
||||
void *display)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int dp_drm_bridge_init(void *display, struct drm_encoder *encoder,
|
||||
u32 max_mixer_count, u32 max_dsc_count)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void dp_drm_bridge_deinit(void *display)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void convert_to_drm_mode(const struct dp_display_mode *dp_mode,
|
||||
struct drm_display_mode *drm_mode)
|
||||
{
|
||||
}
|
||||
|
||||
static int dp_connector_install_properties(void *display,
|
||||
struct drm_connector *conn)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_DRM_MSM_DP */
|
||||
|
||||
#endif /* _DP_DRM_H_ */
|
296
techpack/display/msm/dp/dp_gpio_hpd.c
Normal file
296
techpack/display/msm/dp/dp_gpio_hpd.c
Normal file
@ -0,0 +1,296 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/sde_io_util.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include "dp_gpio_hpd.h"
|
||||
#include "dp_debug.h"
|
||||
|
||||
struct dp_gpio_hpd_private {
|
||||
struct device *dev;
|
||||
struct dp_hpd base;
|
||||
struct dss_gpio gpio_cfg;
|
||||
struct delayed_work work;
|
||||
struct dp_hpd_cb *cb;
|
||||
int irq;
|
||||
bool hpd;
|
||||
};
|
||||
|
||||
static int dp_gpio_hpd_connect(struct dp_gpio_hpd_private *gpio_hpd, bool hpd)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (!gpio_hpd) {
|
||||
DP_ERR("invalid input\n");
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
gpio_hpd->base.hpd_high = hpd;
|
||||
gpio_hpd->base.alt_mode_cfg_done = hpd;
|
||||
gpio_hpd->base.hpd_irq = false;
|
||||
|
||||
if (!gpio_hpd->cb ||
|
||||
!gpio_hpd->cb->configure ||
|
||||
!gpio_hpd->cb->disconnect) {
|
||||
DP_ERR("invalid cb\n");
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (hpd)
|
||||
rc = gpio_hpd->cb->configure(gpio_hpd->dev);
|
||||
else
|
||||
rc = gpio_hpd->cb->disconnect(gpio_hpd->dev);
|
||||
|
||||
error:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int dp_gpio_hpd_attention(struct dp_gpio_hpd_private *gpio_hpd)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (!gpio_hpd) {
|
||||
DP_ERR("invalid input\n");
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
gpio_hpd->base.hpd_irq = true;
|
||||
|
||||
if (gpio_hpd->cb && gpio_hpd->cb->attention)
|
||||
rc = gpio_hpd->cb->attention(gpio_hpd->dev);
|
||||
|
||||
error:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static irqreturn_t dp_gpio_isr(int unused, void *data)
|
||||
{
|
||||
struct dp_gpio_hpd_private *gpio_hpd = data;
|
||||
u32 const disconnect_timeout_retry = 50;
|
||||
bool hpd;
|
||||
int i;
|
||||
|
||||
if (!gpio_hpd)
|
||||
return IRQ_NONE;
|
||||
|
||||
hpd = gpio_get_value_cansleep(gpio_hpd->gpio_cfg.gpio);
|
||||
|
||||
if (!gpio_hpd->hpd && hpd) {
|
||||
gpio_hpd->hpd = true;
|
||||
queue_delayed_work(system_wq, &gpio_hpd->work, 0);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
if (!gpio_hpd->hpd)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
/* In DP 1.2 spec, 100msec is recommended for the detection
|
||||
* of HPD connect event. Here we'll poll HPD status for
|
||||
* 50x2ms = 100ms and if HPD is always low, we know DP is
|
||||
* disconnected. If HPD is high, HPD_IRQ will be handled
|
||||
*/
|
||||
for (i = 0; i < disconnect_timeout_retry; i++) {
|
||||
if (hpd) {
|
||||
dp_gpio_hpd_attention(gpio_hpd);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
usleep_range(2000, 2100);
|
||||
hpd = gpio_get_value_cansleep(gpio_hpd->gpio_cfg.gpio);
|
||||
}
|
||||
|
||||
gpio_hpd->hpd = false;
|
||||
queue_delayed_work(system_wq, &gpio_hpd->work, 0);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void dp_gpio_hpd_work(struct work_struct *work)
|
||||
{
|
||||
struct delayed_work *dw = to_delayed_work(work);
|
||||
struct dp_gpio_hpd_private *gpio_hpd = container_of(dw,
|
||||
struct dp_gpio_hpd_private, work);
|
||||
int ret;
|
||||
|
||||
if (gpio_hpd->hpd) {
|
||||
devm_free_irq(gpio_hpd->dev,
|
||||
gpio_hpd->irq, gpio_hpd);
|
||||
ret = devm_request_threaded_irq(gpio_hpd->dev,
|
||||
gpio_hpd->irq, NULL,
|
||||
dp_gpio_isr,
|
||||
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
|
||||
"dp-gpio-intp", gpio_hpd);
|
||||
dp_gpio_hpd_connect(gpio_hpd, true);
|
||||
} else {
|
||||
devm_free_irq(gpio_hpd->dev,
|
||||
gpio_hpd->irq, gpio_hpd);
|
||||
ret = devm_request_threaded_irq(gpio_hpd->dev,
|
||||
gpio_hpd->irq, NULL,
|
||||
dp_gpio_isr,
|
||||
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
|
||||
"dp-gpio-intp", gpio_hpd);
|
||||
dp_gpio_hpd_connect(gpio_hpd, false);
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
DP_ERR("Cannot claim IRQ dp-gpio-intp\n");
|
||||
}
|
||||
|
||||
static int dp_gpio_hpd_simulate_connect(struct dp_hpd *dp_hpd, bool hpd)
|
||||
{
|
||||
int rc = 0;
|
||||
struct dp_gpio_hpd_private *gpio_hpd;
|
||||
|
||||
if (!dp_hpd) {
|
||||
DP_ERR("invalid input\n");
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
gpio_hpd = container_of(dp_hpd, struct dp_gpio_hpd_private, base);
|
||||
|
||||
dp_gpio_hpd_connect(gpio_hpd, hpd);
|
||||
error:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int dp_gpio_hpd_simulate_attention(struct dp_hpd *dp_hpd, int vdo)
|
||||
{
|
||||
int rc = 0;
|
||||
struct dp_gpio_hpd_private *gpio_hpd;
|
||||
|
||||
if (!dp_hpd) {
|
||||
DP_ERR("invalid input\n");
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
gpio_hpd = container_of(dp_hpd, struct dp_gpio_hpd_private, base);
|
||||
|
||||
dp_gpio_hpd_attention(gpio_hpd);
|
||||
error:
|
||||
return rc;
|
||||
}
|
||||
|
||||
int dp_gpio_hpd_register(struct dp_hpd *dp_hpd)
|
||||
{
|
||||
struct dp_gpio_hpd_private *gpio_hpd;
|
||||
int edge;
|
||||
int rc = 0;
|
||||
|
||||
if (!dp_hpd)
|
||||
return -EINVAL;
|
||||
|
||||
gpio_hpd = container_of(dp_hpd, struct dp_gpio_hpd_private, base);
|
||||
|
||||
gpio_hpd->hpd = gpio_get_value_cansleep(gpio_hpd->gpio_cfg.gpio);
|
||||
|
||||
edge = gpio_hpd->hpd ? IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING;
|
||||
rc = devm_request_threaded_irq(gpio_hpd->dev, gpio_hpd->irq, NULL,
|
||||
dp_gpio_isr,
|
||||
edge | IRQF_ONESHOT,
|
||||
"dp-gpio-intp", gpio_hpd);
|
||||
if (rc) {
|
||||
DP_ERR("Failed to request INTP threaded IRQ: %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (gpio_hpd->hpd)
|
||||
queue_delayed_work(system_wq, &gpio_hpd->work, 0);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
struct dp_hpd *dp_gpio_hpd_get(struct device *dev,
|
||||
struct dp_hpd_cb *cb)
|
||||
{
|
||||
int rc = 0;
|
||||
const char *hpd_gpio_name = "qcom,dp-hpd-gpio";
|
||||
struct dp_gpio_hpd_private *gpio_hpd;
|
||||
struct dp_pinctrl pinctrl = {0};
|
||||
|
||||
if (!dev || !cb) {
|
||||
DP_ERR("invalid device\n");
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
gpio_hpd = devm_kzalloc(dev, sizeof(*gpio_hpd), GFP_KERNEL);
|
||||
if (!gpio_hpd) {
|
||||
rc = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
pinctrl.pin = devm_pinctrl_get(dev);
|
||||
if (!IS_ERR_OR_NULL(pinctrl.pin)) {
|
||||
pinctrl.state_hpd_active = pinctrl_lookup_state(pinctrl.pin,
|
||||
"mdss_dp_hpd_active");
|
||||
if (!IS_ERR_OR_NULL(pinctrl.state_hpd_active)) {
|
||||
rc = pinctrl_select_state(pinctrl.pin,
|
||||
pinctrl.state_hpd_active);
|
||||
if (rc) {
|
||||
DP_ERR("failed to set hpd active state\n");
|
||||
goto gpio_error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gpio_hpd->gpio_cfg.gpio = of_get_named_gpio(dev->of_node,
|
||||
hpd_gpio_name, 0);
|
||||
if (!gpio_is_valid(gpio_hpd->gpio_cfg.gpio)) {
|
||||
DP_ERR("%s gpio not specified\n", hpd_gpio_name);
|
||||
rc = -EINVAL;
|
||||
goto gpio_error;
|
||||
}
|
||||
|
||||
strlcpy(gpio_hpd->gpio_cfg.gpio_name, hpd_gpio_name,
|
||||
sizeof(gpio_hpd->gpio_cfg.gpio_name));
|
||||
gpio_hpd->gpio_cfg.value = 0;
|
||||
|
||||
rc = gpio_request(gpio_hpd->gpio_cfg.gpio,
|
||||
gpio_hpd->gpio_cfg.gpio_name);
|
||||
if (rc) {
|
||||
DP_ERR("%s: failed to request gpio\n", hpd_gpio_name);
|
||||
goto gpio_error;
|
||||
}
|
||||
gpio_direction_input(gpio_hpd->gpio_cfg.gpio);
|
||||
|
||||
gpio_hpd->dev = dev;
|
||||
gpio_hpd->cb = cb;
|
||||
gpio_hpd->irq = gpio_to_irq(gpio_hpd->gpio_cfg.gpio);
|
||||
INIT_DELAYED_WORK(&gpio_hpd->work, dp_gpio_hpd_work);
|
||||
|
||||
gpio_hpd->base.simulate_connect = dp_gpio_hpd_simulate_connect;
|
||||
gpio_hpd->base.simulate_attention = dp_gpio_hpd_simulate_attention;
|
||||
gpio_hpd->base.register_hpd = dp_gpio_hpd_register;
|
||||
|
||||
return &gpio_hpd->base;
|
||||
|
||||
gpio_error:
|
||||
devm_kfree(dev, gpio_hpd);
|
||||
error:
|
||||
return ERR_PTR(rc);
|
||||
}
|
||||
|
||||
void dp_gpio_hpd_put(struct dp_hpd *dp_hpd)
|
||||
{
|
||||
struct dp_gpio_hpd_private *gpio_hpd;
|
||||
|
||||
if (!dp_hpd)
|
||||
return;
|
||||
|
||||
gpio_hpd = container_of(dp_hpd, struct dp_gpio_hpd_private, base);
|
||||
|
||||
gpio_free(gpio_hpd->gpio_cfg.gpio);
|
||||
devm_kfree(gpio_hpd->dev, gpio_hpd);
|
||||
}
|
32
techpack/display/msm/dp/dp_gpio_hpd.h
Normal file
32
techpack/display/msm/dp/dp_gpio_hpd.h
Normal file
@ -0,0 +1,32 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _DP_GPIO_HPD_H_
|
||||
#define _DP_GPIO_HPD_H_
|
||||
|
||||
#include "dp_hpd.h"
|
||||
|
||||
/**
|
||||
* dp_gpio_hpd_get() - configure and get the DisplayPlot HPD module data
|
||||
*
|
||||
* @dev: device instance of the caller
|
||||
* return: pointer to allocated gpio hpd module data
|
||||
*
|
||||
* This function sets up the gpio hpd module
|
||||
*/
|
||||
struct dp_hpd *dp_gpio_hpd_get(struct device *dev,
|
||||
struct dp_hpd_cb *cb);
|
||||
|
||||
/**
|
||||
* dp_gpio_hpd_put()
|
||||
*
|
||||
* Cleans up dp_hpd instance
|
||||
*
|
||||
* @hpd: instance of gpio_hpd
|
||||
*/
|
||||
void dp_gpio_hpd_put(struct dp_hpd *hpd);
|
||||
|
||||
#endif /* _DP_GPIO_HPD_H_ */
|
1032
techpack/display/msm/dp/dp_hdcp2p2.c
Normal file
1032
techpack/display/msm/dp/dp_hdcp2p2.c
Normal file
File diff suppressed because it is too large
Load Diff
111
techpack/display/msm/dp/dp_hpd.c
Normal file
111
techpack/display/msm/dp/dp_hpd.c
Normal file
@ -0,0 +1,111 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include "dp_hpd.h"
|
||||
#include "dp_altmode.h"
|
||||
#include "dp_usbpd.h"
|
||||
#include "dp_gpio_hpd.h"
|
||||
#include "dp_lphw_hpd.h"
|
||||
#include "dp_debug.h"
|
||||
|
||||
static void dp_hpd_host_init(struct dp_hpd *dp_hpd,
|
||||
struct dp_catalog_hpd *catalog)
|
||||
{
|
||||
if (!catalog) {
|
||||
DP_ERR("invalid input\n");
|
||||
return;
|
||||
}
|
||||
catalog->config_hpd(catalog, true);
|
||||
}
|
||||
|
||||
static void dp_hpd_host_deinit(struct dp_hpd *dp_hpd,
|
||||
struct dp_catalog_hpd *catalog)
|
||||
{
|
||||
if (!catalog) {
|
||||
DP_ERR("invalid input\n");
|
||||
return;
|
||||
}
|
||||
catalog->config_hpd(catalog, false);
|
||||
}
|
||||
|
||||
static void dp_hpd_isr(struct dp_hpd *dp_hpd)
|
||||
{
|
||||
}
|
||||
|
||||
struct dp_hpd *dp_hpd_get(struct device *dev, struct dp_parser *parser,
|
||||
struct dp_catalog_hpd *catalog, struct dp_hpd_cb *cb)
|
||||
{
|
||||
struct dp_hpd *dp_hpd;
|
||||
|
||||
if (parser->no_aux_switch && parser->lphw_hpd) {
|
||||
dp_hpd = dp_lphw_hpd_get(dev, parser, catalog, cb);
|
||||
if (IS_ERR_OR_NULL(dp_hpd)) {
|
||||
DP_ERR("failed to get lphw hpd\n");
|
||||
return dp_hpd;
|
||||
}
|
||||
dp_hpd->type = DP_HPD_LPHW;
|
||||
} else if (parser->no_aux_switch) {
|
||||
dp_hpd = dp_gpio_hpd_get(dev, cb);
|
||||
if (IS_ERR_OR_NULL(dp_hpd)) {
|
||||
DP_ERR("failed to get gpio hpd\n");
|
||||
return dp_hpd;
|
||||
}
|
||||
dp_hpd->type = DP_HPD_GPIO;
|
||||
} else {
|
||||
dp_hpd = dp_altmode_get(dev, cb);
|
||||
if (!IS_ERR_OR_NULL(dp_hpd)) {
|
||||
dp_hpd->type = DP_HPD_ALTMODE;
|
||||
goto config;
|
||||
}
|
||||
DP_WARN("dp_altmode failed (%ld), falling back to dp_usbpd\n",
|
||||
PTR_ERR(dp_hpd));
|
||||
|
||||
dp_hpd = dp_usbpd_get(dev, cb);
|
||||
if (IS_ERR_OR_NULL(dp_hpd)) {
|
||||
DP_ERR("failed to get usbpd\n");
|
||||
return dp_hpd;
|
||||
}
|
||||
dp_hpd->type = DP_HPD_USBPD;
|
||||
}
|
||||
|
||||
config:
|
||||
if (!dp_hpd->host_init)
|
||||
dp_hpd->host_init = dp_hpd_host_init;
|
||||
if (!dp_hpd->host_deinit)
|
||||
dp_hpd->host_deinit = dp_hpd_host_deinit;
|
||||
if (!dp_hpd->isr)
|
||||
dp_hpd->isr = dp_hpd_isr;
|
||||
|
||||
return dp_hpd;
|
||||
}
|
||||
|
||||
void dp_hpd_put(struct dp_hpd *dp_hpd)
|
||||
{
|
||||
if (!dp_hpd)
|
||||
return;
|
||||
|
||||
switch (dp_hpd->type) {
|
||||
case DP_HPD_USBPD:
|
||||
dp_usbpd_put(dp_hpd);
|
||||
break;
|
||||
case DP_HPD_ALTMODE:
|
||||
dp_altmode_put(dp_hpd);
|
||||
break;
|
||||
case DP_HPD_GPIO:
|
||||
dp_gpio_hpd_put(dp_hpd);
|
||||
break;
|
||||
case DP_HPD_LPHW:
|
||||
dp_lphw_hpd_put(dp_hpd);
|
||||
break;
|
||||
default:
|
||||
DP_ERR("unknown hpd type %d\n", dp_hpd->type);
|
||||
break;
|
||||
}
|
||||
}
|
116
techpack/display/msm/dp/dp_hpd.h
Normal file
116
techpack/display/msm/dp/dp_hpd.h
Normal file
@ -0,0 +1,116 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _DP_HPD_H_
|
||||
#define _DP_HPD_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
#include "dp_parser.h"
|
||||
#include "dp_catalog.h"
|
||||
|
||||
struct device;
|
||||
|
||||
/**
|
||||
* enum dp_hpd_plug_orientation - plug orientation
|
||||
* @ORIENTATION_NONE: Undefined or unspecified
|
||||
* @ORIENTATION_CC1: CC1
|
||||
* @ORIENTATION_CC2: CC2
|
||||
*/
|
||||
enum dp_hpd_plug_orientation {
|
||||
ORIENTATION_NONE,
|
||||
ORIENTATION_CC1,
|
||||
ORIENTATION_CC2,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum dp_hpd_type - dp hpd type
|
||||
* @DP_HPD_ALTMODE: AltMode over G-Link based HPD
|
||||
* @DP_HPD_USBPD: USB type-c based HPD
|
||||
* @DP_HPD_GPIO: GPIO based HPD
|
||||
* @DP_HPD_BUILTIN: Controller built-in HPD
|
||||
*/
|
||||
|
||||
enum dp_hpd_type {
|
||||
DP_HPD_ALTMODE,
|
||||
DP_HPD_USBPD,
|
||||
DP_HPD_GPIO,
|
||||
DP_HPD_LPHW,
|
||||
DP_HPD_BUILTIN,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dp_hpd_cb - callback functions provided by the client
|
||||
*
|
||||
* @configure: called when dp connection is ready.
|
||||
* @disconnect: notify the cable disconnect event.
|
||||
* @attention: notify any attention message event.
|
||||
*/
|
||||
struct dp_hpd_cb {
|
||||
int (*configure)(struct device *dev);
|
||||
int (*disconnect)(struct device *dev);
|
||||
int (*attention)(struct device *dev);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dp_hpd - DisplayPort HPD status
|
||||
*
|
||||
* @type: type of HPD
|
||||
* @orientation: plug orientation configuration, USBPD type only.
|
||||
* @hpd_high: Hot Plug Detect signal is high.
|
||||
* @hpd_irq: Change in the status since last message
|
||||
* @alt_mode_cfg_done: bool to specify alt mode status
|
||||
* @multi_func: multi-function preferred, USBPD type only
|
||||
* @peer_usb_com: downstream supports usb data communication
|
||||
* @force_multi_func: force multi-function preferred
|
||||
* @isr: event interrupt, BUILTIN and LPHW type only
|
||||
* @register_hpd: register hardware callback
|
||||
* @host_init: source or host side setup for hpd
|
||||
* @host_deinit: source or host side de-initializations
|
||||
* @simulate_connect: simulate disconnect or connect for debug mode
|
||||
* @simulate_attention: simulate attention messages for debug mode
|
||||
* @wakeup_phy: wakeup USBPD phy layer
|
||||
*/
|
||||
struct dp_hpd {
|
||||
enum dp_hpd_type type;
|
||||
u32 orientation;
|
||||
bool hpd_high;
|
||||
bool hpd_irq;
|
||||
bool alt_mode_cfg_done;
|
||||
bool multi_func;
|
||||
bool peer_usb_comm;
|
||||
bool force_multi_func;
|
||||
|
||||
void (*isr)(struct dp_hpd *dp_hpd);
|
||||
int (*register_hpd)(struct dp_hpd *dp_hpd);
|
||||
void (*host_init)(struct dp_hpd *hpd, struct dp_catalog_hpd *catalog);
|
||||
void (*host_deinit)(struct dp_hpd *hpd, struct dp_catalog_hpd *catalog);
|
||||
int (*simulate_connect)(struct dp_hpd *dp_hpd, bool hpd);
|
||||
int (*simulate_attention)(struct dp_hpd *dp_hpd, int vdo);
|
||||
void (*wakeup_phy)(struct dp_hpd *dp_hpd, bool wakeup);
|
||||
};
|
||||
|
||||
/**
|
||||
* dp_hpd_get() - configure and get the DisplayPlot HPD module data
|
||||
*
|
||||
* @dev: device instance of the caller
|
||||
* @parser: DP parser
|
||||
* @cb: callback function for HPD response
|
||||
* return: pointer to allocated hpd module data
|
||||
*
|
||||
* This function sets up the hpd module
|
||||
*/
|
||||
struct dp_hpd *dp_hpd_get(struct device *dev, struct dp_parser *parser,
|
||||
struct dp_catalog_hpd *catalog, struct dp_hpd_cb *cb);
|
||||
|
||||
/**
|
||||
* dp_hpd_put()
|
||||
*
|
||||
* Cleans up dp_hpd instance
|
||||
*
|
||||
* @dp_hpd: instance of dp_hpd
|
||||
*/
|
||||
void dp_hpd_put(struct dp_hpd *dp_hpd);
|
||||
|
||||
#endif /* _DP_HPD_H_ */
|
1525
techpack/display/msm/dp/dp_link.c
Normal file
1525
techpack/display/msm/dp/dp_link.c
Normal file
File diff suppressed because it is too large
Load Diff
206
techpack/display/msm/dp/dp_link.h
Normal file
206
techpack/display/msm/dp/dp_link.h
Normal file
@ -0,0 +1,206 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _DP_LINK_H_
|
||||
#define _DP_LINK_H_
|
||||
|
||||
#include "dp_aux.h"
|
||||
|
||||
#define DS_PORT_STATUS_CHANGED 0x200
|
||||
#define DP_TEST_BIT_DEPTH_UNKNOWN 0xFFFFFFFF
|
||||
#define DP_LINK_ENUM_STR(x) #x
|
||||
|
||||
enum dp_link_voltage_level {
|
||||
DP_LINK_VOLTAGE_LEVEL_0,
|
||||
DP_LINK_VOLTAGE_LEVEL_1,
|
||||
DP_LINK_VOLTAGE_LEVEL_2,
|
||||
DP_LINK_VOLTAGE_MAX = DP_LINK_VOLTAGE_LEVEL_2,
|
||||
};
|
||||
|
||||
enum dp_link_preemaphasis_level {
|
||||
DP_LINK_PRE_EMPHASIS_LEVEL_0,
|
||||
DP_LINK_PRE_EMPHASIS_LEVEL_1,
|
||||
DP_LINK_PRE_EMPHASIS_LEVEL_2,
|
||||
DP_LINK_PRE_EMPHASIS_LEVEL_3,
|
||||
DP_LINK_PRE_EMPHASIS_MAX = DP_LINK_PRE_EMPHASIS_LEVEL_3,
|
||||
};
|
||||
|
||||
struct dp_link_sink_count {
|
||||
u32 count;
|
||||
bool cp_ready;
|
||||
};
|
||||
|
||||
struct dp_link_test_video {
|
||||
u32 test_video_pattern;
|
||||
u32 test_bit_depth;
|
||||
u32 test_dyn_range;
|
||||
u32 test_h_total;
|
||||
u32 test_v_total;
|
||||
u32 test_h_start;
|
||||
u32 test_v_start;
|
||||
u32 test_hsync_pol;
|
||||
u32 test_hsync_width;
|
||||
u32 test_vsync_pol;
|
||||
u32 test_vsync_width;
|
||||
u32 test_h_width;
|
||||
u32 test_v_height;
|
||||
u32 test_rr_d;
|
||||
u32 test_rr_n;
|
||||
};
|
||||
|
||||
struct dp_link_test_audio {
|
||||
u32 test_audio_sampling_rate;
|
||||
u32 test_audio_channel_count;
|
||||
u32 test_audio_pattern_type;
|
||||
u32 test_audio_period_ch_1;
|
||||
u32 test_audio_period_ch_2;
|
||||
u32 test_audio_period_ch_3;
|
||||
u32 test_audio_period_ch_4;
|
||||
u32 test_audio_period_ch_5;
|
||||
u32 test_audio_period_ch_6;
|
||||
u32 test_audio_period_ch_7;
|
||||
u32 test_audio_period_ch_8;
|
||||
};
|
||||
|
||||
struct dp_link_hdcp_status {
|
||||
int hdcp_state;
|
||||
int hdcp_version;
|
||||
};
|
||||
|
||||
struct dp_link_phy_params {
|
||||
u32 phy_test_pattern_sel;
|
||||
u8 v_level;
|
||||
u8 p_level;
|
||||
};
|
||||
|
||||
struct dp_link_params {
|
||||
u32 lane_count;
|
||||
u32 bw_code;
|
||||
};
|
||||
|
||||
static inline char *dp_link_get_test_name(u32 test_requested)
|
||||
{
|
||||
switch (test_requested) {
|
||||
case DP_TEST_LINK_TRAINING:
|
||||
return DP_LINK_ENUM_STR(DP_TEST_LINK_TRAINING);
|
||||
case DP_TEST_LINK_VIDEO_PATTERN:
|
||||
return DP_LINK_ENUM_STR(DP_TEST_LINK_VIDEO_PATTERN);
|
||||
case DP_TEST_LINK_EDID_READ:
|
||||
return DP_LINK_ENUM_STR(DP_TEST_LINK_EDID_READ);
|
||||
case DP_TEST_LINK_PHY_TEST_PATTERN:
|
||||
return DP_LINK_ENUM_STR(DP_TEST_LINK_PHY_TEST_PATTERN);
|
||||
case DP_TEST_LINK_AUDIO_PATTERN:
|
||||
return DP_LINK_ENUM_STR(DP_TEST_LINK_AUDIO_PATTERN);
|
||||
case DS_PORT_STATUS_CHANGED:
|
||||
return DP_LINK_ENUM_STR(DS_PORT_STATUS_CHANGED);
|
||||
case DP_LINK_STATUS_UPDATED:
|
||||
return DP_LINK_ENUM_STR(DP_LINK_STATUS_UPDATED);
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
struct dp_link {
|
||||
u32 sink_request;
|
||||
u32 test_response;
|
||||
|
||||
struct dp_link_sink_count sink_count;
|
||||
struct dp_link_test_video test_video;
|
||||
struct dp_link_test_audio test_audio;
|
||||
struct dp_link_phy_params phy_params;
|
||||
struct dp_link_params link_params;
|
||||
struct dp_link_hdcp_status hdcp_status;
|
||||
|
||||
u32 (*get_test_bits_depth)(struct dp_link *dp_link, u32 bpp);
|
||||
int (*process_request)(struct dp_link *dp_link);
|
||||
int (*get_colorimetry_config)(struct dp_link *dp_link);
|
||||
int (*adjust_levels)(struct dp_link *dp_link, u8 *link_status);
|
||||
int (*send_psm_request)(struct dp_link *dp_link, bool req);
|
||||
void (*send_test_response)(struct dp_link *dp_link);
|
||||
int (*psm_config)(struct dp_link *dp_link,
|
||||
struct drm_dp_link *link_info, bool enable);
|
||||
void (*send_edid_checksum)(struct dp_link *dp_link, u8 checksum);
|
||||
};
|
||||
|
||||
static inline char *dp_link_get_phy_test_pattern(u32 phy_test_pattern_sel)
|
||||
{
|
||||
switch (phy_test_pattern_sel) {
|
||||
case DP_TEST_PHY_PATTERN_NONE:
|
||||
return DP_LINK_ENUM_STR(DP_TEST_PHY_PATTERN_NONE);
|
||||
case DP_TEST_PHY_PATTERN_D10_2_NO_SCRAMBLING:
|
||||
return DP_LINK_ENUM_STR(
|
||||
DP_TEST_PHY_PATTERN_D10_2_NO_SCRAMBLING);
|
||||
case DP_TEST_PHY_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT:
|
||||
return DP_LINK_ENUM_STR(
|
||||
DP_TEST_PHY_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT);
|
||||
case DP_TEST_PHY_PATTERN_PRBS7:
|
||||
return DP_LINK_ENUM_STR(DP_TEST_PHY_PATTERN_PRBS7);
|
||||
case DP_TEST_PHY_PATTERN_80_BIT_CUSTOM_PATTERN:
|
||||
return DP_LINK_ENUM_STR(
|
||||
DP_TEST_PHY_PATTERN_80_BIT_CUSTOM_PATTERN);
|
||||
case DP_TEST_PHY_PATTERN_CP2520_PATTERN_1:
|
||||
return DP_LINK_ENUM_STR(DP_TEST_PHY_PATTERN_CP2520_PATTERN_1);
|
||||
case DP_TEST_PHY_PATTERN_CP2520_PATTERN_2:
|
||||
return DP_LINK_ENUM_STR(DP_TEST_PHY_PATTERN_CP2520_PATTERN_2);
|
||||
case DP_TEST_PHY_PATTERN_CP2520_PATTERN_3:
|
||||
return DP_LINK_ENUM_STR(DP_TEST_PHY_PATTERN_CP2520_PATTERN_3);
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* mdss_dp_test_bit_depth_to_bpp() - convert test bit depth to bpp
|
||||
* @tbd: test bit depth
|
||||
*
|
||||
* Returns the bits per pixel (bpp) to be used corresponding to the
|
||||
* git bit depth value. This function assumes that bit depth has
|
||||
* already been validated.
|
||||
*/
|
||||
static inline u32 dp_link_bit_depth_to_bpp(u32 tbd)
|
||||
{
|
||||
u32 bpp;
|
||||
|
||||
/*
|
||||
* Few simplistic rules and assumptions made here:
|
||||
* 1. Bit depth is per color component
|
||||
* 2. If bit depth is unknown return 0
|
||||
* 3. Assume 3 color components
|
||||
*/
|
||||
switch (tbd) {
|
||||
case DP_TEST_BIT_DEPTH_6:
|
||||
bpp = 18;
|
||||
break;
|
||||
case DP_TEST_BIT_DEPTH_8:
|
||||
bpp = 24;
|
||||
break;
|
||||
case DP_TEST_BIT_DEPTH_10:
|
||||
bpp = 30;
|
||||
break;
|
||||
case DP_TEST_BIT_DEPTH_UNKNOWN:
|
||||
default:
|
||||
bpp = 0;
|
||||
}
|
||||
|
||||
return bpp;
|
||||
}
|
||||
|
||||
/**
|
||||
* dp_link_get() - get the functionalities of dp test module
|
||||
*
|
||||
*
|
||||
* return: a pointer to dp_link struct
|
||||
*/
|
||||
struct dp_link *dp_link_get(struct device *dev, struct dp_aux *aux);
|
||||
|
||||
/**
|
||||
* dp_link_put() - releases the dp test module's resources
|
||||
*
|
||||
* @dp_link: an instance of dp_link module
|
||||
*
|
||||
*/
|
||||
void dp_link_put(struct dp_link *dp_link);
|
||||
|
||||
#endif /* _DP_LINK_H_ */
|
421
techpack/display/msm/dp/dp_lphw_hpd.c
Normal file
421
techpack/display/msm/dp/dp_lphw_hpd.c
Normal file
@ -0,0 +1,421 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/sde_io_util.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include "dp_lphw_hpd.h"
|
||||
#include "dp_debug.h"
|
||||
|
||||
struct dp_lphw_hpd_private {
|
||||
struct device *dev;
|
||||
struct dp_hpd base;
|
||||
struct dp_parser *parser;
|
||||
struct dp_catalog_hpd *catalog;
|
||||
struct dss_gpio gpio_cfg;
|
||||
struct workqueue_struct *connect_wq;
|
||||
struct delayed_work work;
|
||||
struct work_struct connect;
|
||||
struct work_struct disconnect;
|
||||
struct work_struct attention;
|
||||
struct dp_hpd_cb *cb;
|
||||
int irq;
|
||||
bool hpd;
|
||||
};
|
||||
|
||||
static void dp_lphw_hpd_attention(struct work_struct *work)
|
||||
{
|
||||
struct dp_lphw_hpd_private *lphw_hpd = container_of(work,
|
||||
struct dp_lphw_hpd_private, attention);
|
||||
|
||||
if (!lphw_hpd) {
|
||||
DP_ERR("invalid input\n");
|
||||
return;
|
||||
}
|
||||
|
||||
lphw_hpd->base.hpd_irq = true;
|
||||
|
||||
if (lphw_hpd->cb && lphw_hpd->cb->attention)
|
||||
lphw_hpd->cb->attention(lphw_hpd->dev);
|
||||
}
|
||||
|
||||
static void dp_lphw_hpd_connect(struct work_struct *work)
|
||||
{
|
||||
struct dp_lphw_hpd_private *lphw_hpd = container_of(work,
|
||||
struct dp_lphw_hpd_private, connect);
|
||||
|
||||
if (!lphw_hpd) {
|
||||
DP_ERR("invalid input\n");
|
||||
return;
|
||||
}
|
||||
|
||||
lphw_hpd->base.hpd_high = true;
|
||||
lphw_hpd->base.alt_mode_cfg_done = true;
|
||||
lphw_hpd->base.hpd_irq = false;
|
||||
|
||||
if (lphw_hpd->cb && lphw_hpd->cb->configure)
|
||||
lphw_hpd->cb->configure(lphw_hpd->dev);
|
||||
}
|
||||
|
||||
static void dp_lphw_hpd_disconnect(struct work_struct *work)
|
||||
{
|
||||
struct dp_lphw_hpd_private *lphw_hpd = container_of(work,
|
||||
struct dp_lphw_hpd_private, disconnect);
|
||||
|
||||
if (!lphw_hpd) {
|
||||
DP_ERR("invalid input\n");
|
||||
return;
|
||||
}
|
||||
|
||||
lphw_hpd->base.hpd_high = false;
|
||||
lphw_hpd->base.alt_mode_cfg_done = false;
|
||||
lphw_hpd->base.hpd_irq = false;
|
||||
|
||||
if (lphw_hpd->cb && lphw_hpd->cb->disconnect)
|
||||
lphw_hpd->cb->disconnect(lphw_hpd->dev);
|
||||
}
|
||||
|
||||
static irqreturn_t dp_tlmm_isr(int unused, void *data)
|
||||
{
|
||||
struct dp_lphw_hpd_private *lphw_hpd = data;
|
||||
bool hpd;
|
||||
|
||||
if (!lphw_hpd)
|
||||
return IRQ_NONE;
|
||||
|
||||
/*
|
||||
* According to the DP spec, HPD high event can be confirmed only after
|
||||
* the HPD line has een asserted continuously for more than 100ms
|
||||
*/
|
||||
usleep_range(99000, 100000);
|
||||
|
||||
hpd = gpio_get_value_cansleep(lphw_hpd->gpio_cfg.gpio);
|
||||
|
||||
DP_DEBUG("lphw_hpd state = %d, new hpd state = %d\n",
|
||||
lphw_hpd->hpd, hpd);
|
||||
if (!lphw_hpd->hpd && hpd) {
|
||||
lphw_hpd->hpd = true;
|
||||
queue_work(lphw_hpd->connect_wq, &lphw_hpd->connect);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void dp_lphw_hpd_host_init(struct dp_hpd *dp_hpd,
|
||||
struct dp_catalog_hpd *catalog)
|
||||
{
|
||||
struct dp_lphw_hpd_private *lphw_hpd;
|
||||
|
||||
if (!dp_hpd) {
|
||||
DP_ERR("invalid input\n");
|
||||
return;
|
||||
}
|
||||
|
||||
lphw_hpd = container_of(dp_hpd, struct dp_lphw_hpd_private, base);
|
||||
|
||||
lphw_hpd->catalog->config_hpd(lphw_hpd->catalog, true);
|
||||
|
||||
/*
|
||||
* Changing the gpio function to dp controller for the hpd line is not
|
||||
* stopping the tlmm interrupts generation on function 0.
|
||||
* So, as an additional step, disable the gpio interrupt irq also
|
||||
*/
|
||||
disable_irq(lphw_hpd->irq);
|
||||
}
|
||||
|
||||
static void dp_lphw_hpd_host_deinit(struct dp_hpd *dp_hpd,
|
||||
struct dp_catalog_hpd *catalog)
|
||||
{
|
||||
struct dp_lphw_hpd_private *lphw_hpd;
|
||||
|
||||
if (!dp_hpd) {
|
||||
DP_ERR("invalid input\n");
|
||||
return;
|
||||
}
|
||||
|
||||
lphw_hpd = container_of(dp_hpd, struct dp_lphw_hpd_private, base);
|
||||
|
||||
/* Enable the tlmm interrupt irq which was disabled in host_init */
|
||||
enable_irq(lphw_hpd->irq);
|
||||
|
||||
lphw_hpd->catalog->config_hpd(lphw_hpd->catalog, false);
|
||||
}
|
||||
|
||||
static void dp_lphw_hpd_isr(struct dp_hpd *dp_hpd)
|
||||
{
|
||||
struct dp_lphw_hpd_private *lphw_hpd;
|
||||
u32 isr = 0;
|
||||
int rc = 0;
|
||||
|
||||
if (!dp_hpd) {
|
||||
DP_ERR("invalid input\n");
|
||||
return;
|
||||
}
|
||||
|
||||
lphw_hpd = container_of(dp_hpd, struct dp_lphw_hpd_private, base);
|
||||
|
||||
isr = lphw_hpd->catalog->get_interrupt(lphw_hpd->catalog);
|
||||
|
||||
if (isr & DP_HPD_UNPLUG_INT_STATUS) { /* disconnect interrupt */
|
||||
|
||||
DP_DEBUG("disconnect interrupt, hpd isr state: 0x%x\n", isr);
|
||||
|
||||
if (lphw_hpd->base.hpd_high) {
|
||||
lphw_hpd->hpd = false;
|
||||
lphw_hpd->base.hpd_high = false;
|
||||
lphw_hpd->base.alt_mode_cfg_done = false;
|
||||
lphw_hpd->base.hpd_irq = false;
|
||||
|
||||
rc = queue_work(lphw_hpd->connect_wq,
|
||||
&lphw_hpd->disconnect);
|
||||
if (!rc)
|
||||
DP_DEBUG("disconnect not queued\n");
|
||||
} else {
|
||||
DP_ERR("already disconnected\n");
|
||||
}
|
||||
|
||||
} else if (isr & DP_IRQ_HPD_INT_STATUS) { /* attention interrupt */
|
||||
|
||||
DP_DEBUG("hpd_irq interrupt, hpd isr state: 0x%x\n", isr);
|
||||
|
||||
rc = queue_work(lphw_hpd->connect_wq, &lphw_hpd->attention);
|
||||
if (!rc)
|
||||
DP_DEBUG("attention not queued\n");
|
||||
}
|
||||
}
|
||||
|
||||
static int dp_lphw_hpd_simulate_connect(struct dp_hpd *dp_hpd, bool hpd)
|
||||
{
|
||||
struct dp_lphw_hpd_private *lphw_hpd;
|
||||
|
||||
if (!dp_hpd) {
|
||||
DP_ERR("invalid input\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
lphw_hpd = container_of(dp_hpd, struct dp_lphw_hpd_private, base);
|
||||
|
||||
lphw_hpd->base.hpd_high = hpd;
|
||||
lphw_hpd->base.alt_mode_cfg_done = hpd;
|
||||
lphw_hpd->base.hpd_irq = false;
|
||||
|
||||
if (!lphw_hpd->cb || !lphw_hpd->cb->configure ||
|
||||
!lphw_hpd->cb->disconnect) {
|
||||
DP_ERR("invalid callback\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (hpd)
|
||||
lphw_hpd->cb->configure(lphw_hpd->dev);
|
||||
else
|
||||
lphw_hpd->cb->disconnect(lphw_hpd->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dp_lphw_hpd_simulate_attention(struct dp_hpd *dp_hpd, int vdo)
|
||||
{
|
||||
struct dp_lphw_hpd_private *lphw_hpd;
|
||||
|
||||
if (!dp_hpd) {
|
||||
DP_ERR("invalid input\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
lphw_hpd = container_of(dp_hpd, struct dp_lphw_hpd_private, base);
|
||||
|
||||
lphw_hpd->base.hpd_irq = true;
|
||||
|
||||
if (lphw_hpd->cb && lphw_hpd->cb->attention)
|
||||
lphw_hpd->cb->attention(lphw_hpd->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dp_lphw_hpd_register(struct dp_hpd *dp_hpd)
|
||||
{
|
||||
struct dp_lphw_hpd_private *lphw_hpd;
|
||||
int rc = 0;
|
||||
|
||||
if (!dp_hpd)
|
||||
return -EINVAL;
|
||||
|
||||
lphw_hpd = container_of(dp_hpd, struct dp_lphw_hpd_private, base);
|
||||
|
||||
lphw_hpd->hpd = gpio_get_value_cansleep(lphw_hpd->gpio_cfg.gpio);
|
||||
|
||||
rc = devm_request_threaded_irq(lphw_hpd->dev, lphw_hpd->irq, NULL,
|
||||
dp_tlmm_isr,
|
||||
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
|
||||
"dp-gpio-intp", lphw_hpd);
|
||||
if (rc) {
|
||||
DP_ERR("Failed to request INTP threaded IRQ: %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
enable_irq_wake(lphw_hpd->irq);
|
||||
|
||||
if (lphw_hpd->hpd)
|
||||
queue_work(lphw_hpd->connect_wq, &lphw_hpd->connect);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void dp_lphw_hpd_deinit(struct dp_lphw_hpd_private *lphw_hpd)
|
||||
{
|
||||
struct dp_parser *parser = lphw_hpd->parser;
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < parser->mp[DP_PHY_PM].num_vreg; i++) {
|
||||
|
||||
if (!strcmp(parser->mp[DP_PHY_PM].vreg_config[i].vreg_name,
|
||||
"hpd-pwr")) {
|
||||
/* disable the hpd-pwr voltage regulator */
|
||||
if (msm_dss_enable_vreg(
|
||||
&parser->mp[DP_PHY_PM].vreg_config[i], 1,
|
||||
false))
|
||||
DP_ERR("hpd-pwr vreg not disabled\n");
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void dp_lphw_hpd_init(struct dp_lphw_hpd_private *lphw_hpd)
|
||||
{
|
||||
struct dp_pinctrl pinctrl = {0};
|
||||
struct dp_parser *parser = lphw_hpd->parser;
|
||||
int i = 0, rc = 0;
|
||||
|
||||
for (i = 0; i < parser->mp[DP_PHY_PM].num_vreg; i++) {
|
||||
|
||||
if (!strcmp(parser->mp[DP_PHY_PM].vreg_config[i].vreg_name,
|
||||
"hpd-pwr")) {
|
||||
/* enable the hpd-pwr voltage regulator */
|
||||
if (msm_dss_enable_vreg(
|
||||
&parser->mp[DP_PHY_PM].vreg_config[i], 1,
|
||||
true))
|
||||
DP_ERR("hpd-pwr vreg not enabled\n");
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pinctrl.pin = devm_pinctrl_get(lphw_hpd->dev);
|
||||
|
||||
if (!IS_ERR_OR_NULL(pinctrl.pin)) {
|
||||
pinctrl.state_hpd_active = pinctrl_lookup_state(pinctrl.pin,
|
||||
"mdss_dp_hpd_active");
|
||||
|
||||
if (!IS_ERR_OR_NULL(pinctrl.state_hpd_active)) {
|
||||
rc = pinctrl_select_state(pinctrl.pin,
|
||||
pinctrl.state_hpd_active);
|
||||
if (rc)
|
||||
DP_ERR("failed to set hpd_active state\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int dp_lphw_hpd_create_workqueue(struct dp_lphw_hpd_private *lphw_hpd)
|
||||
{
|
||||
lphw_hpd->connect_wq = create_singlethread_workqueue("dp_lphw_work");
|
||||
if (IS_ERR_OR_NULL(lphw_hpd->connect_wq)) {
|
||||
DP_ERR("Error creating connect_wq\n");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
INIT_WORK(&lphw_hpd->connect, dp_lphw_hpd_connect);
|
||||
INIT_WORK(&lphw_hpd->disconnect, dp_lphw_hpd_disconnect);
|
||||
INIT_WORK(&lphw_hpd->attention, dp_lphw_hpd_attention);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dp_hpd *dp_lphw_hpd_get(struct device *dev, struct dp_parser *parser,
|
||||
struct dp_catalog_hpd *catalog, struct dp_hpd_cb *cb)
|
||||
{
|
||||
int rc = 0;
|
||||
const char *hpd_gpio_name = "qcom,dp-hpd-gpio";
|
||||
struct dp_lphw_hpd_private *lphw_hpd;
|
||||
|
||||
if (!dev || !parser || !cb) {
|
||||
DP_ERR("invalid device\n");
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
lphw_hpd = devm_kzalloc(dev, sizeof(*lphw_hpd), GFP_KERNEL);
|
||||
if (!lphw_hpd) {
|
||||
rc = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
lphw_hpd->gpio_cfg.gpio = of_get_named_gpio(dev->of_node,
|
||||
hpd_gpio_name, 0);
|
||||
if (!gpio_is_valid(lphw_hpd->gpio_cfg.gpio)) {
|
||||
DP_ERR("%s gpio not specified\n", hpd_gpio_name);
|
||||
rc = -EINVAL;
|
||||
goto gpio_error;
|
||||
}
|
||||
|
||||
strlcpy(lphw_hpd->gpio_cfg.gpio_name, hpd_gpio_name,
|
||||
sizeof(lphw_hpd->gpio_cfg.gpio_name));
|
||||
lphw_hpd->gpio_cfg.value = 0;
|
||||
|
||||
rc = gpio_request(lphw_hpd->gpio_cfg.gpio,
|
||||
lphw_hpd->gpio_cfg.gpio_name);
|
||||
if (rc) {
|
||||
DP_ERR("%s: failed to request gpio\n", hpd_gpio_name);
|
||||
goto gpio_error;
|
||||
}
|
||||
gpio_direction_input(lphw_hpd->gpio_cfg.gpio);
|
||||
|
||||
lphw_hpd->dev = dev;
|
||||
lphw_hpd->cb = cb;
|
||||
lphw_hpd->irq = gpio_to_irq(lphw_hpd->gpio_cfg.gpio);
|
||||
|
||||
rc = dp_lphw_hpd_create_workqueue(lphw_hpd);
|
||||
if (rc) {
|
||||
DP_ERR("Failed to create a dp_hpd workqueue\n");
|
||||
goto gpio_error;
|
||||
}
|
||||
|
||||
lphw_hpd->parser = parser;
|
||||
lphw_hpd->catalog = catalog;
|
||||
lphw_hpd->base.isr = dp_lphw_hpd_isr;
|
||||
lphw_hpd->base.host_init = dp_lphw_hpd_host_init;
|
||||
lphw_hpd->base.host_deinit = dp_lphw_hpd_host_deinit;
|
||||
lphw_hpd->base.simulate_connect = dp_lphw_hpd_simulate_connect;
|
||||
lphw_hpd->base.simulate_attention = dp_lphw_hpd_simulate_attention;
|
||||
lphw_hpd->base.register_hpd = dp_lphw_hpd_register;
|
||||
|
||||
dp_lphw_hpd_init(lphw_hpd);
|
||||
|
||||
return &lphw_hpd->base;
|
||||
|
||||
gpio_error:
|
||||
devm_kfree(dev, lphw_hpd);
|
||||
error:
|
||||
return ERR_PTR(rc);
|
||||
}
|
||||
|
||||
void dp_lphw_hpd_put(struct dp_hpd *dp_hpd)
|
||||
{
|
||||
struct dp_lphw_hpd_private *lphw_hpd;
|
||||
|
||||
if (!dp_hpd)
|
||||
return;
|
||||
|
||||
lphw_hpd = container_of(dp_hpd, struct dp_lphw_hpd_private, base);
|
||||
|
||||
dp_lphw_hpd_deinit(lphw_hpd);
|
||||
gpio_free(lphw_hpd->gpio_cfg.gpio);
|
||||
devm_kfree(lphw_hpd->dev, lphw_hpd);
|
||||
}
|
36
techpack/display/msm/dp/dp_lphw_hpd.h
Normal file
36
techpack/display/msm/dp/dp_lphw_hpd.h
Normal file
@ -0,0 +1,36 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _DP_LPHW_HPD_H_
|
||||
#define _DP_LPHW_HPD_H_
|
||||
|
||||
#include "dp_hpd.h"
|
||||
|
||||
#define DP_HPD_PLUG_INT_STATUS BIT(0)
|
||||
#define DP_IRQ_HPD_INT_STATUS BIT(1)
|
||||
#define DP_HPD_REPLUG_INT_STATUS BIT(2)
|
||||
#define DP_HPD_UNPLUG_INT_STATUS BIT(3)
|
||||
|
||||
/**
|
||||
* dp_lphw_hpd_get() - configure and get the DisplayPlot HPD module data
|
||||
*
|
||||
* @dev: device instance of the caller
|
||||
* return: pointer to allocated gpio hpd module data
|
||||
*
|
||||
* This function sets up the lphw hpd module
|
||||
*/
|
||||
struct dp_hpd *dp_lphw_hpd_get(struct device *dev, struct dp_parser *parser,
|
||||
struct dp_catalog_hpd *catalog, struct dp_hpd_cb *cb);
|
||||
|
||||
/**
|
||||
* dp_lphw_hpd_put()
|
||||
*
|
||||
* Cleans up dp_hpd instance
|
||||
*
|
||||
* @hpd: instance of lphw_hpd
|
||||
*/
|
||||
void dp_lphw_hpd_put(struct dp_hpd *hpd);
|
||||
|
||||
#endif /* _DP_LPHW_HPD_H_ */
|
2486
techpack/display/msm/dp/dp_mst_drm.c
Normal file
2486
techpack/display/msm/dp/dp_mst_drm.c
Normal file
File diff suppressed because it is too large
Load Diff
65
techpack/display/msm/dp/dp_mst_drm.h
Normal file
65
techpack/display/msm/dp/dp_mst_drm.h
Normal file
@ -0,0 +1,65 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _DP_MST_DRM_H_
|
||||
#define _DP_MST_DRM_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_crtc.h>
|
||||
|
||||
#include "dp_display.h"
|
||||
|
||||
#if IS_ENABLED(CONFIG_DRM_MSM_DP_MST)
|
||||
|
||||
/**
|
||||
* dp_mst_drm_bridge_init - initialize mst bridge
|
||||
* @display: Pointer to private display structure
|
||||
* @encoder: Pointer to encoder for mst bridge mapping
|
||||
*/
|
||||
int dp_mst_drm_bridge_init(void *display,
|
||||
struct drm_encoder *encoder);
|
||||
|
||||
/**
|
||||
* dp_mst_drm_bridge_deinit - de-initialize mst bridges
|
||||
* @display: Pointer to private display structure
|
||||
*/
|
||||
void dp_mst_drm_bridge_deinit(void *display);
|
||||
|
||||
/**
|
||||
* dp_mst_init - initialize mst objects for the given display
|
||||
* @display: Pointer to private display structure
|
||||
*/
|
||||
int dp_mst_init(struct dp_display *dp_display);
|
||||
|
||||
/**
|
||||
* dp_mst_deinit - de-initialize mst objects for the given display
|
||||
* @display: Pointer to private display structure
|
||||
*/
|
||||
void dp_mst_deinit(struct dp_display *dp_display);
|
||||
#else
|
||||
|
||||
static inline int dp_mst_drm_bridge_init(void *display,
|
||||
struct drm_encoder *encoder)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void dp_mst_drm_bridge_deinit(void *display)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int dp_mst_init(struct dp_display *dp_display)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int dp_mst_deinit(struct dp_display *dp_display)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_DRM_MSM_DP_MST */
|
||||
|
||||
#endif /* _DP_MST_DRM_H_ */
|
3112
techpack/display/msm/dp/dp_panel.c
Normal file
3112
techpack/display/msm/dp/dp_panel.c
Normal file
File diff suppressed because it is too large
Load Diff
235
techpack/display/msm/dp/dp_panel.h
Normal file
235
techpack/display/msm/dp/dp_panel.h
Normal file
@ -0,0 +1,235 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _DP_PANEL_H_
|
||||
#define _DP_PANEL_H_
|
||||
|
||||
#include <drm/sde_drm.h>
|
||||
|
||||
#include "dp_aux.h"
|
||||
#include "dp_link.h"
|
||||
#include "sde_edid_parser.h"
|
||||
#include "sde_connector.h"
|
||||
#include "msm_drv.h"
|
||||
|
||||
#define DP_RECEIVER_DSC_CAP_SIZE 15
|
||||
#define DP_RECEIVER_FEC_STATUS_SIZE 3
|
||||
#define DP_RECEIVER_EXT_CAP_SIZE 4
|
||||
/*
|
||||
* A source initiated power down flag is set
|
||||
* when the DP is powered off while physical
|
||||
* DP cable is still connected i.e. without
|
||||
* HPD or not initiated by sink like HPD_IRQ.
|
||||
* This can happen if framework reboots or
|
||||
* device suspends.
|
||||
*/
|
||||
#define DP_PANEL_SRC_INITIATED_POWER_DOWN BIT(0)
|
||||
|
||||
#define DP_EXT_REC_CAP_FIELD BIT(7)
|
||||
|
||||
enum dp_lane_count {
|
||||
DP_LANE_COUNT_1 = 1,
|
||||
DP_LANE_COUNT_2 = 2,
|
||||
DP_LANE_COUNT_4 = 4,
|
||||
};
|
||||
|
||||
#define DP_MAX_DOWNSTREAM_PORTS 0x10
|
||||
|
||||
struct dp_panel_info {
|
||||
u32 h_active;
|
||||
u32 v_active;
|
||||
u32 h_back_porch;
|
||||
u32 h_front_porch;
|
||||
u32 h_sync_width;
|
||||
u32 h_active_low;
|
||||
u32 v_back_porch;
|
||||
u32 v_front_porch;
|
||||
u32 v_sync_width;
|
||||
u32 v_active_low;
|
||||
u32 h_skew;
|
||||
u32 refresh_rate;
|
||||
u32 pixel_clk_khz;
|
||||
u32 bpp;
|
||||
bool widebus_en;
|
||||
struct msm_compression_info comp_info;
|
||||
s64 dsc_overhead_fp;
|
||||
};
|
||||
|
||||
struct dp_display_mode {
|
||||
struct dp_panel_info timing;
|
||||
u32 capabilities;
|
||||
s64 fec_overhead_fp;
|
||||
s64 dsc_overhead_fp;
|
||||
};
|
||||
|
||||
struct dp_panel;
|
||||
|
||||
struct dp_panel_in {
|
||||
struct device *dev;
|
||||
struct dp_aux *aux;
|
||||
struct dp_link *link;
|
||||
struct dp_catalog_panel *catalog;
|
||||
struct drm_connector *connector;
|
||||
struct dp_panel *base_panel;
|
||||
struct dp_parser *parser;
|
||||
};
|
||||
|
||||
struct dp_dsc_caps {
|
||||
bool dsc_capable;
|
||||
u8 version;
|
||||
bool block_pred_en;
|
||||
u8 color_depth;
|
||||
};
|
||||
|
||||
struct dp_audio;
|
||||
|
||||
#define DP_PANEL_CAPS_DSC BIT(0)
|
||||
|
||||
struct dp_panel {
|
||||
/* dpcd raw data */
|
||||
u8 dpcd[DP_RECEIVER_CAP_SIZE + DP_RECEIVER_EXT_CAP_SIZE + 1];
|
||||
u8 ds_ports[DP_MAX_DOWNSTREAM_PORTS];
|
||||
u8 dsc_dpcd[DP_RECEIVER_DSC_CAP_SIZE + 1];
|
||||
u8 fec_dpcd;
|
||||
u8 fec_sts_dpcd[DP_RECEIVER_FEC_STATUS_SIZE + 1];
|
||||
|
||||
struct drm_dp_link link_info;
|
||||
struct sde_edid_ctrl *edid_ctrl;
|
||||
struct dp_panel_info pinfo;
|
||||
bool video_test;
|
||||
bool spd_enabled;
|
||||
|
||||
u32 vic;
|
||||
u32 max_pclk_khz;
|
||||
s64 mst_target_sc;
|
||||
|
||||
/* debug */
|
||||
u32 max_bw_code;
|
||||
u32 lane_count;
|
||||
u32 link_bw_code;
|
||||
|
||||
/* By default, stream_id is assigned to DP_INVALID_STREAM.
|
||||
* Client sets the stream id value using set_stream_id interface.
|
||||
*/
|
||||
enum dp_stream_id stream_id;
|
||||
int vcpi;
|
||||
|
||||
u32 channel_start_slot;
|
||||
u32 channel_total_slots;
|
||||
u32 pbn;
|
||||
|
||||
u32 tot_dsc_blks_in_use;
|
||||
/* DRM connector assosiated with this panel */
|
||||
struct drm_connector *connector;
|
||||
|
||||
struct dp_audio *audio;
|
||||
bool audio_supported;
|
||||
|
||||
struct dp_dsc_caps sink_dsc_caps;
|
||||
bool dsc_feature_enable;
|
||||
bool fec_feature_enable;
|
||||
bool dsc_en;
|
||||
bool fec_en;
|
||||
bool widebus_en;
|
||||
bool dsc_continuous_pps;
|
||||
bool mst_state;
|
||||
|
||||
s64 fec_overhead_fp;
|
||||
|
||||
int (*init)(struct dp_panel *dp_panel);
|
||||
int (*deinit)(struct dp_panel *dp_panel, u32 flags);
|
||||
int (*hw_cfg)(struct dp_panel *dp_panel, bool enable);
|
||||
int (*read_sink_caps)(struct dp_panel *dp_panel,
|
||||
struct drm_connector *connector, bool multi_func);
|
||||
u32 (*get_mode_bpp)(struct dp_panel *dp_panel, u32 mode_max_bpp,
|
||||
u32 mode_pclk_khz);
|
||||
int (*get_modes)(struct dp_panel *dp_panel,
|
||||
struct drm_connector *connector, struct dp_display_mode *mode);
|
||||
void (*handle_sink_request)(struct dp_panel *dp_panel);
|
||||
int (*set_edid)(struct dp_panel *dp_panel, u8 *edid, size_t edid_size);
|
||||
int (*set_dpcd)(struct dp_panel *dp_panel, u8 *dpcd);
|
||||
int (*setup_hdr)(struct dp_panel *dp_panel,
|
||||
struct drm_msm_ext_hdr_metadata *hdr_meta,
|
||||
bool dhdr_update, u64 core_clk_rate, bool flush);
|
||||
int (*set_colorspace)(struct dp_panel *dp_panel,
|
||||
u32 colorspace);
|
||||
void (*tpg_config)(struct dp_panel *dp_panel, bool enable);
|
||||
int (*spd_config)(struct dp_panel *dp_panel);
|
||||
bool (*hdr_supported)(struct dp_panel *dp_panel);
|
||||
|
||||
int (*set_stream_info)(struct dp_panel *dp_panel,
|
||||
enum dp_stream_id stream_id, u32 ch_start_slot,
|
||||
u32 ch_tot_slots, u32 pbn, int vcpi);
|
||||
|
||||
int (*read_sink_status)(struct dp_panel *dp_panel, u8 *sts, u32 size);
|
||||
int (*update_edid)(struct dp_panel *dp_panel, struct edid *edid);
|
||||
bool (*read_mst_cap)(struct dp_panel *dp_panel);
|
||||
void (*convert_to_dp_mode)(struct dp_panel *dp_panel,
|
||||
const struct drm_display_mode *drm_mode,
|
||||
struct dp_display_mode *dp_mode);
|
||||
void (*update_pps)(struct dp_panel *dp_panel, char *pps_cmd);
|
||||
};
|
||||
|
||||
struct dp_tu_calc_input {
|
||||
u64 lclk; /* 162, 270, 540 and 810 */
|
||||
u64 pclk_khz; /* in KHz */
|
||||
u64 hactive; /* active h-width */
|
||||
u64 hporch; /* bp + fp + pulse */
|
||||
int nlanes; /* no.of.lanes */
|
||||
int bpp; /* bits */
|
||||
int pixel_enc; /* 444, 420, 422 */
|
||||
int dsc_en; /* dsc on/off */
|
||||
int async_en; /* async mode */
|
||||
int fec_en; /* fec */
|
||||
int compress_ratio; /* 2:1 = 200, 3:1 = 300, 3.75:1 = 375 */
|
||||
int num_of_dsc_slices; /* number of slices per line */
|
||||
};
|
||||
|
||||
struct dp_vc_tu_mapping_table {
|
||||
u32 vic;
|
||||
u8 lanes;
|
||||
u8 lrate; /* DP_LINK_RATE -> 162(6), 270(10), 540(20), 810 (30) */
|
||||
u8 bpp;
|
||||
u32 valid_boundary_link;
|
||||
u32 delay_start_link;
|
||||
bool boundary_moderation_en;
|
||||
u32 valid_lower_boundary_link;
|
||||
u32 upper_boundary_count;
|
||||
u32 lower_boundary_count;
|
||||
u32 tu_size_minus1;
|
||||
};
|
||||
|
||||
/**
|
||||
* is_link_rate_valid() - validates the link rate
|
||||
* @lane_rate: link rate requested by the sink
|
||||
*
|
||||
* Returns true if the requested link rate is supported.
|
||||
*/
|
||||
static inline bool is_link_rate_valid(u32 bw_code)
|
||||
{
|
||||
return ((bw_code == DP_LINK_BW_1_62) ||
|
||||
(bw_code == DP_LINK_BW_2_7) ||
|
||||
(bw_code == DP_LINK_BW_5_4) ||
|
||||
(bw_code == DP_LINK_BW_8_1));
|
||||
}
|
||||
|
||||
/**
|
||||
* dp_link_is_lane_count_valid() - validates the lane count
|
||||
* @lane_count: lane count requested by the sink
|
||||
*
|
||||
* Returns true if the requested lane count is supported.
|
||||
*/
|
||||
static inline bool is_lane_count_valid(u32 lane_count)
|
||||
{
|
||||
return (lane_count == DP_LANE_COUNT_1) ||
|
||||
(lane_count == DP_LANE_COUNT_2) ||
|
||||
(lane_count == DP_LANE_COUNT_4);
|
||||
}
|
||||
|
||||
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);
|
||||
#endif /* _DP_PANEL_H_ */
|
924
techpack/display/msm/dp/dp_parser.c
Normal file
924
techpack/display/msm/dp/dp_parser.c
Normal file
@ -0,0 +1,924 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/of_platform.h>
|
||||
|
||||
#include "dp_parser.h"
|
||||
#include "dp_debug.h"
|
||||
|
||||
static void dp_parser_unmap_io_resources(struct dp_parser *parser)
|
||||
{
|
||||
int i = 0;
|
||||
struct dp_io *io = &parser->io;
|
||||
|
||||
for (i = 0; i < io->len; i++)
|
||||
msm_dss_iounmap(&io->data[i].io);
|
||||
}
|
||||
|
||||
static int dp_parser_reg(struct dp_parser *parser)
|
||||
{
|
||||
int rc = 0, i = 0;
|
||||
u32 reg_count;
|
||||
struct platform_device *pdev = parser->pdev;
|
||||
struct dp_io *io = &parser->io;
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
reg_count = of_property_count_strings(dev->of_node, "reg-names");
|
||||
if (reg_count <= 0) {
|
||||
DP_ERR("no reg defined\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
io->len = reg_count;
|
||||
io->data = devm_kzalloc(dev, sizeof(struct dp_io_data) * reg_count,
|
||||
GFP_KERNEL);
|
||||
if (!io->data)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < reg_count; i++) {
|
||||
of_property_read_string_index(dev->of_node,
|
||||
"reg-names", i, &io->data[i].name);
|
||||
rc = msm_dss_ioremap_byname(pdev, &io->data[i].io,
|
||||
io->data[i].name);
|
||||
if (rc) {
|
||||
DP_ERR("unable to remap %s resources\n",
|
||||
io->data[i].name);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
err:
|
||||
dp_parser_unmap_io_resources(parser);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static const char *dp_get_phy_aux_config_property(u32 cfg_type)
|
||||
{
|
||||
switch (cfg_type) {
|
||||
case PHY_AUX_CFG0:
|
||||
return "qcom,aux-cfg0-settings";
|
||||
case PHY_AUX_CFG1:
|
||||
return "qcom,aux-cfg1-settings";
|
||||
case PHY_AUX_CFG2:
|
||||
return "qcom,aux-cfg2-settings";
|
||||
case PHY_AUX_CFG3:
|
||||
return "qcom,aux-cfg3-settings";
|
||||
case PHY_AUX_CFG4:
|
||||
return "qcom,aux-cfg4-settings";
|
||||
case PHY_AUX_CFG5:
|
||||
return "qcom,aux-cfg5-settings";
|
||||
case PHY_AUX_CFG6:
|
||||
return "qcom,aux-cfg6-settings";
|
||||
case PHY_AUX_CFG7:
|
||||
return "qcom,aux-cfg7-settings";
|
||||
case PHY_AUX_CFG8:
|
||||
return "qcom,aux-cfg8-settings";
|
||||
case PHY_AUX_CFG9:
|
||||
return "qcom,aux-cfg9-settings";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static void dp_parser_phy_aux_cfg_reset(struct dp_parser *parser)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < PHY_AUX_CFG_MAX; i++)
|
||||
parser->aux_cfg[i] = (const struct dp_aux_cfg){ 0 };
|
||||
}
|
||||
|
||||
static int dp_parser_aux(struct dp_parser *parser)
|
||||
{
|
||||
struct device_node *of_node = parser->pdev->dev.of_node;
|
||||
int len = 0, i = 0, j = 0, config_count = 0;
|
||||
const char *data;
|
||||
int const minimum_config_count = 1;
|
||||
|
||||
for (i = 0; i < PHY_AUX_CFG_MAX; i++) {
|
||||
const char *property = dp_get_phy_aux_config_property(i);
|
||||
|
||||
data = of_get_property(of_node, property, &len);
|
||||
if (!data) {
|
||||
DP_ERR("Unable to read %s\n", property);
|
||||
goto error;
|
||||
}
|
||||
|
||||
config_count = len - 1;
|
||||
if ((config_count < minimum_config_count) ||
|
||||
(config_count > DP_AUX_CFG_MAX_VALUE_CNT)) {
|
||||
DP_ERR("Invalid config count (%d) configs for %s\n",
|
||||
config_count, property);
|
||||
goto error;
|
||||
}
|
||||
|
||||
parser->aux_cfg[i].offset = data[0];
|
||||
parser->aux_cfg[i].cfg_cnt = config_count;
|
||||
DP_DEBUG("%s offset=0x%x, cfg_cnt=%d\n",
|
||||
property,
|
||||
parser->aux_cfg[i].offset,
|
||||
parser->aux_cfg[i].cfg_cnt);
|
||||
for (j = 1; j < len; j++) {
|
||||
parser->aux_cfg[i].lut[j - 1] = data[j];
|
||||
DP_DEBUG("%s lut[%d]=0x%x\n",
|
||||
property,
|
||||
i,
|
||||
parser->aux_cfg[i].lut[j - 1]);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
error:
|
||||
dp_parser_phy_aux_cfg_reset(parser);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int dp_parser_misc(struct dp_parser *parser)
|
||||
{
|
||||
int rc = 0, len = 0, i = 0;
|
||||
const char *data = NULL;
|
||||
|
||||
struct device_node *of_node = parser->pdev->dev.of_node;
|
||||
|
||||
data = of_get_property(of_node, "qcom,logical2physical-lane-map", &len);
|
||||
if (data && (len == DP_MAX_PHY_LN)) {
|
||||
for (i = 0; i < len; i++)
|
||||
parser->l_map[i] = data[i];
|
||||
}
|
||||
|
||||
data = of_get_property(of_node, "qcom,pn-swap-lane-map", &len);
|
||||
if (data && (len == DP_MAX_PHY_LN)) {
|
||||
for (i = 0; i < len; i++)
|
||||
parser->l_pnswap |= (data[i] & 0x01) << i;
|
||||
}
|
||||
|
||||
rc = of_property_read_u32(of_node,
|
||||
"qcom,max-pclk-frequency-khz", &parser->max_pclk_khz);
|
||||
if (rc)
|
||||
parser->max_pclk_khz = DP_MAX_PIXEL_CLK_KHZ;
|
||||
|
||||
rc = of_property_read_u32(of_node,
|
||||
"qcom,max-lclk-frequency-khz", &parser->max_lclk_khz);
|
||||
if (rc)
|
||||
parser->max_lclk_khz = DP_MAX_LINK_CLK_KHZ;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dp_parser_msm_hdcp_dev(struct dp_parser *parser)
|
||||
{
|
||||
struct device_node *node;
|
||||
struct platform_device *pdev;
|
||||
|
||||
node = of_find_compatible_node(NULL, NULL, "qcom,msm-hdcp");
|
||||
if (!node) {
|
||||
// This is a non-fatal error, module initialization can proceed
|
||||
DP_WARN("couldn't find msm-hdcp node\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
pdev = of_find_device_by_node(node);
|
||||
if (!pdev) {
|
||||
// This is a non-fatal error, module initialization can proceed
|
||||
DP_WARN("couldn't find msm-hdcp pdev\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
parser->msm_hdcp_dev = &pdev->dev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dp_parser_pinctrl(struct dp_parser *parser)
|
||||
{
|
||||
int rc = 0;
|
||||
struct dp_pinctrl *pinctrl = &parser->pinctrl;
|
||||
|
||||
pinctrl->pin = devm_pinctrl_get(&parser->pdev->dev);
|
||||
|
||||
if (IS_ERR_OR_NULL(pinctrl->pin)) {
|
||||
DP_DEBUG("failed to get pinctrl, rc=%d\n", rc);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (parser->no_aux_switch && parser->lphw_hpd) {
|
||||
pinctrl->state_hpd_tlmm = pinctrl->state_hpd_ctrl = NULL;
|
||||
|
||||
pinctrl->state_hpd_tlmm = pinctrl_lookup_state(pinctrl->pin,
|
||||
"mdss_dp_hpd_tlmm");
|
||||
if (!IS_ERR_OR_NULL(pinctrl->state_hpd_tlmm)) {
|
||||
pinctrl->state_hpd_ctrl = pinctrl_lookup_state(
|
||||
pinctrl->pin, "mdss_dp_hpd_ctrl");
|
||||
}
|
||||
|
||||
if (!pinctrl->state_hpd_tlmm || !pinctrl->state_hpd_ctrl) {
|
||||
pinctrl->state_hpd_tlmm = NULL;
|
||||
pinctrl->state_hpd_ctrl = NULL;
|
||||
DP_DEBUG("tlmm or ctrl pinctrl state does not exist\n");
|
||||
}
|
||||
}
|
||||
|
||||
pinctrl->state_active = pinctrl_lookup_state(pinctrl->pin,
|
||||
"mdss_dp_active");
|
||||
if (IS_ERR_OR_NULL(pinctrl->state_active)) {
|
||||
rc = PTR_ERR(pinctrl->state_active);
|
||||
DP_ERR("failed to get pinctrl active state, rc=%d\n", rc);
|
||||
goto error;
|
||||
}
|
||||
|
||||
pinctrl->state_suspend = pinctrl_lookup_state(pinctrl->pin,
|
||||
"mdss_dp_sleep");
|
||||
if (IS_ERR_OR_NULL(pinctrl->state_suspend)) {
|
||||
rc = PTR_ERR(pinctrl->state_suspend);
|
||||
DP_ERR("failed to get pinctrl suspend state, rc=%d\n", rc);
|
||||
goto error;
|
||||
}
|
||||
error:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int dp_parser_gpio(struct dp_parser *parser)
|
||||
{
|
||||
int i = 0;
|
||||
struct device *dev = &parser->pdev->dev;
|
||||
struct device_node *of_node = dev->of_node;
|
||||
struct dss_module_power *mp = &parser->mp[DP_CORE_PM];
|
||||
static const char * const dp_gpios[] = {
|
||||
"qcom,aux-en-gpio",
|
||||
"qcom,aux-sel-gpio",
|
||||
"qcom,usbplug-cc-gpio",
|
||||
};
|
||||
|
||||
if (of_find_property(of_node, "qcom,dp-hpd-gpio", NULL)) {
|
||||
parser->no_aux_switch = true;
|
||||
parser->lphw_hpd = of_find_property(of_node,
|
||||
"qcom,dp-low-power-hw-hpd", NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (of_find_property(of_node, "qcom,dp-gpio-aux-switch", NULL))
|
||||
parser->gpio_aux_switch = true;
|
||||
mp->gpio_config = devm_kzalloc(dev,
|
||||
sizeof(struct dss_gpio) * ARRAY_SIZE(dp_gpios), GFP_KERNEL);
|
||||
if (!mp->gpio_config)
|
||||
return -ENOMEM;
|
||||
|
||||
mp->num_gpio = ARRAY_SIZE(dp_gpios);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dp_gpios); i++) {
|
||||
mp->gpio_config[i].gpio = of_get_named_gpio(of_node,
|
||||
dp_gpios[i], 0);
|
||||
|
||||
if (!gpio_is_valid(mp->gpio_config[i].gpio)) {
|
||||
DP_DEBUG("%s gpio not specified\n", dp_gpios[i]);
|
||||
/* In case any gpio was not specified, we think gpio
|
||||
* aux switch also was not specified.
|
||||
*/
|
||||
parser->gpio_aux_switch = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
strlcpy(mp->gpio_config[i].gpio_name, dp_gpios[i],
|
||||
sizeof(mp->gpio_config[i].gpio_name));
|
||||
|
||||
mp->gpio_config[i].value = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *dp_parser_supply_node_name(enum dp_pm_type module)
|
||||
{
|
||||
switch (module) {
|
||||
case DP_CORE_PM: return "qcom,core-supply-entries";
|
||||
case DP_CTRL_PM: return "qcom,ctrl-supply-entries";
|
||||
case DP_PHY_PM: return "qcom,phy-supply-entries";
|
||||
case DP_PLL_PM: return "qcom,pll-supply-entries";
|
||||
default: return "???";
|
||||
}
|
||||
}
|
||||
|
||||
static int dp_parser_get_vreg(struct dp_parser *parser,
|
||||
enum dp_pm_type module)
|
||||
{
|
||||
int i = 0, rc = 0;
|
||||
u32 tmp = 0;
|
||||
const char *pm_supply_name = NULL;
|
||||
struct device_node *supply_node = NULL;
|
||||
struct device_node *of_node = parser->pdev->dev.of_node;
|
||||
struct device_node *supply_root_node = NULL;
|
||||
struct dss_module_power *mp = &parser->mp[module];
|
||||
|
||||
mp->num_vreg = 0;
|
||||
pm_supply_name = dp_parser_supply_node_name(module);
|
||||
supply_root_node = of_get_child_by_name(of_node, pm_supply_name);
|
||||
if (!supply_root_node) {
|
||||
DP_WARN("no supply entry present: %s\n", pm_supply_name);
|
||||
goto novreg;
|
||||
}
|
||||
|
||||
mp->num_vreg = of_get_available_child_count(supply_root_node);
|
||||
|
||||
if (mp->num_vreg == 0) {
|
||||
DP_DEBUG("no vreg\n");
|
||||
goto novreg;
|
||||
} else {
|
||||
DP_DEBUG("vreg found. count=%d\n", mp->num_vreg);
|
||||
}
|
||||
|
||||
mp->vreg_config = devm_kzalloc(&parser->pdev->dev,
|
||||
sizeof(struct dss_vreg) * mp->num_vreg, GFP_KERNEL);
|
||||
if (!mp->vreg_config) {
|
||||
rc = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
for_each_child_of_node(supply_root_node, supply_node) {
|
||||
const char *st = NULL;
|
||||
/* vreg-name */
|
||||
rc = of_property_read_string(supply_node,
|
||||
"qcom,supply-name", &st);
|
||||
if (rc) {
|
||||
DP_ERR("error reading name. rc=%d\n",
|
||||
rc);
|
||||
goto error;
|
||||
}
|
||||
snprintf(mp->vreg_config[i].vreg_name,
|
||||
ARRAY_SIZE((mp->vreg_config[i].vreg_name)), "%s", st);
|
||||
/* vreg-min-voltage */
|
||||
rc = of_property_read_u32(supply_node,
|
||||
"qcom,supply-min-voltage", &tmp);
|
||||
if (rc) {
|
||||
DP_ERR("error reading min volt. rc=%d\n",
|
||||
rc);
|
||||
goto error;
|
||||
}
|
||||
mp->vreg_config[i].min_voltage = tmp;
|
||||
|
||||
/* vreg-max-voltage */
|
||||
rc = of_property_read_u32(supply_node,
|
||||
"qcom,supply-max-voltage", &tmp);
|
||||
if (rc) {
|
||||
DP_ERR("error reading max volt. rc=%d\n",
|
||||
rc);
|
||||
goto error;
|
||||
}
|
||||
mp->vreg_config[i].max_voltage = tmp;
|
||||
|
||||
/* enable-load */
|
||||
rc = of_property_read_u32(supply_node,
|
||||
"qcom,supply-enable-load", &tmp);
|
||||
if (rc) {
|
||||
DP_ERR("error reading enable load. rc=%d\n",
|
||||
rc);
|
||||
goto error;
|
||||
}
|
||||
mp->vreg_config[i].enable_load = tmp;
|
||||
|
||||
/* disable-load */
|
||||
rc = of_property_read_u32(supply_node,
|
||||
"qcom,supply-disable-load", &tmp);
|
||||
if (rc) {
|
||||
DP_ERR("error reading disable load. rc=%d\n",
|
||||
rc);
|
||||
goto error;
|
||||
}
|
||||
mp->vreg_config[i].disable_load = tmp;
|
||||
|
||||
DP_DEBUG("%s min=%d, max=%d, enable=%d, disable=%d\n",
|
||||
mp->vreg_config[i].vreg_name,
|
||||
mp->vreg_config[i].min_voltage,
|
||||
mp->vreg_config[i].max_voltage,
|
||||
mp->vreg_config[i].enable_load,
|
||||
mp->vreg_config[i].disable_load
|
||||
);
|
||||
++i;
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
||||
error:
|
||||
if (mp->vreg_config) {
|
||||
devm_kfree(&parser->pdev->dev, mp->vreg_config);
|
||||
mp->vreg_config = NULL;
|
||||
}
|
||||
novreg:
|
||||
mp->num_vreg = 0;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void dp_parser_put_vreg_data(struct device *dev,
|
||||
struct dss_module_power *mp)
|
||||
{
|
||||
if (!mp) {
|
||||
DEV_ERR("invalid input\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (mp->vreg_config) {
|
||||
devm_kfree(dev, mp->vreg_config);
|
||||
mp->vreg_config = NULL;
|
||||
}
|
||||
mp->num_vreg = 0;
|
||||
}
|
||||
|
||||
static int dp_parser_regulator(struct dp_parser *parser)
|
||||
{
|
||||
int i, rc = 0;
|
||||
struct platform_device *pdev = parser->pdev;
|
||||
|
||||
/* Parse the regulator information */
|
||||
for (i = DP_CORE_PM; i < DP_MAX_PM; i++) {
|
||||
rc = dp_parser_get_vreg(parser, i);
|
||||
if (rc) {
|
||||
DP_ERR("get_dt_vreg_data failed for %s. rc=%d\n",
|
||||
dp_parser_pm_name(i), rc);
|
||||
i--;
|
||||
for (; i >= DP_CORE_PM; i--)
|
||||
dp_parser_put_vreg_data(&pdev->dev,
|
||||
&parser->mp[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static bool dp_parser_check_prefix(const char *clk_prefix, const char *clk_name)
|
||||
{
|
||||
return !!strnstr(clk_name, clk_prefix, strlen(clk_name));
|
||||
}
|
||||
|
||||
static void dp_parser_put_clk_data(struct device *dev,
|
||||
struct dss_module_power *mp)
|
||||
{
|
||||
if (!mp) {
|
||||
DEV_ERR("%s: invalid input\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mp->clk_config) {
|
||||
devm_kfree(dev, mp->clk_config);
|
||||
mp->clk_config = NULL;
|
||||
}
|
||||
|
||||
mp->num_clk = 0;
|
||||
}
|
||||
|
||||
static void dp_parser_put_gpio_data(struct device *dev,
|
||||
struct dss_module_power *mp)
|
||||
{
|
||||
if (!mp) {
|
||||
DEV_ERR("%s: invalid input\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mp->gpio_config) {
|
||||
devm_kfree(dev, mp->gpio_config);
|
||||
mp->gpio_config = NULL;
|
||||
}
|
||||
|
||||
mp->num_gpio = 0;
|
||||
}
|
||||
|
||||
static int dp_parser_init_clk_data(struct dp_parser *parser)
|
||||
{
|
||||
int num_clk = 0, i = 0, rc = 0;
|
||||
int core_clk_count = 0, link_clk_count = 0;
|
||||
int strm0_clk_count = 0, strm1_clk_count = 0;
|
||||
const char *core_clk = "core";
|
||||
const char *strm0_clk = "strm0";
|
||||
const char *strm1_clk = "strm1";
|
||||
const char *link_clk = "link";
|
||||
const char *clk_name;
|
||||
struct device *dev = &parser->pdev->dev;
|
||||
struct dss_module_power *core_power = &parser->mp[DP_CORE_PM];
|
||||
struct dss_module_power *strm0_power = &parser->mp[DP_STREAM0_PM];
|
||||
struct dss_module_power *strm1_power = &parser->mp[DP_STREAM1_PM];
|
||||
struct dss_module_power *link_power = &parser->mp[DP_LINK_PM];
|
||||
|
||||
num_clk = of_property_count_strings(dev->of_node, "clock-names");
|
||||
if (num_clk <= 0) {
|
||||
DP_ERR("no clocks are defined\n");
|
||||
rc = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_clk; i++) {
|
||||
of_property_read_string_index(dev->of_node,
|
||||
"clock-names", i, &clk_name);
|
||||
|
||||
if (dp_parser_check_prefix(core_clk, clk_name))
|
||||
core_clk_count++;
|
||||
|
||||
if (dp_parser_check_prefix(strm0_clk, clk_name))
|
||||
strm0_clk_count++;
|
||||
|
||||
if (dp_parser_check_prefix(strm1_clk, clk_name))
|
||||
strm1_clk_count++;
|
||||
|
||||
if (dp_parser_check_prefix(link_clk, clk_name))
|
||||
link_clk_count++;
|
||||
}
|
||||
|
||||
/* Initialize the CORE power module */
|
||||
if (core_clk_count <= 0) {
|
||||
DP_ERR("no core clocks are defined\n");
|
||||
rc = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
core_power->num_clk = core_clk_count;
|
||||
core_power->clk_config = devm_kzalloc(dev,
|
||||
sizeof(struct dss_clk) * core_power->num_clk,
|
||||
GFP_KERNEL);
|
||||
if (!core_power->clk_config) {
|
||||
rc = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Initialize the STREAM0 power module */
|
||||
if (strm0_clk_count <= 0) {
|
||||
DP_DEBUG("no strm0 clocks are defined\n");
|
||||
} else {
|
||||
strm0_power->num_clk = strm0_clk_count;
|
||||
strm0_power->clk_config = devm_kzalloc(dev,
|
||||
sizeof(struct dss_clk) * strm0_power->num_clk,
|
||||
GFP_KERNEL);
|
||||
if (!strm0_power->clk_config) {
|
||||
strm0_power->num_clk = 0;
|
||||
rc = -EINVAL;
|
||||
goto strm0_clock_error;
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize the STREAM1 power module */
|
||||
if (strm1_clk_count <= 0) {
|
||||
DP_DEBUG("no strm1 clocks are defined\n");
|
||||
} else {
|
||||
strm1_power->num_clk = strm1_clk_count;
|
||||
strm1_power->clk_config = devm_kzalloc(dev,
|
||||
sizeof(struct dss_clk) * strm1_power->num_clk,
|
||||
GFP_KERNEL);
|
||||
if (!strm1_power->clk_config) {
|
||||
strm1_power->num_clk = 0;
|
||||
rc = -EINVAL;
|
||||
goto strm1_clock_error;
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize the link power module */
|
||||
if (link_clk_count <= 0) {
|
||||
DP_ERR("no link clocks are defined\n");
|
||||
rc = -EINVAL;
|
||||
goto link_clock_error;
|
||||
}
|
||||
|
||||
link_power->num_clk = link_clk_count;
|
||||
link_power->clk_config = devm_kzalloc(dev,
|
||||
sizeof(struct dss_clk) * link_power->num_clk,
|
||||
GFP_KERNEL);
|
||||
if (!link_power->clk_config) {
|
||||
link_power->num_clk = 0;
|
||||
rc = -EINVAL;
|
||||
goto link_clock_error;
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
||||
link_clock_error:
|
||||
dp_parser_put_clk_data(dev, strm1_power);
|
||||
strm1_clock_error:
|
||||
dp_parser_put_clk_data(dev, strm0_power);
|
||||
strm0_clock_error:
|
||||
dp_parser_put_clk_data(dev, core_power);
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int dp_parser_clock(struct dp_parser *parser)
|
||||
{
|
||||
int rc = 0, i = 0;
|
||||
int num_clk = 0;
|
||||
int core_clk_index = 0, link_clk_index = 0;
|
||||
int core_clk_count = 0, link_clk_count = 0;
|
||||
int strm0_clk_index = 0, strm1_clk_index = 0;
|
||||
int strm0_clk_count = 0, strm1_clk_count = 0;
|
||||
const char *clk_name;
|
||||
const char *core_clk = "core";
|
||||
const char *strm0_clk = "strm0";
|
||||
const char *strm1_clk = "strm1";
|
||||
const char *link_clk = "link";
|
||||
struct device *dev = &parser->pdev->dev;
|
||||
struct dss_module_power *core_power;
|
||||
struct dss_module_power *strm0_power;
|
||||
struct dss_module_power *strm1_power;
|
||||
struct dss_module_power *link_power;
|
||||
|
||||
core_power = &parser->mp[DP_CORE_PM];
|
||||
strm0_power = &parser->mp[DP_STREAM0_PM];
|
||||
strm1_power = &parser->mp[DP_STREAM1_PM];
|
||||
link_power = &parser->mp[DP_LINK_PM];
|
||||
|
||||
rc = dp_parser_init_clk_data(parser);
|
||||
if (rc) {
|
||||
DP_ERR("failed to initialize power data\n");
|
||||
rc = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
core_clk_count = core_power->num_clk;
|
||||
link_clk_count = link_power->num_clk;
|
||||
strm0_clk_count = strm0_power->num_clk;
|
||||
strm1_clk_count = strm1_power->num_clk;
|
||||
|
||||
num_clk = of_property_count_strings(dev->of_node, "clock-names");
|
||||
|
||||
for (i = 0; i < num_clk; i++) {
|
||||
of_property_read_string_index(dev->of_node, "clock-names",
|
||||
i, &clk_name);
|
||||
|
||||
if (dp_parser_check_prefix(core_clk, clk_name) &&
|
||||
core_clk_index < core_clk_count) {
|
||||
struct dss_clk *clk =
|
||||
&core_power->clk_config[core_clk_index];
|
||||
strlcpy(clk->clk_name, clk_name, sizeof(clk->clk_name));
|
||||
clk->type = DSS_CLK_AHB;
|
||||
core_clk_index++;
|
||||
} else if (dp_parser_check_prefix(link_clk, clk_name) &&
|
||||
link_clk_index < link_clk_count) {
|
||||
struct dss_clk *clk =
|
||||
&link_power->clk_config[link_clk_index];
|
||||
strlcpy(clk->clk_name, clk_name, sizeof(clk->clk_name));
|
||||
link_clk_index++;
|
||||
|
||||
if (!strcmp(clk_name, "link_clk"))
|
||||
clk->type = DSS_CLK_PCLK;
|
||||
else
|
||||
clk->type = DSS_CLK_AHB;
|
||||
} else if (dp_parser_check_prefix(strm0_clk, clk_name) &&
|
||||
strm0_clk_index < strm0_clk_count) {
|
||||
struct dss_clk *clk =
|
||||
&strm0_power->clk_config[strm0_clk_index];
|
||||
strlcpy(clk->clk_name, clk_name, sizeof(clk->clk_name));
|
||||
strm0_clk_index++;
|
||||
|
||||
clk->type = DSS_CLK_PCLK;
|
||||
} else if (dp_parser_check_prefix(strm1_clk, clk_name) &&
|
||||
strm1_clk_index < strm1_clk_count) {
|
||||
struct dss_clk *clk =
|
||||
&strm1_power->clk_config[strm1_clk_index];
|
||||
strlcpy(clk->clk_name, clk_name, sizeof(clk->clk_name));
|
||||
strm1_clk_index++;
|
||||
|
||||
clk->type = DSS_CLK_PCLK;
|
||||
}
|
||||
}
|
||||
|
||||
DP_DEBUG("clock parsing successful\n");
|
||||
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int dp_parser_catalog(struct dp_parser *parser)
|
||||
{
|
||||
int rc;
|
||||
u32 version;
|
||||
struct device *dev = &parser->pdev->dev;
|
||||
|
||||
rc = of_property_read_u32(dev->of_node, "qcom,phy-version", &version);
|
||||
|
||||
if (!rc)
|
||||
parser->hw_cfg.phy_version = version;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dp_parser_mst(struct dp_parser *parser)
|
||||
{
|
||||
struct device *dev = &parser->pdev->dev;
|
||||
int i;
|
||||
|
||||
parser->has_mst = of_property_read_bool(dev->of_node,
|
||||
"qcom,mst-enable");
|
||||
parser->has_mst_sideband = parser->has_mst;
|
||||
|
||||
DP_DEBUG("mst parsing successful. mst:%d\n", parser->has_mst);
|
||||
|
||||
for (i = 0; i < MAX_DP_MST_STREAMS; i++) {
|
||||
of_property_read_u32_index(dev->of_node,
|
||||
"qcom,mst-fixed-topology-ports", i,
|
||||
&parser->mst_fixed_port[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dp_parser_dsc(struct dp_parser *parser)
|
||||
{
|
||||
struct device *dev = &parser->pdev->dev;
|
||||
|
||||
parser->dsc_feature_enable = of_property_read_bool(dev->of_node,
|
||||
"qcom,dsc-feature-enable");
|
||||
|
||||
parser->dsc_continuous_pps = of_property_read_bool(dev->of_node,
|
||||
"qcom,dsc-continuous-pps");
|
||||
|
||||
DP_DEBUG("dsc parsing successful. dsc:%d\n",
|
||||
parser->dsc_feature_enable);
|
||||
DP_DEBUG("cont_pps:%d\n",
|
||||
parser->dsc_continuous_pps);
|
||||
}
|
||||
|
||||
static void dp_parser_fec(struct dp_parser *parser)
|
||||
{
|
||||
struct device *dev = &parser->pdev->dev;
|
||||
|
||||
parser->fec_feature_enable = of_property_read_bool(dev->of_node,
|
||||
"qcom,fec-feature-enable");
|
||||
|
||||
DP_DEBUG("fec parsing successful. fec:%d\n",
|
||||
parser->fec_feature_enable);
|
||||
}
|
||||
|
||||
static void dp_parser_widebus(struct dp_parser *parser)
|
||||
{
|
||||
struct device *dev = &parser->pdev->dev;
|
||||
|
||||
parser->has_widebus = of_property_read_bool(dev->of_node,
|
||||
"qcom,widebus-enable");
|
||||
|
||||
DP_DEBUG("widebus parsing successful. widebus:%d\n",
|
||||
parser->has_widebus);
|
||||
}
|
||||
|
||||
static int dp_parser_parse(struct dp_parser *parser)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (!parser) {
|
||||
DP_ERR("invalid input\n");
|
||||
rc = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
rc = dp_parser_reg(parser);
|
||||
if (rc)
|
||||
goto err;
|
||||
|
||||
rc = dp_parser_aux(parser);
|
||||
if (rc)
|
||||
goto err;
|
||||
|
||||
rc = dp_parser_misc(parser);
|
||||
if (rc)
|
||||
goto err;
|
||||
|
||||
rc = dp_parser_clock(parser);
|
||||
if (rc)
|
||||
goto err;
|
||||
|
||||
rc = dp_parser_regulator(parser);
|
||||
if (rc)
|
||||
goto err;
|
||||
|
||||
rc = dp_parser_gpio(parser);
|
||||
if (rc)
|
||||
goto err;
|
||||
|
||||
rc = dp_parser_catalog(parser);
|
||||
if (rc)
|
||||
goto err;
|
||||
|
||||
rc = dp_parser_pinctrl(parser);
|
||||
if (rc)
|
||||
goto err;
|
||||
|
||||
rc = dp_parser_msm_hdcp_dev(parser);
|
||||
if (rc)
|
||||
goto err;
|
||||
|
||||
rc = dp_parser_mst(parser);
|
||||
if (rc)
|
||||
goto err;
|
||||
|
||||
dp_parser_dsc(parser);
|
||||
dp_parser_fec(parser);
|
||||
dp_parser_widebus(parser);
|
||||
err:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static struct dp_io_data *dp_parser_get_io(struct dp_parser *dp_parser,
|
||||
char *name)
|
||||
{
|
||||
int i = 0;
|
||||
struct dp_io *io;
|
||||
|
||||
if (!dp_parser) {
|
||||
DP_ERR("invalid input\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
io = &dp_parser->io;
|
||||
|
||||
for (i = 0; i < io->len; i++) {
|
||||
struct dp_io_data *data = &io->data[i];
|
||||
|
||||
if (!strcmp(data->name, name))
|
||||
return data;
|
||||
}
|
||||
err:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void dp_parser_get_io_buf(struct dp_parser *dp_parser, char *name)
|
||||
{
|
||||
int i = 0;
|
||||
struct dp_io *io;
|
||||
|
||||
if (!dp_parser) {
|
||||
DP_ERR("invalid input\n");
|
||||
return;
|
||||
}
|
||||
|
||||
io = &dp_parser->io;
|
||||
|
||||
for (i = 0; i < io->len; i++) {
|
||||
struct dp_io_data *data = &io->data[i];
|
||||
|
||||
if (!strcmp(data->name, name)) {
|
||||
if (!data->buf)
|
||||
data->buf = devm_kzalloc(&dp_parser->pdev->dev,
|
||||
data->io.len, GFP_KERNEL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void dp_parser_clear_io_buf(struct dp_parser *dp_parser)
|
||||
{
|
||||
int i = 0;
|
||||
struct dp_io *io;
|
||||
|
||||
if (!dp_parser) {
|
||||
DP_ERR("invalid input\n");
|
||||
return;
|
||||
}
|
||||
|
||||
io = &dp_parser->io;
|
||||
|
||||
for (i = 0; i < io->len; i++) {
|
||||
struct dp_io_data *data = &io->data[i];
|
||||
|
||||
if (data->buf)
|
||||
devm_kfree(&dp_parser->pdev->dev, data->buf);
|
||||
|
||||
data->buf = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
struct dp_parser *dp_parser_get(struct platform_device *pdev)
|
||||
{
|
||||
struct dp_parser *parser;
|
||||
|
||||
parser = devm_kzalloc(&pdev->dev, sizeof(*parser), GFP_KERNEL);
|
||||
if (!parser)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
parser->parse = dp_parser_parse;
|
||||
parser->get_io = dp_parser_get_io;
|
||||
parser->get_io_buf = dp_parser_get_io_buf;
|
||||
parser->clear_io_buf = dp_parser_clear_io_buf;
|
||||
parser->pdev = pdev;
|
||||
|
||||
return parser;
|
||||
}
|
||||
|
||||
void dp_parser_put(struct dp_parser *parser)
|
||||
{
|
||||
int i = 0;
|
||||
struct dss_module_power *power = NULL;
|
||||
|
||||
if (!parser) {
|
||||
DP_ERR("invalid parser module\n");
|
||||
return;
|
||||
}
|
||||
|
||||
power = parser->mp;
|
||||
|
||||
for (i = 0; i < DP_MAX_PM; i++) {
|
||||
dp_parser_put_clk_data(&parser->pdev->dev, &power[i]);
|
||||
dp_parser_put_vreg_data(&parser->pdev->dev, &power[i]);
|
||||
dp_parser_put_gpio_data(&parser->pdev->dev, &power[i]);
|
||||
}
|
||||
|
||||
dp_parser_clear_io_buf(parser);
|
||||
devm_kfree(&parser->pdev->dev, parser->io.data);
|
||||
devm_kfree(&parser->pdev->dev, parser);
|
||||
}
|
271
techpack/display/msm/dp/dp_parser.h
Normal file
271
techpack/display/msm/dp/dp_parser.h
Normal file
@ -0,0 +1,271 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _DP_PARSER_H_
|
||||
#define _DP_PARSER_H_
|
||||
|
||||
#include <linux/sde_io_util.h>
|
||||
|
||||
#define DP_LABEL "MDSS DP DISPLAY"
|
||||
#define AUX_CFG_LEN 10
|
||||
#define DP_MAX_PIXEL_CLK_KHZ 675000
|
||||
#define DP_MAX_LINK_CLK_KHZ 810000
|
||||
#define MAX_DP_MST_STREAMS 2
|
||||
|
||||
enum dp_pm_type {
|
||||
DP_CORE_PM,
|
||||
DP_CTRL_PM,
|
||||
DP_PHY_PM,
|
||||
DP_STREAM0_PM,
|
||||
DP_STREAM1_PM,
|
||||
DP_LINK_PM,
|
||||
DP_PLL_PM,
|
||||
DP_MAX_PM
|
||||
};
|
||||
|
||||
static inline const char *dp_parser_pm_name(enum dp_pm_type module)
|
||||
{
|
||||
switch (module) {
|
||||
case DP_CORE_PM: return "DP_CORE_PM";
|
||||
case DP_CTRL_PM: return "DP_CTRL_PM";
|
||||
case DP_PHY_PM: return "DP_PHY_PM";
|
||||
case DP_STREAM0_PM: return "DP_STREAM0_PM";
|
||||
case DP_STREAM1_PM: return "DP_STREAM1_PM";
|
||||
case DP_LINK_PM: return "DP_LINK_PM";
|
||||
case DP_PLL_PM: return "DP_PLL_PM";
|
||||
default: return "???";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* struct dp_display_data - display related device tree data.
|
||||
*
|
||||
* @ctrl_node: referece to controller device
|
||||
* @phy_node: reference to phy device
|
||||
* @is_active: is the controller currently active
|
||||
* @name: name of the display
|
||||
* @display_type: type of the display
|
||||
*/
|
||||
struct dp_display_data {
|
||||
struct device_node *ctrl_node;
|
||||
struct device_node *phy_node;
|
||||
bool is_active;
|
||||
const char *name;
|
||||
const char *display_type;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dp_io_data - data structure to store DP IO related info
|
||||
* @name: name of the IO
|
||||
* @buf: buffer corresponding to IO for debugging
|
||||
* @io: io data which give len and mapped address
|
||||
*/
|
||||
struct dp_io_data {
|
||||
const char *name;
|
||||
u8 *buf;
|
||||
struct dss_io_data io;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dp_io - data struct to store array of DP IO info
|
||||
* @len: total number of IOs
|
||||
* @data: pointer to an array of DP IO data structures.
|
||||
*/
|
||||
struct dp_io {
|
||||
u32 len;
|
||||
struct dp_io_data *data;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dp_pinctrl - DP's pin control
|
||||
*
|
||||
* @pin: pin-controller's instance
|
||||
* @state_active: active state pin control
|
||||
* @state_hpd_active: hpd active state pin control
|
||||
* @state_suspend: suspend state pin control
|
||||
*/
|
||||
struct dp_pinctrl {
|
||||
struct pinctrl *pin;
|
||||
struct pinctrl_state *state_active;
|
||||
struct pinctrl_state *state_hpd_active;
|
||||
struct pinctrl_state *state_hpd_tlmm;
|
||||
struct pinctrl_state *state_hpd_ctrl;
|
||||
struct pinctrl_state *state_suspend;
|
||||
};
|
||||
|
||||
#define DP_ENUM_STR(x) #x
|
||||
#define DP_AUX_CFG_MAX_VALUE_CNT 3
|
||||
/**
|
||||
* struct dp_aux_cfg - DP's AUX configuration settings
|
||||
*
|
||||
* @cfg_cnt: count of the configurable settings for the AUX register
|
||||
* @current_index: current index of the AUX config lut
|
||||
* @offset: register offset of the AUX config register
|
||||
* @lut: look up table for the AUX config values for this register
|
||||
*/
|
||||
struct dp_aux_cfg {
|
||||
u32 cfg_cnt;
|
||||
u32 current_index;
|
||||
u32 offset;
|
||||
u32 lut[DP_AUX_CFG_MAX_VALUE_CNT];
|
||||
};
|
||||
|
||||
/* PHY AUX config registers */
|
||||
enum dp_phy_aux_config_type {
|
||||
PHY_AUX_CFG0,
|
||||
PHY_AUX_CFG1,
|
||||
PHY_AUX_CFG2,
|
||||
PHY_AUX_CFG3,
|
||||
PHY_AUX_CFG4,
|
||||
PHY_AUX_CFG5,
|
||||
PHY_AUX_CFG6,
|
||||
PHY_AUX_CFG7,
|
||||
PHY_AUX_CFG8,
|
||||
PHY_AUX_CFG9,
|
||||
PHY_AUX_CFG_MAX,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum dp_phy_version - version of the dp phy
|
||||
* @DP_PHY_VERSION_UNKNOWN: Unknown controller version
|
||||
* @DP_PHY_VERSION_4_2_0: DP phy v4.2.0 controller
|
||||
* @DP_PHY_VERSION_MAX: max version
|
||||
*/
|
||||
enum dp_phy_version {
|
||||
DP_PHY_VERSION_UNKNOWN,
|
||||
DP_PHY_VERSION_2_0_0 = 0x200,
|
||||
DP_PHY_VERSION_4_2_0 = 0x420,
|
||||
DP_PHY_VERSION_MAX
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dp_hw_cfg - DP HW specific configuration
|
||||
*
|
||||
* @phy_version: DP PHY HW version
|
||||
*/
|
||||
struct dp_hw_cfg {
|
||||
enum dp_phy_version phy_version;
|
||||
};
|
||||
|
||||
static inline char *dp_phy_aux_config_type_to_string(u32 cfg_type)
|
||||
{
|
||||
switch (cfg_type) {
|
||||
case PHY_AUX_CFG0:
|
||||
return DP_ENUM_STR(PHY_AUX_CFG0);
|
||||
case PHY_AUX_CFG1:
|
||||
return DP_ENUM_STR(PHY_AUX_CFG1);
|
||||
case PHY_AUX_CFG2:
|
||||
return DP_ENUM_STR(PHY_AUX_CFG2);
|
||||
case PHY_AUX_CFG3:
|
||||
return DP_ENUM_STR(PHY_AUX_CFG3);
|
||||
case PHY_AUX_CFG4:
|
||||
return DP_ENUM_STR(PHY_AUX_CFG4);
|
||||
case PHY_AUX_CFG5:
|
||||
return DP_ENUM_STR(PHY_AUX_CFG5);
|
||||
case PHY_AUX_CFG6:
|
||||
return DP_ENUM_STR(PHY_AUX_CFG6);
|
||||
case PHY_AUX_CFG7:
|
||||
return DP_ENUM_STR(PHY_AUX_CFG7);
|
||||
case PHY_AUX_CFG8:
|
||||
return DP_ENUM_STR(PHY_AUX_CFG8);
|
||||
case PHY_AUX_CFG9:
|
||||
return DP_ENUM_STR(PHY_AUX_CFG9);
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* struct dp_parser - DP parser's data exposed to clients
|
||||
*
|
||||
* @pdev: platform data of the client
|
||||
* @msm_hdcp_dev: device pointer for the HDCP driver
|
||||
* @mp: gpio, regulator and clock related data
|
||||
* @pinctrl: pin-control related data
|
||||
* @disp_data: controller's display related data
|
||||
* @l_pnswap: P/N swap status on each lane
|
||||
* @max_pclk_khz: maximum pixel clock supported for the platform
|
||||
* @max_lclk_khz: maximum link clock supported for the platform
|
||||
* @hw_cfg: DP HW specific settings
|
||||
* @has_mst: MST feature enable status
|
||||
* @has_mst_sideband: MST sideband feature enable status
|
||||
* @no_aux_switch: presence AUX switch status
|
||||
* @gpio_aux_switch: presence GPIO AUX switch status
|
||||
* @dsc_feature_enable: DSC feature enable status
|
||||
* @fec_feature_enable: FEC feature enable status
|
||||
* @dsc_continuous_pps: PPS sent every frame by HW
|
||||
* @has_widebus: widebus (2PPC) feature eanble status
|
||||
*@mst_fixed_port: mst port_num reserved for fixed topology
|
||||
* @parse: function to be called by client to parse device tree.
|
||||
* @get_io: function to be called by client to get io data.
|
||||
* @get_io_buf: function to be called by client to get io buffers.
|
||||
* @clear_io_buf: function to be called by client to clear io buffers.
|
||||
*/
|
||||
struct dp_parser {
|
||||
struct platform_device *pdev;
|
||||
struct device *msm_hdcp_dev;
|
||||
struct dss_module_power mp[DP_MAX_PM];
|
||||
struct dp_pinctrl pinctrl;
|
||||
struct dp_io io;
|
||||
struct dp_display_data disp_data;
|
||||
|
||||
u8 l_map[4];
|
||||
u8 l_pnswap;
|
||||
struct dp_aux_cfg aux_cfg[AUX_CFG_LEN];
|
||||
u32 max_pclk_khz;
|
||||
u32 max_lclk_khz;
|
||||
struct dp_hw_cfg hw_cfg;
|
||||
bool has_mst;
|
||||
bool has_mst_sideband;
|
||||
bool no_aux_switch;
|
||||
bool dsc_feature_enable;
|
||||
bool fec_feature_enable;
|
||||
bool dsc_continuous_pps;
|
||||
bool has_widebus;
|
||||
bool gpio_aux_switch;
|
||||
bool lphw_hpd;
|
||||
u32 mst_fixed_port[MAX_DP_MST_STREAMS];
|
||||
|
||||
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);
|
||||
void (*clear_io_buf)(struct dp_parser *parser);
|
||||
};
|
||||
|
||||
enum dp_phy_lane_num {
|
||||
DP_PHY_LN0 = 0,
|
||||
DP_PHY_LN1 = 1,
|
||||
DP_PHY_LN2 = 2,
|
||||
DP_PHY_LN3 = 3,
|
||||
DP_MAX_PHY_LN = 4,
|
||||
};
|
||||
|
||||
enum dp_mainlink_lane_num {
|
||||
DP_ML0 = 0,
|
||||
DP_ML1 = 1,
|
||||
DP_ML2 = 2,
|
||||
DP_ML3 = 3,
|
||||
};
|
||||
|
||||
/**
|
||||
* dp_parser_get() - get the DP's device tree parser module
|
||||
*
|
||||
* @pdev: platform data of the client
|
||||
* return: pointer to dp_parser structure.
|
||||
*
|
||||
* This function provides client capability to parse the
|
||||
* device tree and populate the data structures. The data
|
||||
* related to clock, regulators, pin-control and other
|
||||
* can be parsed using this module.
|
||||
*/
|
||||
struct dp_parser *dp_parser_get(struct platform_device *pdev);
|
||||
|
||||
/**
|
||||
* dp_parser_put() - cleans the dp_parser module
|
||||
*
|
||||
* @parser: pointer to the parser's data.
|
||||
*/
|
||||
void dp_parser_put(struct dp_parser *parser);
|
||||
#endif
|
147
techpack/display/msm/dp/dp_pll.c
Normal file
147
techpack/display/msm/dp/dp_pll.c
Normal file
@ -0,0 +1,147 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/of_device.h>
|
||||
#include "dp_debug.h"
|
||||
#include "dp_pll.h"
|
||||
|
||||
static int dp_pll_fill_io(struct dp_pll *pll)
|
||||
{
|
||||
struct dp_parser *parser = pll->parser;
|
||||
|
||||
pll->io.dp_phy = parser->get_io(parser, "dp_phy");
|
||||
if (!pll->io.dp_phy) {
|
||||
DP_ERR("Invalid dp_phy resource\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
pll->io.dp_pll = parser->get_io(parser, "dp_pll");
|
||||
if (!pll->io.dp_pll) {
|
||||
DP_ERR("Invalid dp_pll resource\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
pll->io.dp_ln_tx0 = parser->get_io(parser, "dp_ln_tx0");
|
||||
if (!pll->io.dp_ln_tx0) {
|
||||
DP_ERR("Invalid dp_ln_tx1 resource\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
pll->io.dp_ln_tx1 = parser->get_io(parser, "dp_ln_tx1");
|
||||
if (!pll->io.dp_ln_tx1) {
|
||||
DP_ERR("Invalid dp_ln_tx1 resource\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
pll->io.gdsc = parser->get_io(parser, "gdsc");
|
||||
if (!pll->io.gdsc) {
|
||||
DP_ERR("Invalid gdsc resource\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dp_pll_clock_register(struct dp_pll *pll)
|
||||
{
|
||||
int rc;
|
||||
|
||||
switch (pll->revision) {
|
||||
case DP_PLL_5NM_V1:
|
||||
case DP_PLL_5NM_V2:
|
||||
case DP_PLL_7NM:
|
||||
rc = dp_pll_clock_register_5nm(pll);
|
||||
break;
|
||||
default:
|
||||
rc = -ENOTSUPP;
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void dp_pll_clock_unregister(struct dp_pll *pll)
|
||||
{
|
||||
switch (pll->revision) {
|
||||
case DP_PLL_5NM_V1:
|
||||
case DP_PLL_5NM_V2:
|
||||
case DP_PLL_7NM:
|
||||
dp_pll_clock_unregister_5nm(pll);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
struct dp_pll *dp_pll_get(struct dp_pll_in *in)
|
||||
{
|
||||
int rc = 0;
|
||||
struct dp_pll *pll;
|
||||
struct dp_parser *parser;
|
||||
const char *label = NULL;
|
||||
struct platform_device *pdev;
|
||||
|
||||
if (!in || !in->pdev || !in->pdev->dev.of_node || !in->parser) {
|
||||
DP_ERR("Invalid resource pointers\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
pll = kzalloc(sizeof(*pll), GFP_KERNEL);
|
||||
if (!pll)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
pll->pdev = in->pdev;
|
||||
pll->parser = in->parser;
|
||||
pll->aux = in->aux;
|
||||
parser = pll->parser;
|
||||
pdev = pll->pdev;
|
||||
|
||||
label = of_get_property(pdev->dev.of_node, "qcom,pll-revision", NULL);
|
||||
if (label) {
|
||||
if (!strcmp(label, "5nm-v1")) {
|
||||
pll->revision = DP_PLL_5NM_V1;
|
||||
} else if (!strcmp(label, "5nm-v2")) {
|
||||
pll->revision = DP_PLL_5NM_V2;
|
||||
} else if (!strcmp(label, "7nm")) {
|
||||
pll->revision = DP_PLL_7NM;
|
||||
} else {
|
||||
DP_ERR("Unsupported pll revision\n");
|
||||
rc = -ENOTSUPP;
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
DP_ERR("pll revision not specified\n");
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
pll->ssc_en = of_property_read_bool(pdev->dev.of_node,
|
||||
"qcom,ssc-feature-enable");
|
||||
pll->bonding_en = of_property_read_bool(pdev->dev.of_node,
|
||||
"qcom,bonding-feature-enable");
|
||||
|
||||
rc = dp_pll_fill_io(pll);
|
||||
if (rc)
|
||||
goto error;
|
||||
|
||||
rc = dp_pll_clock_register(pll);
|
||||
if (rc)
|
||||
goto error;
|
||||
|
||||
DP_INFO("revision=%s, ssc_en=%d, bonding_en=%d\n",
|
||||
dp_pll_get_revision(pll->revision), pll->ssc_en,
|
||||
pll->bonding_en);
|
||||
|
||||
return pll;
|
||||
error:
|
||||
kfree(pll);
|
||||
return ERR_PTR(rc);
|
||||
}
|
||||
|
||||
void dp_pll_put(struct dp_pll *pll)
|
||||
{
|
||||
dp_pll_clock_unregister(pll);
|
||||
kfree(pll);
|
||||
}
|
144
techpack/display/msm/dp/dp_pll.h
Normal file
144
techpack/display/msm/dp/dp_pll.h
Normal file
@ -0,0 +1,144 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef __DP_PLL_H
|
||||
#define __DP_PLL_H
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/of_device.h>
|
||||
#include "dp_parser.h"
|
||||
#include "sde_dbg.h"
|
||||
|
||||
#define DP_VCO_HSCLK_RATE_1620MHZDIV1000 1620000UL
|
||||
#define DP_VCO_HSCLK_RATE_2700MHZDIV1000 2700000UL
|
||||
#define DP_VCO_HSCLK_RATE_5400MHZDIV1000 5400000UL
|
||||
#define DP_VCO_HSCLK_RATE_8100MHZDIV1000 8100000UL
|
||||
|
||||
#define dp_pll_get_base(x) pll->io.x->io.base
|
||||
|
||||
#define dp_pll_read(x, offset) ({ \
|
||||
readl_relaxed((dp_pll_get_base(x)) + (offset)); \
|
||||
})
|
||||
|
||||
#define dp_pll_write(x, offset, data) ({ \
|
||||
DP_DEBUG(#offset", addr=0x%x, val=0x%x\n", \
|
||||
(dp_pll_get_base(x)) + (offset), (data)); \
|
||||
SDE_EVT32_VERBOSE((dp_pll_get_base(x)) + (offset), (data)); \
|
||||
writel_relaxed((data), (dp_pll_get_base(x)) + (offset)); \
|
||||
})
|
||||
|
||||
enum dp_pll_revision {
|
||||
DP_PLL_UNKNOWN,
|
||||
DP_PLL_5NM_V1,
|
||||
DP_PLL_5NM_V2,
|
||||
DP_PLL_7NM,
|
||||
};
|
||||
|
||||
static inline const char *dp_pll_get_revision(enum dp_pll_revision rev)
|
||||
{
|
||||
switch (rev) {
|
||||
case DP_PLL_UNKNOWN: return "DP_PLL_UNKNOWN";
|
||||
case DP_PLL_5NM_V1: return "DP_PLL_5NM_V1";
|
||||
case DP_PLL_5NM_V2: return "DP_PLL_5NM_V2";
|
||||
case DP_PLL_7NM: return "DP_PLL_7NM";
|
||||
default: return "???";
|
||||
}
|
||||
}
|
||||
|
||||
struct dp_pll_io {
|
||||
struct dp_io_data *dp_phy;
|
||||
struct dp_io_data *dp_pll;
|
||||
struct dp_io_data *dp_ln_tx0;
|
||||
struct dp_io_data *dp_ln_tx1;
|
||||
struct dp_io_data *gdsc;
|
||||
};
|
||||
|
||||
struct dp_pll_vco_clk {
|
||||
struct clk_hw hw;
|
||||
unsigned long rate; /* current vco rate */
|
||||
u64 min_rate; /* min vco rate */
|
||||
u64 max_rate; /* max vco rate */
|
||||
void *priv;
|
||||
};
|
||||
|
||||
struct dp_pll {
|
||||
/*
|
||||
* target pll revision information
|
||||
*/
|
||||
u32 revision;
|
||||
|
||||
/*
|
||||
* Certain plls needs to update the same vco rate after resume in
|
||||
* suspend/resume scenario. Cached the vco rate for such plls.
|
||||
*/
|
||||
unsigned long vco_cached_rate;
|
||||
|
||||
/*
|
||||
* PLL index if multiple index are available. Eg. in case of
|
||||
* DSI we have 2 plls.
|
||||
*/
|
||||
uint32_t index;
|
||||
|
||||
bool ssc_en;
|
||||
bool bonding_en;
|
||||
|
||||
void *priv;
|
||||
struct platform_device *pdev;
|
||||
struct dp_parser *parser;
|
||||
struct dp_power *power;
|
||||
struct dp_aux *aux;
|
||||
struct dp_pll_io io;
|
||||
struct clk_onecell_data *clk_data;
|
||||
};
|
||||
|
||||
struct dp_pll_db {
|
||||
struct dp_pll *pll;
|
||||
|
||||
/* lane and orientation settings */
|
||||
u8 lane_cnt;
|
||||
u8 orientation;
|
||||
|
||||
/* COM PHY settings */
|
||||
u32 hsclk_sel;
|
||||
u32 dec_start_mode0;
|
||||
u32 div_frac_start1_mode0;
|
||||
u32 div_frac_start2_mode0;
|
||||
u32 div_frac_start3_mode0;
|
||||
u32 integloop_gain0_mode0;
|
||||
u32 integloop_gain1_mode0;
|
||||
u32 lock_cmp1_mode0;
|
||||
u32 lock_cmp2_mode0;
|
||||
u32 lock_cmp_en;
|
||||
u32 ssc_step_size1_mode0;
|
||||
u32 ssc_step_size2_mode0;
|
||||
|
||||
/* PHY vco divider */
|
||||
u32 phy_vco_div;
|
||||
};
|
||||
|
||||
|
||||
static inline struct dp_pll_vco_clk *to_dp_vco_hw(struct clk_hw *hw)
|
||||
{
|
||||
return container_of(hw, struct dp_pll_vco_clk, hw);
|
||||
}
|
||||
|
||||
static inline bool is_gdsc_disabled(struct dp_pll *pll)
|
||||
{
|
||||
return (dp_pll_read(gdsc, 0x0) & BIT(31)) ? false : true;
|
||||
}
|
||||
|
||||
int dp_pll_clock_register_5nm(struct dp_pll *pll);
|
||||
void dp_pll_clock_unregister_5nm(struct dp_pll *pll);
|
||||
|
||||
struct dp_pll_in {
|
||||
struct platform_device *pdev;
|
||||
struct dp_aux *aux;
|
||||
struct dp_parser *parser;
|
||||
};
|
||||
|
||||
struct dp_pll *dp_pll_get(struct dp_pll_in *in);
|
||||
void dp_pll_put(struct dp_pll *pll);
|
||||
#endif /* __DP_PLL_H */
|
1087
techpack/display/msm/dp/dp_pll_5nm.c
Normal file
1087
techpack/display/msm/dp/dp_pll_5nm.c
Normal file
File diff suppressed because it is too large
Load Diff
739
techpack/display/msm/dp/dp_power.c
Normal file
739
techpack/display/msm/dp/dp_power.c
Normal file
@ -0,0 +1,739 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2012-2021, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <drm/drmP.h>
|
||||
#include "dp_power.h"
|
||||
#include "dp_catalog.h"
|
||||
#include "dp_debug.h"
|
||||
#include "dp_pll.h"
|
||||
|
||||
#define DP_CLIENT_NAME_SIZE 20
|
||||
|
||||
struct dp_power_private {
|
||||
struct dp_parser *parser;
|
||||
struct dp_pll *pll;
|
||||
struct platform_device *pdev;
|
||||
struct clk *pixel_clk_rcg;
|
||||
struct clk *pixel_parent;
|
||||
struct clk *pixel1_clk_rcg;
|
||||
|
||||
struct dp_power dp_power;
|
||||
|
||||
bool core_clks_on;
|
||||
bool link_clks_on;
|
||||
bool strm0_clks_on;
|
||||
bool strm1_clks_on;
|
||||
};
|
||||
|
||||
static int dp_power_regulator_init(struct dp_power_private *power)
|
||||
{
|
||||
int rc = 0, i = 0, j = 0;
|
||||
struct platform_device *pdev;
|
||||
struct dp_parser *parser;
|
||||
|
||||
parser = power->parser;
|
||||
pdev = power->pdev;
|
||||
|
||||
for (i = DP_CORE_PM; !rc && (i < DP_MAX_PM); i++) {
|
||||
rc = msm_dss_get_vreg(&pdev->dev,
|
||||
parser->mp[i].vreg_config,
|
||||
parser->mp[i].num_vreg, 1);
|
||||
if (rc) {
|
||||
DP_ERR("failed to init vregs for %s\n",
|
||||
dp_parser_pm_name(i));
|
||||
for (j = i - 1; j >= DP_CORE_PM; j--) {
|
||||
msm_dss_get_vreg(&pdev->dev,
|
||||
parser->mp[j].vreg_config,
|
||||
parser->mp[j].num_vreg, 0);
|
||||
}
|
||||
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
error:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void dp_power_regulator_deinit(struct dp_power_private *power)
|
||||
{
|
||||
int rc = 0, i = 0;
|
||||
struct platform_device *pdev;
|
||||
struct dp_parser *parser;
|
||||
|
||||
parser = power->parser;
|
||||
pdev = power->pdev;
|
||||
|
||||
for (i = DP_CORE_PM; (i < DP_MAX_PM); i++) {
|
||||
rc = msm_dss_get_vreg(&pdev->dev,
|
||||
parser->mp[i].vreg_config,
|
||||
parser->mp[i].num_vreg, 0);
|
||||
if (rc)
|
||||
DP_ERR("failed to deinit vregs for %s\n",
|
||||
dp_parser_pm_name(i));
|
||||
}
|
||||
}
|
||||
|
||||
static int dp_power_regulator_ctrl(struct dp_power_private *power, bool enable)
|
||||
{
|
||||
int rc = 0, i = 0, j = 0;
|
||||
struct dp_parser *parser;
|
||||
|
||||
parser = power->parser;
|
||||
|
||||
for (i = DP_CORE_PM; i < DP_MAX_PM; i++) {
|
||||
/*
|
||||
* The DP_PLL_PM regulator is controlled by dp_display based
|
||||
* on the link configuration.
|
||||
*/
|
||||
if (i == DP_PLL_PM) {
|
||||
DP_DEBUG("skipping: '%s' vregs for %s\n",
|
||||
enable ? "enable" : "disable",
|
||||
dp_parser_pm_name(i));
|
||||
continue;
|
||||
}
|
||||
|
||||
rc = msm_dss_enable_vreg(
|
||||
parser->mp[i].vreg_config,
|
||||
parser->mp[i].num_vreg, enable);
|
||||
if (rc) {
|
||||
DP_ERR("failed to '%s' vregs for %s\n",
|
||||
enable ? "enable" : "disable",
|
||||
dp_parser_pm_name(i));
|
||||
if (enable) {
|
||||
for (j = i-1; j >= DP_CORE_PM; j--) {
|
||||
msm_dss_enable_vreg(
|
||||
parser->mp[j].vreg_config,
|
||||
parser->mp[j].num_vreg, 0);
|
||||
}
|
||||
}
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
error:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int dp_power_pinctrl_set(struct dp_power_private *power, bool active)
|
||||
{
|
||||
int rc = -EFAULT;
|
||||
struct pinctrl_state *pin_state;
|
||||
struct dp_parser *parser;
|
||||
|
||||
parser = power->parser;
|
||||
|
||||
if (IS_ERR_OR_NULL(parser->pinctrl.pin))
|
||||
return 0;
|
||||
|
||||
if (parser->no_aux_switch && parser->lphw_hpd) {
|
||||
pin_state = active ? parser->pinctrl.state_hpd_ctrl
|
||||
: parser->pinctrl.state_hpd_tlmm;
|
||||
if (!IS_ERR_OR_NULL(pin_state)) {
|
||||
rc = pinctrl_select_state(parser->pinctrl.pin,
|
||||
pin_state);
|
||||
if (rc) {
|
||||
DP_ERR("cannot direct hpd line to %s\n",
|
||||
active ? "ctrl" : "tlmm");
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (parser->no_aux_switch)
|
||||
return 0;
|
||||
|
||||
pin_state = active ? parser->pinctrl.state_active
|
||||
: parser->pinctrl.state_suspend;
|
||||
if (!IS_ERR_OR_NULL(pin_state)) {
|
||||
rc = pinctrl_select_state(parser->pinctrl.pin,
|
||||
pin_state);
|
||||
if (rc)
|
||||
DP_ERR("can not set %s pins\n",
|
||||
active ? "dp_active"
|
||||
: "dp_sleep");
|
||||
} else {
|
||||
DP_ERR("invalid '%s' pinstate\n",
|
||||
active ? "dp_active"
|
||||
: "dp_sleep");
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void dp_power_clk_put(struct dp_power_private *power)
|
||||
{
|
||||
enum dp_pm_type module;
|
||||
|
||||
for (module = DP_CORE_PM; module < DP_MAX_PM; module++) {
|
||||
struct dss_module_power *pm = &power->parser->mp[module];
|
||||
|
||||
if (!pm->num_clk)
|
||||
continue;
|
||||
|
||||
msm_dss_put_clk(pm->clk_config, pm->num_clk);
|
||||
}
|
||||
}
|
||||
|
||||
static int dp_power_clk_init(struct dp_power_private *power, bool enable)
|
||||
{
|
||||
int rc = 0;
|
||||
struct device *dev;
|
||||
enum dp_pm_type module;
|
||||
|
||||
dev = &power->pdev->dev;
|
||||
|
||||
if (enable) {
|
||||
for (module = DP_CORE_PM; module < DP_MAX_PM; module++) {
|
||||
struct dss_module_power *pm =
|
||||
&power->parser->mp[module];
|
||||
|
||||
if (!pm->num_clk)
|
||||
continue;
|
||||
|
||||
rc = msm_dss_get_clk(dev, pm->clk_config, pm->num_clk);
|
||||
if (rc) {
|
||||
DP_ERR("failed to get %s clk. err=%d\n",
|
||||
dp_parser_pm_name(module), rc);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
power->pixel_clk_rcg = clk_get(dev, "pixel_clk_rcg");
|
||||
if (IS_ERR(power->pixel_clk_rcg)) {
|
||||
DP_ERR("Unable to get DP pixel clk RCG: %d\n",
|
||||
PTR_ERR(power->pixel_clk_rcg));
|
||||
rc = PTR_ERR(power->pixel_clk_rcg);
|
||||
power->pixel_clk_rcg = NULL;
|
||||
goto err_pixel_clk_rcg;
|
||||
}
|
||||
|
||||
power->pixel_parent = clk_get(dev, "pixel_parent");
|
||||
if (IS_ERR(power->pixel_parent)) {
|
||||
DP_ERR("Unable to get DP pixel RCG parent: %d\n",
|
||||
PTR_ERR(power->pixel_parent));
|
||||
rc = PTR_ERR(power->pixel_parent);
|
||||
power->pixel_parent = NULL;
|
||||
goto err_pixel_parent;
|
||||
}
|
||||
|
||||
if (power->parser->has_mst) {
|
||||
power->pixel1_clk_rcg = clk_get(dev, "pixel1_clk_rcg");
|
||||
if (IS_ERR(power->pixel1_clk_rcg)) {
|
||||
DP_ERR("Unable to get DP pixel1 clk RCG: %d\n",
|
||||
PTR_ERR(power->pixel1_clk_rcg));
|
||||
rc = PTR_ERR(power->pixel1_clk_rcg);
|
||||
power->pixel1_clk_rcg = NULL;
|
||||
goto err_pixel1_clk_rcg;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (power->pixel1_clk_rcg)
|
||||
clk_put(power->pixel1_clk_rcg);
|
||||
|
||||
if (power->pixel_parent)
|
||||
clk_put(power->pixel_parent);
|
||||
|
||||
if (power->pixel_clk_rcg)
|
||||
clk_put(power->pixel_clk_rcg);
|
||||
|
||||
dp_power_clk_put(power);
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
||||
err_pixel1_clk_rcg:
|
||||
clk_put(power->pixel_parent);
|
||||
err_pixel_parent:
|
||||
clk_put(power->pixel_clk_rcg);
|
||||
err_pixel_clk_rcg:
|
||||
dp_power_clk_put(power);
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int dp_power_clk_set_rate(struct dp_power_private *power,
|
||||
enum dp_pm_type module, bool enable)
|
||||
{
|
||||
int rc = 0;
|
||||
struct dss_module_power *mp;
|
||||
|
||||
if (!power) {
|
||||
DP_ERR("invalid power data\n");
|
||||
rc = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
mp = &power->parser->mp[module];
|
||||
|
||||
if (enable) {
|
||||
rc = msm_dss_clk_set_rate(mp->clk_config, mp->num_clk);
|
||||
if (rc) {
|
||||
DP_ERR("failed to set clks rate.\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = msm_dss_enable_clk(mp->clk_config, mp->num_clk, 1);
|
||||
if (rc) {
|
||||
DP_ERR("failed to enable clks\n");
|
||||
goto exit;
|
||||
}
|
||||
} else {
|
||||
rc = msm_dss_enable_clk(mp->clk_config, mp->num_clk, 0);
|
||||
if (rc) {
|
||||
DP_ERR("failed to disable clks\n");
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int dp_power_clk_enable(struct dp_power *dp_power,
|
||||
enum dp_pm_type pm_type, bool enable)
|
||||
{
|
||||
int rc = 0;
|
||||
struct dss_module_power *mp;
|
||||
struct dp_power_private *power;
|
||||
|
||||
if (!dp_power) {
|
||||
DP_ERR("invalid power data\n");
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
power = container_of(dp_power, struct dp_power_private, dp_power);
|
||||
|
||||
mp = &power->parser->mp[pm_type];
|
||||
|
||||
if (pm_type >= DP_MAX_PM) {
|
||||
DP_ERR("unsupported power module: %s\n",
|
||||
dp_parser_pm_name(pm_type));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (enable) {
|
||||
if (pm_type == DP_CORE_PM && power->core_clks_on) {
|
||||
DP_DEBUG("core clks already enabled\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((pm_type == DP_STREAM0_PM) && (power->strm0_clks_on)) {
|
||||
DP_DEBUG("strm0 clks already enabled\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((pm_type == DP_STREAM1_PM) && (power->strm1_clks_on)) {
|
||||
DP_DEBUG("strm1 clks already enabled\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((pm_type == DP_CTRL_PM) && (!power->core_clks_on)) {
|
||||
DP_DEBUG("Need to enable core clks before link clks\n");
|
||||
|
||||
rc = dp_power_clk_set_rate(power, pm_type, enable);
|
||||
if (rc) {
|
||||
DP_ERR("failed to enable clks: %s. err=%d\n",
|
||||
dp_parser_pm_name(DP_CORE_PM), rc);
|
||||
goto error;
|
||||
} else {
|
||||
power->core_clks_on = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (pm_type == DP_LINK_PM && power->link_clks_on) {
|
||||
DP_DEBUG("links clks already enabled\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
rc = dp_power_clk_set_rate(power, pm_type, enable);
|
||||
if (rc) {
|
||||
DP_ERR("failed to '%s' clks for: %s. err=%d\n",
|
||||
enable ? "enable" : "disable",
|
||||
dp_parser_pm_name(pm_type), rc);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (pm_type == DP_CORE_PM)
|
||||
power->core_clks_on = enable;
|
||||
else if (pm_type == DP_STREAM0_PM)
|
||||
power->strm0_clks_on = enable;
|
||||
else if (pm_type == DP_STREAM1_PM)
|
||||
power->strm1_clks_on = enable;
|
||||
else if (pm_type == DP_LINK_PM)
|
||||
power->link_clks_on = enable;
|
||||
|
||||
/*
|
||||
* This log is printed only when user connects or disconnects
|
||||
* a DP cable. As this is a user-action and not a frequent
|
||||
* usecase, it is not going to flood the kernel logs. Also,
|
||||
* helpful in debugging the NOC issues.
|
||||
*/
|
||||
DP_INFO("core:%s link:%s strm0:%s strm1:%s\n",
|
||||
power->core_clks_on ? "on" : "off",
|
||||
power->link_clks_on ? "on" : "off",
|
||||
power->strm0_clks_on ? "on" : "off",
|
||||
power->strm1_clks_on ? "on" : "off");
|
||||
error:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int dp_power_request_gpios(struct dp_power_private *power)
|
||||
{
|
||||
int rc = 0, i;
|
||||
struct device *dev;
|
||||
struct dss_module_power *mp;
|
||||
static const char * const gpio_names[] = {
|
||||
"aux_enable", "aux_sel", "usbplug_cc",
|
||||
};
|
||||
|
||||
if (!power) {
|
||||
DP_ERR("invalid power data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev = &power->pdev->dev;
|
||||
mp = &power->parser->mp[DP_CORE_PM];
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(gpio_names); i++) {
|
||||
unsigned int gpio = mp->gpio_config[i].gpio;
|
||||
|
||||
if (gpio_is_valid(gpio)) {
|
||||
rc = gpio_request(gpio, gpio_names[i]);
|
||||
if (rc) {
|
||||
DP_ERR("request %s gpio failed, rc=%d\n",
|
||||
gpio_names[i], rc);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
error:
|
||||
for (i = 0; i < ARRAY_SIZE(gpio_names); i++) {
|
||||
unsigned int gpio = mp->gpio_config[i].gpio;
|
||||
|
||||
if (gpio_is_valid(gpio))
|
||||
gpio_free(gpio);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static bool dp_power_find_gpio(const char *gpio1, const char *gpio2)
|
||||
{
|
||||
return !!strnstr(gpio1, gpio2, strlen(gpio1));
|
||||
}
|
||||
|
||||
static void dp_power_set_gpio(struct dp_power_private *power, bool flip)
|
||||
{
|
||||
int i;
|
||||
struct dss_module_power *mp = &power->parser->mp[DP_CORE_PM];
|
||||
struct dss_gpio *config = mp->gpio_config;
|
||||
|
||||
for (i = 0; i < mp->num_gpio; i++) {
|
||||
if (dp_power_find_gpio(config->gpio_name, "aux-sel"))
|
||||
config->value = flip;
|
||||
|
||||
if (gpio_is_valid(config->gpio)) {
|
||||
DP_DEBUG("gpio %s, value %d\n", config->gpio_name,
|
||||
config->value);
|
||||
|
||||
if (dp_power_find_gpio(config->gpio_name, "aux-en") ||
|
||||
dp_power_find_gpio(config->gpio_name, "aux-sel"))
|
||||
gpio_direction_output(config->gpio,
|
||||
config->value);
|
||||
else
|
||||
gpio_set_value(config->gpio, config->value);
|
||||
|
||||
}
|
||||
config++;
|
||||
}
|
||||
}
|
||||
|
||||
static int dp_power_config_gpios(struct dp_power_private *power, bool flip,
|
||||
bool enable)
|
||||
{
|
||||
int rc = 0, i;
|
||||
struct dss_module_power *mp;
|
||||
struct dss_gpio *config;
|
||||
|
||||
if (power->parser->no_aux_switch)
|
||||
return 0;
|
||||
|
||||
mp = &power->parser->mp[DP_CORE_PM];
|
||||
config = mp->gpio_config;
|
||||
|
||||
if (enable) {
|
||||
rc = dp_power_request_gpios(power);
|
||||
if (rc) {
|
||||
DP_ERR("gpio request failed\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
dp_power_set_gpio(power, flip);
|
||||
} else {
|
||||
for (i = 0; i < mp->num_gpio; i++) {
|
||||
if (gpio_is_valid(config[i].gpio)) {
|
||||
gpio_set_value(config[i].gpio, 0);
|
||||
gpio_free(config[i].gpio);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dp_power_client_init(struct dp_power *dp_power,
|
||||
struct sde_power_handle *phandle, struct drm_device *drm_dev)
|
||||
{
|
||||
int rc = 0;
|
||||
struct dp_power_private *power;
|
||||
|
||||
if (!drm_dev) {
|
||||
DP_ERR("invalid drm_dev\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
power = container_of(dp_power, struct dp_power_private, dp_power);
|
||||
|
||||
rc = dp_power_regulator_init(power);
|
||||
if (rc) {
|
||||
DP_ERR("failed to init regulators\n");
|
||||
goto error_power;
|
||||
}
|
||||
|
||||
rc = dp_power_clk_init(power, true);
|
||||
if (rc) {
|
||||
DP_ERR("failed to init clocks\n");
|
||||
goto error_clk;
|
||||
}
|
||||
dp_power->phandle = phandle;
|
||||
dp_power->drm_dev = drm_dev;
|
||||
|
||||
return 0;
|
||||
|
||||
error_clk:
|
||||
dp_power_regulator_deinit(power);
|
||||
error_power:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void dp_power_client_deinit(struct dp_power *dp_power)
|
||||
{
|
||||
struct dp_power_private *power;
|
||||
|
||||
if (!dp_power) {
|
||||
DP_ERR("invalid power data\n");
|
||||
return;
|
||||
}
|
||||
|
||||
power = container_of(dp_power, struct dp_power_private, dp_power);
|
||||
|
||||
dp_power_clk_init(power, false);
|
||||
dp_power_regulator_deinit(power);
|
||||
}
|
||||
|
||||
static int dp_power_set_pixel_clk_parent(struct dp_power *dp_power, u32 strm_id)
|
||||
{
|
||||
int rc = 0;
|
||||
struct dp_power_private *power;
|
||||
|
||||
if (!dp_power || strm_id >= DP_STREAM_MAX) {
|
||||
DP_ERR("invalid power data. stream %d\n", strm_id);
|
||||
rc = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
power = container_of(dp_power, struct dp_power_private, dp_power);
|
||||
|
||||
if (strm_id == DP_STREAM_0) {
|
||||
if (power->pixel_clk_rcg && power->pixel_parent)
|
||||
rc = clk_set_parent(power->pixel_clk_rcg,
|
||||
power->pixel_parent);
|
||||
else
|
||||
DP_WARN("skipped for strm_id=%d\n", strm_id);
|
||||
} else if (strm_id == DP_STREAM_1) {
|
||||
if (power->pixel1_clk_rcg && power->pixel_parent)
|
||||
rc = clk_set_parent(power->pixel1_clk_rcg,
|
||||
power->pixel_parent);
|
||||
else
|
||||
DP_WARN("skipped for strm_id=%d\n", strm_id);
|
||||
}
|
||||
|
||||
if (rc)
|
||||
DP_ERR("failed. strm_id=%d, rc=%d\n", strm_id, rc);
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static u64 dp_power_clk_get_rate(struct dp_power *dp_power, char *clk_name)
|
||||
{
|
||||
size_t i;
|
||||
enum dp_pm_type j;
|
||||
struct dss_module_power *mp;
|
||||
struct dp_power_private *power;
|
||||
bool clk_found = false;
|
||||
u64 rate = 0;
|
||||
|
||||
if (!clk_name) {
|
||||
DP_ERR("invalid pointer for clk_name\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
power = container_of(dp_power, struct dp_power_private, dp_power);
|
||||
mp = &dp_power->phandle->mp;
|
||||
for (i = 0; i < mp->num_clk; i++) {
|
||||
if (!strcmp(mp->clk_config[i].clk_name, clk_name)) {
|
||||
rate = clk_get_rate(mp->clk_config[i].clk);
|
||||
clk_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (j = DP_CORE_PM; j < DP_MAX_PM && !clk_found; j++) {
|
||||
mp = &power->parser->mp[j];
|
||||
for (i = 0; i < mp->num_clk; i++) {
|
||||
if (!strcmp(mp->clk_config[i].clk_name, clk_name)) {
|
||||
rate = clk_get_rate(mp->clk_config[i].clk);
|
||||
clk_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
static int dp_power_init(struct dp_power *dp_power, bool flip)
|
||||
{
|
||||
int rc = 0;
|
||||
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_regulator_ctrl(power, true);
|
||||
if (rc) {
|
||||
DP_ERR("failed to enable regulators\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = dp_power_pinctrl_set(power, true);
|
||||
if (rc) {
|
||||
DP_ERR("failed to set pinctrl state\n");
|
||||
goto err_pinctrl;
|
||||
}
|
||||
|
||||
rc = dp_power_config_gpios(power, flip, true);
|
||||
if (rc) {
|
||||
DP_ERR("failed to enable gpios\n");
|
||||
goto err_gpio;
|
||||
}
|
||||
|
||||
rc = pm_runtime_get_sync(dp_power->drm_dev->dev);
|
||||
if (rc < 0) {
|
||||
DP_ERR("Power resource enable failed\n");
|
||||
goto err_sde_power;
|
||||
}
|
||||
|
||||
rc = dp_power_clk_enable(dp_power, DP_CORE_PM, true);
|
||||
if (rc) {
|
||||
DP_ERR("failed to enable DP core clocks\n");
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_clk:
|
||||
pm_runtime_put_sync(dp_power->drm_dev->dev);
|
||||
err_sde_power:
|
||||
dp_power_config_gpios(power, flip, false);
|
||||
err_gpio:
|
||||
dp_power_pinctrl_set(power, false);
|
||||
err_pinctrl:
|
||||
dp_power_regulator_ctrl(power, false);
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int dp_power_deinit(struct dp_power *dp_power)
|
||||
{
|
||||
int rc = 0;
|
||||
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);
|
||||
|
||||
if (power->link_clks_on)
|
||||
dp_power_clk_enable(dp_power, DP_LINK_PM, false);
|
||||
|
||||
dp_power_clk_enable(dp_power, DP_CORE_PM, false);
|
||||
pm_runtime_put_sync(dp_power->drm_dev->dev);
|
||||
|
||||
dp_power_config_gpios(power, false, false);
|
||||
dp_power_pinctrl_set(power, false);
|
||||
dp_power_regulator_ctrl(power, false);
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
struct dp_power *dp_power_get(struct dp_parser *parser, struct dp_pll *pll)
|
||||
{
|
||||
int rc = 0;
|
||||
struct dp_power_private *power;
|
||||
struct dp_power *dp_power;
|
||||
|
||||
if (!parser || !pll) {
|
||||
DP_ERR("invalid input\n");
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
power = kzalloc(sizeof(*power), GFP_KERNEL);
|
||||
if (!power) {
|
||||
rc = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
power->parser = parser;
|
||||
power->pll = pll;
|
||||
power->pdev = parser->pdev;
|
||||
|
||||
dp_power = &power->dp_power;
|
||||
|
||||
dp_power->init = dp_power_init;
|
||||
dp_power->deinit = dp_power_deinit;
|
||||
dp_power->clk_enable = dp_power_clk_enable;
|
||||
dp_power->set_pixel_clk_parent = dp_power_set_pixel_clk_parent;
|
||||
dp_power->clk_get_rate = dp_power_clk_get_rate;
|
||||
dp_power->power_client_init = dp_power_client_init;
|
||||
dp_power->power_client_deinit = dp_power_client_deinit;
|
||||
|
||||
return dp_power;
|
||||
error:
|
||||
return ERR_PTR(rc);
|
||||
}
|
||||
|
||||
void dp_power_put(struct dp_power *dp_power)
|
||||
{
|
||||
struct dp_power_private *power = NULL;
|
||||
|
||||
if (!dp_power)
|
||||
return;
|
||||
|
||||
power = container_of(dp_power, struct dp_power_private, dp_power);
|
||||
|
||||
kfree(power);
|
||||
}
|
58
techpack/display/msm/dp/dp_power.h
Normal file
58
techpack/display/msm/dp/dp_power.h
Normal file
@ -0,0 +1,58 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _DP_POWER_H_
|
||||
#define _DP_POWER_H_
|
||||
|
||||
#include "dp_parser.h"
|
||||
#include "dp_pll.h"
|
||||
#include "sde_power_handle.h"
|
||||
|
||||
/**
|
||||
* sruct dp_power - DisplayPort's power related data
|
||||
*
|
||||
* @init: initializes the regulators/core clocks/GPIOs/pinctrl
|
||||
* @deinit: turns off the regulators/core clocks/GPIOs/pinctrl
|
||||
* @clk_enable: enable/disable the DP clocks
|
||||
* @set_pixel_clk_parent: set the parent of DP pixel clock
|
||||
* @clk_get_rate: get the current rate for provided clk_name
|
||||
* @power_client_init: configures clocks and regulators
|
||||
* @power_client_deinit: frees clock and regulator resources
|
||||
*/
|
||||
struct dp_power {
|
||||
struct drm_device *drm_dev;
|
||||
struct sde_power_handle *phandle;
|
||||
int (*init)(struct dp_power *power, bool flip);
|
||||
int (*deinit)(struct dp_power *power);
|
||||
int (*clk_enable)(struct dp_power *power, enum dp_pm_type pm_type,
|
||||
bool enable);
|
||||
int (*set_pixel_clk_parent)(struct dp_power *power, u32 stream_id);
|
||||
u64 (*clk_get_rate)(struct dp_power *power, char *clk_name);
|
||||
int (*power_client_init)(struct dp_power *power,
|
||||
struct sde_power_handle *phandle,
|
||||
struct drm_device *drm_dev);
|
||||
void (*power_client_deinit)(struct dp_power *power);
|
||||
};
|
||||
|
||||
/**
|
||||
* dp_power_get() - configure and get the DisplayPort power module data
|
||||
*
|
||||
* @parser: instance of parser module
|
||||
* @pll: instance of pll module
|
||||
* return: pointer to allocated power module data
|
||||
*
|
||||
* This API will configure the DisplayPort's power module and provides
|
||||
* methods to be called by the client to configure the power related
|
||||
* modueles.
|
||||
*/
|
||||
struct dp_power *dp_power_get(struct dp_parser *parser, struct dp_pll *pll);
|
||||
|
||||
/**
|
||||
* dp_power_put() - release the power related resources
|
||||
*
|
||||
* @power: pointer to the power module's data
|
||||
*/
|
||||
void dp_power_put(struct dp_power *power);
|
||||
#endif /* _DP_POWER_H_ */
|
439
techpack/display/msm/dp/dp_reg.h
Normal file
439
techpack/display/msm/dp/dp_reg.h
Normal file
@ -0,0 +1,439 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _DP_REG_H_
|
||||
#define _DP_REG_H_
|
||||
|
||||
/* DP_TX Registers */
|
||||
#define DP_HW_VERSION (0x00000000)
|
||||
#define DP_SW_RESET (0x00000010)
|
||||
#define DP_PHY_CTRL (0x00000014)
|
||||
#define DP_CLK_CTRL (0x00000018)
|
||||
#define DP_CLK_ACTIVE (0x0000001C)
|
||||
#define DP_INTR_STATUS (0x00000020)
|
||||
#define DP_INTR_STATUS2 (0x00000024)
|
||||
#define DP_INTR_STATUS3 (0x00000028)
|
||||
#define DP_INTR_STATUS5 (0x00000034)
|
||||
|
||||
#define DP_DP_HPD_CTRL (0x00000000)
|
||||
#define DP_DP_HPD_INT_STATUS (0x00000004)
|
||||
#define DP_DP_HPD_INT_ACK (0x00000008)
|
||||
#define DP_DP_HPD_INT_MASK (0x0000000C)
|
||||
#define DP_DP_HPD_REFTIMER (0x00000018)
|
||||
#define DP_DP_HPD_EVENT_TIME_0 (0x0000001C)
|
||||
#define DP_DP_HPD_EVENT_TIME_1 (0x00000020)
|
||||
#define DP_AUX_CTRL (0x00000030)
|
||||
#define DP_AUX_DATA (0x00000034)
|
||||
#define DP_AUX_TRANS_CTRL (0x00000038)
|
||||
#define DP_TIMEOUT_COUNT (0x0000003C)
|
||||
#define DP_AUX_LIMITS (0x00000040)
|
||||
#define DP_AUX_STATUS (0x00000044)
|
||||
|
||||
#define DP_DPCD_CP_IRQ (0x201)
|
||||
#define DP_DPCD_RXSTATUS (0x69493)
|
||||
|
||||
#define DP_INTERRUPT_TRANS_NUM (0x000000A0)
|
||||
|
||||
#define DP_MAINLINK_CTRL (0x00000000)
|
||||
#define DP_STATE_CTRL (0x00000004)
|
||||
#define DP_CONFIGURATION_CTRL (0x00000008)
|
||||
#define DP_SOFTWARE_MVID (0x00000010)
|
||||
#define DP_SOFTWARE_NVID (0x00000018)
|
||||
#define DP_TOTAL_HOR_VER (0x0000001C)
|
||||
#define DP_START_HOR_VER_FROM_SYNC (0x00000020)
|
||||
#define DP_HSYNC_VSYNC_WIDTH_POLARITY (0x00000024)
|
||||
#define DP_ACTIVE_HOR_VER (0x00000028)
|
||||
#define DP_MISC1_MISC0 (0x0000002C)
|
||||
#define DP_VALID_BOUNDARY (0x00000030)
|
||||
#define DP_VALID_BOUNDARY_2 (0x00000034)
|
||||
#define DP_LOGICAL2PHYSICAL_LANE_MAPPING (0x00000038)
|
||||
|
||||
#define DP1_CONFIGURATION_CTRL (0x00000400)
|
||||
#define DP_DP0_TIMESLOT_1_32 (0x00000404)
|
||||
#define DP_DP0_TIMESLOT_33_63 (0x00000408)
|
||||
#define DP_DP1_TIMESLOT_1_32 (0x0000040C)
|
||||
#define DP_DP1_TIMESLOT_33_63 (0x00000410)
|
||||
#define DP1_SOFTWARE_MVID (0x00000414)
|
||||
#define DP1_SOFTWARE_NVID (0x00000418)
|
||||
#define DP1_TOTAL_HOR_VER (0x0000041C)
|
||||
#define DP1_START_HOR_VER_FROM_SYNC (0x00000420)
|
||||
#define DP1_HSYNC_VSYNC_WIDTH_POLARITY (0x00000424)
|
||||
#define DP1_ACTIVE_HOR_VER (0x00000428)
|
||||
#define DP1_MISC1_MISC0 (0x0000042C)
|
||||
#define DP_DP0_RG (0x000004F8)
|
||||
#define DP_DP1_RG (0x000004FC)
|
||||
|
||||
#define DP_MST_ACT (0x00000500)
|
||||
#define DP_MST_MAINLINK_READY (0x00000504)
|
||||
|
||||
#define DP_MAINLINK_READY (0x00000040)
|
||||
#define DP_MAINLINK_LEVELS (0x00000044)
|
||||
#define DP_TU (0x0000004C)
|
||||
|
||||
#define DP_HBR2_COMPLIANCE_SCRAMBLER_RESET (0x00000054)
|
||||
#define DP_TEST_80BIT_CUSTOM_PATTERN_REG0 (0x000000C0)
|
||||
#define DP_TEST_80BIT_CUSTOM_PATTERN_REG1 (0x000000C4)
|
||||
#define DP_TEST_80BIT_CUSTOM_PATTERN_REG2 (0x000000C8)
|
||||
|
||||
#define MMSS_DP_MISC1_MISC0 (0x0000002C)
|
||||
#define MMSS_DP_AUDIO_TIMING_GEN (0x00000080)
|
||||
#define MMSS_DP_AUDIO_TIMING_RBR_32 (0x00000084)
|
||||
#define MMSS_DP_AUDIO_TIMING_HBR_32 (0x00000088)
|
||||
#define MMSS_DP_AUDIO_TIMING_RBR_44 (0x0000008C)
|
||||
#define MMSS_DP_AUDIO_TIMING_HBR_44 (0x00000090)
|
||||
#define MMSS_DP_AUDIO_TIMING_RBR_48 (0x00000094)
|
||||
#define MMSS_DP_AUDIO_TIMING_HBR_48 (0x00000098)
|
||||
|
||||
#define MMSS_DP_PSR_CRC_RG (0x00000154)
|
||||
#define MMSS_DP_PSR_CRC_B (0x00000158)
|
||||
|
||||
#define DP_COMPRESSION_MODE_CTRL (0x00000180)
|
||||
#define DP_PPS_HB_0_3 (0x00000184)
|
||||
#define DP_PPS_PB_0_3 (0x00000188)
|
||||
#define DP_PPS_PB_4_7 (0x0000018C)
|
||||
#define DP_PPS_PB_8_11 (0x00000190)
|
||||
#define DP_PPS_PB_12_15 (0x00000194)
|
||||
#define DP_PPS_PB_16_19 (0x00000198)
|
||||
#define DP_PPS_PB_20_23 (0x0000019C)
|
||||
#define DP_PPS_PB_24_27 (0x000001A0)
|
||||
#define DP_PPS_PB_28_31 (0x000001A4)
|
||||
#define DP_PPS_PPS_0_3 (0x000001A8)
|
||||
#define DP_PPS_PPS_4_7 (0x000001AC)
|
||||
#define DP_PPS_PPS_8_11 (0x000001B0)
|
||||
#define DP_PPS_PPS_12_15 (0x000001B4)
|
||||
#define DP_PPS_PPS_16_19 (0x000001B8)
|
||||
#define DP_PPS_PPS_20_23 (0x000001BC)
|
||||
#define DP_PPS_PPS_24_27 (0x000001C0)
|
||||
#define DP_PPS_PPS_28_31 (0x000001C4)
|
||||
#define DP_PPS_PPS_32_35 (0x000001C8)
|
||||
#define DP_PPS_PPS_36_39 (0x000001CC)
|
||||
#define DP_PPS_PPS_40_43 (0x000001D0)
|
||||
#define DP_PPS_PPS_44_47 (0x000001D4)
|
||||
#define DP_PPS_PPS_48_51 (0x000001D8)
|
||||
#define DP_PPS_PPS_52_55 (0x000001DC)
|
||||
#define DP_PPS_PPS_56_59 (0x000001E0)
|
||||
#define DP_PPS_PPS_60_63 (0x000001E4)
|
||||
#define DP_PPS_PPS_64_67 (0x000001E8)
|
||||
#define DP_PPS_PPS_68_71 (0x000001EC)
|
||||
#define DP_PPS_PPS_72_75 (0x000001F0)
|
||||
#define DP_PPS_PPS_76_79 (0x000001F4)
|
||||
#define DP_PPS_PPS_80_83 (0x000001F8)
|
||||
#define DP_PPS_PPS_84_87 (0x000001FC)
|
||||
|
||||
#define MMSS_DP_AUDIO_CFG (0x00000200)
|
||||
#define MMSS_DP_AUDIO_STATUS (0x00000204)
|
||||
#define MMSS_DP_AUDIO_PKT_CTRL (0x00000208)
|
||||
#define MMSS_DP_AUDIO_PKT_CTRL2 (0x0000020C)
|
||||
#define MMSS_DP_AUDIO_ACR_CTRL (0x00000210)
|
||||
#define MMSS_DP_AUDIO_CTRL_RESET (0x00000214)
|
||||
|
||||
#define MMSS_DP_SDP_CFG (0x00000228)
|
||||
#define MMSS_DP_SDP_CFG2 (0x0000022C)
|
||||
#define MMSS_DP_SDP_CFG3 (0x0000024C)
|
||||
#define MMSS_DP_SDP_CFG4 (0x000004EC)
|
||||
#define MMSS_DP_AUDIO_TIMESTAMP_0 (0x00000230)
|
||||
#define MMSS_DP_AUDIO_TIMESTAMP_1 (0x00000234)
|
||||
|
||||
#define MMSS_DP_AUDIO_STREAM_0 (0x00000240)
|
||||
#define MMSS_DP_AUDIO_STREAM_1 (0x00000244)
|
||||
|
||||
#define MMSS_DP_EXTENSION_0 (0x00000250)
|
||||
#define MMSS_DP_EXTENSION_1 (0x00000254)
|
||||
#define MMSS_DP_EXTENSION_2 (0x00000258)
|
||||
#define MMSS_DP_EXTENSION_3 (0x0000025C)
|
||||
#define MMSS_DP_EXTENSION_4 (0x00000260)
|
||||
#define MMSS_DP_EXTENSION_5 (0x00000264)
|
||||
#define MMSS_DP_EXTENSION_6 (0x00000268)
|
||||
#define MMSS_DP_EXTENSION_7 (0x0000026C)
|
||||
#define MMSS_DP_EXTENSION_8 (0x00000270)
|
||||
#define MMSS_DP_EXTENSION_9 (0x00000274)
|
||||
#define MMSS_DP_AUDIO_COPYMANAGEMENT_0 (0x00000278)
|
||||
#define MMSS_DP_AUDIO_COPYMANAGEMENT_1 (0x0000027C)
|
||||
#define MMSS_DP_AUDIO_COPYMANAGEMENT_2 (0x00000280)
|
||||
#define MMSS_DP_AUDIO_COPYMANAGEMENT_3 (0x00000284)
|
||||
#define MMSS_DP_AUDIO_COPYMANAGEMENT_4 (0x00000288)
|
||||
#define MMSS_DP_AUDIO_COPYMANAGEMENT_5 (0x0000028C)
|
||||
#define MMSS_DP_AUDIO_ISRC_0 (0x00000290)
|
||||
#define MMSS_DP_AUDIO_ISRC_1 (0x00000294)
|
||||
#define MMSS_DP_AUDIO_ISRC_2 (0x00000298)
|
||||
#define MMSS_DP_AUDIO_ISRC_3 (0x0000029C)
|
||||
#define MMSS_DP_AUDIO_ISRC_4 (0x000002A0)
|
||||
#define MMSS_DP_AUDIO_ISRC_5 (0x000002A4)
|
||||
#define MMSS_DP_AUDIO_INFOFRAME_0 (0x000002A8)
|
||||
#define MMSS_DP_AUDIO_INFOFRAME_1 (0x000002AC)
|
||||
#define MMSS_DP_AUDIO_INFOFRAME_2 (0x000002B0)
|
||||
|
||||
#define MMSS_DP_FLUSH (0x000002F8)
|
||||
#define MMSS_DP1_FLUSH (0x000002FC)
|
||||
|
||||
#define MMSS_DP_GENERIC0_0 (0x00000300)
|
||||
#define MMSS_DP_GENERIC0_1 (0x00000304)
|
||||
#define MMSS_DP_GENERIC0_2 (0x00000308)
|
||||
#define MMSS_DP_GENERIC0_3 (0x0000030C)
|
||||
#define MMSS_DP_GENERIC0_4 (0x00000310)
|
||||
#define MMSS_DP_GENERIC0_5 (0x00000314)
|
||||
#define MMSS_DP_GENERIC0_6 (0x00000318)
|
||||
#define MMSS_DP_GENERIC0_7 (0x0000031C)
|
||||
#define MMSS_DP_GENERIC0_8 (0x00000320)
|
||||
#define MMSS_DP_GENERIC0_9 (0x00000324)
|
||||
#define MMSS_DP_GENERIC1_0 (0x00000328)
|
||||
#define MMSS_DP_GENERIC1_1 (0x0000032C)
|
||||
#define MMSS_DP_GENERIC1_2 (0x00000330)
|
||||
#define MMSS_DP_GENERIC1_3 (0x00000334)
|
||||
#define MMSS_DP_GENERIC1_4 (0x00000338)
|
||||
#define MMSS_DP_GENERIC1_5 (0x0000033C)
|
||||
#define MMSS_DP_GENERIC1_6 (0x00000340)
|
||||
#define MMSS_DP_GENERIC1_7 (0x00000344)
|
||||
#define MMSS_DP_GENERIC1_8 (0x00000348)
|
||||
#define MMSS_DP_GENERIC1_9 (0x0000034C)
|
||||
|
||||
#define MMSS_DP1_GENERIC0_0 (0x00000490)
|
||||
#define MMSS_DP1_GENERIC0_1 (0x00000494)
|
||||
#define MMSS_DP1_GENERIC0_2 (0x00000498)
|
||||
#define MMSS_DP1_GENERIC0_3 (0x0000049C)
|
||||
#define MMSS_DP1_GENERIC0_4 (0x000004A0)
|
||||
#define MMSS_DP1_GENERIC0_5 (0x000004A4)
|
||||
#define MMSS_DP1_GENERIC0_6 (0x000004A8)
|
||||
#define MMSS_DP1_GENERIC0_7 (0x000004AC)
|
||||
#define MMSS_DP1_GENERIC0_8 (0x000004B0)
|
||||
#define MMSS_DP1_GENERIC0_9 (0x000004B4)
|
||||
#define MMSS_DP1_GENERIC1_0 (0x000004B8)
|
||||
#define MMSS_DP1_GENERIC1_1 (0x000004BC)
|
||||
#define MMSS_DP1_GENERIC1_2 (0x000004C0)
|
||||
#define MMSS_DP1_GENERIC1_3 (0x000004C4)
|
||||
#define MMSS_DP1_GENERIC1_4 (0x000004C8)
|
||||
#define MMSS_DP1_GENERIC1_5 (0x000004CC)
|
||||
#define MMSS_DP1_GENERIC1_6 (0x000004D0)
|
||||
#define MMSS_DP1_GENERIC1_7 (0x000004D4)
|
||||
#define MMSS_DP1_GENERIC1_8 (0x000004D8)
|
||||
#define MMSS_DP1_GENERIC1_9 (0x000004DC)
|
||||
|
||||
#define MMSS_DP_GENERIC2_0 (0x000003d8)
|
||||
#define MMSS_DP_GENERIC2_1 (0x000003dc)
|
||||
#define MMSS_DP_GENERIC2_2 (0x000003e0)
|
||||
#define MMSS_DP_GENERIC2_3 (0x000003e4)
|
||||
#define MMSS_DP_GENERIC2_4 (0x000003e8)
|
||||
#define MMSS_DP_GENERIC2_5 (0x000003ec)
|
||||
#define MMSS_DP_GENERIC2_6 (0x000003f0)
|
||||
#define MMSS_DP_GENERIC2_7 (0x000003f4)
|
||||
#define MMSS_DP_GENERIC2_8 (0x000003f8)
|
||||
#define MMSS_DP_GENERIC2_9 (0x000003fc)
|
||||
#define MMSS_DP1_GENERIC2_0 (0x00000510)
|
||||
#define MMSS_DP1_GENERIC2_1 (0x00000514)
|
||||
#define MMSS_DP1_GENERIC2_2 (0x00000518)
|
||||
#define MMSS_DP1_GENERIC2_3 (0x0000051c)
|
||||
#define MMSS_DP1_GENERIC2_4 (0x00000520)
|
||||
#define MMSS_DP1_GENERIC2_5 (0x00000524)
|
||||
#define MMSS_DP1_GENERIC2_6 (0x00000528)
|
||||
#define MMSS_DP1_GENERIC2_7 (0x0000052C)
|
||||
#define MMSS_DP1_GENERIC2_8 (0x00000530)
|
||||
#define MMSS_DP1_GENERIC2_9 (0x00000534)
|
||||
|
||||
#define MMSS_DP1_SDP_CFG (0x000004E0)
|
||||
#define MMSS_DP1_SDP_CFG2 (0x000004E4)
|
||||
#define MMSS_DP1_SDP_CFG3 (0x000004E8)
|
||||
#define MMSS_DP1_SDP_CFG4 (0x000004F0)
|
||||
|
||||
#define DP1_COMPRESSION_MODE_CTRL (0x00000560)
|
||||
#define DP1_PPS_HB_0_3 (0x00000564)
|
||||
#define DP1_PPS_PB_0_3 (0x00000568)
|
||||
#define DP1_PPS_PB_4_7 (0x0000056C)
|
||||
#define DP1_PPS_PB_8_11 (0x00000570)
|
||||
#define DP1_PPS_PB_12_15 (0x00000574)
|
||||
#define DP1_PPS_PB_16_19 (0x00000578)
|
||||
#define DP1_PPS_PB_20_23 (0x0000057C)
|
||||
#define DP1_PPS_PB_24_27 (0x00000580)
|
||||
#define DP1_PPS_PB_28_31 (0x00000584)
|
||||
#define DP1_PPS_PPS_0_3 (0x00000588)
|
||||
#define DP1_PPS_PPS_4_7 (0x0000058C)
|
||||
#define DP1_PPS_PPS_8_11 (0x00000590)
|
||||
#define DP1_PPS_PPS_12_15 (0x00000594)
|
||||
#define DP1_PPS_PPS_16_19 (0x00000598)
|
||||
#define DP1_PPS_PPS_20_23 (0x0000059C)
|
||||
#define DP1_PPS_PPS_24_27 (0x000005A0)
|
||||
#define DP1_PPS_PPS_28_31 (0x000005A4)
|
||||
#define DP1_PPS_PPS_32_35 (0x000005A8)
|
||||
#define DP1_PPS_PPS_36_39 (0x000005AC)
|
||||
#define DP1_PPS_PPS_40_43 (0x000005B0)
|
||||
#define DP1_PPS_PPS_44_47 (0x000005B4)
|
||||
#define DP1_PPS_PPS_48_51 (0x000005B8)
|
||||
#define DP1_PPS_PPS_52_55 (0x000005BC)
|
||||
#define DP1_PPS_PPS_56_59 (0x000005C0)
|
||||
#define DP1_PPS_PPS_60_63 (0x000005C4)
|
||||
#define DP1_PPS_PPS_64_67 (0x000005C8)
|
||||
#define DP1_PPS_PPS_68_71 (0x000005CC)
|
||||
#define DP1_PPS_PPS_72_75 (0x000005D0)
|
||||
#define DP1_PPS_PPS_76_79 (0x000005D4)
|
||||
#define DP1_PPS_PPS_80_83 (0x000005D8)
|
||||
#define DP1_PPS_PPS_84_87 (0x000005DC)
|
||||
|
||||
#define MMSS_DP_VSCEXT_0 (0x000002D0)
|
||||
#define MMSS_DP_VSCEXT_1 (0x000002D4)
|
||||
#define MMSS_DP_VSCEXT_2 (0x000002D8)
|
||||
#define MMSS_DP_VSCEXT_3 (0x000002DC)
|
||||
#define MMSS_DP_VSCEXT_4 (0x000002E0)
|
||||
#define MMSS_DP_VSCEXT_5 (0x000002E4)
|
||||
#define MMSS_DP_VSCEXT_6 (0x000002E8)
|
||||
#define MMSS_DP_VSCEXT_7 (0x000002EC)
|
||||
#define MMSS_DP_VSCEXT_8 (0x000002F0)
|
||||
#define MMSS_DP_VSCEXT_9 (0x000002F4)
|
||||
|
||||
#define MMSS_DP1_VSCEXT_0 (0x00000468)
|
||||
#define MMSS_DP1_VSCEXT_1 (0x0000046c)
|
||||
#define MMSS_DP1_VSCEXT_2 (0x00000470)
|
||||
#define MMSS_DP1_VSCEXT_3 (0x00000474)
|
||||
#define MMSS_DP1_VSCEXT_4 (0x00000478)
|
||||
#define MMSS_DP1_VSCEXT_5 (0x0000047c)
|
||||
#define MMSS_DP1_VSCEXT_6 (0x00000480)
|
||||
#define MMSS_DP1_VSCEXT_7 (0x00000484)
|
||||
#define MMSS_DP1_VSCEXT_8 (0x00000488)
|
||||
#define MMSS_DP1_VSCEXT_9 (0x0000048c)
|
||||
|
||||
#define MMSS_DP_BIST_ENABLE (0x00000000)
|
||||
#define MMSS_DP_TIMING_ENGINE_EN (0x00000010)
|
||||
#define MMSS_DP_INTF_CONFIG (0x00000014)
|
||||
#define MMSS_DP_INTF_HSYNC_CTL (0x00000018)
|
||||
#define MMSS_DP_INTF_VSYNC_PERIOD_F0 (0x0000001C)
|
||||
#define MMSS_DP_INTF_VSYNC_PERIOD_F1 (0x00000020)
|
||||
#define MMSS_DP_INTF_VSYNC_PULSE_WIDTH_F0 (0x00000024)
|
||||
#define MMSS_DP_INTF_VSYNC_PULSE_WIDTH_F1 (0x00000028)
|
||||
#define MMSS_INTF_DISPLAY_V_START_F0 (0x0000002C)
|
||||
#define MMSS_INTF_DISPLAY_V_START_F1 (0x00000030)
|
||||
#define MMSS_DP_INTF_DISPLAY_V_END_F0 (0x00000034)
|
||||
#define MMSS_DP_INTF_DISPLAY_V_END_F1 (0x00000038)
|
||||
#define MMSS_DP_INTF_ACTIVE_V_START_F0 (0x0000003C)
|
||||
#define MMSS_DP_INTF_ACTIVE_V_START_F1 (0x00000040)
|
||||
#define MMSS_DP_INTF_ACTIVE_V_END_F0 (0x00000044)
|
||||
#define MMSS_DP_INTF_ACTIVE_V_END_F1 (0x00000048)
|
||||
#define MMSS_DP_INTF_DISPLAY_HCTL (0x0000004C)
|
||||
#define MMSS_DP_INTF_ACTIVE_HCTL (0x00000050)
|
||||
#define MMSS_DP_INTF_POLARITY_CTL (0x00000058)
|
||||
#define MMSS_DP_TPG_MAIN_CONTROL (0x00000060)
|
||||
#define MMSS_DP_TPG_VIDEO_CONFIG (0x00000064)
|
||||
#define MMSS_DP_DSC_DTO (0x0000007C)
|
||||
#define MMSS_DP_DSC_DTO_COUNT (0x00000084)
|
||||
#define MMSS_DP_ASYNC_FIFO_CONFIG (0x00000088)
|
||||
|
||||
#define MMSS_DP1_BIST_ENABLE (0x00000000)
|
||||
#define MMSS_DP1_TIMING_ENGINE_EN (0x00000010)
|
||||
#define MMSS_DP1_INTF_CONFIG (0x00000014)
|
||||
#define MMSS_DP1_INTF_HSYNC_CTL (0x00000018)
|
||||
#define MMSS_DP1_INTF_VSYNC_PERIOD_F0 (0x0000001C)
|
||||
#define MMSS_DP1_INTF_VSYNC_PERIOD_F1 (0x00000020)
|
||||
#define MMSS_DP1_INTF_VSYNC_PULSE_WIDTH_F0 (0x00000024)
|
||||
#define MMSS_DP1_INTF_VSYNC_PULSE_WIDTH_F1 (0x00000028)
|
||||
#define MMSS_DP1_INTF_DISPLAY_V_START_F0 (0x0000002C)
|
||||
#define MMSS_DP1_INTF_DISPLAY_V_START_F1 (0x00000030)
|
||||
#define MMSS_DP1_INTF_DISPLAY_V_END_F0 (0x00000034)
|
||||
#define MMSS_DP1_INTF_DISPLAY_V_END_F1 (0x00000038)
|
||||
#define MMSS_DP1_INTF_ACTIVE_V_START_F0 (0x0000003C)
|
||||
#define MMSS_DP1_INTF_ACTIVE_V_START_F1 (0x00000040)
|
||||
#define MMSS_DP1_INTF_ACTIVE_V_END_F0 (0x00000044)
|
||||
#define MMSS_DP1_INTF_ACTIVE_V_END_F1 (0x00000048)
|
||||
#define MMSS_DP1_INTF_DISPLAY_HCTL (0x0000004C)
|
||||
#define MMSS_DP1_INTF_ACTIVE_HCTL (0x00000050)
|
||||
#define MMSS_DP1_INTF_POLARITY_CTL (0x00000058)
|
||||
#define MMSS_DP1_TPG_MAIN_CONTROL (0x00000060)
|
||||
#define MMSS_DP1_TPG_VIDEO_CONFIG (0x00000064)
|
||||
#define MMSS_DP1_DSC_DTO (0x0000007C)
|
||||
#define MMSS_DP1_DSC_DTO_COUNT (0x00000084)
|
||||
#define MMSS_DP1_ASYNC_FIFO_CONFIG (0x00000088)
|
||||
|
||||
/*DP PHY Register offsets */
|
||||
#define DP_PHY_REVISION_ID0 (0x00000000)
|
||||
#define DP_PHY_REVISION_ID1 (0x00000004)
|
||||
#define DP_PHY_REVISION_ID2 (0x00000008)
|
||||
#define DP_PHY_REVISION_ID3 (0x0000000C)
|
||||
|
||||
#define DP_PHY_CFG (0x00000010)
|
||||
#define DP_PHY_PD_CTL (0x00000018)
|
||||
#define DP_PHY_MODE (0x0000001C)
|
||||
|
||||
#define DP_PHY_AUX_CFG0 (0x00000020)
|
||||
#define DP_PHY_AUX_CFG1 (0x00000024)
|
||||
#define DP_PHY_AUX_CFG2 (0x00000028)
|
||||
#define DP_PHY_AUX_CFG3 (0x0000002C)
|
||||
#define DP_PHY_AUX_CFG4 (0x00000030)
|
||||
#define DP_PHY_AUX_CFG5 (0x00000034)
|
||||
#define DP_PHY_AUX_CFG6 (0x00000038)
|
||||
#define DP_PHY_AUX_CFG7 (0x0000003C)
|
||||
#define DP_PHY_AUX_CFG8 (0x00000040)
|
||||
#define DP_PHY_AUX_CFG9 (0x00000044)
|
||||
#define DP_PHY_AUX_INTERRUPT_MASK (0x00000048)
|
||||
#define DP_PHY_AUX_INTERRUPT_CLEAR (0x0000004C)
|
||||
#define DP_PHY_AUX_INTERRUPT_STATUS (0x000000BC)
|
||||
#define DP_PHY_AUX_INTERRUPT_MASK_V200 (0x00000048)
|
||||
#define DP_PHY_AUX_INTERRUPT_CLEAR_V200 (0x0000004C)
|
||||
#define DP_PHY_AUX_INTERRUPT_STATUS_V200 (0x000000BC)
|
||||
|
||||
#define DP_PHY_SPARE0 (0x00AC)
|
||||
|
||||
#define TXn_TX_EMP_POST1_LVL (0x000C)
|
||||
#define TXn_TX_DRV_LVL (0x001C)
|
||||
#define TXn_TX_POL_INV (0x0064)
|
||||
|
||||
#define TXn_TRANSCEIVER_BIAS_EN (0x005C)
|
||||
#define TXn_HIGHZ_DRVR_EN (0x0060)
|
||||
|
||||
#define DP_PHY_STATUS (0x00DC)
|
||||
#define DP_PHY_AUX_INTERRUPT_MASK_V420 (0x0054)
|
||||
#define DP_PHY_AUX_INTERRUPT_CLEAR_V420 (0x0058)
|
||||
#define DP_PHY_AUX_INTERRUPT_STATUS_V420 (0x00D8)
|
||||
#define DP_PHY_SPARE0_V420 (0x00C8)
|
||||
#define TXn_TX_DRV_LVL_V420 (0x0014)
|
||||
#define TXn_TRANSCEIVER_BIAS_EN_V420 (0x0054)
|
||||
#define TXn_HIGHZ_DRVR_EN_V420 (0x0058)
|
||||
#define TXn_TX_POL_INV_V420 (0x005C)
|
||||
|
||||
#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN (0x044)
|
||||
|
||||
/* DP MMSS_CC registers */
|
||||
#define MMSS_DP_PIXEL_M (0x01B4)
|
||||
#define MMSS_DP_PIXEL_N (0x01B8)
|
||||
#define MMSS_DP_PIXEL1_M (0x01CC)
|
||||
#define MMSS_DP_PIXEL1_N (0x01D0)
|
||||
#define MMSS_DP_PIXEL_M_V200 (0x0130)
|
||||
#define MMSS_DP_PIXEL_N_V200 (0x0134)
|
||||
#define MMSS_DP_PIXEL1_M_V200 (0x0148)
|
||||
#define MMSS_DP_PIXEL1_N_V200 (0x014C)
|
||||
#define MMSS_DP_PIXEL_M_V420 (0x01B0)
|
||||
#define MMSS_DP_PIXEL_N_V420 (0x01B4)
|
||||
#define MMSS_DP_PIXEL1_M_V420 (0x01C8)
|
||||
#define MMSS_DP_PIXEL1_N_V420 (0x01CC)
|
||||
|
||||
/* DP HDCP 1.3 registers */
|
||||
#define DP_HDCP_CTRL (0x0A0)
|
||||
#define DP_HDCP_STATUS (0x0A4)
|
||||
#define DP_HDCP_SW_UPPER_AKSV (0x098)
|
||||
#define DP_HDCP_SW_LOWER_AKSV (0x09C)
|
||||
#define DP_HDCP_ENTROPY_CTRL0 (0x350)
|
||||
#define DP_HDCP_ENTROPY_CTRL1 (0x35C)
|
||||
#define DP_HDCP_SHA_STATUS (0x0C8)
|
||||
#define DP_HDCP_RCVPORT_DATA2_0 (0x0B0)
|
||||
#define DP_HDCP_RCVPORT_DATA3 (0x0A4)
|
||||
#define DP_HDCP_RCVPORT_DATA4 (0x0A8)
|
||||
#define DP_HDCP_RCVPORT_DATA5 (0x0C0)
|
||||
#define DP_HDCP_RCVPORT_DATA6 (0x0C4)
|
||||
|
||||
#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_CTRL (0x024)
|
||||
#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_DATA (0x028)
|
||||
#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA0 (0x004)
|
||||
#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA1 (0x008)
|
||||
#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA7 (0x00C)
|
||||
#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA8 (0x010)
|
||||
#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA9 (0x014)
|
||||
#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA10 (0x018)
|
||||
#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA11 (0x01C)
|
||||
#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA12 (0x020)
|
||||
|
||||
/* USB3 DP COM registers */
|
||||
#define USB3_DP_COM_PHY_MODE_CTRL (0x00)
|
||||
#define USB3_DP_COM_SW_RESET (0x04)
|
||||
#define USB3_DP_COM_POWER_DOWN_CTRL (0x08)
|
||||
#define USB3_DP_COM_SWI_CTRL (0x0C)
|
||||
#define USB3_DP_COM_TYPEC_CTRL (0x10)
|
||||
#define USB3_DP_COM_RESET_OVRD_CTRL (0x1C)
|
||||
|
||||
#endif /* _DP_REG_H_ */
|
582
techpack/display/msm/dp/dp_usbpd.c
Normal file
582
techpack/display/msm/dp/dp_usbpd.c
Normal file
@ -0,0 +1,582 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/usb/usbpd.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "dp_usbpd.h"
|
||||
#include "dp_debug.h"
|
||||
|
||||
/* DP specific VDM commands */
|
||||
#define DP_USBPD_VDM_STATUS 0x10
|
||||
#define DP_USBPD_VDM_CONFIGURE 0x11
|
||||
|
||||
/* USBPD-TypeC specific Macros */
|
||||
#define VDM_VERSION 0x0
|
||||
#define USB_C_DP_SID 0xFF01
|
||||
|
||||
enum dp_usbpd_pin_assignment {
|
||||
DP_USBPD_PIN_A,
|
||||
DP_USBPD_PIN_B,
|
||||
DP_USBPD_PIN_C,
|
||||
DP_USBPD_PIN_D,
|
||||
DP_USBPD_PIN_E,
|
||||
DP_USBPD_PIN_F,
|
||||
DP_USBPD_PIN_MAX,
|
||||
};
|
||||
|
||||
enum dp_usbpd_events {
|
||||
DP_USBPD_EVT_DISCOVER,
|
||||
DP_USBPD_EVT_ENTER,
|
||||
DP_USBPD_EVT_STATUS,
|
||||
DP_USBPD_EVT_CONFIGURE,
|
||||
DP_USBPD_EVT_CC_PIN_POLARITY,
|
||||
DP_USBPD_EVT_EXIT,
|
||||
DP_USBPD_EVT_ATTENTION,
|
||||
};
|
||||
|
||||
enum dp_usbpd_alt_mode {
|
||||
DP_USBPD_ALT_MODE_NONE = 0,
|
||||
DP_USBPD_ALT_MODE_INIT = BIT(0),
|
||||
DP_USBPD_ALT_MODE_DISCOVER = BIT(1),
|
||||
DP_USBPD_ALT_MODE_ENTER = BIT(2),
|
||||
DP_USBPD_ALT_MODE_STATUS = BIT(3),
|
||||
DP_USBPD_ALT_MODE_CONFIGURE = BIT(4),
|
||||
};
|
||||
|
||||
struct dp_usbpd_capabilities {
|
||||
enum dp_usbpd_port port;
|
||||
bool receptacle_state;
|
||||
u8 ulink_pin_config;
|
||||
u8 dlink_pin_config;
|
||||
};
|
||||
|
||||
struct dp_usbpd_private {
|
||||
bool forced_disconnect;
|
||||
u32 vdo;
|
||||
struct device *dev;
|
||||
struct usbpd *pd;
|
||||
struct usbpd_svid_handler svid_handler;
|
||||
struct dp_hpd_cb *dp_cb;
|
||||
struct dp_usbpd_capabilities cap;
|
||||
struct dp_usbpd dp_usbpd;
|
||||
enum dp_usbpd_alt_mode alt_mode;
|
||||
u32 dp_usbpd_config;
|
||||
};
|
||||
|
||||
static const char *dp_usbpd_pin_name(u8 pin)
|
||||
{
|
||||
switch (pin) {
|
||||
case DP_USBPD_PIN_A: return "DP_USBPD_PIN_ASSIGNMENT_A";
|
||||
case DP_USBPD_PIN_B: return "DP_USBPD_PIN_ASSIGNMENT_B";
|
||||
case DP_USBPD_PIN_C: return "DP_USBPD_PIN_ASSIGNMENT_C";
|
||||
case DP_USBPD_PIN_D: return "DP_USBPD_PIN_ASSIGNMENT_D";
|
||||
case DP_USBPD_PIN_E: return "DP_USBPD_PIN_ASSIGNMENT_E";
|
||||
case DP_USBPD_PIN_F: return "DP_USBPD_PIN_ASSIGNMENT_F";
|
||||
default: return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
static const char *dp_usbpd_port_name(enum dp_usbpd_port port)
|
||||
{
|
||||
switch (port) {
|
||||
case DP_USBPD_PORT_NONE: return "DP_USBPD_PORT_NONE";
|
||||
case DP_USBPD_PORT_UFP_D: return "DP_USBPD_PORT_UFP_D";
|
||||
case DP_USBPD_PORT_DFP_D: return "DP_USBPD_PORT_DFP_D";
|
||||
case DP_USBPD_PORT_D_UFP_D: return "DP_USBPD_PORT_D_UFP_D";
|
||||
default: return "DP_USBPD_PORT_NONE";
|
||||
}
|
||||
}
|
||||
|
||||
static const char *dp_usbpd_cmd_name(u8 cmd)
|
||||
{
|
||||
switch (cmd) {
|
||||
case USBPD_SVDM_DISCOVER_MODES: return "USBPD_SVDM_DISCOVER_MODES";
|
||||
case USBPD_SVDM_ENTER_MODE: return "USBPD_SVDM_ENTER_MODE";
|
||||
case USBPD_SVDM_ATTENTION: return "USBPD_SVDM_ATTENTION";
|
||||
case DP_USBPD_VDM_STATUS: return "DP_USBPD_VDM_STATUS";
|
||||
case DP_USBPD_VDM_CONFIGURE: return "DP_USBPD_VDM_CONFIGURE";
|
||||
default: return "DP_USBPD_VDM_ERROR";
|
||||
}
|
||||
}
|
||||
|
||||
static void dp_usbpd_init_port(enum dp_usbpd_port *port, u32 in_port)
|
||||
{
|
||||
switch (in_port) {
|
||||
case 0:
|
||||
*port = DP_USBPD_PORT_NONE;
|
||||
break;
|
||||
case 1:
|
||||
*port = DP_USBPD_PORT_UFP_D;
|
||||
break;
|
||||
case 2:
|
||||
*port = DP_USBPD_PORT_DFP_D;
|
||||
break;
|
||||
case 3:
|
||||
*port = DP_USBPD_PORT_D_UFP_D;
|
||||
break;
|
||||
default:
|
||||
*port = DP_USBPD_PORT_NONE;
|
||||
}
|
||||
DP_DEBUG("port:%s\n", dp_usbpd_port_name(*port));
|
||||
}
|
||||
|
||||
static void dp_usbpd_get_capabilities(struct dp_usbpd_private *pd)
|
||||
{
|
||||
struct dp_usbpd_capabilities *cap = &pd->cap;
|
||||
u32 buf = pd->vdo;
|
||||
int port = buf & 0x3;
|
||||
|
||||
cap->receptacle_state = (buf & BIT(6)) ? true : false;
|
||||
cap->dlink_pin_config = (buf >> 8) & 0xff;
|
||||
cap->ulink_pin_config = (buf >> 16) & 0xff;
|
||||
|
||||
dp_usbpd_init_port(&cap->port, port);
|
||||
}
|
||||
|
||||
static void dp_usbpd_get_status(struct dp_usbpd_private *pd)
|
||||
{
|
||||
struct dp_usbpd *status = &pd->dp_usbpd;
|
||||
u32 buf = pd->vdo;
|
||||
int port = buf & 0x3;
|
||||
|
||||
status->low_pow_st = (buf & BIT(2)) ? true : false;
|
||||
status->adaptor_dp_en = (buf & BIT(3)) ? true : false;
|
||||
status->base.multi_func = (buf & BIT(4)) ? true : false;
|
||||
status->usb_config_req = (buf & BIT(5)) ? true : false;
|
||||
status->exit_dp_mode = (buf & BIT(6)) ? true : false;
|
||||
status->base.hpd_high = (buf & BIT(7)) ? true : false;
|
||||
status->base.hpd_irq = (buf & BIT(8)) ? true : false;
|
||||
|
||||
DP_DEBUG("low_pow_st = %d, adaptor_dp_en = %d, multi_func = %d\n",
|
||||
status->low_pow_st, status->adaptor_dp_en,
|
||||
status->base.multi_func);
|
||||
DP_DEBUG("usb_config_req = %d, exit_dp_mode = %d, hpd_high =%d\n",
|
||||
status->usb_config_req,
|
||||
status->exit_dp_mode, status->base.hpd_high);
|
||||
DP_DEBUG("hpd_irq = %d\n", status->base.hpd_irq);
|
||||
|
||||
dp_usbpd_init_port(&status->port, port);
|
||||
}
|
||||
|
||||
static u32 dp_usbpd_gen_config_pkt(struct dp_usbpd_private *pd)
|
||||
{
|
||||
u8 pin_cfg, pin;
|
||||
u32 config = 0;
|
||||
const u32 ufp_d_config = 0x2, dp_ver = 0x1;
|
||||
|
||||
if (pd->cap.receptacle_state)
|
||||
pin_cfg = pd->cap.ulink_pin_config;
|
||||
else
|
||||
pin_cfg = pd->cap.dlink_pin_config;
|
||||
|
||||
for (pin = DP_USBPD_PIN_A; pin < DP_USBPD_PIN_MAX; pin++) {
|
||||
if (pin_cfg & BIT(pin)) {
|
||||
if (pd->dp_usbpd.base.multi_func) {
|
||||
if (pin == DP_USBPD_PIN_D)
|
||||
break;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pin == DP_USBPD_PIN_MAX)
|
||||
pin = DP_USBPD_PIN_C;
|
||||
|
||||
DP_DEBUG("pin assignment: %s\n", dp_usbpd_pin_name(pin));
|
||||
|
||||
config |= BIT(pin) << 8;
|
||||
|
||||
config |= (dp_ver << 2);
|
||||
config |= ufp_d_config;
|
||||
|
||||
DP_DEBUG("config = 0x%x\n", config);
|
||||
return config;
|
||||
}
|
||||
|
||||
static void dp_usbpd_send_event(struct dp_usbpd_private *pd,
|
||||
enum dp_usbpd_events event)
|
||||
{
|
||||
u32 config;
|
||||
|
||||
switch (event) {
|
||||
case DP_USBPD_EVT_DISCOVER:
|
||||
usbpd_send_svdm(pd->pd, USB_C_DP_SID,
|
||||
USBPD_SVDM_DISCOVER_MODES,
|
||||
SVDM_CMD_TYPE_INITIATOR, 0x0, 0x0, 0x0);
|
||||
break;
|
||||
case DP_USBPD_EVT_ENTER:
|
||||
usbpd_send_svdm(pd->pd, USB_C_DP_SID,
|
||||
USBPD_SVDM_ENTER_MODE,
|
||||
SVDM_CMD_TYPE_INITIATOR, 0x1, 0x0, 0x0);
|
||||
break;
|
||||
case DP_USBPD_EVT_EXIT:
|
||||
usbpd_send_svdm(pd->pd, USB_C_DP_SID,
|
||||
USBPD_SVDM_EXIT_MODE,
|
||||
SVDM_CMD_TYPE_INITIATOR, 0x1, 0x0, 0x0);
|
||||
break;
|
||||
case DP_USBPD_EVT_STATUS:
|
||||
config = 0x1; /* DFP_D connected */
|
||||
usbpd_send_svdm(pd->pd, USB_C_DP_SID, DP_USBPD_VDM_STATUS,
|
||||
SVDM_CMD_TYPE_INITIATOR, 0x1, &config, 0x1);
|
||||
break;
|
||||
case DP_USBPD_EVT_CONFIGURE:
|
||||
config = dp_usbpd_gen_config_pkt(pd);
|
||||
usbpd_send_svdm(pd->pd, USB_C_DP_SID, DP_USBPD_VDM_CONFIGURE,
|
||||
SVDM_CMD_TYPE_INITIATOR, 0x1, &config, 0x1);
|
||||
break;
|
||||
default:
|
||||
DP_ERR("unknown event:%d\n", event);
|
||||
}
|
||||
}
|
||||
|
||||
static void dp_usbpd_connect_cb(struct usbpd_svid_handler *hdlr,
|
||||
bool peer_usb_comm)
|
||||
{
|
||||
struct dp_usbpd_private *pd;
|
||||
|
||||
pd = container_of(hdlr, struct dp_usbpd_private, svid_handler);
|
||||
if (!pd) {
|
||||
DP_ERR("get_usbpd phandle failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
DP_DEBUG("peer_usb_comm: %d\n", peer_usb_comm);
|
||||
pd->dp_usbpd.base.peer_usb_comm = peer_usb_comm;
|
||||
dp_usbpd_send_event(pd, DP_USBPD_EVT_DISCOVER);
|
||||
}
|
||||
|
||||
static void dp_usbpd_disconnect_cb(struct usbpd_svid_handler *hdlr)
|
||||
{
|
||||
struct dp_usbpd_private *pd;
|
||||
|
||||
pd = container_of(hdlr, struct dp_usbpd_private, svid_handler);
|
||||
if (!pd) {
|
||||
DP_ERR("get_usbpd phandle failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
pd->alt_mode = DP_USBPD_ALT_MODE_NONE;
|
||||
pd->dp_usbpd.base.alt_mode_cfg_done = false;
|
||||
DP_DEBUG("\n");
|
||||
|
||||
if (pd->dp_cb && pd->dp_cb->disconnect)
|
||||
pd->dp_cb->disconnect(pd->dev);
|
||||
}
|
||||
|
||||
static int dp_usbpd_validate_callback(u8 cmd,
|
||||
enum usbpd_svdm_cmd_type cmd_type, int num_vdos)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (cmd_type == SVDM_CMD_TYPE_RESP_NAK) {
|
||||
DP_ERR("error: NACK\n");
|
||||
ret = -EINVAL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (cmd_type == SVDM_CMD_TYPE_RESP_BUSY) {
|
||||
DP_ERR("error: BUSY\n");
|
||||
ret = -EBUSY;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (cmd == USBPD_SVDM_ATTENTION) {
|
||||
if (cmd_type != SVDM_CMD_TYPE_INITIATOR) {
|
||||
DP_ERR("error: invalid cmd type for attention\n");
|
||||
ret = -EINVAL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!num_vdos) {
|
||||
DP_ERR("error: no vdo provided\n");
|
||||
ret = -EINVAL;
|
||||
goto end;
|
||||
}
|
||||
} else {
|
||||
if (cmd_type != SVDM_CMD_TYPE_RESP_ACK) {
|
||||
DP_ERR("error: invalid cmd type\n");
|
||||
ret = -EINVAL;
|
||||
}
|
||||
}
|
||||
end:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int dp_usbpd_get_ss_lanes(struct dp_usbpd_private *pd)
|
||||
{
|
||||
int rc = 0;
|
||||
int timeout = 250;
|
||||
|
||||
/*
|
||||
* By default, USB reserves two lanes for Super Speed.
|
||||
* Which means DP has remaining two lanes to operate on.
|
||||
* If multi-function is not supported, request USB to
|
||||
* release the Super Speed lanes so that DP can use
|
||||
* all four lanes in case DPCD indicates support for
|
||||
* four lanes.
|
||||
*/
|
||||
if (!pd->dp_usbpd.base.multi_func) {
|
||||
while (timeout) {
|
||||
rc = pd->svid_handler.request_usb_ss_lane(
|
||||
pd->pd, &pd->svid_handler);
|
||||
if (rc != -EBUSY)
|
||||
break;
|
||||
|
||||
DP_WARN("USB busy, retry\n");
|
||||
|
||||
/* wait for hw recommended delay for usb */
|
||||
msleep(20);
|
||||
timeout--;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void dp_usbpd_response_cb(struct usbpd_svid_handler *hdlr, u8 cmd,
|
||||
enum usbpd_svdm_cmd_type cmd_type,
|
||||
const u32 *vdos, int num_vdos)
|
||||
{
|
||||
struct dp_usbpd_private *pd;
|
||||
int rc = 0;
|
||||
|
||||
pd = container_of(hdlr, struct dp_usbpd_private, svid_handler);
|
||||
|
||||
DP_DEBUG("callback -> cmd: %s, *vdos = 0x%x, num_vdos = %d\n",
|
||||
dp_usbpd_cmd_name(cmd), *vdos, num_vdos);
|
||||
|
||||
if (dp_usbpd_validate_callback(cmd, cmd_type, num_vdos)) {
|
||||
DP_DEBUG("invalid callback received\n");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
case USBPD_SVDM_DISCOVER_MODES:
|
||||
pd->vdo = *vdos;
|
||||
dp_usbpd_get_capabilities(pd);
|
||||
|
||||
pd->alt_mode |= DP_USBPD_ALT_MODE_DISCOVER;
|
||||
|
||||
if (pd->cap.port & BIT(0))
|
||||
dp_usbpd_send_event(pd, DP_USBPD_EVT_ENTER);
|
||||
break;
|
||||
case USBPD_SVDM_ENTER_MODE:
|
||||
pd->alt_mode |= DP_USBPD_ALT_MODE_ENTER;
|
||||
|
||||
dp_usbpd_send_event(pd, DP_USBPD_EVT_STATUS);
|
||||
break;
|
||||
case USBPD_SVDM_ATTENTION:
|
||||
if (pd->forced_disconnect)
|
||||
break;
|
||||
|
||||
pd->vdo = *vdos;
|
||||
dp_usbpd_get_status(pd);
|
||||
|
||||
if (!pd->dp_usbpd.base.alt_mode_cfg_done) {
|
||||
if (pd->dp_usbpd.port & BIT(1))
|
||||
dp_usbpd_send_event(pd, DP_USBPD_EVT_CONFIGURE);
|
||||
break;
|
||||
}
|
||||
|
||||
if (pd->dp_cb && pd->dp_cb->attention)
|
||||
pd->dp_cb->attention(pd->dev);
|
||||
|
||||
break;
|
||||
case DP_USBPD_VDM_STATUS:
|
||||
pd->vdo = *vdos;
|
||||
dp_usbpd_get_status(pd);
|
||||
|
||||
if (!(pd->alt_mode & DP_USBPD_ALT_MODE_CONFIGURE)) {
|
||||
pd->alt_mode |= DP_USBPD_ALT_MODE_STATUS;
|
||||
|
||||
if (pd->dp_usbpd.port & BIT(1))
|
||||
dp_usbpd_send_event(pd, DP_USBPD_EVT_CONFIGURE);
|
||||
}
|
||||
break;
|
||||
case DP_USBPD_VDM_CONFIGURE:
|
||||
pd->alt_mode |= DP_USBPD_ALT_MODE_CONFIGURE;
|
||||
pd->dp_usbpd.base.alt_mode_cfg_done = true;
|
||||
pd->forced_disconnect = false;
|
||||
dp_usbpd_get_status(pd);
|
||||
|
||||
pd->dp_usbpd.base.orientation =
|
||||
usbpd_get_plug_orientation(pd->pd);
|
||||
|
||||
rc = dp_usbpd_get_ss_lanes(pd);
|
||||
if (rc) {
|
||||
DP_ERR("failed to get SuperSpeed lanes\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (pd->dp_cb && pd->dp_cb->configure)
|
||||
pd->dp_cb->configure(pd->dev);
|
||||
break;
|
||||
default:
|
||||
DP_ERR("unknown cmd: %d\n", cmd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int dp_usbpd_simulate_connect(struct dp_hpd *dp_hpd, bool hpd)
|
||||
{
|
||||
int rc = 0;
|
||||
struct dp_usbpd *dp_usbpd;
|
||||
struct dp_usbpd_private *pd;
|
||||
|
||||
if (!dp_hpd) {
|
||||
DP_ERR("invalid input\n");
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
dp_usbpd = container_of(dp_hpd, struct dp_usbpd, base);
|
||||
pd = container_of(dp_usbpd, struct dp_usbpd_private, dp_usbpd);
|
||||
|
||||
dp_usbpd->base.hpd_high = hpd;
|
||||
pd->forced_disconnect = !hpd;
|
||||
pd->dp_usbpd.base.alt_mode_cfg_done = hpd;
|
||||
|
||||
DP_DEBUG("hpd_high=%d, forced_disconnect=%d, orientation=%d\n",
|
||||
dp_usbpd->base.hpd_high, pd->forced_disconnect,
|
||||
pd->dp_usbpd.base.orientation);
|
||||
if (hpd)
|
||||
pd->dp_cb->configure(pd->dev);
|
||||
else
|
||||
pd->dp_cb->disconnect(pd->dev);
|
||||
|
||||
error:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int dp_usbpd_simulate_attention(struct dp_hpd *dp_hpd, int vdo)
|
||||
{
|
||||
int rc = 0;
|
||||
struct dp_usbpd *dp_usbpd;
|
||||
struct dp_usbpd_private *pd;
|
||||
|
||||
dp_usbpd = container_of(dp_hpd, struct dp_usbpd, base);
|
||||
if (!dp_usbpd) {
|
||||
DP_ERR("invalid input\n");
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
pd = container_of(dp_usbpd, struct dp_usbpd_private, dp_usbpd);
|
||||
|
||||
pd->vdo = vdo;
|
||||
dp_usbpd_get_status(pd);
|
||||
|
||||
if (pd->dp_cb && pd->dp_cb->attention)
|
||||
pd->dp_cb->attention(pd->dev);
|
||||
error:
|
||||
return rc;
|
||||
}
|
||||
|
||||
int dp_usbpd_register(struct dp_hpd *dp_hpd)
|
||||
{
|
||||
struct dp_usbpd *dp_usbpd;
|
||||
struct dp_usbpd_private *usbpd;
|
||||
int rc = 0;
|
||||
|
||||
if (!dp_hpd)
|
||||
return -EINVAL;
|
||||
|
||||
dp_usbpd = container_of(dp_hpd, struct dp_usbpd, base);
|
||||
|
||||
usbpd = container_of(dp_usbpd, struct dp_usbpd_private, dp_usbpd);
|
||||
|
||||
rc = usbpd_register_svid(usbpd->pd, &usbpd->svid_handler);
|
||||
if (rc)
|
||||
DP_ERR("pd registration failed\n");
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void dp_usbpd_wakeup_phy(struct dp_hpd *dp_hpd, bool wakeup)
|
||||
{
|
||||
struct dp_usbpd *dp_usbpd;
|
||||
struct dp_usbpd_private *usbpd;
|
||||
|
||||
dp_usbpd = container_of(dp_hpd, struct dp_usbpd, base);
|
||||
usbpd = container_of(dp_usbpd, struct dp_usbpd_private, dp_usbpd);
|
||||
|
||||
if (!usbpd->pd) {
|
||||
DP_ERR("usbpd pointer invalid");
|
||||
return;
|
||||
}
|
||||
|
||||
usbpd_vdm_in_suspend(usbpd->pd, wakeup);
|
||||
}
|
||||
|
||||
struct dp_hpd *dp_usbpd_get(struct device *dev, struct dp_hpd_cb *cb)
|
||||
{
|
||||
int rc = 0;
|
||||
const char *pd_phandle = "qcom,dp-usbpd-detection";
|
||||
struct usbpd *pd = NULL;
|
||||
struct dp_usbpd_private *usbpd;
|
||||
struct dp_usbpd *dp_usbpd;
|
||||
struct usbpd_svid_handler svid_handler = {
|
||||
.svid = USB_C_DP_SID,
|
||||
.vdm_received = NULL,
|
||||
.connect = &dp_usbpd_connect_cb,
|
||||
.svdm_received = &dp_usbpd_response_cb,
|
||||
.disconnect = &dp_usbpd_disconnect_cb,
|
||||
};
|
||||
|
||||
if (!cb) {
|
||||
DP_ERR("invalid cb data\n");
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
pd = devm_usbpd_get_by_phandle(dev, pd_phandle);
|
||||
if (IS_ERR(pd)) {
|
||||
DP_ERR("usbpd phandle failed (%ld)\n", PTR_ERR(pd));
|
||||
rc = PTR_ERR(pd);
|
||||
goto error;
|
||||
}
|
||||
|
||||
usbpd = devm_kzalloc(dev, sizeof(*usbpd), GFP_KERNEL);
|
||||
if (!usbpd) {
|
||||
rc = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
usbpd->dev = dev;
|
||||
usbpd->pd = pd;
|
||||
usbpd->svid_handler = svid_handler;
|
||||
usbpd->dp_cb = cb;
|
||||
|
||||
dp_usbpd = &usbpd->dp_usbpd;
|
||||
dp_usbpd->base.simulate_connect = dp_usbpd_simulate_connect;
|
||||
dp_usbpd->base.simulate_attention = dp_usbpd_simulate_attention;
|
||||
dp_usbpd->base.register_hpd = dp_usbpd_register;
|
||||
dp_usbpd->base.wakeup_phy = dp_usbpd_wakeup_phy;
|
||||
|
||||
return &dp_usbpd->base;
|
||||
error:
|
||||
return ERR_PTR(rc);
|
||||
}
|
||||
|
||||
void dp_usbpd_put(struct dp_hpd *dp_hpd)
|
||||
{
|
||||
struct dp_usbpd *dp_usbpd;
|
||||
struct dp_usbpd_private *usbpd;
|
||||
|
||||
dp_usbpd = container_of(dp_hpd, struct dp_usbpd, base);
|
||||
if (!dp_usbpd)
|
||||
return;
|
||||
|
||||
usbpd = container_of(dp_usbpd, struct dp_usbpd_private, dp_usbpd);
|
||||
|
||||
usbpd_unregister_svid(usbpd->pd, &usbpd->svid_handler);
|
||||
|
||||
devm_kfree(usbpd->dev, usbpd);
|
||||
}
|
75
techpack/display/msm/dp/dp_usbpd.h
Normal file
75
techpack/display/msm/dp/dp_usbpd.h
Normal file
@ -0,0 +1,75 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _DP_USBPD_H_
|
||||
#define _DP_USBPD_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
#include "dp_hpd.h"
|
||||
|
||||
struct device;
|
||||
|
||||
/**
|
||||
* enum dp_usbpd_port - usb/dp port type
|
||||
* @DP_USBPD_PORT_NONE: port not configured
|
||||
* @DP_USBPD_PORT_UFP_D: Upstream Facing Port - DisplayPort
|
||||
* @DP_USBPD_PORT_DFP_D: Downstream Facing Port - DisplayPort
|
||||
* @DP_USBPD_PORT_D_UFP_D: Both UFP & DFP - DisplayPort
|
||||
*/
|
||||
|
||||
enum dp_usbpd_port {
|
||||
DP_USBPD_PORT_NONE,
|
||||
DP_USBPD_PORT_UFP_D,
|
||||
DP_USBPD_PORT_DFP_D,
|
||||
DP_USBPD_PORT_D_UFP_D,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dp_usbpd - DisplayPort status
|
||||
*
|
||||
* @port: port configured
|
||||
* @low_pow_st: low power state
|
||||
* @adaptor_dp_en: adaptor functionality enabled
|
||||
* @usb_config_req: request to switch to usb
|
||||
* @exit_dp_mode: request exit from displayport mode
|
||||
* @debug_en: bool to specify debug mode
|
||||
*/
|
||||
struct dp_usbpd {
|
||||
struct dp_hpd base;
|
||||
enum dp_usbpd_port port;
|
||||
bool low_pow_st;
|
||||
bool adaptor_dp_en;
|
||||
bool usb_config_req;
|
||||
bool exit_dp_mode;
|
||||
bool debug_en;
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_DRM_MSM_DP_USBPD_LEGACY)
|
||||
/**
|
||||
* dp_usbpd_get() - setup usbpd module
|
||||
*
|
||||
* @dev: device instance of the caller
|
||||
* @cb: struct containing callback function pointers.
|
||||
*
|
||||
* This function allows the client to initialize the usbpd
|
||||
* module. The module will communicate with usb driver and
|
||||
* handles the power delivery (PD) communication with the
|
||||
* sink/usb device. This module will notify the client using
|
||||
* the callback functions about the connection and status.
|
||||
*/
|
||||
struct dp_hpd *dp_usbpd_get(struct device *dev, struct dp_hpd_cb *cb);
|
||||
void dp_usbpd_put(struct dp_hpd *pd);
|
||||
#else
|
||||
static inline struct dp_hpd *dp_usbpd_get(struct device *dev,
|
||||
struct dp_hpd_cb *cb)
|
||||
{
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
static inline void dp_usbpd_put(struct dp_hpd *pd)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_DRM_MSM_DP_USBPD_LEGACY */
|
||||
#endif /* _DP_USBPD_H_ */
|
346
techpack/display/msm/dsi/dsi_catalog.c
Normal file
346
techpack/display/msm/dsi/dsi_catalog.c
Normal file
@ -0,0 +1,346 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/errno.h>
|
||||
|
||||
#include "dsi_catalog.h"
|
||||
|
||||
/**
|
||||
* dsi_catalog_cmn_init() - catalog init for dsi controller v1.4
|
||||
*/
|
||||
static void dsi_catalog_cmn_init(struct dsi_ctrl_hw *ctrl,
|
||||
enum dsi_ctrl_version version)
|
||||
{
|
||||
/* common functions */
|
||||
ctrl->ops.host_setup = dsi_ctrl_hw_cmn_host_setup;
|
||||
ctrl->ops.video_engine_en = dsi_ctrl_hw_cmn_video_engine_en;
|
||||
ctrl->ops.video_engine_setup = dsi_ctrl_hw_cmn_video_engine_setup;
|
||||
ctrl->ops.set_video_timing = dsi_ctrl_hw_cmn_set_video_timing;
|
||||
ctrl->ops.set_timing_db = dsi_ctrl_hw_cmn_set_timing_db;
|
||||
ctrl->ops.cmd_engine_setup = dsi_ctrl_hw_cmn_cmd_engine_setup;
|
||||
ctrl->ops.setup_cmd_stream = dsi_ctrl_hw_cmn_setup_cmd_stream;
|
||||
ctrl->ops.ctrl_en = dsi_ctrl_hw_cmn_ctrl_en;
|
||||
ctrl->ops.cmd_engine_en = dsi_ctrl_hw_cmn_cmd_engine_en;
|
||||
ctrl->ops.phy_sw_reset = dsi_ctrl_hw_cmn_phy_sw_reset;
|
||||
ctrl->ops.soft_reset = dsi_ctrl_hw_cmn_soft_reset;
|
||||
ctrl->ops.kickoff_command = dsi_ctrl_hw_cmn_kickoff_command;
|
||||
ctrl->ops.kickoff_fifo_command = dsi_ctrl_hw_cmn_kickoff_fifo_command;
|
||||
ctrl->ops.reset_cmd_fifo = dsi_ctrl_hw_cmn_reset_cmd_fifo;
|
||||
ctrl->ops.trigger_command_dma = dsi_ctrl_hw_cmn_trigger_command_dma;
|
||||
ctrl->ops.get_interrupt_status = dsi_ctrl_hw_cmn_get_interrupt_status;
|
||||
ctrl->ops.poll_slave_dma_status = dsi_ctrl_hw_cmn_poll_slave_dma_status;
|
||||
ctrl->ops.get_error_status = dsi_ctrl_hw_cmn_get_error_status;
|
||||
ctrl->ops.clear_error_status = dsi_ctrl_hw_cmn_clear_error_status;
|
||||
ctrl->ops.clear_interrupt_status =
|
||||
dsi_ctrl_hw_cmn_clear_interrupt_status;
|
||||
ctrl->ops.enable_status_interrupts =
|
||||
dsi_ctrl_hw_cmn_enable_status_interrupts;
|
||||
ctrl->ops.enable_error_interrupts =
|
||||
dsi_ctrl_hw_cmn_enable_error_interrupts;
|
||||
ctrl->ops.video_test_pattern_setup =
|
||||
dsi_ctrl_hw_cmn_video_test_pattern_setup;
|
||||
ctrl->ops.cmd_test_pattern_setup =
|
||||
dsi_ctrl_hw_cmn_cmd_test_pattern_setup;
|
||||
ctrl->ops.test_pattern_enable = dsi_ctrl_hw_cmn_test_pattern_enable;
|
||||
ctrl->ops.trigger_cmd_test_pattern =
|
||||
dsi_ctrl_hw_cmn_trigger_cmd_test_pattern;
|
||||
ctrl->ops.clear_phy0_ln_err = dsi_ctrl_hw_dln0_phy_err;
|
||||
ctrl->ops.phy_reset_config = dsi_ctrl_hw_cmn_phy_reset_config;
|
||||
ctrl->ops.setup_misr = dsi_ctrl_hw_cmn_setup_misr;
|
||||
ctrl->ops.collect_misr = dsi_ctrl_hw_cmn_collect_misr;
|
||||
ctrl->ops.get_cmd_read_data = dsi_ctrl_hw_cmn_get_cmd_read_data;
|
||||
ctrl->ops.clear_rdbk_register = dsi_ctrl_hw_cmn_clear_rdbk_reg;
|
||||
ctrl->ops.ctrl_reset = dsi_ctrl_hw_cmn_ctrl_reset;
|
||||
ctrl->ops.mask_error_intr = dsi_ctrl_hw_cmn_mask_error_intr;
|
||||
ctrl->ops.error_intr_ctrl = dsi_ctrl_hw_cmn_error_intr_ctrl;
|
||||
ctrl->ops.get_error_mask = dsi_ctrl_hw_cmn_get_error_mask;
|
||||
ctrl->ops.get_hw_version = dsi_ctrl_hw_cmn_get_hw_version;
|
||||
ctrl->ops.wait_for_cmd_mode_mdp_idle =
|
||||
dsi_ctrl_hw_cmn_wait_for_cmd_mode_mdp_idle;
|
||||
ctrl->ops.setup_avr = dsi_ctrl_hw_cmn_setup_avr;
|
||||
ctrl->ops.set_continuous_clk = dsi_ctrl_hw_cmn_set_continuous_clk;
|
||||
ctrl->ops.wait4dynamic_refresh_done =
|
||||
dsi_ctrl_hw_cmn_wait4dynamic_refresh_done;
|
||||
ctrl->ops.hs_req_sel = dsi_ctrl_hw_cmn_hs_req_sel;
|
||||
ctrl->ops.vid_engine_busy = dsi_ctrl_hw_cmn_vid_engine_busy;
|
||||
|
||||
switch (version) {
|
||||
case DSI_CTRL_VERSION_1_4:
|
||||
ctrl->ops.setup_lane_map = dsi_ctrl_hw_14_setup_lane_map;
|
||||
ctrl->ops.ulps_ops.ulps_request = dsi_ctrl_hw_cmn_ulps_request;
|
||||
ctrl->ops.ulps_ops.ulps_exit = dsi_ctrl_hw_cmn_ulps_exit;
|
||||
ctrl->ops.wait_for_lane_idle =
|
||||
dsi_ctrl_hw_14_wait_for_lane_idle;
|
||||
ctrl->ops.ulps_ops.get_lanes_in_ulps =
|
||||
dsi_ctrl_hw_cmn_get_lanes_in_ulps;
|
||||
ctrl->ops.clamp_enable = dsi_ctrl_hw_14_clamp_enable;
|
||||
ctrl->ops.clamp_disable = dsi_ctrl_hw_14_clamp_disable;
|
||||
ctrl->ops.reg_dump_to_buffer =
|
||||
dsi_ctrl_hw_14_reg_dump_to_buffer;
|
||||
ctrl->ops.schedule_dma_cmd = NULL;
|
||||
ctrl->ops.kickoff_command_non_embedded_mode = NULL;
|
||||
ctrl->ops.config_clk_gating = NULL;
|
||||
ctrl->ops.configure_cmddma_window = NULL;
|
||||
ctrl->ops.reset_trig_ctrl = NULL;
|
||||
ctrl->ops.log_line_count = NULL;
|
||||
break;
|
||||
case DSI_CTRL_VERSION_2_0:
|
||||
ctrl->ops.setup_lane_map = dsi_ctrl_hw_20_setup_lane_map;
|
||||
ctrl->ops.wait_for_lane_idle =
|
||||
dsi_ctrl_hw_20_wait_for_lane_idle;
|
||||
ctrl->ops.reg_dump_to_buffer =
|
||||
dsi_ctrl_hw_20_reg_dump_to_buffer;
|
||||
ctrl->ops.ulps_ops.ulps_request = NULL;
|
||||
ctrl->ops.ulps_ops.ulps_exit = NULL;
|
||||
ctrl->ops.ulps_ops.get_lanes_in_ulps = NULL;
|
||||
ctrl->ops.clamp_enable = NULL;
|
||||
ctrl->ops.clamp_disable = NULL;
|
||||
ctrl->ops.schedule_dma_cmd = NULL;
|
||||
ctrl->ops.kickoff_command_non_embedded_mode = NULL;
|
||||
ctrl->ops.config_clk_gating = NULL;
|
||||
ctrl->ops.configure_cmddma_window = NULL;
|
||||
ctrl->ops.reset_trig_ctrl = NULL;
|
||||
ctrl->ops.log_line_count = NULL;
|
||||
break;
|
||||
case DSI_CTRL_VERSION_2_2:
|
||||
case DSI_CTRL_VERSION_2_3:
|
||||
case DSI_CTRL_VERSION_2_4:
|
||||
case DSI_CTRL_VERSION_2_5:
|
||||
ctrl->ops.phy_reset_config = dsi_ctrl_hw_22_phy_reset_config;
|
||||
ctrl->ops.config_clk_gating = dsi_ctrl_hw_22_config_clk_gating;
|
||||
ctrl->ops.setup_lane_map = dsi_ctrl_hw_22_setup_lane_map;
|
||||
ctrl->ops.wait_for_lane_idle =
|
||||
dsi_ctrl_hw_22_wait_for_lane_idle;
|
||||
ctrl->ops.reg_dump_to_buffer =
|
||||
dsi_ctrl_hw_22_reg_dump_to_buffer;
|
||||
ctrl->ops.ulps_ops.ulps_request = dsi_ctrl_hw_cmn_ulps_request;
|
||||
ctrl->ops.ulps_ops.ulps_exit = dsi_ctrl_hw_cmn_ulps_exit;
|
||||
ctrl->ops.ulps_ops.get_lanes_in_ulps =
|
||||
dsi_ctrl_hw_cmn_get_lanes_in_ulps;
|
||||
ctrl->ops.clamp_enable = NULL;
|
||||
ctrl->ops.clamp_disable = NULL;
|
||||
ctrl->ops.schedule_dma_cmd = dsi_ctrl_hw_22_schedule_dma_cmd;
|
||||
ctrl->ops.kickoff_command_non_embedded_mode =
|
||||
dsi_ctrl_hw_kickoff_non_embedded_mode;
|
||||
ctrl->ops.configure_cmddma_window =
|
||||
dsi_ctrl_hw_22_configure_cmddma_window;
|
||||
ctrl->ops.reset_trig_ctrl =
|
||||
dsi_ctrl_hw_22_reset_trigger_controls;
|
||||
ctrl->ops.log_line_count = dsi_ctrl_hw_22_log_line_count;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* dsi_catalog_ctrl_setup() - return catalog info for dsi controller
|
||||
* @ctrl: Pointer to DSI controller hw object.
|
||||
* @version: DSI controller version.
|
||||
* @index: DSI controller instance ID.
|
||||
* @phy_isolation_enabled: DSI controller works isolated from phy.
|
||||
* @null_insertion_enabled: DSI controller inserts null packet.
|
||||
*
|
||||
* This function setups the catalog information in the dsi_ctrl_hw object.
|
||||
*
|
||||
* return: error code for failure and 0 for success.
|
||||
*/
|
||||
int dsi_catalog_ctrl_setup(struct dsi_ctrl_hw *ctrl,
|
||||
enum dsi_ctrl_version version, u32 index,
|
||||
bool phy_isolation_enabled, bool null_insertion_enabled)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (version == DSI_CTRL_VERSION_UNKNOWN ||
|
||||
version >= DSI_CTRL_VERSION_MAX) {
|
||||
DSI_ERR("Unsupported version: %d\n", version);
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
ctrl->index = index;
|
||||
ctrl->null_insertion_enabled = null_insertion_enabled;
|
||||
set_bit(DSI_CTRL_VIDEO_TPG, ctrl->feature_map);
|
||||
set_bit(DSI_CTRL_CMD_TPG, ctrl->feature_map);
|
||||
set_bit(DSI_CTRL_VARIABLE_REFRESH_RATE, ctrl->feature_map);
|
||||
set_bit(DSI_CTRL_DYNAMIC_REFRESH, ctrl->feature_map);
|
||||
set_bit(DSI_CTRL_DESKEW_CALIB, ctrl->feature_map);
|
||||
set_bit(DSI_CTRL_DPHY, ctrl->feature_map);
|
||||
|
||||
switch (version) {
|
||||
case DSI_CTRL_VERSION_1_4:
|
||||
dsi_catalog_cmn_init(ctrl, version);
|
||||
break;
|
||||
case DSI_CTRL_VERSION_2_0:
|
||||
case DSI_CTRL_VERSION_2_2:
|
||||
case DSI_CTRL_VERSION_2_3:
|
||||
case DSI_CTRL_VERSION_2_4:
|
||||
ctrl->phy_isolation_enabled = phy_isolation_enabled;
|
||||
dsi_catalog_cmn_init(ctrl, version);
|
||||
break;
|
||||
case DSI_CTRL_VERSION_2_5:
|
||||
ctrl->widebus_support = true;
|
||||
ctrl->phy_isolation_enabled = phy_isolation_enabled;
|
||||
dsi_catalog_cmn_init(ctrl, version);
|
||||
break;
|
||||
default:
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* dsi_catalog_phy_2_0_init() - catalog init for DSI PHY 14nm
|
||||
*/
|
||||
static void dsi_catalog_phy_2_0_init(struct dsi_phy_hw *phy)
|
||||
{
|
||||
phy->ops.regulator_enable = dsi_phy_hw_v2_0_regulator_enable;
|
||||
phy->ops.regulator_disable = dsi_phy_hw_v2_0_regulator_disable;
|
||||
phy->ops.enable = dsi_phy_hw_v2_0_enable;
|
||||
phy->ops.disable = dsi_phy_hw_v2_0_disable;
|
||||
phy->ops.calculate_timing_params =
|
||||
dsi_phy_hw_calculate_timing_params;
|
||||
phy->ops.phy_idle_on = dsi_phy_hw_v2_0_idle_on;
|
||||
phy->ops.phy_idle_off = dsi_phy_hw_v2_0_idle_off;
|
||||
phy->ops.calculate_timing_params =
|
||||
dsi_phy_hw_calculate_timing_params;
|
||||
phy->ops.phy_timing_val = dsi_phy_hw_timing_val_v2_0;
|
||||
phy->ops.clamp_ctrl = dsi_phy_hw_v2_0_clamp_ctrl;
|
||||
phy->ops.dyn_refresh_ops.dyn_refresh_config =
|
||||
dsi_phy_hw_v2_0_dyn_refresh_config;
|
||||
phy->ops.dyn_refresh_ops.dyn_refresh_pipe_delay =
|
||||
dsi_phy_hw_v2_0_dyn_refresh_pipe_delay;
|
||||
phy->ops.dyn_refresh_ops.dyn_refresh_helper =
|
||||
dsi_phy_hw_v2_0_dyn_refresh_helper;
|
||||
phy->ops.dyn_refresh_ops.dyn_refresh_trigger_sel = NULL;
|
||||
phy->ops.dyn_refresh_ops.cache_phy_timings =
|
||||
dsi_phy_hw_v2_0_cache_phy_timings;
|
||||
}
|
||||
|
||||
/**
|
||||
* dsi_catalog_phy_3_0_init() - catalog init for DSI PHY 10nm
|
||||
*/
|
||||
static void dsi_catalog_phy_3_0_init(struct dsi_phy_hw *phy)
|
||||
{
|
||||
phy->ops.regulator_enable = dsi_phy_hw_v3_0_regulator_enable;
|
||||
phy->ops.regulator_disable = dsi_phy_hw_v3_0_regulator_disable;
|
||||
phy->ops.enable = dsi_phy_hw_v3_0_enable;
|
||||
phy->ops.disable = dsi_phy_hw_v3_0_disable;
|
||||
phy->ops.calculate_timing_params =
|
||||
dsi_phy_hw_calculate_timing_params;
|
||||
phy->ops.ulps_ops.wait_for_lane_idle =
|
||||
dsi_phy_hw_v3_0_wait_for_lane_idle;
|
||||
phy->ops.ulps_ops.ulps_request =
|
||||
dsi_phy_hw_v3_0_ulps_request;
|
||||
phy->ops.ulps_ops.ulps_exit =
|
||||
dsi_phy_hw_v3_0_ulps_exit;
|
||||
phy->ops.ulps_ops.get_lanes_in_ulps =
|
||||
dsi_phy_hw_v3_0_get_lanes_in_ulps;
|
||||
phy->ops.ulps_ops.is_lanes_in_ulps =
|
||||
dsi_phy_hw_v3_0_is_lanes_in_ulps;
|
||||
phy->ops.phy_timing_val = dsi_phy_hw_timing_val_v3_0;
|
||||
phy->ops.clamp_ctrl = dsi_phy_hw_v3_0_clamp_ctrl;
|
||||
phy->ops.phy_lane_reset = dsi_phy_hw_v3_0_lane_reset;
|
||||
phy->ops.toggle_resync_fifo = dsi_phy_hw_v3_0_toggle_resync_fifo;
|
||||
phy->ops.dyn_refresh_ops.dyn_refresh_config =
|
||||
dsi_phy_hw_v3_0_dyn_refresh_config;
|
||||
phy->ops.dyn_refresh_ops.dyn_refresh_pipe_delay =
|
||||
dsi_phy_hw_v3_0_dyn_refresh_pipe_delay;
|
||||
phy->ops.dyn_refresh_ops.dyn_refresh_helper =
|
||||
dsi_phy_hw_v3_0_dyn_refresh_helper;
|
||||
phy->ops.dyn_refresh_ops.dyn_refresh_trigger_sel = NULL;
|
||||
phy->ops.dyn_refresh_ops.cache_phy_timings =
|
||||
dsi_phy_hw_v3_0_cache_phy_timings;
|
||||
}
|
||||
|
||||
/**
|
||||
* dsi_catalog_phy_4_0_init() - catalog init for DSI PHY 7nm
|
||||
*/
|
||||
static void dsi_catalog_phy_4_0_init(struct dsi_phy_hw *phy)
|
||||
{
|
||||
phy->ops.regulator_enable = NULL;
|
||||
phy->ops.regulator_disable = NULL;
|
||||
phy->ops.enable = dsi_phy_hw_v4_0_enable;
|
||||
phy->ops.disable = dsi_phy_hw_v4_0_disable;
|
||||
phy->ops.calculate_timing_params =
|
||||
dsi_phy_hw_calculate_timing_params;
|
||||
phy->ops.ulps_ops.wait_for_lane_idle =
|
||||
dsi_phy_hw_v4_0_wait_for_lane_idle;
|
||||
phy->ops.ulps_ops.ulps_request =
|
||||
dsi_phy_hw_v4_0_ulps_request;
|
||||
phy->ops.ulps_ops.ulps_exit =
|
||||
dsi_phy_hw_v4_0_ulps_exit;
|
||||
phy->ops.ulps_ops.get_lanes_in_ulps =
|
||||
dsi_phy_hw_v4_0_get_lanes_in_ulps;
|
||||
phy->ops.ulps_ops.is_lanes_in_ulps =
|
||||
dsi_phy_hw_v4_0_is_lanes_in_ulps;
|
||||
phy->ops.phy_timing_val = dsi_phy_hw_timing_val_v4_0;
|
||||
phy->ops.phy_lane_reset = dsi_phy_hw_v4_0_lane_reset;
|
||||
phy->ops.toggle_resync_fifo = dsi_phy_hw_v4_0_toggle_resync_fifo;
|
||||
phy->ops.reset_clk_en_sel = dsi_phy_hw_v4_0_reset_clk_en_sel;
|
||||
|
||||
phy->ops.dyn_refresh_ops.dyn_refresh_config =
|
||||
dsi_phy_hw_v4_0_dyn_refresh_config;
|
||||
phy->ops.dyn_refresh_ops.dyn_refresh_pipe_delay =
|
||||
dsi_phy_hw_v4_0_dyn_refresh_pipe_delay;
|
||||
phy->ops.dyn_refresh_ops.dyn_refresh_helper =
|
||||
dsi_phy_hw_v4_0_dyn_refresh_helper;
|
||||
phy->ops.dyn_refresh_ops.dyn_refresh_trigger_sel =
|
||||
dsi_phy_hw_v4_0_dyn_refresh_trigger_sel;
|
||||
phy->ops.dyn_refresh_ops.cache_phy_timings =
|
||||
dsi_phy_hw_v4_0_cache_phy_timings;
|
||||
phy->ops.set_continuous_clk = dsi_phy_hw_v4_0_set_continuous_clk;
|
||||
phy->ops.commit_phy_timing = dsi_phy_hw_v4_0_commit_phy_timing;
|
||||
}
|
||||
|
||||
/**
|
||||
* dsi_catalog_phy_setup() - return catalog info for dsi phy hardware
|
||||
* @ctrl: Pointer to DSI PHY hw object.
|
||||
* @version: DSI PHY version.
|
||||
* @index: DSI PHY instance ID.
|
||||
*
|
||||
* This function setups the catalog information in the dsi_phy_hw object.
|
||||
*
|
||||
* return: error code for failure and 0 for success.
|
||||
*/
|
||||
int dsi_catalog_phy_setup(struct dsi_phy_hw *phy,
|
||||
enum dsi_phy_version version,
|
||||
u32 index)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (version == DSI_PHY_VERSION_UNKNOWN ||
|
||||
version >= DSI_PHY_VERSION_MAX) {
|
||||
DSI_ERR("Unsupported version: %d\n", version);
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
phy->index = index;
|
||||
phy->version = version;
|
||||
set_bit(DSI_PHY_DPHY, phy->feature_map);
|
||||
|
||||
dsi_phy_timing_calc_init(phy, version);
|
||||
|
||||
switch (version) {
|
||||
case DSI_PHY_VERSION_2_0:
|
||||
dsi_catalog_phy_2_0_init(phy);
|
||||
break;
|
||||
case DSI_PHY_VERSION_3_0:
|
||||
dsi_catalog_phy_3_0_init(phy);
|
||||
break;
|
||||
case DSI_PHY_VERSION_4_0:
|
||||
case DSI_PHY_VERSION_4_1:
|
||||
case DSI_PHY_VERSION_4_2:
|
||||
dsi_catalog_phy_4_0_init(phy);
|
||||
break;
|
||||
case DSI_PHY_VERSION_0_0_HPM:
|
||||
case DSI_PHY_VERSION_0_0_LPM:
|
||||
case DSI_PHY_VERSION_1_0:
|
||||
default:
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
288
techpack/display/msm/dsi/dsi_catalog.h
Normal file
288
techpack/display/msm/dsi/dsi_catalog.h
Normal file
@ -0,0 +1,288 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _DSI_CATALOG_H_
|
||||
#define _DSI_CATALOG_H_
|
||||
|
||||
#include "dsi_ctrl_hw.h"
|
||||
#include "dsi_phy_hw.h"
|
||||
|
||||
/**
|
||||
* dsi_catalog_ctrl_setup() - return catalog info for dsi controller
|
||||
* @ctrl: Pointer to DSI controller hw object.
|
||||
* @version: DSI controller version.
|
||||
* @index: DSI controller instance ID.
|
||||
* @phy_isolation_enabled: DSI controller works isolated from phy.
|
||||
* @null_insertion_enabled: DSI controller inserts null packet.
|
||||
*
|
||||
* This function setups the catalog information in the dsi_ctrl_hw object.
|
||||
*
|
||||
* return: error code for failure and 0 for success.
|
||||
*/
|
||||
int dsi_catalog_ctrl_setup(struct dsi_ctrl_hw *ctrl,
|
||||
enum dsi_ctrl_version version, u32 index,
|
||||
bool phy_isolation_enabled, bool null_insertion_enabled);
|
||||
|
||||
/**
|
||||
* dsi_catalog_phy_setup() - return catalog info for dsi phy hardware
|
||||
* @phy: Pointer to DSI PHY hw object.
|
||||
* @version: DSI PHY version.
|
||||
* @index: DSI PHY instance ID.
|
||||
*
|
||||
* This function setups the catalog information in the dsi_phy_hw object.
|
||||
*
|
||||
* return: error code for failure and 0 for success.
|
||||
*/
|
||||
int dsi_catalog_phy_setup(struct dsi_phy_hw *phy,
|
||||
enum dsi_phy_version version,
|
||||
u32 index);
|
||||
|
||||
/**
|
||||
* dsi_phy_timing_calc_init() - initialize info for DSI PHY timing calculations
|
||||
* @phy: Pointer to DSI PHY hw object.
|
||||
* @version: DSI PHY version.
|
||||
*
|
||||
* This function setups the catalog information in the dsi_phy_hw object.
|
||||
*
|
||||
* return: error code for failure and 0 for success.
|
||||
*/
|
||||
int dsi_phy_timing_calc_init(struct dsi_phy_hw *phy,
|
||||
enum dsi_phy_version version);
|
||||
|
||||
/**
|
||||
* dsi_phy_hw_calculate_timing_params() - DSI PHY timing parameter calculations
|
||||
* @phy: Pointer to DSI PHY hw object.
|
||||
* @mode: DSI mode information.
|
||||
* @host: DSI host configuration.
|
||||
* @timing: DSI phy lane configurations.
|
||||
* @use_mode_bit_clk: Boolean to indicate whether to recalculate bit clk.
|
||||
*
|
||||
* This function setups the catalog information in the dsi_phy_hw object.
|
||||
*
|
||||
* return: error code for failure and 0 for success.
|
||||
*/
|
||||
int dsi_phy_hw_calculate_timing_params(struct dsi_phy_hw *phy,
|
||||
struct dsi_mode_info *mode,
|
||||
struct dsi_host_common_cfg *host,
|
||||
struct dsi_phy_per_lane_cfgs *timing,
|
||||
bool use_mode_bit_clk);
|
||||
|
||||
/* Definitions for 14nm PHY hardware driver */
|
||||
void dsi_phy_hw_v2_0_regulator_enable(struct dsi_phy_hw *phy,
|
||||
struct dsi_phy_per_lane_cfgs *cfg);
|
||||
void dsi_phy_hw_v2_0_regulator_disable(struct dsi_phy_hw *phy);
|
||||
void dsi_phy_hw_v2_0_enable(struct dsi_phy_hw *phy, struct dsi_phy_cfg *cfg);
|
||||
void dsi_phy_hw_v2_0_disable(struct dsi_phy_hw *phy, struct dsi_phy_cfg *cfg);
|
||||
void dsi_phy_hw_v2_0_idle_on(struct dsi_phy_hw *phy, struct dsi_phy_cfg *cfg);
|
||||
void dsi_phy_hw_v2_0_idle_off(struct dsi_phy_hw *phy);
|
||||
int dsi_phy_hw_timing_val_v2_0(struct dsi_phy_per_lane_cfgs *timing_cfg,
|
||||
u32 *timing_val, u32 size);
|
||||
void dsi_phy_hw_v2_0_clamp_ctrl(struct dsi_phy_hw *phy, bool enable);
|
||||
void dsi_phy_hw_v2_0_dyn_refresh_helper(struct dsi_phy_hw *phy, u32 offset);
|
||||
void dsi_phy_hw_v2_0_dyn_refresh_config(struct dsi_phy_hw *phy,
|
||||
struct dsi_phy_cfg *cfg, bool is_master);
|
||||
void dsi_phy_hw_v2_0_dyn_refresh_pipe_delay(struct dsi_phy_hw *phy,
|
||||
struct dsi_dyn_clk_delay *delay);
|
||||
int dsi_phy_hw_v2_0_cache_phy_timings(struct dsi_phy_per_lane_cfgs *timings,
|
||||
u32 *dst, u32 size);
|
||||
|
||||
/* Definitions for 10nm PHY hardware driver */
|
||||
void dsi_phy_hw_v3_0_regulator_enable(struct dsi_phy_hw *phy,
|
||||
struct dsi_phy_per_lane_cfgs *cfg);
|
||||
void dsi_phy_hw_v3_0_regulator_disable(struct dsi_phy_hw *phy);
|
||||
void dsi_phy_hw_v3_0_enable(struct dsi_phy_hw *phy, struct dsi_phy_cfg *cfg);
|
||||
void dsi_phy_hw_v3_0_disable(struct dsi_phy_hw *phy, struct dsi_phy_cfg *cfg);
|
||||
int dsi_phy_hw_v3_0_wait_for_lane_idle(struct dsi_phy_hw *phy, u32 lanes);
|
||||
void dsi_phy_hw_v3_0_ulps_request(struct dsi_phy_hw *phy,
|
||||
struct dsi_phy_cfg *cfg, u32 lanes);
|
||||
void dsi_phy_hw_v3_0_ulps_exit(struct dsi_phy_hw *phy,
|
||||
struct dsi_phy_cfg *cfg, u32 lanes);
|
||||
u32 dsi_phy_hw_v3_0_get_lanes_in_ulps(struct dsi_phy_hw *phy);
|
||||
bool dsi_phy_hw_v3_0_is_lanes_in_ulps(u32 lanes, u32 ulps_lanes);
|
||||
int dsi_phy_hw_timing_val_v3_0(struct dsi_phy_per_lane_cfgs *timing_cfg,
|
||||
u32 *timing_val, u32 size);
|
||||
void dsi_phy_hw_v3_0_clamp_ctrl(struct dsi_phy_hw *phy, bool enable);
|
||||
int dsi_phy_hw_v3_0_lane_reset(struct dsi_phy_hw *phy);
|
||||
void dsi_phy_hw_v3_0_toggle_resync_fifo(struct dsi_phy_hw *phy);
|
||||
|
||||
/* Definitions for 7nm PHY hardware driver */
|
||||
void dsi_phy_hw_v4_0_enable(struct dsi_phy_hw *phy, struct dsi_phy_cfg *cfg);
|
||||
void dsi_phy_hw_v4_0_disable(struct dsi_phy_hw *phy, struct dsi_phy_cfg *cfg);
|
||||
int dsi_phy_hw_v4_0_wait_for_lane_idle(struct dsi_phy_hw *phy, u32 lanes);
|
||||
void dsi_phy_hw_v4_0_ulps_request(struct dsi_phy_hw *phy,
|
||||
struct dsi_phy_cfg *cfg, u32 lanes);
|
||||
void dsi_phy_hw_v4_0_ulps_exit(struct dsi_phy_hw *phy,
|
||||
struct dsi_phy_cfg *cfg, u32 lanes);
|
||||
u32 dsi_phy_hw_v4_0_get_lanes_in_ulps(struct dsi_phy_hw *phy);
|
||||
bool dsi_phy_hw_v4_0_is_lanes_in_ulps(u32 lanes, u32 ulps_lanes);
|
||||
int dsi_phy_hw_timing_val_v4_0(struct dsi_phy_per_lane_cfgs *timing_cfg,
|
||||
u32 *timing_val, u32 size);
|
||||
int dsi_phy_hw_v4_0_lane_reset(struct dsi_phy_hw *phy);
|
||||
void dsi_phy_hw_v4_0_toggle_resync_fifo(struct dsi_phy_hw *phy);
|
||||
void dsi_phy_hw_v4_0_reset_clk_en_sel(struct dsi_phy_hw *phy);
|
||||
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);
|
||||
|
||||
/* DSI controller common ops */
|
||||
u32 dsi_ctrl_hw_cmn_get_interrupt_status(struct dsi_ctrl_hw *ctrl);
|
||||
u32 dsi_ctrl_hw_cmn_poll_slave_dma_status(struct dsi_ctrl_hw *ctrl);
|
||||
void dsi_ctrl_hw_cmn_clear_interrupt_status(struct dsi_ctrl_hw *ctrl, u32 ints);
|
||||
void dsi_ctrl_hw_cmn_enable_status_interrupts(struct dsi_ctrl_hw *ctrl,
|
||||
u32 ints);
|
||||
|
||||
u64 dsi_ctrl_hw_cmn_get_error_status(struct dsi_ctrl_hw *ctrl);
|
||||
void dsi_ctrl_hw_cmn_clear_error_status(struct dsi_ctrl_hw *ctrl, u64 errors);
|
||||
void dsi_ctrl_hw_cmn_enable_error_interrupts(struct dsi_ctrl_hw *ctrl,
|
||||
u64 errors);
|
||||
|
||||
void dsi_ctrl_hw_cmn_video_test_pattern_setup(struct dsi_ctrl_hw *ctrl,
|
||||
enum dsi_test_pattern type,
|
||||
u32 init_val);
|
||||
void dsi_ctrl_hw_cmn_cmd_test_pattern_setup(struct dsi_ctrl_hw *ctrl,
|
||||
enum dsi_test_pattern type,
|
||||
u32 init_val,
|
||||
u32 stream_id);
|
||||
void dsi_ctrl_hw_cmn_test_pattern_enable(struct dsi_ctrl_hw *ctrl, bool enable);
|
||||
void dsi_ctrl_hw_cmn_trigger_cmd_test_pattern(struct dsi_ctrl_hw *ctrl,
|
||||
u32 stream_id);
|
||||
|
||||
void dsi_ctrl_hw_cmn_host_setup(struct dsi_ctrl_hw *ctrl,
|
||||
struct dsi_host_common_cfg *config);
|
||||
void dsi_ctrl_hw_cmn_video_engine_en(struct dsi_ctrl_hw *ctrl, bool on);
|
||||
void dsi_ctrl_hw_cmn_video_engine_setup(struct dsi_ctrl_hw *ctrl,
|
||||
struct dsi_host_common_cfg *common_cfg,
|
||||
struct dsi_video_engine_cfg *cfg);
|
||||
|
||||
void dsi_ctrl_hw_cmn_setup_avr(struct dsi_ctrl_hw *ctrl, bool enable);
|
||||
|
||||
void dsi_ctrl_hw_cmn_set_video_timing(struct dsi_ctrl_hw *ctrl,
|
||||
struct dsi_mode_info *mode);
|
||||
void dsi_ctrl_hw_cmn_set_timing_db(struct dsi_ctrl_hw *ctrl,
|
||||
bool enable);
|
||||
void dsi_ctrl_hw_cmn_cmd_engine_setup(struct dsi_ctrl_hw *ctrl,
|
||||
struct dsi_host_common_cfg *common_cfg,
|
||||
struct dsi_cmd_engine_cfg *cfg);
|
||||
|
||||
void dsi_ctrl_hw_cmn_ctrl_en(struct dsi_ctrl_hw *ctrl, bool on);
|
||||
void dsi_ctrl_hw_cmn_cmd_engine_en(struct dsi_ctrl_hw *ctrl, bool on);
|
||||
|
||||
void dsi_ctrl_hw_cmn_setup_cmd_stream(struct dsi_ctrl_hw *ctrl,
|
||||
struct dsi_mode_info *mode,
|
||||
struct dsi_host_common_cfg *cfg,
|
||||
u32 vc_id,
|
||||
struct dsi_rect *roi);
|
||||
void dsi_ctrl_hw_cmn_phy_sw_reset(struct dsi_ctrl_hw *ctrl);
|
||||
void dsi_ctrl_hw_cmn_soft_reset(struct dsi_ctrl_hw *ctrl);
|
||||
|
||||
void dsi_ctrl_hw_cmn_setup_misr(struct dsi_ctrl_hw *ctrl,
|
||||
enum dsi_op_mode panel_mode,
|
||||
bool enable, u32 frame_count);
|
||||
u32 dsi_ctrl_hw_cmn_collect_misr(struct dsi_ctrl_hw *ctrl,
|
||||
enum dsi_op_mode panel_mode);
|
||||
|
||||
void dsi_ctrl_hw_cmn_kickoff_command(struct dsi_ctrl_hw *ctrl,
|
||||
struct dsi_ctrl_cmd_dma_info *cmd,
|
||||
u32 flags);
|
||||
|
||||
void dsi_ctrl_hw_cmn_kickoff_fifo_command(struct dsi_ctrl_hw *ctrl,
|
||||
struct dsi_ctrl_cmd_dma_fifo_info *cmd,
|
||||
u32 flags);
|
||||
void dsi_ctrl_hw_cmn_reset_cmd_fifo(struct dsi_ctrl_hw *ctrl);
|
||||
void dsi_ctrl_hw_cmn_trigger_command_dma(struct dsi_ctrl_hw *ctrl);
|
||||
void dsi_ctrl_hw_dln0_phy_err(struct dsi_ctrl_hw *ctrl);
|
||||
void dsi_ctrl_hw_cmn_phy_reset_config(struct dsi_ctrl_hw *ctrl,
|
||||
bool enable);
|
||||
void dsi_ctrl_hw_22_phy_reset_config(struct dsi_ctrl_hw *ctrl,
|
||||
bool enable);
|
||||
u32 dsi_ctrl_hw_cmn_get_cmd_read_data(struct dsi_ctrl_hw *ctrl,
|
||||
u8 *rd_buf,
|
||||
u32 read_offset,
|
||||
u32 rx_byte,
|
||||
u32 pkt_size, u32 *hw_read_cnt);
|
||||
void dsi_ctrl_hw_cmn_clear_rdbk_reg(struct dsi_ctrl_hw *ctrl);
|
||||
void dsi_ctrl_hw_22_schedule_dma_cmd(struct dsi_ctrl_hw *ctrl, int line_on);
|
||||
int dsi_ctrl_hw_cmn_ctrl_reset(struct dsi_ctrl_hw *ctrl,
|
||||
int mask);
|
||||
void dsi_ctrl_hw_cmn_mask_error_intr(struct dsi_ctrl_hw *ctrl, u32 idx,
|
||||
bool en);
|
||||
void dsi_ctrl_hw_cmn_error_intr_ctrl(struct dsi_ctrl_hw *ctrl, bool en);
|
||||
u32 dsi_ctrl_hw_cmn_get_error_mask(struct dsi_ctrl_hw *ctrl);
|
||||
u32 dsi_ctrl_hw_cmn_get_hw_version(struct dsi_ctrl_hw *ctrl);
|
||||
int dsi_ctrl_hw_cmn_wait_for_cmd_mode_mdp_idle(struct dsi_ctrl_hw *ctrl);
|
||||
|
||||
/* Definitions specific to 1.4 DSI controller hardware */
|
||||
int dsi_ctrl_hw_14_wait_for_lane_idle(struct dsi_ctrl_hw *ctrl, u32 lanes);
|
||||
void dsi_ctrl_hw_14_setup_lane_map(struct dsi_ctrl_hw *ctrl,
|
||||
struct dsi_lane_map *lane_map);
|
||||
void dsi_ctrl_hw_cmn_ulps_request(struct dsi_ctrl_hw *ctrl, u32 lanes);
|
||||
void dsi_ctrl_hw_cmn_ulps_exit(struct dsi_ctrl_hw *ctrl, u32 lanes);
|
||||
u32 dsi_ctrl_hw_cmn_get_lanes_in_ulps(struct dsi_ctrl_hw *ctrl);
|
||||
|
||||
void dsi_ctrl_hw_14_clamp_enable(struct dsi_ctrl_hw *ctrl,
|
||||
u32 lanes,
|
||||
bool enable_ulps);
|
||||
|
||||
void dsi_ctrl_hw_14_clamp_disable(struct dsi_ctrl_hw *ctrl,
|
||||
u32 lanes,
|
||||
bool disable_ulps);
|
||||
ssize_t dsi_ctrl_hw_14_reg_dump_to_buffer(struct dsi_ctrl_hw *ctrl,
|
||||
char *buf,
|
||||
u32 size);
|
||||
|
||||
/* Definitions specific to 2.0 DSI controller hardware */
|
||||
void dsi_ctrl_hw_20_setup_lane_map(struct dsi_ctrl_hw *ctrl,
|
||||
struct dsi_lane_map *lane_map);
|
||||
int dsi_ctrl_hw_20_wait_for_lane_idle(struct dsi_ctrl_hw *ctrl, u32 lanes);
|
||||
ssize_t dsi_ctrl_hw_20_reg_dump_to_buffer(struct dsi_ctrl_hw *ctrl,
|
||||
char *buf,
|
||||
u32 size);
|
||||
void dsi_ctrl_hw_kickoff_non_embedded_mode(struct dsi_ctrl_hw *ctrl,
|
||||
struct dsi_ctrl_cmd_dma_info *cmd,
|
||||
u32 flags);
|
||||
|
||||
/* Definitions specific to 2.2 DSI controller hardware */
|
||||
void dsi_ctrl_hw_22_setup_lane_map(struct dsi_ctrl_hw *ctrl,
|
||||
struct dsi_lane_map *lane_map);
|
||||
int dsi_ctrl_hw_22_wait_for_lane_idle(struct dsi_ctrl_hw *ctrl, u32 lanes);
|
||||
ssize_t dsi_ctrl_hw_22_reg_dump_to_buffer(struct dsi_ctrl_hw *ctrl,
|
||||
char *buf, u32 size);
|
||||
|
||||
void dsi_ctrl_hw_22_config_clk_gating(struct dsi_ctrl_hw *ctrl, bool enable,
|
||||
enum dsi_clk_gate_type clk_selection);
|
||||
|
||||
void dsi_ctrl_hw_cmn_set_continuous_clk(struct dsi_ctrl_hw *ctrl, bool enable);
|
||||
void dsi_ctrl_hw_cmn_hs_req_sel(struct dsi_ctrl_hw *ctrl, bool sel_phy);
|
||||
|
||||
/* dynamic refresh specific functions */
|
||||
void dsi_phy_hw_v3_0_dyn_refresh_helper(struct dsi_phy_hw *phy, u32 offset);
|
||||
void dsi_phy_hw_v3_0_dyn_refresh_config(struct dsi_phy_hw *phy,
|
||||
struct dsi_phy_cfg *cfg, bool is_master);
|
||||
void dsi_phy_hw_v3_0_dyn_refresh_pipe_delay(struct dsi_phy_hw *phy,
|
||||
struct dsi_dyn_clk_delay *delay);
|
||||
|
||||
int dsi_ctrl_hw_cmn_wait4dynamic_refresh_done(struct dsi_ctrl_hw *ctrl);
|
||||
bool dsi_ctrl_hw_cmn_vid_engine_busy(struct dsi_ctrl_hw *ctrl);
|
||||
int dsi_phy_hw_v3_0_cache_phy_timings(struct dsi_phy_per_lane_cfgs *timings,
|
||||
u32 *dst, u32 size);
|
||||
|
||||
void dsi_phy_hw_v4_0_dyn_refresh_trigger_sel(struct dsi_phy_hw *phy,
|
||||
bool is_master);
|
||||
void dsi_phy_hw_v4_0_dyn_refresh_helper(struct dsi_phy_hw *phy, u32 offset);
|
||||
void dsi_phy_hw_v4_0_dyn_refresh_config(struct dsi_phy_hw *phy,
|
||||
struct dsi_phy_cfg *cfg, bool is_master);
|
||||
void dsi_phy_hw_v4_0_dyn_refresh_pipe_delay(struct dsi_phy_hw *phy,
|
||||
struct dsi_dyn_clk_delay *delay);
|
||||
|
||||
int dsi_phy_hw_v4_0_cache_phy_timings(struct dsi_phy_per_lane_cfgs *timings,
|
||||
u32 *dst, u32 size);
|
||||
|
||||
void dsi_ctrl_hw_22_configure_cmddma_window(struct dsi_ctrl_hw *ctrl,
|
||||
struct dsi_ctrl_cmd_dma_info *cmd,
|
||||
u32 line_no, u32 window);
|
||||
void dsi_ctrl_hw_22_reset_trigger_controls(struct dsi_ctrl_hw *ctrl,
|
||||
struct dsi_host_common_cfg *cfg);
|
||||
u32 dsi_ctrl_hw_22_log_line_count(struct dsi_ctrl_hw *ctrl, bool cmd_mode);
|
||||
#endif /* _DSI_CATALOG_H_ */
|
332
techpack/display/msm/dsi/dsi_clk.h
Normal file
332
techpack/display/msm/dsi/dsi_clk.h
Normal file
@ -0,0 +1,332 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _DSI_CLK_H_
|
||||
#define _DSI_CLK_H_
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/clk.h>
|
||||
#include <drm/drmP.h>
|
||||
|
||||
#define MAX_STRING_LEN 32
|
||||
#define MAX_DSI_CTRL 2
|
||||
|
||||
enum dsi_clk_state {
|
||||
DSI_CLK_OFF,
|
||||
DSI_CLK_ON,
|
||||
DSI_CLK_EARLY_GATE,
|
||||
};
|
||||
|
||||
enum clk_req_client {
|
||||
DSI_CLK_REQ_MDP_CLIENT = 0,
|
||||
DSI_CLK_REQ_DSI_CLIENT,
|
||||
};
|
||||
|
||||
enum dsi_link_clk_type {
|
||||
DSI_LINK_ESC_CLK,
|
||||
DSI_LINK_BYTE_CLK,
|
||||
DSI_LINK_PIX_CLK,
|
||||
DSI_LINK_BYTE_INTF_CLK,
|
||||
DSI_LINK_CLK_MAX,
|
||||
};
|
||||
|
||||
enum dsi_link_clk_op_type {
|
||||
DSI_LINK_CLK_SET_RATE = BIT(0),
|
||||
DSI_LINK_CLK_PREPARE = BIT(1),
|
||||
DSI_LINK_CLK_ENABLE = BIT(2),
|
||||
DSI_LINK_CLK_START = BIT(0) | BIT(1) | BIT(2),
|
||||
};
|
||||
|
||||
enum dsi_clk_type {
|
||||
DSI_CORE_CLK = BIT(0),
|
||||
DSI_LINK_CLK = BIT(1),
|
||||
DSI_ALL_CLKS = (BIT(0) | BIT(1)),
|
||||
DSI_CLKS_MAX = BIT(2),
|
||||
};
|
||||
|
||||
enum dsi_lclk_type {
|
||||
DSI_LINK_NONE = 0,
|
||||
DSI_LINK_LP_CLK = BIT(0),
|
||||
DSI_LINK_HS_CLK = BIT(1),
|
||||
};
|
||||
|
||||
struct dsi_clk_ctrl_info {
|
||||
enum dsi_clk_type clk_type;
|
||||
enum dsi_clk_state clk_state;
|
||||
enum clk_req_client client;
|
||||
};
|
||||
|
||||
struct clk_ctrl_cb {
|
||||
void *priv;
|
||||
int (*dsi_clk_cb)(void *priv, struct dsi_clk_ctrl_info clk_ctrl_info);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dsi_core_clk_info - Core clock information for DSI hardware
|
||||
* @mdp_core_clk: Handle to MDP core clock.
|
||||
* @iface_clk: Handle to MDP interface clock.
|
||||
* @core_mmss_clk: Handle to MMSS core clock.
|
||||
* @bus_clk: Handle to bus clock.
|
||||
* @mnoc_clk: Handle to MMSS NOC clock.
|
||||
* @drm: Pointer to drm device node
|
||||
*/
|
||||
struct dsi_core_clk_info {
|
||||
struct clk *mdp_core_clk;
|
||||
struct clk *iface_clk;
|
||||
struct clk *core_mmss_clk;
|
||||
struct clk *bus_clk;
|
||||
struct clk *mnoc_clk;
|
||||
struct drm_device *drm;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dsi_link_hs_clk_info - Set of high speed link clocks for DSI HW
|
||||
* @byte_clk: Handle to DSI byte_clk.
|
||||
* @pixel_clk: Handle to DSI pixel_clk.
|
||||
* @byte_intf_clk: Handle to DSI byte intf. clock.
|
||||
*/
|
||||
struct dsi_link_hs_clk_info {
|
||||
struct clk *byte_clk;
|
||||
struct clk *pixel_clk;
|
||||
struct clk *byte_intf_clk;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dsi_link_lp_clk_info - Set of low power link clocks for DSI HW.
|
||||
* @esc_clk: Handle to DSI escape clock.
|
||||
*/
|
||||
struct dsi_link_lp_clk_info {
|
||||
struct clk *esc_clk;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct link_clk_freq - Clock frequency information for Link clocks
|
||||
* @byte_clk_rate: Frequency of DSI byte_clk in Hz.
|
||||
* @byte_intf_clk_rate: Frequency of DSI byte_intf_clk in Hz.
|
||||
* @pixel_clk_rate: Frequency of DSI pixel_clk in Hz.
|
||||
* @esc_clk_rate: Frequency of DSI escape clock in Hz.
|
||||
*/
|
||||
struct link_clk_freq {
|
||||
u32 byte_clk_rate;
|
||||
u32 byte_intf_clk_rate;
|
||||
u32 pix_clk_rate;
|
||||
u32 esc_clk_rate;
|
||||
};
|
||||
|
||||
/**
|
||||
* typedef *pre_clockoff_cb() - Callback before clock is turned off
|
||||
* @priv: private data pointer.
|
||||
* @clk_type: clock which is being turned off.
|
||||
* @l_type: specifies if the clock is HS or LP type. Valid only for link clocks.
|
||||
* @new_state: next state for the clock.
|
||||
*
|
||||
* @return: error code.
|
||||
*/
|
||||
typedef int (*pre_clockoff_cb)(void *priv,
|
||||
enum dsi_clk_type clk_type,
|
||||
enum dsi_lclk_type l_type,
|
||||
enum dsi_clk_state new_state);
|
||||
|
||||
/**
|
||||
* typedef *post_clockoff_cb() - Callback after clock is turned off
|
||||
* @priv: private data pointer.
|
||||
* @clk_type: clock which was turned off.
|
||||
* @l_type: specifies if the clock is HS or LP type. Valid only for link clocks.
|
||||
* @curr_state: current state for the clock.
|
||||
*
|
||||
* @return: error code.
|
||||
*/
|
||||
typedef int (*post_clockoff_cb)(void *priv,
|
||||
enum dsi_clk_type clk_type,
|
||||
enum dsi_lclk_type l_type,
|
||||
enum dsi_clk_state curr_state);
|
||||
|
||||
/**
|
||||
* typedef *post_clockon_cb() - Callback after clock is turned on
|
||||
* @priv: private data pointer.
|
||||
* @clk_type: clock which was turned on.
|
||||
* @l_type: specifies if the clock is HS or LP type. Valid only for link clocks.
|
||||
* @curr_state: current state for the clock.
|
||||
*
|
||||
* @return: error code.
|
||||
*/
|
||||
typedef int (*post_clockon_cb)(void *priv,
|
||||
enum dsi_clk_type clk_type,
|
||||
enum dsi_lclk_type l_type,
|
||||
enum dsi_clk_state curr_state);
|
||||
|
||||
/**
|
||||
* typedef *pre_clockon_cb() - Callback before clock is turned on
|
||||
* @priv: private data pointer.
|
||||
* @clk_type: clock which is being turned on.
|
||||
* @l_type: specifies if the clock is HS or LP type.Valid only for link clocks.
|
||||
* @new_state: next state for the clock.
|
||||
*
|
||||
* @return: error code.
|
||||
*/
|
||||
typedef int (*pre_clockon_cb)(void *priv,
|
||||
enum dsi_clk_type clk_type,
|
||||
enum dsi_lclk_type l_type,
|
||||
enum dsi_clk_state new_state);
|
||||
|
||||
|
||||
/**
|
||||
* struct dsi_clk_info - clock information for DSI hardware.
|
||||
* @name: client name.
|
||||
* @c_clks[MAX_DSI_CTRL] array of core clock configurations
|
||||
* @l_lp_clks[MAX_DSI_CTRL] array of low power(esc) clock configurations
|
||||
* @l_hs_clks[MAX_DSI_CTRL] array of high speed clock configurations
|
||||
* @ctrl_index[MAX_DSI_CTRL] array of DSI controller indexes mapped
|
||||
* to core and link clock configurations
|
||||
* @pre_clkoff_cb callback before clock is turned off
|
||||
* @post_clkoff_cb callback after clock is turned off
|
||||
* @post_clkon_cb callback after clock is turned on
|
||||
* @pre_clkon_cb callback before clock is turned on
|
||||
* @priv_data pointer to private data
|
||||
* @master_ndx master DSI controller index
|
||||
* @dsi_ctrl_count number of DSI controllers
|
||||
*/
|
||||
struct dsi_clk_info {
|
||||
char name[MAX_STRING_LEN];
|
||||
struct dsi_core_clk_info c_clks[MAX_DSI_CTRL];
|
||||
struct dsi_link_lp_clk_info l_lp_clks[MAX_DSI_CTRL];
|
||||
struct dsi_link_hs_clk_info l_hs_clks[MAX_DSI_CTRL];
|
||||
u32 ctrl_index[MAX_DSI_CTRL];
|
||||
pre_clockoff_cb pre_clkoff_cb;
|
||||
post_clockoff_cb post_clkoff_cb;
|
||||
post_clockon_cb post_clkon_cb;
|
||||
pre_clockon_cb pre_clkon_cb;
|
||||
void *priv_data;
|
||||
u32 master_ndx;
|
||||
u32 dsi_ctrl_count;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dsi_clk_link_set - Pair of clock handles to describe link clocks
|
||||
* @byte_clk: Handle to DSi byte_clk.
|
||||
* @pixel_clk: Handle to DSI pixel_clk.
|
||||
*/
|
||||
struct dsi_clk_link_set {
|
||||
struct clk *byte_clk;
|
||||
struct clk *pixel_clk;
|
||||
};
|
||||
|
||||
/**
|
||||
* dsi_display_clk_mngr_update_splash_status() - Update splash stattus
|
||||
* @clk_mngr: Structure containing DSI clock information
|
||||
* @status: Splash status
|
||||
*/
|
||||
void dsi_display_clk_mngr_update_splash_status(void *clk_mgr, bool status);
|
||||
|
||||
/**
|
||||
* dsi_display_clk_mgr_register() - Register DSI clock manager
|
||||
* @info: Structure containing DSI clock information
|
||||
*/
|
||||
void *dsi_display_clk_mngr_register(struct dsi_clk_info *info);
|
||||
|
||||
/**
|
||||
* dsi_display_clk_mngr_deregister() - Deregister DSI clock manager
|
||||
* @clk_mngr: DSI clock manager pointer
|
||||
*/
|
||||
int dsi_display_clk_mngr_deregister(void *clk_mngr);
|
||||
|
||||
/**
|
||||
* dsi_register_clk_handle() - Register clock handle with DSI clock manager
|
||||
* @clk_mngr: DSI clock manager pointer
|
||||
* @client: DSI clock client pointer.
|
||||
*/
|
||||
void *dsi_register_clk_handle(void *clk_mngr, char *client);
|
||||
|
||||
/**
|
||||
* dsi_deregister_clk_handle() - Deregister clock handle from DSI clock manager
|
||||
* @client: DSI clock client pointer.
|
||||
*
|
||||
* return: error code in case of failure or 0 for success.
|
||||
*/
|
||||
int dsi_deregister_clk_handle(void *client);
|
||||
|
||||
/**
|
||||
* dsi_display_link_clk_force_update_ctrl() - force to set link clks
|
||||
* @handle: Handle of desired DSI clock client.
|
||||
*
|
||||
* return: error code in case of failure or 0 for success.
|
||||
*/
|
||||
|
||||
int dsi_display_link_clk_force_update_ctrl(void *handle);
|
||||
|
||||
/**
|
||||
* dsi_display_clk_ctrl() - set frequencies for link clks
|
||||
* @handle: Handle of desired DSI clock client.
|
||||
* @clk_type: Clock which is being controlled.
|
||||
* @clk_state: Desired state of clock
|
||||
*
|
||||
* return: error code in case of failure or 0 for success.
|
||||
*/
|
||||
int dsi_display_clk_ctrl(void *handle, u32 clk_type, u32 clk_state);
|
||||
|
||||
/**
|
||||
* dsi_clk_set_link_frequencies() - set frequencies for link clks
|
||||
* @client: DSI clock client pointer.
|
||||
* @freq: Structure containing link clock frequencies.
|
||||
* @index: Index of the DSI controller.
|
||||
*
|
||||
* return: error code in case of failure or 0 for success.
|
||||
*/
|
||||
int dsi_clk_set_link_frequencies(void *client, struct link_clk_freq freq,
|
||||
u32 index);
|
||||
|
||||
|
||||
/**
|
||||
* dsi_clk_set_pixel_clk_rate() - set frequency for pixel_clk
|
||||
* @client: DSI clock client pointer.
|
||||
* @pixel_clk: Pixel_clk rate in Hz.
|
||||
* @index: Index of the DSI controller.
|
||||
* return: error code in case of failure or 0 for success.
|
||||
*/
|
||||
int dsi_clk_set_pixel_clk_rate(void *client, u64 pixel_clk, u32 index);
|
||||
|
||||
|
||||
/**
|
||||
* dsi_clk_set_byte_clk_rate() - set frequency for byte clock
|
||||
* @client: DSI clock client pointer.
|
||||
* @byte_clk: Pixel clock rate in Hz.
|
||||
* @byte_intf_clk: Byte interface clock rate in Hz.
|
||||
* @index: Index of the DSI controller.
|
||||
* return: error code in case of failure or 0 for success.
|
||||
*/
|
||||
int dsi_clk_set_byte_clk_rate(void *client, u64 byte_clk,
|
||||
u64 byte_intf_clk, u32 index);
|
||||
|
||||
/**
|
||||
* dsi_clk_update_parent() - update parent clocks for specified clock
|
||||
* @parent: link clock pair which are set as parent.
|
||||
* @child: link clock pair whose parent has to be set.
|
||||
*/
|
||||
int dsi_clk_update_parent(struct dsi_clk_link_set *parent,
|
||||
struct dsi_clk_link_set *child);
|
||||
|
||||
/**
|
||||
* dsi_clk_prepare_enable() - prepare and enable dsi src clocks
|
||||
* @clk: list of src clocks.
|
||||
*
|
||||
* @return: Zero on success and err no on failure
|
||||
*/
|
||||
int dsi_clk_prepare_enable(struct dsi_clk_link_set *clk);
|
||||
|
||||
/**
|
||||
* dsi_clk_disable_unprepare() - disable and unprepare dsi src clocks
|
||||
* @clk: list of src clocks.
|
||||
*/
|
||||
void dsi_clk_disable_unprepare(struct dsi_clk_link_set *clk);
|
||||
|
||||
/**
|
||||
* dsi_display_dump_clk_handle_state() - dump client clock state
|
||||
* @client: DSI clock client pointer.
|
||||
*/
|
||||
int dsi_display_dump_clk_handle_state(void *client);
|
||||
|
||||
#endif /* _DSI_CLK_H_ */
|
1482
techpack/display/msm/dsi/dsi_clk_manager.c
Normal file
1482
techpack/display/msm/dsi/dsi_clk_manager.c
Normal file
File diff suppressed because it is too large
Load Diff
4127
techpack/display/msm/dsi/dsi_ctrl.c
Normal file
4127
techpack/display/msm/dsi/dsi_ctrl.c
Normal file
File diff suppressed because it is too large
Load Diff
889
techpack/display/msm/dsi/dsi_ctrl.h
Normal file
889
techpack/display/msm/dsi/dsi_ctrl.h
Normal file
@ -0,0 +1,889 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _DSI_CTRL_H_
|
||||
#define _DSI_CTRL_H_
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
|
||||
#include "dsi_defs.h"
|
||||
#include "dsi_ctrl_hw.h"
|
||||
#include "dsi_clk.h"
|
||||
#include "dsi_pwr.h"
|
||||
#include "drm_mipi_dsi.h"
|
||||
|
||||
/*
|
||||
* DSI Command transfer modifiers
|
||||
* @DSI_CTRL_CMD_READ: The current transfer involves reading data.
|
||||
* @DSI_CTRL_CMD_BROADCAST: The current transfer needs to be done in
|
||||
* broadcast mode to multiple slaves.
|
||||
* @DSI_CTRL_CMD_BROADCAST_MASTER: This controller is the master and the slaves
|
||||
* sync to this trigger.
|
||||
* @DSI_CTRL_CMD_DEFER_TRIGGER: Defer the command trigger to later.
|
||||
* @DSI_CTRL_CMD_FIFO_STORE: Use FIFO for command transfer in place of
|
||||
* reading data from memory.
|
||||
* @DSI_CTRL_CMD_FETCH_MEMORY: Fetch command from memory through AXI bus
|
||||
* and transfer it.
|
||||
* @DSI_CTRL_CMD_LAST_COMMAND: Trigger the DMA cmd transfer if this is last
|
||||
* command in the batch.
|
||||
* @DSI_CTRL_CMD_NON_EMBEDDED_MODE:Transfer cmd packets in non embedded mode.
|
||||
* @DSI_CTRL_CMD_CUSTOM_DMA_SCHED: Use the dma scheduling line number defined in
|
||||
* display panel dtsi file instead of default.
|
||||
* @DSI_CTRL_CMD_ASYNC_WAIT: Command flag to indicate that the wait for done
|
||||
* for this command is asynchronous and must be queued.
|
||||
*/
|
||||
#define DSI_CTRL_CMD_READ 0x1
|
||||
#define DSI_CTRL_CMD_BROADCAST 0x2
|
||||
#define DSI_CTRL_CMD_BROADCAST_MASTER 0x4
|
||||
#define DSI_CTRL_CMD_DEFER_TRIGGER 0x8
|
||||
#define DSI_CTRL_CMD_FIFO_STORE 0x10
|
||||
#define DSI_CTRL_CMD_FETCH_MEMORY 0x20
|
||||
#define DSI_CTRL_CMD_LAST_COMMAND 0x40
|
||||
#define DSI_CTRL_CMD_NON_EMBEDDED_MODE 0x80
|
||||
#define DSI_CTRL_CMD_CUSTOM_DMA_SCHED 0x100
|
||||
#define DSI_CTRL_CMD_ASYNC_WAIT 0x200
|
||||
|
||||
/* DSI embedded mode fifo size
|
||||
* If the command is greater than 256 bytes it is sent in non-embedded mode.
|
||||
*/
|
||||
#define DSI_EMBEDDED_MODE_DMA_MAX_SIZE_BYTES 256
|
||||
|
||||
/* max size supported for dsi cmd transfer using TPG */
|
||||
#define DSI_CTRL_MAX_CMD_FIFO_STORE_SIZE 64
|
||||
|
||||
/*Default tearcheck window size as programmed by MDP*/
|
||||
#define TEARCHECK_WINDOW_SIZE 5
|
||||
|
||||
/**
|
||||
* enum dsi_power_state - defines power states for dsi controller.
|
||||
* @DSI_CTRL_POWER_VREG_OFF: Digital and analog supplies for DSI controller
|
||||
turned off
|
||||
* @DSI_CTRL_POWER_VREG_ON: Digital and analog supplies for DSI controller
|
||||
* @DSI_CTRL_POWER_MAX: Maximum value.
|
||||
*/
|
||||
enum dsi_power_state {
|
||||
DSI_CTRL_POWER_VREG_OFF = 0,
|
||||
DSI_CTRL_POWER_VREG_ON,
|
||||
DSI_CTRL_POWER_MAX,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum dsi_engine_state - define engine status for dsi controller.
|
||||
* @DSI_CTRL_ENGINE_OFF: Engine is turned off.
|
||||
* @DSI_CTRL_ENGINE_ON: Engine is turned on.
|
||||
* @DSI_CTRL_ENGINE_MAX: Maximum value.
|
||||
*/
|
||||
enum dsi_engine_state {
|
||||
DSI_CTRL_ENGINE_OFF = 0,
|
||||
DSI_CTRL_ENGINE_ON,
|
||||
DSI_CTRL_ENGINE_MAX,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum dsi_ctrl_driver_ops - controller driver ops
|
||||
*/
|
||||
enum dsi_ctrl_driver_ops {
|
||||
DSI_CTRL_OP_POWER_STATE_CHANGE,
|
||||
DSI_CTRL_OP_CMD_ENGINE,
|
||||
DSI_CTRL_OP_VID_ENGINE,
|
||||
DSI_CTRL_OP_HOST_ENGINE,
|
||||
DSI_CTRL_OP_CMD_TX,
|
||||
DSI_CTRL_OP_HOST_INIT,
|
||||
DSI_CTRL_OP_TPG,
|
||||
DSI_CTRL_OP_PHY_SW_RESET,
|
||||
DSI_CTRL_OP_ASYNC_TIMING,
|
||||
DSI_CTRL_OP_MAX
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dsi_ctrl_power_info - digital and analog power supplies for dsi host
|
||||
* @digital: Digital power supply required to turn on DSI controller hardware.
|
||||
* @host_pwr: Analog power supplies required to turn on DSI controller hardware.
|
||||
* Even though DSI controller it self does not require an analog
|
||||
* power supply, supplies required for PLL can be defined here to
|
||||
* allow proper control over these supplies.
|
||||
*/
|
||||
struct dsi_ctrl_power_info {
|
||||
struct dsi_regulator_info digital;
|
||||
struct dsi_regulator_info host_pwr;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dsi_ctrl_clk_info - clock information for DSI controller
|
||||
* @core_clks: Core clocks needed to access DSI controller registers.
|
||||
* @hs_link_clks: Clocks required to transmit high speed data over DSI
|
||||
* @lp_link_clks: Clocks required to perform low power ops over DSI
|
||||
* @rcg_clks: Root clock generation clocks generated in MMSS_CC. The
|
||||
* output of the PLL is set as parent for these root
|
||||
* clocks. These clocks are specific to controller
|
||||
* instance.
|
||||
* @mux_clks: Mux clocks used for Dynamic refresh feature.
|
||||
* @ext_clks: External byte/pixel clocks from the MMSS block. These
|
||||
* clocks are set as parent to rcg clocks.
|
||||
* @pll_op_clks: TODO:
|
||||
* @shadow_clks: TODO:
|
||||
*/
|
||||
struct dsi_ctrl_clk_info {
|
||||
/* Clocks parsed from DT */
|
||||
struct dsi_core_clk_info core_clks;
|
||||
struct dsi_link_hs_clk_info hs_link_clks;
|
||||
struct dsi_link_lp_clk_info lp_link_clks;
|
||||
struct dsi_clk_link_set rcg_clks;
|
||||
|
||||
/* Clocks set by DSI Manager */
|
||||
struct dsi_clk_link_set mux_clks;
|
||||
struct dsi_clk_link_set ext_clks;
|
||||
struct dsi_clk_link_set pll_op_clks;
|
||||
struct dsi_clk_link_set shadow_clks;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dsi_ctrl_state_info - current driver state information
|
||||
* @power_state: Status of power states on DSI controller.
|
||||
* @cmd_engine_state: Status of DSI command engine.
|
||||
* @vid_engine_state: Status of DSI video engine.
|
||||
* @controller_state: Status of DSI Controller engine.
|
||||
* @host_initialized: Boolean to indicate status of DSi host Initialization
|
||||
* @tpg_enabled: Boolean to indicate whether tpg is enabled.
|
||||
*/
|
||||
struct dsi_ctrl_state_info {
|
||||
enum dsi_power_state power_state;
|
||||
enum dsi_engine_state cmd_engine_state;
|
||||
enum dsi_engine_state vid_engine_state;
|
||||
enum dsi_engine_state controller_state;
|
||||
bool host_initialized;
|
||||
bool tpg_enabled;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dsi_ctrl_interrupts - define interrupt information
|
||||
* @irq_lock: Spinlock for ISR handler.
|
||||
* @irq_num: Linux interrupt number associated with device.
|
||||
* @irq_stat_mask: Hardware mask of currently enabled interrupts.
|
||||
* @irq_stat_refcount: Number of times each interrupt has been requested.
|
||||
* @irq_stat_cb: Status IRQ callback definitions.
|
||||
* @irq_err_cb: IRQ callback definition to handle DSI ERRORs.
|
||||
* @cmd_dma_done: Completion signal for DSI_CMD_MODE_DMA_DONE interrupt
|
||||
* @vid_frame_done: Completion signal for DSI_VIDEO_MODE_FRAME_DONE int.
|
||||
* @cmd_frame_done: Completion signal for DSI_CMD_FRAME_DONE interrupt.
|
||||
*/
|
||||
struct dsi_ctrl_interrupts {
|
||||
spinlock_t irq_lock;
|
||||
int irq_num;
|
||||
uint32_t irq_stat_mask;
|
||||
int irq_stat_refcount[DSI_STATUS_INTERRUPT_COUNT];
|
||||
struct dsi_event_cb_info irq_stat_cb[DSI_STATUS_INTERRUPT_COUNT];
|
||||
struct dsi_event_cb_info irq_err_cb;
|
||||
|
||||
struct completion cmd_dma_done;
|
||||
struct completion vid_frame_done;
|
||||
struct completion cmd_frame_done;
|
||||
struct completion bta_done;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dsi_ctrl - DSI controller object
|
||||
* @pdev: Pointer to platform device.
|
||||
* @cell_index: Instance cell id.
|
||||
* @horiz_index: Index in physical horizontal CTRL layout, 0 = leftmost
|
||||
* @name: Name of the controller instance.
|
||||
* @refcount: ref counter.
|
||||
* @ctrl_lock: Mutex for hardware and object access.
|
||||
* @drm_dev: Pointer to DRM device.
|
||||
* @version: DSI controller version.
|
||||
* @hw: DSI controller hardware object.
|
||||
* @current_state: Current driver and hardware state.
|
||||
* @clk_cb: Callback for DSI clock control.
|
||||
* @irq_info: Interrupt information.
|
||||
* @recovery_cb: Recovery call back to SDE.
|
||||
* @panel_id_cb: Callback for reporting panel id.
|
||||
* @clk_info: Clock information.
|
||||
* @clk_freq: DSi Link clock frequency information.
|
||||
* @pwr_info: Power information.
|
||||
* @host_config: Current host configuration.
|
||||
* @mode_bounds: Boundaries of the default mode ROI.
|
||||
* Origin is at top left of all CTRLs.
|
||||
* @roi: Partial update region of interest.
|
||||
* Origin is top left of this CTRL.
|
||||
* @tx_cmd_buf: Tx command buffer.
|
||||
* @cmd_buffer_iova: cmd buffer mapped address.
|
||||
* @cmd_buffer_size: Size of command buffer.
|
||||
* @vaddr: CPU virtual address of cmd buffer.
|
||||
* @secure_mode: Indicates if secure-session is in progress
|
||||
* @esd_check_underway: Indicates if esd status check is in progress
|
||||
* @dma_cmd_wait: Work object waiting on DMA command transfer done.
|
||||
* @dma_cmd_workq: Pointer to the workqueue of DMA command transfer done
|
||||
* wait sequence.
|
||||
* @dma_wait_queued: Indicates if any DMA command transfer wait work
|
||||
* is queued.
|
||||
* @dma_irq_trig: Atomic state to indicate DMA done IRQ
|
||||
* triggered.
|
||||
* @debugfs_root: Root for debugfs entries.
|
||||
* @misr_enable: Frame MISR enable/disable
|
||||
* @misr_cache: Cached Frame MISR value
|
||||
* @frame_threshold_time_us: Frame threshold time in microseconds, where
|
||||
* dsi data lane will be idle i.e from pingpong done to
|
||||
* next TE for command mode.
|
||||
* @phy_isolation_enabled: A boolean property allows to isolate the phy from
|
||||
* dsi controller and run only dsi controller.
|
||||
* @null_insertion_enabled: A boolean property to allow dsi controller to
|
||||
* insert null packet.
|
||||
* @modeupdated: Boolean to send new roi if mode is updated.
|
||||
* @split_link_supported: Boolean to check if hw supports split link.
|
||||
* @enable_cmd_dma_stats: Boolean to indicate the verbose logging during
|
||||
* CMD transfer.
|
||||
* count.
|
||||
* @cmd_mode: Boolean to indicate if panel is running in
|
||||
* command mode.
|
||||
* @cmd_trigger_line: unsigned integer that indicates the line at
|
||||
* which command gets triggered.
|
||||
* @cmd_trigger_frame: unsigned integer that indicates the frame at
|
||||
* which command gets triggered.
|
||||
* @cmd_success_line: unsigned integer that indicates the line at
|
||||
* which command transfer is successful.
|
||||
* @cmd_success_frame: unsigned integer that indicates the frame at
|
||||
* which command transfer is successful.
|
||||
*/
|
||||
struct dsi_ctrl {
|
||||
struct platform_device *pdev;
|
||||
u32 cell_index;
|
||||
u32 horiz_index;
|
||||
const char *name;
|
||||
u32 refcount;
|
||||
struct mutex ctrl_lock;
|
||||
struct drm_device *drm_dev;
|
||||
|
||||
enum dsi_ctrl_version version;
|
||||
struct dsi_ctrl_hw hw;
|
||||
|
||||
/* Current state */
|
||||
struct dsi_ctrl_state_info current_state;
|
||||
struct clk_ctrl_cb clk_cb;
|
||||
|
||||
struct dsi_ctrl_interrupts irq_info;
|
||||
struct dsi_event_cb_info recovery_cb;
|
||||
struct dsi_event_cb_info panel_id_cb;
|
||||
|
||||
/* Clock and power states */
|
||||
struct dsi_ctrl_clk_info clk_info;
|
||||
struct link_clk_freq clk_freq;
|
||||
struct dsi_ctrl_power_info pwr_info;
|
||||
|
||||
struct dsi_host_config host_config;
|
||||
struct dsi_rect mode_bounds;
|
||||
struct dsi_rect roi;
|
||||
|
||||
/* Command tx and rx */
|
||||
struct drm_gem_object *tx_cmd_buf;
|
||||
u32 cmd_buffer_size;
|
||||
u32 cmd_buffer_iova;
|
||||
u32 cmd_len;
|
||||
void *vaddr;
|
||||
bool secure_mode;
|
||||
bool esd_check_underway;
|
||||
struct work_struct dma_cmd_wait;
|
||||
struct workqueue_struct *dma_cmd_workq;
|
||||
bool dma_wait_queued;
|
||||
atomic_t dma_irq_trig;
|
||||
|
||||
/* Debug Information */
|
||||
struct dentry *debugfs_root;
|
||||
|
||||
/* MISR */
|
||||
bool misr_enable;
|
||||
u32 misr_cache;
|
||||
|
||||
u32 frame_threshold_time_us;
|
||||
|
||||
/* Check for spurious interrupts */
|
||||
unsigned long jiffies_start;
|
||||
unsigned int error_interrupt_count;
|
||||
|
||||
bool phy_isolation_enabled;
|
||||
bool null_insertion_enabled;
|
||||
bool modeupdated;
|
||||
bool split_link_supported;
|
||||
bool enable_cmd_dma_stats;
|
||||
bool cmd_mode;
|
||||
u32 cmd_trigger_line;
|
||||
u32 cmd_trigger_frame;
|
||||
u32 cmd_success_line;
|
||||
u32 cmd_success_frame;
|
||||
};
|
||||
|
||||
/**
|
||||
* dsi_ctrl_get() - get a dsi_ctrl handle from an of_node
|
||||
* @of_node: of_node of the DSI controller.
|
||||
*
|
||||
* Gets the DSI controller handle for the corresponding of_node. The ref count
|
||||
* is incremented to one and all subsequent gets will fail until the original
|
||||
* clients calls a put.
|
||||
*
|
||||
* Return: DSI Controller handle.
|
||||
*/
|
||||
struct dsi_ctrl *dsi_ctrl_get(struct device_node *of_node);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_put() - releases a dsi controller handle.
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
*
|
||||
* Releases the DSI controller. Driver will clean up all resources and puts back
|
||||
* the DSI controller into reset state.
|
||||
*/
|
||||
void dsi_ctrl_put(struct dsi_ctrl *dsi_ctrl);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_drv_init() - initialize dsi controller driver.
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
* @parent: Parent directory for debug fs.
|
||||
*
|
||||
* Initializes DSI controller driver. Driver should be initialized after
|
||||
* dsi_ctrl_get() succeeds.
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int dsi_ctrl_drv_init(struct dsi_ctrl *dsi_ctrl, struct dentry *parent);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_drv_deinit() - de-initializes dsi controller driver
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
*
|
||||
* Releases all resources acquired by dsi_ctrl_drv_init().
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int dsi_ctrl_drv_deinit(struct dsi_ctrl *dsi_ctrl);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_validate_timing() - validate a video timing configuration
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
* @timing: Pointer to timing data.
|
||||
*
|
||||
* Driver will validate if the timing configuration is supported on the
|
||||
* controller hardware.
|
||||
*
|
||||
* Return: error code if timing is not supported.
|
||||
*/
|
||||
int dsi_ctrl_validate_timing(struct dsi_ctrl *dsi_ctrl,
|
||||
struct dsi_mode_info *timing);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_update_host_config() - update dsi host configuration
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
* @config: DSI host configuration.
|
||||
* @mode: DSI host mode selected.
|
||||
* @flags: dsi_mode_flags modifying the behavior
|
||||
* @clk_handle: Clock handle for DSI clocks
|
||||
*
|
||||
* Updates driver with new Host configuration to use for host initialization.
|
||||
* This function call will only update the software context. The stored
|
||||
* configuration information will be used when the host is initialized.
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int dsi_ctrl_update_host_config(struct dsi_ctrl *dsi_ctrl,
|
||||
struct dsi_host_config *config,
|
||||
struct dsi_display_mode *mode, int flags,
|
||||
void *clk_handle);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_timing_db_update() - update only controller Timing DB
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
* @enable: Enable/disable Timing DB register
|
||||
*
|
||||
* Update timing db register value during dfps usecases
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int dsi_ctrl_timing_db_update(struct dsi_ctrl *dsi_ctrl,
|
||||
bool enable);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_async_timing_update() - update only controller timing
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
* @timing: New DSI timing info
|
||||
*
|
||||
* Updates host timing values to asynchronously transition to new timing
|
||||
* For example, to update the porch values in a seamless/dynamic fps switch.
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int dsi_ctrl_async_timing_update(struct dsi_ctrl *dsi_ctrl,
|
||||
struct dsi_mode_info *timing);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_phy_sw_reset() - perform a PHY software reset
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
*
|
||||
* Performs a PHY software reset on the DSI controller. Reset should be done
|
||||
* when the controller power state is DSI_CTRL_POWER_CORE_CLK_ON and the PHY is
|
||||
* not enabled.
|
||||
*
|
||||
* This function will fail if driver is in any other state.
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int dsi_ctrl_phy_sw_reset(struct dsi_ctrl *dsi_ctrl);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_phy_reset_config() - Mask/unmask propagation of ahb reset signal
|
||||
* to DSI PHY hardware.
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
* @enable: Mask/unmask the PHY reset signal.
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int dsi_ctrl_phy_reset_config(struct dsi_ctrl *dsi_ctrl, bool enable);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_config_clk_gating() - Enable/Disable DSI PHY clk gating
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
* @enable: Enable/disable DSI PHY clk gating
|
||||
* @clk_selection: clock selection for gating
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int dsi_ctrl_config_clk_gating(struct dsi_ctrl *dsi_ctrl, bool enable,
|
||||
enum dsi_clk_gate_type clk_selection);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_soft_reset() - perform a soft reset on DSI controller
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
*
|
||||
* The video, command and controller engines will be disabled before the
|
||||
* reset is triggered. After, the engines will be re-enabled to the same state
|
||||
* as before the reset.
|
||||
*
|
||||
* If the reset is done while MDP timing engine is turned on, the video
|
||||
* engine should be re-enabled only during the vertical blanking time.
|
||||
*
|
||||
* Return: error code
|
||||
*/
|
||||
int dsi_ctrl_soft_reset(struct dsi_ctrl *dsi_ctrl);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_host_timing_update - reinitialize host with new timing values
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
*
|
||||
* Reinitialize DSI controller hardware with new display timing values
|
||||
* when resolution is switched dynamically.
|
||||
*
|
||||
* Return: error code
|
||||
*/
|
||||
int dsi_ctrl_host_timing_update(struct dsi_ctrl *dsi_ctrl);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_host_init() - Initialize DSI host hardware.
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
* @skip_op: Boolean to indicate few operations can be skipped.
|
||||
* Set during the cont-splash or trusted-vm enable case.
|
||||
*
|
||||
* Initializes DSI controller hardware with host configuration provided by
|
||||
* dsi_ctrl_update_host_config(). Initialization can be performed only during
|
||||
* DSI_CTRL_POWER_CORE_CLK_ON state and after the PHY SW reset has been
|
||||
* performed.
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int dsi_ctrl_host_init(struct dsi_ctrl *dsi_ctrl, bool skip_op);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_host_deinit() - De-Initialize DSI host hardware.
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
*
|
||||
* De-initializes DSI controller hardware. It can be performed only during
|
||||
* DSI_CTRL_POWER_CORE_CLK_ON state after LINK clocks have been turned off.
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int dsi_ctrl_host_deinit(struct dsi_ctrl *dsi_ctrl);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_set_ulps() - set ULPS state for DSI lanes.
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
* @enable: enable/disable ULPS.
|
||||
*
|
||||
* ULPS can be enabled/disabled after DSI host engine is turned on.
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int dsi_ctrl_set_ulps(struct dsi_ctrl *dsi_ctrl, bool enable);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_timing_setup() - Setup DSI host config
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
*
|
||||
* Initializes DSI controller hardware with host configuration provided by
|
||||
* dsi_ctrl_update_host_config(). This is called while setting up DSI host
|
||||
* through dsi_ctrl_setup() and after any ROI change.
|
||||
*
|
||||
* Also used to program the video mode timing values.
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int dsi_ctrl_timing_setup(struct dsi_ctrl *dsi_ctrl);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_setup() - Setup DSI host hardware while coming out of idle screen.
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
*
|
||||
* Initialization of DSI controller hardware with host configuration and
|
||||
* enabling required interrupts. Initialization can be performed only during
|
||||
* DSI_CTRL_POWER_CORE_CLK_ON state and after the PHY SW reset has been
|
||||
* performed.
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int dsi_ctrl_setup(struct dsi_ctrl *dsi_ctrl);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_set_roi() - Set DSI controller's region of interest
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
* @roi: Region of interest rectangle, must be less than mode bounds
|
||||
* @changed: Output parameter, set to true of the controller's ROI was
|
||||
* dirtied by setting the new ROI, and DCS cmd update needed
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int dsi_ctrl_set_roi(struct dsi_ctrl *dsi_ctrl, struct dsi_rect *roi,
|
||||
bool *changed);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_set_tpg_state() - enable/disable test pattern on the controller
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
* @on: enable/disable test pattern.
|
||||
*
|
||||
* Test pattern can be enabled only after Video engine (for video mode panels)
|
||||
* or command engine (for cmd mode panels) is enabled.
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int dsi_ctrl_set_tpg_state(struct dsi_ctrl *dsi_ctrl, bool on);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_cmd_transfer() - Transfer commands on DSI link
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
* @msg: Message to transfer on DSI link.
|
||||
* @flags: Modifiers for message transfer.
|
||||
*
|
||||
* Command transfer can be done only when command engine is enabled. The
|
||||
* transfer API will until either the command transfer finishes or the timeout
|
||||
* value is reached. If the trigger is deferred, it will return without
|
||||
* triggering the transfer. Command parameters are programmed to hardware.
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int dsi_ctrl_cmd_transfer(struct dsi_ctrl *dsi_ctrl,
|
||||
const struct mipi_dsi_msg *msg,
|
||||
u32 *flags);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_cmd_tx_trigger() - Trigger a deferred command.
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
* @flags: Modifiers.
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int dsi_ctrl_cmd_tx_trigger(struct dsi_ctrl *dsi_ctrl, u32 flags);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_set_power_state() - set power state for dsi controller
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
* @state: Power state.
|
||||
*
|
||||
* Set power state for DSI controller. Power state can be changed only when
|
||||
* Controller, Video and Command engines are turned off.
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int dsi_ctrl_set_power_state(struct dsi_ctrl *dsi_ctrl,
|
||||
enum dsi_power_state state);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_set_cmd_engine_state() - set command engine state
|
||||
* @dsi_ctrl: DSI Controller handle.
|
||||
* @state: Engine state.
|
||||
* @skip_op: Boolean to indicate few operations can be skipped.
|
||||
* Set during the cont-splash or trusted-vm enable case.
|
||||
*
|
||||
* Command engine state can be modified only when DSI controller power state is
|
||||
* set to DSI_CTRL_POWER_LINK_CLK_ON.
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int dsi_ctrl_set_cmd_engine_state(struct dsi_ctrl *dsi_ctrl,
|
||||
enum dsi_engine_state state, bool skip_op);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_validate_host_state() - validate DSI ctrl host state
|
||||
* @dsi_ctrl: DSI Controller handle.
|
||||
*
|
||||
* Validate DSI cotroller host state
|
||||
*
|
||||
* Return: boolean indicating whether host is not initialized.
|
||||
*/
|
||||
bool dsi_ctrl_validate_host_state(struct dsi_ctrl *dsi_ctrl);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_set_vid_engine_state() - set video engine state
|
||||
* @dsi_ctrl: DSI Controller handle.
|
||||
* @state: Engine state.
|
||||
* @skip_op: Boolean to indicate few operations can be skipped.
|
||||
* Set during the cont-splash or trusted-vm enable case.
|
||||
*
|
||||
* Video engine state can be modified only when DSI controller power state is
|
||||
* set to DSI_CTRL_POWER_LINK_CLK_ON.
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int dsi_ctrl_set_vid_engine_state(struct dsi_ctrl *dsi_ctrl,
|
||||
enum dsi_engine_state state, bool skip_op);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_set_host_engine_state() - set host engine state
|
||||
* @dsi_ctrl: DSI Controller handle.
|
||||
* @state: Engine state.
|
||||
* @skip_op: Boolean to indicate few operations can be skipped.
|
||||
* Set during the cont-splash or trusted-vm enable case.
|
||||
*
|
||||
* Host engine state can be modified only when DSI controller power state is
|
||||
* set to DSI_CTRL_POWER_LINK_CLK_ON and cmd, video engines are disabled.
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int dsi_ctrl_set_host_engine_state(struct dsi_ctrl *dsi_ctrl,
|
||||
enum dsi_engine_state state, bool skip_op);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_set_ulps() - set ULPS state for DSI lanes.
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
* @enable: enable/disable ULPS.
|
||||
*
|
||||
* ULPS can be enabled/disabled after DSI host engine is turned on.
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int dsi_ctrl_set_ulps(struct dsi_ctrl *dsi_ctrl, bool enable);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_clk_cb_register() - Register DSI controller clk control callback
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
* @clk__cb: Structure containing callback for clock control.
|
||||
*
|
||||
* Register call for DSI clock control
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int dsi_ctrl_clk_cb_register(struct dsi_ctrl *dsi_ctrl,
|
||||
struct clk_ctrl_cb *clk_cb);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_set_clamp_state() - set clamp state for DSI phy
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
* @enable: enable/disable clamping.
|
||||
* @ulps_enabled: ulps state.
|
||||
*
|
||||
* Clamps can be enabled/disabled while DSI controller is still turned on.
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int dsi_ctrl_set_clamp_state(struct dsi_ctrl *dsi_Ctrl,
|
||||
bool enable, bool ulps_enabled);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_set_clock_source() - set clock source fpr dsi link clocks
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
* @source_clks: Source clocks for DSI link clocks.
|
||||
*
|
||||
* Clock source should be changed while link clocks are disabled.
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int dsi_ctrl_set_clock_source(struct dsi_ctrl *dsi_ctrl,
|
||||
struct dsi_clk_link_set *source_clks);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_enable_status_interrupt() - enable status interrupts
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
* @intr_idx: Index interrupt to disable.
|
||||
* @event_info: Pointer to event callback definition
|
||||
*/
|
||||
void dsi_ctrl_enable_status_interrupt(struct dsi_ctrl *dsi_ctrl,
|
||||
uint32_t intr_idx, struct dsi_event_cb_info *event_info);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_disable_status_interrupt() - disable status interrupts
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
* @intr_idx: Index interrupt to disable.
|
||||
*/
|
||||
void dsi_ctrl_disable_status_interrupt(
|
||||
struct dsi_ctrl *dsi_ctrl, uint32_t intr_idx);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_setup_misr() - Setup frame MISR
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
* @enable: enable/disable MISR.
|
||||
* @frame_count: Number of frames to accumulate MISR.
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int dsi_ctrl_setup_misr(struct dsi_ctrl *dsi_ctrl,
|
||||
bool enable,
|
||||
u32 frame_count);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_collect_misr() - Read frame MISR
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
*
|
||||
* Return: MISR value.
|
||||
*/
|
||||
u32 dsi_ctrl_collect_misr(struct dsi_ctrl *dsi_ctrl);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_cache_misr - Cache frame MISR value
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
*/
|
||||
void dsi_ctrl_cache_misr(struct dsi_ctrl *dsi_ctrl);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_drv_register() - register platform driver for dsi controller
|
||||
*/
|
||||
void dsi_ctrl_drv_register(void);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_drv_unregister() - unregister platform driver
|
||||
*/
|
||||
void dsi_ctrl_drv_unregister(void);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_reset() - Reset DSI PHY CLK/DATA lane
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
* @mask: Mask to indicate if CLK and/or DATA lane needs reset.
|
||||
*/
|
||||
int dsi_ctrl_reset(struct dsi_ctrl *dsi_ctrl, int mask);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_get_hw_version() - read dsi controller hw revision
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
*/
|
||||
int dsi_ctrl_get_hw_version(struct dsi_ctrl *dsi_ctrl);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_vid_engine_en() - Control DSI video engine HW state
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
* @on: variable to control video engine ON/OFF.
|
||||
*/
|
||||
int dsi_ctrl_vid_engine_en(struct dsi_ctrl *dsi_ctrl, bool on);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_setup_avr() - Set/Clear the AVR_SUPPORT_ENABLE bit
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
* @enable: variable to control AVR support ON/OFF.
|
||||
*/
|
||||
int dsi_ctrl_setup_avr(struct dsi_ctrl *dsi_ctrl, bool enable);
|
||||
|
||||
/**
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
* cmd_len: Length of command.
|
||||
* flags: Config mode flags.
|
||||
*/
|
||||
void dsi_message_setup_tx_mode(struct dsi_ctrl *dsi_ctrl, u32 cmd_len,
|
||||
u32 *flags);
|
||||
|
||||
/**
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
* cmd_len: Length of command.
|
||||
* flags: Config mode flags.
|
||||
*/
|
||||
int dsi_message_validate_tx_mode(struct dsi_ctrl *dsi_ctrl, u32 cmd_len,
|
||||
u32 *flags);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_isr_configure() - API to register/deregister dsi isr
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
* @enable: variable to control register/deregister isr
|
||||
*/
|
||||
void dsi_ctrl_isr_configure(struct dsi_ctrl *dsi_ctrl, bool enable);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_mask_error_status_interrupts() - API to mask dsi ctrl error status
|
||||
* interrupts
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
* @idx: id indicating which interrupts to enable/disable.
|
||||
* @mask_enable: boolean to enable/disable masking.
|
||||
*/
|
||||
void dsi_ctrl_mask_error_status_interrupts(struct dsi_ctrl *dsi_ctrl, u32 idx,
|
||||
bool mask_enable);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_irq_update() - Put a irq vote to process DSI error
|
||||
* interrupts at any time.
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
* @enable: variable to control enable/disable irq line
|
||||
*/
|
||||
void dsi_ctrl_irq_update(struct dsi_ctrl *dsi_ctrl, bool enable);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_get_host_engine_init_state() - Return host init state
|
||||
*/
|
||||
int dsi_ctrl_get_host_engine_init_state(struct dsi_ctrl *dsi_ctrl,
|
||||
bool *state);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_wait_for_cmd_mode_mdp_idle() - Wait for command mode engine not to
|
||||
* be busy sending data from display engine.
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
*/
|
||||
int dsi_ctrl_wait_for_cmd_mode_mdp_idle(struct dsi_ctrl *dsi_ctrl);
|
||||
/**
|
||||
* dsi_ctrl_update_host_state() - Set the host state
|
||||
*/
|
||||
int dsi_ctrl_update_host_state(struct dsi_ctrl *dsi_ctrl,
|
||||
enum dsi_ctrl_driver_ops op, bool en);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_pixel_format_to_bpp() - returns number of bits per pxl
|
||||
*/
|
||||
int dsi_ctrl_pixel_format_to_bpp(enum dsi_pixel_format dst_format);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_hs_req_sel() - API to enable continuous clk support through phy
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
* @sel_phy: Boolean to control whether to select phy or
|
||||
* controller
|
||||
*/
|
||||
void dsi_ctrl_hs_req_sel(struct dsi_ctrl *dsi_ctrl, bool sel_phy);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_set_continuous_clk() - API to set/unset force clock lane HS request.
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
* @enable: variable to control continuous clock.
|
||||
*/
|
||||
void dsi_ctrl_set_continuous_clk(struct dsi_ctrl *dsi_ctrl, bool enable);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_wait4dynamic_refresh_done() - Poll for dynamic refresh done
|
||||
* interrupt.
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
*/
|
||||
int dsi_ctrl_wait4dynamic_refresh_done(struct dsi_ctrl *ctrl);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_get_io_resources() - reads associated register range
|
||||
*
|
||||
* @io_res: pointer to msm_io_res struct to populate the ranges
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int dsi_ctrl_get_io_resources(struct msm_io_res *io_res);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_mask_overflow() - API to mask/unmask overflow errors.
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
* @enable: variable to control masking/unmasking.
|
||||
*/
|
||||
void dsi_ctrl_mask_overflow(struct dsi_ctrl *dsi_ctrl, bool enable);
|
||||
|
||||
#endif /* _DSI_CTRL_H_ */
|
929
techpack/display/msm/dsi/dsi_ctrl_hw.h
Normal file
929
techpack/display/msm/dsi/dsi_ctrl_hw.h
Normal file
@ -0,0 +1,929 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _DSI_CTRL_HW_H_
|
||||
#define _DSI_CTRL_HW_H_
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/bitmap.h>
|
||||
|
||||
#include "dsi_defs.h"
|
||||
|
||||
#define DSI_CTRL_HW_DBG(c, fmt, ...) DRM_DEV_DEBUG(NULL, "[msm-dsi-debug]: DSI_%d: "\
|
||||
fmt, c ? c->index : -1, ##__VA_ARGS__)
|
||||
#define DSI_CTRL_HW_ERR(c, fmt, ...) DRM_DEV_ERROR(NULL, "[msm-dsi-error]: DSI_%d: "\
|
||||
fmt, c ? c->index : -1, ##__VA_ARGS__)
|
||||
#define DSI_CTRL_HW_INFO(c, fmt, ...) DRM_DEV_INFO(NULL, "[msm-dsi-info]: DSI_%d: "\
|
||||
fmt, c ? c->index : -1, ##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* Modifier flag for command transmission. If this flag is set, command
|
||||
* information is programmed to hardware and transmission is not triggered.
|
||||
* Caller should call the trigger_command_dma() to start the transmission. This
|
||||
* flag is valed for kickoff_command() and kickoff_fifo_command() operations.
|
||||
*/
|
||||
#define DSI_CTRL_HW_CMD_WAIT_FOR_TRIGGER 0x1
|
||||
|
||||
/**
|
||||
* enum dsi_ctrl_version - version of the dsi host controller
|
||||
* @DSI_CTRL_VERSION_UNKNOWN: Unknown controller version
|
||||
* @DSI_CTRL_VERSION_1_3: DSI host v1.3 controller
|
||||
* @DSI_CTRL_VERSION_1_4: DSI host v1.4 controller
|
||||
* @DSI_CTRL_VERSION_2_0: DSI host v2.0 controller
|
||||
* @DSI_CTRL_VERSION_2_2: DSI host v2.2 controller
|
||||
* @DSI_CTRL_VERSION_2_3: DSI host v2.3 controller
|
||||
* @DSI_CTRL_VERSION_2_4: DSI host v2.4 controller
|
||||
* @DSI_CTRL_VERSION_2_5: DSI host v2.5 controller
|
||||
* @DSI_CTRL_VERSION_MAX: max version
|
||||
*/
|
||||
enum dsi_ctrl_version {
|
||||
DSI_CTRL_VERSION_UNKNOWN,
|
||||
DSI_CTRL_VERSION_1_3,
|
||||
DSI_CTRL_VERSION_1_4,
|
||||
DSI_CTRL_VERSION_2_0,
|
||||
DSI_CTRL_VERSION_2_2,
|
||||
DSI_CTRL_VERSION_2_3,
|
||||
DSI_CTRL_VERSION_2_4,
|
||||
DSI_CTRL_VERSION_2_5,
|
||||
DSI_CTRL_VERSION_MAX
|
||||
};
|
||||
|
||||
/**
|
||||
* enum dsi_ctrl_hw_features - features supported by dsi host controller
|
||||
* @DSI_CTRL_VIDEO_TPG: Test pattern support for video mode.
|
||||
* @DSI_CTRL_CMD_TPG: Test pattern support for command mode.
|
||||
* @DSI_CTRL_VARIABLE_REFRESH_RATE: variable panel timing
|
||||
* @DSI_CTRL_DYNAMIC_REFRESH: variable pixel clock rate
|
||||
* @DSI_CTRL_NULL_PACKET_INSERTION: NULL packet insertion
|
||||
* @DSI_CTRL_DESKEW_CALIB: Deskew calibration support
|
||||
* @DSI_CTRL_DPHY: Controller support for DPHY
|
||||
* @DSI_CTRL_CPHY: Controller support for CPHY
|
||||
* @DSI_CTRL_MAX_FEATURES:
|
||||
*/
|
||||
enum dsi_ctrl_hw_features {
|
||||
DSI_CTRL_VIDEO_TPG,
|
||||
DSI_CTRL_CMD_TPG,
|
||||
DSI_CTRL_VARIABLE_REFRESH_RATE,
|
||||
DSI_CTRL_DYNAMIC_REFRESH,
|
||||
DSI_CTRL_NULL_PACKET_INSERTION,
|
||||
DSI_CTRL_DESKEW_CALIB,
|
||||
DSI_CTRL_DPHY,
|
||||
DSI_CTRL_CPHY,
|
||||
DSI_CTRL_MAX_FEATURES
|
||||
};
|
||||
|
||||
/**
|
||||
* enum dsi_test_pattern - test pattern type
|
||||
* @DSI_TEST_PATTERN_FIXED: Test pattern is fixed, based on init value.
|
||||
* @DSI_TEST_PATTERN_INC: Incremental test pattern, base on init value.
|
||||
* @DSI_TEST_PATTERN_POLY: Pattern generated from polynomial and init val.
|
||||
* @DSI_TEST_PATTERN_MAX:
|
||||
*/
|
||||
enum dsi_test_pattern {
|
||||
DSI_TEST_PATTERN_FIXED = 0,
|
||||
DSI_TEST_PATTERN_INC,
|
||||
DSI_TEST_PATTERN_POLY,
|
||||
DSI_TEST_PATTERN_MAX
|
||||
};
|
||||
|
||||
/**
|
||||
* enum dsi_status_int_index - index of interrupts generated by DSI controller
|
||||
* @DSI_SINT_CMD_MODE_DMA_DONE: Command mode DMA packets are sent out.
|
||||
* @DSI_SINT_CMD_STREAM0_FRAME_DONE: A frame of cmd mode stream0 is sent out.
|
||||
* @DSI_SINT_CMD_STREAM1_FRAME_DONE: A frame of cmd mode stream1 is sent out.
|
||||
* @DSI_SINT_CMD_STREAM2_FRAME_DONE: A frame of cmd mode stream2 is sent out.
|
||||
* @DSI_SINT_VIDEO_MODE_FRAME_DONE: A frame of video mode stream is sent out.
|
||||
* @DSI_SINT_BTA_DONE: A BTA is completed.
|
||||
* @DSI_SINT_CMD_FRAME_DONE: A frame of selected cmd mode stream is
|
||||
* sent out by MDP.
|
||||
* @DSI_SINT_DYN_REFRESH_DONE: The dynamic refresh operation completed.
|
||||
* @DSI_SINT_DESKEW_DONE: The deskew calibration operation done.
|
||||
* @DSI_SINT_DYN_BLANK_DMA_DONE: The dynamic blankin DMA operation has
|
||||
* completed.
|
||||
* @DSI_SINT_ERROR: DSI error has happened.
|
||||
*/
|
||||
enum dsi_status_int_index {
|
||||
DSI_SINT_CMD_MODE_DMA_DONE = 0,
|
||||
DSI_SINT_CMD_STREAM0_FRAME_DONE = 1,
|
||||
DSI_SINT_CMD_STREAM1_FRAME_DONE = 2,
|
||||
DSI_SINT_CMD_STREAM2_FRAME_DONE = 3,
|
||||
DSI_SINT_VIDEO_MODE_FRAME_DONE = 4,
|
||||
DSI_SINT_BTA_DONE = 5,
|
||||
DSI_SINT_CMD_FRAME_DONE = 6,
|
||||
DSI_SINT_DYN_REFRESH_DONE = 7,
|
||||
DSI_SINT_DESKEW_DONE = 8,
|
||||
DSI_SINT_DYN_BLANK_DMA_DONE = 9,
|
||||
DSI_SINT_ERROR = 10,
|
||||
|
||||
DSI_STATUS_INTERRUPT_COUNT
|
||||
};
|
||||
|
||||
/**
|
||||
* enum dsi_status_int_type - status interrupts generated by DSI controller
|
||||
* @DSI_CMD_MODE_DMA_DONE: Command mode DMA packets are sent out.
|
||||
* @DSI_CMD_STREAM0_FRAME_DONE: A frame of command mode stream0 is sent out.
|
||||
* @DSI_CMD_STREAM1_FRAME_DONE: A frame of command mode stream1 is sent out.
|
||||
* @DSI_CMD_STREAM2_FRAME_DONE: A frame of command mode stream2 is sent out.
|
||||
* @DSI_VIDEO_MODE_FRAME_DONE: A frame of video mode stream is sent out.
|
||||
* @DSI_BTA_DONE: A BTA is completed.
|
||||
* @DSI_CMD_FRAME_DONE: A frame of selected command mode stream is
|
||||
* sent out by MDP.
|
||||
* @DSI_DYN_REFRESH_DONE: The dynamic refresh operation has completed.
|
||||
* @DSI_DESKEW_DONE: The deskew calibration operation has completed
|
||||
* @DSI_DYN_BLANK_DMA_DONE: The dynamic blankin DMA operation has
|
||||
* completed.
|
||||
* @DSI_ERROR: DSI error has happened.
|
||||
*/
|
||||
enum dsi_status_int_type {
|
||||
DSI_CMD_MODE_DMA_DONE = BIT(DSI_SINT_CMD_MODE_DMA_DONE),
|
||||
DSI_CMD_STREAM0_FRAME_DONE = BIT(DSI_SINT_CMD_STREAM0_FRAME_DONE),
|
||||
DSI_CMD_STREAM1_FRAME_DONE = BIT(DSI_SINT_CMD_STREAM1_FRAME_DONE),
|
||||
DSI_CMD_STREAM2_FRAME_DONE = BIT(DSI_SINT_CMD_STREAM2_FRAME_DONE),
|
||||
DSI_VIDEO_MODE_FRAME_DONE = BIT(DSI_SINT_VIDEO_MODE_FRAME_DONE),
|
||||
DSI_BTA_DONE = BIT(DSI_SINT_BTA_DONE),
|
||||
DSI_CMD_FRAME_DONE = BIT(DSI_SINT_CMD_FRAME_DONE),
|
||||
DSI_DYN_REFRESH_DONE = BIT(DSI_SINT_DYN_REFRESH_DONE),
|
||||
DSI_DESKEW_DONE = BIT(DSI_SINT_DESKEW_DONE),
|
||||
DSI_DYN_BLANK_DMA_DONE = BIT(DSI_SINT_DYN_BLANK_DMA_DONE),
|
||||
DSI_ERROR = BIT(DSI_SINT_ERROR)
|
||||
};
|
||||
|
||||
/**
|
||||
* enum dsi_error_int_index - index of error interrupts from DSI controller
|
||||
* @DSI_EINT_RDBK_SINGLE_ECC_ERR: Single bit ECC error in read packet.
|
||||
* @DSI_EINT_RDBK_MULTI_ECC_ERR: Multi bit ECC error in read packet.
|
||||
* @DSI_EINT_RDBK_CRC_ERR: CRC error in read packet.
|
||||
* @DSI_EINT_RDBK_INCOMPLETE_PKT: Incomplete read packet.
|
||||
* @DSI_EINT_PERIPH_ERROR_PKT: Error packet returned from peripheral,
|
||||
* @DSI_EINT_LP_RX_TIMEOUT: Low power reverse transmission timeout.
|
||||
* @DSI_EINT_HS_TX_TIMEOUT: High speed fwd transmission timeout.
|
||||
* @DSI_EINT_BTA_TIMEOUT: BTA timeout.
|
||||
* @DSI_EINT_PLL_UNLOCK: PLL has unlocked.
|
||||
* @DSI_EINT_DLN0_ESC_ENTRY_ERR: Incorrect LP Rx escape entry.
|
||||
* @DSI_EINT_DLN0_ESC_SYNC_ERR: LP Rx data is not byte aligned.
|
||||
* @DSI_EINT_DLN0_LP_CONTROL_ERR: Incorrect LP Rx state sequence.
|
||||
* @DSI_EINT_PANEL_SPECIFIC_ERR: DSI Protocol violation error.
|
||||
* @DSI_EINT_INTERLEAVE_OP_CONTENTION: Interleave operation contention.
|
||||
* @DSI_EINT_CMD_DMA_FIFO_UNDERFLOW: Command mode DMA FIFO underflow.
|
||||
* @DSI_EINT_CMD_MDP_FIFO_UNDERFLOW: Command MDP FIFO underflow (failed to
|
||||
* receive one complete line from MDP).
|
||||
* @DSI_EINT_DLN0_HS_FIFO_OVERFLOW: High speed FIFO data lane 0 overflows.
|
||||
* @DSI_EINT_DLN1_HS_FIFO_OVERFLOW: High speed FIFO data lane 1 overflows.
|
||||
* @DSI_EINT_DLN2_HS_FIFO_OVERFLOW: High speed FIFO data lane 2 overflows.
|
||||
* @DSI_EINT_DLN3_HS_FIFO_OVERFLOW: High speed FIFO data lane 3 overflows.
|
||||
* @DSI_EINT_DLN0_HS_FIFO_UNDERFLOW: High speed FIFO data lane 0 underflows.
|
||||
* @DSI_EINT_DLN1_HS_FIFO_UNDERFLOW: High speed FIFO data lane 1 underflows.
|
||||
* @DSI_EINT_DLN2_HS_FIFO_UNDERFLOW: High speed FIFO data lane 2 underflows.
|
||||
* @DSI_EINT_DLN3_HS_FIFO_UNDERFLOW: High speed FIFO data lane 3 undeflows.
|
||||
* @DSI_EINT_DLN0_LP0_CONTENTION: PHY level contention while lane 0 low.
|
||||
* @DSI_EINT_DLN1_LP0_CONTENTION: PHY level contention while lane 1 low.
|
||||
* @DSI_EINT_DLN2_LP0_CONTENTION: PHY level contention while lane 2 low.
|
||||
* @DSI_EINT_DLN3_LP0_CONTENTION: PHY level contention while lane 3 low.
|
||||
* @DSI_EINT_DLN0_LP1_CONTENTION: PHY level contention while lane 0 high.
|
||||
* @DSI_EINT_DLN1_LP1_CONTENTION: PHY level contention while lane 1 high.
|
||||
* @DSI_EINT_DLN2_LP1_CONTENTION: PHY level contention while lane 2 high.
|
||||
* @DSI_EINT_DLN3_LP1_CONTENTION: PHY level contention while lane 3 high.
|
||||
*/
|
||||
enum dsi_error_int_index {
|
||||
DSI_EINT_RDBK_SINGLE_ECC_ERR = 0,
|
||||
DSI_EINT_RDBK_MULTI_ECC_ERR = 1,
|
||||
DSI_EINT_RDBK_CRC_ERR = 2,
|
||||
DSI_EINT_RDBK_INCOMPLETE_PKT = 3,
|
||||
DSI_EINT_PERIPH_ERROR_PKT = 4,
|
||||
DSI_EINT_LP_RX_TIMEOUT = 5,
|
||||
DSI_EINT_HS_TX_TIMEOUT = 6,
|
||||
DSI_EINT_BTA_TIMEOUT = 7,
|
||||
DSI_EINT_PLL_UNLOCK = 8,
|
||||
DSI_EINT_DLN0_ESC_ENTRY_ERR = 9,
|
||||
DSI_EINT_DLN0_ESC_SYNC_ERR = 10,
|
||||
DSI_EINT_DLN0_LP_CONTROL_ERR = 11,
|
||||
DSI_EINT_PANEL_SPECIFIC_ERR = 12,
|
||||
DSI_EINT_INTERLEAVE_OP_CONTENTION = 13,
|
||||
DSI_EINT_CMD_DMA_FIFO_UNDERFLOW = 14,
|
||||
DSI_EINT_CMD_MDP_FIFO_UNDERFLOW = 15,
|
||||
DSI_EINT_DLN0_HS_FIFO_OVERFLOW = 16,
|
||||
DSI_EINT_DLN1_HS_FIFO_OVERFLOW = 17,
|
||||
DSI_EINT_DLN2_HS_FIFO_OVERFLOW = 18,
|
||||
DSI_EINT_DLN3_HS_FIFO_OVERFLOW = 19,
|
||||
DSI_EINT_DLN0_HS_FIFO_UNDERFLOW = 20,
|
||||
DSI_EINT_DLN1_HS_FIFO_UNDERFLOW = 21,
|
||||
DSI_EINT_DLN2_HS_FIFO_UNDERFLOW = 22,
|
||||
DSI_EINT_DLN3_HS_FIFO_UNDERFLOW = 23,
|
||||
DSI_EINT_DLN0_LP0_CONTENTION = 24,
|
||||
DSI_EINT_DLN1_LP0_CONTENTION = 25,
|
||||
DSI_EINT_DLN2_LP0_CONTENTION = 26,
|
||||
DSI_EINT_DLN3_LP0_CONTENTION = 27,
|
||||
DSI_EINT_DLN0_LP1_CONTENTION = 28,
|
||||
DSI_EINT_DLN1_LP1_CONTENTION = 29,
|
||||
DSI_EINT_DLN2_LP1_CONTENTION = 30,
|
||||
DSI_EINT_DLN3_LP1_CONTENTION = 31,
|
||||
|
||||
DSI_ERROR_INTERRUPT_COUNT
|
||||
};
|
||||
|
||||
/**
|
||||
* enum dsi_error_int_type - error interrupts generated by DSI controller
|
||||
* @DSI_RDBK_SINGLE_ECC_ERR: Single bit ECC error in read packet.
|
||||
* @DSI_RDBK_MULTI_ECC_ERR: Multi bit ECC error in read packet.
|
||||
* @DSI_RDBK_CRC_ERR: CRC error in read packet.
|
||||
* @DSI_RDBK_INCOMPLETE_PKT: Incomplete read packet.
|
||||
* @DSI_PERIPH_ERROR_PKT: Error packet returned from peripheral,
|
||||
* @DSI_LP_RX_TIMEOUT: Low power reverse transmission timeout.
|
||||
* @DSI_HS_TX_TIMEOUT: High speed forward transmission timeout.
|
||||
* @DSI_BTA_TIMEOUT: BTA timeout.
|
||||
* @DSI_PLL_UNLOCK: PLL has unlocked.
|
||||
* @DSI_DLN0_ESC_ENTRY_ERR: Incorrect LP Rx escape entry.
|
||||
* @DSI_DLN0_ESC_SYNC_ERR: LP Rx data is not byte aligned.
|
||||
* @DSI_DLN0_LP_CONTROL_ERR: Incorrect LP Rx state sequence.
|
||||
* @DSI_PANEL_SPECIFIC_ERR: DSI Protocol violation.
|
||||
* @DSI_INTERLEAVE_OP_CONTENTION: Interleave operation contention.
|
||||
* @DSI_CMD_DMA_FIFO_UNDERFLOW: Command mode DMA FIFO underflow.
|
||||
* @DSI_CMD_MDP_FIFO_UNDERFLOW: Command MDP FIFO underflow (failed to
|
||||
* receive one complete line from MDP).
|
||||
* @DSI_DLN0_HS_FIFO_OVERFLOW: High speed FIFO for data lane 0 overflows.
|
||||
* @DSI_DLN1_HS_FIFO_OVERFLOW: High speed FIFO for data lane 1 overflows.
|
||||
* @DSI_DLN2_HS_FIFO_OVERFLOW: High speed FIFO for data lane 2 overflows.
|
||||
* @DSI_DLN3_HS_FIFO_OVERFLOW: High speed FIFO for data lane 3 overflows.
|
||||
* @DSI_DLN0_HS_FIFO_UNDERFLOW: High speed FIFO for data lane 0 underflows.
|
||||
* @DSI_DLN1_HS_FIFO_UNDERFLOW: High speed FIFO for data lane 1 underflows.
|
||||
* @DSI_DLN2_HS_FIFO_UNDERFLOW: High speed FIFO for data lane 2 underflows.
|
||||
* @DSI_DLN3_HS_FIFO_UNDERFLOW: High speed FIFO for data lane 3 undeflows.
|
||||
* @DSI_DLN0_LP0_CONTENTION: PHY level contention while lane 0 is low.
|
||||
* @DSI_DLN1_LP0_CONTENTION: PHY level contention while lane 1 is low.
|
||||
* @DSI_DLN2_LP0_CONTENTION: PHY level contention while lane 2 is low.
|
||||
* @DSI_DLN3_LP0_CONTENTION: PHY level contention while lane 3 is low.
|
||||
* @DSI_DLN0_LP1_CONTENTION: PHY level contention while lane 0 is high.
|
||||
* @DSI_DLN1_LP1_CONTENTION: PHY level contention while lane 1 is high.
|
||||
* @DSI_DLN2_LP1_CONTENTION: PHY level contention while lane 2 is high.
|
||||
* @DSI_DLN3_LP1_CONTENTION: PHY level contention while lane 3 is high.
|
||||
*/
|
||||
enum dsi_error_int_type {
|
||||
DSI_RDBK_SINGLE_ECC_ERR = BIT(DSI_EINT_RDBK_SINGLE_ECC_ERR),
|
||||
DSI_RDBK_MULTI_ECC_ERR = BIT(DSI_EINT_RDBK_MULTI_ECC_ERR),
|
||||
DSI_RDBK_CRC_ERR = BIT(DSI_EINT_RDBK_CRC_ERR),
|
||||
DSI_RDBK_INCOMPLETE_PKT = BIT(DSI_EINT_RDBK_INCOMPLETE_PKT),
|
||||
DSI_PERIPH_ERROR_PKT = BIT(DSI_EINT_PERIPH_ERROR_PKT),
|
||||
DSI_LP_RX_TIMEOUT = BIT(DSI_EINT_LP_RX_TIMEOUT),
|
||||
DSI_HS_TX_TIMEOUT = BIT(DSI_EINT_HS_TX_TIMEOUT),
|
||||
DSI_BTA_TIMEOUT = BIT(DSI_EINT_BTA_TIMEOUT),
|
||||
DSI_PLL_UNLOCK = BIT(DSI_EINT_PLL_UNLOCK),
|
||||
DSI_DLN0_ESC_ENTRY_ERR = BIT(DSI_EINT_DLN0_ESC_ENTRY_ERR),
|
||||
DSI_DLN0_ESC_SYNC_ERR = BIT(DSI_EINT_DLN0_ESC_SYNC_ERR),
|
||||
DSI_DLN0_LP_CONTROL_ERR = BIT(DSI_EINT_DLN0_LP_CONTROL_ERR),
|
||||
DSI_PANEL_SPECIFIC_ERR = BIT(DSI_EINT_PANEL_SPECIFIC_ERR),
|
||||
DSI_INTERLEAVE_OP_CONTENTION = BIT(DSI_EINT_INTERLEAVE_OP_CONTENTION),
|
||||
DSI_CMD_DMA_FIFO_UNDERFLOW = BIT(DSI_EINT_CMD_DMA_FIFO_UNDERFLOW),
|
||||
DSI_CMD_MDP_FIFO_UNDERFLOW = BIT(DSI_EINT_CMD_MDP_FIFO_UNDERFLOW),
|
||||
DSI_DLN0_HS_FIFO_OVERFLOW = BIT(DSI_EINT_DLN0_HS_FIFO_OVERFLOW),
|
||||
DSI_DLN1_HS_FIFO_OVERFLOW = BIT(DSI_EINT_DLN1_HS_FIFO_OVERFLOW),
|
||||
DSI_DLN2_HS_FIFO_OVERFLOW = BIT(DSI_EINT_DLN2_HS_FIFO_OVERFLOW),
|
||||
DSI_DLN3_HS_FIFO_OVERFLOW = BIT(DSI_EINT_DLN3_HS_FIFO_OVERFLOW),
|
||||
DSI_DLN0_HS_FIFO_UNDERFLOW = BIT(DSI_EINT_DLN0_HS_FIFO_UNDERFLOW),
|
||||
DSI_DLN1_HS_FIFO_UNDERFLOW = BIT(DSI_EINT_DLN1_HS_FIFO_UNDERFLOW),
|
||||
DSI_DLN2_HS_FIFO_UNDERFLOW = BIT(DSI_EINT_DLN2_HS_FIFO_UNDERFLOW),
|
||||
DSI_DLN3_HS_FIFO_UNDERFLOW = BIT(DSI_EINT_DLN3_HS_FIFO_UNDERFLOW),
|
||||
DSI_DLN0_LP0_CONTENTION = BIT(DSI_EINT_DLN0_LP0_CONTENTION),
|
||||
DSI_DLN1_LP0_CONTENTION = BIT(DSI_EINT_DLN1_LP0_CONTENTION),
|
||||
DSI_DLN2_LP0_CONTENTION = BIT(DSI_EINT_DLN2_LP0_CONTENTION),
|
||||
DSI_DLN3_LP0_CONTENTION = BIT(DSI_EINT_DLN3_LP0_CONTENTION),
|
||||
DSI_DLN0_LP1_CONTENTION = BIT(DSI_EINT_DLN0_LP1_CONTENTION),
|
||||
DSI_DLN1_LP1_CONTENTION = BIT(DSI_EINT_DLN1_LP1_CONTENTION),
|
||||
DSI_DLN2_LP1_CONTENTION = BIT(DSI_EINT_DLN2_LP1_CONTENTION),
|
||||
DSI_DLN3_LP1_CONTENTION = BIT(DSI_EINT_DLN3_LP1_CONTENTION),
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dsi_ctrl_cmd_dma_info - command buffer information
|
||||
* @offset: IOMMU VA for command buffer address.
|
||||
* @length: Length of the command buffer.
|
||||
* @datatype: Datatype of cmd.
|
||||
* @en_broadcast: Enable broadcast mode if set to true.
|
||||
* @is_master: Is master in broadcast mode.
|
||||
* @use_lpm: Use low power mode for command transmission.
|
||||
*/
|
||||
struct dsi_ctrl_cmd_dma_info {
|
||||
u32 offset;
|
||||
u32 length;
|
||||
u8 datatype;
|
||||
bool en_broadcast;
|
||||
bool is_master;
|
||||
bool use_lpm;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dsi_ctrl_cmd_dma_fifo_info - command payload tp be sent using FIFO
|
||||
* @command: VA for command buffer.
|
||||
* @size: Size of the command buffer.
|
||||
* @en_broadcast: Enable broadcast mode if set to true.
|
||||
* @is_master: Is master in broadcast mode.
|
||||
* @use_lpm: Use low power mode for command transmission.
|
||||
*/
|
||||
struct dsi_ctrl_cmd_dma_fifo_info {
|
||||
u32 *command;
|
||||
u32 size;
|
||||
bool en_broadcast;
|
||||
bool is_master;
|
||||
bool use_lpm;
|
||||
};
|
||||
|
||||
struct dsi_ctrl_hw;
|
||||
|
||||
struct ctrl_ulps_config_ops {
|
||||
/**
|
||||
* ulps_request() - request ulps entry for specified lanes
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
* @lanes: ORed list of lanes (enum dsi_data_lanes) which need
|
||||
* to enter ULPS.
|
||||
*
|
||||
* Caller should check if lanes are in ULPS mode by calling
|
||||
* get_lanes_in_ulps() operation.
|
||||
*/
|
||||
void (*ulps_request)(struct dsi_ctrl_hw *ctrl, u32 lanes);
|
||||
|
||||
/**
|
||||
* ulps_exit() - exit ULPS on specified lanes
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
* @lanes: ORed list of lanes (enum dsi_data_lanes) which need
|
||||
* to exit ULPS.
|
||||
*
|
||||
* Caller should check if lanes are in active mode by calling
|
||||
* get_lanes_in_ulps() operation.
|
||||
*/
|
||||
void (*ulps_exit)(struct dsi_ctrl_hw *ctrl, u32 lanes);
|
||||
|
||||
/**
|
||||
* get_lanes_in_ulps() - returns the list of lanes in ULPS mode
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
*
|
||||
* Returns an ORed list of lanes (enum dsi_data_lanes) that are in ULPS
|
||||
* state. If 0 is returned, all the lanes are active.
|
||||
*
|
||||
* Return: List of lanes in ULPS state.
|
||||
*/
|
||||
u32 (*get_lanes_in_ulps)(struct dsi_ctrl_hw *ctrl);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dsi_ctrl_hw_ops - operations supported by dsi host hardware
|
||||
*/
|
||||
struct dsi_ctrl_hw_ops {
|
||||
|
||||
/**
|
||||
* host_setup() - Setup DSI host configuration
|
||||
* @ctrl: Pointer to controller host hardware.
|
||||
* @config: Configuration for DSI host controller
|
||||
*/
|
||||
void (*host_setup)(struct dsi_ctrl_hw *ctrl,
|
||||
struct dsi_host_common_cfg *config);
|
||||
|
||||
/**
|
||||
* video_engine_en() - enable DSI video engine
|
||||
* @ctrl: Pointer to controller host hardware.
|
||||
* @on: Enable/disabel video engine.
|
||||
*/
|
||||
void (*video_engine_en)(struct dsi_ctrl_hw *ctrl, bool on);
|
||||
|
||||
/**
|
||||
* setup_avr() - set the AVR_SUPPORT_ENABLE bit in DSI_VIDEO_MODE_CTRL
|
||||
* @ctrl: Pointer to controller host hardware.
|
||||
* @enable: Controls whether this bit is set or cleared
|
||||
*/
|
||||
void (*setup_avr)(struct dsi_ctrl_hw *ctrl, bool enable);
|
||||
|
||||
/**
|
||||
* video_engine_setup() - Setup dsi host controller for video mode
|
||||
* @ctrl: Pointer to controller host hardware.
|
||||
* @common_cfg: Common configuration parameters.
|
||||
* @cfg: Video mode configuration.
|
||||
*
|
||||
* Set up DSI video engine with a specific configuration. Controller and
|
||||
* video engine are not enabled as part of this function.
|
||||
*/
|
||||
void (*video_engine_setup)(struct dsi_ctrl_hw *ctrl,
|
||||
struct dsi_host_common_cfg *common_cfg,
|
||||
struct dsi_video_engine_cfg *cfg);
|
||||
|
||||
/**
|
||||
* set_video_timing() - set up the timing for video frame
|
||||
* @ctrl: Pointer to controller host hardware.
|
||||
* @mode: Video mode information.
|
||||
*
|
||||
* Set up the video timing parameters for the DSI video mode operation.
|
||||
*/
|
||||
void (*set_video_timing)(struct dsi_ctrl_hw *ctrl,
|
||||
struct dsi_mode_info *mode);
|
||||
|
||||
/**
|
||||
* cmd_engine_setup() - setup dsi host controller for command mode
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
* @common_cfg: Common configuration parameters.
|
||||
* @cfg: Command mode configuration.
|
||||
*
|
||||
* Setup DSI CMD engine with a specific configuration. Controller and
|
||||
* command engine are not enabled as part of this function.
|
||||
*/
|
||||
void (*cmd_engine_setup)(struct dsi_ctrl_hw *ctrl,
|
||||
struct dsi_host_common_cfg *common_cfg,
|
||||
struct dsi_cmd_engine_cfg *cfg);
|
||||
|
||||
/**
|
||||
* setup_cmd_stream() - set up parameters for command pixel streams
|
||||
* @ctrl: Pointer to controller host hardware.
|
||||
* @mode: Pointer to mode information.
|
||||
* @cfg: DSI host configuration that is common to both
|
||||
* video and command modes.
|
||||
* @vc_id: stream_id.
|
||||
*
|
||||
* Setup parameters for command mode pixel stream size.
|
||||
*/
|
||||
void (*setup_cmd_stream)(struct dsi_ctrl_hw *ctrl,
|
||||
struct dsi_mode_info *mode,
|
||||
struct dsi_host_common_cfg *cfg,
|
||||
u32 vc_id,
|
||||
struct dsi_rect *roi);
|
||||
|
||||
/**
|
||||
* ctrl_en() - enable DSI controller engine
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
* @on: turn on/off the DSI controller engine.
|
||||
*/
|
||||
void (*ctrl_en)(struct dsi_ctrl_hw *ctrl, bool on);
|
||||
|
||||
/**
|
||||
* cmd_engine_en() - enable DSI controller command engine
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
* @on: Turn on/off the DSI command engine.
|
||||
*/
|
||||
void (*cmd_engine_en)(struct dsi_ctrl_hw *ctrl, bool on);
|
||||
|
||||
/**
|
||||
* phy_sw_reset() - perform a soft reset on the PHY.
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
*/
|
||||
void (*phy_sw_reset)(struct dsi_ctrl_hw *ctrl);
|
||||
|
||||
/**
|
||||
* config_clk_gating() - enable/disable DSI PHY clk gating
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
* @enable: enable/disable DSI PHY clock gating.
|
||||
* @clk_selection: clock to enable/disable clock gating.
|
||||
*/
|
||||
void (*config_clk_gating)(struct dsi_ctrl_hw *ctrl, bool enable,
|
||||
enum dsi_clk_gate_type clk_selection);
|
||||
|
||||
/**
|
||||
* soft_reset() - perform a soft reset on DSI controller
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
*
|
||||
* The video, command and controller engines will be disabled before the
|
||||
* reset is triggered. After, the engines will be re-enabled to the same
|
||||
* state as before the reset.
|
||||
*
|
||||
* If the reset is done while MDP timing engine is turned on, the video
|
||||
* engine should be re-enabled only during the vertical blanking time.
|
||||
*/
|
||||
void (*soft_reset)(struct dsi_ctrl_hw *ctrl);
|
||||
|
||||
/**
|
||||
* setup_lane_map() - setup mapping between logical and physical lanes
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
* @lane_map: Structure defining the mapping between DSI logical
|
||||
* lanes and physical lanes.
|
||||
*/
|
||||
void (*setup_lane_map)(struct dsi_ctrl_hw *ctrl,
|
||||
struct dsi_lane_map *lane_map);
|
||||
|
||||
/**
|
||||
* kickoff_command() - transmits commands stored in memory
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
* @cmd: Command information.
|
||||
* @flags: Modifiers for command transmission.
|
||||
*
|
||||
* The controller hardware is programmed with address and size of the
|
||||
* command buffer. The transmission is kicked off if
|
||||
* DSI_CTRL_HW_CMD_WAIT_FOR_TRIGGER flag is not set. If this flag is
|
||||
* set, caller should make a separate call to trigger_command_dma() to
|
||||
* transmit the command.
|
||||
*/
|
||||
void (*kickoff_command)(struct dsi_ctrl_hw *ctrl,
|
||||
struct dsi_ctrl_cmd_dma_info *cmd,
|
||||
u32 flags);
|
||||
|
||||
/**
|
||||
* kickoff_command_non_embedded_mode() - cmd in non embedded mode
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
* @cmd: Command information.
|
||||
* @flags: Modifiers for command transmission.
|
||||
*
|
||||
* If command length is greater than DMA FIFO size of 256 bytes we use
|
||||
* this non- embedded mode.
|
||||
* The controller hardware is programmed with address and size of the
|
||||
* command buffer. The transmission is kicked off if
|
||||
* DSI_CTRL_HW_CMD_WAIT_FOR_TRIGGER flag is not set. If this flag is
|
||||
* set, caller should make a separate call to trigger_command_dma() to
|
||||
* transmit the command.
|
||||
*/
|
||||
|
||||
void (*kickoff_command_non_embedded_mode)(struct dsi_ctrl_hw *ctrl,
|
||||
struct dsi_ctrl_cmd_dma_info *cmd,
|
||||
u32 flags);
|
||||
|
||||
/**
|
||||
* kickoff_fifo_command() - transmits a command using FIFO in dsi
|
||||
* hardware.
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
* @cmd: Command information.
|
||||
* @flags: Modifiers for command transmission.
|
||||
*
|
||||
* The controller hardware FIFO is programmed with command header and
|
||||
* payload. The transmission is kicked off if
|
||||
* DSI_CTRL_HW_CMD_WAIT_FOR_TRIGGER flag is not set. If this flag is
|
||||
* set, caller should make a separate call to trigger_command_dma() to
|
||||
* transmit the command.
|
||||
*/
|
||||
void (*kickoff_fifo_command)(struct dsi_ctrl_hw *ctrl,
|
||||
struct dsi_ctrl_cmd_dma_fifo_info *cmd,
|
||||
u32 flags);
|
||||
|
||||
void (*reset_cmd_fifo)(struct dsi_ctrl_hw *ctrl);
|
||||
/**
|
||||
* trigger_command_dma() - trigger transmission of command buffer.
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
*
|
||||
* This trigger can be only used if there was a prior call to
|
||||
* kickoff_command() of kickoff_fifo_command() with
|
||||
* DSI_CTRL_HW_CMD_WAIT_FOR_TRIGGER flag.
|
||||
*/
|
||||
void (*trigger_command_dma)(struct dsi_ctrl_hw *ctrl);
|
||||
|
||||
/**
|
||||
* get_cmd_read_data() - get data read from the peripheral
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
* @rd_buf: Buffer where data will be read into.
|
||||
* @read_offset: Offset from where to read.
|
||||
* @rx_byte: Number of bytes to be read.
|
||||
* @pkt_size: Size of response expected.
|
||||
* @hw_read_cnt: Actual number of bytes read by HW.
|
||||
*/
|
||||
u32 (*get_cmd_read_data)(struct dsi_ctrl_hw *ctrl,
|
||||
u8 *rd_buf,
|
||||
u32 read_offset,
|
||||
u32 rx_byte,
|
||||
u32 pkt_size,
|
||||
u32 *hw_read_cnt);
|
||||
|
||||
/**
|
||||
* wait_for_lane_idle() - wait for DSI lanes to go to idle state
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
* @lanes: ORed list of lanes (enum dsi_data_lanes) which need
|
||||
* to be checked to be in idle state.
|
||||
*/
|
||||
int (*wait_for_lane_idle)(struct dsi_ctrl_hw *ctrl, u32 lanes);
|
||||
|
||||
struct ctrl_ulps_config_ops ulps_ops;
|
||||
|
||||
/**
|
||||
* clamp_enable() - enable DSI clamps
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
* @lanes: ORed list of lanes which need to have clamps released.
|
||||
* @enable_ulps: ulps state.
|
||||
*/
|
||||
|
||||
/**
|
||||
* clamp_enable() - enable DSI clamps to keep PHY driving a stable link
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
* @lanes: ORed list of lanes which need to have clamps released.
|
||||
* @enable_ulps: TODO:??
|
||||
*/
|
||||
void (*clamp_enable)(struct dsi_ctrl_hw *ctrl,
|
||||
u32 lanes,
|
||||
bool enable_ulps);
|
||||
|
||||
/**
|
||||
* clamp_disable() - disable DSI clamps
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
* @lanes: ORed list of lanes which need to have clamps released.
|
||||
* @disable_ulps: ulps state.
|
||||
*/
|
||||
void (*clamp_disable)(struct dsi_ctrl_hw *ctrl,
|
||||
u32 lanes,
|
||||
bool disable_ulps);
|
||||
|
||||
/**
|
||||
* phy_reset_config() - Disable/enable propagation of reset signal
|
||||
* from ahb domain to DSI PHY
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
* @enable: True to mask the reset signal, false to unmask
|
||||
*/
|
||||
void (*phy_reset_config)(struct dsi_ctrl_hw *ctrl,
|
||||
bool enable);
|
||||
|
||||
/**
|
||||
* get_interrupt_status() - returns the interrupt status
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
*
|
||||
* Returns the ORed list of interrupts(enum dsi_status_int_type) that
|
||||
* are active. This list does not include any error interrupts. Caller
|
||||
* should call get_error_status for error interrupts.
|
||||
*
|
||||
* Return: List of active interrupts.
|
||||
*/
|
||||
u32 (*get_interrupt_status)(struct dsi_ctrl_hw *ctrl);
|
||||
|
||||
/**
|
||||
* clear_interrupt_status() - clears the specified interrupts
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
* @ints: List of interrupts to be cleared.
|
||||
*/
|
||||
void (*clear_interrupt_status)(struct dsi_ctrl_hw *ctrl, u32 ints);
|
||||
|
||||
/**
|
||||
* poll_slave_dma_status()- API to poll slave DMA status
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
*/
|
||||
u32 (*poll_slave_dma_status)(struct dsi_ctrl_hw *ctrl);
|
||||
|
||||
/**
|
||||
* enable_status_interrupts() - enable the specified interrupts
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
* @ints: List of interrupts to be enabled.
|
||||
*
|
||||
* Enables the specified interrupts. This list will override the
|
||||
* previous interrupts enabled through this function. Caller has to
|
||||
* maintain the state of the interrupts enabled. To disable all
|
||||
* interrupts, set ints to 0.
|
||||
*/
|
||||
void (*enable_status_interrupts)(struct dsi_ctrl_hw *ctrl, u32 ints);
|
||||
|
||||
/**
|
||||
* get_error_status() - returns the error status
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
*
|
||||
* Returns the ORed list of errors(enum dsi_error_int_type) that are
|
||||
* active. This list does not include any status interrupts. Caller
|
||||
* should call get_interrupt_status for status interrupts.
|
||||
*
|
||||
* Return: List of active error interrupts.
|
||||
*/
|
||||
u64 (*get_error_status)(struct dsi_ctrl_hw *ctrl);
|
||||
|
||||
/**
|
||||
* clear_error_status() - clears the specified errors
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
* @errors: List of errors to be cleared.
|
||||
*/
|
||||
void (*clear_error_status)(struct dsi_ctrl_hw *ctrl, u64 errors);
|
||||
|
||||
/**
|
||||
* enable_error_interrupts() - enable the specified interrupts
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
* @errors: List of errors to be enabled.
|
||||
*
|
||||
* Enables the specified interrupts. This list will override the
|
||||
* previous interrupts enabled through this function. Caller has to
|
||||
* maintain the state of the interrupts enabled. To disable all
|
||||
* interrupts, set errors to 0.
|
||||
*/
|
||||
void (*enable_error_interrupts)(struct dsi_ctrl_hw *ctrl, u64 errors);
|
||||
|
||||
/**
|
||||
* video_test_pattern_setup() - setup test pattern engine for video mode
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
* @type: Type of test pattern.
|
||||
* @init_val: Initial value to use for generating test pattern.
|
||||
*/
|
||||
void (*video_test_pattern_setup)(struct dsi_ctrl_hw *ctrl,
|
||||
enum dsi_test_pattern type,
|
||||
u32 init_val);
|
||||
|
||||
/**
|
||||
* cmd_test_pattern_setup() - setup test patttern engine for cmd mode
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
* @type: Type of test pattern.
|
||||
* @init_val: Initial value to use for generating test pattern.
|
||||
* @stream_id: Stream Id on which packets are generated.
|
||||
*/
|
||||
void (*cmd_test_pattern_setup)(struct dsi_ctrl_hw *ctrl,
|
||||
enum dsi_test_pattern type,
|
||||
u32 init_val,
|
||||
u32 stream_id);
|
||||
|
||||
/**
|
||||
* test_pattern_enable() - enable test pattern engine
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
* @enable: Enable/Disable test pattern engine.
|
||||
*/
|
||||
void (*test_pattern_enable)(struct dsi_ctrl_hw *ctrl, bool enable);
|
||||
|
||||
/**
|
||||
* clear_phy0_ln_err() - clear DSI PHY lane-0 errors
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
*/
|
||||
void (*clear_phy0_ln_err)(struct dsi_ctrl_hw *ctrl);
|
||||
|
||||
/**
|
||||
* trigger_cmd_test_pattern() - trigger a command mode frame update with
|
||||
* test pattern
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
* @stream_id: Stream on which frame update is sent.
|
||||
*/
|
||||
void (*trigger_cmd_test_pattern)(struct dsi_ctrl_hw *ctrl,
|
||||
u32 stream_id);
|
||||
|
||||
ssize_t (*reg_dump_to_buffer)(struct dsi_ctrl_hw *ctrl,
|
||||
char *buf,
|
||||
u32 size);
|
||||
|
||||
/**
|
||||
* setup_misr() - Setup frame MISR
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
* @panel_mode: CMD or VIDEO mode indicator
|
||||
* @enable: Enable/disable MISR.
|
||||
* @frame_count: Number of frames to accumulate MISR.
|
||||
*/
|
||||
void (*setup_misr)(struct dsi_ctrl_hw *ctrl,
|
||||
enum dsi_op_mode panel_mode,
|
||||
bool enable, u32 frame_count);
|
||||
|
||||
/**
|
||||
* collect_misr() - Read frame MISR
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
* @panel_mode: CMD or VIDEO mode indicator
|
||||
*/
|
||||
u32 (*collect_misr)(struct dsi_ctrl_hw *ctrl,
|
||||
enum dsi_op_mode panel_mode);
|
||||
|
||||
/**
|
||||
* set_timing_db() - enable/disable Timing DB register
|
||||
* @ctrl: Pointer to controller host hardware.
|
||||
* @enable: Enable/Disable flag.
|
||||
*
|
||||
* Enable or Disabe the Timing DB register.
|
||||
*/
|
||||
void (*set_timing_db)(struct dsi_ctrl_hw *ctrl,
|
||||
bool enable);
|
||||
/**
|
||||
* clear_rdbk_register() - Clear and reset read back register
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
*/
|
||||
void (*clear_rdbk_register)(struct dsi_ctrl_hw *ctrl);
|
||||
|
||||
/** schedule_dma_cmd() - Schdeule DMA command transfer on a
|
||||
* particular blanking line.
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
* @line_no: Blanking line number on whihch DMA command
|
||||
* needs to be sent.
|
||||
*/
|
||||
void (*schedule_dma_cmd)(struct dsi_ctrl_hw *ctrl, int line_no);
|
||||
|
||||
/**
|
||||
* ctrl_reset() - Reset DSI lanes to recover from DSI errors
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
* @mask: Indicates the error type.
|
||||
*/
|
||||
int (*ctrl_reset)(struct dsi_ctrl_hw *ctrl, int mask);
|
||||
|
||||
/**
|
||||
* mask_error_int() - Mask/Unmask particular DSI error interrupts
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
* @idx: Indicates the errors to be masked.
|
||||
* @en: Bool for mask or unmask of the error
|
||||
*/
|
||||
void (*mask_error_intr)(struct dsi_ctrl_hw *ctrl, u32 idx, bool en);
|
||||
|
||||
/**
|
||||
* error_intr_ctrl() - Mask/Unmask master DSI error interrupt
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
* @en: Bool for mask or unmask of DSI error
|
||||
*/
|
||||
void (*error_intr_ctrl)(struct dsi_ctrl_hw *ctrl, bool en);
|
||||
|
||||
/**
|
||||
* get_error_mask() - get DSI error interrupt mask status
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
*/
|
||||
u32 (*get_error_mask)(struct dsi_ctrl_hw *ctrl);
|
||||
|
||||
/**
|
||||
* get_hw_version() - get DSI controller hw version
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
*/
|
||||
u32 (*get_hw_version)(struct dsi_ctrl_hw *ctrl);
|
||||
|
||||
/**
|
||||
* wait_for_cmd_mode_mdp_idle() - wait for command mode engine not to
|
||||
* be busy sending data from display engine
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
*/
|
||||
int (*wait_for_cmd_mode_mdp_idle)(struct dsi_ctrl_hw *ctrl);
|
||||
|
||||
/**
|
||||
* hw.ops.set_continuous_clk() - Set continuous clock
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
* @enable: Bool to control continuous clock request.
|
||||
*/
|
||||
void (*set_continuous_clk)(struct dsi_ctrl_hw *ctrl, bool enable);
|
||||
|
||||
/**
|
||||
* hw.ops.wait4dynamic_refresh_done() - Wait for dynamic refresh done
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
*/
|
||||
int (*wait4dynamic_refresh_done)(struct dsi_ctrl_hw *ctrl);
|
||||
|
||||
/**
|
||||
* hw.ops.vid_engine_busy() - Returns true if vid engine is busy
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
*/
|
||||
bool (*vid_engine_busy)(struct dsi_ctrl_hw *ctrl);
|
||||
|
||||
/**
|
||||
* hw.ops.hs_req_sel() - enable continuous clk support through phy
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
* @sel_phy: Bool to control whether to select phy or controller
|
||||
*/
|
||||
void (*hs_req_sel)(struct dsi_ctrl_hw *ctrl, bool sel_phy);
|
||||
|
||||
/**
|
||||
* hw.ops.configure_cmddma_window() - configure DMA window for CMD TX
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
* @cmd: Pointer to the DSI DMA command info.
|
||||
* @line_no: Line number at which the CMD needs to be triggered.
|
||||
* @window: Width of the DMA CMD window.
|
||||
*/
|
||||
void (*configure_cmddma_window)(struct dsi_ctrl_hw *ctrl,
|
||||
struct dsi_ctrl_cmd_dma_info *cmd,
|
||||
u32 line_no, u32 window);
|
||||
|
||||
/**
|
||||
* hw.ops.reset_trig_ctrl() - resets trigger control of DSI controller
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
* @cfg: Common configuration parameters.
|
||||
*/
|
||||
void (*reset_trig_ctrl)(struct dsi_ctrl_hw *ctrl,
|
||||
struct dsi_host_common_cfg *cfg);
|
||||
|
||||
/**
|
||||
* hw.ops.log_line_count() - reads the MDP interface line count
|
||||
* registers.
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
* @cmd_mode: Boolean to indicate command mode operation.
|
||||
*/
|
||||
u32 (*log_line_count)(struct dsi_ctrl_hw *ctrl, bool cmd_mode);
|
||||
};
|
||||
|
||||
/*
|
||||
* struct dsi_ctrl_hw - DSI controller hardware object specific to an instance
|
||||
* @base: VA for the DSI controller base address.
|
||||
* @length: Length of the DSI controller register map.
|
||||
* @mmss_misc_base: Base address of mmss_misc register map.
|
||||
* @mmss_misc_length: Length of mmss_misc register map.
|
||||
* @disp_cc_base: Base address of disp_cc register map.
|
||||
* @disp_cc_length: Length of disp_cc register map.
|
||||
* @mdp_intf_base: Base address of mdp_intf register map. Addresses of
|
||||
* MDP_TEAR_INTF_TEAR_LINE_COUNT and MDP_TEAR_INTF_LINE_COUNT
|
||||
* are mapped using the base address to test and validate
|
||||
* the RD ptr value and line count value respectively when
|
||||
* a CMD is triggered and it succeeds.
|
||||
* @index: Instance ID of the controller.
|
||||
* @feature_map: Features supported by the DSI controller.
|
||||
* @ops: Function pointers to the operations supported by the
|
||||
* controller.
|
||||
* @supported_interrupts: Number of supported interrupts.
|
||||
* @supported_errors: Number of supported errors.
|
||||
* @phy_isolation_enabled: A boolean property allows to isolate the phy from
|
||||
* dsi controller and run only dsi controller.
|
||||
* @null_insertion_enabled: A boolean property to allow dsi controller to
|
||||
* insert null packet.
|
||||
* @widebus_support: 48 bit wide data bus is supported.
|
||||
* @reset_trig_ctrl: Boolean to indicate if trigger control needs to
|
||||
* be reset to default.
|
||||
*/
|
||||
struct dsi_ctrl_hw {
|
||||
void __iomem *base;
|
||||
u32 length;
|
||||
void __iomem *mmss_misc_base;
|
||||
u32 mmss_misc_length;
|
||||
void __iomem *disp_cc_base;
|
||||
u32 disp_cc_length;
|
||||
void __iomem *mdp_intf_base;
|
||||
u32 index;
|
||||
|
||||
/* features */
|
||||
DECLARE_BITMAP(feature_map, DSI_CTRL_MAX_FEATURES);
|
||||
struct dsi_ctrl_hw_ops ops;
|
||||
|
||||
/* capabilities */
|
||||
u32 supported_interrupts;
|
||||
u64 supported_errors;
|
||||
|
||||
bool phy_isolation_enabled;
|
||||
bool null_insertion_enabled;
|
||||
bool widebus_support;
|
||||
bool reset_trig_ctrl;
|
||||
};
|
||||
|
||||
#endif /* _DSI_CTRL_HW_H_ */
|
475
techpack/display/msm/dsi/dsi_ctrl_hw_1_4.c
Normal file
475
techpack/display/msm/dsi/dsi_ctrl_hw_1_4.c
Normal file
@ -0,0 +1,475 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/iopoll.h>
|
||||
|
||||
#include "dsi_ctrl_hw.h"
|
||||
#include "dsi_ctrl_reg.h"
|
||||
#include "dsi_hw.h"
|
||||
|
||||
#define MMSS_MISC_CLAMP_REG_OFF 0x0014
|
||||
|
||||
/**
|
||||
* dsi_ctrl_hw_14_setup_lane_map() - setup mapping between
|
||||
* logical and physical lanes
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
* @lane_map: Structure defining the mapping between DSI logical
|
||||
* lanes and physical lanes.
|
||||
*/
|
||||
void dsi_ctrl_hw_14_setup_lane_map(struct dsi_ctrl_hw *ctrl,
|
||||
struct dsi_lane_map *lane_map)
|
||||
{
|
||||
DSI_W32(ctrl, DSI_LANE_SWAP_CTRL, lane_map->lane_map_v1);
|
||||
|
||||
DSI_CTRL_HW_DBG(ctrl, "Lane swap setup complete\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* dsi_ctrl_hw_14_wait_for_lane_idle()
|
||||
* This function waits for all the active DSI lanes to be idle by polling all
|
||||
* the FIFO_EMPTY bits and polling he lane status to ensure that all the lanes
|
||||
* are in stop state. This function assumes that the bus clocks required to
|
||||
* access the registers are already turned on.
|
||||
*
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
* @lanes: ORed list of lanes (enum dsi_data_lanes) which need
|
||||
* to be stopped.
|
||||
*
|
||||
* return: Error code.
|
||||
*/
|
||||
int dsi_ctrl_hw_14_wait_for_lane_idle(struct dsi_ctrl_hw *ctrl, u32 lanes)
|
||||
{
|
||||
int rc = 0, val = 0;
|
||||
u32 stop_state_mask = 0, fifo_empty_mask = 0;
|
||||
u32 const sleep_us = 10;
|
||||
u32 const timeout_us = 100;
|
||||
|
||||
if (lanes & DSI_DATA_LANE_0) {
|
||||
stop_state_mask |= BIT(0);
|
||||
fifo_empty_mask |= (BIT(12) | BIT(16));
|
||||
}
|
||||
if (lanes & DSI_DATA_LANE_1) {
|
||||
stop_state_mask |= BIT(1);
|
||||
fifo_empty_mask |= BIT(20);
|
||||
}
|
||||
if (lanes & DSI_DATA_LANE_2) {
|
||||
stop_state_mask |= BIT(2);
|
||||
fifo_empty_mask |= BIT(24);
|
||||
}
|
||||
if (lanes & DSI_DATA_LANE_3) {
|
||||
stop_state_mask |= BIT(3);
|
||||
fifo_empty_mask |= BIT(28);
|
||||
}
|
||||
|
||||
DSI_CTRL_HW_DBG(ctrl, "polling for fifo empty, mask=0x%08x\n",
|
||||
fifo_empty_mask);
|
||||
rc = readl_poll_timeout(ctrl->base + DSI_FIFO_STATUS, val,
|
||||
(val & fifo_empty_mask), sleep_us, timeout_us);
|
||||
if (rc) {
|
||||
DSI_CTRL_HW_ERR(ctrl, "fifo not empty, FIFO_STATUS=0x%08x\n",
|
||||
val);
|
||||
goto error;
|
||||
}
|
||||
|
||||
DSI_CTRL_HW_DBG(ctrl, "polling for lanes to be in stop state, mask=0x%08x\n",
|
||||
stop_state_mask);
|
||||
rc = readl_poll_timeout(ctrl->base + DSI_LANE_STATUS, val,
|
||||
(val & stop_state_mask), sleep_us, timeout_us);
|
||||
if (rc) {
|
||||
DSI_CTRL_HW_ERR(ctrl, "lanes not in stop state, LANE_STATUS=0x%08x\n",
|
||||
val);
|
||||
goto error;
|
||||
}
|
||||
|
||||
error:
|
||||
return rc;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* ulps_request() - request ulps entry for specified lanes
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
* @lanes: ORed list of lanes (enum dsi_data_lanes) which need
|
||||
* to enter ULPS.
|
||||
*
|
||||
* Caller should check if lanes are in ULPS mode by calling
|
||||
* get_lanes_in_ulps() operation.
|
||||
*/
|
||||
void dsi_ctrl_hw_cmn_ulps_request(struct dsi_ctrl_hw *ctrl, u32 lanes)
|
||||
{
|
||||
u32 reg = 0;
|
||||
|
||||
reg = DSI_R32(ctrl, DSI_LANE_CTRL);
|
||||
|
||||
if (lanes & DSI_CLOCK_LANE)
|
||||
reg |= BIT(4);
|
||||
if (lanes & DSI_DATA_LANE_0)
|
||||
reg |= BIT(0);
|
||||
if (lanes & DSI_DATA_LANE_1)
|
||||
reg |= BIT(1);
|
||||
if (lanes & DSI_DATA_LANE_2)
|
||||
reg |= BIT(2);
|
||||
if (lanes & DSI_DATA_LANE_3)
|
||||
reg |= BIT(3);
|
||||
|
||||
/*
|
||||
* ULPS entry request. Wait for short time to make sure
|
||||
* that the lanes enter ULPS. Recommended as per HPG.
|
||||
*/
|
||||
DSI_W32(ctrl, DSI_LANE_CTRL, reg);
|
||||
usleep_range(100, 110);
|
||||
|
||||
DSI_CTRL_HW_DBG(ctrl, "ULPS requested for lanes 0x%x\n", lanes);
|
||||
}
|
||||
|
||||
/**
|
||||
* ulps_exit() - exit ULPS on specified lanes
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
* @lanes: ORed list of lanes (enum dsi_data_lanes) which need
|
||||
* to exit ULPS.
|
||||
*
|
||||
* Caller should check if lanes are in active mode by calling
|
||||
* get_lanes_in_ulps() operation.
|
||||
*/
|
||||
void dsi_ctrl_hw_cmn_ulps_exit(struct dsi_ctrl_hw *ctrl, u32 lanes)
|
||||
{
|
||||
u32 reg = 0;
|
||||
u32 prev_reg = 0;
|
||||
|
||||
prev_reg = DSI_R32(ctrl, DSI_LANE_CTRL);
|
||||
prev_reg &= BIT(24);
|
||||
|
||||
if (lanes & DSI_CLOCK_LANE)
|
||||
reg |= BIT(12);
|
||||
if (lanes & DSI_DATA_LANE_0)
|
||||
reg |= BIT(8);
|
||||
if (lanes & DSI_DATA_LANE_1)
|
||||
reg |= BIT(9);
|
||||
if (lanes & DSI_DATA_LANE_2)
|
||||
reg |= BIT(10);
|
||||
if (lanes & DSI_DATA_LANE_3)
|
||||
reg |= BIT(11);
|
||||
|
||||
/*
|
||||
* ULPS Exit Request
|
||||
* Hardware requirement is to wait for at least 1ms
|
||||
*/
|
||||
DSI_W32(ctrl, DSI_LANE_CTRL, reg | prev_reg);
|
||||
usleep_range(1000, 1010);
|
||||
/*
|
||||
* Sometimes when exiting ULPS, it is possible that some DSI
|
||||
* lanes are not in the stop state which could lead to DSI
|
||||
* commands not going through. To avoid this, force the lanes
|
||||
* to be in stop state.
|
||||
*/
|
||||
DSI_W32(ctrl, DSI_LANE_CTRL, (reg << 8) | prev_reg);
|
||||
wmb(); /* ensure lanes are put to stop state */
|
||||
DSI_W32(ctrl, DSI_LANE_CTRL, 0x0 | prev_reg);
|
||||
wmb(); /* ensure lanes are put to stop state */
|
||||
|
||||
DSI_CTRL_HW_DBG(ctrl, "ULPS exit request for lanes=0x%x\n", lanes);
|
||||
}
|
||||
|
||||
/**
|
||||
* get_lanes_in_ulps() - returns the list of lanes in ULPS mode
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
*
|
||||
* Returns an ORed list of lanes (enum dsi_data_lanes) that are in ULPS
|
||||
* state. If 0 is returned, all the lanes are active.
|
||||
*
|
||||
* Return: List of lanes in ULPS state.
|
||||
*/
|
||||
u32 dsi_ctrl_hw_cmn_get_lanes_in_ulps(struct dsi_ctrl_hw *ctrl)
|
||||
{
|
||||
u32 reg = 0;
|
||||
u32 lanes = 0;
|
||||
|
||||
reg = DSI_R32(ctrl, DSI_LANE_STATUS);
|
||||
if (!(reg & BIT(8)))
|
||||
lanes |= DSI_DATA_LANE_0;
|
||||
if (!(reg & BIT(9)))
|
||||
lanes |= DSI_DATA_LANE_1;
|
||||
if (!(reg & BIT(10)))
|
||||
lanes |= DSI_DATA_LANE_2;
|
||||
if (!(reg & BIT(11)))
|
||||
lanes |= DSI_DATA_LANE_3;
|
||||
if (!(reg & BIT(12)))
|
||||
lanes |= DSI_CLOCK_LANE;
|
||||
|
||||
DSI_CTRL_HW_DBG(ctrl, "lanes in ulps = 0x%x\n", lanes);
|
||||
return lanes;
|
||||
}
|
||||
|
||||
/**
|
||||
* clamp_enable() - enable DSI clamps to keep PHY driving a stable link
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
* @lanes: ORed list of lanes which need to be clamped.
|
||||
* @enable_ulps: Boolean to specify if ULPS is enabled in DSI controller
|
||||
*/
|
||||
void dsi_ctrl_hw_14_clamp_enable(struct dsi_ctrl_hw *ctrl,
|
||||
u32 lanes,
|
||||
bool enable_ulps)
|
||||
{
|
||||
u32 clamp_reg = 0;
|
||||
u32 bit_shift = 0;
|
||||
u32 reg = 0;
|
||||
|
||||
if (ctrl->index == 1)
|
||||
bit_shift = 16;
|
||||
|
||||
if (lanes & DSI_CLOCK_LANE) {
|
||||
clamp_reg |= BIT(9);
|
||||
if (enable_ulps)
|
||||
clamp_reg |= BIT(8);
|
||||
}
|
||||
|
||||
if (lanes & DSI_DATA_LANE_0) {
|
||||
clamp_reg |= BIT(7);
|
||||
if (enable_ulps)
|
||||
clamp_reg |= BIT(6);
|
||||
}
|
||||
|
||||
if (lanes & DSI_DATA_LANE_1) {
|
||||
clamp_reg |= BIT(5);
|
||||
if (enable_ulps)
|
||||
clamp_reg |= BIT(4);
|
||||
}
|
||||
|
||||
if (lanes & DSI_DATA_LANE_2) {
|
||||
clamp_reg |= BIT(3);
|
||||
if (enable_ulps)
|
||||
clamp_reg |= BIT(2);
|
||||
}
|
||||
|
||||
if (lanes & DSI_DATA_LANE_3) {
|
||||
clamp_reg |= BIT(1);
|
||||
if (enable_ulps)
|
||||
clamp_reg |= BIT(0);
|
||||
}
|
||||
|
||||
reg = DSI_MMSS_MISC_R32(ctrl, MMSS_MISC_CLAMP_REG_OFF);
|
||||
reg |= (clamp_reg << bit_shift);
|
||||
DSI_MMSS_MISC_W32(ctrl, MMSS_MISC_CLAMP_REG_OFF, reg);
|
||||
|
||||
reg = DSI_MMSS_MISC_R32(ctrl, MMSS_MISC_CLAMP_REG_OFF);
|
||||
reg |= (BIT(15) << bit_shift); /* Enable clamp */
|
||||
DSI_MMSS_MISC_W32(ctrl, MMSS_MISC_CLAMP_REG_OFF, reg);
|
||||
|
||||
DSI_CTRL_HW_DBG(ctrl, "Clamps enabled for lanes=0x%x\n", lanes);
|
||||
}
|
||||
|
||||
/**
|
||||
* clamp_disable() - disable DSI clamps
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
* @lanes: ORed list of lanes which need to have clamps released.
|
||||
* @disable_ulps: Boolean to specify if ULPS is enabled in DSI controller
|
||||
*/
|
||||
void dsi_ctrl_hw_14_clamp_disable(struct dsi_ctrl_hw *ctrl,
|
||||
u32 lanes,
|
||||
bool disable_ulps)
|
||||
{
|
||||
u32 clamp_reg = 0;
|
||||
u32 bit_shift = 0;
|
||||
u32 reg = 0;
|
||||
|
||||
if (ctrl->index == 1)
|
||||
bit_shift = 16;
|
||||
|
||||
if (lanes & DSI_CLOCK_LANE) {
|
||||
clamp_reg |= BIT(9);
|
||||
if (disable_ulps)
|
||||
clamp_reg |= BIT(8);
|
||||
}
|
||||
|
||||
if (lanes & DSI_DATA_LANE_0) {
|
||||
clamp_reg |= BIT(7);
|
||||
if (disable_ulps)
|
||||
clamp_reg |= BIT(6);
|
||||
}
|
||||
|
||||
if (lanes & DSI_DATA_LANE_1) {
|
||||
clamp_reg |= BIT(5);
|
||||
if (disable_ulps)
|
||||
clamp_reg |= BIT(4);
|
||||
}
|
||||
|
||||
if (lanes & DSI_DATA_LANE_2) {
|
||||
clamp_reg |= BIT(3);
|
||||
if (disable_ulps)
|
||||
clamp_reg |= BIT(2);
|
||||
}
|
||||
|
||||
if (lanes & DSI_DATA_LANE_3) {
|
||||
clamp_reg |= BIT(1);
|
||||
if (disable_ulps)
|
||||
clamp_reg |= BIT(0);
|
||||
}
|
||||
|
||||
clamp_reg |= BIT(15); /* Enable clamp */
|
||||
clamp_reg <<= bit_shift;
|
||||
|
||||
reg = DSI_MMSS_MISC_R32(ctrl, MMSS_MISC_CLAMP_REG_OFF);
|
||||
reg &= ~(clamp_reg);
|
||||
DSI_MMSS_MISC_W32(ctrl, MMSS_MISC_CLAMP_REG_OFF, reg);
|
||||
|
||||
DSI_CTRL_HW_DBG(ctrl, "Disable clamps for lanes=%d\n", lanes);
|
||||
}
|
||||
|
||||
#define DUMP_REG_VALUE(off) "\t%-30s: 0x%08x\n", #off, DSI_R32(ctrl, off)
|
||||
ssize_t dsi_ctrl_hw_14_reg_dump_to_buffer(struct dsi_ctrl_hw *ctrl,
|
||||
char *buf,
|
||||
u32 size)
|
||||
{
|
||||
u32 len = 0;
|
||||
|
||||
len += snprintf((buf + len), (size - len), "CONFIGURATION REGS:\n");
|
||||
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_HW_VERSION));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_STATUS));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_FIFO_STATUS));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_VIDEO_MODE_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_VIDEO_MODE_SYNC_DATATYPE));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_VIDEO_MODE_PIXEL_DATATYPE));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_VIDEO_MODE_BLANKING_DATATYPE));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_VIDEO_MODE_DATA_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_VIDEO_MODE_ACTIVE_H));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_VIDEO_MODE_ACTIVE_V));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_VIDEO_MODE_TOTAL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_VIDEO_MODE_HSYNC));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_VIDEO_MODE_VSYNC));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_VIDEO_MODE_VSYNC_VPOS));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_COMMAND_MODE_DMA_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_COMMAND_MODE_MDP_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_COMMAND_MODE_MDP_DCS_CMD_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_DMA_CMD_OFFSET));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_DMA_CMD_LENGTH));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_DMA_FIFO_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_DMA_NULL_PACKET_DATA));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_COMMAND_MODE_MDP_STREAM0_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_COMMAND_MODE_MDP_STREAM0_TOTAL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_COMMAND_MODE_MDP_STREAM1_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_COMMAND_MODE_MDP_STREAM1_TOTAL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_ACK_ERR_STATUS));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_RDBK_DATA0));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_RDBK_DATA1));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_RDBK_DATA2));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_RDBK_DATA3));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_RDBK_DATATYPE0));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_RDBK_DATATYPE1));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_TRIG_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_EXT_MUX));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_EXT_MUX_TE_PULSE_DETECT_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_CMD_MODE_DMA_SW_TRIGGER));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_CMD_MODE_MDP_SW_TRIGGER));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_CMD_MODE_BTA_SW_TRIGGER));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_RESET_SW_TRIGGER));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_LANE_STATUS));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_LANE_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_LANE_SWAP_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_DLN0_PHY_ERR));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_LP_TIMER_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_HS_TIMER_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_TIMEOUT_STATUS));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_CLKOUT_TIMING_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_EOT_PACKET));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_EOT_PACKET_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_GENERIC_ESC_TX_TRIGGER));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_ERR_INT_MASK0));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_INT_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_SOFT_RESET));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_CLK_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_CLK_STATUS));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_PHY_SW_RESET));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_AXI2AHB_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_COMMAND_MODE_MDP_CTRL2));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_COMMAND_MODE_MDP_STREAM2_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_COMMAND_MODE_MDP_STREAM2_TOTAL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_VBIF_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_AES_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_RDBK_DATA_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_TEST_PATTERN_GEN_CMD_DMA_INIT_VAL2));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_TPG_DMA_FIFO_STATUS));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_TPG_DMA_FIFO_WRITE_TRIGGER));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_DSI_TIMING_FLUSH));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_DSI_TIMING_DB_MODE));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_TPG_DMA_FIFO_RESET));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_VERSION));
|
||||
|
||||
DSI_CTRL_HW_ERR(ctrl, "LLENGTH = %d\n", len);
|
||||
return len;
|
||||
}
|
224
techpack/display/msm/dsi/dsi_ctrl_hw_2_0.c
Normal file
224
techpack/display/msm/dsi/dsi_ctrl_hw_2_0.c
Normal file
@ -0,0 +1,224 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/iopoll.h>
|
||||
|
||||
#include "dsi_ctrl_hw.h"
|
||||
#include "dsi_ctrl_reg.h"
|
||||
#include "dsi_hw.h"
|
||||
|
||||
void dsi_ctrl_hw_20_setup_lane_map(struct dsi_ctrl_hw *ctrl,
|
||||
struct dsi_lane_map *lane_map)
|
||||
{
|
||||
u32 reg_value = lane_map->lane_map_v2[DSI_LOGICAL_LANE_0] |
|
||||
(lane_map->lane_map_v2[DSI_LOGICAL_LANE_1] << 4) |
|
||||
(lane_map->lane_map_v2[DSI_LOGICAL_LANE_2] << 8) |
|
||||
(lane_map->lane_map_v2[DSI_LOGICAL_LANE_3] << 12);
|
||||
|
||||
DSI_W32(ctrl, DSI_LANE_SWAP_CTRL, reg_value);
|
||||
|
||||
DSI_CTRL_HW_DBG(ctrl, "Lane swap setup complete\n");
|
||||
}
|
||||
|
||||
int dsi_ctrl_hw_20_wait_for_lane_idle(struct dsi_ctrl_hw *ctrl,
|
||||
u32 lanes)
|
||||
{
|
||||
int rc = 0, val = 0;
|
||||
u32 fifo_empty_mask = 0;
|
||||
u32 const sleep_us = 10;
|
||||
u32 const timeout_us = 100;
|
||||
|
||||
if (lanes & DSI_DATA_LANE_0)
|
||||
fifo_empty_mask |= (BIT(12) | BIT(16));
|
||||
|
||||
if (lanes & DSI_DATA_LANE_1)
|
||||
fifo_empty_mask |= BIT(20);
|
||||
|
||||
if (lanes & DSI_DATA_LANE_2)
|
||||
fifo_empty_mask |= BIT(24);
|
||||
|
||||
if (lanes & DSI_DATA_LANE_3)
|
||||
fifo_empty_mask |= BIT(28);
|
||||
|
||||
DSI_CTRL_HW_DBG(ctrl, "polling for fifo empty, mask=0x%08x\n",
|
||||
fifo_empty_mask);
|
||||
rc = readl_poll_timeout(ctrl->base + DSI_FIFO_STATUS, val,
|
||||
(val & fifo_empty_mask), sleep_us, timeout_us);
|
||||
if (rc) {
|
||||
DSI_CTRL_HW_ERR(ctrl, "fifo not empty, FIFO_STATUS=0x%08x\n",
|
||||
val);
|
||||
goto error;
|
||||
}
|
||||
|
||||
error:
|
||||
return rc;
|
||||
}
|
||||
|
||||
#define DUMP_REG_VALUE(off) "\t%-30s: 0x%08x\n", #off, DSI_R32(ctrl, off)
|
||||
ssize_t dsi_ctrl_hw_20_reg_dump_to_buffer(struct dsi_ctrl_hw *ctrl,
|
||||
char *buf,
|
||||
u32 size)
|
||||
{
|
||||
u32 len = 0;
|
||||
|
||||
len += snprintf((buf + len), (size - len), "CONFIGURATION REGS:\n");
|
||||
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_HW_VERSION));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_STATUS));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_FIFO_STATUS));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_VIDEO_MODE_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_VIDEO_MODE_SYNC_DATATYPE));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_VIDEO_MODE_PIXEL_DATATYPE));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_VIDEO_MODE_BLANKING_DATATYPE));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_VIDEO_MODE_DATA_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_VIDEO_MODE_ACTIVE_H));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_VIDEO_MODE_ACTIVE_V));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_VIDEO_MODE_TOTAL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_VIDEO_MODE_HSYNC));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_VIDEO_MODE_VSYNC));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_VIDEO_MODE_VSYNC_VPOS));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_COMMAND_MODE_DMA_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_COMMAND_MODE_MDP_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_COMMAND_MODE_MDP_DCS_CMD_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_DMA_CMD_OFFSET));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_DMA_CMD_LENGTH));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_DMA_FIFO_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_DMA_NULL_PACKET_DATA));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_COMMAND_MODE_MDP_STREAM0_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_COMMAND_MODE_MDP_STREAM0_TOTAL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_COMMAND_MODE_MDP_STREAM1_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_COMMAND_MODE_MDP_STREAM1_TOTAL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_ACK_ERR_STATUS));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_RDBK_DATA0));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_RDBK_DATA1));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_RDBK_DATA2));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_RDBK_DATA3));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_RDBK_DATATYPE0));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_RDBK_DATATYPE1));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_TRIG_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_EXT_MUX));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_EXT_MUX_TE_PULSE_DETECT_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_CMD_MODE_DMA_SW_TRIGGER));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_CMD_MODE_MDP_SW_TRIGGER));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_CMD_MODE_BTA_SW_TRIGGER));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_RESET_SW_TRIGGER));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_MISR_CMD_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_MISR_VIDEO_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_LANE_STATUS));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_LANE_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_LANE_SWAP_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_DLN0_PHY_ERR));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_LP_TIMER_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_HS_TIMER_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_TIMEOUT_STATUS));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_CLKOUT_TIMING_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_EOT_PACKET));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_EOT_PACKET_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_GENERIC_ESC_TX_TRIGGER));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_ERR_INT_MASK0));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_INT_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_SOFT_RESET));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_CLK_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_CLK_STATUS));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_PHY_SW_RESET));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_AXI2AHB_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_MISR_CMD_MDP0_32BIT));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_MISR_CMD_MDP1_32BIT));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_MISR_VIDEO_32BIT));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_COMMAND_MODE_MDP_CTRL2));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_COMMAND_MODE_MDP_STREAM2_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_COMMAND_MODE_MDP_STREAM2_TOTAL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_VBIF_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_AES_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_RDBK_DATA_CTRL));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_TEST_PATTERN_GEN_CMD_DMA_INIT_VAL2));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_TPG_DMA_FIFO_STATUS));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_TPG_DMA_FIFO_WRITE_TRIGGER));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_DSI_TIMING_FLUSH));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_DSI_TIMING_DB_MODE));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_TPG_DMA_FIFO_RESET));
|
||||
len += snprintf((buf + len), (size - len),
|
||||
DUMP_REG_VALUE(DSI_VERSION));
|
||||
|
||||
DSI_CTRL_HW_ERR(ctrl, "LLENGTH = %d\n", len);
|
||||
return len;
|
||||
}
|
282
techpack/display/msm/dsi/dsi_ctrl_hw_2_2.c
Normal file
282
techpack/display/msm/dsi/dsi_ctrl_hw_2_2.c
Normal file
@ -0,0 +1,282 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
#include <linux/iopoll.h>
|
||||
#include "dsi_ctrl_hw.h"
|
||||
#include "dsi_ctrl_reg.h"
|
||||
#include "dsi_hw.h"
|
||||
#include "dsi_catalog.h"
|
||||
|
||||
#define DISP_CC_MISC_CMD_REG_OFF 0x00
|
||||
|
||||
/* register to configure DMA scheduling */
|
||||
#define DSI_DMA_SCHEDULE_CTRL 0x100
|
||||
#define DSI_DMA_SCHEDULE_CTRL2 0x0104
|
||||
|
||||
/* offset addresses of MDP INTF base register, to be mapped for debug feature */
|
||||
#define MDP_INTF_TEAR_OFFSET 0x280
|
||||
#define MDP_INTF_TEAR_LINE_COUNT_OFFSET 0x30
|
||||
#define MDP_INTF_LINE_COUNT_OFFSET 0xB0
|
||||
|
||||
void dsi_ctrl_hw_22_setup_lane_map(struct dsi_ctrl_hw *ctrl,
|
||||
struct dsi_lane_map *lane_map)
|
||||
{
|
||||
u32 reg_value = lane_map->lane_map_v2[DSI_LOGICAL_LANE_0] |
|
||||
(lane_map->lane_map_v2[DSI_LOGICAL_LANE_1] << 4) |
|
||||
(lane_map->lane_map_v2[DSI_LOGICAL_LANE_2] << 8) |
|
||||
(lane_map->lane_map_v2[DSI_LOGICAL_LANE_3] << 12);
|
||||
|
||||
DSI_W32(ctrl, DSI_LANE_SWAP_CTRL, reg_value);
|
||||
|
||||
DSI_CTRL_HW_DBG(ctrl, "[DSI_%d] Lane swap setup complete\n",
|
||||
ctrl->index);
|
||||
}
|
||||
|
||||
int dsi_ctrl_hw_22_wait_for_lane_idle(struct dsi_ctrl_hw *ctrl,
|
||||
u32 lanes)
|
||||
{
|
||||
int rc = 0, val = 0;
|
||||
u32 fifo_empty_mask = 0;
|
||||
u32 const sleep_us = 10;
|
||||
u32 const timeout_us = 100;
|
||||
|
||||
if (lanes & DSI_DATA_LANE_0)
|
||||
fifo_empty_mask |= (BIT(12) | BIT(16));
|
||||
|
||||
if (lanes & DSI_DATA_LANE_1)
|
||||
fifo_empty_mask |= BIT(20);
|
||||
|
||||
if (lanes & DSI_DATA_LANE_2)
|
||||
fifo_empty_mask |= BIT(24);
|
||||
|
||||
if (lanes & DSI_DATA_LANE_3)
|
||||
fifo_empty_mask |= BIT(28);
|
||||
|
||||
DSI_CTRL_HW_DBG(ctrl, "%s: polling for fifo empty, mask=0x%08x\n",
|
||||
__func__, fifo_empty_mask);
|
||||
rc = readl_poll_timeout(ctrl->base + DSI_FIFO_STATUS, val,
|
||||
(val & fifo_empty_mask), sleep_us, timeout_us);
|
||||
if (rc) {
|
||||
DSI_CTRL_HW_ERR(ctrl,
|
||||
"%s: fifo not empty, FIFO_STATUS=0x%08x\n",
|
||||
__func__, val);
|
||||
goto error;
|
||||
}
|
||||
error:
|
||||
return rc;
|
||||
}
|
||||
|
||||
ssize_t dsi_ctrl_hw_22_reg_dump_to_buffer(struct dsi_ctrl_hw *ctrl,
|
||||
char *buf,
|
||||
u32 size)
|
||||
{
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* dsi_ctrl_hw_22_phy_reset_config() - to configure clamp control during ulps
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
* @enable: boolean to specify enable/disable.
|
||||
*/
|
||||
void dsi_ctrl_hw_22_phy_reset_config(struct dsi_ctrl_hw *ctrl,
|
||||
bool enable)
|
||||
{
|
||||
u32 reg = 0;
|
||||
|
||||
reg = DSI_DISP_CC_R32(ctrl, DISP_CC_MISC_CMD_REG_OFF);
|
||||
|
||||
/* Mask/unmask disable PHY reset bit */
|
||||
if (enable)
|
||||
reg &= ~BIT(ctrl->index);
|
||||
else
|
||||
reg |= BIT(ctrl->index);
|
||||
DSI_DISP_CC_W32(ctrl, DISP_CC_MISC_CMD_REG_OFF, reg);
|
||||
}
|
||||
|
||||
/**
|
||||
* dsi_ctrl_hw_22_schedule_dma_cmd() - to schedule DMA command transfer
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
* @line_no: Line number at which command needs to be sent.
|
||||
*/
|
||||
void dsi_ctrl_hw_22_schedule_dma_cmd(struct dsi_ctrl_hw *ctrl, int line_no)
|
||||
{
|
||||
u32 reg = 0;
|
||||
|
||||
reg = DSI_R32(ctrl, DSI_DMA_SCHEDULE_CTRL);
|
||||
reg |= BIT(28);
|
||||
reg |= (line_no & 0xffff);
|
||||
|
||||
DSI_W32(ctrl, DSI_DMA_SCHEDULE_CTRL, reg);
|
||||
ctrl->reset_trig_ctrl = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* dsi_ctrl_hw_kickoff_non_embedded_mode()-Kickoff cmd in non-embedded mode
|
||||
* @ctrl: - Pointer to the controller host hardware.
|
||||
* @dsi_ctrl_cmd_dma_info: - command buffer information.
|
||||
* @flags: - DSI CTRL Flags.
|
||||
*/
|
||||
void dsi_ctrl_hw_kickoff_non_embedded_mode(struct dsi_ctrl_hw *ctrl,
|
||||
struct dsi_ctrl_cmd_dma_info *cmd,
|
||||
u32 flags)
|
||||
{
|
||||
u32 reg = 0;
|
||||
|
||||
reg = DSI_R32(ctrl, DSI_COMMAND_MODE_DMA_CTRL);
|
||||
|
||||
reg &= ~BIT(31);/* disable broadcast */
|
||||
reg &= ~BIT(30);
|
||||
|
||||
if (cmd->use_lpm)
|
||||
reg |= BIT(26);
|
||||
else
|
||||
reg &= ~BIT(26);
|
||||
|
||||
/* Select non EMBEDDED_MODE, pick the packet header from register */
|
||||
reg &= ~BIT(28);
|
||||
reg |= BIT(24);/* long packet */
|
||||
reg |= BIT(29);/* wc_sel = 1 */
|
||||
reg |= (((cmd->datatype) & 0x03f) << 16);/* data type */
|
||||
DSI_W32(ctrl, DSI_COMMAND_MODE_DMA_CTRL, reg);
|
||||
|
||||
/* Enable WRITE_WATERMARK_DISABLE and READ_WATERMARK_DISABLE bits */
|
||||
reg = DSI_R32(ctrl, DSI_DMA_FIFO_CTRL);
|
||||
reg |= BIT(20);
|
||||
reg |= BIT(16);
|
||||
reg |= 0x33;/* Set READ and WRITE watermark levels to maximum */
|
||||
DSI_W32(ctrl, DSI_DMA_FIFO_CTRL, reg);
|
||||
|
||||
DSI_W32(ctrl, DSI_DMA_CMD_OFFSET, cmd->offset);
|
||||
DSI_W32(ctrl, DSI_DMA_CMD_LENGTH, ((cmd->length) & 0xFFFFFF));
|
||||
|
||||
/* wait for writes to complete before kick off */
|
||||
wmb();
|
||||
|
||||
if (!(flags & DSI_CTRL_HW_CMD_WAIT_FOR_TRIGGER))
|
||||
DSI_W32(ctrl, DSI_CMD_MODE_DMA_SW_TRIGGER, 0x1);
|
||||
}
|
||||
|
||||
/*
|
||||
* dsi_ctrl_hw_22_config_clk_gating() - enable/disable clk gating on DSI PHY
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
* @enable: bool to notify enable/disable.
|
||||
* @clk_selection: clock to enable/disable clock gating.
|
||||
*
|
||||
*/
|
||||
void dsi_ctrl_hw_22_config_clk_gating(struct dsi_ctrl_hw *ctrl, bool enable,
|
||||
enum dsi_clk_gate_type clk_selection)
|
||||
{
|
||||
u32 reg = 0;
|
||||
u32 enable_select = 0;
|
||||
|
||||
reg = DSI_DISP_CC_R32(ctrl, DISP_CC_MISC_CMD_REG_OFF);
|
||||
|
||||
if (clk_selection & PIXEL_CLK)
|
||||
enable_select |= ctrl->index ? BIT(6) : BIT(5);
|
||||
|
||||
if (clk_selection & BYTE_CLK)
|
||||
enable_select |= ctrl->index ? BIT(8) : BIT(7);
|
||||
|
||||
if (clk_selection & DSI_PHY)
|
||||
enable_select |= ctrl->index ? BIT(10) : BIT(9);
|
||||
|
||||
if (enable)
|
||||
reg |= enable_select;
|
||||
else
|
||||
reg &= ~enable_select;
|
||||
|
||||
DSI_DISP_CC_W32(ctrl, DISP_CC_MISC_CMD_REG_OFF, reg);
|
||||
}
|
||||
|
||||
/**
|
||||
* dsi_ctrl_hw_22_configure_cmddma_window() - configure DMA window for CMD TX
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
* @cmd: Pointer to the DSI DMA command info.
|
||||
* @line_no: Line number at which the CMD needs to be triggered.
|
||||
* @window: Width of the DMA CMD window.
|
||||
*/
|
||||
void dsi_ctrl_hw_22_configure_cmddma_window(struct dsi_ctrl_hw *ctrl,
|
||||
struct dsi_ctrl_cmd_dma_info *cmd,
|
||||
u32 line_no, u32 window)
|
||||
{
|
||||
u32 reg = 0;
|
||||
|
||||
if (cmd->en_broadcast) {
|
||||
reg = DSI_R32(ctrl, DSI_TRIG_CTRL);
|
||||
if (cmd->is_master) {
|
||||
reg &= ~0xF;
|
||||
reg |= 0xc;
|
||||
} else {
|
||||
reg &= ~0xF;
|
||||
reg |= BIT(16);
|
||||
}
|
||||
|
||||
DSI_W32(ctrl, DSI_TRIG_CTRL, reg);
|
||||
|
||||
if (cmd->is_master) {
|
||||
reg = 0;
|
||||
reg |= line_no;
|
||||
reg |= window << 16;
|
||||
DSI_W32(ctrl, DSI_DMA_SCHEDULE_CTRL2, reg);
|
||||
}
|
||||
} else {
|
||||
reg = DSI_R32(ctrl, DSI_TRIG_CTRL);
|
||||
reg &= ~0xF;
|
||||
reg |= 0xc;
|
||||
DSI_W32(ctrl, DSI_TRIG_CTRL, reg);
|
||||
|
||||
reg = 0;
|
||||
reg |= line_no;
|
||||
reg |= window << 16;
|
||||
DSI_W32(ctrl, DSI_DMA_SCHEDULE_CTRL2, reg);
|
||||
}
|
||||
ctrl->reset_trig_ctrl = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* dsi_ctrl_hw_22_reset_trigger_controls() - reset dsi trigger configurations
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
* @cfg: DSI host configuration that is common to both video and
|
||||
* command modes.
|
||||
*/
|
||||
void dsi_ctrl_hw_22_reset_trigger_controls(struct dsi_ctrl_hw *ctrl,
|
||||
struct dsi_host_common_cfg *cfg)
|
||||
{
|
||||
u32 reg = 0;
|
||||
const u8 trigger_map[DSI_TRIGGER_MAX] = {
|
||||
0x0, 0x2, 0x1, 0x4, 0x5, 0x6 };
|
||||
|
||||
reg |= (cfg->te_mode == DSI_TE_ON_EXT_PIN) ? BIT(31) : 0;
|
||||
reg |= (trigger_map[cfg->dma_cmd_trigger] & 0x7);
|
||||
reg |= (trigger_map[cfg->mdp_cmd_trigger] & 0x7) << 4;
|
||||
DSI_W32(ctrl, DSI_TRIG_CTRL, reg);
|
||||
DSI_W32(ctrl, DSI_DMA_SCHEDULE_CTRL2, 0x0);
|
||||
DSI_W32(ctrl, DSI_DMA_SCHEDULE_CTRL, 0x0);
|
||||
ctrl->reset_trig_ctrl = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* dsi_ctrl_hw_22_log_line_count() - reads the MDP interface line count
|
||||
* registers.
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
* @cmd_mode: Boolean to indicate command mode operation.
|
||||
*
|
||||
* Return: INTF register value.
|
||||
*/
|
||||
u32 dsi_ctrl_hw_22_log_line_count(struct dsi_ctrl_hw *ctrl, bool cmd_mode)
|
||||
{
|
||||
|
||||
u32 reg = 0;
|
||||
|
||||
if (IS_ERR_OR_NULL(ctrl->mdp_intf_base))
|
||||
return reg;
|
||||
|
||||
if (cmd_mode)
|
||||
reg = readl_relaxed(ctrl->mdp_intf_base + MDP_INTF_TEAR_OFFSET
|
||||
+ MDP_INTF_TEAR_LINE_COUNT_OFFSET);
|
||||
else
|
||||
reg = readl_relaxed(ctrl->mdp_intf_base
|
||||
+ MDP_INTF_LINE_COUNT_OFFSET);
|
||||
return reg;
|
||||
}
|
1740
techpack/display/msm/dsi/dsi_ctrl_hw_cmn.c
Normal file
1740
techpack/display/msm/dsi/dsi_ctrl_hw_cmn.c
Normal file
File diff suppressed because it is too large
Load Diff
152
techpack/display/msm/dsi/dsi_ctrl_reg.h
Normal file
152
techpack/display/msm/dsi/dsi_ctrl_reg.h
Normal file
@ -0,0 +1,152 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _DSI_CTRL_REG_H_
|
||||
#define _DSI_CTRL_REG_H_
|
||||
|
||||
#define DSI_HW_VERSION (0x0000)
|
||||
#define DSI_CTRL (0x0004)
|
||||
#define DSI_STATUS (0x0008)
|
||||
#define DSI_FIFO_STATUS (0x000C)
|
||||
#define DSI_VIDEO_MODE_CTRL (0x0010)
|
||||
#define DSI_VIDEO_MODE_SYNC_DATATYPE (0x0014)
|
||||
#define DSI_VIDEO_MODE_PIXEL_DATATYPE (0x0018)
|
||||
#define DSI_VIDEO_MODE_BLANKING_DATATYPE (0x001C)
|
||||
#define DSI_VIDEO_MODE_DATA_CTRL (0x0020)
|
||||
#define DSI_VIDEO_MODE_ACTIVE_H (0x0024)
|
||||
#define DSI_VIDEO_MODE_ACTIVE_V (0x0028)
|
||||
#define DSI_VIDEO_MODE_TOTAL (0x002C)
|
||||
#define DSI_VIDEO_MODE_HSYNC (0x0030)
|
||||
#define DSI_VIDEO_MODE_VSYNC (0x0034)
|
||||
#define DSI_VIDEO_MODE_VSYNC_VPOS (0x0038)
|
||||
#define DSI_COMMAND_MODE_DMA_CTRL (0x003C)
|
||||
#define DSI_COMMAND_MODE_MDP_CTRL (0x0040)
|
||||
#define DSI_COMMAND_MODE_MDP_DCS_CMD_CTRL (0x0044)
|
||||
#define DSI_DMA_CMD_OFFSET (0x0048)
|
||||
#define DSI_DMA_CMD_LENGTH (0x004C)
|
||||
#define DSI_DMA_FIFO_CTRL (0x0050)
|
||||
#define DSI_DMA_NULL_PACKET_DATA (0x0054)
|
||||
#define DSI_COMMAND_MODE_MDP_STREAM0_CTRL (0x0058)
|
||||
#define DSI_COMMAND_MODE_MDP_STREAM0_TOTAL (0x005C)
|
||||
#define DSI_COMMAND_MODE_MDP_STREAM1_CTRL (0x0060)
|
||||
#define DSI_COMMAND_MODE_MDP_STREAM1_TOTAL (0x0064)
|
||||
#define DSI_ACK_ERR_STATUS (0x0068)
|
||||
#define DSI_RDBK_DATA0 (0x006C)
|
||||
#define DSI_RDBK_DATA1 (0x0070)
|
||||
#define DSI_RDBK_DATA2 (0x0074)
|
||||
#define DSI_RDBK_DATA3 (0x0078)
|
||||
#define DSI_RDBK_DATATYPE0 (0x007C)
|
||||
#define DSI_RDBK_DATATYPE1 (0x0080)
|
||||
#define DSI_TRIG_CTRL (0x0084)
|
||||
#define DSI_EXT_MUX (0x0088)
|
||||
#define DSI_EXT_MUX_TE_PULSE_DETECT_CTRL (0x008C)
|
||||
#define DSI_CMD_MODE_DMA_SW_TRIGGER (0x0090)
|
||||
#define DSI_CMD_MODE_MDP_SW_TRIGGER (0x0094)
|
||||
#define DSI_CMD_MODE_BTA_SW_TRIGGER (0x0098)
|
||||
#define DSI_RESET_SW_TRIGGER (0x009C)
|
||||
#define DSI_MISR_CMD_CTRL (0x00A0)
|
||||
#define DSI_MISR_VIDEO_CTRL (0x00A4)
|
||||
#define DSI_LANE_STATUS (0x00A8)
|
||||
#define DSI_LANE_CTRL (0x00AC)
|
||||
#define DSI_LANE_SWAP_CTRL (0x00B0)
|
||||
#define DSI_DLN0_PHY_ERR (0x00B4)
|
||||
#define DSI_LP_TIMER_CTRL (0x00B8)
|
||||
#define DSI_HS_TIMER_CTRL (0x00BC)
|
||||
#define DSI_TIMEOUT_STATUS (0x00C0)
|
||||
#define DSI_CLKOUT_TIMING_CTRL (0x00C4)
|
||||
#define DSI_EOT_PACKET (0x00C8)
|
||||
#define DSI_EOT_PACKET_CTRL (0x00CC)
|
||||
#define DSI_GENERIC_ESC_TX_TRIGGER (0x00D0)
|
||||
#define DSI_CAM_BIST_CTRL (0x00D4)
|
||||
#define DSI_CAM_BIST_FRAME_SIZE (0x00D8)
|
||||
#define DSI_CAM_BIST_BLOCK_SIZE (0x00DC)
|
||||
#define DSI_CAM_BIST_FRAME_CONFIG (0x00E0)
|
||||
#define DSI_CAM_BIST_LSFR_CTRL (0x00E4)
|
||||
#define DSI_CAM_BIST_LSFR_INIT (0x00E8)
|
||||
#define DSI_CAM_BIST_START (0x00EC)
|
||||
#define DSI_CAM_BIST_STATUS (0x00F0)
|
||||
#define DSI_ERR_INT_MASK0 (0x010C)
|
||||
#define DSI_INT_CTRL (0x0110)
|
||||
#define DSI_IOBIST_CTRL (0x0114)
|
||||
#define DSI_SOFT_RESET (0x0118)
|
||||
#define DSI_CLK_CTRL (0x011C)
|
||||
#define DSI_CLK_STATUS (0x0120)
|
||||
#define DSI_DEBUG_BUS_CTL (0x0124)
|
||||
#define DSI_DEBUG_BUS_STATUS (0x0128)
|
||||
#define DSI_PHY_SW_RESET (0x012C)
|
||||
#define DSI_AXI2AHB_CTRL (0x0130)
|
||||
#define DSI_MISR_CMD_MDP0_32BIT (0x0134)
|
||||
#define DSI_MISR_CMD_MDP1_32BIT (0x0138)
|
||||
#define DSI_MISR_CMD_DMA_32BIT (0x013C)
|
||||
#define DSI_MISR_VIDEO_32BIT (0x0140)
|
||||
#define DSI_LANE_MISR_CTRL (0x0144)
|
||||
#define DSI_LANE0_MISR (0x0148)
|
||||
#define DSI_LANE1_MISR (0x014C)
|
||||
#define DSI_LANE2_MISR (0x0150)
|
||||
#define DSI_LANE3_MISR (0x0154)
|
||||
#define DSI_TEST_PATTERN_GEN_CTRL (0x015C)
|
||||
#define DSI_TEST_PATTERN_GEN_VIDEO_POLY (0x0160)
|
||||
#define DSI_TEST_PATTERN_GEN_VIDEO_INIT_VAL (0x0164)
|
||||
#define DSI_TEST_PATTERN_GEN_CMD_MDP_STREAM0_POLY (0x0168)
|
||||
#define DSI_TEST_PATTERN_GEN_CMD_MDP_INIT_VAL0 (0x016C)
|
||||
#define DSI_TEST_PATTERN_GEN_CMD_MDP_STREAM1_POLY (0x0170)
|
||||
#define DSI_TEST_PATTERN_GEN_CMD_MDP_INIT_VAL1 (0x0174)
|
||||
#define DSI_TEST_PATTERN_GEN_CMD_DMA_POLY (0x0178)
|
||||
#define DSI_TEST_PATTERN_GEN_CMD_DMA_INIT_VAL (0x017C)
|
||||
#define DSI_TEST_PATTERN_GEN_VIDEO_ENABLE (0x0180)
|
||||
#define DSI_TEST_PATTERN_GEN_CMD_STREAM0_TRIGGER (0x0184)
|
||||
#define DSI_TEST_PATTERN_GEN_CMD_STREAM1_TRIGGER (0x0188)
|
||||
#define DSI_TEST_PATTERN_GEN_CMD_MDP_INIT_VAL2 (0x018C)
|
||||
#define DSI_TEST_PATTERN_GEN_CMD_MDP_STREAM2_POLY (0x0190)
|
||||
#define DSI_TEST_PATTERN_GEN_CMD_MDP_STREAM2_POLY (0x0190)
|
||||
#define DSI_COMMAND_MODE_MDP_IDLE_CTRL (0x0194)
|
||||
#define DSI_TEST_PATTERN_GEN_CMD_STREAM2_TRIGGER (0x0198)
|
||||
#define DSI_TPG_MAIN_CONTROL (0x019C)
|
||||
#define DSI_TPG_MAIN_CONTROL2 (0x01A0)
|
||||
#define DSI_TPG_VIDEO_CONFIG (0x01A4)
|
||||
#define DSI_TPG_COMPONENT_LIMITS (0x01A8)
|
||||
#define DSI_TPG_RECTANGLE (0x01AC)
|
||||
#define DSI_TPG_BLACK_WHITE_PATTERN_FRAMES (0x01B0)
|
||||
#define DSI_TPG_RGB_MAPPING (0x01B4)
|
||||
#define DSI_COMMAND_MODE_MDP_CTRL2 (0x01B8)
|
||||
#define DSI_COMMAND_MODE_MDP_STREAM2_CTRL (0x01BC)
|
||||
#define DSI_COMMAND_MODE_MDP_STREAM2_TOTAL (0x01C0)
|
||||
#define DSI_MISR_CMD_MDP2_8BIT (0x01C4)
|
||||
#define DSI_MISR_CMD_MDP2_32BIT (0x01C8)
|
||||
#define DSI_VBIF_CTRL (0x01CC)
|
||||
#define DSI_AES_CTRL (0x01D0)
|
||||
#define DSI_RDBK_DATA_CTRL (0x01D4)
|
||||
#define DSI_TEST_PATTERN_GEN_CMD_DMA_INIT_VAL2 (0x01D8)
|
||||
#define DSI_TPG_DMA_FIFO_STATUS (0x01DC)
|
||||
#define DSI_TPG_DMA_FIFO_WRITE_TRIGGER (0x01E0)
|
||||
#define DSI_DSI_TIMING_FLUSH (0x01E4)
|
||||
#define DSI_DSI_TIMING_DB_MODE (0x01E8)
|
||||
#define DSI_TPG_DMA_FIFO_RESET (0x01EC)
|
||||
#define DSI_SCRATCH_REGISTER_0 (0x01F0)
|
||||
#define DSI_VERSION (0x01F4)
|
||||
#define DSI_SCRATCH_REGISTER_1 (0x01F8)
|
||||
#define DSI_SCRATCH_REGISTER_2 (0x01FC)
|
||||
#define DSI_DYNAMIC_REFRESH_CTRL (0x0200)
|
||||
#define DSI_DYNAMIC_REFRESH_STATUS (0x0210)
|
||||
#define DSI_VIDEO_COMPRESSION_MODE_CTRL (0x02A0)
|
||||
#define DSI_VIDEO_COMPRESSION_MODE_CTRL2 (0x02A4)
|
||||
#define DSI_COMMAND_COMPRESSION_MODE_CTRL (0x02A8)
|
||||
#define DSI_COMMAND_COMPRESSION_MODE_CTRL2 (0x02AC)
|
||||
#define DSI_COMMAND_COMPRESSION_MODE_CTRL3 (0x02B0)
|
||||
#define DSI_COMMAND_MODE_NULL_INSERTION_CTRL (0x02B4)
|
||||
#define DSI_READ_BACK_DISABLE_STATUS (0x02B8)
|
||||
#define DSI_DESKEW_CTRL (0x02BC)
|
||||
#define DSI_DESKEW_DELAY_CTRL (0x02C0)
|
||||
#define DSI_DESKEW_SW_TRIGGER (0x02C4)
|
||||
#define DSI_DEBUG_CTRL (0x02C8)
|
||||
#define DSI_SECURE_DISPLAY_STATUS (0x02CC)
|
||||
#define DSI_SECURE_DISPLAY_BLOCK_COMMAND_COLOR (0x02D0)
|
||||
#define DSI_SECURE_DISPLAY_BLOCK_VIDEO_COLOR (0x02D4)
|
||||
#define DSI_CPHY_MODE_CTRL (0x02D8)
|
||||
#define DSI_LOGICAL_LANE_SWAP_CTRL (0x0310)
|
||||
#define DSI_SPLIT_LINK (0x0330)
|
||||
|
||||
|
||||
#endif /* _DSI_CTRL_REG_H_ */
|
770
techpack/display/msm/dsi/dsi_defs.h
Normal file
770
techpack/display/msm/dsi/dsi_defs.h
Normal file
@ -0,0 +1,770 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _DSI_DEFS_H_
|
||||
#define _DSI_DEFS_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <drm/drm_mipi_dsi.h>
|
||||
#include "msm_drv.h"
|
||||
|
||||
#define DSI_H_TOTAL(t) (((t)->h_active) + ((t)->h_back_porch) + \
|
||||
((t)->h_sync_width) + ((t)->h_front_porch))
|
||||
|
||||
#define DSI_V_TOTAL(t) (((t)->v_active) + ((t)->v_back_porch) + \
|
||||
((t)->v_sync_width) + ((t)->v_front_porch))
|
||||
|
||||
#define DSI_H_SCALE(h, s) (DIV_ROUND_UP((h) * (s)->numer, (s)->denom))
|
||||
|
||||
#define DSI_DEBUG_NAME_LEN 32
|
||||
#define display_for_each_ctrl(index, display) \
|
||||
for (index = 0; (index < (display)->ctrl_count) &&\
|
||||
(index < MAX_DSI_CTRLS_PER_DISPLAY); index++)
|
||||
|
||||
#define DSI_WARN(fmt, ...) DRM_WARN("[msm-dsi-warn]: "fmt, ##__VA_ARGS__)
|
||||
#define DSI_ERR(fmt, ...) DRM_DEV_ERROR(NULL, "[msm-dsi-error]: " fmt, \
|
||||
##__VA_ARGS__)
|
||||
#define DSI_INFO(fmt, ...) DRM_DEV_INFO(NULL, "[msm-dsi-info]: "fmt, \
|
||||
##__VA_ARGS__)
|
||||
#define DSI_DEBUG(fmt, ...) DRM_DEV_DEBUG(NULL, "[msm-dsi-debug]: "fmt, \
|
||||
##__VA_ARGS__)
|
||||
/**
|
||||
* enum dsi_pixel_format - DSI pixel formats
|
||||
* @DSI_PIXEL_FORMAT_RGB565:
|
||||
* @DSI_PIXEL_FORMAT_RGB666:
|
||||
* @DSI_PIXEL_FORMAT_RGB666_LOOSE:
|
||||
* @DSI_PIXEL_FORMAT_RGB888:
|
||||
* @DSI_PIXEL_FORMAT_RGB111:
|
||||
* @DSI_PIXEL_FORMAT_RGB332:
|
||||
* @DSI_PIXEL_FORMAT_RGB444:
|
||||
* @DSI_PIXEL_FORMAT_MAX:
|
||||
*/
|
||||
enum dsi_pixel_format {
|
||||
DSI_PIXEL_FORMAT_RGB565 = 0,
|
||||
DSI_PIXEL_FORMAT_RGB666,
|
||||
DSI_PIXEL_FORMAT_RGB666_LOOSE,
|
||||
DSI_PIXEL_FORMAT_RGB888,
|
||||
DSI_PIXEL_FORMAT_RGB111,
|
||||
DSI_PIXEL_FORMAT_RGB332,
|
||||
DSI_PIXEL_FORMAT_RGB444,
|
||||
DSI_PIXEL_FORMAT_MAX
|
||||
};
|
||||
|
||||
/**
|
||||
* enum dsi_op_mode - dsi operation mode
|
||||
* @DSI_OP_VIDEO_MODE: DSI video mode operation
|
||||
* @DSI_OP_CMD_MODE: DSI Command mode operation
|
||||
* @DSI_OP_MODE_MAX:
|
||||
*/
|
||||
enum dsi_op_mode {
|
||||
DSI_OP_VIDEO_MODE = 0,
|
||||
DSI_OP_CMD_MODE,
|
||||
DSI_OP_MODE_MAX
|
||||
};
|
||||
|
||||
/**
|
||||
* enum dsi_mode_flags - flags to signal other drm components via private flags
|
||||
* @DSI_MODE_FLAG_SEAMLESS: Seamless transition requested by user
|
||||
* @DSI_MODE_FLAG_DFPS: Seamless transition is DynamicFPS
|
||||
* @DSI_MODE_FLAG_VBLANK_PRE_MODESET: Transition needs VBLANK before Modeset
|
||||
* @DSI_MODE_FLAG_DMS: Seamless transition is dynamic mode switch
|
||||
* @DSI_MODE_FLAG_VRR: Seamless transition is DynamicFPS.
|
||||
* New timing values are sent from DAL.
|
||||
* @DSI_MODE_FLAG_POMS:
|
||||
* Seamless transition is dynamic panel operating mode switch
|
||||
* @DSI_MODE_FLAG_DYN_CLK: Seamless transition is dynamic clock change
|
||||
* @DSI_MODE_FLAG_DMS_FPS: Seamless fps only transition in Dynamic Mode Switch
|
||||
*/
|
||||
enum dsi_mode_flags {
|
||||
DSI_MODE_FLAG_SEAMLESS = BIT(0),
|
||||
DSI_MODE_FLAG_DFPS = BIT(1),
|
||||
DSI_MODE_FLAG_VBLANK_PRE_MODESET = BIT(2),
|
||||
DSI_MODE_FLAG_DMS = BIT(3),
|
||||
DSI_MODE_FLAG_VRR = BIT(4),
|
||||
DSI_MODE_FLAG_POMS = BIT(5),
|
||||
DSI_MODE_FLAG_DYN_CLK = BIT(6),
|
||||
DSI_MODE_FLAG_DMS_FPS = BIT(7),
|
||||
};
|
||||
|
||||
/**
|
||||
* enum dsi_logical_lane - dsi logical lanes
|
||||
* @DSI_LOGICAL_LANE_0: Logical lane 0
|
||||
* @DSI_LOGICAL_LANE_1: Logical lane 1
|
||||
* @DSI_LOGICAL_LANE_2: Logical lane 2
|
||||
* @DSI_LOGICAL_LANE_3: Logical lane 3
|
||||
* @DSI_LOGICAL_CLOCK_LANE: Clock lane
|
||||
* @DSI_LANE_MAX: Maximum lanes supported
|
||||
*/
|
||||
enum dsi_logical_lane {
|
||||
DSI_LOGICAL_LANE_0 = 0,
|
||||
DSI_LOGICAL_LANE_1,
|
||||
DSI_LOGICAL_LANE_2,
|
||||
DSI_LOGICAL_LANE_3,
|
||||
DSI_LOGICAL_CLOCK_LANE,
|
||||
DSI_LANE_MAX
|
||||
};
|
||||
|
||||
/**
|
||||
* enum dsi_data_lanes - BIT map for DSI data lanes
|
||||
* This is used to identify the active DSI data lanes for
|
||||
* various operations like DSI data lane enable/ULPS/clamp
|
||||
* configurations.
|
||||
* @DSI_DATA_LANE_0: BIT(DSI_LOGICAL_LANE_0)
|
||||
* @DSI_DATA_LANE_1: BIT(DSI_LOGICAL_LANE_1)
|
||||
* @DSI_DATA_LANE_2: BIT(DSI_LOGICAL_LANE_2)
|
||||
* @DSI_DATA_LANE_3: BIT(DSI_LOGICAL_LANE_3)
|
||||
* @DSI_CLOCK_LANE: BIT(DSI_LOGICAL_CLOCK_LANE)
|
||||
*/
|
||||
enum dsi_data_lanes {
|
||||
DSI_DATA_LANE_0 = BIT(DSI_LOGICAL_LANE_0),
|
||||
DSI_DATA_LANE_1 = BIT(DSI_LOGICAL_LANE_1),
|
||||
DSI_DATA_LANE_2 = BIT(DSI_LOGICAL_LANE_2),
|
||||
DSI_DATA_LANE_3 = BIT(DSI_LOGICAL_LANE_3),
|
||||
DSI_CLOCK_LANE = BIT(DSI_LOGICAL_CLOCK_LANE)
|
||||
};
|
||||
|
||||
/**
|
||||
* enum dsi_phy_data_lanes - dsi physical lanes
|
||||
* used for DSI logical to physical lane mapping
|
||||
* @DSI_PHYSICAL_LANE_INVALID: Physical lane valid/invalid
|
||||
* @DSI_PHYSICAL_LANE_0: Physical lane 0
|
||||
* @DSI_PHYSICAL_LANE_1: Physical lane 1
|
||||
* @DSI_PHYSICAL_LANE_2: Physical lane 2
|
||||
* @DSI_PHYSICAL_LANE_3: Physical lane 3
|
||||
*/
|
||||
enum dsi_phy_data_lanes {
|
||||
DSI_PHYSICAL_LANE_INVALID = 0,
|
||||
DSI_PHYSICAL_LANE_0 = BIT(0),
|
||||
DSI_PHYSICAL_LANE_1 = BIT(1),
|
||||
DSI_PHYSICAL_LANE_2 = BIT(2),
|
||||
DSI_PHYSICAL_LANE_3 = BIT(3)
|
||||
};
|
||||
|
||||
enum dsi_lane_map_type_v1 {
|
||||
DSI_LANE_MAP_0123,
|
||||
DSI_LANE_MAP_3012,
|
||||
DSI_LANE_MAP_2301,
|
||||
DSI_LANE_MAP_1230,
|
||||
DSI_LANE_MAP_0321,
|
||||
DSI_LANE_MAP_1032,
|
||||
DSI_LANE_MAP_2103,
|
||||
DSI_LANE_MAP_3210,
|
||||
};
|
||||
|
||||
/**
|
||||
* lane_map: DSI logical <-> physical lane mapping
|
||||
* lane_map_v1: Lane mapping for DSI controllers < v2.0
|
||||
* lane_map_v2: Lane mapping for DSI controllers >= 2.0
|
||||
*/
|
||||
struct dsi_lane_map {
|
||||
enum dsi_lane_map_type_v1 lane_map_v1;
|
||||
u8 lane_map_v2[DSI_LANE_MAX - 1];
|
||||
};
|
||||
|
||||
/**
|
||||
* enum dsi_trigger_type - dsi trigger type
|
||||
* @DSI_TRIGGER_NONE: No trigger.
|
||||
* @DSI_TRIGGER_TE: TE trigger.
|
||||
* @DSI_TRIGGER_SEOF: Start or End of frame.
|
||||
* @DSI_TRIGGER_SW: Software trigger.
|
||||
* @DSI_TRIGGER_SW_SEOF: Software trigger and start/end of frame.
|
||||
* @DSI_TRIGGER_SW_TE: Software and TE triggers.
|
||||
* @DSI_TRIGGER_MAX: Max trigger values.
|
||||
*/
|
||||
enum dsi_trigger_type {
|
||||
DSI_TRIGGER_NONE = 0,
|
||||
DSI_TRIGGER_TE,
|
||||
DSI_TRIGGER_SEOF,
|
||||
DSI_TRIGGER_SW,
|
||||
DSI_TRIGGER_SW_SEOF,
|
||||
DSI_TRIGGER_SW_TE,
|
||||
DSI_TRIGGER_MAX
|
||||
};
|
||||
|
||||
/**
|
||||
* enum dsi_color_swap_mode - color swap mode
|
||||
* @DSI_COLOR_SWAP_RGB:
|
||||
* @DSI_COLOR_SWAP_RBG:
|
||||
* @DSI_COLOR_SWAP_BGR:
|
||||
* @DSI_COLOR_SWAP_BRG:
|
||||
* @DSI_COLOR_SWAP_GRB:
|
||||
* @DSI_COLOR_SWAP_GBR:
|
||||
*/
|
||||
enum dsi_color_swap_mode {
|
||||
DSI_COLOR_SWAP_RGB = 0,
|
||||
DSI_COLOR_SWAP_RBG,
|
||||
DSI_COLOR_SWAP_BGR,
|
||||
DSI_COLOR_SWAP_BRG,
|
||||
DSI_COLOR_SWAP_GRB,
|
||||
DSI_COLOR_SWAP_GBR
|
||||
};
|
||||
|
||||
/**
|
||||
* enum dsi_dfps_type - Dynamic FPS support type
|
||||
* @DSI_DFPS_NONE: Dynamic FPS is not supported.
|
||||
* @DSI_DFPS_SUSPEND_RESUME:
|
||||
* @DSI_DFPS_IMMEDIATE_CLK:
|
||||
* @DSI_DFPS_IMMEDIATE_HFP:
|
||||
* @DSI_DFPS_IMMEDIATE_VFP:
|
||||
* @DSI_DPFS_MAX:
|
||||
*/
|
||||
enum dsi_dfps_type {
|
||||
DSI_DFPS_NONE = 0,
|
||||
DSI_DFPS_SUSPEND_RESUME,
|
||||
DSI_DFPS_IMMEDIATE_CLK,
|
||||
DSI_DFPS_IMMEDIATE_HFP,
|
||||
DSI_DFPS_IMMEDIATE_VFP,
|
||||
DSI_DFPS_MAX
|
||||
};
|
||||
|
||||
/**
|
||||
* enum dsi_dyn_clk_feature_type - Dynamic clock feature support type
|
||||
* @DSI_DYN_CLK_TYPE_LEGACY: Constant FPS is not supported
|
||||
* @DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_HFP: Constant FPS supported with
|
||||
* change in hfp
|
||||
* @DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_VFP: Constant FPS supported with
|
||||
* change in vfp
|
||||
* @DSI_DYN_CLK_TYPE_MAX:
|
||||
*/
|
||||
enum dsi_dyn_clk_feature_type {
|
||||
DSI_DYN_CLK_TYPE_LEGACY = 0,
|
||||
DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_HFP,
|
||||
DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_VFP,
|
||||
DSI_DYN_CLK_TYPE_MAX
|
||||
};
|
||||
|
||||
/**
|
||||
* enum dsi_cmd_set_type - DSI command set type
|
||||
* @DSI_CMD_SET_PRE_ON: Panel pre on
|
||||
* @DSI_CMD_SET_ON: Panel on
|
||||
* @DSI_CMD_SET_POST_ON: Panel post on
|
||||
* @DSI_CMD_SET_PRE_OFF: Panel pre off
|
||||
* @DSI_CMD_SET_OFF: Panel off
|
||||
* @DSI_CMD_SET_POST_OFF: Panel post off
|
||||
* @DSI_CMD_SET_PRE_RES_SWITCH: Pre resolution switch
|
||||
* @DSI_CMD_SET_RES_SWITCH: Resolution switch
|
||||
* @DSI_CMD_SET_POST_RES_SWITCH: Post resolution switch
|
||||
* @DSI_CMD_SET_CMD_TO_VID_SWITCH: Cmd to video mode switch
|
||||
* @DSI_CMD_SET_POST_CMD_TO_VID_SWITCH: Post cmd to vid switch
|
||||
* @DSI_CMD_SET_VID_TO_CMD_SWITCH: Video to cmd mode switch
|
||||
* @DSI_CMD_SET_POST_VID_TO_CMD_SWITCH: Post vid to cmd switch
|
||||
* @DSI_CMD_SET_PANEL_STATUS: Panel status
|
||||
* @DSI_CMD_SET_LP1: Low power mode 1
|
||||
* @DSI_CMD_SET_LP2: Low power mode 2
|
||||
* @DSI_CMD_SET_NOLP: Low power mode disable
|
||||
* @DSI_CMD_SET_PPS: DSC PPS command
|
||||
* @DSI_CMD_SET_ROI: Panel ROI update
|
||||
* @DSI_CMD_SET_TIMING_SWITCH: Timing switch
|
||||
* @DSI_CMD_SET_POST_TIMING_SWITCH: Post timing switch
|
||||
* @DSI_CMD_SET_QSYNC_ON Enable qsync mode
|
||||
* @DSI_CMD_SET_QSYNC_OFF Disable qsync mode
|
||||
* @DSI_CMD_SET_MAX
|
||||
*/
|
||||
enum dsi_cmd_set_type {
|
||||
DSI_CMD_SET_PRE_ON = 0,
|
||||
DSI_CMD_SET_ON,
|
||||
DSI_CMD_SET_POST_ON,
|
||||
DSI_CMD_SET_PRE_OFF,
|
||||
DSI_CMD_SET_OFF,
|
||||
DSI_CMD_SET_POST_OFF,
|
||||
DSI_CMD_SET_PRE_RES_SWITCH,
|
||||
DSI_CMD_SET_RES_SWITCH,
|
||||
DSI_CMD_SET_POST_RES_SWITCH,
|
||||
DSI_CMD_SET_CMD_TO_VID_SWITCH,
|
||||
DSI_CMD_SET_POST_CMD_TO_VID_SWITCH,
|
||||
DSI_CMD_SET_VID_TO_CMD_SWITCH,
|
||||
DSI_CMD_SET_POST_VID_TO_CMD_SWITCH,
|
||||
DSI_CMD_SET_PANEL_STATUS,
|
||||
DSI_CMD_SET_LP1,
|
||||
DSI_CMD_SET_LP2,
|
||||
DSI_CMD_SET_NOLP,
|
||||
DSI_CMD_SET_PPS,
|
||||
DSI_CMD_SET_ROI,
|
||||
DSI_CMD_SET_TIMING_SWITCH,
|
||||
DSI_CMD_SET_POST_TIMING_SWITCH,
|
||||
DSI_CMD_SET_QSYNC_ON,
|
||||
DSI_CMD_SET_QSYNC_OFF,
|
||||
DSI_CMD_SET_MAX
|
||||
};
|
||||
|
||||
/**
|
||||
* enum dsi_cmd_set_state - command set state
|
||||
* @DSI_CMD_SET_STATE_LP: dsi low power mode
|
||||
* @DSI_CMD_SET_STATE_HS: dsi high speed mode
|
||||
* @DSI_CMD_SET_STATE_MAX
|
||||
*/
|
||||
enum dsi_cmd_set_state {
|
||||
DSI_CMD_SET_STATE_LP = 0,
|
||||
DSI_CMD_SET_STATE_HS,
|
||||
DSI_CMD_SET_STATE_MAX
|
||||
};
|
||||
|
||||
/**
|
||||
* enum dsi_clk_gate_type - Type of clock to be gated.
|
||||
* @PIXEL_CLK: DSI pixel clock.
|
||||
* @BYTE_CLK: DSI byte clock.
|
||||
* @DSI_PHY: DSI PHY.
|
||||
* @DSI_CLK_ALL: All available DSI clocks
|
||||
* @DSI_CLK_NONE: None of the clocks should be gated
|
||||
*/
|
||||
enum dsi_clk_gate_type {
|
||||
PIXEL_CLK = 1,
|
||||
BYTE_CLK = 2,
|
||||
DSI_PHY = 4,
|
||||
DSI_CLK_ALL = (PIXEL_CLK | BYTE_CLK | DSI_PHY),
|
||||
DSI_CLK_NONE = 8,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum dsi_phy_type - DSI phy types
|
||||
* @DSI_PHY_TYPE_DPHY:
|
||||
* @DSI_PHY_TYPE_CPHY:
|
||||
*/
|
||||
enum dsi_phy_type {
|
||||
DSI_PHY_TYPE_DPHY,
|
||||
DSI_PHY_TYPE_CPHY
|
||||
};
|
||||
|
||||
/**
|
||||
* enum dsi_te_mode - dsi te source
|
||||
* @DSI_TE_ON_DATA_LINK: TE read from DSI link
|
||||
* @DSI_TE_ON_EXT_PIN: TE signal on an external GPIO
|
||||
*/
|
||||
enum dsi_te_mode {
|
||||
DSI_TE_ON_DATA_LINK = 0,
|
||||
DSI_TE_ON_EXT_PIN,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum dsi_video_traffic_mode - video mode pixel transmission type
|
||||
* @DSI_VIDEO_TRAFFIC_SYNC_PULSES: Non-burst mode with sync pulses.
|
||||
* @DSI_VIDEO_TRAFFIC_SYNC_START_EVENTS: Non-burst mode with sync start events.
|
||||
* @DSI_VIDEO_TRAFFIC_BURST_MODE: Burst mode using sync start events.
|
||||
*/
|
||||
enum dsi_video_traffic_mode {
|
||||
DSI_VIDEO_TRAFFIC_SYNC_PULSES = 0,
|
||||
DSI_VIDEO_TRAFFIC_SYNC_START_EVENTS,
|
||||
DSI_VIDEO_TRAFFIC_BURST_MODE,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dsi_cmd_desc - description of a dsi command
|
||||
* @msg: dsi mipi msg packet
|
||||
* @last_command: indicates whether the cmd is the last one to send
|
||||
* @post_wait_ms: post wait duration
|
||||
*/
|
||||
struct dsi_cmd_desc {
|
||||
struct mipi_dsi_msg msg;
|
||||
bool last_command;
|
||||
u32 post_wait_ms;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dsi_panel_cmd_set - command set of the panel
|
||||
* @type: type of the command
|
||||
* @state: state of the command
|
||||
* @count: number of cmds
|
||||
* @ctrl_idx: index of the dsi control
|
||||
* @cmds: arry of cmds
|
||||
*/
|
||||
struct dsi_panel_cmd_set {
|
||||
enum dsi_cmd_set_type type;
|
||||
enum dsi_cmd_set_state state;
|
||||
u32 count;
|
||||
u32 ctrl_idx;
|
||||
struct dsi_cmd_desc *cmds;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dsi_mode_info - video mode information dsi frame
|
||||
* @h_active: Active width of one frame in pixels.
|
||||
* @h_back_porch: Horizontal back porch in pixels.
|
||||
* @h_sync_width: HSYNC width in pixels.
|
||||
* @h_front_porch: Horizontal fron porch in pixels.
|
||||
* @h_skew:
|
||||
* @h_sync_polarity: Polarity of HSYNC (false is active low).
|
||||
* @v_active: Active height of one frame in lines.
|
||||
* @v_back_porch: Vertical back porch in lines.
|
||||
* @v_sync_width: VSYNC width in lines.
|
||||
* @v_front_porch: Vertical front porch in lines.
|
||||
* @v_sync_polarity: Polarity of VSYNC (false is active low).
|
||||
* @refresh_rate: Refresh rate in Hz.
|
||||
* @clk_rate_hz: DSI bit clock rate per lane in Hz.
|
||||
* @min_dsi_clk_hz: Min DSI bit clock to transfer in vsync time.
|
||||
* @mdp_transfer_time_us: Specifies the mdp transfer time for command mode
|
||||
* panels in microseconds.
|
||||
* @dsi_transfer_time_us: Specifies dsi transfer time for command mode.
|
||||
* @dsc_enabled: DSC compression enabled.
|
||||
* @vdc_enabled: VDC compression enabled.
|
||||
* @dsc: DSC compression configuration.
|
||||
* @vdc: VDC compression configuration.
|
||||
* @pclk_scale: pclk scale factor, target bpp to source bpp
|
||||
* @roi_caps: Panel ROI capabilities.
|
||||
*/
|
||||
struct dsi_mode_info {
|
||||
u32 h_active;
|
||||
u32 h_back_porch;
|
||||
u32 h_sync_width;
|
||||
u32 h_front_porch;
|
||||
u32 h_skew;
|
||||
bool h_sync_polarity;
|
||||
|
||||
u32 v_active;
|
||||
u32 v_back_porch;
|
||||
u32 v_sync_width;
|
||||
u32 v_front_porch;
|
||||
bool v_sync_polarity;
|
||||
|
||||
u32 refresh_rate;
|
||||
u64 clk_rate_hz;
|
||||
u64 min_dsi_clk_hz;
|
||||
u32 mdp_transfer_time_us;
|
||||
u32 dsi_transfer_time_us;
|
||||
bool dsc_enabled;
|
||||
bool vdc_enabled;
|
||||
struct msm_display_dsc_info *dsc;
|
||||
struct msm_display_vdc_info *vdc;
|
||||
struct msm_ratio pclk_scale;
|
||||
struct msm_roi_caps roi_caps;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dsi_split_link_config - Split Link Configuration
|
||||
* @split_link_enabled: Split Link Enabled.
|
||||
* @num_sublinks: Number of sublinks.
|
||||
* @lanes_per_sublink: Number of lanes per sublink.
|
||||
*/
|
||||
struct dsi_split_link_config {
|
||||
bool split_link_enabled;
|
||||
u32 num_sublinks;
|
||||
u32 lanes_per_sublink;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dsi_host_common_cfg - Host configuration common to video and cmd mode
|
||||
* @dst_format: Destination pixel format.
|
||||
* @data_lanes: Physical data lanes to be enabled.
|
||||
* @num_data_lanes: Number of physical data lanes.
|
||||
* @bpp: Number of bits per pixel.
|
||||
* @en_crc_check: Enable CRC checks.
|
||||
* @en_ecc_check: Enable ECC checks.
|
||||
* @te_mode: Source for TE signalling.
|
||||
* @mdp_cmd_trigger: MDP frame update trigger for command mode.
|
||||
* @dma_cmd_trigger: Command DMA trigger.
|
||||
* @cmd_trigger_stream: Command mode stream to trigger.
|
||||
* @swap_mode: DSI color swap mode.
|
||||
* @bit_swap_read: Is red color bit swapped.
|
||||
* @bit_swap_green: Is green color bit swapped.
|
||||
* @bit_swap_blue: Is blue color bit swapped.
|
||||
* @t_clk_post: Number of byte clock cycles that the transmitter shall
|
||||
* continue sending after last data lane has transitioned
|
||||
* to LP mode.
|
||||
* @t_clk_pre: Number of byte clock cycles that the high spped clock
|
||||
* shall be driven prior to data lane transitions from LP
|
||||
* to HS mode.
|
||||
* @ignore_rx_eot: Ignore Rx EOT packets if set to true.
|
||||
* @append_tx_eot: Append EOT packets for forward transmissions if set to
|
||||
* true.
|
||||
* @ext_bridge_mode: External bridge is connected.
|
||||
* @force_hs_clk_lane: Send continuous clock to the panel.
|
||||
* @phy_type: DPHY/CPHY is enabled for this panel.
|
||||
* @dsi_split_link_config: Split Link Configuration.
|
||||
* @byte_intf_clk_div: Determines the factor for calculating byte intf clock.
|
||||
* @dma_sched_line: Line at which dma command gets triggered. In case of
|
||||
* video mode it is the line number after vactive and for
|
||||
* cmd it points to the line after TE.
|
||||
* @dma_sched_window: Determines the width of the window during the
|
||||
* DSI command will be sent by the HW.
|
||||
*/
|
||||
struct dsi_host_common_cfg {
|
||||
enum dsi_pixel_format dst_format;
|
||||
enum dsi_data_lanes data_lanes;
|
||||
u8 num_data_lanes;
|
||||
u8 bpp;
|
||||
bool en_crc_check;
|
||||
bool en_ecc_check;
|
||||
enum dsi_te_mode te_mode;
|
||||
enum dsi_trigger_type mdp_cmd_trigger;
|
||||
enum dsi_trigger_type dma_cmd_trigger;
|
||||
u32 cmd_trigger_stream;
|
||||
enum dsi_color_swap_mode swap_mode;
|
||||
bool bit_swap_red;
|
||||
bool bit_swap_green;
|
||||
bool bit_swap_blue;
|
||||
u32 t_clk_post;
|
||||
u32 t_clk_pre;
|
||||
bool ignore_rx_eot;
|
||||
bool append_tx_eot;
|
||||
bool ext_bridge_mode;
|
||||
bool force_hs_clk_lane;
|
||||
enum dsi_phy_type phy_type;
|
||||
struct dsi_split_link_config split_link;
|
||||
u32 byte_intf_clk_div;
|
||||
u32 dma_sched_line;
|
||||
u32 dma_sched_window;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dsi_video_engine_cfg - DSI video engine configuration
|
||||
* @last_line_interleave_en: Allow command mode op interleaved on last line of
|
||||
* video stream.
|
||||
* @pulse_mode_hsa_he: Send HSA and HE following VS/VE packet if set to
|
||||
* true.
|
||||
* @hfp_lp11_en: Enter low power stop mode (LP-11) during HFP.
|
||||
* @hbp_lp11_en: Enter low power stop mode (LP-11) during HBP.
|
||||
* @hsa_lp11_en: Enter low power stop mode (LP-11) during HSA.
|
||||
* @eof_bllp_lp11_en: Enter low power stop mode (LP-11) during BLLP of
|
||||
* last line of a frame.
|
||||
* @bllp_lp11_en: Enter low power stop mode (LP-11) during BLLP.
|
||||
* @traffic_mode: Traffic mode for video stream.
|
||||
* @vc_id: Virtual channel identifier.
|
||||
*/
|
||||
struct dsi_video_engine_cfg {
|
||||
bool last_line_interleave_en;
|
||||
bool pulse_mode_hsa_he;
|
||||
bool hfp_lp11_en;
|
||||
bool hbp_lp11_en;
|
||||
bool hsa_lp11_en;
|
||||
bool eof_bllp_lp11_en;
|
||||
bool bllp_lp11_en;
|
||||
enum dsi_video_traffic_mode traffic_mode;
|
||||
u32 vc_id;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dsi_cmd_engine_cfg - DSI command engine configuration
|
||||
* @max_cmd_packets_interleave Maximum number of command mode RGB packets to
|
||||
* send with in one horizontal blanking period
|
||||
* of the video mode frame.
|
||||
* @wr_mem_start: DCS command for write_memory_start.
|
||||
* @wr_mem_continue: DCS command for write_memory_continue.
|
||||
* @insert_dcs_command: Insert DCS command as first byte of payload
|
||||
* of the pixel data.
|
||||
* @mdp_idle_ctrl_en: Enable idle insertion between command mode mdp packets.
|
||||
* @mdp_idle_ctrl_len: No. of dsi pclk cycles of idle time to insert between
|
||||
* command mode mdp packets.
|
||||
*/
|
||||
struct dsi_cmd_engine_cfg {
|
||||
u32 max_cmd_packets_interleave;
|
||||
u32 wr_mem_start;
|
||||
u32 wr_mem_continue;
|
||||
bool insert_dcs_command;
|
||||
bool mdp_idle_ctrl_en;
|
||||
u32 mdp_idle_ctrl_len;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dsi_host_config - DSI host configuration parameters.
|
||||
* @panel_mode: Operation mode for panel (video or cmd mode).
|
||||
* @common_config: Host configuration common to both Video and Cmd mode.
|
||||
* @video_engine: Video engine configuration if panel is in video mode.
|
||||
* @cmd_engine: Cmd engine configuration if panel is in cmd mode.
|
||||
* @esc_clk_rate_hz: Esc clock frequency in Hz.
|
||||
* @bit_clk_rate_hz: Bit clock frequency in Hz.
|
||||
* @bit_clk_rate_hz_override: DSI bit clk rate override from dt/sysfs.
|
||||
* @video_timing: Video timing information of a frame.
|
||||
* @lane_map: Mapping between logical and physical lanes.
|
||||
*/
|
||||
struct dsi_host_config {
|
||||
enum dsi_op_mode panel_mode;
|
||||
struct dsi_host_common_cfg common_config;
|
||||
union {
|
||||
struct dsi_video_engine_cfg video_engine;
|
||||
struct dsi_cmd_engine_cfg cmd_engine;
|
||||
} u;
|
||||
u64 esc_clk_rate_hz;
|
||||
u64 bit_clk_rate_hz;
|
||||
u64 bit_clk_rate_hz_override;
|
||||
struct dsi_mode_info video_timing;
|
||||
struct dsi_lane_map lane_map;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dsi_display_mode_priv_info - private mode info that will be attached
|
||||
* with each drm mode
|
||||
* @cmd_sets: Command sets of the mode
|
||||
* @phy_timing_val: Phy timing values
|
||||
* @phy_timing_len: Phy timing array length
|
||||
* @panel_jitter: Panel jitter for RSC backoff
|
||||
* @panel_prefill_lines: Panel prefill lines for RSC
|
||||
* @mdp_transfer_time_us: Specifies the mdp transfer time for command mode
|
||||
* panels in microseconds.
|
||||
* @dsi_transfer_time_us: Specifies the dsi transfer time for cmd panels.
|
||||
* @clk_rate_hz: DSI bit clock per lane in hz.
|
||||
* @min_dsi_clk_hz: Min dsi clk per lane to transfer frame in vsync time.
|
||||
* @topology: Topology selected for the panel
|
||||
* @dsc: DSC compression info
|
||||
* @vdc: VDC compression info
|
||||
* @dsc_enabled: DSC compression enabled
|
||||
* @vdc_enabled: VDC compression enabled
|
||||
* @pclk_scale: pclk scale factor, target bpp to source bpp
|
||||
* @roi_caps: Panel ROI capabilities
|
||||
* @widebus_support 48 bit wide data bus is supported by hw
|
||||
* @allowed_mode_switch: BIT mask to mark allowed mode switches
|
||||
*/
|
||||
struct dsi_display_mode_priv_info {
|
||||
struct dsi_panel_cmd_set cmd_sets[DSI_CMD_SET_MAX];
|
||||
|
||||
u32 *phy_timing_val;
|
||||
u32 phy_timing_len;
|
||||
|
||||
u32 panel_jitter_numer;
|
||||
u32 panel_jitter_denom;
|
||||
u32 panel_prefill_lines;
|
||||
u32 mdp_transfer_time_us;
|
||||
u32 dsi_transfer_time_us;
|
||||
u64 clk_rate_hz;
|
||||
u64 min_dsi_clk_hz;
|
||||
|
||||
struct msm_display_topology topology;
|
||||
struct msm_display_dsc_info dsc;
|
||||
struct msm_display_vdc_info vdc;
|
||||
bool dsc_enabled;
|
||||
bool vdc_enabled;
|
||||
struct msm_ratio pclk_scale;
|
||||
struct msm_roi_caps roi_caps;
|
||||
bool widebus_support;
|
||||
u32 allowed_mode_switch;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dsi_display_mode - specifies mode for dsi display
|
||||
* @timing: Timing parameters for the panel.
|
||||
* @pixel_clk_khz: Pixel clock in Khz.
|
||||
* @dsi_mode_flags: Flags to signal other drm components via private flags
|
||||
* @panel_mode: Panel mode
|
||||
* @is_preferred: Is mode preferred
|
||||
* @priv_info: Mode private info
|
||||
*/
|
||||
struct dsi_display_mode {
|
||||
struct dsi_mode_info timing;
|
||||
u32 pixel_clk_khz;
|
||||
u32 dsi_mode_flags;
|
||||
enum dsi_op_mode panel_mode;
|
||||
bool is_preferred;
|
||||
struct dsi_display_mode_priv_info *priv_info;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dsi_rect - dsi rectangle representation
|
||||
* Note: sde_rect is also using u16, this must be maintained for memcpy
|
||||
*/
|
||||
struct dsi_rect {
|
||||
u16 x;
|
||||
u16 y;
|
||||
u16 w;
|
||||
u16 h;
|
||||
};
|
||||
|
||||
/**
|
||||
* dsi_rect_intersect - intersect two rectangles
|
||||
* @r1: first rectangle
|
||||
* @r2: scissor rectangle
|
||||
* @result: result rectangle, all 0's on no intersection found
|
||||
*/
|
||||
void dsi_rect_intersect(const struct dsi_rect *r1,
|
||||
const struct dsi_rect *r2,
|
||||
struct dsi_rect *result);
|
||||
|
||||
/**
|
||||
* dsi_rect_is_equal - compares two rects
|
||||
* @r1: rect value to compare
|
||||
* @r2: rect value to compare
|
||||
*
|
||||
* Returns true if the rects are same
|
||||
*/
|
||||
static inline bool dsi_rect_is_equal(struct dsi_rect *r1,
|
||||
struct dsi_rect *r2)
|
||||
{
|
||||
return r1->x == r2->x && r1->y == r2->y && r1->w == r2->w &&
|
||||
r1->h == r2->h;
|
||||
}
|
||||
|
||||
struct dsi_event_cb_info {
|
||||
uint32_t event_idx;
|
||||
void *event_usr_ptr;
|
||||
|
||||
int (*event_cb)(void *event_usr_ptr,
|
||||
uint32_t event_idx, uint32_t instance_idx,
|
||||
uint32_t data0, uint32_t data1,
|
||||
uint32_t data2, uint32_t data3);
|
||||
};
|
||||
|
||||
/**
|
||||
* enum dsi_error_status - various dsi errors
|
||||
* @DSI_FIFO_OVERFLOW: DSI FIFO Overflow error
|
||||
* @DSI_FIFO_UNDERFLOW: DSI FIFO Underflow error
|
||||
* @DSI_LP_Rx_TIMEOUT: DSI LP/RX Timeout error
|
||||
* @DSI_PLL_UNLOCK_ERR: DSI PLL unlock error
|
||||
*/
|
||||
enum dsi_error_status {
|
||||
DSI_FIFO_OVERFLOW = 1,
|
||||
DSI_FIFO_UNDERFLOW,
|
||||
DSI_LP_Rx_TIMEOUT,
|
||||
DSI_PLL_UNLOCK_ERR,
|
||||
DSI_ERR_INTR_ALL,
|
||||
};
|
||||
|
||||
/* structure containing the delays required for dynamic clk */
|
||||
struct dsi_dyn_clk_delay {
|
||||
u32 pipe_delay;
|
||||
u32 pipe_delay2;
|
||||
u32 pll_delay;
|
||||
};
|
||||
|
||||
/* dynamic refresh control bits */
|
||||
enum dsi_dyn_clk_control_bits {
|
||||
DYN_REFRESH_INTF_SEL = 1,
|
||||
DYN_REFRESH_SYNC_MODE,
|
||||
DYN_REFRESH_SW_TRIGGER,
|
||||
DYN_REFRESH_SWI_CTRL,
|
||||
};
|
||||
|
||||
/* convert dsi pixel format into bits per pixel */
|
||||
static inline int dsi_pixel_format_to_bpp(enum dsi_pixel_format fmt)
|
||||
{
|
||||
switch (fmt) {
|
||||
case DSI_PIXEL_FORMAT_RGB888:
|
||||
case DSI_PIXEL_FORMAT_MAX:
|
||||
return 24;
|
||||
case DSI_PIXEL_FORMAT_RGB666:
|
||||
case DSI_PIXEL_FORMAT_RGB666_LOOSE:
|
||||
return 18;
|
||||
case DSI_PIXEL_FORMAT_RGB565:
|
||||
return 16;
|
||||
case DSI_PIXEL_FORMAT_RGB111:
|
||||
return 3;
|
||||
case DSI_PIXEL_FORMAT_RGB332:
|
||||
return 8;
|
||||
case DSI_PIXEL_FORMAT_RGB444:
|
||||
return 12;
|
||||
}
|
||||
return 24;
|
||||
}
|
||||
|
||||
static inline u64 dsi_h_active_dce(struct dsi_mode_info *mode)
|
||||
{
|
||||
u64 h_active = 0;
|
||||
|
||||
if (mode->dsc_enabled && mode->dsc)
|
||||
h_active = mode->dsc->pclk_per_line;
|
||||
else if (mode->vdc_enabled && mode->vdc)
|
||||
h_active = mode->vdc->pclk_per_line;
|
||||
else
|
||||
h_active = mode->h_active;
|
||||
|
||||
return h_active;
|
||||
}
|
||||
|
||||
static inline u64 dsi_h_total_dce(struct dsi_mode_info *mode)
|
||||
{
|
||||
u64 h_total = dsi_h_active_dce(mode);
|
||||
|
||||
h_total += mode->h_back_porch + mode->h_front_porch +
|
||||
mode->h_sync_width;
|
||||
return h_total;
|
||||
}
|
||||
|
||||
#endif /* _DSI_DEFS_H_ */
|
8605
techpack/display/msm/dsi/dsi_display.c
Normal file
8605
techpack/display/msm/dsi/dsi_display.c
Normal file
File diff suppressed because it is too large
Load Diff
802
techpack/display/msm/dsi/dsi_display.h
Normal file
802
techpack/display/msm/dsi/dsi_display.h
Normal file
@ -0,0 +1,802 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _DSI_DISPLAY_H_
|
||||
#define _DSI_DISPLAY_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_crtc.h>
|
||||
|
||||
#include "msm_drv.h"
|
||||
#include "dsi_defs.h"
|
||||
#include "dsi_ctrl.h"
|
||||
#include "dsi_phy.h"
|
||||
#include "dsi_panel.h"
|
||||
|
||||
#define MAX_DSI_CTRLS_PER_DISPLAY 2
|
||||
#define DSI_CLIENT_NAME_SIZE 20
|
||||
#define MAX_CMDLINE_PARAM_LEN 512
|
||||
#define MAX_CMD_PAYLOAD_SIZE 256
|
||||
/*
|
||||
* DSI Validate Mode modifiers
|
||||
* @DSI_VALIDATE_FLAG_ALLOW_ADJUST: Allow mode validation to also do fixup
|
||||
*/
|
||||
#define DSI_VALIDATE_FLAG_ALLOW_ADJUST 0x1
|
||||
|
||||
/**
|
||||
* enum dsi_display_selection_type - enumerates DSI display selection types
|
||||
* @DSI_PRIMARY: primary DSI display selected from module parameter
|
||||
* @DSI_SECONDARY: Secondary DSI display selected from module parameter
|
||||
* @MAX_DSI_ACTIVE_DISPLAY: Maximum acive displays that can be selected
|
||||
*/
|
||||
enum dsi_display_selection_type {
|
||||
DSI_PRIMARY = 0,
|
||||
DSI_SECONDARY,
|
||||
MAX_DSI_ACTIVE_DISPLAY,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum dsi_display_type - enumerates DSI display types
|
||||
* @DSI_DISPLAY_SINGLE: A panel connected on a single DSI interface.
|
||||
* @DSI_DISPLAY_EXT_BRIDGE: A bridge is connected between panel and DSI host.
|
||||
* It utilizes a single DSI interface.
|
||||
* @DSI_DISPLAY_SPLIT: A panel that utilizes more than one DSI
|
||||
* interfaces.
|
||||
* @DSI_DISPLAY_SPLIT_EXT_BRIDGE: A bridge is present between panel and DSI
|
||||
* host. It utilizes more than one DSI interface.
|
||||
*/
|
||||
enum dsi_display_type {
|
||||
DSI_DISPLAY_SINGLE = 0,
|
||||
DSI_DISPLAY_EXT_BRIDGE,
|
||||
DSI_DISPLAY_SPLIT,
|
||||
DSI_DISPLAY_SPLIT_EXT_BRIDGE,
|
||||
DSI_DISPLAY_MAX,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dsi_display_ctrl - dsi ctrl/phy information for the display
|
||||
* @ctrl: Handle to the DSI controller device.
|
||||
* @ctrl_of_node: pHandle to the DSI controller device.
|
||||
* @dsi_ctrl_idx: DSI controller instance id.
|
||||
* @power_state: Current power state of the DSI controller.
|
||||
* @phy: Handle to the DSI PHY device.
|
||||
* @phy_of_node: pHandle to the DSI PHY device.
|
||||
* @phy_enabled: PHY power status.
|
||||
*/
|
||||
struct dsi_display_ctrl {
|
||||
/* controller info */
|
||||
struct dsi_ctrl *ctrl;
|
||||
struct device_node *ctrl_of_node;
|
||||
u32 dsi_ctrl_idx;
|
||||
|
||||
enum dsi_power_state power_state;
|
||||
|
||||
/* phy info */
|
||||
struct msm_dsi_phy *phy;
|
||||
struct device_node *phy_of_node;
|
||||
|
||||
bool phy_enabled;
|
||||
};
|
||||
/**
|
||||
* struct dsi_display_boot_param - defines DSI boot display selection
|
||||
* @name:Name of DSI display selected as a boot param.
|
||||
* @boot_disp_en:bool to indicate dtsi availability of display node
|
||||
* @is_primary:bool to indicate whether current display is primary display
|
||||
* @length:length of DSI display.
|
||||
* @cmdline_topology: Display topology shared from kernel command line.
|
||||
*/
|
||||
struct dsi_display_boot_param {
|
||||
char name[MAX_CMDLINE_PARAM_LEN];
|
||||
char *boot_param;
|
||||
bool boot_disp_en;
|
||||
int length;
|
||||
struct device_node *node;
|
||||
int cmdline_topology;
|
||||
void *disp;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dsi_display_clk_info - dsi display clock source information
|
||||
* @src_clks: Source clocks for DSI display.
|
||||
* @mux_clks: Mux clocks used for DFPS.
|
||||
* @shadow_clks: Used for D-phy clock switch.
|
||||
* @shadow_cphy_clks: Used for C-phy clock switch.
|
||||
*/
|
||||
struct dsi_display_clk_info {
|
||||
struct dsi_clk_link_set src_clks;
|
||||
struct dsi_clk_link_set mux_clks;
|
||||
struct dsi_clk_link_set cphy_clks;
|
||||
struct dsi_clk_link_set shadow_clks;
|
||||
struct dsi_clk_link_set shadow_cphy_clks;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dsi_display_ext_bridge - dsi display external bridge information
|
||||
* @display: Pointer of DSI display.
|
||||
* @node_of: Bridge node created from bridge driver.
|
||||
* @bridge: Bridge created from bridge driver
|
||||
* @orig_funcs: Bridge function from bridge driver (split mode only)
|
||||
* @bridge_funcs: Overridden function from bridge driver (split mode only)
|
||||
*/
|
||||
struct dsi_display_ext_bridge {
|
||||
void *display;
|
||||
struct device_node *node_of;
|
||||
struct drm_bridge *bridge;
|
||||
const struct drm_bridge_funcs *orig_funcs;
|
||||
struct drm_bridge_funcs bridge_funcs;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dsi_display - dsi display information
|
||||
* @pdev: Pointer to platform device.
|
||||
* @drm_dev: DRM device associated with the display.
|
||||
* @drm_conn: Pointer to DRM connector associated with the display
|
||||
* @ext_conn: Pointer to external connector attached to DSI connector
|
||||
* @name: Name of the display.
|
||||
* @display_type: Display type as defined in device tree.
|
||||
* @list: List pointer.
|
||||
* @is_active: Is display active.
|
||||
* @is_cont_splash_enabled: Is continuous splash enabled
|
||||
* @sw_te_using_wd: Is software te enabled
|
||||
* @display_lock: Mutex for dsi_display interface.
|
||||
* @disp_te_gpio: GPIO for panel TE interrupt.
|
||||
* @is_te_irq_enabled:bool to specify whether TE interrupt is enabled.
|
||||
* @esd_te_gate: completion gate to signal TE interrupt.
|
||||
* @ctrl_count: Number of DSI interfaces required by panel.
|
||||
* @ctrl: Controller information for DSI display.
|
||||
* @panel: Handle to DSI panel.
|
||||
* @panel_node: pHandle to DSI panel actually in use.
|
||||
* @ext_bridge: External bridge information for DSI display.
|
||||
* @ext_bridge_cnt: Number of external bridges
|
||||
* @modes: Array of probed DSI modes
|
||||
* @type: DSI display type.
|
||||
* @clk_master_idx: The master controller for controlling clocks. This is an
|
||||
* index into the ctrl[MAX_DSI_CTRLS_PER_DISPLAY] array.
|
||||
* @cmd_master_idx: The master controller for sending DSI commands to panel.
|
||||
* @video_master_idx: The master controller for enabling video engine.
|
||||
* @cached_clk_rate: The cached DSI clock rate set dynamically by sysfs.
|
||||
* @clkrate_change_pending: Flag indicating the pending DSI clock re-enabling.
|
||||
* @clock_info: Clock sourcing for DSI display.
|
||||
* @config: DSI host configuration information.
|
||||
* @lane_map: Lane mapping between DSI host and Panel.
|
||||
* @cmdline_topology: Display topology shared from kernel command line.
|
||||
* @cmdline_timing: Display timing shared from kernel command line.
|
||||
* @is_tpg_enabled: TPG state.
|
||||
* @poms_pending; Flag indicating the pending panel operating mode switch.
|
||||
* @ulps_enabled: ulps state.
|
||||
* @clamp_enabled: clamp state.
|
||||
* @phy_idle_power_off: PHY power state.
|
||||
* @host: DRM MIPI DSI Host.
|
||||
* @bridge: Pointer to DRM bridge object.
|
||||
* @cmd_engine_refcount: Reference count enforcing single instance of cmd eng
|
||||
* @clk_mngr: DSI clock manager.
|
||||
* @dsi_clk_handle: DSI clock handle.
|
||||
* @mdp_clk_handle: MDP clock handle.
|
||||
* @root: Debugfs root directory
|
||||
* @misr_enable Frame MISR enable/disable
|
||||
* @misr_frame_count Number of frames to accumulate the MISR value
|
||||
* @esd_trigger field indicating ESD trigger through debugfs
|
||||
* @poms_te_work POMS delayed work for disabling panel TE
|
||||
* @te_source vsync source pin information
|
||||
* @clk_gating_config Clocks for which clock gating needs to be enabled
|
||||
* @queue_cmd_waits Indicates if wait for dma commands done has to be queued.
|
||||
* @dma_cmd_workq: Pointer to the workqueue of DMA command transfer done
|
||||
* wait sequence.
|
||||
* @is_active: status of the display
|
||||
* @trusted_vm_env: Set to true, it the executing VM is Trusted VM.
|
||||
* Set to false, otherwise.
|
||||
* @hw_ownership: Indicates if VM owns the hardware resources.
|
||||
* @tx_cmd_buf_ndx: Index to the DSI debugfs TX CMD buffer.
|
||||
* @cmd_set: Debugfs TX cmd set.
|
||||
* @enabled: Boolean to indicate display enabled.
|
||||
*/
|
||||
struct dsi_display {
|
||||
struct platform_device *pdev;
|
||||
struct drm_device *drm_dev;
|
||||
struct drm_connector *drm_conn;
|
||||
struct drm_connector *ext_conn;
|
||||
|
||||
const char *name;
|
||||
const char *display_type;
|
||||
struct list_head list;
|
||||
bool is_cont_splash_enabled;
|
||||
bool sw_te_using_wd;
|
||||
struct mutex display_lock;
|
||||
int disp_te_gpio;
|
||||
bool is_te_irq_enabled;
|
||||
struct completion esd_te_gate;
|
||||
|
||||
u32 ctrl_count;
|
||||
struct dsi_display_ctrl ctrl[MAX_DSI_CTRLS_PER_DISPLAY];
|
||||
|
||||
/* panel info */
|
||||
struct dsi_panel *panel;
|
||||
struct device_node *panel_node;
|
||||
struct device_node *parser_node;
|
||||
|
||||
/* external bridge */
|
||||
struct dsi_display_ext_bridge ext_bridge[MAX_DSI_CTRLS_PER_DISPLAY];
|
||||
u32 ext_bridge_cnt;
|
||||
|
||||
struct dsi_display_mode *modes;
|
||||
|
||||
enum dsi_display_type type;
|
||||
u32 clk_master_idx;
|
||||
u32 cmd_master_idx;
|
||||
u32 video_master_idx;
|
||||
|
||||
/* dynamic DSI clock info*/
|
||||
u32 cached_clk_rate;
|
||||
atomic_t clkrate_change_pending;
|
||||
|
||||
struct dsi_display_clk_info clock_info;
|
||||
struct dsi_host_config config;
|
||||
struct dsi_lane_map lane_map;
|
||||
int cmdline_topology;
|
||||
int cmdline_timing;
|
||||
bool is_tpg_enabled;
|
||||
bool poms_pending;
|
||||
bool ulps_enabled;
|
||||
bool clamp_enabled;
|
||||
bool phy_idle_power_off;
|
||||
struct drm_gem_object *tx_cmd_buf;
|
||||
u32 cmd_buffer_size;
|
||||
u64 cmd_buffer_iova;
|
||||
void *vaddr;
|
||||
struct msm_gem_address_space *aspace;
|
||||
|
||||
struct mipi_dsi_host host;
|
||||
struct dsi_bridge *bridge;
|
||||
u32 cmd_engine_refcount;
|
||||
|
||||
void *clk_mngr;
|
||||
void *dsi_clk_handle;
|
||||
void *mdp_clk_handle;
|
||||
|
||||
/* DEBUG FS */
|
||||
struct dentry *root;
|
||||
|
||||
bool misr_enable;
|
||||
u32 misr_frame_count;
|
||||
u32 esd_trigger;
|
||||
/* multiple dsi error handlers */
|
||||
struct workqueue_struct *err_workq;
|
||||
struct work_struct fifo_underflow_work;
|
||||
struct work_struct fifo_overflow_work;
|
||||
struct work_struct lp_rx_timeout_work;
|
||||
|
||||
/* panel te delayed work */
|
||||
struct delayed_work poms_te_work;
|
||||
|
||||
/* firmware panel data */
|
||||
const struct firmware *fw;
|
||||
void *parser;
|
||||
|
||||
struct dsi_display_boot_param *boot_disp;
|
||||
|
||||
u32 te_source;
|
||||
u32 clk_gating_config;
|
||||
bool queue_cmd_waits;
|
||||
struct workqueue_struct *dma_cmd_workq;
|
||||
|
||||
/* panel id of the display */
|
||||
u64 panel_id;
|
||||
bool is_active;
|
||||
|
||||
bool trusted_vm_env;
|
||||
bool hw_ownership;
|
||||
|
||||
int tx_cmd_buf_ndx;
|
||||
struct dsi_panel_cmd_set cmd_set;
|
||||
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
int dsi_display_dev_probe(struct platform_device *pdev);
|
||||
int dsi_display_dev_remove(struct platform_device *pdev);
|
||||
|
||||
/**
|
||||
* dsi_display_get_num_of_displays() - returns number of display devices
|
||||
* supported.
|
||||
*
|
||||
* Return: number of displays.
|
||||
*/
|
||||
int dsi_display_get_num_of_displays(void);
|
||||
|
||||
/**
|
||||
* dsi_display_get_active_displays - returns pointers for active display devices
|
||||
* @display_array: Pointer to display array to be filled
|
||||
* @max_display_count: Size of display_array
|
||||
* @Returns: Number of display entries filled
|
||||
*/
|
||||
int dsi_display_get_active_displays(void **display_array,
|
||||
u32 max_display_count);
|
||||
|
||||
/**
|
||||
* dsi_display_get_display_by_name()- finds display by name
|
||||
* @name: name of the display.
|
||||
*
|
||||
* Return: handle to the display or error code.
|
||||
*/
|
||||
struct dsi_display *dsi_display_get_display_by_name(const char *name);
|
||||
|
||||
/**
|
||||
* dsi_display_set_active_state() - sets the state of the display
|
||||
* @display: Handle to display.
|
||||
* @is_active: state
|
||||
*/
|
||||
void dsi_display_set_active_state(struct dsi_display *display, bool is_active);
|
||||
|
||||
/**
|
||||
* dsi_display_drm_bridge_init() - initializes DRM bridge object for DSI
|
||||
* @display: Handle to the display.
|
||||
* @encoder: Pointer to the encoder object which is connected to the
|
||||
* display.
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int dsi_display_drm_bridge_init(struct dsi_display *display,
|
||||
struct drm_encoder *enc);
|
||||
|
||||
/**
|
||||
* dsi_display_drm_bridge_deinit() - destroys DRM bridge for the display
|
||||
* @display: Handle to the display.
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int dsi_display_drm_bridge_deinit(struct dsi_display *display);
|
||||
|
||||
/**
|
||||
* dsi_display_drm_ext_bridge_init() - initializes DRM bridge for ext bridge
|
||||
* @display: Handle to the display.
|
||||
* @enc: Pointer to the encoder object which is connected to the
|
||||
* display.
|
||||
* @connector: Pointer to the connector object which is connected to
|
||||
* the display.
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int dsi_display_drm_ext_bridge_init(struct dsi_display *display,
|
||||
struct drm_encoder *enc, struct drm_connector *connector);
|
||||
|
||||
/**
|
||||
* dsi_display_get_info() - returns the display properties
|
||||
* @connector: Pointer to drm connector structure
|
||||
* @info: Pointer to the structure where info is stored.
|
||||
* @disp: Handle to the display.
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int dsi_display_get_info(struct drm_connector *connector,
|
||||
struct msm_display_info *info, void *disp);
|
||||
|
||||
/**
|
||||
* dsi_display_get_mode_count() - get number of modes supported by the display
|
||||
* @display: Handle to display.
|
||||
* @count: Number of modes supported
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int dsi_display_get_mode_count(struct dsi_display *display, u32 *count);
|
||||
|
||||
/**
|
||||
* dsi_display_get_modes() - get modes supported by display
|
||||
* @display: Handle to display.
|
||||
* @modes; Output param, list of DSI modes. Number of modes matches
|
||||
* count got from display->panel->num_display_modes;
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int dsi_display_get_modes(struct dsi_display *display,
|
||||
struct dsi_display_mode **modes);
|
||||
|
||||
/**
|
||||
* dsi_display_put_mode() - free up mode created for the display
|
||||
* @display: Handle to display.
|
||||
* @mode: Display mode to be freed up
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
void dsi_display_put_mode(struct dsi_display *display,
|
||||
struct dsi_display_mode *mode);
|
||||
|
||||
/**
|
||||
* dsi_display_get_default_lms() - retrieve max number of lms used
|
||||
* for dsi display by traversing through all topologies
|
||||
* @display: Handle to display.
|
||||
* @num_lm: Number of LMs used
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int dsi_display_get_default_lms(void *dsi_display, u32 *num_lm);
|
||||
|
||||
/**
|
||||
* dsi_display_get_qsync_min_fps() - get qsync min fps for given fps
|
||||
* @display: Handle to display.
|
||||
* @mode_fps: Fps value of current mode
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int dsi_display_get_qsync_min_fps(void *dsi_display, u32 mode_fps);
|
||||
|
||||
/**
|
||||
* dsi_conn_get_lm_from_mode() - retrieves LM count from dsi mode priv info
|
||||
* @display: Handle to display.
|
||||
* @mode: Pointer to DRM mode structure
|
||||
*
|
||||
* Return: LM count from dsi panel topology
|
||||
*/
|
||||
int dsi_conn_get_lm_from_mode(void *dsi_display, const struct drm_display_mode *mode);
|
||||
|
||||
/**
|
||||
* dsi_display_find_mode() - retrieve cached DSI mode given relevant params
|
||||
* @display: Handle to display.
|
||||
* @cmp: Mode to use as comparison to find original
|
||||
* @out_mode: Output parameter, pointer to retrieved mode
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int dsi_display_find_mode(struct dsi_display *display,
|
||||
const struct dsi_display_mode *cmp,
|
||||
struct dsi_display_mode **out_mode);
|
||||
/**
|
||||
* dsi_display_validate_mode() - validates if mode is supported by display
|
||||
* @display: Handle to display.
|
||||
* @mode: Mode to be validated.
|
||||
* @flags: Modifier flags.
|
||||
*
|
||||
* Return: 0 if supported or error code.
|
||||
*/
|
||||
int dsi_display_validate_mode(struct dsi_display *display,
|
||||
struct dsi_display_mode *mode,
|
||||
u32 flags);
|
||||
|
||||
/**
|
||||
* dsi_display_validate_mode_change() - validates mode if variable refresh case
|
||||
* or dynamic clk change case
|
||||
* @display: Handle to display.
|
||||
* @mode: Mode to be validated..
|
||||
*
|
||||
* Return: 0 if error code.
|
||||
*/
|
||||
int dsi_display_validate_mode_change(struct dsi_display *display,
|
||||
struct dsi_display_mode *cur_dsi_mode,
|
||||
struct dsi_display_mode *mode);
|
||||
|
||||
/**
|
||||
* dsi_display_set_mode() - Set mode on the display.
|
||||
* @display: Handle to display.
|
||||
* @mode: mode to be set.
|
||||
* @flags: Modifier flags.
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int dsi_display_set_mode(struct dsi_display *display,
|
||||
struct dsi_display_mode *mode,
|
||||
u32 flags);
|
||||
|
||||
/**
|
||||
* dsi_display_prepare() - prepare display
|
||||
* @display: Handle to display.
|
||||
*
|
||||
* Prepare will perform power up sequences for the host and panel hardware.
|
||||
* Power and clock resources might be turned on (depending on the panel mode).
|
||||
* The video engine is not enabled.
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int dsi_display_prepare(struct dsi_display *display);
|
||||
|
||||
/**
|
||||
* dsi_display_splash_res_cleanup() - cleanup for continuous splash
|
||||
* @display: Pointer to dsi display
|
||||
* Returns: Zero on success
|
||||
*/
|
||||
int dsi_display_splash_res_cleanup(struct dsi_display *display);
|
||||
|
||||
/**
|
||||
* dsi_display_config_ctrl_for_cont_splash()- Enable engine modes for DSI
|
||||
* controller during continuous splash
|
||||
* @display: Handle to DSI display
|
||||
*
|
||||
* Return: returns error code
|
||||
*/
|
||||
int dsi_display_config_ctrl_for_cont_splash(struct dsi_display *display);
|
||||
|
||||
/**
|
||||
* dsi_display_enable() - enable display
|
||||
* @display: Handle to display.
|
||||
*
|
||||
* Enable will turn on the host engine and the panel. At the end of the enable
|
||||
* function, Host and panel hardware are ready to accept pixel data from
|
||||
* upstream.
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int dsi_display_enable(struct dsi_display *display);
|
||||
|
||||
/**
|
||||
* dsi_display_post_enable() - perform post enable operations.
|
||||
* @display: Handle to display.
|
||||
*
|
||||
* Some panels might require some commands to be sent after pixel data
|
||||
* transmission has started. Such commands are sent as part of the post_enable
|
||||
* function.
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int dsi_display_post_enable(struct dsi_display *display);
|
||||
|
||||
/**
|
||||
* dsi_display_pre_disable() - perform pre disable operations.
|
||||
* @display: Handle to display.
|
||||
*
|
||||
* If a panel requires commands to be sent before pixel data transmission is
|
||||
* stopped, those can be sent as part of pre_disable.
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int dsi_display_pre_disable(struct dsi_display *display);
|
||||
|
||||
/**
|
||||
* dsi_display_disable() - disable panel and host hardware.
|
||||
* @display: Handle to display.
|
||||
*
|
||||
* Disable host and panel hardware and pixel data transmission can not continue.
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int dsi_display_disable(struct dsi_display *display);
|
||||
|
||||
/**
|
||||
* dsi_pre_clkoff_cb() - Callback before clock is turned off
|
||||
* @priv: private data pointer.
|
||||
* @clk_type: clock which is being turned on.
|
||||
* @l_type: specifies if the clock is HS or LP type. Valid only for link clocks.
|
||||
* @new_state: next state for the clock.
|
||||
*
|
||||
* @return: error code.
|
||||
*/
|
||||
int dsi_pre_clkoff_cb(void *priv, enum dsi_clk_type clk_type,
|
||||
enum dsi_lclk_type l_type,
|
||||
enum dsi_clk_state new_state);
|
||||
|
||||
/**
|
||||
* dsi_display_update_pps() - update PPS buffer.
|
||||
* @pps_cmd: PPS buffer.
|
||||
* @display: Handle to display.
|
||||
*
|
||||
* Copies new PPS buffer into display structure.
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int dsi_display_update_pps(char *pps_cmd, void *display);
|
||||
|
||||
/**
|
||||
* dsi_post_clkoff_cb() - Callback after clock is turned off
|
||||
* @priv: private data pointer.
|
||||
* @clk_type: clock which is being turned on.
|
||||
* @l_type: specifies if the clock is HS or LP type. Valid only for link clocks.
|
||||
* @curr_state: current state for the clock.
|
||||
*
|
||||
* @return: error code.
|
||||
*/
|
||||
int dsi_post_clkoff_cb(void *priv, enum dsi_clk_type clk_type,
|
||||
enum dsi_lclk_type l_type,
|
||||
enum dsi_clk_state curr_state);
|
||||
|
||||
/**
|
||||
* dsi_post_clkon_cb() - Callback after clock is turned on
|
||||
* @priv: private data pointer.
|
||||
* @clk_type: clock which is being turned on.
|
||||
* @l_type: specifies if the clock is HS or LP type. Valid only for link clocks.
|
||||
* @curr_state: current state for the clock.
|
||||
*
|
||||
* @return: error code.
|
||||
*/
|
||||
int dsi_post_clkon_cb(void *priv, enum dsi_clk_type clk_type,
|
||||
enum dsi_lclk_type l_type,
|
||||
enum dsi_clk_state curr_state);
|
||||
|
||||
/**
|
||||
* dsi_pre_clkon_cb() - Callback before clock is turned on
|
||||
* @priv: private data pointer.
|
||||
* @clk_type: clock which is being turned on.
|
||||
* @l_type: specifies if the clock is HS or LP type. Valid only for link clocks.
|
||||
* @new_state: next state for the clock.
|
||||
*
|
||||
* @return: error code.
|
||||
*/
|
||||
int dsi_pre_clkon_cb(void *priv, enum dsi_clk_type clk_type,
|
||||
enum dsi_lclk_type l_type,
|
||||
enum dsi_clk_state new_state);
|
||||
|
||||
/**
|
||||
* dsi_display_unprepare() - power off display hardware.
|
||||
* @display: Handle to display.
|
||||
*
|
||||
* Host and panel hardware is turned off. Panel will be in reset state at the
|
||||
* end of the function.
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int dsi_display_unprepare(struct dsi_display *display);
|
||||
|
||||
int dsi_display_set_tpg_state(struct dsi_display *display, bool enable);
|
||||
|
||||
int dsi_display_clock_gate(struct dsi_display *display, bool enable);
|
||||
int dsi_dispaly_static_frame(struct dsi_display *display, bool enable);
|
||||
|
||||
/**
|
||||
* dsi_display_get_drm_panel() - get drm_panel from display.
|
||||
* @display: Handle to display.
|
||||
* Get drm_panel which was inclued in dsi_display's dsi_panel.
|
||||
*
|
||||
* Return: drm_panel/NULL.
|
||||
*/
|
||||
struct drm_panel *dsi_display_get_drm_panel(struct dsi_display *display);
|
||||
|
||||
/**
|
||||
* dsi_display_enable_event() - enable interrupt based connector event
|
||||
* @connector: Pointer to drm connector structure
|
||||
* @display: Handle to display.
|
||||
* @event_idx: Event index.
|
||||
* @event_info: Event callback definition.
|
||||
* @enable: Whether to enable/disable the event interrupt.
|
||||
*/
|
||||
void dsi_display_enable_event(struct drm_connector *connector,
|
||||
struct dsi_display *display,
|
||||
uint32_t event_idx, struct dsi_event_cb_info *event_info,
|
||||
bool enable);
|
||||
|
||||
/**
|
||||
* dsi_display_set_backlight() - set backlight
|
||||
* @connector: Pointer to drm connector structure
|
||||
* @display: Handle to display.
|
||||
* @bl_lvl: Backlight level.
|
||||
* @event_info: Event callback definition.
|
||||
* @enable: Whether to enable/disable the event interrupt.
|
||||
*/
|
||||
int dsi_display_set_backlight(struct drm_connector *connector,
|
||||
void *display, u32 bl_lvl);
|
||||
|
||||
/**
|
||||
* dsi_display_check_status() - check if panel is dead or alive
|
||||
* @connector: Pointer to drm connector structure
|
||||
* @display: Handle to display.
|
||||
* @te_check_override: Whether check for TE from panel or default check
|
||||
*/
|
||||
int dsi_display_check_status(struct drm_connector *connector, void *display,
|
||||
bool te_check_override);
|
||||
|
||||
/**
|
||||
* dsi_display_cmd_transfer() - transfer command to the panel
|
||||
* @connector: Pointer to drm connector structure
|
||||
* @display: Handle to display.
|
||||
* @cmd_buf: Command buffer
|
||||
* @cmd_buf_len: Command buffer length in bytes
|
||||
*/
|
||||
int dsi_display_cmd_transfer(struct drm_connector *connector,
|
||||
void *display, const char *cmd_buffer,
|
||||
u32 cmd_buf_len);
|
||||
|
||||
/**
|
||||
* dsi_display_cmd_receive() - receive response from the panel
|
||||
* @display: Handle to display.
|
||||
* @cmd_buf: Command buffer
|
||||
* @cmd_buf_len: Command buffer length in bytes
|
||||
* @recv_buf: Receive buffer
|
||||
* @recv_buf_len: Receive buffer length in bytes
|
||||
*/
|
||||
int dsi_display_cmd_receive(void *display, const char *cmd_buf,
|
||||
u32 cmd_buf_len, u8 *recv_buf, u32 recv_buf_len);
|
||||
|
||||
/**
|
||||
* dsi_display_soft_reset() - perform a soft reset on DSI controller
|
||||
* @display: Handle to display
|
||||
*
|
||||
* The video, command and controller engines will be disabled before the
|
||||
* reset is triggered. After, the engines will be re-enabled to the same state
|
||||
* as before the reset.
|
||||
*
|
||||
* If the reset is done while MDP timing engine is turned on, the video
|
||||
* engine should be re-enabled only during the vertical blanking time.
|
||||
*
|
||||
* Return: error code
|
||||
*/
|
||||
int dsi_display_soft_reset(void *display);
|
||||
|
||||
/**
|
||||
* dsi_display_set_power - update power/dpms setting
|
||||
* @connector: Pointer to drm connector structure
|
||||
* @power_mode: One of the following,
|
||||
* SDE_MODE_DPMS_ON
|
||||
* SDE_MODE_DPMS_LP1
|
||||
* SDE_MODE_DPMS_LP2
|
||||
* SDE_MODE_DPMS_STANDBY
|
||||
* SDE_MODE_DPMS_SUSPEND
|
||||
* SDE_MODE_DPMS_OFF
|
||||
* @display: Pointer to private display structure
|
||||
* Returns: Zero on success
|
||||
*/
|
||||
int dsi_display_set_power(struct drm_connector *connector,
|
||||
int power_mode, void *display);
|
||||
|
||||
/*
|
||||
* dsi_display_pre_kickoff - program kickoff-time features
|
||||
* @connector: Pointer to drm connector structure
|
||||
* @display: Pointer to private display structure
|
||||
* @params: Parameters for kickoff-time programming
|
||||
* Returns: Zero on success
|
||||
*/
|
||||
int dsi_display_pre_kickoff(struct drm_connector *connector,
|
||||
struct dsi_display *display,
|
||||
struct msm_display_kickoff_params *params);
|
||||
|
||||
/*
|
||||
* dsi_display_pre_commit - program pre commit features
|
||||
* @display: Pointer to private display structure
|
||||
* @params: Parameters for pre commit time programming
|
||||
* Returns: Zero on success
|
||||
*/
|
||||
int dsi_display_pre_commit(void *display,
|
||||
struct msm_display_conn_params *params);
|
||||
|
||||
/**
|
||||
* dsi_display_get_dst_format() - get dst_format from DSI display
|
||||
* @connector: Pointer to drm connector structure
|
||||
* @display: Handle to display
|
||||
*
|
||||
* Return: enum dsi_pixel_format type
|
||||
*/
|
||||
enum dsi_pixel_format dsi_display_get_dst_format(
|
||||
struct drm_connector *connector,
|
||||
void *display);
|
||||
|
||||
/**
|
||||
* dsi_display_cont_splash_config() - initialize splash resources
|
||||
* @display: Handle to display
|
||||
*
|
||||
* Return: Zero on Success
|
||||
*/
|
||||
int dsi_display_cont_splash_config(void *display);
|
||||
|
||||
/**
|
||||
* dsi_display_cont_splash_res_disable() - Disable resource votes added in probe
|
||||
* @display: Pointer to dsi display
|
||||
* Returns: Zero on success
|
||||
*/
|
||||
int dsi_display_cont_splash_res_disable(void *display);
|
||||
|
||||
/*
|
||||
* dsi_display_get_panel_vfp - get panel vsync
|
||||
* @display: Pointer to private display structure
|
||||
* @h_active: width
|
||||
* @v_active: height
|
||||
* Returns: v_front_porch on success error code on failure
|
||||
*/
|
||||
int dsi_display_get_panel_vfp(void *display,
|
||||
int h_active, int v_active);
|
||||
|
||||
/**
|
||||
* dsi_display_dump_clks_state() - dump clocks state to console
|
||||
* @display: Handle to display
|
||||
*
|
||||
* Return: Zero on Success
|
||||
*/
|
||||
int dsi_display_dump_clks_state(struct dsi_display *display);
|
||||
|
||||
/**
|
||||
* dsi_display_dfps_update_parent() - update dsi clock parent to src clock
|
||||
* @display: Handle to display
|
||||
*/
|
||||
void dsi_display_dfps_update_parent(struct dsi_display *display);
|
||||
|
||||
#endif /* _DSI_DISPLAY_H_ */
|
96
techpack/display/msm/dsi/dsi_display_test.c
Normal file
96
techpack/display/msm/dsi/dsi_display_test.c
Normal file
@ -0,0 +1,96 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "dsi_display_test.h"
|
||||
|
||||
static void dsi_display_test_dump_modes(struct dsi_display_mode *mode, u32
|
||||
count)
|
||||
{
|
||||
}
|
||||
|
||||
static void dsi_display_test_work(struct work_struct *work)
|
||||
{
|
||||
struct dsi_display_test *test;
|
||||
struct dsi_display *display;
|
||||
struct dsi_display_mode *modes;
|
||||
u32 count = 0;
|
||||
int rc = 0;
|
||||
|
||||
test = container_of(work, struct dsi_display_test, test_work);
|
||||
|
||||
display = test->display;
|
||||
rc = dsi_display_get_mode_count(display, &count);
|
||||
if (rc) {
|
||||
DSI_ERR("failed to get modes count, rc=%d\n", rc);
|
||||
goto test_fail;
|
||||
}
|
||||
|
||||
rc = dsi_display_get_modes(display, &modes);
|
||||
if (rc) {
|
||||
DSI_ERR("failed to get modes, rc=%d\n", rc);
|
||||
goto test_fail_free_modes;
|
||||
}
|
||||
|
||||
dsi_display_test_dump_modes(modes, count);
|
||||
|
||||
rc = dsi_display_set_mode(display, &modes[0], 0x0);
|
||||
if (rc) {
|
||||
DSI_ERR("failed to set mode, rc=%d\n", rc);
|
||||
goto test_fail_free_modes;
|
||||
}
|
||||
|
||||
rc = dsi_display_prepare(display);
|
||||
if (rc) {
|
||||
DSI_ERR("failed to prepare display, rc=%d\n", rc);
|
||||
goto test_fail_free_modes;
|
||||
}
|
||||
|
||||
rc = dsi_display_enable(display);
|
||||
if (rc) {
|
||||
DSI_ERR("failed to enable display, rc=%d\n", rc);
|
||||
goto test_fail_unprep_disp;
|
||||
}
|
||||
return;
|
||||
|
||||
test_fail_unprep_disp:
|
||||
if (rc) {
|
||||
DSI_ERR("failed to unprep display, rc=%d\n", rc);
|
||||
goto test_fail_free_modes;
|
||||
}
|
||||
|
||||
test_fail_free_modes:
|
||||
kfree(modes);
|
||||
test_fail:
|
||||
return;
|
||||
}
|
||||
|
||||
int dsi_display_test_init(struct dsi_display *display)
|
||||
{
|
||||
static int done;
|
||||
int rc = 0;
|
||||
struct dsi_display_test *test;
|
||||
|
||||
if (done)
|
||||
return rc;
|
||||
|
||||
done = 1;
|
||||
if (!display) {
|
||||
DSI_ERR("Invalid params\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
test = kzalloc(sizeof(*test), GFP_KERNEL);
|
||||
if (!test)
|
||||
return -ENOMEM;
|
||||
|
||||
test->display = display;
|
||||
INIT_WORK(&test->test_work, dsi_display_test_work);
|
||||
|
||||
dsi_display_test_work(&test->test_work);
|
||||
return rc;
|
||||
}
|
22
techpack/display/msm/dsi/dsi_display_test.h
Normal file
22
techpack/display/msm/dsi/dsi_display_test.h
Normal file
@ -0,0 +1,22 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _DSI_DISPLAY_TEST_H_
|
||||
#define _DSI_DISPLAY_TEST_H_
|
||||
|
||||
#include "dsi_display.h"
|
||||
#include "dsi_ctrl_hw.h"
|
||||
#include "dsi_ctrl.h"
|
||||
|
||||
struct dsi_display_test {
|
||||
struct dsi_display *display;
|
||||
|
||||
struct work_struct test_work;
|
||||
};
|
||||
|
||||
int dsi_display_test_init(struct dsi_display *display);
|
||||
|
||||
|
||||
#endif /* _DSI_DISPLAY_TEST_H_ */
|
1269
techpack/display/msm/dsi/dsi_drm.c
Normal file
1269
techpack/display/msm/dsi/dsi_drm.c
Normal file
File diff suppressed because it is too large
Load Diff
158
techpack/display/msm/dsi/dsi_drm.h
Normal file
158
techpack/display/msm/dsi/dsi_drm.h
Normal file
@ -0,0 +1,158 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _DSI_DRM_H_
|
||||
#define _DSI_DRM_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_crtc.h>
|
||||
|
||||
#include "msm_drv.h"
|
||||
|
||||
#include "dsi_display.h"
|
||||
|
||||
#define NO_OVERRIDE -1
|
||||
|
||||
struct dsi_bridge {
|
||||
struct drm_bridge base;
|
||||
u32 id;
|
||||
|
||||
struct dsi_display *display;
|
||||
struct dsi_display_mode dsi_mode;
|
||||
};
|
||||
|
||||
/**
|
||||
* dsi_conn_set_info_blob - callback to perform info blob initialization
|
||||
* @connector: Pointer to drm connector structure
|
||||
* @info: Pointer to sde connector info structure
|
||||
* @display: Pointer to private display handle
|
||||
* @mode_info: Pointer to mode info structure
|
||||
* Returns: Zero on success
|
||||
*/
|
||||
int dsi_conn_set_info_blob(struct drm_connector *connector,
|
||||
void *info,
|
||||
void *display,
|
||||
struct msm_mode_info *mode_info);
|
||||
|
||||
/**
|
||||
* dsi_conn_detect - callback to determine if connector is connected
|
||||
* @connector: Pointer to drm connector structure
|
||||
* @force: Force detect setting from drm framework
|
||||
* @display: Pointer to private display handle
|
||||
* Returns: Connector 'is connected' status
|
||||
*/
|
||||
enum drm_connector_status dsi_conn_detect(struct drm_connector *conn,
|
||||
bool force,
|
||||
void *display);
|
||||
|
||||
/**
|
||||
* dsi_connector_get_modes - callback to add drm modes via drm_mode_probed_add()
|
||||
* @connector: Pointer to drm connector structure
|
||||
* @display: Pointer to private display handle
|
||||
* @avail_res: Pointer with curr available resources
|
||||
* Returns: Number of modes added
|
||||
*/
|
||||
int dsi_connector_get_modes(struct drm_connector *connector,
|
||||
void *display, const struct msm_resource_caps_info *avail_res);
|
||||
|
||||
/**
|
||||
* dsi_connector_put_modes - callback to free up drm modes of the connector
|
||||
* @connector: Pointer to drm connector structure
|
||||
* @display: Pointer to private display handle
|
||||
*/
|
||||
void dsi_connector_put_modes(struct drm_connector *connector,
|
||||
void *display);
|
||||
|
||||
/**
|
||||
* dsi_conn_get_mode_info - retrieve information on the mode selected
|
||||
* @drm_mode: Display mode set for the display
|
||||
* @mode_info: Out parameter. information of the mode.
|
||||
* @display: Pointer to private display structure
|
||||
* @avail_res: Pointer with curr available resources
|
||||
* Returns: Zero on success
|
||||
*/
|
||||
int dsi_conn_get_mode_info(struct drm_connector *connector,
|
||||
const struct drm_display_mode *drm_mode,
|
||||
struct msm_mode_info *mode_info,
|
||||
void *display, const struct msm_resource_caps_info *avail_res);
|
||||
|
||||
/**
|
||||
* dsi_conn_mode_valid - callback to determine if specified mode is valid
|
||||
* @connector: Pointer to drm connector structure
|
||||
* @mode: Pointer to drm mode structure
|
||||
* @display: Pointer to private display handle
|
||||
* @avail_res: Pointer with curr available resources
|
||||
* Returns: Validity status for specified mode
|
||||
*/
|
||||
enum drm_mode_status dsi_conn_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode,
|
||||
void *display, const struct msm_resource_caps_info *avail_res);
|
||||
|
||||
/**
|
||||
* dsi_conn_enable_event - callback to notify DSI driver of event registration
|
||||
* @connector: Pointer to drm connector structure
|
||||
* @event_idx: Connector event index
|
||||
* @enable: Whether or not the event is enabled
|
||||
* @display: Pointer to private display handle
|
||||
*/
|
||||
void dsi_conn_enable_event(struct drm_connector *connector,
|
||||
uint32_t event_idx, bool enable, void *display);
|
||||
|
||||
struct dsi_bridge *dsi_drm_bridge_init(struct dsi_display *display,
|
||||
struct drm_device *dev,
|
||||
struct drm_encoder *encoder);
|
||||
|
||||
void dsi_drm_bridge_cleanup(struct dsi_bridge *bridge);
|
||||
|
||||
/**
|
||||
* dsi_display_pre_kickoff - program kickoff-time features
|
||||
* @connector: Pointer to drm connector structure
|
||||
* @display: Pointer to private display structure
|
||||
* @params: Parameters for kickoff-time programming
|
||||
* Returns: Zero on success
|
||||
*/
|
||||
int dsi_conn_pre_kickoff(struct drm_connector *connector,
|
||||
void *display,
|
||||
struct msm_display_kickoff_params *params);
|
||||
|
||||
/**
|
||||
* dsi_display_post_kickoff - program post kickoff-time features
|
||||
* @connector: Pointer to drm connector structure
|
||||
* @params: Parameters for post kickoff programming
|
||||
* Returns: Zero on success
|
||||
*/
|
||||
int dsi_conn_post_kickoff(struct drm_connector *connector,
|
||||
struct msm_display_conn_params *params);
|
||||
|
||||
/**
|
||||
* dsi_convert_to_drm_mode - Update drm mode with dsi mode information
|
||||
* @dsi_mode: input parameter. structure having dsi mode information.
|
||||
* @drm_mode: output parameter. DRM mode set for the display
|
||||
*/
|
||||
void dsi_convert_to_drm_mode(const struct dsi_display_mode *dsi_mode,
|
||||
struct drm_display_mode *drm_mode);
|
||||
|
||||
u64 dsi_drm_find_bit_clk_rate(void *display,
|
||||
const struct drm_display_mode *drm_mode);
|
||||
|
||||
/**
|
||||
* dsi_conn_prepare_commit - program pre commit time features
|
||||
* @display: Pointer to private display structure
|
||||
* @params: Parameters for pre commit programming
|
||||
* Returns: Zero on success
|
||||
*/
|
||||
int dsi_conn_prepare_commit(void *display,
|
||||
struct msm_display_conn_params *params);
|
||||
|
||||
/**
|
||||
* dsi_set_allowed_mode_switch - set allowed mode switch bitmask
|
||||
* @connector: Pointer to drm connector structure
|
||||
* @display: Pointer to private display structure
|
||||
*/
|
||||
void dsi_conn_set_allowed_mode_switch(struct drm_connector *connector,
|
||||
void *display);
|
||||
|
||||
#endif /* _DSI_DRM_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