Add 'qcom/opensource/display-drivers/' from commit '5ff96e683134b356ebe6c37069b4197034502ef9'

git-subtree-dir: qcom/opensource/display-drivers
git-subtree-mainline: 2d61911ef6
git-subtree-split: 5ff96e6831
Change-Id:
repo: https://git.codelinaro.org/clo/la/platform/vendor/opensource/display-drivers
tag: DISPLAY.LA.4.0.r2-07600-lanai.0
This commit is contained in:
David Wronek 2024-10-06 16:44:29 +02:00
commit 1841c0f616
337 changed files with 239264 additions and 0 deletions

View 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
}

View File

@ -0,0 +1,12 @@
# Android makefile for display kernel modules
DISPLAY_DLKM_ENABLE := true
ifeq ($(TARGET_KERNEL_DLKM_DISABLE), true)
ifeq ($(TARGET_KERNEL_DLKM_DISPLAY_OVERRIDE), false)
DISPLAY_DLKM_ENABLE := false
endif
endif
ifeq ($(DISPLAY_DLKM_ENABLE), true)
LOCAL_PATH := $(call my-dir)
include $(LOCAL_PATH)/msm/Android.mk
endif

View File

@ -0,0 +1,72 @@
load("//build/kernel/kleaf:kernel.bzl", "ddk_headers")
package(
default_visibility = [
"//visibility:public"],
)
ddk_headers(
name = "linux_includes",
hdrs = glob([
"include/linux/*.h",
]),
includes = ["include"]
)
ddk_headers(
name = "uapi_headers",
hdrs = glob([
"include/uapi/display/drm/*.h",
"include/uapi/display/hdcp/*.h",
"include/uapi/display/media/*.h",
]),
includes = ["include/uapi/display"]
)
ddk_headers(
name = "dp_headers",
hdrs = glob([
"msm/dp/*.h",
]),
includes = ["msm/dp"]
)
ddk_headers(
name = "dsi_headers",
hdrs = glob([
"msm/dsi/*.h",
]),
includes = ["msm/dsi"]
)
ddk_headers(
name = "sde_headers",
hdrs = glob([
"msm/sde/*.h",
]),
includes = ["msm/sde"]
)
ddk_headers(
name = "rotator_headers",
hdrs = glob([
"rotator/*.h",
]),
includes = ["rotator"]
)
ddk_headers(
name = "msm_headers",
hdrs = glob([
"msm/*.h",
]),
includes = ["msm"]
)
ddk_headers(
name = "display_drivers_headers",
hdrs = [ ":linux_includes", ":uapi_headers", ":msm_headers",":dp_headers",":dsi_headers",":sde_headers",":rotator_headers"]
)
load(":target.bzl", "define_display_target")
define_display_target()

View File

@ -0,0 +1,58 @@
QTI Snapdragon Display Engine (SDE) DP-MST sideband message emulation driver
Required properties:
- compatible: "qcom,dp-mst-sim"
Each child node represents a port at root branch, with properties:
- qcom,mode-h-active: A u32 property defines the horizontal active size.
- qcom,mode-h-front-porch: A u32 property defines the horizontal front porch.
- qcom,mode-h-pulse-width: A u32 property defines the horizontal pulse.
- qcom,mode-h-back-porch: A u32 property defines the horizontal back porch.
- qcom,mode-h-active-high: A boolean property if horizontal polarity is high.
- qcom,mode-v-active: A u32 property defines the vertical active size.
- qcom,mode-v-front-porch: A u32 property defines the vertical front portch.
- qcom,mode-v-pulse-width: A u32 property defines the vertical pulse width.
- qcom,mode-v-back-porch: A u32 property defines the vertical back porch.
- qcom,mode-v-active-high: A boolean property if vertical polarity is high.
- qcom,mode-refresh-rate: A u32 property defines vertial refresh rate.
- qcom,mode-clock-in-khz: A u32 property defines clock in kHz.
Example:
/ {
...
sde_dp_mst_sim: qcom,dp-mst-sim {
compatible = "qcom,dp-mst-sim";
port@0 {
qcom,mode-h-active = <1920>;
qcom,mode-h-front-porch = <88>;
qcom,mode-h-pulse-width = <44>;
qcom,mode-h-back-porch = <148>;
qcom,mode-h-active-high;
qcom,mode-v-active = <1080>;
qcom,mode-v-front-porch = <4>;
qcom,mode-v-pulse-width = <5>;
qcom,mode-v-back-porch = <36>;
qcom,mode-v-active-high;
qcom,mode-refresh-rate = <60>;
qcom,mode-clock-in-khz = <148500>;
};
port@1 {
qcom,mode-h-active = <1920>;
qcom,mode-h-front-porch = <88>;
qcom,mode-h-pulse-width = <44>;
qcom,mode-h-back-porch = <148>;
qcom,mode-h-active-high;
qcom,mode-v-active = <1080>;
qcom,mode-v-front-porch = <4>;
qcom,mode-v-pulse-width = <5>;
qcom,mode-v-back-porch = <36>;
qcom,mode-v-active-high;
qcom,mode-refresh-rate = <60>;
qcom,mode-clock-in-khz = <148500>;
};
};
};

View File

@ -0,0 +1,12 @@
# SPDX-License-Identifier: GPL-2.0-only
ifeq ($(DISPLAY_ROOT),)
DISPLAY_ROOT=$(srctree)/techpack/display
endif
LINUXINCLUDE += \
-I$(DISPLAY_ROOT)/include/uapi/display \
-I$(DISPLAY_ROOT)/include
USERINCLUDE += -I$(DISPLAY_ROOT)/include/uapi/display
obj-$(CONFIG_DRM_MSM) += msm/

View File

@ -0,0 +1,16 @@
# SPDX-License-Identifier: GPL-2.0-only
KBUILD_OPTIONS+= DISPLAY_ROOT=$(KERNEL_SRC)/$(M)
all:
$(MAKE) -C $(KERNEL_SRC) M=$(M) modules $(KBUILD_OPTIONS)
modules_install:
$(MAKE) INSTALL_MOD_STRIP=1 -C $(KERNEL_SRC) M=$(M) modules_install
%:
$(MAKE) -C $(KERNEL_SRC) M=$(M) $@ $(KBUILD_OPTIONS)
clean:
rm -f *.o *.ko *.mod.c *.mod.o *~ .*.cmd Module.symvers
rm -rf .tmp_versions

View File

@ -0,0 +1,24 @@
# SPDX-License-Identifier: GPL-2.0-only
DISPLAY_ROOT=$(ROOTDIR)display/vendor/qcom/opensource/display-drivers
CONFIG_DRM_MSM=$(MODULE_DRM_MSM)
KBUILD_OPTIONS := DISPLAY_ROOT=$(DISPLAY_ROOT) CONFIG_DRM_MSM=$(CONFIG_DRM_MSM)
ifeq ($(TARGET_SUPPORT),genericarmv8)
KBUILD_OPTIONS += CONFIG_ARCH_PINEAPPLE=y
endif
obj-m += msm/
all:
$(MAKE) -C $(KERNEL_SRC) M=$(M) modules $(KBUILD_OPTIONS)
modules_install:
$(MAKE) INSTALL_MOD_STRIP=1 -C $(KERNEL_SRC) M=$(M) modules_install
%:
$(MAKE) -C $(KERNEL_SRC) M=$(M) $@ $(KBUILD_OPTIONS)
clean:
rm -f *.o *.ko *.mod.c *.mod.o *~ .*.cmd Module.symvers
rm -rf .tmp_versions

View File

@ -0,0 +1,93 @@
/* 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 (c) 2009 Keith Packard
*
* 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.
*/
/*
* Copyright (c) 2008 Keith Packard
*
* 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.
*/
/*
* 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.
*/

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,18 @@
# SPDX-License-Identifier: GPL-2.0-only
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_DRM_MSM_DP_MST=n
export CONFIG_QCOM_MDSS_PLL=y
export CONFIG_DRM_SDE_RSC=n
export CONFIG_DRM_SDE_WB=n
export CONFIG_DRM_MSM_REGISTER_LOGGING=n
export CONFIG_SDE_RECOVERY_MANAGER=n
export CONFIG_DRM_SDE_SHD=n
export CONFIG_DRM_SDE_SHP=n
export CONFIG_DRM_SDE_ROI_MISR=n
export CONFIG_DRM_MSM_LEASE=n
export CONFIG_DISPLAY_BUILD=m

View File

@ -0,0 +1,22 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. 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 0
#define CONFIG_DRM_MSM_DP_MST 0
#define CONFIG_DRM_SDE_WB 0
#define CONFIG_DRM_SDE_RSC 0
#define CONFIG_DRM_MSM_REGISTER_LOGGING 0
#define CONFIG_DRM_SDE_EVTLOG_DEBUG 1
#define CONFIG_QCOM_MDSS_PLL 1
#define CONFIG_GKI_DISPLAY 1
#define CONFIG_MSM_EXT_DISPLAY 1
#define CONFIG_DRM_SDE_ROI_MISR 0
#define CONFIG_DRM_SDE_SHD 0
#define CONFIG_DRM_SDE_SHP 0
#define CONFIG_DRM_MSM_LEASE 0

View 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

View 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

View File

@ -0,0 +1,18 @@
# 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_DISPLAY_BUILD=m
export CONFIG_MSM_SDE_ROTATOR=y
export CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y
export CONFIG_MSM_SDE_ROTATOR_INIT_ONLY=y

View File

