sm8750: init kernel modules repo

This commit is contained in:
2025-08-11 12:21:01 +02:00
parent 2681143b87
commit facad83b01
8851 changed files with 6894561 additions and 0 deletions

View File

@@ -0,0 +1,41 @@
headers_src = [
"include/uapi/*/**/*.h",
]
display_headers_out = [
"display/drm/msm_drm_pp.h",
"display/drm/msm_drm_aiqe.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,81 @@
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(":targets/sun.bzl", "define_sun")
define_sun()
load(":targets/pineapple.bzl", "define_pineapple")
define_pineapple()
load(":targets/niobe.bzl", "define_niobe")
define_niobe()
load(":targets/monaco.bzl", "define_monaco")
define_monaco()

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,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_SUN=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,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_SUN=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.
*/

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,13 @@
# 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_SDE_WB=n
export CONFIG_DRM_MSM_REGISTER_LOGGING=y
export CONFIG_QCOM_MDSS_PLL=y
export CONFIG_MSM_SDE_ROTATOR=n
export CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=n
export CONFIG_DRM_SDE_RSC=n
export CONFIG_DISPLAY_BUILD=y

View File

@@ -0,0 +1,11 @@
/* 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_REGISTER_LOGGING 1
#define CONFIG_QCOM_MDSS_PLL 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,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=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_QCOM_SPEC_SYNC=y
export CONFIG_DISPLAY_BUILD=m
export CONFIG_HDCP_QSEECOM=y
export CONFIG_DRM_SDE_SYSTEM_SLEEP_DISABLE=y
export CONFIG_DRM_SDE_IPCC=y
export CONFIG_DRM_SDE_MINIDUMP_DISABLE=y
export CONFIG_QCOM_FSA4480_I2C=y

View File

@@ -0,0 +1,24 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022-2024 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_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_MSM_EXT_DISPLAY 1
#define CONFIG_HDCP_QSEECOM 1
#define CONFIG_DRM_SDE_SYSTEM_SLEEP_DISABLE 1
#define CONFIG_DRM_SDE_IPCC 1
#define CONFIG_DRM_SDE_MINIDUMP_DISABLE 1
#define CONFIG_QCOM_SPEC_SYNC 1
#define CONFIG_QCOM_FSA4480_I2C 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=n
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=n
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-2024 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 0
#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 0
#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,22 @@
# Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
# 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=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_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
export CONFIG_DRM_SDE_CESTA=y
export CONFIG_SMMU_PROXY=y

View File

@@ -0,0 +1,26 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2023-2024 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_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
#define CONFIG_DRM_SDE_CESTA 1
#define CONFIG_SMMU_PROXY 1

View File

@@ -0,0 +1,13 @@
# SPDX-License-Identifier: GPL-2.0-only
# Copyright (c) 2024 Qualcomm Innovation Center, Inc. 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
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) 2024 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,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,117 @@
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":
for nest_src in nest_name:
final_srcs = nest_name[nest_src]
processed_config_srcs[nest_src] = final_srcs
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)
deps = [formatter(dep) for dep in deps]
return 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 = []):
kernel_build = "{}_{}".format(target, variant)
kernel_build_label = "//msm-kernel:{}".format(kernel_build)
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)
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),
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,221 @@
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_catalog_v500.c",
"msm/dp/dp_aux.c",
"msm/dp/dp_panel.c",
"msm/dp/dp_panel_tu.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",
"msm/dp/dp_pll_3nm.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",
"msm/sde/sde_color_proc_property_helper.c",
"msm/sde/sde_color_processing_aiqe.c",
"msm/sde/sde_hw_color_proc_aiqe_v1.c",
"msm/sde/sde_aiqe_common.c",
"msm/sde/sde_loopback.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_SDE_CESTA" : [
"msm/sde_cesta.c",
"msm/sde_cesta_hw.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_hw_v7_2.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_pll_3nm.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_display_manager.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"],
},
},
deps = [
"//vendor/qcom/opensource/mm-drivers:mm_drivers_headers",
],
# Configs are handled by config_options = []
config_deps = {
"CONFIG_QTI_HW_FENCE" : [
"//vendor/qcom/opensource/mm-drivers/hw_fence:%b_msm_hw_fence",
"//vendor/qcom/opensource/synx-kernel:%b_modules",
"//vendor/qcom/opensource/synx-kernel:synx_headers",
],
"CONFIG_QCOM_SPEC_SYNC" : [
"//vendor/qcom/opensource/mm-drivers/sync_fence:%b_sync_fence",
],
"CONFIG_MSM_EXT_DISPLAY" : [
"//vendor/qcom/opensource/mm-drivers/msm_ext_display:%b_msm_ext_display",
],
"CONFIG_HDCP_QSEECOM" : [
"//vendor/qcom/opensource/securemsm-kernel:%b_hdcp_qseecom_dlkm"
],
"CONFIG_MSM_MMRM" : [
"//vendor/qcom/opensource/mmrm-driver:%b_mmrm_driver",
],
"CONFIG_SMMU_PROXY" : [
"//vendor/qcom/opensource/securemsm-kernel:%b_smmu_proxy_dlkm",
"//vendor/qcom/opensource/securemsm-kernel:smmu_proxy_headers",
],
},
)

View File

@@ -0,0 +1,348 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2022-2023 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>
#include <linux/version.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_GPL(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_GPL(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_GPL(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;
}
#if (KERNEL_VERSION(6, 3, 0) <= LINUX_VERSION_CODE)
hdcp->class = class_create(CLASS_NAME);
#else
hdcp->class = class_create(THIS_MODULE, CLASS_NAME);
#endif
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,6 @@
# SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note
header-y += msm_drm_pp.h
header-y += sde_drm.h
header-y += msm_drm_aiqe.h

View File

@@ -0,0 +1,127 @@
/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
/*
* Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef _MSM_DRM_AIQE_H_
#define _MSM_DRM_AIQE_H_
#include <linux/types.h>
#define AIQE_MDNIE_SUPPORTED
#define AIQE_MDNIE_PARAM_LEN 118
/**
* struct drm_msm_mdnie - mDNIe feature structure
* @flags - Setting flags for mDNIe feature
* @param - Parameters for mDNIe feature
*/
struct drm_msm_mdnie {
__u64 flags;
__u32 param[AIQE_MDNIE_PARAM_LEN];
};
/**
* struct drm_msm_mdnie_art - mDNIe ART feature structure
* @flags - Setting flags for mDNIe ART feature
* @param - mDNIe ART parameter
*/
struct drm_msm_mdnie_art {
__u64 flags;
__u32 param;
};
/**
* struct drm_msm_mdnie_art_done - mDNIe ART INTR structure
* @art_done - mDNIe ART done parameter
*/
struct drm_msm_mdnie_art_done {
__u32 art_done;
};
#define AIQE_SSRC_SUPPORTED
/*
* struct drm_msm_ssrc_config - AIQE SSRC configuration structure
* @flags - Configuration flags for AIQE SSRC
* @config - Configuration data
*/
#define AIQE_SSRC_PARAM_LEN 16
struct drm_msm_ssrc_config {
__u32 flags;
__u32 config[AIQE_SSRC_PARAM_LEN];
};
/*
* struct drm_msm_ssrc_data - AIQE SSRC data update structure
* @data_size - Size of total region data
* @data - Region data for SRAM. Format is as follows:
* Addr 0 - Region A size
* Addr 1:{Region A size} - SRAM data
* Addr {Region A size + 1} - Region B size
* ...
*
* Data description must match size reported in data_size.
*/
#define AIQE_SSRC_DATA_LEN 5128
struct drm_msm_ssrc_data {
__u32 data_size;
__u32 data[AIQE_SSRC_DATA_LEN];
};
#define AIQE_COPR_PARAM_LEN 17
/**
* struct drm_msm_copr - COPR feature structure
* @flags - Setting flags for COPR feature
* @param - Parameters for COPR feature
*/
struct drm_msm_copr {
__u64 flags;
__u32 param[AIQE_COPR_PARAM_LEN];
};
#define AIQE_COPR_STATUS_LEN 10
/**
* struct drm_msm_copr_status - COPR read only status structure
* @status - Parameters for COPR statistics read registers
*/
struct drm_msm_copr_status {
__u32 status[AIQE_COPR_STATUS_LEN];
};
#define AIQE_AI_SCALER_PARAM_LEN 485
/**
* struct drm_msm_ai_scaler - AI Scaler configuration structure
* @flags - Setting flags. Currently unused
* @config - configuration data
* @src_w - AI Scaler input width
* @src_h - AI Scaler input height
* @dst_w - AI Scaler output width
* @dst_h - AI Scaler output height
* @param - parameter data
*/
struct drm_msm_ai_scaler {
__u64 flags;
__u32 config;
__u32 src_w;
__u32 src_h;
__u32 dst_w;
__u32 dst_h;
__u32 param[AIQE_AI_SCALER_PARAM_LEN];
};
#define AIQE_ABC_SUPPORTED
#define AIQE_ABC_PARAM_LEN 44
#define AIQE_ABC_SRC_SEL_DMA1 1
#define AIQE_ABC_SRC_SEL_DMA3 3
/**
* struct drm_msm_abc - abc feature structure
* @flags - flags for abc feature
* @src_sel - pipe selected for abc feature
* @param - Parameters for abc feature
*/
struct drm_msm_abc {
__u64 flags;
__u32 src_sel;
__u32 param[AIQE_ABC_PARAM_LEN];
};
#endif /* _MSM_DRM_AIQE_H_ */

View File

@@ -0,0 +1,847 @@
/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
/*
* Copyright (c) 2022-2024 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_TBL_LEN_EXTENDED 128
#define PGC_8B_ROUND (1 << 0)
#define PGC_HIGHPREC_EN (1 << 1)
/**
* struct drm_msm_pgc_lut - pgc lut feature structure
* @flags: flags for the featue values can be:
* - PGC_8B_ROUND
* - PGC_HIGHPREC_EN
* @c0: color0 component lut
* @c1: color1 component lut
* @c2: color2 component lut
* @c0_extended: extended color0 component lut
* @c1_extended: extended color1 component lut
* @c2_extended: extended 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];
__u32 c0_extended[PGC_TBL_LEN_EXTENDED];
__u32 c1_extended[PGC_TBL_LEN_EXTENDED];
__u32 c2_extended[PGC_TBL_LEN_EXTENDED];
};
#define IGC_TBL_LEN 256
#define IGC_TBL_LEN_EXTENDED 128
#define IGC_DITHER_ENABLE (1 << 0)
#define IGC_HIGH_PREC_ENABLE (1 << 1)
/**
* 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
* @c0_extended: extended color0 component lut
* @c1_extended: extended color1 component lut
* @c2_extended: extended color2 component lut
*/
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;
__u32 c0_extended[IGC_TBL_LEN_EXTENDED];
__u32 c1_extended[IGC_TBL_LEN_EXTENDED];
__u32 c2_extended[IGC_TBL_LEN_EXTENDED];
};
#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)
#define DEMURA_FLAG_3
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;
__u32 cfg0_param5_len;
__u32 cfg0_param5[CFG0_PARAM_LEN];
__u32 cfg0_param6_len;
__u32 cfg0_param6[CFG0_PARAM_LEN];
__u32 cfg0_param4_1_len;
__u32 cfg0_param4_1[CFG0_PARAM_LEN];
__u32 cfg0_param5_1_len;
__u32 cfg0_param5_1[CFG0_PARAM_LEN];
__u32 cfg0_param6_1_len;
__u32 cfg0_param6_1[CFG0_PARAM_LEN];
};
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_ */