@ -0,0 +1,17 @@
/* 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_GKI_DISPLAY 1
#define CONFIG_MSM_SDE_ROTATOR 1
#define CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG 1
#define CONFIG_MSM_SDE_ROTATOR_INIT_ONLY 1

View File

@ -0,0 +1,18 @@
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_RSC=y
export CONFIG_DRM_SDE_WB=y
export CONFIG_DRM_MSM_REGISTER_LOGGING=y
export CONFIG_MSM_MMRM=y
export CONFIG_DISPLAY_BUILD=m
export CONFIG_HDCP_QSEECOM=y
export CONFIG_DRM_SDE_VM=y
export CONFIG_QTI_HW_FENCE=y
export CONFIG_QCOM_SPEC_SYNC=y
export CONFIG_QCOM_FSA4480_I2C=y

View File

@ -0,0 +1,26 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
* 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_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_SDE_RSC 1
#define CONFIG_DRM_MSM_REGISTER_LOGGING 1
#define CONFIG_MSM_MMRM 1
#define CONFIG_DRM_SDE_EVTLOG_DEBUG 1
#define CONFIG_QCOM_MDSS_PLL 1
#define CONFIG_GKI_DISPLAY 1
#define CONFIG_MSM_EXT_DISPLAY 1
#define CONFIG_HDCP_QSEECOM 1
#define CONFIG_DRM_SDE_VM 1
#define CONFIG_QTI_HW_FENCE 1
#define CONFIG_QCOM_SPEC_SYNC 1
#define CONFIG_QCOM_FSA4480_I2C 1

View File

@ -0,0 +1,10 @@
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_QCOM_MDSS_PLL=y
export CONFIG_DRM_MSM_REGISTER_LOGGING=y
export CONFIG_DISPLAY_BUILD=m
export CONFIG_DRM_SDE_VM=y
export CONFIG_DRM_LOW_MSM_MEM_FOOTPRINT=y

View File

@ -0,0 +1,17 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
* 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_DRM_SDE_EVTLOG_DEBUG 1
#define CONFIG_QCOM_MDSS_PLL 1
#define CONFIG_GKI_DISPLAY 1
#define CONFIG_DRM_SDE_VM 1
#define CONFIG_DRM_MSM_LOW_MEM_FOOTPRINT 1

View 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

View 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

View File

@ -0,0 +1,11 @@
# 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_QCOM_MDSS_PLL=y
export CONFIG_DRM_MSM_REGISTER_LOGGING=y
export CONFIG_DISPLAY_BUILD=m

View File

@ -0,0 +1,14 @@
/* 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_DRM_SDE_EVTLOG_DEBUG 1
#define CONFIG_QCOM_MDSS_PLL 1
#define CONFIG_GKI_DISPLAY 1

View File

@ -0,0 +1,16 @@
# SPDX-License-Identifier: GPL-2.0-only
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_QCOM_MDSS_PLL=y
export CONFIG_DRM_SDE_RSC=y
export CONFIG_DRM_SDE_WB=y
export CONFIG_DRM_MSM_REGISTER_LOGGING=y
export CONFIG_MSM_MMRM=y
export CONFIG_DISPLAY_BUILD=m
export CONFIG_DRM_SDE_SYSTEM_SLEEP_DISABLE=y
export CONFIG_DRM_SDE_IPCC=y
export CONFIG_DRM_SDE_MINIDUMP_DISABLE=y

View File

@ -0,0 +1,22 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. 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_SDE_WB 1
#define CONFIG_DRM_SDE_RSC 1
#define CONFIG_DRM_MSM_REGISTER_LOGGING 1
#define CONFIG_MSM_MMRM 1
#define CONFIG_DRM_SDE_EVTLOG_DEBUG 1
#define CONFIG_QCOM_MDSS_PLL 1
#define CONFIG_GKI_DISPLAY 1
#define CONFIG_MSM_EXT_DISPLAY 1
#define CONFIG_DRM_SDE_SYSTEM_SLEEP_DISABLE 1
#define CONFIG_DRM_SDE_IPCC 1
#define CONFIG_DRM_SDE_MINIDUMP_DISABLE 1

View File

@ -0,0 +1,11 @@
# SPDX-License-Identifier: GPL-2.0-only
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=y
export CONFIG_QCOM_MDSS_PLL=y
export CONFIG_DRM_MSM_REGISTER_LOGGING=y
export CONFIG_DISPLAY_BUILD=m

View File

@ -0,0 +1,16 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. 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_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

View File

@ -0,0 +1,18 @@
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_RSC=y
export CONFIG_DRM_SDE_WB=y
export CONFIG_DRM_MSM_REGISTER_LOGGING=y
export CONFIG_MSM_MMRM=y
export CONFIG_DISPLAY_BUILD=m
export CONFIG_HDCP_QSEECOM=y
export CONFIG_DRM_SDE_VM=y
export CONFIG_QTI_HW_FENCE=y
export CONFIG_QCOM_SPEC_SYNC=y
export CONFIG_QCOM_WCD939X_I2C=y

View File

@ -0,0 +1,26 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. 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_SDE_RSC 1
#define CONFIG_DRM_MSM_REGISTER_LOGGING 1
#define CONFIG_MSM_MMRM 1
#define CONFIG_DRM_SDE_EVTLOG_DEBUG 1
#define CONFIG_QCOM_MDSS_PLL 1
#define CONFIG_GKI_DISPLAY 1
#define CONFIG_MSM_EXT_DISPLAY 1
#define CONFIG_HDCP_QSEECOM 1
#define CONFIG_DRM_SDE_VM 1
#define CONFIG_QTI_HW_FENCE 1
#define CONFIG_QCOM_SPEC_SYNC 1
#define CONFIG_QCOM_WCD939X_I2C 1

View File

@ -0,0 +1,10 @@
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_QCOM_MDSS_PLL=y
export CONFIG_DRM_MSM_REGISTER_LOGGING=y
export CONFIG_DISPLAY_BUILD=m
export CONFIG_DRM_SDE_VM=y
export CONFIG_DRM_LOW_MSM_MEM_FOOTPRINT=y

View File

@ -0,0 +1,17 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. 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_DRM_SDE_VM 1
#define CONFIG_DRM_MSM_LOW_MEM_FOOTPRINT 1

View File

@ -0,0 +1,11 @@
# SPDX-License-Identifier: GPL-2.0-only
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_QCOM_MDSS_PLL=y
export CONFIG_DRM_MSM_REGISTER_LOGGING=y
export CONFIG_DISPLAY_BUILD=m
export CONFIG_QCOM_SPEC_SYNC=y

View File

@ -0,0 +1,17 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. 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_EXT_DISPLAY 1
#define CONFIG_QCOM_SPEC_SYNC 1

View File

@ -0,0 +1,15 @@
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_RSC=y
export CONFIG_DRM_SDE_WB=y
export CONFIG_DRM_MSM_REGISTER_LOGGING=y
export CONFIG_MSM_MMRM=y
export CONFIG_DISPLAY_BUILD=m
export CONFIG_DRM_SDE_VM=y
export CONFIG_HDCP_QSEECOM=y

View File

@ -0,0 +1,22 @@
/* 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_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_SDE_RSC 1
#define CONFIG_DRM_MSM_REGISTER_LOGGING 1
#define CONFIG_MSM_MMRM 1
#define CONFIG_DRM_SDE_EVTLOG_DEBUG 1
#define CONFIG_QCOM_MDSS_PLL 1
#define CONFIG_GKI_DISPLAY 1
#define CONFIG_MSM_EXT_DISPLAY 1
#define CONFIG_DRM_SDE_VM 1
#define CONFIG_HDCP_QSEECOM 1

View File

@ -0,0 +1,10 @@
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_QCOM_MDSS_PLL=y
export CONFIG_DRM_MSM_REGISTER_LOGGING=y
export CONFIG_DISPLAY_BUILD=m
export CONFIG_DRM_SDE_VM=y
export CONFIG_DRM_LOW_MSM_MEM_FOOTPRINT=y

View File

@ -0,0 +1,16 @@
/* 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_DRM_SDE_EVTLOG_DEBUG 1
#define CONFIG_QCOM_MDSS_PLL 1
#define CONFIG_GKI_DISPLAY 1
#define CONFIG_DRM_SDE_VM 1
#define CONFIG_DRM_MSM_LOW_MEM_FOOTPRINT 1

View 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

View 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

View 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

View 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

View 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=y
export CONFIG_DRM_SDE_VM=y

View 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

View 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

View 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

View File

@ -0,0 +1,15 @@
#SPDX-License-Identifier: GPL-2.0-only
DISPLAY_DLKM_ENABLE := true
ifeq ($(TARGET_KERNEL_DLKM_DISABLE), true)
ifeq ($(TARGET_KERNEL_DLKM_DISPLAY_OVERRIDE), false)
DISPLAY_DLKM_ENABLE := false
endif
endif
ifeq ($(DISPLAY_DLKM_ENABLE), true)
ifeq ($(call is-board-platform-in-list,$(TARGET_BOARD_PLATFORM)),true)
BOARD_VENDOR_KERNEL_MODULES += $(KERNEL_MODULES_OUT)/msm_drm.ko
BOARD_VENDOR_RAMDISK_KERNEL_MODULES += $(KERNEL_MODULES_OUT)/msm_drm.ko
BOARD_VENDOR_RAMDISK_RECOVERY_KERNEL_MODULES_LOAD += $(KERNEL_MODULES_OUT)/msm_drm.ko
endif
endif

View File

@ -0,0 +1,124 @@
load("//build/kernel/kleaf:kernel.bzl", "ddk_module", "ddk_submodule")
load("//build/bazel_common_rules/dist:dist.bzl", "copy_to_dist_dir")
def _register_module_to_map(module_map, name, path, config_option, srcs, config_srcs, deps, config_deps):
processed_config_srcs = {}
nested_config = {}
processed_config_deps = {}
for config_src_name in config_srcs:
config_src = config_srcs[config_src_name]
if type(config_src) == "list":
processed_config_srcs[config_src_name] = {True: config_src}
else:
processed_config_srcs[config_src_name] = config_src
if type(config_src) == "dict":
nested_config = config_src
for nested_src, nest_name in nested_config.items():
if nested_src == True:
processed_config_srcs[config_src_name] = {True: nest_name}
else:
processed_config_srcs[nested_src] = {True: nest_name}
for config_deps_name in config_deps:
config_dep = config_deps[config_deps_name]
if type(config_dep) == "list":
processed_config_deps[config_deps_name] = {True: config_dep}
else:
processed_config_deps[config_deps_name] = config_dep
module = struct(
name = name,
path = path,
srcs = srcs,
config_srcs = processed_config_srcs,
config_option = config_option,
deps = deps,
config_deps = processed_config_deps
)
module_map[name] = module
def _get_config_choices(map, options):
choices = []
for option in map:
choices.extend(map[option].get(option in options,[]))
return choices
def _get_kernel_build_options(modules, config_options):
all_options = {option: True for option in config_options}
all_options = all_options | {module.config_option: True for module in modules if module.config_option}
return all_options
def _get_kernel_build_module_srcs(module, options, formatter):
srcs = module.srcs + _get_config_choices(module.config_srcs, options)
module_path = "{}/".format(module.path) if module.path else ""
return ["{}{}".format(module_path, formatter(src)) for src in srcs]
def _get_kernel_build_module_deps(module, options, formatter):
deps = module.deps + _get_config_choices(module.config_deps, options)
return [formatter(dep) for dep in deps]
def display_module_entry(hdrs = []):
module_map = {}
def register(name, path = None, config_option = None, srcs = [], config_srcs = {}, deps = [], config_deps = {}):
_register_module_to_map(module_map, name, path, config_option, srcs, config_srcs, deps, config_deps)
return struct(
register = register,
get = module_map.get,
hdrs = hdrs,
module_map = module_map
)
def define_target_variant_modules(target, variant, registry, modules, config_options = [], lunch_target=None):
kernel_build_hdr = "{}_{}".format(target, variant)
kernel_build_label = "//msm-kernel:{}".format(kernel_build_hdr)
if lunch_target != None:
kernel_build = "{}_{}_{}".format(target, variant, lunch_target)
else:
kernel_build = "{}_{}".format(target, variant)
modules = [registry.get(module_name) for module_name in modules]
options = _get_kernel_build_options(modules, config_options)
build_print = lambda message : print("{}: {}".format(kernel_build, message))
formatter = lambda s : s.replace("%b", kernel_build).replace("%t", target)
formatter_hdr = lambda s : s.replace("%b", kernel_build_hdr).replace("%t", target)
headers = ["//msm-kernel:all_headers"] + registry.hdrs
all_module_rules = []
for module in modules:
rule_name = "{}_{}".format(kernel_build, module.name)
module_srcs = _get_kernel_build_module_srcs(module, options, formatter)
print(rule_name)
if not module_srcs:
continue
ddk_submodule(
name = rule_name,
srcs = module_srcs,
out = "{}.ko".format(module.name),
deps = headers + _get_kernel_build_module_deps(module, options, formatter_hdr),
local_defines = options.keys(),
)
all_module_rules.append(rule_name)
ddk_module(
name = "{}_display_drivers".format(kernel_build),
kernel_build = kernel_build_label,
deps = all_module_rules,
)
copy_to_dist_dir(
name = "{}_display_drivers_dist".format(kernel_build),
data = [":{}_display_drivers".format(kernel_build)],
dist_dir = "out/target/product/{}/dlkm/lib/modules/".format(target),
flat = True,
wipe_dist_dir = False,
allow_duplicate_filenames = False,
mode_overrides = {"**/*": "644"},
log = "info",
)

View File

@ -0,0 +1,14 @@
# SPDX-License-Identifier: GPL-2.0-only
DISPLAY_DLKM_ENABLE := true
ifeq ($(TARGET_KERNEL_DLKM_DISABLE), true)
ifeq ($(TARGET_KERNEL_DLKM_DISPLAY_OVERRIDE), false)
DISPLAY_DLKM_ENABLE := false
endif
endif
ifeq ($(DISPLAY_DLKM_ENABLE), true)
PRODUCT_PACKAGES += msm_drm.ko
endif
DISPLAY_MODULES_DRIVER := msm_drm.ko

View File

@ -0,0 +1,93 @@
# Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 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())

View File

@ -0,0 +1,195 @@
load(":display_driver_build.bzl", "display_module_entry")
display_driver_modules = display_module_entry([":display_drivers_headers"])
module_entry = display_driver_modules.register
#---------- MSM-DRM MODULE -------------------------
module_entry(
name = "msm_drm",
config_option = "CONFIG_DRM_MSM",
path = None,
config_srcs = {
"CONFIG_HDCP_QSEECOM": [
"hdcp/msm_hdcp.c",
"msm/dp/dp_hdcp2p2.c",
"msm/sde_hdcp_1x.c",
"msm/sde_hdcp_2x.c",
],
"CONFIG_DRM_SDE_VM" : [
"msm/sde/sde_vm_common.c",
"msm/sde/sde_vm_primary.c",
"msm/sde/sde_vm_trusted.c",
"msm/sde/sde_vm_msgq.c",
],
"CONFIG_DRM_MSM_DP" : [
"msm/dp/dp_altmode.c",
"msm/dp/dp_parser.c",
"msm/dp/dp_power.c",
"msm/dp/dp_catalog.c",
"msm/dp/dp_catalog_v420.c",
"msm/dp/dp_catalog_v200.c",
"msm/dp/dp_aux.c",
"msm/dp/dp_panel.c",
"msm/dp/dp_link.c",
"msm/dp/dp_ctrl.c",
"msm/dp/dp_audio.c",
"msm/dp/dp_debug.c",
"msm/dp/dp_hpd.c",
"msm/dp/dp_aux_bridge.c",
"msm/dp/dp_bridge_hpd.c",
"msm/dp/dp_mst_sim.c",
"msm/dp/dp_mst_sim_helper.c",
"msm/dp/dp_gpio_hpd.c",
"msm/dp/dp_lphw_hpd.c",
"msm/dp/dp_display.c",
"msm/dp/dp_drm.c",
"msm/dp/dp_pll.c",
"msm/dp/dp_pll_5nm.c",
"msm/dp/dp_pll_4nm.c",
],
"CONFIG_DRM_MSM_DP_MST" : [
"msm/dp/dp_mst_drm.c",
],
"CONFIG_DRM_MSM_DP_USBPD_LEGACY" : [
"msm/dp/dp_usbpd.c",
],
"CONFIG_DRM_MSM_SDE" : [
"msm/sde/sde_crtc.c",
"msm/sde/sde_encoder.c",
"msm/sde/sde_encoder_dce.c",
"msm/sde/sde_encoder_phys_vid.c",
"msm/sde/sde_encoder_phys_cmd.c",
"msm/sde/sde_irq.c",
"msm/sde/sde_core_irq.c",
"msm/sde/sde_core_perf.c",
"msm/sde/sde_rm.c",
"msm/sde/sde_kms_utils.c",
"msm/sde/sde_kms.c",
"msm/sde/sde_plane.c",
"msm/sde/sde_connector.c",
"msm/sde/sde_color_processing.c",
"msm/sde/sde_vbif.c",
"msm/sde_dbg.c",
"msm/sde_dbg_evtlog.c",
"msm/sde_io_util.c",
"msm/sde_vm_event.c",
"msm/sde/sde_hw_reg_dma_v1_color_proc.c",
"msm/sde/sde_hw_color_proc_v4.c",
"msm/sde/sde_hw_ad4.c",
"msm/sde/sde_hw_uidle.c",
"msm/sde_edid_parser.c",
"msm/sde/sde_hw_catalog.c",
"msm/sde/sde_hw_cdm.c",
"msm/sde/sde_hw_dspp.c",
"msm/sde/sde_hw_intf.c",
"msm/sde/sde_hw_lm.c",
"msm/sde/sde_hw_ctl.c",
"msm/sde/sde_hw_util.c",
"msm/sde/sde_hw_sspp.c",
"msm/sde/sde_hw_wb.c",
"msm/sde/sde_hw_pingpong.c",
"msm/sde/sde_hw_top.c",
"msm/sde/sde_hw_interrupts.c",
"msm/sde/sde_hw_vbif.c",
"msm/sde/sde_formats.c",
"msm/sde_power_handle.c",
"msm/sde/sde_hw_color_processing_v1_7.c",
"msm/sde/sde_reg_dma.c",
"msm/sde/sde_hw_reg_dma_v1.c",
"msm/sde/sde_hw_dsc.c",
"msm/sde/sde_hw_dsc_1_2.c",
"msm/sde/sde_hw_vdc.c",
"msm/sde/sde_hw_ds.c",
"msm/sde/sde_fence.c",
"msm/sde/sde_hw_qdss.c",
"msm/sde_dsc_helper.c",
"msm/sde_vdc_helper.c",
"msm/sde/sde_hw_dnsc_blur.c",
"msm/sde/sde_hw_rc.c",
],
"CONFIG_DRM_SDE_WB" : [
"msm/sde/sde_wb.c",
"msm/sde/sde_encoder_phys_wb.c"
],
"CONFIG_DRM_SDE_RSC" : [
"msm/sde_rsc.c",
"msm/sde_rsc_hw.c",
"msm/sde_rsc_hw_v3.c",
],
"CONFIG_DRM_MSM_DSI" : [
"msm/dsi/dsi_phy.c",
"msm/dsi/dsi_pwr.c",
"msm/dsi/dsi_phy_hw_v3_0.c",
"msm/dsi/dsi_phy_hw_v4_0.c",
"msm/dsi/dsi_phy_hw_v5_0.c",
"msm/dsi/dsi_phy_timing_calc.c",
"msm/dsi/dsi_phy_timing_v3_0.c",
"msm/dsi/dsi_phy_timing_v4_0.c",
"msm/dsi/dsi_pll.c",
"msm/dsi/dsi_pll_5nm.c",
"msm/dsi/dsi_pll_4nm.c",
"msm/dsi/dsi_ctrl_hw_cmn.c",
"msm/dsi/dsi_ctrl_hw_2_2.c",
"msm/dsi/dsi_ctrl.c",
"msm/dsi/dsi_catalog.c",
"msm/dsi/dsi_drm.c",
"msm/dsi/dsi_display.c",
"msm/dsi/dsi_panel.c",
"msm/dsi/dsi_clk_manager.c",
"msm/dsi/dsi_display_test.c",
],
"CONFIG_DSI_PARSER" : [
"msm/dsi/dsi_parser.c",
],
"CONFIG_THERMAL_OF" : [
"msm/msm_cooling_device.c",
],
"CONFIG_DRM_MSM" : [
"msm/msm_atomic.c",
"msm/msm_fb.c",
"msm/msm_drv.c",
"msm/msm_gem.c",
"msm/msm_gem_prime.c",
"msm/msm_gem_vma.c",
"msm/msm_smmu.c",
"msm/msm_prop.c",
],
"CONFIG_MSM_SDE_ROTATOR":{
True: [
"rotator/sde_rotator_dev.c",
"rotator/sde_rotator_core.c",
"rotator/sde_rotator_base.c",
"rotator/sde_rotator_formats.c",
"rotator/sde_rotator_util.c",
"rotator/sde_rotator_io_util.c",
"rotator/sde_rotator_smmu.c",
"rotator/sde_rotator_r1_wb.c",
"rotator/sde_rotator_r1_pipe.c",
"rotator/sde_rotator_r1_ctl.c",
"rotator/sde_rotator_r1.c",
"rotator/sde_rotator_r3.c"],
"CONFIG_SYNC_FILE":["rotator/sde_rotator_sync.c"],
"CONFIG_DEBUG_FS":["rotator/sde_rotator_debug.c",
"rotator/sde_rotator_r1_debug.c",
"rotator/sde_rotator_r3_debug.c"],
},
},
config_deps = {
"CONFIG_HDCP_QSEECOM" : [
"//vendor/qcom/opensource/securemsm-kernel:%b_hdcp_qseecom_dlkm"
],
"CONFIG_MSM_MMRM" : [
"//vendor/qcom/opensource/mmrm-driver:%b_mmrm_driver"
],
"CONFIG_QCOM_SPEC_SYNC" : [
"//vendor/qcom/opensource/mm-drivers/sync_fence:%b_sync_fence"
],
"CONFIG_QTI_HW_FENCE" : [
"//vendor/qcom/opensource/mm-drivers/hw_fence:%b_msm_hw_fence"
],
"CONFIG_MSM_EXT_DISPLAY" : [
"//vendor/qcom/opensource/mm-drivers/msm_ext_display:%b_msm_ext_display"
],
}
)

View File

@ -0,0 +1,342 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
* 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);
/* reset the flag once the data is written back to user space */
hdcp->tp_msgid = DOWN_REQUEST_TOPOLOGY;
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");
hdcp->tp_msgid = DOWN_REQUEST_TOPOLOGY;
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);
}

View File

@ -0,0 +1,2 @@
# Top-level Makefile calls into asm-$(ARCH)
# List only non-arch directories below

View 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

View 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 */

View File

@ -0,0 +1,136 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2012, 2017-2021, 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>
#include <linux/soc/qcom/msm_mmrm.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_MMRM, /* set rate called through mmrm driver */
DSS_CLK_OTHER,
};
struct dss_clk_mmrm_cb {
void *phandle;
struct dss_clk *clk;
};
struct dss_clk_mmrm {
unsigned int clk_id;
unsigned int flags;
struct mmrm_client *mmrm_client;
struct dss_clk_mmrm_cb *mmrm_cb_data;
unsigned long mmrm_requested_clk;
wait_queue_head_t mmrm_cb_wq;
};
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_clk_mmrm mmrm;
};
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_gpio_io_mem(const int gpio_pin, 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);
int msm_dss_mmrm_register(struct device *dev, struct dss_module_power *mp,
int (*cb_fnc)(struct mmrm_client_notifier_data *data), void *phandle,
bool *mmrm_enable);
void msm_dss_mmrm_deregister(struct device *dev, struct dss_module_power *mp);
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__ */

View 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_ */

View 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: gh_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__

View File

@ -0,0 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note
# Top-level Makefile calls into asm-$(ARCH)
# List only non-arch directories below
header-y += display/

View 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/

View 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

View File

@ -0,0 +1,817 @@
/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
/*
* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
*/
#ifndef _MSM_DRM_PP_H_
#define _MSM_DRM_PP_H_
#include <linux/types.h>
#include <drm/drm.h>
#define ENABLE_EVENT_SPR_OPR_VALUE
#define ENABLE_EVENT_INTF_MISR_SIGNATURE
#define MAX_DSI_DISPLAY 4
/**
* 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)
#define SIXZONE_SV_ENABLE (1 << 3)
/* 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
* - SIXZONE_SV_ENABLE: Enable SV feature
* @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.
* @sat_adjust_p0: Saturation adjustment curve.
* @sat_adjust_p1: Saturation adjustment curve.
* @curve_p2: Saturation Mid/Saturation High adjustment
*/
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];
__u32 sat_adjust_p0;
__u32 sat_adjust_p1;
__u32 curve_p2[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 4
#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
#define SPR_INIT_PARAM_SIZE_6 7
#define SPR_FLAG_BYPASS (1 << 0)
/**
* 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];
__u16 cfg18_en;
__u8 cfg18[SPR_INIT_PARAM_SIZE_6];
};
/**
* struct drm_msm_spr_udc_cfg - SPR UDC configuration structure
*/
#define SPR_UDC_PARAM_SIZE_1 27
#define SPR_UDC_PARAM_SIZE_2 1536
struct drm_msm_spr_udc_cfg {
__u64 flags;
__u16 init_cfg4;
__u16 init_cfg11[SPR_INIT_PARAM_SIZE_1];
__u16 cfg1[SPR_UDC_PARAM_SIZE_1];
__u16 cfg2[SPR_UDC_PARAM_SIZE_2];
};
#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
#define DEMURA_FLAG_0 (1 << 0)
#define DEMURA_FLAG_1 (1 << 1)
#define DEMURA_FLAG_2 (3 << 2)
#define DEMURA_SKIP_CFG0_PARAM2 (1 << 4)
#define DEMURA_PRECISION_0 (0 << 2)
#define DEMURA_PRECISION_1 (1 << 2)
#define DEMURA_PRECISION_2 (2 << 2)
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;
__u32 cfg0_param2_idx;
};
struct drm_msm_dem_cfg0_param2 {
__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];
};
/**
* 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];
__u32 height;
__u32 width;
};
#define FP16_SUPPORTED
#define FP16_GC_FLAG_ALPHA_EN (1 << 0)
/* FP16 GC mode options */
#define FP16_GC_MODE_INVALID 0
#define FP16_GC_MODE_SRGB 1
#define FP16_GC_MODE_PQ 2
/**
* struct drm_msm_fp16_gc - FP16 GC configuration structure
* @in flags - Settings flags for FP16 GC
* @in mode - Gamma correction mode to use for FP16 GC
*/
struct drm_msm_fp16_gc {
__u64 flags;
__u64 mode;
};
/**
* struct drm_msm_fp16_csc - FP16 CSC configuration structure
* @in flags - Settings flags for FP16 CSC. Currently unused
* @in cfg_param_0_len - Length of data for cfg_param_0
* @in cfg_param_0 - Data for param 0. Max size is FP16_CSC_CFG0_PARAM_LEN
* @in cfg_param_1_len - Length of data for cfg_param_1
* @in cfg_param_1 - Data for param 1. Max size is FP16_CSC_CFG1_PARAM_LEN
*/
#define FP16_CSC_CFG0_PARAM_LEN 12
#define FP16_CSC_CFG1_PARAM_LEN 8
struct drm_msm_fp16_csc {
__u64 flags;
__u32 cfg_param_0_len;
__u32 cfg_param_0[FP16_CSC_CFG0_PARAM_LEN];
__u32 cfg_param_1_len;
__u32 cfg_param_1[FP16_CSC_CFG1_PARAM_LEN];
};
#define DIMMING_ENABLE (1 << 0)
#define DIMMING_MIN_BL_VALID (1 << 1)
struct drm_msm_backlight_info {
__u32 brightness_max;
__u32 brightness;
__u32 bl_level_max;
__u32 bl_level;
__u32 bl_scale;
__u32 bl_scale_sv;
__u32 status;
__u32 min_bl;
__u32 bl_scale_max;
__u32 bl_scale_sv_max;
};
#define DIMMING_BL_LUT_LEN 8192
struct drm_msm_dimming_bl_lut {
__u32 length;
__u32 mapped_bl[DIMMING_BL_LUT_LEN];
};
struct drm_msm_opr_value {
__u32 num_valid_opr;
__u32 opr_value[MAX_DSI_DISPLAY];
};
#define SDE_MAX_ROI 4
struct drm_msm_roi {
__u32 num_rects;
struct drm_clip_rect roi[SDE_MAX_ROI];
};
struct drm_msm_misr_sign {
__u64 num_valid_misr;
struct drm_msm_roi roi_list;
__u64 misr_sign_value[MAX_DSI_DISPLAY];
};
#define UCSC_SUPPORTED
#define UCSC_CSC_CFG0_PARAM_LEN FP16_CSC_CFG0_PARAM_LEN
#define UCSC_CSC_CFG1_PARAM_LEN FP16_CSC_CFG1_PARAM_LEN
typedef struct drm_msm_fp16_csc drm_msm_ucsc_csc;
#endif /* _MSM_DRM_PP_H_ */

View File