File diff suppressed because it is too large Load Diff

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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,78 @@
DISPLAY_SELECT := CONFIG_DRM_MSM=m
LOCAL_PATH := $(call my-dir)
LOCAL_MODULE_DDK_BUILD := true
include $(CLEAR_VARS)
BOARD_OPENSOURCE_DIR ?= vendor/qcom/opensource
BOARD_COMMON_DIR ?= device/qcom/common
# This makefile is only for DLKM
ifneq ($(findstring vendor,$(LOCAL_PATH)),)
ifneq ($(findstring opensource,$(LOCAL_PATH)),)
DISPLAY_BLD_DIR := $(TOP)/$(BOARD_OPENSOURCE_DIR)/display-drivers
endif # opensource
DLKM_DIR := $(TOP)/$(BOARD_COMMON_DIR)/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)
ifeq ($(CONFIG_MSM_MMRM), y)
KBUILD_OPTIONS += KBUILD_EXTRA_SYMBOLS+=$(PWD)/$(call intermediates-dir-for,DLKM,mmrm-module-symvers)/Module.symvers
endif
ifneq ($(call is-board-platform-in-list, taro monaco), true)
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
ifeq ($(CONFIG_HDCP_QSEECOM), y)
KBUILD_OPTIONS += KBUILD_EXTRA_SYMBOLS+=$(PWD)/$(call intermediates-dir-for,DLKM,sec-module-symvers)/Module.symvers
endif
ifeq ($(CONFIG_SMMU_PROXY), y)
KBUILD_OPTIONS += KBUILD_EXTRA_SYMBOLS+=$(PWD)/$(call intermediates-dir-for,DLKM,smmu-proxy-module-symvers)/Module.symvers
endif
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)
ifeq ($(CONFIG_MSM_MMRM), y)
LOCAL_REQUIRED_MODULES += mmrm-module-symvers
LOCAL_ADDITIONAL_DEPENDENCIES += $(call intermediates-dir-for,DLKM,mmrm-module-symvers)/Module.symvers
endif
ifneq ($(call is-board-platform-in-list, taro monaco), true)
LOCAL_REQUIRED_MODULES += sync-fence-module-symvers
LOCAL_REQUIRED_MODULES += msm-ext-disp-module-symvers
LOCAL_REQUIRED_MODULES += hw-fence-module-symvers
ifeq ($(CONFIG_HDCP_QSEECOM), y)
LOCAL_REQUIRED_MODULES += sec-module-symvers
endif
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
ifeq ($(CONFIG_HDCP_QSEECOM), y)
LOCAL_ADDITIONAL_DEPENDENCIES += $(call intermediates-dir-for,DLKM,sec-module-symvers)/Module.symvers
endif
endif
endif
include $(DLKM_DIR)/Build_external_kernelmodule.mk
###########################################################
endif # DLKM check