@ -0,0 +1,974 @@
/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
/*
* Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2017-2021, 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
/**
* DRM format modifier tokens
*
* @DRM_FORMAT_MOD_QCOM_DX: Refers to a DX variant of the base format.
* Implementation may be platform and
* base-format specific.
*/
#define DRM_FORMAT_MOD_QCOM_DX fourcc_mod_code(QCOM, 0x2)
/**
* @DRM_FORMAT_MOD_QCOM_TIGHT: Refers to a tightly packed variant of the
* base variant. Implementation may be
* platform and base-format specific.
*/
#define DRM_FORMAT_MOD_QCOM_TIGHT fourcc_mod_code(QCOM, 0x4)
/**
* @DRM_FORMAT_MOD_QCOM_TILE: Refers to a tile variant of the base format.
* Implementation may be platform and
* base-format specific.
*/
#define DRM_FORMAT_MOD_QCOM_TILE fourcc_mod_code(QCOM, 0x8)
/**
* @DRM_FORMAT_MOD_QCOM_ALPHA_SWAP: Refers to a pixel format for which
* its alpha ordering has been reversed.
* Implementation may be platform and
* base-format specific.
*/
#define DRM_FORMAT_MOD_QCOM_ALPHA_SWAP fourcc_mod_code(QCOM, 0x10)
/**
* 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_DE_LPF_BLEND_FILT
#define SDE_DE_LPF_BLEND_FLAG_EN (1 << 0)
#define SDE_DRM_QSEED3LITE
#define SDE_DRM_QSEED4
#define SDE_DRM_INLINE_PREDOWNSCALE
#define SDE_DRM_QSEED6
/**
* 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)
* @de_lpf_flags: Detail enhancer lpf blned configuration flags
* @de_lpf_h: Detail enhancer lpf blend high
* @de_lpf_l: Detail enhancer lpf blend low
* @de_lpf_m: Detail enhancer lpf blend medium
* @dir45_en: 45/-45 degree direction filtering enable
* @cor_en: corner enhancer enable
*/
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;
__u32 de_lpf_flags;
__u32 de_lpf_h;
__u32 de_lpf_l;
__u32 de_lpf_m;
__u32 dir45_en;
__u32 cor_en;
};
/* Number of dest scalers supported */
#define SDE_MAX_DS_COUNT 4
/*
* 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
/* bitmask for allowed_dsc_reservation_switch property */
#define SDE_DP_DSC_RESERVATION_SWITCH (1 << 0)
/**
* 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
#define SDE_DRM_SPR_ROI 1
/* DRM_ROI_CONFIG_FLAGS */
#define SDE_DRM_ROI_SPR_FLAG_EN (1 << 0)
/**
* 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
* @roi_feature_flags: flags indicates that specific roi rect is valid or not
* @spr_roi: list of roi rectangles for spr
*/
struct sde_drm_roi_v1 {
__u32 num_rects;
struct drm_clip_rect roi[SDE_MAX_ROI_V1];
__u32 roi_feature_flags;
struct drm_clip_rect spr_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
/**
* Define UBWC statistics config
*/
#define UBWC_STATS_MAX_ROI 0x3
/**
* struct sde_drm_ubwc_stats_roi - region of interest for ubwc stats
* y_coord0: first y offset from top of display
* y_coord1: second y offset from top of display
*/
struct sde_drm_ubwc_stats_roi {
__u16 y_coord0;
__u16 y_coord1;
};
/**
* struct sde_drm_ubwc_stats_data: ubwc statistics
* roi: region of interest
* worst_bw: worst bandwidth, per roi
* worst_bw_y_coord: y offset (row) location of worst bandwidth, per roi
* total_bw: total bandwidth, per roi
* error: error status
* meta_error: meta error data
*/
struct sde_drm_ubwc_stats_data {
struct sde_drm_ubwc_stats_roi roi;
__u16 worst_bw[UBWC_STATS_MAX_ROI];
__u16 worst_bw_y_coord[UBWC_STATS_MAX_ROI];
__u32 total_bw[UBWC_STATS_MAX_ROI];
__u32 error;
__u32 meta_error;
};
/**
* Define frame data config
*/
#define SDE_FRAME_DATA_BUFFER_MAX 0x3
#define SDE_FRAME_DATA_GUARD_BYTES 0xFF
#define SDE_FRAME_DATA_MAX_PLANES 0x14
/**
* struct sde_drm_frame_data_buffers_ctrl - control frame data buffers
* num_buffers: number of allocated buffers
* fds: fd list for allocated buffers
*/
struct sde_drm_frame_data_buffers_ctrl {
__u32 num_buffers;
__u32 fds[SDE_FRAME_DATA_BUFFER_MAX];
};
/**
* struct sde_drm_frame_data_buf - frame data buffer info sent to userspace
* fd: buffer fd
* offset: offset from buffer address
* status: status flag
*/
struct sde_drm_frame_data_buf {
__u32 fd;
__u32 offset;
__u32 status;
};
/**
* struct sde_drm_plane_frame_data - definition of plane frame data struct
* plane_id: drm plane id
* ubwc_stats: ubwc statistics
*/
struct sde_drm_plane_frame_data {
__u32 plane_id;
struct sde_drm_ubwc_stats_data ubwc_stats;
};
/**
* struct sde_drm_frame_data_packet - definition of frame data struct
* frame_count: interface frame count
* commit_count: sw commit count
* plane_frame_data: data available per plane
*/
struct sde_drm_frame_data_packet {
__u32 frame_count;
__u64 commit_count;
struct sde_drm_plane_frame_data plane_frame_data[SDE_FRAME_DATA_MAX_PLANES];
};
/*
* 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_NOISE_LAYER_CFG
#define DRM_NOISE_TEMPORAL_FLAG (1 << 0)
#define DRM_NOISE_ATTN_MAX 255
#define DRM_NOISE_STREN_MAX 6
/**
* struct drm_msm_noise_layer_cfg: Payload to enable/disable noise blend
* @flags: operation control flags, for future use
* @zposn: noise zorder
* @zposattn: attenuation zorder
* @attn_factor: attenuation factor in range of 1 to 255
* @stength: strength in range of 0 to 6
* @alpha_noise: attenuation in range of 1 to 255
*/
struct drm_msm_noise_layer_cfg {
__u64 flags;
__u32 zposn;
__u32 zposattn;
__u32 attn_factor;
__u32 strength;
__u32 alpha_noise;
};
#define FEATURE_DNSC_BLUR
/* Downscale Blur - number of gaussian coefficient LUTs */
#define DNSC_BLUR_COEF_NUM 64
/* Downscale Blur flags */
#define DNSC_BLUR_EN (1 << 0)
#define DNSC_BLUR_RND_8B_EN (1 << 1)
#define DNSC_BLUR_DITHER_EN (1 << 2)
#define DNSC_BLUR_MIRROR_BLK_CFG (1 << 16)
#define DNSC_BLUR_INDEPENDENT_BLK_CFG (1 << 17)
/* Downscale Blur horizontal/vertical filter flags */
#define DNSC_BLUR_GAUS_FILTER (1 << 0)
#define DNSC_BLUR_PCMN_FILTER (1 << 1)
/* Downscale Blur Dither matrix size */
#define DNSC_BLUR_DITHER_MATRIX_SZ 16
/* Downscale Blur Dither flags */
#define DNSC_BLUR_DITHER_LUMA_MODE (1 << 0)
/**
* struct sde_drm_dnsc_blur_cfg - Downscale Blur config structure
* @flags: Flags to indicate features enabled, values are
* based on "Downscale Blur flags"
* @num_blocks: Active dnsc_blur blocks used for the display
* @src_width: Source width configuration
* @src_height: Source height configuration
* @dst_width: Destination width configuration
* @dst_height: Destination height configuration
* @flags_h: Flags for horizontal downscaling, values are
* based on "Downscale Blur horizontal/vertical filter flags"
* @flags_v: Flags for veritcal downscaling
* @phase_init_h: Initial phase value for horizontal downscaling
* @phase_step_h: Phase step value for horizontal downscaling
* @phase_init_v: Initial phase value for vertical downscaling
* @phase_step_v: Phase step value for vertical downscaling
* @norm_h: Horizontal downscale normalization downshift value
* @ratio_h: Horizontal downscale ratio value
* @norm_v: Vertical downscale normalization downshift value
* @ratio_v: Vertical downscale ratio value
* @coef_hori: Horizontal downscale LUT coefficients
* @coef_vert: Vertical downscale LUT coefficients
* @dither_flags: Flags for dither customization, values are
* based on "Downscale Blur Dither flags"
* @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
* @dither_matrix: Dither strength matrix
*/
struct sde_drm_dnsc_blur_cfg {
__u64 flags;
__u32 num_blocks;
__u32 src_width;
__u32 src_height;
__u32 dst_width;
__u32 dst_height;
__u32 flags_h;
__u32 flags_v;
/* pcmn filter parameters */
__u32 phase_init_h;
__u32 phase_step_h;
__u32 phase_init_v;
__u32 phase_step_v;
/* gaussian filter parameters */
__u32 norm_h;
__u32 ratio_h;
__u32 norm_v;
__u32 ratio_v;
__u32 coef_hori[DNSC_BLUR_COEF_NUM];
__u32 coef_vert[DNSC_BLUR_COEF_NUM];
/* dither configs */
__u64 dither_flags;
__u32 temporal_en;
__u32 c0_bitdepth;
__u32 c1_bitdepth;
__u32 c2_bitdepth;
__u32 c3_bitdepth;
__u32 dither_matrix[DNSC_BLUR_DITHER_MATRIX_SZ];
};
#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
#define DRM_EVENT_MMRM_CB 0X8000000B
#define DRM_EVENT_FRAME_DATA 0x8000000C
#define DRM_EVENT_DIMMING_BL 0X8000000D
#define DRM_EVENT_VM_RELEASE 0X8000000E
#define DRM_EVENT_OPR_VALUE 0X8000000F
#define DRM_EVENT_MISR_SIGN 0X80000010
#ifndef DRM_MODE_FLAG_VID_MODE_PANEL
#define DRM_MODE_FLAG_VID_MODE_PANEL 0x01
#endif
#ifndef DRM_MODE_FLAG_CMD_MODE_PANEL
#define DRM_MODE_FLAG_CMD_MODE_PANEL 0x02
#endif
#ifndef DRM_MODE_FLAG_DSI_24BPP
#define DRM_MODE_FLAG_DSI_24BPP 0x01
#endif
#ifndef DRM_MODE_FLAG_DSI_30BPP
#define DRM_MODE_FLAG_DSI_30BPP 0x02
#endif
/* 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_ */

View File

@ -0,0 +1,3 @@
# SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note
header-y += msm_hdmi_hdcp_mgr.h

View File

@ -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 */

View 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

File diff suppressed because it is too large Load Diff

View 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__ */

View File

@ -0,0 +1,75 @@
DISPLAY_SELECT := CONFIG_DRM_MSM=m
LOCAL_PATH := $(call my-dir)
ifeq ($(TARGET_BOARD_PLATFORM), niobe)
LOCAL_MODULE_DDK_BUILD := false
else
LOCAL_MODULE_DDK_BUILD := true
endif
include $(CLEAR_VARS)
LOCAL_MODULE_DDK_SUBTARGET_REGEX := "display_drivers*"
ifeq ($(TARGET_BOARD_PLATFORM), volcano)
LOCAL_MODULE_DDK_SUBTARGET_REGEX := "$(TARGET_BOARD_PLATFORM)_display_drivers.*"
endif
# This makefile is only for DLKM
ifneq ($(findstring vendor,$(LOCAL_PATH)),)
ifneq ($(findstring opensource,$(LOCAL_PATH)),)
DISPLAY_BLD_DIR := $(TOP)/vendor/qcom/opensource/display-drivers
endif # opensource
DLKM_DIR := $(TOP)/device/qcom/common/dlkm
LOCAL_ADDITIONAL_DEPENDENCIES := $(wildcard $(LOCAL_PATH)/**/*) $(wildcard $(LOCAL_PATH)/*)
# Build display.ko as msm_drm.ko
###########################################################
# This is set once per LOCAL_PATH, not per (kernel) module
KBUILD_OPTIONS := DISPLAY_ROOT=$(DISPLAY_BLD_DIR)
KBUILD_OPTIONS += MODNAME=msm_drm
KBUILD_OPTIONS += BOARD_PLATFORM=$(TARGET_BOARD_PLATFORM)
KBUILD_OPTIONS += $(DISPLAY_SELECT)
ifneq ($(TARGET_BOARD_AUTO),true)
ifneq ($(TARGET_BOARD_PLATFORM), pitti)
KBUILD_OPTIONS += KBUILD_EXTRA_SYMBOLS+=$(PWD)/$(call intermediates-dir-for,DLKM,mmrm-module-symvers)/Module.symvers
endif
ifneq ($(TARGET_BOARD_PLATFORM), taro)
KBUILD_OPTIONS += KBUILD_EXTRA_SYMBOLS+=$(PWD)/$(call intermediates-dir-for,DLKM,sync-fence-module-symvers)/Module.symvers
KBUILD_OPTIONS += KBUILD_EXTRA_SYMBOLS+=$(PWD)/$(call intermediates-dir-for,DLKM,msm-ext-disp-module-symvers)/Module.symvers
KBUILD_OPTIONS += KBUILD_EXTRA_SYMBOLS+=$(PWD)/$(call intermediates-dir-for,DLKM,hw-fence-module-symvers)/Module.symvers
KBUILD_OPTIONS += KBUILD_EXTRA_SYMBOLS+=$(PWD)/$(call intermediates-dir-for,DLKM,sec-module-symvers)/Module.symvers
endif
endif
###########################################################
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/**/*) $(wildcard $(LOCAL_PATH)/*)
LOCAL_MODULE := msm_drm.ko
LOCAL_MODULE_KBUILD_NAME := msm_drm.ko
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_DEBUG_ENABLE := true
LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
ifneq ($(TARGET_BOARD_AUTO),true)
ifneq ($(TARGET_BOARD_PLATFORM), pitti)
LOCAL_REQUIRED_MODULES += mmrm-module-symvers
LOCAL_ADDITIONAL_DEPENDENCIES += $(call intermediates-dir-for,DLKM,mmrm-module-symvers)/Module.symvers
endif
ifneq ($(TARGET_BOARD_PLATFORM), taro)
LOCAL_REQUIRED_MODULES += sync-fence-module-symvers
LOCAL_REQUIRED_MODULES += msm-ext-disp-module-symvers
LOCAL_REQUIRED_MODULES += hw-fence-module-symvers
LOCAL_REQUIRED_MODULES += sec-module-symvers
LOCAL_ADDITIONAL_DEPENDENCIES += $(call intermediates-dir-for,DLKM,sync-fence-module-symvers)/Module.symvers
LOCAL_ADDITIONAL_DEPENDENCIES += $(call intermediates-dir-for,DLKM,msm-ext-disp-module-symvers)/Module.symvers
LOCAL_ADDITIONAL_DEPENDENCIES += $(call intermediates-dir-for,DLKM,hw-fence-module-symvers)/Module.symvers
LOCAL_ADDITIONAL_DEPENDENCIES += $(call intermediates-dir-for,DLKM,sec-module-symvers)/Module.symvers
endif
endif
include $(DLKM_DIR)/Build_external_kernelmodule.mk
###########################################################
endif # DLKM check

View File

@ -0,0 +1,267 @@
# SPDX-License-Identifier: GPL-2.0-only
KDIR := $(TOP)/kernel_platform/msm-kernel
ifeq ($(CONFIG_ARCH_WAIPIO), y)
ifeq ($(CONFIG_ARCH_QTI_VM), y)
include $(DISPLAY_ROOT)/config/gki_waipiodisptui.conf
LINUX_INC += -include $(DISPLAY_ROOT)/config/gki_waipiodisptuiconf.h
else
include $(DISPLAY_ROOT)/config/gki_waipiodisp.conf
LINUX_INC += -include $(DISPLAY_ROOT)/config/gki_waipiodispconf.h
endif
endif
ifeq ($(CONFIG_ARCH_NEO), y)
include $(DISPLAY_ROOT)/config/gki_neodisp.conf
LINUX_INC += -include $(DISPLAY_ROOT)/config/gki_neodispconf.h
endif
ifeq ($(CONFIG_ARCH_PARROT), y)
include $(DISPLAY_ROOT)/config/gki_parrotdisp.conf
LINUX_INC += -include $(DISPLAY_ROOT)/config/gki_parrotdispconf.h
endif
ifeq ($(CONFIG_ARCH_PITTI), y)
include $(DISPLAY_ROOT)/config/gki_pittidisp.conf
LINUX_INC += -include $(DISPLAY_ROOT)/config/gki_pittidispconf.h
endif
ifeq ($(CONFIG_ARCH_NIOBE), y)
include $(DISPLAY_ROOT)/config/gki_niobedisp.conf
LINUX_INC += -include $(DISPLAY_ROOT)/config/gki_niobedispconf.h
endif
ifeq ($(CONFIG_ARCH_PINEAPPLE), y)
ifeq ($(CONFIG_ARCH_QTI_VM), y)
include $(DISPLAY_ROOT)/config/gki_pineappledisptui.conf
LINUX_INC += -include $(DISPLAY_ROOT)/config/gki_pineappledisptuiconf.h
else
include $(DISPLAY_ROOT)/config/gki_pineappledisp.conf
LINUX_INC += -include $(DISPLAY_ROOT)/config/gki_pineappledispconf.h
endif
endif
ifeq ($(CONFIG_ARCH_KALAMA), y)
ifeq ($(CONFIG_ARCH_QTI_VM), y)
include $(DISPLAY_ROOT)/config/gki_kalamadisptui.conf
LINUX_INC += -include $(DISPLAY_ROOT)/config/gki_kalamadisptuiconf.h
else
include $(DISPLAY_ROOT)/config/gki_kalamadisp.conf
LINUX_INC += -include $(DISPLAY_ROOT)/config/gki_kalamadispconf.h
endif
endif
ifeq (y, $(findstring y, $(CONFIG_ARCH_SA8155) $(CONFIG_ARCH_SA6155) $(CONFIG_ARCH_SA8195)))
include $(DISPLAY_ROOT)/config/augen3disp.conf
LINUX_INC += -include $(DISPLAY_ROOT)/config/augen3dispconf.h
endif
LINUX_INC += -I$(KERNEL_SRC)/include/linux \
-I$(KERNEL_SRC)/include/linux/drm
LINUX_INC += -I$(DISPLAY_ROOT) \
-I$(DISPLAY_ROOT)/include \
-I$(KERNEL_ROOT)/drivers/clk/qcom \
-I$(KERNEL_SRC)/drivers/clk/qcom \
-I$(DISPLAY_ROOT)/include/linux \
-I$(DISPLAY_ROOT)/rotator \
-I$(DISPLAY_ROOT)/msm \
-I$(DISPLAY_ROOT)/msm/dp \
-I$(DISPLAY_ROOT)/msm/dsi \
-I$(DISPLAY_ROOT)/msm/sde \
-I$(DISPLAY_ROOT)/include/uapi/display \
CDEFINES += -DANI_LITTLE_BYTE_ENDIAN \
-DANI_LITTLE_BIT_ENDIAN \
-DDOT11F_LITTLE_ENDIAN_HOST \
-DANI_COMPILER_TYPE_GCC \
-DANI_OS_TYPE_ANDROID=6 \
-DPTT_SOCK_SVC_ENABLE \
-Wall\
-Werror\
-D__linux__
KBUILD_CPPFLAGS += $(CDEFINES)
ccflags-y += $(LINUX_INC)
ifeq ($(call cc-option-yn, -Wmaybe-uninitialized),y)
EXTRA_CFLAGS += -Wmaybe-uninitialized
endif
KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/display-drivers/hdcp/Module.symvers
KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/display-drivers/msm/Module.symvers
ifeq ($(call cc-option-yn, -Wheader-guard),y)
EXTRA_CFLAGS += -Wheader-guard
endif
ccflags-y += -Wformat-extra-args -Wstrict-prototypes -Wformat-insufficient-args \
-Wformat-invalid-specifier -Wformat-zero-length -Wnonnull
ifneq ($(MODNAME), qdsp6v2)
CHIP_NAME ?= $(MODNAME)
CDEFINES += -DMULTI_IF_NAME=\"$(CHIP_NAME)\"
endif
######### CONFIG_DRM_MSM ########
obj-m += msm_drm.o
msm_drm-$(CONFIG_HDCP_QSEECOM) := ../hdcp/msm_hdcp.o \
dp/dp_hdcp2p2.o \
sde_hdcp_1x.o \
sde_hdcp_2x.o
msm_drm-$(CONFIG_MSM_SDE_ROTATOR) += ../rotator/sde_rotator_dev.o \
../rotator/sde_rotator_dev.o \
../rotator/sde_rotator_core.o \
../rotator/sde_rotator_base.o \
../rotator/sde_rotator_formats.o \
../rotator/sde_rotator_util.o \
../rotator/sde_rotator_io_util.o \
../rotator/sde_rotator_smmu.o \
../rotator/sde_rotator_r1_wb.o \
../rotator/sde_rotator_r1_pipe.o \
../rotator/sde_rotator_r1_ctl.o \
../rotator/sde_rotator_r1.o \
../rotator/sde_rotator_r3.o
ifeq ($(CONFIG_MSM_SDE_ROTATOR), y)
msm_drm-$(CONFIG_SYNC_FILE) += ../rotator/sde_rotator_sync.o
msm_drm-$(CONFIG_DEBUG_FS) += ../rotator/sde_rotator_debug.o \
../rotator/sde_rotator_r1_debug.o \
../rotator/sde_rotator_r3_debug.o
endif
msm_drm-$(CONFIG_DRM_SDE_VM) += sde/sde_vm_common.o \
sde/sde_vm_primary.o \
sde/sde_vm_trusted.o \
sde/sde_vm_msgq.o
msm_drm-$(CONFIG_DRM_MSM_DP) += dp/dp_altmode.o \
dp/dp_parser.o \
dp/dp_power.o \
dp/dp_catalog.o \
dp/dp_catalog_v420.o \
dp/dp_catalog_v200.o \
dp/dp_aux.o \
dp/dp_panel.o \
dp/dp_link.o \
dp/dp_ctrl.o \
dp/dp_audio.o \
dp/dp_debug.o \
dp/dp_hpd.o \
dp/dp_aux_bridge.o \
dp/dp_bridge_hpd.o \
dp/dp_mst_sim.o \
dp/dp_mst_sim_helper.o \
dp/dp_gpio_hpd.o \
dp/dp_lphw_hpd.o \
dp/dp_display.o \
dp/dp_drm.o \
dp/dp_pll.o \
dp/dp_pll_5nm.o \
dp/dp_pll_4nm.o
msm_drm-$(CONFIG_DRM_MSM_DP_MST) += dp/dp_mst_drm.o
msm_drm-$(CONFIG_DRM_MSM_DP_USBPD_LEGACY) += dp/dp_usbpd.o
msm_drm-$(CONFIG_DRM_MSM_SDE) += sde/sde_crtc.o \
sde/sde_encoder.o \
sde/sde_encoder_dce.o \
sde/sde_encoder_phys_vid.o \
sde/sde_encoder_phys_cmd.o \
sde/sde_irq.o sde/sde_core_irq.o \
sde/sde_core_perf.o \
sde/sde_rm.o \
sde/sde_kms_utils.o \
sde/sde_kms.o \
sde/sde_plane.o \
sde/sde_connector.o \
sde/sde_color_processing.o \
sde/sde_vbif.o \
sde_dbg.o \
sde_dbg_evtlog.o \
sde_io_util.o \
sde_vm_event.o \
sde/sde_hw_reg_dma_v1_color_proc.o \
sde/sde_hw_color_proc_v4.o \
sde/sde_hw_ad4.o \
sde/sde_hw_uidle.o \
sde_edid_parser.o \
sde/sde_hw_catalog.o \
sde/sde_hw_cdm.o \
sde/sde_hw_dspp.o \
sde/sde_hw_intf.o \
sde/sde_hw_lm.o \
sde/sde_hw_ctl.o \
sde/sde_hw_util.o \
sde/sde_hw_sspp.o \
sde/sde_hw_wb.o \
sde/sde_hw_pingpong.o \
sde/sde_hw_top.o \
sde/sde_hw_interrupts.o \
sde/sde_hw_vbif.o \
sde/sde_formats.o \
sde_power_handle.o \
sde/sde_hw_color_processing_v1_7.o \
sde/sde_reg_dma.o \
sde/sde_hw_reg_dma_v1.o \
sde/sde_hw_dsc.o \
sde/sde_hw_dsc_1_2.o \
sde/sde_hw_vdc.o \
sde/sde_hw_ds.o \
sde/sde_fence.o \
sde/sde_hw_qdss.o \
sde_dsc_helper.o \
sde_vdc_helper.o \
sde/sde_hw_dnsc_blur.o \
sde/sde_hw_rc.o
msm_drm-$(CONFIG_DRM_SDE_WB) += sde/sde_wb.o \
sde/sde_encoder_phys_wb.o
msm_drm-$(CONFIG_DRM_SDE_RSC) += sde_rsc.o \
sde_rsc_hw.o \
sde_rsc_hw_v3.o
msm_drm-$(CONFIG_DRM_MSM_DSI) += dsi/dsi_phy.o \
dsi/dsi_pwr.o \
dsi/dsi_phy.o \
dsi/dsi_phy_hw_v3_0.o \
dsi/dsi_phy_hw_v4_0.o \
dsi/dsi_phy_hw_v5_0.o \
dsi/dsi_phy_timing_calc.o \
dsi/dsi_phy_timing_v3_0.o \
dsi/dsi_phy_timing_v4_0.o \
dsi/dsi_pll.o \
dsi/dsi_pll_5nm.o \
dsi/dsi_pll_4nm.o \
dsi/dsi_ctrl_hw_cmn.o \
dsi/dsi_ctrl_hw_2_2.o \
dsi/dsi_ctrl.o \
dsi/dsi_catalog.o \
dsi/dsi_drm.o \
dsi/dsi_display.o \
dsi/dsi_panel.o \
dsi/dsi_clk_manager.o \
dsi/dsi_display_test.o
msm_drm-$(CONFIG_DSI_PARSER) += dsi/dsi_parser.o
msm_drm-$(CONFIG_THERMAL_OF) += msm_cooling_device.o
msm_drm-$(CONFIG_DRM_MSM) += msm_atomic.o \
msm_fb.o \
msm_drv.o \
msm_gem.o \
msm_gem_prime.o \
msm_gem_vma.o \
msm_smmu.o \
msm_prop.o
CDEFINES += -DBUILD_TIMESTAMP=\"$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')\"

View File

@ -0,0 +1,16 @@
# SPDX-License-Identifier: GPL-2.0
KBUILD_OPTIONS+= DISPLAY_ROOT=$(KERNEL_SRC)/$(M)/../
all: modules
modules_install:
$(MAKE) INSTALL_MOD_STRIP=1 -C $(KERNEL_SRC) M=$(M) modules_install
%:
$(MAKE) -C $(KERNEL_SRC) M=$(M) $@ $(KBUILD_OPTIONS)
clean:
rm -f *.o *.ko *.mod.c *.mod.o *~ .*.cmd Module.symvers
rm -rf .tmp_versions

View File

@ -0,0 +1,325 @@
// 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;
u32 lanes;
};
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_set_usb_dp_mode(struct dp_altmode_private *altmode)
{
int rc = 0;
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_set_dp_mode(&usb_pdev->dev, altmode->connected, altmode->lanes);
if (rc != -EBUSY && rc != -EAGAIN)
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);
rc = dp_altmode_set_usb_dp_mode(altmode);
if (rc)
DP_ERR("failed to clear usb dp mode, rc: %d\n", rc);
}
goto ack;
}
/* Configure */
if (!altmode->connected) {
altmode->connected = true;
altmode->dp_altmode.base.alt_mode_cfg_done = true;
altmode->forced_disconnect = false;
altmode->lanes = 4;
if (altmode->dp_altmode.base.multi_func)
altmode->lanes = 2;
DP_DEBUG("Connected=%d, lanes=%d\n",altmode->connected,altmode->lanes);
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_set_usb_dp_mode(altmode);
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: %ld\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);
}

View 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_ */

View File

@ -0,0 +1,915 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
*/
#include <linux/of_platform.h>
#include <linux/soc/qcom/msm_ext_display.h>
#include <linux/version.h>
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 0))
#include <drm/display/drm_dp_helper.h>
#else
#include <drm/drm_dp_helper.h>
#endif
#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;
if (audio->panel->get_panel_on(audio->panel))
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;
}
if (audio->panel->stream_id >= DP_STREAM_MAX) {
DP_WARN("invalid stream id: %d\n",
audio->panel->stream_id);
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 IS_ENABLED(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 IS_ENABLED(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, bool skip_wait)
{
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");
if (!skip_wait) {
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);
}

View File

@ -0,0 +1,76 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
* 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.
* @skip_wait: flag to skip any waits
*
* Returns the error code in case of failure, 0 in success case.
*/
int (*off)(struct dp_audio *dp_audio, bool skip_wait);
};
/**
* 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_ */

View File

@ -0,0 +1,958 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2021-2023, Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2012-2021, The Linux Foundation. All rights reserved.
*/
#include <linux/delay.h>
#if IS_ENABLED(CONFIG_QCOM_FSA4480_I2C)
#include <linux/soc/qcom/fsa4480-i2c.h>
#endif
#if IS_ENABLED(CONFIG_QCOM_WCD939X_I2C)
#include <linux/soc/qcom/wcd939x-i2c.h>
#endif
#include "dp_aux.h"
#include "dp_hpd.h"
#include "dp_debug.h"
#define DP_AUX_ENUM_STR(x) #x
#define DP_AUX_IPC_NUM_PAGES 10
#define DP_AUX_DEBUG(dp_aux, fmt, ...) \
do { \
if (dp_aux) \
ipc_log_string(dp_aux->ipc_log_context, "[d][%-4d]"fmt,\
current->pid, ##__VA_ARGS__); \
DP_DEBUG_V(fmt, ##__VA_ARGS__); \
} while (0)
#define DP_AUX_WARN(dp_aux, fmt, ...) \
do { \
if (dp_aux) \
ipc_log_string(dp_aux->ipc_log_context, "[w][%-4d]"fmt,\
current->pid, ##__VA_ARGS__); \
DP_WARN_V(fmt, ##__VA_ARGS__); \
} while (0)
#define DP_AUX_WARN_RATELIMITED(dp_aux, fmt, ...) \
do { \
if (dp_aux) \
ipc_log_string(dp_aux->ipc_log_context, "[w][%-4d]"fmt,\
current->pid, ##__VA_ARGS__); \
DP_WARN_RATELIMITED_V(fmt, ##__VA_ARGS__); \
} while (0)
#define DP_AUX_ERR(dp_aux, fmt, ...) \
do { \
if (dp_aux) \
ipc_log_string(dp_aux->ipc_log_context, "[e][%-4d]"fmt,\
current->pid, ##__VA_ARGS__); \
DP_ERR_V(fmt, ##__VA_ARGS__); \
} while (0)
#define DP_AUX_ERR_RATELIMITED(dp_aux, fmt, ...) \
do { \
if (dp_aux) \
ipc_log_string(dp_aux->ipc_log_context, "[e][%-4d]"fmt,\
current->pid, ##__VA_ARGS__); \
DP_ERR_RATELIMITED_V(fmt, ##__VA_ARGS__); \
} while (0)
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;
struct dp_aux_bridge *aux_bridge;
struct dp_aux_bridge *sim_bridge;
bool bridge_in_transfer;
bool sim_in_transfer;
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;
bool switch_enable;
int switch_orientation;
atomic_t aborted;
};
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);
struct dp_aux *dp_aux = &aux->dp_aux;
snprintf(prefix, sizeof(prefix), "%s %s %4xh(%2zu): ",
(msg->request & DP_AUX_I2C_MOT) ? "I2C" : "NAT",
(msg->request & DP_AUX_I2C_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);
if (msg->size == 1 && msg->address == 0)
DP_DEBUG_V("%s%s\n", prefix, linebuf);
else
DP_AUX_DEBUG(dp_aux, "%s%s\n", prefix, linebuf);
}
}
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;
struct dp_aux *dp_aux = &aux->dp_aux;
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_AUX_ERR(dp_aux, "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;
struct dp_aux *dp_aux = &aux->dp_aux;
char prefix[64];
snprintf(prefix, sizeof(prefix), "%s %s %4xh(%2zu): ",
(msg->request & DP_AUX_I2C_MOT) ? "I2C" : "NAT",
(msg->request & DP_AUX_I2C_READ) ? "RD" : "WR",
msg->address, msg->size);
reinit_completion(&aux->comp);
len = dp_aux_write(aux, msg);
if (len == 0) {
DP_AUX_ERR(dp_aux, "DP AUX write failed: %s\n", prefix);
return -EINVAL;
}
timeout = wait_for_completion_timeout(&aux->comp, aux_timeout_ms);
if (!timeout) {
DP_AUX_WARN_RATELIMITED(dp_aux, "aux timeout during [%s]\n", prefix);
return -ETIMEDOUT;
}
if (aux->aux_error_num == DP_AUX_ERR_NONE) {
ret = len;
} else {
DP_AUX_WARN_RATELIMITED(dp_aux, "aux err [%s] during [%s]\n",
dp_aux_get_error(aux->aux_error_num), prefix);
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;
struct dp_aux *dp_aux = &aux->dp_aux;
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_AUX_WARN(dp_aux, "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_AUX_ERR(dp_aux, "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_AUX_ERR(dp_aux, "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_AUX_ERR(dp_aux, "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;
struct dp_aux *dp_aux = &aux->dp_aux;
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_AUX_ERR(dp_aux, "%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 inline bool dp_aux_is_sideband_msg(u32 address, size_t size)
{
return (address >= 0x1000 && address + size < 0x1800) ||
(address >= 0x2000 && address + size < 0x2200);
}
/*
* 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 ssize_t dp_aux_bridge_transfer(struct drm_dp_aux *drm_aux,
struct drm_dp_aux_msg *msg)
{
struct dp_aux_private *aux = container_of(drm_aux,
struct dp_aux_private, drm_aux);
ssize_t size;
if (aux->bridge_in_transfer) {
size = dp_aux_transfer(drm_aux, msg);
} else {
aux->bridge_in_transfer = true;
size = aux->aux_bridge->transfer(aux->aux_bridge,
drm_aux, msg);
aux->bridge_in_transfer = false;
dp_aux_hex_dump(drm_aux, msg);
}
return size;
}
static ssize_t dp_aux_transfer_debug(struct drm_dp_aux *drm_aux,
struct drm_dp_aux_msg *msg)
{
struct dp_aux_private *aux = container_of(drm_aux,
struct dp_aux_private, drm_aux);
ssize_t size;
int aborted;
mutex_lock(&aux->mutex);
aborted = atomic_read(&aux->aborted);
mutex_unlock(&aux->mutex);
if (aborted) {
size = -ETIMEDOUT;
goto end;
}
if (aux->sim_in_transfer) {
if (aux->aux_bridge && aux->aux_bridge->transfer)
size = dp_aux_bridge_transfer(drm_aux, msg);
else
size = dp_aux_transfer(drm_aux, msg);
} else {
aux->sim_in_transfer = true;
size = aux->sim_bridge->transfer(aux->sim_bridge,
drm_aux, msg);
aux->sim_in_transfer = false;
dp_aux_hex_dump(drm_aux, msg);
}
end:
return size;
}
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_AUX_ERR(dp_aux, "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_AUX_ERR(dp_aux, "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 drm_device *drm_dev)
{
struct dp_aux_private *aux;
int ret = 0;
if (!dp_aux) {
DP_AUX_ERR(dp_aux, "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;
#if (KERNEL_VERSION(5, 15, 0) <= LINUX_VERSION_CODE)
aux->drm_aux.drm_dev = drm_dev;
#endif
atomic_set(&aux->aborted, 1);
ret = drm_dp_aux_register(&aux->drm_aux);
if (ret) {
DP_AUX_ERR(dp_aux, "%s: failed to register drm aux: %d\n", __func__, ret);
goto exit;
}
dp_aux->drm_aux = &aux->drm_aux;
/* if bridge is defined, override transfer function */
if (aux->aux_bridge && aux->aux_bridge->transfer)
aux->drm_aux.transfer = dp_aux_bridge_transfer;
exit:
return ret;
}
static void dp_aux_deregister(struct dp_aux *dp_aux)
{
struct dp_aux_private *aux;
if (!dp_aux) {
DP_AUX_ERR(dp_aux, "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_set_sim_mode(struct dp_aux *dp_aux,
struct dp_aux_bridge *sim_bridge)
{
struct dp_aux_private *aux;
if (!dp_aux) {
DP_AUX_ERR(dp_aux, "invalid input\n");
return;
}
aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
mutex_lock(&aux->mutex);
aux->sim_bridge = sim_bridge;
if (sim_bridge) {
atomic_set(&aux->aborted, 0);
aux->drm_aux.transfer = dp_aux_transfer_debug;
} else if (aux->aux_bridge && aux->aux_bridge->transfer) {
aux->drm_aux.transfer = dp_aux_bridge_transfer;
} else {
aux->drm_aux.transfer = dp_aux_transfer;
}
mutex_unlock(&aux->mutex);
}
#if IS_ENABLED(CONFIG_QCOM_FSA4480_I2C)
static int dp_aux_configure_fsa_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_AUX_ERR(dp_aux, "invalid input\n");
rc = -EINVAL;
goto end;
}
aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
if (!aux->aux_switch_node) {
DP_AUX_DEBUG(dp_aux, "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_AUX_ERR(dp_aux, "invalid orientation\n");
rc = -EINVAL;
goto end;
}
}
DP_AUX_DEBUG(dp_aux, "enable=%d, orientation=%d, event=%d\n",
enable, orientation, event);
rc = fsa4480_switch_event(aux->aux_switch_node, event);
if (rc)
DP_AUX_ERR(dp_aux, "failed to configure fsa4480 i2c device (%d)\n", rc);
end:
return rc;
}
#endif
#if IS_ENABLED(CONFIG_QCOM_WCD939X_I2C)
static int dp_aux_configure_wcd_switch(struct dp_aux *dp_aux,
bool enable, int orientation)
{
struct dp_aux_private *aux;
int rc = 0;
enum wcd_usbss_cable_status status = WCD_USBSS_CABLE_DISCONNECT;
enum wcd_usbss_cable_types event = WCD_USBSS_DP_AUX_CC1;
if (!dp_aux) {
DP_AUX_ERR(dp_aux, "invalid input\n");
rc = -EINVAL;
goto end;
}
aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
if (!aux->aux_switch_node) {
DP_AUX_DEBUG(dp_aux, "undefined wcd939x switch handle\n");
rc = -EINVAL;
goto end;
}
if ((aux->switch_enable == enable) && (aux->switch_orientation == orientation))
goto end;
if (enable) {
status = WCD_USBSS_CABLE_CONNECT;
switch (orientation) {
case ORIENTATION_CC1:
event = WCD_USBSS_DP_AUX_CC1;
break;
case ORIENTATION_CC2:
event = WCD_USBSS_DP_AUX_CC2;
break;
default:
DP_AUX_ERR(dp_aux, "invalid orientation\n");
rc = -EINVAL;
goto end;
}
}
DP_AUX_DEBUG(dp_aux, "enable=%d, orientation=%d, event=%d\n",
enable, orientation, event);
rc = wcd_usbss_switch_update(event, status);
if (rc) {
DP_AUX_ERR(dp_aux, "failed to configure wcd939x i2c device (%d)\n", rc);
} else {
aux->switch_enable = enable;
aux->switch_orientation = orientation;
}
end:
return rc;
}
#endif
struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog,
struct dp_parser *parser, struct device_node *aux_switch,
struct dp_aux_bridge *aux_bridge, void *ipc_log_context,
enum dp_aux_switch_type switch_type)
{
int rc = 0;
struct dp_aux_private *aux;
struct dp_aux *dp_aux = NULL;
if (!catalog || !parser) {
DP_AUX_ERR(dp_aux, "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;
aux->aux_bridge = aux_bridge;
dp_aux = &aux->dp_aux;
aux->retry_cnt = 0;
aux->switch_orientation = -1;
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->set_sim_mode = dp_aux_set_sim_mode;
dp_aux->ipc_log_context = ipc_log_context;
/*Condition to avoid allocating function pointers for aux bypass mode*/
if (switch_type != DP_AUX_SWITCH_BYPASS) {
#if IS_ENABLED(CONFIG_QCOM_FSA4480_I2C)
if (switch_type == DP_AUX_SWITCH_FSA4480) {
dp_aux->switch_configure = dp_aux_configure_fsa_switch;
dp_aux->switch_register_notifier = fsa4480_reg_notifier;
dp_aux->switch_unregister_notifier = fsa4480_unreg_notifier;
}
#endif
#if IS_ENABLED(CONFIG_QCOM_WCD939X_I2C)
if (switch_type == DP_AUX_SWITCH_WCD939x) {
dp_aux->switch_configure = dp_aux_configure_wcd_switch;
dp_aux->switch_register_notifier = wcd_usbss_reg_notifier;
dp_aux->switch_unregister_notifier = wcd_usbss_unreg_notifier;
}
#endif
}
return dp_aux;
error:
return ERR_PTR(rc);
}
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);
}

View File

@ -0,0 +1,77 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2012-2021, The Linux Foundation. All rights reserved.
*/
#ifndef _DP_AUX_H_
#define _DP_AUX_H_
#include "dp_catalog.h"
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 0))
#include <drm/display/drm_dp_helper.h>
#else
#include <drm/drm_dp_helper.h>
#endif
#include "dp_aux_bridge.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_switch_type {
DP_AUX_SWITCH_BYPASS,
DP_AUX_SWITCH_FSA4480,
DP_AUX_SWITCH_WCD939x,
};
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 state;
bool read;
struct mutex *access_lock;
void *ipc_log_context;
struct drm_dp_aux *drm_aux;
int (*drm_aux_register)(struct dp_aux *aux, struct drm_device *drm_dev);
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 (*set_sim_mode)(struct dp_aux *aux, struct dp_aux_bridge *sim_bridge);
int (*switch_configure)(struct dp_aux *aux, bool enable, int orientation);
int (*switch_register_notifier)(struct notifier_block *nb, struct device_node *node);
int (*switch_unregister_notifier)(struct notifier_block *nb, struct device_node *node);
};
struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog,
struct dp_parser *parser, struct device_node *aux_switch,
struct dp_aux_bridge *aux_bridge, void *ipc_log_context,
enum dp_aux_switch_type switch_type);
void dp_aux_put(struct dp_aux *aux);
#endif /*__DP_AUX_H_*/

View File

@ -0,0 +1,71 @@
/*
* Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2019-2021, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
/*
* Copyright (c) 2014 Samsung Electronics Co., Ltd
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sub license,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "dp_aux_bridge.h"
static DEFINE_MUTEX(dp_aux_bridge_lock);
static LIST_HEAD(du_aux_bridge_list);
int dp_aux_add_bridge(struct dp_aux_bridge *bridge)
{
mutex_lock(&dp_aux_bridge_lock);
list_add_tail(&bridge->head, &du_aux_bridge_list);
mutex_unlock(&dp_aux_bridge_lock);
return 0;
}
#if IS_ENABLED(CONFIG_OF)
struct dp_aux_bridge *of_dp_aux_find_bridge(struct device_node *np)
{
struct dp_aux_bridge *bridge;
mutex_lock(&dp_aux_bridge_lock);
list_for_each_entry(bridge, &du_aux_bridge_list, head) {
if (bridge->of_node == np) {
mutex_unlock(&dp_aux_bridge_lock);
return bridge;
}
}
mutex_unlock(&dp_aux_bridge_lock);
return NULL;
}
#endif /* CONFIG_OF */

View File

@ -0,0 +1,135 @@
/*
* Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2019-2021, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
/*
* Copyright (c) 2016 Intel Corporation
*
* 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.
*/
#ifndef _DP_AUX_BRIDGE_H_
#define _DP_AUX_BRIDGE_H_
#include <linux/version.h>
#include <linux/types.h>
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 0))
#include <drm/display/drm_dp_helper.h>
#else
#include <drm/drm_dp_helper.h>
#endif
/**
* enum dp_aux_bridge_flag - DP aux bridge capability flag
* DP_AUX_BRIDGE_HPD: HPD will be generated by DP aux bridge
* DP_AUX_BRIDGE_MST: MST simulator is used by DP aux bridge
*/
enum dp_aux_bridge_flag {
DP_AUX_BRIDGE_HPD = (1 << 0),
DP_AUX_BRIDGE_MST = (1 << 1),
};
/**
* struct dp_aux_bridge - DP aux bridge control structure
* @of_node: device node pointer to the bridge
* @dev_priv: pointer to the bridge driver's internal context
* @flag: flag for capability
* @mst_ctx: pointer to mst context when DP_AUX_BRIDGE_MST is set
* @head: to keep track of all added bridges
*/
struct dp_aux_bridge {
#if IS_ENABLED(CONFIG_OF)
struct device_node *of_node;
#endif /* CONFIG_OF */
void *dev_priv;
u32 flag;
void *mst_ctx;
struct list_head head;
/**
* @register_hpd:
*
* This callback is invoked whenever bridge is registered
* for HPD handling
*
* The attach callback is optional.
*
* Host will pass HPD callback handle to bridge, with
* arguments @hpd_cb(void* dev, bool hpd, bool hpd_irq):
*
* @dev: private handle passed in register_hpd
* @hpd: true if HPD is high, false if HPD is low
* @hpd_irq: true if this is a HPD irq. @hpd will be
* ignored when hpd_irq is true.
*
* RETURNS:
*
* Zero on success, error code on failure.
*/
int (*register_hpd)(struct dp_aux_bridge *bridge,
int (*hpd_cb)(void *, bool, bool), void *dev);
/**
* @transfer:
*
* This callback is invoked whenever dp_aux transfer
* is called from host. Inside @transfer bridge can still
* call @drm_aux->transfer to trigger the actual
* DPCD/I2C transfer at host side.
*
* The attach callback is optional.
*
* RETURNS:
*
* Size of the bytes transferred, error code on failure.
*/
ssize_t (*transfer)(struct dp_aux_bridge *bridge,
struct drm_dp_aux *drm_aux,
struct drm_dp_aux_msg *msg);
};
/**
* dp_aux_add_bridge - Register DP aux bridge
* @bridge: bridge pointer
* return: 0 if successful
*/
int dp_aux_add_bridge(struct dp_aux_bridge *bridge);
#if IS_ENABLED(CONFIG_OF)
/**
* of_dp_aux_find_bridge - Find registered DP aux bridge
* @np: device node pointer to the bridge
* return: DP aux bridge pointer, NULL if not found
*/
struct dp_aux_bridge *of_dp_aux_find_bridge(struct device_node *np);
#endif /* CONFIG_OF */
#endif /* _DP_AUX_BRIDGE_H_ */

View File

@ -0,0 +1,208 @@
/*
* Copyright (c) 2019-2021, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__
#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 "dp_bridge_hpd.h"
struct dp_bridge_hpd_private {
struct device *dev;
struct dp_hpd base;
struct dp_aux_bridge *bridge;
struct delayed_work work;
struct dp_hpd_cb *cb;
bool hpd;
bool hpd_irq;
struct mutex hpd_lock;
};
static int dp_bridge_hpd_connect(struct dp_bridge_hpd_private *bridge_hpd,
bool hpd)
{
int rc = 0;
if (!bridge_hpd) {
pr_err("invalid input\n");
rc = -EINVAL;
goto error;
}
bridge_hpd->base.hpd_high = hpd;
bridge_hpd->base.alt_mode_cfg_done = hpd;
bridge_hpd->base.hpd_irq = false;
if (!bridge_hpd->cb ||
!bridge_hpd->cb->configure ||
!bridge_hpd->cb->disconnect) {
pr_err("invalid cb\n");
rc = -EINVAL;
goto error;
}
if (hpd)
rc = bridge_hpd->cb->configure(bridge_hpd->dev);
else
rc = bridge_hpd->cb->disconnect(bridge_hpd->dev);
error:
return rc;
}
static int dp_bridge_hpd_attention(struct dp_bridge_hpd_private *bridge_hpd)
{
int rc = 0;
if (!bridge_hpd) {
pr_err("invalid input\n");
rc = -EINVAL;
goto error;
}
bridge_hpd->base.hpd_irq = true;
if (bridge_hpd->cb && bridge_hpd->cb->attention)
rc = bridge_hpd->cb->attention(bridge_hpd->dev);
error:
return rc;
}
static void dp_bridge_hpd_work(struct work_struct *work)
{
struct delayed_work *dw = to_delayed_work(work);
struct dp_bridge_hpd_private *bridge_hpd = container_of(dw,
struct dp_bridge_hpd_private, work);
mutex_lock(&bridge_hpd->hpd_lock);
if (bridge_hpd->hpd_irq)
dp_bridge_hpd_attention(bridge_hpd);
else
dp_bridge_hpd_connect(bridge_hpd, bridge_hpd->hpd);
mutex_unlock(&bridge_hpd->hpd_lock);
}
static int dp_bridge_hpd_simulate_connect(struct dp_hpd *dp_hpd, bool hpd)
{
int rc = 0;
struct dp_bridge_hpd_private *bridge_hpd;
if (!dp_hpd) {
pr_err("invalid input\n");
rc = -EINVAL;
goto error;
}
bridge_hpd = container_of(dp_hpd, struct dp_bridge_hpd_private, base);
dp_bridge_hpd_connect(bridge_hpd, hpd);
error:
return rc;
}
static int dp_bridge_hpd_simulate_attention(struct dp_hpd *dp_hpd, int vdo)
{
int rc = 0;
struct dp_bridge_hpd_private *bridge_hpd;
if (!dp_hpd) {
pr_err("invalid input\n");
rc = -EINVAL;
goto error;
}
bridge_hpd = container_of(dp_hpd, struct dp_bridge_hpd_private, base);
dp_bridge_hpd_attention(bridge_hpd);
error:
return rc;
}
static int dp_bridge_hpd_cb(void *dp_hpd, bool hpd, bool hpd_irq)
{
struct dp_bridge_hpd_private *bridge_hpd = dp_hpd;
mutex_lock(&bridge_hpd->hpd_lock);
bridge_hpd->hpd = hpd;
bridge_hpd->hpd_irq = hpd_irq;
queue_delayed_work(system_wq, &bridge_hpd->work, 0);
mutex_unlock(&bridge_hpd->hpd_lock);
return 0;
}
static int dp_bridge_hpd_register(struct dp_hpd *dp_hpd)
{
struct dp_bridge_hpd_private *bridge_hpd;
if (!dp_hpd)
return -EINVAL;
bridge_hpd = container_of(dp_hpd, struct dp_bridge_hpd_private, base);
return bridge_hpd->bridge->register_hpd(bridge_hpd->bridge,
dp_bridge_hpd_cb, bridge_hpd);
}
struct dp_hpd *dp_bridge_hpd_get(struct device *dev,
struct dp_hpd_cb *cb, struct dp_aux_bridge *aux_bridge)
{
int rc = 0;
struct dp_bridge_hpd_private *bridge_hpd;
if (!dev || !cb) {
pr_err("invalid device\n");
rc = -EINVAL;
goto error;
}
bridge_hpd = devm_kzalloc(dev, sizeof(*bridge_hpd), GFP_KERNEL);
if (!bridge_hpd) {
rc = -ENOMEM;
goto error;
}
bridge_hpd->dev = dev;
bridge_hpd->cb = cb;
bridge_hpd->bridge = aux_bridge;
mutex_init(&bridge_hpd->hpd_lock);
INIT_DELAYED_WORK(&bridge_hpd->work, dp_bridge_hpd_work);
bridge_hpd->base.simulate_connect = dp_bridge_hpd_simulate_connect;
bridge_hpd->base.simulate_attention = dp_bridge_hpd_simulate_attention;
bridge_hpd->base.register_hpd = dp_bridge_hpd_register;
return &bridge_hpd->base;
error:
return ERR_PTR(rc);
}
void dp_bridge_hpd_put(struct dp_hpd *dp_hpd)
{
struct dp_bridge_hpd_private *bridge_hpd;
if (!dp_hpd)
return;
bridge_hpd = container_of(dp_hpd, struct dp_bridge_hpd_private, base);
devm_kfree(bridge_hpd->dev, bridge_hpd);
}

View File

@ -0,0 +1,42 @@
/*
* Copyright (c) 2019-2021, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef _DP_BRIDGE_HPD_H_
#define _DP_BRIDGE_HPD_H_
#include "dp_hpd.h"
/**
* dp_bridge_hpd_get() - configure and get the DisplayPlot HPD module data
*
* @dev: device instance of the caller
* @cb: callback function for HPD response
* @aux_bridge: handle for aux_bridge driver data
* return: pointer to allocated gpio hpd module data
*
* This function sets up the gpio hpd module
*/
struct dp_hpd *dp_bridge_hpd_get(struct device *dev,
struct dp_hpd_cb *cb, struct dp_aux_bridge *aux_bridge);
/**
* dp_bridge_hpd_put()
*
* Cleans up dp_hpd instance
*
* @hpd: instance of gpio_hpd
*/
void dp_bridge_hpd_put(struct dp_hpd *hpd);
#endif /* _DP_BRIDGE_HPD_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,376 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
*/
#ifndef _DP_CATALOG_H_
#define _DP_CATALOG_H_
#include <linux/version.h>
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 0))
#include <drm/display/drm_dp_helper.h>
#else
#include <drm/drm_dp_helper.h>
#endif
#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_SST_FIFO_UNDERFLOW BIT(28)
#define DP_INTR_MST_DP0_VCPF_SENT BIT(0)
#define DP_INTR_MST_DP1_VCPF_SENT BIT(3)
#define DP_INTR_SST_ML_FIFO_OVERFLOW BIT(12)
#define DP_INTR_MST0_ML_FIFO_OVERFLOW BIT(15)
#define DP_INTR_MST1_ML_FIFO_OVERFLOW BIT(18)
#define DP_INTR_DP1_FRAME_END BIT(21)
#define DP_INTR_SDP0_COLLISION BIT(24)
#define DP_INTR_SDP1_COLLISION BIT(27)
#define DP_INTR_DP0_BACKPRESSURE_ERROR (BIT(1) | BIT(0))
#define DP_INTR_DP1_BACKPRESSURE_ERROR (BIT(5) | BIT(4))
#define DP_INTR_SST_BS_LATE BIT(8)
#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_misr40_data {
u32 ctrl_misr[8];
u32 phy_misr[8];
};
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 isr3;
u32 isr5;
u32 isr6;
u8 *swing_hbr2_3;
u8 *pre_emp_hbr2_3;
u8 *swing_hbr_rbr;
u8 *pre_emp_hbr_rbr;
bool valid_lt_params;
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);
int (*setup_misr)(struct dp_catalog_ctrl *ctrl);
int (*read_misr)(struct dp_catalog_ctrl *ctrl, struct dp_misr40_data *data);
};
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, u32 pattern);
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);
int (*get_src_crc)(struct dp_catalog_panel *panel, u16 *crc);
};
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);
u32 dp_catalog_get_dp_core_version(struct dp_catalog *dp_catalog);
u32 dp_catalog_get_dp_phy_version(struct dp_catalog *dp_catalog);
#endif /* _DP_CATALOG_H_ */

View 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;
}

View File

@ -0,0 +1,346 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include "dp_catalog.h"
#include "dp_reg.h"
#include "dp_debug.h"
#include "dp_pll.h"
#include <linux/rational.h>
#include <drm/drm_fixed.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 */
};
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;
u32 phy_version;
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 */
phy_version = dp_catalog_get_dp_phy_version(catalog->dpc);
if (phy_version >= 0x60000000) {
/* Turn on BIAS current for PHY/PLL */
io_data = catalog->io->dp_pll;
dp_write(QSERDES_COM_BIAS_EN_CLKBUFLR_EN_V600, 0x17);
wmb(); /* make sure BIAS programming happened */
} else {
/* 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;
u32 phy_version;
if (!aux) {
DP_ERR("invalid input\n");
return;
}
catalog = dp_catalog_get_priv_v420(aux);
phy_version = dp_catalog_get_dp_phy_version(catalog->dpc);
io_data = catalog->io->dp_phy;
if (phy_version >= 0x60000000)
data = dp_read(DP_PHY_AUX_INTERRUPT_STATUS_V600);
else
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 mvid, nvid, mvid_off = 0, nvid_off = 0;
u32 const nvid_fixed = 0x8000;
struct dp_catalog *dp_catalog;
struct dp_catalog_private_v420 *catalog;
struct dp_io_data *io_data;
unsigned long num, den;
u32 const input_scale = 10;
u64 f1, f2;
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;
}
dp_catalog = container_of(panel, struct dp_catalog, panel);
catalog = container_of(dp_catalog->sub, struct dp_catalog_private_v420, sub);
/*
* MND calculator requires the target clock to be less than half the input clock. To meet
* this requirement, the input clock is scaled here and then the resulting M value is
* scaled by the same factor to offset the pre-scale.
*/
rational_best_approximation(rate * input_scale, stream_rate_khz,
(unsigned long)(1 << 16) - 1,
(unsigned long)(1 << 16) - 1, &den, &num);
mvid = (num & 0xFFFF);
nvid = (den & 0xFFFF);
mvid *= input_scale;
if (nvid < nvid_fixed) {
f1 = drm_fixp_from_fraction(nvid_fixed, nvid);
f2 = drm_fixp_from_fraction(mvid, 1);
f1 = drm_fixp_mul(f1, f2);
mvid = drm_fixp2int(f1);
nvid = nvid_fixed;
}
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("pclk=%ld, lclk=%ld, mvid=0x%x, nvid=0x%x\n", stream_rate_khz, rate, 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;
u32 phy_version;
int idx;
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);
phy_version = dp_catalog_get_dp_phy_version(catalog->dpc);
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 && ctrl->valid_lt_params) {
idx = v_level * MAX_VOLTAGE_LEVELS + p_level;
if (high) {
value0 = ctrl->swing_hbr2_3[idx];
value1 = ctrl->pre_emp_hbr2_3[idx];
} else {
value0 = ctrl->swing_hbr_rbr[idx];
value1 = ctrl->pre_emp_hbr_rbr[idx];
}
} 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;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,54 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2012-2021, 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);
int (*setup_misr)(struct dp_ctrl *dp_ctrl);
int (*read_misr)(struct dp_ctrl *dp_ctrl, struct dp_misr40_data *data);
};
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_pll *pll;
};
struct dp_ctrl *dp_ctrl_get(struct dp_ctrl_in *in);
void dp_ctrl_put(struct dp_ctrl *dp_ctrl);
#endif /* _DP_CTRL_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,175 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2017-2021, 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"
#include <linux/ipc_logging.h>
#define DP_IPC_LOG(fmt, ...) \
do { \
void *ipc_logging_context = get_ipc_log_context(); \
ipc_log_string(ipc_logging_context, fmt, ##__VA_ARGS__); \
} while (0)
#define DP_DEBUG(fmt, ...) \
do { \
DP_IPC_LOG("[d][%-4d]"fmt, current->pid, ##__VA_ARGS__); \
DP_DEBUG_V(fmt, ##__VA_ARGS__); \
} while (0)
#define DP_INFO(fmt, ...) \
do { \
DP_IPC_LOG("[i][%-4d]"fmt, current->pid, ##__VA_ARGS__); \
DP_INFO_V(fmt, ##__VA_ARGS__); \
} while (0)
#define DP_WARN(fmt, ...) \
do { \
DP_IPC_LOG("[w][%-4d]"fmt, current->pid, ##__VA_ARGS__); \
DP_WARN_V(fmt, ##__VA_ARGS__); \
} while (0)
#define DP_ERR(fmt, ...) \
do { \
DP_IPC_LOG("[e][%-4d]"fmt, current->pid, ##__VA_ARGS__); \
DP_ERR_V(fmt, ##__VA_ARGS__); \
} while (0)
#define DP_DEBUG_V(fmt, ...) \
do { \
if (drm_debug_enabled(DRM_UT_KMS)) \
DRM_DEBUG("[msm-dp-debug][%-4d]"fmt, current->pid, \
##__VA_ARGS__); \
else \
pr_debug("[drm:%s][msm-dp-debug][%-4d]"fmt, __func__,\
current->pid, ##__VA_ARGS__); \
} while (0)
#define DP_INFO_V(fmt, ...) \
do { \
if (drm_debug_enabled(DRM_UT_KMS)) \
DRM_INFO("[msm-dp-info][%-4d]"fmt, current->pid, \
##__VA_ARGS__); \
else \
pr_info("[drm:%s][msm-dp-info][%-4d]"fmt, __func__, \
current->pid, ##__VA_ARGS__); \
} while (0)
#define DP_WARN_V(fmt, ...) \
pr_warn("[drm:%s][msm-dp-warn][%-4d]"fmt, __func__, \
current->pid, ##__VA_ARGS__)
#define DP_WARN_RATELIMITED_V(fmt, ...) \
pr_warn_ratelimited("[drm:%s][msm-dp-warn][%-4d]"fmt, __func__, \
current->pid, ##__VA_ARGS__)
#define DP_ERR_V(fmt, ...) \
pr_err("[drm:%s][msm-dp-err][%-4d]"fmt, __func__, \
current->pid, ##__VA_ARGS__)
#define DP_ERR_RATELIMITED_V(fmt, ...) \
pr_err_ratelimited("[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
* @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
* @tpg_pattern: selects tpg pattern on the controller
* @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
* @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
* @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 sim_mode;
bool psm_enabled;
bool hdcp_disabled;
bool hdcp_wait_sink_sync;
u32 tpg_pattern;
u32 max_pclk_khz;
bool force_encryption;
bool skip_uevent;
char hdcp_status[SZ_128];
bool mst_sim_add_con;
bool mst_sim_remove_con;
int mst_sim_remove_con_id;
unsigned long connect_notification_delay_ms;
u32 disconnect_delay_ms;
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
* @display: instance of display 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;
struct dp_display *display;
};
/**
* 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_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,144 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2021-2023, Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
*/
#ifndef _DP_DISPLAY_H_
#define _DP_DISPLAY_H_
#include <linux/list.h>
#include <drm/sde_drm.h>
#include "dp_panel.h"
enum dp_drv_state {
PM_DEFAULT,
PM_SUSPEND,
};
struct dp_mst_drm_cbs {
void (*hpd)(void *display, bool hpd_status);
void (*hpd_irq)(void *display);
void (*set_drv_state)(void *dp_display,
enum dp_drv_state mst_state);
int (*set_mgr_state)(void *dp_display, bool state);
void (*set_mst_mode_params)(void *dp_display, struct dp_display_mode *mode);
};
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_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;
void *dp_ipc_log;
void *dp_aux_ipc_log;
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_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);
void (*clear_reservation)(struct dp_display *dp, struct dp_panel *panel);
int (*get_mst_pbn_div)(struct dp_display *dp);
};
void *get_ipc_log_context(void);
#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);
int dp_display_mmrm_callback(struct mmrm_client_notifier_data *notifier_data);
#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;
}
static inline int dp_display_mmrm_callback(struct mmrm_client_notifier_data *notifier_data)
{
return 0;
}
#endif /* CONFIG_DRM_MSM_DP */
#endif /* _DP_DISPLAY_H_ */

View File

@ -0,0 +1,794 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2017-2021, 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->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,
enum drm_bridge_attach_flags flags)
{
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);
dp->clear_reservation(dp, bridge->dp_panel);
}
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);
dp->clear_reservation(dp, bridge->dp_panel);
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_add_custom_mode(struct drm_connector *conn, struct dp_display_mode *dp_mode)
{
struct drm_display_mode *m, drm_mode;
memset(&drm_mode, 0x0, sizeof(drm_mode));
convert_to_drm_mode(dp_mode, &drm_mode);
m = drm_mode_duplicate(conn->dev, &drm_mode);
if (!m) {
DP_ERR("failed to add mode %ux%u\n", drm_mode.hdisplay, drm_mode.vdisplay);
return 0;
}
m->width_mm = conn->display_info.width_mm;
m->height_mm = conn->display_info.height_mm;
drm_mode_probed_add(conn, m);
return 1;
}
void init_failsafe_mode(struct dp_display_mode *dp_mode)
{
static const struct dp_panel_info fail_safe = {
.h_active = 640,
.v_active = 480,
.h_back_porch = 48,
.h_front_porch = 16,
.h_sync_width = 96,
.h_active_low = 1,
.v_back_porch = 33,
.v_front_porch = 10,
.v_sync_width = 2,
.v_active_low = 1,
.h_skew = 0,
.refresh_rate = 60,
.pixel_clk_khz = 25175,
.bpp = 24,
.widebus_en = true,
};
memcpy(&dp_mode->timing, &fail_safe, sizeof(fail_safe));
}
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_sub_mode *sub_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;
}
/* reset dp connector lm_mask for every connection event and
* this will get re-populated in resource manager based on
* resolution and topology of dp display.
*/
sde_conn->lm_mask = 0;
topology->num_enc = no_enc;
topology->num_intf = single_intf;
mode_info->frame_rate = drm_mode_vrefresh(drm_mode);
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.enabled) {
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->curr_panel_mode = MSM_DISPLAY_VIDEO_MODE;
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 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) {
/*
* 1. for test request, rc = 1, and dp_mode will have test mode populated
* 2. During normal operation, dp_mode will be untouched
* a. if mode query succeeds rc >= 0, valid modes will be added to connector
* b. if edid read failed, then connector mode list will be empty and rc <= 0
*/
rc = dp->get_modes(dp, sde_conn->drv_panel, dp_mode);
if (!rc) {
DP_WARN("failed to get DP sink modes, adding failsafe");
init_failsafe_mode(dp_mode);
}
if (dp_mode->timing.pixel_clk_khz) /* valid DP mode */
rc = dp_connector_add_custom_mode(connector, dp_mode);
} 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, 0);
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;
}
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;
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, vrefresh;
struct dp_display *dp_disp;
struct sde_connector *sde_conn;
struct msm_resource_caps_info avail_dp_res;
struct dp_panel *dp_panel;
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;
dp_panel = sde_conn->drv_panel;
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;
}
/* As per spec, failsafe mode should always be present */
if ((mode->hdisplay == 640) && (mode->vdisplay == 480) && (mode->clock == 25175))
goto validate_mode;
if (dp_panel->mode_override && (mode->hdisplay != dp_panel->hdisplay ||
mode->vdisplay != dp_panel->vdisplay ||
vrefresh != dp_panel->vrefresh ||
mode->picture_aspect_ratio != dp_panel->aspect_ratio))
return MODE_BAD;
validate_mode:
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;
}

View File

@ -0,0 +1,275 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
*/
#ifndef _DP_DRM_H_
#define _DP_DRM_H_
#include <linux/types.h>
#include <drm/drm_crtc.h>
#include <drm/drm_bridge.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
* @sub_mode: Additional mode info to drm display 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_sub_mode *sub_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);
/**
* init_failsafe_mode - add failsafe edid mode
* @dp_mode: Pointer to mode
*/
void init_failsafe_mode(struct dp_display_mode *dp_mode);
/**
* dp_connector_add_custom_mode - add edid mode to connector
* @conn: Pointer to connector
* @dp_mode: Pointer to mode
*/
int dp_connector_add_custom_mode(struct drm_connector *conn, struct dp_display_mode *dp_mode);
#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_sub_mode *sub_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_ */

View File

@ -0,0 +1,298 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved.
* 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};
unsigned int gpio;
if (!dev || !cb) {
DP_ERR("invalid device\n");
rc = -EINVAL;
goto error;
}
gpio = of_get_named_gpio(dev->of_node, hpd_gpio_name, 0);
if (!gpio_is_valid(gpio)) {
DP_DEBUG("%s gpio not specified\n", hpd_gpio_name);
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 = gpio;
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);
}

View 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_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,123 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2012-2021, 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"
#include "dp_bridge_hpd.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_aux_bridge *aux_bridge,
struct dp_hpd_cb *cb)
{
struct dp_hpd *dp_hpd = NULL;
if (aux_bridge && (aux_bridge->flag & DP_AUX_BRIDGE_HPD)) {
dp_hpd = dp_bridge_hpd_get(dev, cb, aux_bridge);
if (!IS_ERR(dp_hpd)) {
dp_hpd->type = DP_HPD_BRIDGE;
goto config;
}
}
dp_hpd = dp_lphw_hpd_get(dev, parser, catalog, cb);
if (!IS_ERR_OR_NULL(dp_hpd)) {
dp_hpd->type = DP_HPD_LPHW;
goto config;
}
dp_hpd = dp_gpio_hpd_get(dev, cb);
if (!IS_ERR_OR_NULL(dp_hpd)) {
dp_hpd->type = DP_HPD_GPIO;
goto config;
}
dp_hpd = dp_altmode_get(dev, cb);
if (!IS_ERR_OR_NULL(dp_hpd)) {
dp_hpd->type = DP_HPD_ALTMODE;
goto config;
}
dp_hpd = dp_usbpd_get(dev, cb);
if (!IS_ERR_OR_NULL(dp_hpd)) {
dp_hpd->type = DP_HPD_USBPD;
goto config;
}
DP_ERR("Failed to detect HPD type\n");
goto end;
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;
end:
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;
case DP_HPD_BRIDGE:
dp_bridge_hpd_put(dp_hpd);
break;
default:
DP_ERR("unknown hpd type %d\n", dp_hpd->type);
break;
}
}