View File

@@ -0,0 +1,291 @@
# 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_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_SUN), y)
ifeq ($(CONFIG_ARCH_QTI_VM), y)
include $(DISPLAY_ROOT)/config/gki_sundisptui.conf
LINUX_INC += -include $(DISPLAY_ROOT)/config/gki_sundisptuiconf.h
else
include $(DISPLAY_ROOT)/config/gki_sundisp.conf
LINUX_INC += -include $(DISPLAY_ROOT)/config/gki_sundispconf.h
endif
endif
ifeq ($(CONFIG_ARCH_MONACO), y)
include $(DISPLAY_ROOT)/config/gki_monacodisp.conf
LINUX_INC += -include $(DISPLAY_ROOT)/config/gki_monacodispconf.h
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)/../mm-drivers/hw_fence/include \
-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_catalog_v500.o \
dp/dp_aux.o \
dp/dp_panel.o \
dp/dp_panel_tu.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 \
dp/dp_pll_3nm.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 \
sde/sde_color_proc_property_helper.o \
sde/sde_color_processing_aiqe.o \
sde/sde_hw_color_proc_aiqe_v1.o \
sde/sde_aiqe_common.o \
sde/sde_loopback.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_SDE_CESTA) += sde_cesta.o \
sde_cesta_hw.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_hw_v7_2.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_pll_3nm.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_display_manager.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,327 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2024 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/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 <linux/of_platform.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,930 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2022-2024, Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
*/
#include <linux/of_platform.h>
#include <linux/version.h>
#if (KERNEL_VERSION(6, 3, 0) <= LINUX_VERSION_CODE)
#include <msm_ext_display.h>
#else
#include <linux/soc/qcom/msm_ext_display.h>
#endif
#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->panel || !audio->panel->get_panel_on) {
DP_ERR("invalid panel data\n");
rc = -EINVAL;
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->panel || !audio->panel->get_panel_on) {
DP_ERR("invalid panel data\n");
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-2024, 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-2024, 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,385 @@
/* 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 {
bool is_edp;
void (*config_hpd)(struct dp_catalog_hpd *hpd, bool en);
u32 (*get_interrupt)(struct dp_catalog_hpd *hpd);
bool (*wait_for_edp_panel_ready)(struct dp_catalog_hpd *hpd);
void (*set_edp_mode)(struct dp_catalog_hpd *hpd, bool is_edp);
};
#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;
u32 pclk_factor;
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;
struct dp_parser *parser;
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);
struct dp_catalog_sub *dp_catalog_get_v500(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.
* Copyright (c) 2023, Qualcomm Innovation Center, Inc. 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);
mvid = mvid * (panel->pclk_factor);
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=%u, lclk=%u, 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;
}

View File

@@ -0,0 +1,474 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
*/
#define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__
#include "dp_catalog.h"
#include "dp_reg.h"
#include "dp_debug.h"
#define MMSS_DP_M_OFF (0x8)
#define MMSS_DP_N_OFF (0xC)
#define dp_catalog_get_priv_v500(x) ({ \
struct dp_catalog *catalog; \
catalog = container_of(x, struct dp_catalog, x); \
container_of(catalog->sub, \
struct dp_catalog_private_v500, 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
enum {
TX_DRIVE_MODE_LOW_SWING_LOW_HBR = 0,
TX_DRIVE_MODE_HIGH_SWING_LOW_HBR,
TX_DRIVE_MODE_LOW_SWING_HIGH_HBR,
TX_DRIVE_MODE_HIGH_SWING_HIGH_HBR,
TX_DRIVE_MODE_DP,
TX_DRIVE_MODE_MINIDP,
TX_DRIVE_MODE_MAX,
};
static const u8 ldo_config[TX_DRIVE_MODE_MAX] = {
0x81, /* 600mV */
0x00, /* off */
0x41, /* 650mV */
0x00, /* off */
0x00, /* off */
0x00, /* off */
};
static const u8 vm_pre_emphasis
[TX_DRIVE_MODE_MAX][MAX_VOLTAGE_LEVELS][MAX_PRE_EMP_LEVELS] = {
/* pe0, 0 db; pe1, 2.0 db; pe2, 3.6 db; pe3, 6.0 db */
{ // Low swing/pre-emphasis, low HBR
{0x05, 0x12, 0x17, 0x1D}, /* sw0, 0.2v */
{0x05, 0x11, 0x18, 0xFF}, /* sw1, 0.25 v */
{0x06, 0x11, 0xFF, 0xFF}, /* sw2, 0.3 v */
{0x00, 0xFF, 0xFF, 0xFF} /* sw3, 0.35 v */
},
{ // High swing/pre-emphasis, low HBR
{0x02, 0x0F, 0x17, 0x1D}, /* sw0, 0.3v */
{0x01, 0x0F, 0x17, 0xFF}, /* sw1, 0.35v */
{0x02, 0x0F, 0xFF, 0xFF}, /* sw2, 0.4v */
{0x00, 0xFF, 0xFF, 0xFF} /* sw3, 0.45v */
},
{ // Low swing/pre-emphasis, high HBR
{0x0C, 0x15, 0x19, 0x1E}, /* sw0, 0.2v */
{0x08, 0x15, 0x19, 0xFF}, /* sw1, 0.25v */
{0x0E, 0x14, 0xFF, 0xFF}, /* sw2, 0.3v */
{0x0D, 0xFF, 0xFF, 0xFF} /* sw3, 0.35v */
},
{ // High swing/pre-emphasis, high HBR
{0x08, 0x11, 0x17, 0x1B}, /* sw0, 0.3v */
{0x00, 0x0C, 0x13, 0xFF}, /* sw1, 0.35v */
{0x05, 0x10, 0xFF, 0xFF}, /* sw2, 0.4v */
{0x00, 0xFF, 0xFF, 0xFF} /* sw3, 0.45v */
},
{ // DP-only, DP/USB
{0x20, 0x2E, 0x35, 0xFF}, /* sw0, 0.4v */
{0x20, 0x2E, 0x35, 0xFF}, /* sw1, 0.6v */
{0x20, 0x2E, 0xFF, 0xFF}, /* sw2, 0.8v */
{0xFF, 0xFF, 0xFF, 0xFF} /* sw3, 1.2 v, optional */
},
{ // MiniDP-only
{0x00, 0x0E, 0x17, 0xFF}, /* sw0, 0.4v */
{0x00, 0x0D, 0x16, 0xFF}, /* sw1, 0.6v */
{0x00, 0x0D, 0xFF, 0xFF}, /* sw2, 0.8v */
{0xFF, 0xFF, 0xFF, 0xFF} /* sw3, 1.2 v, optional */
},
};
/* voltage swing, 0.2v and 1.0v are not support */
static const u8 vm_voltage_swing
[TX_DRIVE_MODE_MAX][MAX_VOLTAGE_LEVELS][MAX_PRE_EMP_LEVELS] = {
/* pe0, 0 db; pe1, 2.0 db; pe2, 3.6 db; pe3, 6.0 db */
{ // Low swing/pre-emphasis, low HBR
{0x07, 0x0F, 0x16, 0x1F}, /* sw0, 0.2v */
{0x0D, 0x16, 0x1E, 0xFF}, /* sw1, 0.25 v */
{0x11, 0x1B, 0xFF, 0xFF}, /* sw1, 0.3 v */
{0x16, 0xFF, 0xFF, 0xFF} /* sw1, 0.35 v */
},
{ // High swing/pre-emphasis, low HBR
{0x05, 0x0C, 0x14, 0x1D}, /* sw0, 0.3v */
{0x08, 0x13, 0x1B, 0xFF}, /* sw1, 0.35 v */
{0x0C, 0x17, 0xFF, 0xFF}, /* sw1, 0.4 v */
{0x14, 0xFF, 0xFF, 0xFF} /* sw1, 0.45 v */
},
{ // Low swing/pre-emphasis, high HBR
{0x0B, 0x11, 0x17, 0x1C}, /* sw0, 0.2v */
{0x10, 0x19, 0x1F, 0xFF}, /* sw1, 0.25 v */
{0x19, 0x1F, 0xFF, 0xFF}, /* sw1, 0.3 v */
{0x1F, 0xFF, 0xFF, 0xFF} /* sw1, 0.35 v */
},
{ // High swing/pre-emphasis, high HBR
{0x0A, 0x11, 0x17, 0x1F}, /* sw0, 0.3v */
{0x0C, 0x14, 0x1D, 0xFF}, /* sw1, 0.35 v */
{0x15, 0x1F, 0xFF, 0xFF}, /* sw1, 0.4 v */
{0x17, 0xFF, 0xFF, 0xFF} /* sw1, 0.45 v */
},
{ // DP-only, DP/USB
{0x27, 0x2F, 0x36, 0xFF}, /* sw0, 0.4v */
{0x31, 0x3E, 0x3F, 0xFF}, /* sw1, 0.6v */
{0x3A, 0x3F, 0xFF, 0xFF}, /* sw2, 0.8v */
{0xFF, 0xFF, 0xFF, 0xFF} /* sw3, 1.2 v, optional */
},
{ // MiniDP-only
{0x09, 0x17, 0x1F, 0xFF}, /* sw0, 0.4v */
{0x11, 0x1D, 0x1F, 0xFF}, /* sw1, 0.6v */
{0x1C, 0x1F, 0xFF, 0xFF}, /* sw2, 0.8v */
{0xFF, 0xFF, 0xFF, 0xFF} /* sw3, 1.2 v, optional */
},
};
struct dp_catalog_private_v500 {
struct device *dev;
struct dp_catalog_sub sub;
struct dp_catalog_io *io;
struct dp_catalog *dpc;
struct dp_catalog_ctrl dp_ctrl;
struct dp_catalog_audio dp_audio;
};
static void dp_catalog_aux_setup_v500(struct dp_catalog_aux *aux,
struct dp_aux_cfg *cfg)
{
struct dp_catalog_private_v500 *catalog;
struct dp_io_data *io_data;
u32 revision_id = 0;
int i = 0;
if (!aux || !cfg) {
DP_ERR("invalid input\n");
return;
}
catalog = dp_catalog_get_priv_v500(aux);
io_data = catalog->io->dp_phy;
/* PHY will not work if DP_PHY_MODE is not set */
revision_id = dp_catalog_get_dp_phy_version(catalog->dpc);
DP_DEBUG("DP phy revision_id: 0x%X\n", revision_id);
if (revision_id > 0x5000)
dp_write(DP_PHY_MODE_V500, 0xfc);
else
dp_write(DP_PHY_MODE, 0xfc);
dp_write(DP_PHY_PD_CTL_V500, 0x7d);
wmb(); /* make sure PD programming happened */
/* Turn on BIAS current for PHY/PLL */
io_data = catalog->io->dp_pll;
dp_write(QSERDES_COM_BIAS_EN_CLKBUFLR_EN,
0x17);
wmb(); /* make sure BIAS programming happened */
io_data = catalog->io->dp_phy;
/* DP AUX CFG register programming */
for (i = 0; i < PHY_AUX_CFG_MAX; i++) {
DP_DEBUG("%s: offset=0x%08x, value=0x%08x\n",
dp_phy_aux_config_type_to_string(i),
cfg[i].offset, cfg[i].lut[cfg[i].current_index]);
dp_write(cfg[i].offset,
cfg[i].lut[cfg[i].current_index]);
}
wmb(); /* make sure DP AUX CFG programming happened */
dp_write(DP_PHY_AUX_INTERRUPT_MASK_V500,
0x1F);
}
static void dp_catalog_aux_clear_hw_interrupts_v500(struct dp_catalog_aux *aux)
{
struct dp_catalog_private_v500 *catalog;
struct dp_io_data *io_data;
u32 data = 0;
if (!aux) {
DP_ERR("invalid input\n");
return;
}
catalog = dp_catalog_get_priv_v500(aux);
io_data = catalog->io->dp_phy;
data = dp_read(DP_PHY_AUX_INTERRUPT_STATUS_V500);
dp_write(DP_PHY_AUX_INTERRUPT_CLEAR_V500, 0x1f);
wmb(); /* make sure 0x1f is written before next write */
dp_write(DP_PHY_AUX_INTERRUPT_CLEAR_V500, 0x9f);
wmb(); /* make sure 0x9f is written before next write */
dp_write(DP_PHY_AUX_INTERRUPT_CLEAR_V500, 0);
wmb(); /* make sure register is cleared */
}
static void dp_catalog_panel_config_msa_v500(struct dp_catalog_panel *panel,
u32 rate, u32 stream_rate_khz)
{
u32 pixel_m, pixel_n;
u32 mvid, nvid, reg_off = 0, mvid_off = 0, nvid_off = 0;
u32 const nvid_fixed = 0x8000;
u32 const link_rate_hbr2 = 540000;
u32 const link_rate_hbr3 = 810000;
struct dp_catalog_private_v500 *catalog;
struct dp_io_data *io_data;
if (!panel || !rate) {
DP_ERR("invalid input\n");
return;
}
if (panel->stream_id >= DP_STREAM_MAX) {
DP_ERR("invalid stream id:%d\n", panel->stream_id);
return;
}
catalog = dp_catalog_get_priv_v500(panel);
io_data = catalog->io->dp_mmss_cc;
if (panel->stream_id == DP_STREAM_1)
reg_off = catalog->dpc->parser->pixel_base_off[1];
else
reg_off = catalog->dpc->parser->pixel_base_off[0];
pixel_m = dp_read(reg_off + MMSS_DP_M_OFF);
pixel_n = dp_read(reg_off + MMSS_DP_N_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);
mvid = mvid * (panel->pclk_factor);
if (link_rate_hbr2 == rate)
nvid *= 2;
if (link_rate_hbr3 == rate)
nvid *= 3;
io_data = catalog->io->dp_link;
if (panel->stream_id == DP_STREAM_1) {
mvid_off = DP1_SOFTWARE_MVID - DP_SOFTWARE_MVID;
nvid_off = DP1_SOFTWARE_NVID - DP_SOFTWARE_NVID;
}
DP_DEBUG("mvid=0x%x, nvid=0x%x\n", mvid, nvid);
dp_write(DP_SOFTWARE_MVID + mvid_off, mvid);
dp_write(DP_SOFTWARE_NVID + nvid_off, nvid);
}
static void dp_catalog_ctrl_phy_lane_cfg_v500(struct dp_catalog_ctrl *ctrl,
bool flipped, u8 ln_cnt)
{
u32 info = 0x0;
struct dp_catalog_private_v500 *catalog;
u8 orientation = BIT(!!flipped);
struct dp_io_data *io_data;
if (!ctrl) {
DP_ERR("invalid input\n");
return;
}
catalog = dp_catalog_get_priv_v500(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_V500, info);
}
static void dp_catalog_ctrl_update_vx_px_v500(struct dp_catalog_ctrl *ctrl,
u8 v_level, u8 p_level, bool high)
{
struct dp_catalog *dp_catalog;
struct dp_catalog_private_v500 *catalog;
struct dp_io_data *io_data;
u8 value0, value1, ldo_cfg;
int index;
if (!ctrl || !((v_level < MAX_VOLTAGE_LEVELS)
&& (p_level < MAX_PRE_EMP_LEVELS))) {
DP_ERR("invalid input\n");
return;
}
dp_catalog = container_of(ctrl, struct dp_catalog, ctrl);
catalog = dp_catalog_get_priv_v500(ctrl);
DP_DEBUG("hw: v=%d p=%d\n", v_level, p_level);
io_data = catalog->io->dp_phy;
switch (dp_catalog->parser->hw_cfg.phy_mode) {
case DP_PHY_MODE_DP:
case DP_PHY_MODE_UNKNOWN:
index = TX_DRIVE_MODE_DP;
break;
case DP_PHY_MODE_MINIDP:
index = TX_DRIVE_MODE_MINIDP;
break;
case DP_PHY_MODE_EDP:
default:
if (!high)
index = TX_DRIVE_MODE_LOW_SWING_LOW_HBR;
else
index = TX_DRIVE_MODE_LOW_SWING_HIGH_HBR;
break;
case DP_PHY_MODE_EDP_HIGH_SWING:
if (!high)
index = TX_DRIVE_MODE_HIGH_SWING_LOW_HBR;
else
index = TX_DRIVE_MODE_HIGH_SWING_HIGH_HBR;
break;
}
value0 = vm_voltage_swing[index][v_level][p_level];
value1 = vm_pre_emphasis[index][v_level][p_level];
ldo_cfg = ldo_config[index];
/* program default setting first */
io_data = catalog->io->dp_ln_tx0;
dp_write(TXn_LDO_CONFIG_V500, 0x01);
dp_write(TXn_TX_DRV_LVL_V500, 0x17);
dp_write(TXn_TX_EMP_POST1_LVL_V500, 0x00);
io_data = catalog->io->dp_ln_tx1;
dp_write(TXn_LDO_CONFIG_V500, 0x01);
dp_write(TXn_TX_DRV_LVL_V500, 0x2A);
dp_write(TXn_TX_EMP_POST1_LVL_V500, 0x20);
/* 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_LDO_CONFIG_V500,
ldo_cfg);
dp_write(TXn_TX_DRV_LVL_V500,
value0);
dp_write(TXn_TX_EMP_POST1_LVL_V500,
value1);
io_data = catalog->io->dp_ln_tx1;
dp_write(TXn_LDO_CONFIG_V500,
ldo_cfg);
dp_write(TXn_TX_DRV_LVL_V500,
value0);
dp_write(TXn_TX_EMP_POST1_LVL_V500,
value1);
DP_DEBUG("hw: vx_value=0x%x px_value=0x%x ldo_value=0x%x\n",
value0, value1, ldo_cfg);
} 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_v500(struct dp_catalog_ctrl *ctrl,
u8 ln_pnswap)
{
struct dp_catalog_private_v500 *catalog;
struct dp_io_data *io_data;
u32 cfg0, cfg1;
catalog = dp_catalog_get_priv_v500(ctrl);
cfg0 = 0x00;
cfg1 = 0x00;
cfg0 |= ((ln_pnswap >> 0) & 0x1) << 0;
cfg0 |= ((ln_pnswap >> 1) & 0x1) << 1;
cfg1 |= ((ln_pnswap >> 2) & 0x1) << 0;
cfg1 |= ((ln_pnswap >> 3) & 0x1) << 1;
io_data = catalog->io->dp_ln_tx0;
dp_write(TXn_TX_POL_INV_V500, cfg0);
io_data = catalog->io->dp_ln_tx1;
dp_write(TXn_TX_POL_INV_V500, cfg1);
}
static void dp_catalog_ctrl_usb_reset_v500(struct dp_catalog_ctrl *ctrl,
bool flip)
{
// USB isn't available
}
static int dp_catalog_ctrl_late_phy_init_v500(struct dp_catalog_ctrl *ctrl,
u8 lane_cnt, bool flipped)
{
// No late init
return 0;
}
static void dp_catalog_put_v500(struct dp_catalog *catalog)
{
struct dp_catalog_private_v500 *catalog_priv;
if (!catalog)
return;
catalog_priv = container_of(catalog->sub,
struct dp_catalog_private_v500, sub);
}
struct dp_catalog_sub *dp_catalog_get_v500(struct device *dev,
struct dp_catalog *catalog, struct dp_catalog_io *io)
{
struct dp_catalog_private_v500 *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->dp_ctrl = catalog->ctrl;
catalog_priv->dp_audio = catalog->audio;
catalog_priv->sub.put = dp_catalog_put_v500;
catalog->aux.setup = dp_catalog_aux_setup_v500;
catalog->aux.clear_hw_interrupts =
dp_catalog_aux_clear_hw_interrupts_v500;
catalog->panel.config_msa = dp_catalog_panel_config_msa_v500;
catalog->ctrl.phy_lane_cfg = dp_catalog_ctrl_phy_lane_cfg_v500;
catalog->ctrl.update_vx_px = dp_catalog_ctrl_update_vx_px_v500;
catalog->ctrl.lane_pnswap = dp_catalog_ctrl_lane_pnswap_v500;
catalog->ctrl.usb_reset = dp_catalog_ctrl_usb_reset_v500;
catalog->ctrl.late_phy_init = dp_catalog_ctrl_late_phy_init_v500;
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-2024, 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,164 @@
/* 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"
#include "dp_parser.h"
#define MAX_DP_ACTIVE_DISPLAY 8
enum dp_drv_state {
PM_DEFAULT,
PM_SUSPEND,
};
struct dp_display_info {
u32 cell_idx;
u32 intf_idx[DP_STREAM_MAX];
u32 phy_idx;
u32 stream_cnt;
};
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 is_edp;
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);
int (*get_display_type)(struct dp_display *dp_display,
const char **display_type);
int (*mst_get_fixed_topology_display_type)(struct dp_display *dp_display,
u32 strm_id, const char **display_type);
int (*edp_detect)(struct dp_display *dp_display);
};
void *get_ipc_log_context(void);
#if IS_ENABLED(CONFIG_DRM_MSM_DP)
int dp_display_get_num_of_displays(struct drm_device *dev);
int dp_display_get_displays(struct drm_device *dev, void **displays, int count);
int dp_display_get_num_of_streams(struct drm_device *dev);
int dp_display_get_info(void *dp_display, struct dp_display_info *dp_info);
int dp_display_mmrm_callback(struct mmrm_client_notifier_data *notifier_data);
#else
static inline int dp_display_get_num_of_displays(struct drm_device *dev)
{
return 0;
}
static inline int dp_display_get_displays(struct drm_device *dev, void **displays, int count)
{
return 0;
}
static inline int dp_display_get_num_of_streams(struct drm_device *dev)
{
return 0;
}
static inline int dp_display_get_info(void *dp_display, struct dp_display_info *dp_info)
{
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,827 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2022-2024 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;
mode_info->pclk_factor = dp_panel->pclk_factor;
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;
if (display && display->is_edp) {
info->intf_type = DRM_MODE_CONNECTOR_eDP;
info->display_type = SDE_CONNECTOR_PRIMARY;
} else {
info->capabilities |= 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;
struct dp_display *dp_disp;
int rc;
if (!conn || !display)
return status;
dp_disp = display;
/* 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;
rc = dp_disp->edp_detect(dp_disp);
if (rc) {
DP_ERR("error in turning on panel power sequence rc:%d\n", rc);
return connector_status_unknown;
}
}
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_connector_set_info_blob(struct drm_connector *connector,
void *info, void *display, struct msm_mode_info *mode_info)
{
struct dp_display *dp_display = display;
const char *display_type = NULL;
dp_display->get_display_type(dp_display, &display_type);
sde_kms_info_add_keystr(info, "display type", display_type);
return 0;
}
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;
else if (dp_panel->mode_override)
mode->type |= DRM_MODE_TYPE_PREFERRED;
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 */
#if (KERNEL_VERSION(6, 3, 0) <= LINUX_VERSION_CODE)
rc = drm_mode_create_dp_colorspace_property(base_conn, 0);
#else
rc = drm_mode_create_dp_colorspace_property(base_conn);
#endif
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,293 @@
/* 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
*/
/**
* dp_conn_set_info_blob - callback to perform info blob initialization
* @connector: Pointer to drm connector structure
* @info: Pointer to sde connector info structure
* @display: Pointer to private display handle
* @mode_info: Pointer to mode info structure
* Returns: Zero on success
*/
int dp_connector_set_info_blob(struct drm_connector *connector,
void *info, void *display, struct msm_mode_info *mode_info);
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_connector_set_info_blob(struct drm_connector *connector,
void *info, void *display, struct msm_mode_info *mode_info)
{
return 0;
}
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 inline 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,302 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2021-2024, 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/version.h>
#if (KERNEL_VERSION(6, 3, 0) <= LINUX_VERSION_CODE)
#include <linux/pinctrl/consumer.h>
#endif
#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;
strscpy(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_ */

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