View File

@ -0,0 +1,122 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2012-2021, 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"
#include "dp_aux_bridge.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_LPHW: LPHW based HPD
* @DP_HPD_BRIDGE: External bridge HPD
*/
enum dp_hpd_type {
DP_HPD_ALTMODE,
DP_HPD_USBPD,
DP_HPD_GPIO,
DP_HPD_LPHW,
DP_HPD_BRIDGE,
};
/**
* 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: pointer to DP parser module
* @catalog: pointer to DP catalog module
* @aux_bridge: handle for aux_bridge driver data
* @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_aux_bridge *aux_bridge,
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_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,248 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2012-2021, The Linux Foundation. All rights reserved.
*
* Copyright (c) 2008 Keith Packard
*
* 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.
*/
#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
#define DP_PHY_TEST_PATTERN_CP2520_2 0x6
#define DP_PHY_TEST_PATTERN_CP2520_3 0x7
struct drm_dp_aux;
#define DP_LINK_CAP_ENHANCED_FRAMING (1 << 0)
#define DP_LINK_CAP_CRC (1 << 1)
struct drm_dp_link {
unsigned char revision;
unsigned int rate;
unsigned int num_lanes;
unsigned long capabilities;
};
int dp_link_probe(struct drm_dp_aux *aux, struct drm_dp_link *link);
int dp_link_power_up(struct drm_dp_aux *aux, struct drm_dp_link *link);
int dp_link_power_down(struct drm_dp_aux *aux, struct drm_dp_link *link);
int dp_link_configure(struct drm_dp_aux *aux, struct drm_dp_link *link);
enum dp_link_voltage_level {
DP_LINK_VOLTAGE_LEVEL_0,
DP_LINK_VOLTAGE_LEVEL_1,
DP_LINK_VOLTAGE_LEVEL_2,
DP_LINK_VOLTAGE_LEVEL_3,
};
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,
};
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;
u8 max_v_level;
u8 max_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_PHY_TEST_PATTERN_NONE:
return DP_LINK_ENUM_STR(DP_PHY_TEST_PATTERN_NONE);
case DP_PHY_TEST_PATTERN_D10_2:
return DP_LINK_ENUM_STR(
DP_PHY_TEST_PATTERN_D10_2);
case DP_PHY_TEST_PATTERN_ERROR_COUNT:
return DP_LINK_ENUM_STR(
DP_PHY_TEST_PATTERN_ERROR_COUNT);
case DP_PHY_TEST_PATTERN_PRBS7:
return DP_LINK_ENUM_STR(DP_PHY_TEST_PATTERN_PRBS7);
case DP_PHY_TEST_PATTERN_80BIT_CUSTOM:
return DP_LINK_ENUM_STR(
DP_PHY_TEST_PATTERN_80BIT_CUSTOM);
case DP_PHY_TEST_PATTERN_CP2520:
return DP_LINK_ENUM_STR(DP_PHY_TEST_PATTERN_CP2520);
case DP_PHY_TEST_PATTERN_CP2520_2:
return DP_LINK_ENUM_STR(DP_PHY_TEST_PATTERN_CP2520_2);
case DP_PHY_TEST_PATTERN_CP2520_3:
return DP_LINK_ENUM_STR(DP_PHY_TEST_PATTERN_CP2520_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, u32 dp_core_revision);
/**
* 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_ */

View File

@ -0,0 +1,424 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved.
* 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");
}
pinctrl.state_hpd_tlmm = pinctrl.state_hpd_ctrl = NULL;
}
}
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 = NULL;
unsigned int gpio;
if (!dev || !parser || !cb) {
DP_ERR("invalid device\n");
rc = -EINVAL;
goto error;
}
gpio = of_get_named_gpio(dev->of_node, hpd_gpio_name, 0);
if (!gpio_is_valid(gpio)) {
DP_DEBUG("%s gpio not specified\n", hpd_gpio_name);
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 = gpio;
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);
}

Some files were not shown because too many files have changed in this diff Show More