diff --git a/packages/linux-firmware/firmware-imx/package.mk b/packages/linux-firmware/firmware-imx/package.mk index 89563f3fdc..63ae591ad5 100644 --- a/packages/linux-firmware/firmware-imx/package.mk +++ b/packages/linux-firmware/firmware-imx/package.mk @@ -3,9 +3,9 @@ # Copyright (C) 2019-present Team LibreELEC (https://libreelec.tv) PKG_NAME="firmware-imx" -PKG_VERSION="8.21" -PKG_SHA256="c3447f0f813415ccea9dc2ef12080cb3ac8bbc0c67392a74fc7d59205eb5a672" -PKG_ARCH="arm" +PKG_VERSION="8.25-27879f8" +PKG_SHA256="55766dad38961fde3ed3224ee6a46ab1c5aea62a5b947530228d8fbc4a7d2816" +PKG_ARCH="aarch64 arm" PKG_LICENSE="other" PKG_SITE="http://www.freescale.com" PKG_URL="https://www.nxp.com/lgfiles/NMG/MAD/YOCTO/${PKG_NAME}-${PKG_VERSION}.bin" @@ -20,11 +20,17 @@ unpack() { makeinstall_target() { mkdir -p ${INSTALL}/$(get_full_firmware_dir)/imx/sdma - cp -P firmware/sdma/sdma-imx6q.bin ${INSTALL}/$(get_full_firmware_dir)/imx/sdma - cp -P firmware/sdma/sdma-imx7d.bin ${INSTALL}/$(get_full_firmware_dir)/imx/sdma - mkdir -p ${INSTALL}/$(get_full_firmware_dir)/vpu - cp -P firmware/vpu/vpu_fw_imx6d.bin ${INSTALL}/$(get_full_firmware_dir)/vpu - cp -P firmware/vpu/vpu_fw_imx6q.bin ${INSTALL}/$(get_full_firmware_dir)/vpu - cp -P firmware/vpu/vpu_fw_imx8_dec.bin ${INSTALL}/$(get_full_firmware_dir)/vpu + + case "${DEVICE}" in + "iMX6") + cp -P firmware/sdma/sdma-imx6q.bin ${INSTALL}/$(get_full_firmware_dir)/imx/sdma + cp -P firmware/vpu/vpu_fw_imx6d.bin ${INSTALL}/$(get_full_firmware_dir)/vpu + cp -P firmware/vpu/vpu_fw_imx6q.bin ${INSTALL}/$(get_full_firmware_dir)/vpu + ;; + "iMX8") + cp -P firmware/sdma/sdma-imx7d.bin ${INSTALL}/$(get_full_firmware_dir)/imx/sdma + cp -P firmware/vpu/vpu_fw_imx8_dec.bin ${INSTALL}/$(get_full_firmware_dir)/vpu + ;; + esac } diff --git a/projects/NXP/README.md b/projects/NXP/README.md new file mode 100644 index 0000000000..e5f726113a --- /dev/null +++ b/projects/NXP/README.md @@ -0,0 +1,15 @@ +# NXP + +This project is for NXP SoC devices + +## Devices + +**iMX6** +* [Cubox-i](devices/iMX6) +* [Udoo](devices/iMX6) +* [Wandboard](devices/iMX6) + +**iMX8** +* [Coral Edge TPU Development Board](devices/iMX8) +* [i.MX8MQ EVK](devices/iMX8) +* [TechNexion PICO-PI-8M](devices/iMX8) diff --git a/projects/NXP/devices/iMX8/linux/linux.aarch64.conf b/projects/NXP/devices/iMX8/linux/linux.aarch64.conf index 395deef367..1506fb9303 100644 --- a/projects/NXP/devices/iMX8/linux/linux.aarch64.conf +++ b/projects/NXP/devices/iMX8/linux/linux.aarch64.conf @@ -1,20 +1,21 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/arm64 6.10.0 Kernel Configuration +# Linux/arm64 6.11.0 Kernel Configuration # -CONFIG_CC_VERSION_TEXT="aarch64-libreelec-linux-gnu-gcc-14.1.0 (GCC) 14.1.0" +CONFIG_CC_VERSION_TEXT="aarch64-libreelec-linux-gnu-gcc-14.2.0 (GCC) 14.2.0" CONFIG_CC_IS_GCC=y -CONFIG_GCC_VERSION=140100 +CONFIG_GCC_VERSION=140200 CONFIG_CLANG_VERSION=0 CONFIG_AS_IS_GNU=y -CONFIG_AS_VERSION=24200 +CONFIG_AS_VERSION=24301 CONFIG_LD_IS_BFD=y -CONFIG_LD_VERSION=24200 +CONFIG_LD_VERSION=24301 CONFIG_LLD_VERSION=0 CONFIG_CC_CAN_LINK=y CONFIG_CC_CAN_LINK_STATIC=y CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y CONFIG_CC_HAS_ASM_GOTO_TIED_OUTPUT=y +CONFIG_TOOLS_SUPPORT_RELR=y CONFIG_CC_HAS_ASM_INLINE=y CONFIG_CC_HAS_NO_PROFILE_FN_ATTR=y CONFIG_PAHOLE_VERSION=0 @@ -157,7 +158,7 @@ CONFIG_CGROUPS=y CONFIG_PAGE_COUNTER=y # CONFIG_CGROUP_FAVOR_DYNMODS is not set CONFIG_MEMCG=y -CONFIG_MEMCG_KMEM=y +# CONFIG_MEMCG_V1 is not set CONFIG_BLK_CGROUP=y CONFIG_CGROUP_WRITEBACK=y CONFIG_CGROUP_SCHED=y @@ -238,7 +239,6 @@ CONFIG_CACHESTAT_SYSCALL=y CONFIG_KALLSYMS=y # CONFIG_KALLSYMS_SELFTEST is not set # CONFIG_KALLSYMS_ALL is not set -CONFIG_KALLSYMS_BASE_RELATIVE=y CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y CONFIG_HAVE_PERF_EVENTS=y @@ -270,7 +270,6 @@ CONFIG_ARCH_MMAP_RND_BITS_MIN=18 CONFIG_ARCH_MMAP_RND_BITS_MAX=33 CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=11 CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=16 -CONFIG_NO_IOPORT_MAP=y CONFIG_STACKTRACE_SUPPORT=y CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000 CONFIG_LOCKDEP_SUPPORT=y @@ -372,7 +371,6 @@ CONFIG_ARM64_ERRATUM_1319367=y # CONFIG_ARM64_ERRATUM_2966298 is not set # CONFIG_ARM64_ERRATUM_3117295 is not set # CONFIG_ARM64_ERRATUM_3194386 is not set -# CONFIG_ARM64_ERRATUM_3312417 is not set # CONFIG_CAVIUM_ERRATUM_22375 is not set # CONFIG_CAVIUM_ERRATUM_23154 is not set # CONFIG_CAVIUM_ERRATUM_27456 is not set @@ -506,6 +504,7 @@ CONFIG_ARM64_CONTPTE=y # CONFIG_CMDLINE="" # CONFIG_EFI is not set +# CONFIG_COMPRESSED_INSTALL is not set # end of Boot options # @@ -688,6 +687,7 @@ CONFIG_HAVE_ARCH_COMPILER_H=y CONFIG_HAVE_ARCH_PREL32_RELOCATIONS=y # CONFIG_LOCK_EVENT_COUNTS is not set CONFIG_ARCH_HAS_RELR=y +CONFIG_RELR=y CONFIG_HAVE_PREEMPT_DYNAMIC=y CONFIG_HAVE_PREEMPT_DYNAMIC_KEY=y CONFIG_ARCH_WANT_LD_ORPHAN_WARN=y @@ -875,6 +875,7 @@ CONFIG_COREDUMP=y # CONFIG_SWAP=y # CONFIG_ZSWAP is not set +CONFIG_HAVE_ZSMALLOC=y # # Slab allocator options @@ -884,6 +885,7 @@ CONFIG_SLUB=y CONFIG_SLAB_MERGE_DEFAULT=y # CONFIG_SLAB_FREELIST_RANDOM is not set # CONFIG_SLAB_FREELIST_HARDENED is not set +CONFIG_SLAB_BUCKETS=y # CONFIG_SLUB_STATS is not set CONFIG_SLUB_CPU_PARTIAL=y # CONFIG_RANDOM_KMALLOC_CACHES is not set @@ -926,7 +928,7 @@ CONFIG_THP_SWAP=y CONFIG_PGTABLE_HAS_HUGE_LEAVES=y CONFIG_CMA=y CONFIG_CMA_DEBUGFS=y -# CONFIG_CMA_SYSFS is not set +CONFIG_CMA_SYSFS=y CONFIG_CMA_AREAS=7 CONFIG_GENERIC_EARLY_IOREMAP=y # CONFIG_DEFERRED_STRUCT_PAGE_INIT is not set @@ -1470,6 +1472,7 @@ CONFIG_BT_HCIUART_QCA=y # CONFIG_BT_HCIUART_AG6XX is not set # CONFIG_BT_HCIUART_MRVL is not set CONFIG_BT_HCIBCM203X=m +# CONFIG_BT_HCIBCM4377 is not set # CONFIG_BT_HCIBPA10X is not set CONFIG_BT_HCIBFUSB=m # CONFIG_BT_HCIVHCI is not set @@ -1478,6 +1481,7 @@ CONFIG_BT_ATH3K=m # CONFIG_BT_MTKSDIO is not set # CONFIG_BT_MTKUART is not set CONFIG_BT_NXPUART=m +# CONFIG_BT_INTEL_PCIE is not set # end of Bluetooth device drivers # CONFIG_AF_RXRPC is not set @@ -1535,8 +1539,87 @@ CONFIG_ETHTOOL_NETLINK=y CONFIG_ARM_AMBA=y CONFIG_HAVE_PCI=y CONFIG_GENERIC_PCI_IOMAP=y -# CONFIG_PCI is not set +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_DOMAINS_GENERIC=y +CONFIG_PCI_SYSCALL=y +# CONFIG_PCIEPORTBUS is not set +# CONFIG_PCIEASPM is not set +# CONFIG_PCIE_PTM is not set +CONFIG_PCI_MSI=y +CONFIG_PCI_QUIRKS=y +# CONFIG_PCI_DEBUG is not set +# CONFIG_PCI_STUB is not set +# CONFIG_PCI_IOV is not set +# CONFIG_PCI_PRI is not set +# CONFIG_PCI_PASID is not set +CONFIG_PCI_DYNAMIC_OF_NODES=y +# CONFIG_PCIE_BUS_TUNE_OFF is not set +CONFIG_PCIE_BUS_DEFAULT=y +# CONFIG_PCIE_BUS_SAFE is not set +# CONFIG_PCIE_BUS_PERFORMANCE is not set +# CONFIG_PCIE_BUS_PEER2PEER is not set +# CONFIG_VGA_ARB is not set +# CONFIG_HOTPLUG_PCI is not set + +# +# PCI controller drivers +# +# CONFIG_PCIE_ALTERA is not set +# CONFIG_PCI_HOST_THUNDER_PEM is not set +# CONFIG_PCI_HOST_THUNDER_ECAM is not set +# CONFIG_PCI_FTPCI100 is not set +# CONFIG_PCI_HOST_GENERIC is not set +# CONFIG_PCI_XGENE is not set +# CONFIG_PCIE_XILINX is not set + +# +# Cadence-based PCIe controllers +# +# CONFIG_PCIE_CADENCE_PLAT_HOST is not set +# end of Cadence-based PCIe controllers + +# +# DesignWare-based PCIe controllers +# +CONFIG_PCIE_DW=y +CONFIG_PCIE_DW_HOST=y +# CONFIG_PCIE_AL is not set +# CONFIG_PCI_MESON is not set +CONFIG_PCI_IMX6=y +CONFIG_PCI_IMX6_HOST=y +# CONFIG_PCI_HISI is not set +# CONFIG_PCIE_KIRIN is not set +# CONFIG_PCIE_DW_PLAT_HOST is not set +# end of DesignWare-based PCIe controllers + +# +# Mobiveil-based PCIe controllers +# +# end of Mobiveil-based PCIe controllers + +# +# PLDA-based PCIe controllers +# +# CONFIG_PCIE_MICROCHIP_HOST is not set +# end of PLDA-based PCIe controllers +# end of PCI controller drivers + +# +# PCI Endpoint +# +# CONFIG_PCI_ENDPOINT is not set +# end of PCI Endpoint + +# +# PCI switch controller drivers +# +# CONFIG_PCI_SW_SWITCHTEC is not set +# end of PCI switch controller drivers + +# CONFIG_CXL_BUS is not set # CONFIG_PCCARD is not set +# CONFIG_RAPIDIO is not set # # Generic Driver Options @@ -1610,6 +1693,7 @@ CONFIG_GENERIC_ARCH_TOPOLOGY=y CONFIG_ARM_SCPI_PROTOCOL=y # CONFIG_FIRMWARE_MEMMAP is not set +# CONFIG_FW_CFG_SYSFS is not set # CONFIG_ARM_FFA_TRANSPORT is not set # CONFIG_GOOGLE_FIRMWARE is not set CONFIG_IMX_DSP=m @@ -1689,6 +1773,7 @@ CONFIG_MTD_CFI_I2=y # # Self-contained MTD device drivers # +# CONFIG_MTD_PMC551 is not set # CONFIG_MTD_DATAFLASH is not set # CONFIG_MTD_MCHP23K256 is not set # CONFIG_MTD_MCHP48L640 is not set @@ -1749,6 +1834,7 @@ CONFIG_OF_OVERLAY=y CONFIG_BLK_DEV=y # CONFIG_BLK_DEV_NULL_BLK is not set CONFIG_CDROM=y +# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_LOOP_MIN_COUNT=0 # CONFIG_BLK_DEV_DRBD is not set @@ -1764,6 +1850,7 @@ CONFIG_BLK_DEV_RAM_SIZE=4096 # # NVME Support # +# CONFIG_BLK_DEV_NVME is not set # CONFIG_NVME_FC is not set # CONFIG_NVME_TCP is not set # CONFIG_NVME_TARGET is not set @@ -1774,8 +1861,11 @@ CONFIG_BLK_DEV_RAM_SIZE=4096 # # CONFIG_AD525X_DPOT is not set # CONFIG_DUMMY_IRQ is not set +# CONFIG_PHANTOM is not set +# CONFIG_TIFM_CORE is not set # CONFIG_ICS932S401 is not set # CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_HP_ILO is not set # CONFIG_APDS9802ALS is not set # CONFIG_ISL29003 is not set # CONFIG_ISL29020 is not set @@ -1786,6 +1876,8 @@ CONFIG_BLK_DEV_RAM_SIZE=4096 # CONFIG_DS1682 is not set # CONFIG_LATTICE_ECP3_CONFIG is not set # CONFIG_SRAM is not set +# CONFIG_DW_XDATA_PCIE is not set +# CONFIG_PCI_ENDPOINT_TEST is not set # CONFIG_XILINX_SDFEC is not set # CONFIG_HISI_HIKEY_USB is not set # CONFIG_OPEN_DICE is not set @@ -1804,6 +1896,8 @@ CONFIG_EEPROM_93CX6=m # CONFIG_EEPROM_EE1004 is not set # end of EEPROM support +# CONFIG_CB710_CORE is not set + # # Texas Instruments shared transport line discipline # @@ -1813,10 +1907,17 @@ CONFIG_EEPROM_93CX6=m # CONFIG_SENSORS_LIS3_SPI is not set # CONFIG_SENSORS_LIS3_I2C is not set # CONFIG_ALTERA_STAPL is not set +# CONFIG_VMWARE_VMCI is not set +# CONFIG_GENWQE is not set # CONFIG_ECHO is not set +# CONFIG_BCM_VK is not set +# CONFIG_MISC_ALCOR_PCI is not set +# CONFIG_MISC_RTSX_PCI is not set # CONFIG_MISC_RTSX_USB is not set # CONFIG_UACCE is not set # CONFIG_PVPANIC is not set +# CONFIG_GP_PCI1XXXX is not set +# CONFIG_KEBA_CP500 is not set # end of Misc devices # @@ -1857,7 +1958,52 @@ CONFIG_SCSI_SAS_HOST_SMP=y CONFIG_SCSI_LOWLEVEL=y # CONFIG_ISCSI_TCP is not set # CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_SCSI_CXGB3_ISCSI is not set +# CONFIG_SCSI_CXGB4_ISCSI is not set +# CONFIG_SCSI_BNX2_ISCSI is not set +# CONFIG_BE2ISCSI is not set +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_HPSA is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_3W_SAS is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_MVSAS is not set +# CONFIG_SCSI_MVUMI is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_SCSI_ESAS2R is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_SCSI_MPT3SAS is not set +# CONFIG_SCSI_MPT2SAS is not set +# CONFIG_SCSI_MPI3MR is not set +# CONFIG_SCSI_SMARTPQI is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_MYRB is not set +# CONFIG_SCSI_MYRS is not set +# CONFIG_SCSI_SNIC is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_FDOMAIN_PCI is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_WD719X is not set # CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_PMCRAID is not set +# CONFIG_SCSI_PM8001 is not set # CONFIG_SCSI_DH is not set # end of SCSI device support @@ -1896,6 +2042,15 @@ CONFIG_DM_THIN_PROVISIONING=m # CONFIG_DM_INTEGRITY is not set # CONFIG_DM_VDO is not set # CONFIG_TARGET_CORE is not set +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_FIREWIRE is not set +# CONFIG_FIREWIRE_NOSY is not set +# end of IEEE 1394 (FireWire) support + CONFIG_NETDEVICES=y CONFIG_MII=y CONFIG_NET_CORE=y @@ -1904,6 +2059,7 @@ CONFIG_DUMMY=m CONFIG_WIREGUARD=m # CONFIG_WIREGUARD_DEBUG is not set # CONFIG_EQUALIZER is not set +# CONFIG_NET_FC is not set # CONFIG_NET_TEAM is not set CONFIG_MACVLAN=m # CONFIG_MACVTAP is not set @@ -1927,20 +2083,31 @@ CONFIG_TUN=y CONFIG_VETH=m CONFIG_NLMON=m # CONFIG_NETKIT is not set +# CONFIG_ARCNET is not set CONFIG_ETHERNET=y +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_NET_VENDOR_ADAPTEC is not set +# CONFIG_NET_VENDOR_AGERE is not set # CONFIG_NET_VENDOR_ALACRITECH is not set +# CONFIG_NET_VENDOR_ALTEON is not set # CONFIG_ALTERA_TSE is not set # CONFIG_NET_VENDOR_AMAZON is not set # CONFIG_NET_VENDOR_AMD is not set # CONFIG_NET_VENDOR_AQUANTIA is not set # CONFIG_NET_VENDOR_ARC is not set # CONFIG_NET_VENDOR_ASIX is not set +# CONFIG_NET_VENDOR_ATHEROS is not set # CONFIG_NET_VENDOR_BROADCOM is not set # CONFIG_NET_VENDOR_CADENCE is not set # CONFIG_NET_VENDOR_CAVIUM is not set +# CONFIG_NET_VENDOR_CHELSIO is not set +# CONFIG_NET_VENDOR_CISCO is not set # CONFIG_NET_VENDOR_CORTINA is not set # CONFIG_NET_VENDOR_DAVICOM is not set # CONFIG_DNET is not set +# CONFIG_NET_VENDOR_DEC is not set +# CONFIG_NET_VENDOR_DLINK is not set +# CONFIG_NET_VENDOR_EMULEX is not set # CONFIG_NET_VENDOR_ENGLEDER is not set # CONFIG_NET_VENDOR_EZCHIP is not set CONFIG_NET_VENDOR_FREESCALE=y @@ -1948,30 +2115,52 @@ CONFIG_FEC=y # CONFIG_FSL_PQ_MDIO is not set # CONFIG_FSL_XGMAC_MDIO is not set # CONFIG_GIANFAR is not set +# CONFIG_FSL_ENETC is not set +# CONFIG_FSL_ENETC_VF is not set # CONFIG_FSL_ENETC_IERB is not set +# CONFIG_FSL_ENETC_MDIO is not set # CONFIG_NET_VENDOR_FUNGIBLE is not set CONFIG_NET_VENDOR_GOOGLE=y +# CONFIG_GVE is not set # CONFIG_NET_VENDOR_HISILICON is not set # CONFIG_NET_VENDOR_HUAWEI is not set # CONFIG_NET_VENDOR_INTEL is not set +# CONFIG_JME is not set # CONFIG_NET_VENDOR_ADI is not set # CONFIG_NET_VENDOR_LITEX is not set # CONFIG_NET_VENDOR_MARVELL is not set # CONFIG_NET_VENDOR_MELLANOX is not set +# CONFIG_NET_VENDOR_META is not set # CONFIG_NET_VENDOR_MICREL is not set # CONFIG_NET_VENDOR_MICROCHIP is not set # CONFIG_NET_VENDOR_MICROSEMI is not set # CONFIG_NET_VENDOR_MICROSOFT is not set +# CONFIG_NET_VENDOR_MYRI is not set +# CONFIG_FEALNX is not set # CONFIG_NET_VENDOR_NI is not set # CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_NETERION is not set # CONFIG_NET_VENDOR_NETRONOME is not set +# CONFIG_NET_VENDOR_NVIDIA is not set +# CONFIG_NET_VENDOR_OKI is not set # CONFIG_ETHOC is not set +# CONFIG_NET_VENDOR_PACKET_ENGINES is not set CONFIG_NET_VENDOR_PENSANDO=y +# CONFIG_IONIC is not set +# CONFIG_NET_VENDOR_QLOGIC is not set +# CONFIG_NET_VENDOR_BROCADE is not set # CONFIG_NET_VENDOR_QUALCOMM is not set +# CONFIG_NET_VENDOR_RDC is not set +CONFIG_NET_VENDOR_REALTEK=y +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_R8169 is not set # CONFIG_NET_VENDOR_RENESAS is not set # CONFIG_NET_VENDOR_ROCKER is not set # CONFIG_NET_VENDOR_SAMSUNG is not set # CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SILAN is not set +# CONFIG_NET_VENDOR_SIS is not set # CONFIG_NET_VENDOR_SOLARFLARE is not set # CONFIG_NET_VENDOR_SMSC is not set # CONFIG_NET_VENDOR_SOCIONEXT is not set @@ -1983,7 +2172,11 @@ CONFIG_STMMAC_PLATFORM=y CONFIG_DWMAC_GENERIC=y CONFIG_DWMAC_IMX8=y # CONFIG_DWMAC_INTEL_PLAT is not set +# CONFIG_STMMAC_PCI is not set +# CONFIG_NET_VENDOR_SUN is not set # CONFIG_NET_VENDOR_SYNOPSYS is not set +# CONFIG_NET_VENDOR_TEHUTI is not set +# CONFIG_NET_VENDOR_TI is not set # CONFIG_NET_VENDOR_VERTEXCOM is not set # CONFIG_NET_VENDOR_VIA is not set # CONFIG_NET_VENDOR_WANGXUN is not set @@ -1991,6 +2184,8 @@ CONFIG_DWMAC_IMX8=y CONFIG_NET_VENDOR_XILINX=y # CONFIG_XILINX_EMACLITE is not set # CONFIG_XILINX_LL_TEMAC is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set CONFIG_PHYLINK=y CONFIG_PHYLIB=y CONFIG_SWPHY=y @@ -2074,6 +2269,7 @@ CONFIG_MDIO_BITBANG=y # CONFIG_MDIO_OCTEON is not set # CONFIG_MDIO_IPQ4019 is not set # CONFIG_MDIO_IPQ8064 is not set +# CONFIG_MDIO_THUNDER is not set # # MDIO Multiplexers @@ -2130,14 +2326,17 @@ CONFIG_USB_IPHETH=m # CONFIG_USB_NET_AQC111 is not set CONFIG_USB_RTL8153_ECM=m CONFIG_WLAN=y -CONFIG_WLAN_VENDOR_ADMTEK=y +# CONFIG_WLAN_VENDOR_ADMTEK is not set CONFIG_ATH_COMMON=m CONFIG_WLAN_VENDOR_ATH=y # CONFIG_ATH_DEBUG is not set +# CONFIG_ATH5K is not set +# CONFIG_ATH5K_PCI is not set CONFIG_ATH9K_HW=m CONFIG_ATH9K_COMMON=m CONFIG_ATH9K_BTCOEX_SUPPORT=y CONFIG_ATH9K=m +# CONFIG_ATH9K_PCI is not set # CONFIG_ATH9K_AHB is not set # CONFIG_ATH9K_DYNACK is not set # CONFIG_ATH9K_WOW is not set @@ -2156,15 +2355,20 @@ CONFIG_ATH6KL=m CONFIG_ATH6KL_USB=m # CONFIG_ATH6KL_DEBUG is not set CONFIG_AR5523=m +# CONFIG_WIL6210 is not set CONFIG_ATH10K=m CONFIG_ATH10K_CE=y +CONFIG_ATH10K_PCI=m +# CONFIG_ATH10K_AHB is not set CONFIG_ATH10K_SDIO=m CONFIG_ATH10K_USB=m # CONFIG_ATH10K_DEBUG is not set # CONFIG_ATH10K_DEBUGFS is not set +CONFIG_ATH10K_LEDS=y CONFIG_WCN36XX=m # CONFIG_WCN36XX_DEBUGFS is not set # CONFIG_ATH11K is not set +# CONFIG_ATH12K is not set CONFIG_WLAN_VENDOR_ATMEL=y # CONFIG_AT76C50X_USB is not set CONFIG_WLAN_VENDOR_BROADCOM=y @@ -2191,18 +2395,26 @@ CONFIG_BRCMFMAC=m CONFIG_BRCMFMAC_PROTO_BCDC=y CONFIG_BRCMFMAC_SDIO=y CONFIG_BRCMFMAC_USB=y +# CONFIG_BRCMFMAC_PCIE is not set # CONFIG_BRCM_TRACING is not set # CONFIG_BRCMDBG is not set CONFIG_WLAN_VENDOR_INTEL=y +# CONFIG_IPW2100 is not set +# CONFIG_IPW2200 is not set +# CONFIG_IWL4965 is not set +# CONFIG_IWL3945 is not set +# CONFIG_IWLWIFI is not set CONFIG_WLAN_VENDOR_INTERSIL=y CONFIG_P54_COMMON=m CONFIG_P54_USB=m +# CONFIG_P54_PCI is not set # CONFIG_P54_SPI is not set CONFIG_P54_LEDS=y CONFIG_WLAN_VENDOR_MARVELL=y # CONFIG_LIBERTAS is not set # CONFIG_LIBERTAS_THINFIRM is not set # CONFIG_MWIFIEX is not set +# CONFIG_MWL8K is not set CONFIG_WLAN_VENDOR_MEDIATEK=y CONFIG_MT7601U=m CONFIG_MT76_CORE=m @@ -2215,13 +2427,21 @@ CONFIG_MT792x_LIB=m CONFIG_MT792x_USB=m CONFIG_MT76x0_COMMON=m CONFIG_MT76x0U=m +# CONFIG_MT76x0E is not set CONFIG_MT76x2_COMMON=m +# CONFIG_MT76x2E is not set CONFIG_MT76x2U=m +# CONFIG_MT7603E is not set +# CONFIG_MT7615E is not set # CONFIG_MT7663U is not set # CONFIG_MT7663S is not set +# CONFIG_MT7915E is not set CONFIG_MT7921_COMMON=m +# CONFIG_MT7921E is not set # CONFIG_MT7921S is not set CONFIG_MT7921U=m +# CONFIG_MT7996E is not set +# CONFIG_MT7925E is not set # CONFIG_MT7925U is not set CONFIG_WLAN_VENDOR_MICROCHIP=y # CONFIG_WILC1000_SDIO is not set @@ -2229,6 +2449,10 @@ CONFIG_WLAN_VENDOR_MICROCHIP=y # CONFIG_WLAN_VENDOR_PURELIFI is not set CONFIG_WLAN_VENDOR_RALINK=y CONFIG_RT2X00=m +# CONFIG_RT2400PCI is not set +# CONFIG_RT2500PCI is not set +# CONFIG_RT61PCI is not set +# CONFIG_RT2800PCI is not set CONFIG_RT2500USB=m CONFIG_RT73USB=m CONFIG_RT2800USB=m @@ -2246,9 +2470,18 @@ CONFIG_RT2X00_LIB_CRYPTO=y CONFIG_RT2X00_LIB_LEDS=y # CONFIG_RT2X00_DEBUG is not set CONFIG_WLAN_VENDOR_REALTEK=y +# CONFIG_RTL8180 is not set CONFIG_RTL8187=m CONFIG_RTL8187_LEDS=y CONFIG_RTL_CARDS=m +# CONFIG_RTL8192CE is not set +# CONFIG_RTL8192SE is not set +# CONFIG_RTL8192DE is not set +# CONFIG_RTL8723AE is not set +# CONFIG_RTL8723BE is not set +# CONFIG_RTL8188EE is not set +# CONFIG_RTL8192EE is not set +# CONFIG_RTL8821AE is not set # CONFIG_RTL8192CU is not set CONFIG_RTL8192DU=m CONFIG_RTLWIFI=m @@ -2265,13 +2498,17 @@ CONFIG_RTW88_8822C=m CONFIG_RTW88_8723X=m CONFIG_RTW88_8723D=m CONFIG_RTW88_8821C=m +# CONFIG_RTW88_8822BE is not set # CONFIG_RTW88_8822BS is not set CONFIG_RTW88_8822BU=m +# CONFIG_RTW88_8822CE is not set # CONFIG_RTW88_8822CS is not set CONFIG_RTW88_8822CU=m +# CONFIG_RTW88_8723DE is not set # CONFIG_RTW88_8723DS is not set # CONFIG_RTW88_8723CS is not set CONFIG_RTW88_8723DU=m +# CONFIG_RTW88_8821CE is not set # CONFIG_RTW88_8821CS is not set CONFIG_RTW88_8821CU=m # CONFIG_RTW88_DEBUG is not set @@ -2303,6 +2540,7 @@ CONFIG_ZD1211RW=m # CONFIG_WWAN is not set # end of Wireless WAN +# CONFIG_VMXNET3 is not set # CONFIG_NETDEVSIM is not set # CONFIG_NET_FAILOVER is not set # CONFIG_ISDN is not set @@ -2466,6 +2704,7 @@ CONFIG_RMI4_F30=y CONFIG_SERIO=y CONFIG_SERIO_SERPORT=y # CONFIG_SERIO_AMBAKMI is not set +# CONFIG_SERIO_PCIPS2 is not set # CONFIG_SERIO_LIBPS2 is not set # CONFIG_SERIO_RAW is not set # CONFIG_SERIO_ALTERA_PS2 is not set @@ -2502,10 +2741,13 @@ CONFIG_SERIAL_8250_16550A_VARIANTS=y # CONFIG_SERIAL_8250_FINTEK is not set CONFIG_SERIAL_8250_CONSOLE=y CONFIG_SERIAL_8250_DMA=y +# CONFIG_SERIAL_8250_PCI is not set +# CONFIG_SERIAL_8250_EXAR is not set CONFIG_SERIAL_8250_NR_UARTS=1 CONFIG_SERIAL_8250_RUNTIME_UARTS=0 CONFIG_SERIAL_8250_EXTENDED=y # CONFIG_SERIAL_8250_MANY_PORTS is not set +# CONFIG_SERIAL_8250_PCI1XXXX is not set CONFIG_SERIAL_8250_SHARE_IRQ=y # CONFIG_SERIAL_8250_DETECT_IRQ is not set # CONFIG_SERIAL_8250_RSA is not set @@ -2513,6 +2755,7 @@ CONFIG_SERIAL_8250_DWLIB=y CONFIG_SERIAL_8250_FSL=y CONFIG_SERIAL_8250_DW=y # CONFIG_SERIAL_8250_RT288X is not set +# CONFIG_SERIAL_8250_PERICOM is not set CONFIG_SERIAL_OF_PLATFORM=y # @@ -2529,6 +2772,7 @@ CONFIG_SERIAL_IMX_CONSOLE=y # CONFIG_SERIAL_UARTLITE is not set CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set # CONFIG_SERIAL_SIFIVE is not set # CONFIG_SERIAL_SCCNXP is not set # CONFIG_SERIAL_SC16IS7XX is not set @@ -2536,6 +2780,7 @@ CONFIG_SERIAL_CORE_CONSOLE=y # CONFIG_SERIAL_ALTERA_UART is not set # CONFIG_SERIAL_XILINX_PS_UART is not set # CONFIG_SERIAL_ARC is not set +# CONFIG_SERIAL_RP2 is not set # CONFIG_SERIAL_FSL_LPUART is not set # CONFIG_SERIAL_FSL_LINFLEXUART is not set # CONFIG_SERIAL_CONEXANT_DIGICOLOR is not set @@ -2545,6 +2790,7 @@ CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_SERIAL_MCTRL_GPIO=y # CONFIG_SERIAL_NONSTANDARD is not set # CONFIG_N_GSM is not set +# CONFIG_NOZOMI is not set # CONFIG_NULL_TTY is not set # CONFIG_HVC_DCC is not set CONFIG_SERIAL_DEV_BUS=y @@ -2561,6 +2807,8 @@ CONFIG_HW_RANDOM_OPTEE=m # CONFIG_HW_RANDOM_CCTRNG is not set # CONFIG_HW_RANDOM_XIPHERA is not set CONFIG_HW_RANDOM_ARM_SMCCC_TRNG=m +# CONFIG_HW_RANDOM_CN10K is not set +# CONFIG_APPLICOM is not set CONFIG_DEVMEM=y CONFIG_DEVPORT=y # CONFIG_TCG_TPM is not set @@ -2599,6 +2847,25 @@ CONFIG_I2C_ALGOBIT=m # I2C Hardware Bus support # +# +# PC SMBus host controller drivers +# +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_ISCH is not set +# CONFIG_I2C_PIIX4 is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_NVIDIA_GPU is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set + # # I2C system bus drivers (mostly embedded / system-on-chip) # @@ -2607,6 +2874,7 @@ CONFIG_I2C_ALGOBIT=m CONFIG_I2C_DESIGNWARE_CORE=y # CONFIG_I2C_DESIGNWARE_SLAVE is not set CONFIG_I2C_DESIGNWARE_PLATFORM=y +# CONFIG_I2C_DESIGNWARE_PCI is not set # CONFIG_I2C_EMEV2 is not set # CONFIG_I2C_GPIO is not set # CONFIG_I2C_HISI is not set @@ -2617,6 +2885,7 @@ CONFIG_I2C_IMX_LPI2C=y # CONFIG_I2C_PCA_PLATFORM is not set # CONFIG_I2C_RK3X is not set # CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_THUNDERX is not set # CONFIG_I2C_XILINX is not set # @@ -2624,6 +2893,7 @@ CONFIG_I2C_IMX_LPI2C=y # # CONFIG_I2C_DIOLAN_U2C is not set # CONFIG_I2C_CP2615 is not set +# CONFIG_I2C_PCI1XXXX is not set # CONFIG_I2C_ROBOTFUZZ_OSIF is not set # CONFIG_I2C_TAOS_EVM is not set # CONFIG_I2C_TINY_USB is not set @@ -2659,6 +2929,7 @@ CONFIG_SPI_BITBANG=y # CONFIG_SPI_CADENCE is not set # CONFIG_SPI_CADENCE_QUADSPI is not set # CONFIG_SPI_CADENCE_XSPI is not set +# CONFIG_SPI_CH341 is not set # CONFIG_SPI_DESIGNWARE is not set # CONFIG_SPI_FSL_LPSPI is not set # CONFIG_SPI_FSL_QUADSPI is not set @@ -2669,11 +2940,13 @@ CONFIG_SPI_IMX=y # CONFIG_SPI_MICROCHIP_CORE is not set # CONFIG_SPI_MICROCHIP_CORE_QSPI is not set # CONFIG_SPI_OC_TINY is not set +# CONFIG_SPI_PCI1XXXX is not set CONFIG_SPI_PL022=y # CONFIG_SPI_SC18IS602 is not set # CONFIG_SPI_SIFIVE is not set # CONFIG_SPI_SN_F_OSPI is not set # CONFIG_SPI_MXIC is not set +# CONFIG_SPI_THUNDERX is not set # CONFIG_SPI_XCOMM is not set # CONFIG_SPI_XILINX is not set # CONFIG_SPI_ZYNQMP_GQSPI is not set @@ -2744,6 +3017,7 @@ CONFIG_PINCTRL_IMX8QXP=y # CONFIG_PINCTRL_IMX8DXL is not set # CONFIG_PINCTRL_IMX8ULP is not set # CONFIG_PINCTRL_IMXRT1050 is not set +# CONFIG_PINCTRL_IMX91 is not set # CONFIG_PINCTRL_IMX93 is not set # CONFIG_PINCTRL_IMXRT1170 is not set @@ -2810,6 +3084,15 @@ CONFIG_GPIO_VF610=y # CONFIG_GPIO_WM8994 is not set # end of MFD GPIO expanders +# +# PCI GPIO expanders +# +# CONFIG_GPIO_BT8XX is not set +# CONFIG_GPIO_PCI_IDIO_16 is not set +# CONFIG_GPIO_PCIE_IDIO_24 is not set +# CONFIG_GPIO_RDC321X is not set +# end of PCI GPIO expanders + # # SPI GPIO expanders # @@ -2835,6 +3118,13 @@ CONFIG_GPIO_VF610=y # CONFIG_GPIO_SIM is not set # end of Virtual GPIO drivers +# +# GPIO Debugging utilities +# +# CONFIG_GPIO_SLOPPY_LOGIC_ANALYZER is not set +# CONFIG_GPIO_VIRTUSER is not set +# end of GPIO Debugging utilities + # CONFIG_W1 is not set CONFIG_POWER_RESET=y CONFIG_POWER_RESET_GPIO=y @@ -2847,6 +3137,7 @@ CONFIG_POWER_RESET_SYSCON=y # CONFIG_POWER_RESET_SYSCON_POWEROFF is not set # CONFIG_SYSCON_REBOOT_MODE is not set # CONFIG_NVMEM_REBOOT_MODE is not set +# CONFIG_POWER_SEQUENCING is not set CONFIG_POWER_SUPPLY=y # CONFIG_POWER_SUPPLY_DEBUG is not set CONFIG_POWER_SUPPLY_HWMON=y @@ -2865,6 +3156,7 @@ CONFIG_POWER_SUPPLY_HWMON=y # CONFIG_BATTERY_BQ27XXX is not set # CONFIG_BATTERY_MAX17040 is not set # CONFIG_BATTERY_MAX17042 is not set +# CONFIG_BATTERY_MAX1720X is not set # CONFIG_CHARGER_MAX8903 is not set # CONFIG_CHARGER_LP8727 is not set # CONFIG_CHARGER_GPIO is not set @@ -2903,7 +3195,6 @@ CONFIG_HWMON=y # CONFIG_SENSORS_AD7314 is not set # CONFIG_SENSORS_AD7414 is not set # CONFIG_SENSORS_AD7418 is not set -# CONFIG_SENSORS_ADM1021 is not set # CONFIG_SENSORS_ADM1025 is not set # CONFIG_SENSORS_ADM1026 is not set # CONFIG_SENSORS_ADM1029 is not set @@ -2927,8 +3218,10 @@ CONFIG_SENSORS_ARM_SCPI=y # CONFIG_SENSORS_CHIPCAP2 is not set # CONFIG_SENSORS_CORSAIR_CPRO is not set # CONFIG_SENSORS_CORSAIR_PSU is not set +# CONFIG_SENSORS_CROS_EC is not set # CONFIG_SENSORS_DS620 is not set # CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_I5K_AMB is not set # CONFIG_SENSORS_F71805F is not set # CONFIG_SENSORS_F71882FG is not set # CONFIG_SENSORS_F75375S is not set @@ -2973,7 +3266,6 @@ CONFIG_SENSORS_GPIO_FAN=m # CONFIG_SENSORS_MAX6620 is not set # CONFIG_SENSORS_MAX6621 is not set # CONFIG_SENSORS_MAX6639 is not set -# CONFIG_SENSORS_MAX6642 is not set # CONFIG_SENSORS_MAX6650 is not set # CONFIG_SENSORS_MAX6697 is not set # CONFIG_SENSORS_MAX31790 is not set @@ -3023,6 +3315,7 @@ CONFIG_SENSORS_PWM_FAN=m # CONFIG_SENSORS_SHT3x is not set # CONFIG_SENSORS_SHT4x is not set # CONFIG_SENSORS_SHTC1 is not set +# CONFIG_SENSORS_SIS5595 is not set # CONFIG_SENSORS_DME1737 is not set # CONFIG_SENSORS_EMC1403 is not set # CONFIG_SENSORS_EMC2103 is not set @@ -3042,6 +3335,7 @@ CONFIG_SENSORS_PWM_FAN=m # CONFIG_SENSORS_INA2XX is not set # CONFIG_SENSORS_INA238 is not set # CONFIG_SENSORS_INA3221 is not set +# CONFIG_SENSORS_SPD5118 is not set # CONFIG_SENSORS_TC74 is not set # CONFIG_SENSORS_THMC50 is not set # CONFIG_SENSORS_TMP102 is not set @@ -3051,7 +3345,9 @@ CONFIG_SENSORS_PWM_FAN=m # CONFIG_SENSORS_TMP421 is not set # CONFIG_SENSORS_TMP464 is not set # CONFIG_SENSORS_TMP513 is not set +# CONFIG_SENSORS_VIA686A is not set # CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_VT8231 is not set # CONFIG_SENSORS_W83773G is not set # CONFIG_SENSORS_W83781D is not set # CONFIG_SENSORS_W83791D is not set @@ -3116,8 +3412,17 @@ CONFIG_IMX2_WDT=y # CONFIG_IMX_SC_WDT is not set # CONFIG_IMX7ULP_WDT is not set # CONFIG_ARM_SMC_WATCHDOG is not set +# CONFIG_ALIM7101_WDT is not set +# CONFIG_I6300ESB_WDT is not set +# CONFIG_HP_WATCHDOG is not set # CONFIG_MEN_A21_WDT is not set +# +# PCI-based Watchdog Cards +# +# CONFIG_PCIPCWATCHDOG is not set +# CONFIG_WDTPCI is not set + # # USB-based Watchdog Cards # @@ -3131,7 +3436,9 @@ CONFIG_SSB_SDIOHOST_POSSIBLE=y CONFIG_BCMA_POSSIBLE=y CONFIG_BCMA=m CONFIG_BCMA_BLOCKIO=y +# CONFIG_BCMA_HOST_PCI is not set # CONFIG_BCMA_HOST_SOC is not set +# CONFIG_BCMA_DRIVER_PCI is not set # CONFIG_BCMA_DRIVER_GMAC_CMN is not set # CONFIG_BCMA_DRIVER_GPIO is not set # CONFIG_BCMA_DEBUG is not set @@ -3168,11 +3475,15 @@ CONFIG_MFD_CROS_EC_DEV=y # CONFIG_MFD_MC13XXX_I2C is not set # CONFIG_MFD_MP2629 is not set # CONFIG_MFD_HI6421_PMIC is not set +# CONFIG_LPC_ICH is not set +# CONFIG_LPC_SCH is not set # CONFIG_MFD_IQS62X is not set +# CONFIG_MFD_JANZ_CMODIO is not set # CONFIG_MFD_KEMPLD is not set # CONFIG_MFD_88PM800 is not set # CONFIG_MFD_88PM805 is not set # CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_88PM886_PMIC is not set # CONFIG_MFD_MAX14577 is not set # CONFIG_MFD_MAX77541 is not set # CONFIG_MFD_MAX77620 is not set @@ -3197,6 +3508,7 @@ CONFIG_MFD_CROS_EC_DEV=y # CONFIG_MFD_RETU is not set # CONFIG_MFD_PCF50633 is not set # CONFIG_MFD_SY7636A is not set +# CONFIG_MFD_RDC321X is not set # CONFIG_MFD_RT4831 is not set # CONFIG_MFD_RT5033 is not set # CONFIG_MFD_RT5120 is not set @@ -3236,6 +3548,7 @@ CONFIG_MFD_SYSCON=y # CONFIG_MFD_LM3533 is not set # CONFIG_MFD_TC3589X is not set # CONFIG_MFD_TQMX86 is not set +# CONFIG_MFD_VX855 is not set # CONFIG_MFD_LOCHNAGAR is not set CONFIG_MFD_ARIZONA=m CONFIG_MFD_ARIZONA_I2C=m @@ -3253,10 +3566,13 @@ CONFIG_MFD_WM8994=y CONFIG_MFD_ROHM_BD718XX=y # CONFIG_MFD_ROHM_BD71828 is not set # CONFIG_MFD_ROHM_BD957XMUF is not set +# CONFIG_MFD_ROHM_BD96801 is not set # CONFIG_MFD_STPMIC1 is not set # CONFIG_MFD_STMFX is not set # CONFIG_MFD_ATC260X_I2C is not set # CONFIG_MFD_QCOM_PM8008 is not set +# CONFIG_MFD_CS40L50_I2C is not set +# CONFIG_MFD_CS40L50_SPI is not set # CONFIG_RAVE_SP_CORE is not set # CONFIG_MFD_INTEL_M10_BMC_SPI is not set # CONFIG_MFD_RSMU_I2C is not set @@ -3381,8 +3697,6 @@ CONFIG_IR_TTUSBIR=m CONFIG_RC_ATI_REMOTE=m # CONFIG_RC_LOOPBACK is not set CONFIG_RC_XBOX_DVD=m -CONFIG_CEC_CORE=y -CONFIG_CEC_NOTIFIER=y # # CEC support @@ -3542,6 +3856,8 @@ CONFIG_DVB_USB_UMT_010=m CONFIG_DVB_USB_VP702X=m CONFIG_DVB_USB_VP7045=m CONFIG_SMS_USB_DRV=m +# CONFIG_DVB_TTUSB_BUDGET is not set +# CONFIG_DVB_TTUSB_DEC is not set # # Webcam, TV (analog/digital) USB devices @@ -3558,6 +3874,7 @@ CONFIG_VIDEO_EM28XX_RC=m # CONFIG_USB_AIRSPY is not set # CONFIG_USB_HACKRF is not set # CONFIG_USB_MSI2500 is not set +# CONFIG_MEDIA_PCI_SUPPORT is not set # CONFIG_RADIO_ADAPTERS is not set CONFIG_MEDIA_PLATFORM_DRIVERS=y # CONFIG_V4L_PLATFORM_DRIVERS is not set @@ -3597,6 +3914,7 @@ CONFIG_VIDEO_MEM2MEM_DEINTERLACE=m # Chips&Media media platform drivers # # CONFIG_VIDEO_CODA is not set +# CONFIG_VIDEO_E5010_JPEG_ENC is not set # # Intel media platform drivers @@ -3638,6 +3956,10 @@ CONFIG_VIDEO_IMX8_JPEG=m # Qualcomm media platform drivers # +# +# Raspberry Pi media platform drivers +# + # # Renesas media platform drivers # @@ -3715,6 +4037,8 @@ CONFIG_VIDEO_CAMERA_SENSOR=y # CONFIG_VIDEO_ALVIUM_CSI2 is not set # CONFIG_VIDEO_AR0521 is not set # CONFIG_VIDEO_GC0308 is not set +# CONFIG_VIDEO_GC05A2 is not set +# CONFIG_VIDEO_GC08A3 is not set # CONFIG_VIDEO_GC2145 is not set # CONFIG_VIDEO_HI556 is not set # CONFIG_VIDEO_HI846 is not set @@ -3724,6 +4048,7 @@ CONFIG_VIDEO_CAMERA_SENSOR=y # CONFIG_VIDEO_IMX219 is not set # CONFIG_VIDEO_IMX258 is not set # CONFIG_VIDEO_IMX274 is not set +# CONFIG_VIDEO_IMX283 is not set # CONFIG_VIDEO_IMX290 is not set # CONFIG_VIDEO_IMX296 is not set # CONFIG_VIDEO_IMX319 is not set @@ -3779,7 +4104,7 @@ CONFIG_VIDEO_CAMERA_SENSOR=y # CONFIG_VIDEO_S5C73M3 is not set # CONFIG_VIDEO_S5K5BAF is not set # CONFIG_VIDEO_S5K6A3 is not set -# CONFIG_VIDEO_ST_VGXY61 is not set +# CONFIG_VIDEO_VGXY61 is not set # CONFIG_VIDEO_CCS is not set # CONFIG_VIDEO_ET8EK8 is not set @@ -3919,6 +4244,8 @@ CONFIG_VIDEO_CX25840=m # CONFIG_VIDEO_DS90UB913 is not set # CONFIG_VIDEO_DS90UB953 is not set # CONFIG_VIDEO_DS90UB960 is not set +# CONFIG_VIDEO_MAX96714 is not set +# CONFIG_VIDEO_MAX96717 is not set # end of Video serializers and deserializers # @@ -4157,13 +4484,14 @@ CONFIG_DRM_FBDEV_EMULATION=y CONFIG_DRM_FBDEV_OVERALLOC=100 # CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM is not set CONFIG_DRM_LOAD_EDID_FIRMWARE=y -CONFIG_DRM_DISPLAY_HELPER=y CONFIG_DRM_DISPLAY_DP_AUX_BUS=y +CONFIG_DRM_DISPLAY_HELPER=y +CONFIG_DRM_BRIDGE_CONNECTOR=y # CONFIG_DRM_DISPLAY_DP_AUX_CEC is not set # CONFIG_DRM_DISPLAY_DP_AUX_CHARDEV is not set CONFIG_DRM_DISPLAY_DP_HELPER=y -CONFIG_DRM_DISPLAY_HDCP_HELPER=y CONFIG_DRM_DISPLAY_HDMI_HELPER=y +CONFIG_DRM_DISPLAY_HDMI_STATE_HELPER=y CONFIG_DRM_GEM_DMA_HELPER=y CONFIG_DRM_SCHED=y @@ -4184,9 +4512,17 @@ CONFIG_DRM_SCHED=y # CONFIG_DRM_KOMEDA is not set # end of ARM devices +# CONFIG_DRM_RADEON is not set +# CONFIG_DRM_AMDGPU is not set +# CONFIG_DRM_NOUVEAU is not set +# CONFIG_DRM_XE is not set # CONFIG_DRM_VGEM is not set # CONFIG_DRM_VKMS is not set +# CONFIG_DRM_VMWGFX is not set # CONFIG_DRM_UDL is not set +# CONFIG_DRM_AST is not set +# CONFIG_DRM_MGAG200 is not set +# CONFIG_DRM_QXL is not set CONFIG_DRM_PANEL=y # @@ -4269,13 +4605,9 @@ CONFIG_DRM_FSL_LDB=m # CONFIG_DRM_ANALOGIX_ANX7625 is not set # CONFIG_DRM_I2C_ADV7511 is not set # CONFIG_DRM_CDNS_DSI is not set +CONFIG_CDNS_MHDP_HELPER=y # CONFIG_DRM_CDNS_MHDP8546 is not set -CONFIG_DRM_CDNS_MHDP=y -CONFIG_DRM_CDNS_HDMI=y -CONFIG_DRM_CDNS_DP=y -CONFIG_DRM_CDNS_AUDIO=y -CONFIG_DRM_CDNS_HDMI_HDCP=y -CONFIG_DRM_CDNS_HDMI_CEC=y +CONFIG_DRM_CDNS_MHDP8501=y # CONFIG_DRM_IMX8MP_DW_HDMI_BRIDGE is not set # CONFIG_DRM_IMX8MP_HDMI_PVI is not set # CONFIG_DRM_IMX8QM_LDB is not set @@ -4288,14 +4620,16 @@ CONFIG_DRM_CDNS_HDMI_CEC=y CONFIG_DRM_IMX_DCSS=y # CONFIG_DRM_IMX_LCDC is not set -CONFIG_DRM_IMX_CDNS_MHDP=y CONFIG_DRM_ETNAVIV=y CONFIG_DRM_ETNAVIV_THERMAL=y +# CONFIG_DRM_HISI_HIBMC is not set # CONFIG_DRM_HISI_KIRIN is not set # CONFIG_DRM_LOGICVC is not set # CONFIG_DRM_MXSFB is not set # CONFIG_DRM_IMX_LCDIF is not set # CONFIG_DRM_ARCPGU is not set +# CONFIG_DRM_BOCHS is not set +# CONFIG_DRM_CIRRUS_QEMU is not set # CONFIG_DRM_GM12U320 is not set # CONFIG_DRM_PANEL_MIPI_DBI is not set # CONFIG_DRM_SIMPLEDRM is not set @@ -4323,16 +4657,42 @@ CONFIG_DRM_PANEL_ORIENTATION_QUIRKS=y # Frame buffer Devices # CONFIG_FB=y +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_PM2 is not set # CONFIG_FB_IMX is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_ASILIANT is not set +# CONFIG_FB_IMSTT is not set # CONFIG_FB_OPENCORES is not set # CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_NVIDIA is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_I740 is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_S3 is not set +# CONFIG_FB_SAVAGE is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_VT8623 is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_ARK is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_CARMINE is not set # CONFIG_FB_SMSCUFX is not set # CONFIG_FB_UDL is not set # CONFIG_FB_IBM_GXT4500 is not set # CONFIG_FB_VIRTUAL is not set # CONFIG_FB_METRONOME is not set +# CONFIG_FB_MB862XX is not set # CONFIG_FB_SIMPLE is not set # CONFIG_FB_SSD1307 is not set +# CONFIG_FB_SM712 is not set CONFIG_FB_CORE=y CONFIG_FB_NOTIFY=y # CONFIG_FIRMWARE_EDID is not set @@ -4362,6 +4722,7 @@ CONFIG_BACKLIGHT_CLASS_DEVICE=y # CONFIG_BACKLIGHT_QCOM_WLED is not set # CONFIG_BACKLIGHT_ADP8860 is not set # CONFIG_BACKLIGHT_ADP8870 is not set +# CONFIG_BACKLIGHT_LM3509 is not set # CONFIG_BACKLIGHT_LM3630A is not set # CONFIG_BACKLIGHT_LM3639 is not set # CONFIG_BACKLIGHT_LP855X is not set @@ -4423,6 +4784,7 @@ CONFIG_SND_DRIVERS=y # CONFIG_SND_SERIAL_U16550 is not set # CONFIG_SND_SERIAL_GENERIC is not set # CONFIG_SND_MPU401 is not set +# CONFIG_SND_PCI is not set # # HD-Audio @@ -4468,7 +4830,6 @@ CONFIG_SND_IMX_SOC=y # CONFIG_SND_SOC_IMX_ES8328=y CONFIG_SND_SOC_IMX_SGTL5000=y -CONFIG_SND_SOC_IMX_SPDIF=y CONFIG_SND_SOC_FSL_ASOC_CARD=y CONFIG_SND_SOC_IMX_AUDMIX=y CONFIG_SND_SOC_IMX_HDMI=y @@ -4511,6 +4872,7 @@ CONFIG_SND_SOC_WM_HUBS=y CONFIG_SND_SOC_AK4458=y # CONFIG_SND_SOC_AK4554 is not set # CONFIG_SND_SOC_AK4613 is not set +# CONFIG_SND_SOC_AK4619 is not set # CONFIG_SND_SOC_AK4642 is not set # CONFIG_SND_SOC_AK5386 is not set CONFIG_SND_SOC_AK5558=y @@ -4552,12 +4914,14 @@ CONFIG_SND_SOC_AK5558=y # CONFIG_SND_SOC_CS4341 is not set # CONFIG_SND_SOC_CS4349 is not set # CONFIG_SND_SOC_CS53L30 is not set +# CONFIG_SND_SOC_CS530X_I2C is not set # CONFIG_SND_SOC_CX2072X is not set # CONFIG_SND_SOC_DA7213 is not set # CONFIG_SND_SOC_DMIC is not set CONFIG_SND_SOC_HDMI_CODEC=y CONFIG_SND_SOC_ES7134=y # CONFIG_SND_SOC_ES7241 is not set +# CONFIG_SND_SOC_ES8311 is not set # CONFIG_SND_SOC_ES8316 is not set # CONFIG_SND_SOC_ES8326 is not set CONFIG_SND_SOC_ES8328=y @@ -4851,6 +5215,7 @@ CONFIG_USB_COMMON=y # CONFIG_USB_CONN_GPIO is not set CONFIG_USB_ARCH_HAS_HCD=y CONFIG_USB=y +# CONFIG_USB_PCI is not set CONFIG_USB_ANNOUNCE_NEW_DEVICES=y # @@ -4954,6 +5319,7 @@ CONFIG_USB_DWC2=y # # CONFIG_USB_DWC2_PERIPHERAL is not set CONFIG_USB_DWC2_DUAL_ROLE=y +# CONFIG_USB_DWC2_PCI is not set # CONFIG_USB_DWC2_DEBUG is not set # CONFIG_USB_DWC2_TRACK_MISSED_SOFS is not set # CONFIG_USB_CHIPIDEA is not set @@ -5122,6 +5488,7 @@ CONFIG_MMC_BLOCK_MINORS=32 # CONFIG_MMC_ARMMMCI is not set CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_IO_ACCESSORS=y +# CONFIG_MMC_SDHCI_PCI is not set CONFIG_MMC_SDHCI_PLTFM=y # CONFIG_MMC_SDHCI_OF_ARASAN is not set # CONFIG_MMC_SDHCI_OF_AT91 is not set @@ -5132,13 +5499,17 @@ CONFIG_MMC_SDHCI_ESDHC_IMX=y # CONFIG_MMC_SDHCI_F_SDH30 is not set # CONFIG_MMC_SDHCI_MILBEAUT is not set # CONFIG_MMC_MXC is not set +# CONFIG_MMC_TIFM_SD is not set CONFIG_MMC_SPI=y +# CONFIG_MMC_CB710 is not set +# CONFIG_MMC_VIA_SDMMC is not set # CONFIG_MMC_DW is not set # CONFIG_MMC_VUB300 is not set # CONFIG_MMC_USHC is not set # CONFIG_MMC_USDHI6ROL0 is not set CONFIG_MMC_CQHCI=y # CONFIG_MMC_HSQ is not set +# CONFIG_MMC_TOSHIBA_PCI is not set # CONFIG_MMC_MTK is not set # CONFIG_MMC_SDHCI_XENON is not set # CONFIG_SCSI_UFSHCD is not set @@ -5158,6 +5529,7 @@ CONFIG_LEDS_CLASS_MULTICOLOR=y # CONFIG_LEDS_BCM6328 is not set # CONFIG_LEDS_BCM6358 is not set # CONFIG_LEDS_CR0014114 is not set +# CONFIG_LEDS_CROS_EC is not set # CONFIG_LEDS_EL15203000 is not set # CONFIG_LEDS_LM3530 is not set # CONFIG_LEDS_LM3532 is not set @@ -5205,6 +5577,7 @@ CONFIG_LEDS_SYSCON=y # CONFIG_LEDS_RT4505 is not set # CONFIG_LEDS_RT8515 is not set # CONFIG_LEDS_SGM3140 is not set +# CONFIG_LEDS_SY7802 is not set # # RGB LED drivers @@ -5237,6 +5610,7 @@ CONFIG_LEDS_TRIGGER_CPU=y # CONFIG_LEDS_TRIGGER_NETDEV is not set # CONFIG_LEDS_TRIGGER_PATTERN is not set # CONFIG_LEDS_TRIGGER_TTY is not set +# CONFIG_LEDS_TRIGGER_INPUT_EVENTS is not set # # Simple LED drivers @@ -5387,6 +5761,7 @@ CONFIG_IMX_SDMA=m # CONFIG_MV_XOR_V2 is not set # CONFIG_MXS_DMA is not set CONFIG_PL330_DMA=m +# CONFIG_PLX_DMA is not set # CONFIG_XILINX_DMA is not set # CONFIG_XILINX_XDMA is not set # CONFIG_XILINX_ZYNQMP_DMA is not set @@ -5395,6 +5770,8 @@ CONFIG_PL330_DMA=m # CONFIG_QCOM_HIDMA is not set CONFIG_DW_DMAC_CORE=m CONFIG_DW_DMAC=m +# CONFIG_DW_DMAC_PCI is not set +# CONFIG_DW_EDMA is not set # CONFIG_SF_PDMA is not set # @@ -5438,6 +5815,8 @@ CONFIG_STAGING=y # CONFIG_RTLLIB is not set # CONFIG_RTL8723BS is not set CONFIG_R8712U=m +# CONFIG_RTS5208 is not set +# CONFIG_VT6655 is not set # CONFIG_VT6656 is not set # @@ -5477,7 +5856,9 @@ CONFIG_R8712U=m # end of Network Analyzer, Impedance Converters # end of IIO staging drivers +# CONFIG_FB_SM750 is not set CONFIG_STAGING_MEDIA=y +# CONFIG_DVB_AV7110 is not set # CONFIG_VIDEO_MAX96712 is not set # @@ -5493,6 +5874,7 @@ CONFIG_STAGING_MEDIA_DEPRECATED=y # CONFIG_KS7010 is not set # CONFIG_XIL_AXIS_FIFO is not set # CONFIG_FIELDBUS_DEV is not set +# CONFIG_VME_BUS is not set # CONFIG_GOLDFISH is not set CONFIG_CHROME_PLATFORMS=y CONFIG_CROS_EC=y @@ -5508,10 +5890,10 @@ CONFIG_CROS_EC_SENSORHUB=y CONFIG_CROS_EC_SYSFS=y # CONFIG_CROS_HPS_I2C is not set CONFIG_CROS_USBPD_NOTIFY=y +# CONFIG_CZNIC_PLATFORMS is not set # CONFIG_MELLANOX_PLATFORM is not set # CONFIG_SURFACE_PLATFORMS is not set CONFIG_ARM64_PLATFORM_DEVICES=y -# CONFIG_EC_ACER_ASPIRE1 is not set CONFIG_HAVE_CLK=y CONFIG_HAVE_CLK_PREPARE=y CONFIG_COMMON_CLK=y @@ -5808,6 +6190,7 @@ CONFIG_IIO=y # CONFIG_AD7291 is not set # CONFIG_AD7292 is not set # CONFIG_AD7298 is not set +# CONFIG_AD7380 is not set # CONFIG_AD7476 is not set # CONFIG_AD7606_IFACE_PARALLEL is not set # CONFIG_AD7606_IFACE_SPI is not set @@ -5822,7 +6205,6 @@ CONFIG_IIO=y # CONFIG_AD7949 is not set # CONFIG_AD799X is not set # CONFIG_AD9467 is not set -# CONFIG_ADI_AXI_ADC is not set # CONFIG_CC10001_ADC is not set # CONFIG_ENVELOPE_DETECTOR is not set # CONFIG_HI8435 is not set @@ -5861,6 +6243,7 @@ CONFIG_IIO=y # CONFIG_TI_ADC128S052 is not set # CONFIG_TI_ADC161S626 is not set # CONFIG_TI_ADS1015 is not set +# CONFIG_TI_ADS1119 is not set # CONFIG_TI_ADS7924 is not set # CONFIG_TI_ADS1100 is not set # CONFIG_TI_ADS1298 is not set @@ -5912,6 +6295,7 @@ CONFIG_IIO=y # CONFIG_ATLAS_EZO_SENSOR is not set # CONFIG_BME680 is not set # CONFIG_CCS811 is not set +# CONFIG_ENS160 is not set # CONFIG_IAQCORE is not set # CONFIG_PMS7003 is not set # CONFIG_SCD30_CORE is not set @@ -5957,7 +6341,6 @@ CONFIG_IIO=y # CONFIG_AD5504 is not set # CONFIG_AD5624R_SPI is not set # CONFIG_AD9739A is not set -# CONFIG_ADI_AXI_DAC is not set # CONFIG_LTC2688 is not set # CONFIG_AD5686_SPI is not set # CONFIG_AD5696_I2C is not set @@ -6146,6 +6529,7 @@ CONFIG_IIO=y # CONFIG_VCNL4000 is not set # CONFIG_VCNL4035 is not set # CONFIG_VEML6030 is not set +# CONFIG_VEML6040 is not set # CONFIG_VEML6070 is not set # CONFIG_VEML6075 is not set # CONFIG_VL6180 is not set @@ -6287,12 +6671,15 @@ CONFIG_IIO=y # CONFIG_MCP9600 is not set # end of Temperature sensors +# CONFIG_NTB is not set CONFIG_PWM=y # CONFIG_PWM_DEBUG is not set # CONFIG_PWM_ATMEL_TCB is not set # CONFIG_PWM_CLK is not set # CONFIG_PWM_CROS_EC is not set +# CONFIG_PWM_DWC is not set # CONFIG_PWM_FSL_FTM is not set +# CONFIG_PWM_GPIO is not set # CONFIG_PWM_IMX1 is not set # CONFIG_PWM_IMX27 is not set # CONFIG_PWM_IMX_TPM is not set @@ -6307,7 +6694,9 @@ CONFIG_ARM_GIC=y CONFIG_ARM_GIC_MAX_NR=1 CONFIG_ARM_GIC_V3=y CONFIG_ARM_GIC_V3_ITS=y +CONFIG_IRQ_MSI_LIB=y # CONFIG_AL_FIC is not set +# CONFIG_LAN966X_OIC is not set # CONFIG_XILINX_INTC is not set CONFIG_IMX_GPCV2=y CONFIG_PARTITION_PERCPU=y @@ -6320,6 +6709,7 @@ CONFIG_IMX_INTMUX=y CONFIG_RESET_CONTROLLER=y # CONFIG_RESET_GPIO is not set CONFIG_RESET_IMX7=y +# CONFIG_RESET_IMX8MP_AUDIOMIX is not set # CONFIG_RESET_SIMPLE is not set # CONFIG_RESET_TI_SYSCON is not set # CONFIG_RESET_TI_TPS380X is not set @@ -6345,6 +6735,8 @@ CONFIG_PHY_FSL_IMX8MQ_USB=y # CONFIG_PHY_MIXEL_LVDS_PHY is not set # CONFIG_PHY_MIXEL_MIPI_DPHY is not set CONFIG_PHY_FSL_IMX8M_PCIE=y +# CONFIG_PHY_FSL_IMX8QM_HSIO is not set +CONFIG_PHY_FSL_IMX8MQ_HDPTX=y # CONFIG_PHY_FSL_SAMSUNG_HDMI_PHY is not set # CONFIG_PHY_PXA_28NM_HSIC is not set # CONFIG_PHY_PXA_28NM_USB2 is not set @@ -6371,10 +6763,14 @@ CONFIG_ARM_PMUV3=y CONFIG_FSL_IMX8_DDR_PMU=y # CONFIG_FSL_IMX9_DDR_PMU is not set # CONFIG_ARM_SPE_PMU is not set +# CONFIG_HISI_PCIE_PMU is not set +# CONFIG_HNS3_PMU is not set +# CONFIG_DWC_PCIE_PMU is not set # CONFIG_ARM_CORESIGHT_PMU_ARCH_SYSTEM_PMU is not set # end of Performance monitor support # CONFIG_RAS is not set +# CONFIG_USB4 is not set # # Android @@ -6408,6 +6804,7 @@ CONFIG_NVMEM_U_BOOT_ENV=m # # CONFIG_STM is not set # CONFIG_INTEL_TH is not set +# CONFIG_HISI_PTT is not set # end of HW tracing support # CONFIG_FPGA is not set @@ -6786,7 +7183,6 @@ CONFIG_CRYPTO_ECC=y CONFIG_CRYPTO_ECDH=y # CONFIG_CRYPTO_ECDSA is not set # CONFIG_CRYPTO_ECRDSA is not set -# CONFIG_CRYPTO_SM2 is not set # CONFIG_CRYPTO_CURVE25519 is not set # end of Public-key cryptography @@ -6951,6 +7347,16 @@ CONFIG_CRYPTO_HW=y # CONFIG_CRYPTO_DEV_ATMEL_SHA204A is not set # CONFIG_CRYPTO_DEV_CCP is not set # CONFIG_CRYPTO_DEV_MXS_DCP is not set +# CONFIG_CRYPTO_DEV_NITROX_CNN55XX is not set +# CONFIG_CRYPTO_DEV_QAT_DH895xCC is not set +# CONFIG_CRYPTO_DEV_QAT_C3XXX is not set +# CONFIG_CRYPTO_DEV_QAT_C62X is not set +# CONFIG_CRYPTO_DEV_QAT_4XXX is not set +# CONFIG_CRYPTO_DEV_QAT_420XX is not set +# CONFIG_CRYPTO_DEV_QAT_DH895xCCVF is not set +# CONFIG_CRYPTO_DEV_QAT_C3XXXVF is not set +# CONFIG_CRYPTO_DEV_QAT_C62XVF is not set +# CONFIG_CRYPTO_DEV_CAVIUM_ZIP is not set # CONFIG_CRYPTO_DEV_SAFEXCEL is not set # CONFIG_CRYPTO_DEV_CCREE is not set # CONFIG_CRYPTO_DEV_HISI_SEC is not set @@ -7058,6 +7464,7 @@ CONFIG_XARRAY_MULTI=y CONFIG_ASSOCIATIVE_ARRAY=y CONFIG_HAS_IOMEM=y CONFIG_HAS_IOPORT=y +CONFIG_HAS_IOPORT_MAP=y CONFIG_HAS_DMA=y CONFIG_DMA_OPS=y CONFIG_NEED_SG_DMA_FLAGS=y @@ -7082,7 +7489,7 @@ CONFIG_DMA_CMA=y # # Default contiguous memory area size: # -CONFIG_CMA_SIZE_MBYTES=256 +CONFIG_CMA_SIZE_MBYTES=384 CONFIG_CMA_SIZE_SEL_MBYTES=y # CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set # CONFIG_CMA_SIZE_SEL_MIN is not set @@ -7099,6 +7506,7 @@ CONFIG_NLATTR=y CONFIG_CLZ_TAB=y # CONFIG_IRQ_POLL is not set CONFIG_MPILIB=y +CONFIG_DIMLIB=y CONFIG_LIBFDT=y CONFIG_OID_REGISTRY=y CONFIG_HAVE_GENERIC_VDSO=y diff --git a/projects/NXP/devices/iMX8/patches/linux/0001-Initial-support-Cadence-MHDP8501-HDMI-DP-for-i-MX8MQ.patch b/projects/NXP/devices/iMX8/patches/linux/0001-Initial-support-Cadence-MHDP8501-HDMI-DP-for-i-MX8MQ.patch new file mode 100644 index 0000000000..ea96d66bfc --- /dev/null +++ b/projects/NXP/devices/iMX8/patches/linux/0001-Initial-support-Cadence-MHDP8501-HDMI-DP-for-i-MX8MQ.patch @@ -0,0 +1,5662 @@ +From patchwork Tue Jul 2 12:22:33 2024 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [PATCH v16 0/8] Initial support Cadence MHDP8501(HDMI/DP) for i.MX8MQ +From: Sandor Yu +Message-Id: +To: dmitry.baryshkov@linaro.org, andrzej.hajda@intel.com, + neil.armstrong@linaro.org, Laurent.pinchart@ideasonboard.com, + jonas@kwiboo.se, jernej.skrabec@gmail.com, airlied@gmail.com, + daniel@ffwll.ch, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, + shawnguo@kernel.org, s.hauer@pengutronix.de, festevam@gmail.com, + vkoul@kernel.org, dri-devel@lists.freedesktop.org, + devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, + linux-kernel@vger.kernel.org, linux-phy@lists.infradead.org, + mripard@kernel.org +Cc: kernel@pengutronix.de, linux-imx@nxp.com, Sandor.yu@nxp.com, + oliver.brown@nxp.com, alexander.stein@ew.tq-group.com, sam@ravnborg.org +Date: Tue, 2 Jul 2024 20:22:32 +0800 + +This patchset sits on top +Dmitry's 'make use of the HDMI connector infrastructure' patchset ([2]). + +The patch set initial support Cadence MHDP8501(HDMI/DP) DRM bridge +driver and Cadence HDP-TX PHY(HDMI/DP) driver for Freescale i.MX8MQ. + +The patch set compose of DRM bridge drivers and PHY driver. + +Both of them need by patch #1 and #2 to pass build. + +DRM bridges driver patches: + #1: drm: bridge: Cadence: Creat mhdp helper driver + #2: phy: Add HDMI configuration options + #3: dt-bindings: display: bridge: Add Cadence MHDP8501 + #4: drm: bridge: Cadence: Add MHDP8501 DP/HDMI driver + +PHY driver patches: + #1: drm: bridge: Cadence: Creat mhdp helper driver + #2: phy: Add HDMI configuration options + #5: dt-bindings: phy: Add Freescale iMX8MQ DP and HDMI PHY + #6: phy: freescale: Add DisplayPort/HDMI Combo-PHY driver for i.MX8MQ + +i.MX8M/TQMa8Mx DT patches: + #7: Add DT nodes for DCSS/HDMI pipeline + #8: Enable HDMI for TQMa8Mx/MBa8Mx + +[2] https://patchwork.freedesktop.org/series/130888/ + +v15->v16: +Patch #2: +- Remove pixel_clk_rate, bpc and color_space fields from struct + phy_configure_opts_hdmi, they were replaced by + unsigned long long tmds_char_rate. +- Remove r-b and a-c tags because this patch have important change. +Patch #4: +- Add DRM_BRIDGE_OP_HDMI flags for HDMI driver, +- Introduce the hdmi info frame helper functions, + added hdmi_clear_infoframe(), hdmi_write_infoframe() and + hdmi_tmds_char_rate_valid() according Dmitry's patch + 'make use of the HDMI connector infrastructure' patchset ([2]). +- mode_fixup() is replaced by atomic_check(). +- Fix video mode 4Kp30 did not work on some displays that support + LTE_340Mcsc_scramble. +- updated for tmds_char_rate added in patch #2. +Patch #6: +- updated for tmds_char_rate added in patch #2. + +v14->v15: +Patch #6 + #7: +- Merged PHY driver into a single combo PHY driver +Patch #7 + #8: +- Add DT patches for a running HDMI setup + +v13->v14: +Patch #4: +- Rebase to next-20240219, replace get_edid function by edid_read + function as commits d807ad80d811b ("drm/bridge: add ->edid_read + hook and drm_bridge_edid_read()") and 27b8f91c08d99 ("drm/bridge: + remove ->get_edid callback") had change the API. + +v12->v13: +Patch #4: +- Explicitly include linux/platform_device.h for cdns-mhdp8501-core.c +- Fix build warning +- Order bit bpc and color_space in descending shit. +Patch #7: +- Fix build warning + +v11->v12: +Patch #1: +- Move status initialize out of mbox_mutex. +- Reorder API functions in alphabetical. +- Add notes for malibox access functions. +- Add year 2024 to copyright. +Patch #4: +- Replace DRM_INFO with dev_info or dev_warn. +- Replace DRM_ERROR with dev_err. +- Return ret when cdns_mhdp_dpcd_read failed in function cdns_dp_aux_transferi(). +- Remove unused parmeter in function cdns_dp_get_msa_misc + and use two separate variables for color space and bpc. +- Add year 2024 to copyright. +Patch #6: +- Return error code to replace -1 for function wait_for_ack(). +- Set cdns_phy->power_up = false in phy_power_down function. +- Remove "RATE_8_1 = 810000", it is not used in driver. +- Add year 2024 to copyright. +Patch #7: +- Adjust clk disable order. +- Return error code to replace -1 for function wait_for_ack(). +- Use bool for variable pclk_in. +- Add year 2024 to copyright. + +v10->v11: +- rewrite cdns_mhdp_set_firmware_active() in mhdp8546 core driver, +use cdns_mhdp_mailbox_send() to replace cdns_mhdp_mailbox_write() +same as the other mailbox access functions. +- use static for cdns_mhdp_mailbox_write() and cdns_mhdp_mailbox_read() +and remove them from EXPORT_SYMBOL_GPL(). +- remove MODULE_ALIAS() from mhdp8501 driver. + +v9->v10: +- Create mhdp helper driver to replace macro functions, +move all mhdp mailbox access functions and common functions +into the helper driver. +Patch #1:drm: bridge: Cadence: Creat mhdp helper driver +it is totaly different with v9. + +v8->v9: +- Remove compatible string "cdns,mhdp8501" that had removed + from dt-bindings file in v8. +- Add Dmitry's R-b tag to patch #2 +- Add Krzysztof's R-b tag to patch #3 + +v7->v8: +MHDP8501 HDMI/DP: +- Correct DT node name to "display-bridge". +- Remove "cdns,mhdp8501" from mhdp8501 dt-binding doc. + +HDMI/DP PHY: +- Introduced functions `wait_for_ack` and `wait_for_ack_clear` to handle + waiting with acknowledgment bits set and cleared respectively. +- Use FIELD_PRE() to set bitfields for both HDMI and DP PHY. + +v6->v7: +MHDP8501 HDMI/DP: +- Combine HDMI and DP driver into one mhdp8501 driver. + Use the connector type to load the corresponding functions. +- Remove connector init functions. +- Add in phy_hdmi.h to reuse 'enum hdmi_colorspace'. + +HDMI/DP PHY: +- Lowercase hex values +- Fix parameters indent issue on some functions +- Replace 'udelay' with 'usleep_range' + +v5->v6: +HDMI/DP bridge driver +- 8501 is the part number of Cadence MHDP on i.MX8MQ. + Use MHDP8501 to name hdmi/dp drivers and files. +- Add compatible "fsl,imx8mq-mhdp8501-dp" for i.MX8MQ DP driver +- Add compatible "fsl,imx8mq-mhdp8501-hdmi" for i.MX8MQ HDMI driver +- Combine HDMI and DP dt-bindings into one file cdns,mhdp8501.yaml +- Fix HDMI scrambling is not enable issue when driver working in 4Kp60 + mode. +- Add HDMI/DP PHY API mailbox protect. + +HDMI/DP PHY driver: +- Rename DP and HDMI PHY files and move to folder phy/freescale/ +- Remove properties num_lanes and link_rate from DP PHY driver. +- Combine HDMI and DP dt-bindings into one file fsl,imx8mq-dp-hdmi-phy.yaml +- Update compatible string to "fsl,imx8mq-dp-phy". +- Update compatible string to "fsl,imx8mq-hdmi-phy". + +v4->v5: +- Drop "clk" suffix in clock name. +- Add output port property in the example of hdmi/dp. + +v3->v4: +dt-bindings: +- Correct dt-bindings coding style and address review comments. +- Add apb_clk description. +- Add output port for HDMI/DP connector +PHY: +- Alphabetically sorted in Kconfig and Makefile for DP and HDMI PHY +- Remove unused registers define from HDMI and DP PHY drivers. +- More description in phy_hdmi.h. +- Add apb_clk to HDMI and DP phy driver. +HDMI/DP: +- Use get_unaligned_le32() to replace hardcode type conversion + in HDMI AVI infoframe data fill function. +- Add mailbox mutex lock in HDMI/DP driver for phy functions + to reslove race conditions between HDMI/DP and PHY drivers. +- Add apb_clk to both HDMI and DP driver. +- Rename some function names and add prefix with "cdns_hdmi/cdns_dp". +- Remove bpc 12 and 16 optional that not supported. + +v2->v3: +Address comments for dt-bindings files. +- Correct dts-bindings file names + Rename phy-cadence-hdptx-dp.yaml to cdns,mhdp-imx8mq-dp.yaml + Rename phy-cadence-hdptx-hdmi.yaml to cdns,mhdp-imx8mq-hdmi.yaml +- Drop redundant words and descriptions. +- Correct hdmi/dp node name. + +v2 is a completely different version compared to v1. +Previous v1 can be available here [1]. + +v1->v2: +- Reuse Cadence mailbox access functions from mhdp8546 instead of + rockchip DP. +- Mailbox access functions be convert to marco functions + that will be referenced by HDP-TX PHY(HDMI/DP) driver too. +- Plain bridge instead of component driver. +- Standalone Cadence HDP-TX PHY(HDMI/DP) driver. +- Audio driver are removed from the patch set, it will be add in another + patch set later. + +[1] https://patchwork.kernel.org/project/linux-rockchip/cover/cover.1590982881.git.Sandor.yu@nxp.com/ + +Alexander Stein (2): + arm64: dts: imx8mq: Add DCSS + HDMI/DP display pipeline + arm64: dts: imx8mq: tqma8mq-mba8mx: Enable HDMI support + +Sandor Yu (6): + drm: bridge: Cadence: Create mhdp helper driver + phy: Add HDMI configuration options + dt-bindings: display: bridge: Add Cadence MHDP8501 + drm: bridge: Cadence: Add MHDP8501 DP/HDMI driver + dt-bindings: phy: Add Freescale iMX8MQ DP and HDMI PHY + phy: freescale: Add DisplayPort/HDMI Combo-PHY driver for i.MX8MQ + + .../display/bridge/cdns,mhdp8501.yaml | 104 ++ + .../bindings/phy/fsl,imx8mq-dp-hdmi-phy.yaml | 51 + + .../dts/freescale/imx8mq-tqma8mq-mba8mx.dts | 20 + + arch/arm64/boot/dts/freescale/imx8mq.dtsi | 68 + + arch/arm64/boot/dts/freescale/mba8mx.dtsi | 11 + + drivers/gpu/drm/bridge/cadence/Kconfig | 20 + + drivers/gpu/drm/bridge/cadence/Makefile | 3 + + .../gpu/drm/bridge/cadence/cdns-mhdp-helper.c | 304 ++++ + .../drm/bridge/cadence/cdns-mhdp8501-core.c | 330 ++++ + .../drm/bridge/cadence/cdns-mhdp8501-core.h | 367 +++++ + .../gpu/drm/bridge/cadence/cdns-mhdp8501-dp.c | 700 +++++++++ + .../drm/bridge/cadence/cdns-mhdp8501-hdmi.c | 595 ++++++++ + .../drm/bridge/cadence/cdns-mhdp8546-core.c | 403 +---- + .../drm/bridge/cadence/cdns-mhdp8546-core.h | 44 +- + drivers/phy/freescale/Kconfig | 10 + + drivers/phy/freescale/Makefile | 1 + + drivers/phy/freescale/phy-fsl-imx8mq-hdptx.c | 1340 +++++++++++++++++ + include/drm/bridge/cdns-mhdp-helper.h | 97 ++ + include/linux/phy/phy-hdmi.h | 20 + + include/linux/phy/phy.h | 7 +- + 20 files changed, 4120 insertions(+), 375 deletions(-) + create mode 100644 Documentation/devicetree/bindings/display/bridge/cdns,mhdp8501.yaml + create mode 100644 Documentation/devicetree/bindings/phy/fsl,imx8mq-dp-hdmi-phy.yaml + create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp-helper.c + create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp8501-core.c + create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp8501-core.h + create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp8501-dp.c + create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp8501-hdmi.c + create mode 100644 drivers/phy/freescale/phy-fsl-imx8mq-hdptx.c + create mode 100644 include/drm/bridge/cdns-mhdp-helper.h + create mode 100644 include/linux/phy/phy-hdmi.h + +-- +2.34.1 + + + +From patchwork Tue Jul 2 12:22:33 2024 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [v16,1/8] drm: bridge: Cadence: Create mhdp helper driver +From: Sandor Yu +X-Patchwork-Id: 601663 +Message-Id: + <4e3a5991fc2af2a69dcfd57f32f2406f6849704d.1719903904.git.Sandor.yu@nxp.com> +To: dmitry.baryshkov@linaro.org, andrzej.hajda@intel.com, + neil.armstrong@linaro.org, Laurent.pinchart@ideasonboard.com, + jonas@kwiboo.se, jernej.skrabec@gmail.com, airlied@gmail.com, + daniel@ffwll.ch, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, + shawnguo@kernel.org, s.hauer@pengutronix.de, festevam@gmail.com, + vkoul@kernel.org, dri-devel@lists.freedesktop.org, + devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, + linux-kernel@vger.kernel.org, linux-phy@lists.infradead.org, + mripard@kernel.org +Cc: kernel@pengutronix.de, linux-imx@nxp.com, Sandor.yu@nxp.com, + oliver.brown@nxp.com, alexander.stein@ew.tq-group.com, sam@ravnborg.org +Date: Tue, 2 Jul 2024 20:22:33 +0800 + +MHDP8546 mailbox access functions will be share to other mhdp driver +and Cadence HDP-TX HDMI/DP PHY drivers. +Create a new mhdp helper driver and move all those functions into. + +cdns_mhdp_reg_write() is renamed to cdns_mhdp_dp_reg_write(), +because it use the DPTX command ID DPTX_WRITE_REGISTER. + +New cdns_mhdp_reg_write() is created with the general command ID +GENERAL_REGISTER_WRITE. + +rewrite cdns_mhdp_set_firmware_active() in mhdp8546 core driver, +use cdns_mhdp_mailbox_send() to replace cdns_mhdp_mailbox_write() +same as the other mailbox access functions. + +Signed-off-by: Sandor Yu +--- +v12->v16: + *No change. + +V11->v12: +- Move status initialize out of mbox_mutex. +- Reorder API functions in alphabetical. +- Add notes for malibox access functions. +- Add year 2024 to copyright. + + drivers/gpu/drm/bridge/cadence/Kconfig | 4 + + drivers/gpu/drm/bridge/cadence/Makefile | 1 + + .../gpu/drm/bridge/cadence/cdns-mhdp-helper.c | 304 +++++++++++++ + .../drm/bridge/cadence/cdns-mhdp8546-core.c | 403 +++--------------- + .../drm/bridge/cadence/cdns-mhdp8546-core.h | 44 +- + include/drm/bridge/cdns-mhdp-helper.h | 97 +++++ + 6 files changed, 479 insertions(+), 374 deletions(-) + create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp-helper.c + create mode 100644 include/drm/bridge/cdns-mhdp-helper.h + +diff --git a/drivers/gpu/drm/bridge/cadence/Kconfig b/drivers/gpu/drm/bridge/cadence/Kconfig +index cced81633ddc..e0973339e9e3 100644 +--- a/drivers/gpu/drm/bridge/cadence/Kconfig ++++ b/drivers/gpu/drm/bridge/cadence/Kconfig +@@ -21,6 +21,9 @@ config DRM_CDNS_DSI_J721E + the routing of the DSS DPI signal to the Cadence DSI. + endif + ++config CDNS_MHDP_HELPER ++ tristate ++ + config DRM_CDNS_MHDP8546 + tristate "Cadence DPI/DP bridge" + select DRM_DISPLAY_DP_HELPER +@@ -28,6 +31,7 @@ config DRM_CDNS_MHDP8546 + select DRM_DISPLAY_HELPER + select DRM_KMS_HELPER + select DRM_PANEL_BRIDGE ++ select CDNS_MHDP_HELPER + depends on OF + help + Support Cadence DPI to DP bridge. This is an internal +diff --git a/drivers/gpu/drm/bridge/cadence/Makefile b/drivers/gpu/drm/bridge/cadence/Makefile +index c95fd5b81d13..087dc074820d 100644 +--- a/drivers/gpu/drm/bridge/cadence/Makefile ++++ b/drivers/gpu/drm/bridge/cadence/Makefile +@@ -2,6 +2,7 @@ + obj-$(CONFIG_DRM_CDNS_DSI) += cdns-dsi.o + cdns-dsi-y := cdns-dsi-core.o + cdns-dsi-$(CONFIG_DRM_CDNS_DSI_J721E) += cdns-dsi-j721e.o ++obj-$(CONFIG_CDNS_MHDP_HELPER) += cdns-mhdp-helper.o + obj-$(CONFIG_DRM_CDNS_MHDP8546) += cdns-mhdp8546.o + cdns-mhdp8546-y := cdns-mhdp8546-core.o cdns-mhdp8546-hdcp.o + cdns-mhdp8546-$(CONFIG_DRM_CDNS_MHDP8546_J721E) += cdns-mhdp8546-j721e.o +diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-helper.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-helper.c +new file mode 100644 +index 000000000000..ba31695b483a +--- /dev/null ++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-helper.c +@@ -0,0 +1,304 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Copyright (C) 2023, 2024 NXP Semiconductor, Inc. ++ * ++ */ ++#include ++#include ++#include ++ ++/* Mailbox helper functions */ ++static int cdns_mhdp_mailbox_read(struct cdns_mhdp_base *base) ++{ ++ int ret, empty; ++ ++ WARN_ON(!mutex_is_locked(base->mbox_mutex)); ++ ++ ret = readx_poll_timeout(readl, base->regs + CDNS_MAILBOX_EMPTY, ++ empty, !empty, MAILBOX_RETRY_US, ++ MAILBOX_TIMEOUT_US); ++ if (ret < 0) ++ return ret; ++ ++ return readl(base->regs + CDNS_MAILBOX_RX_DATA) & 0xff; ++} ++ ++static int cdns_mhdp_mailbox_write(struct cdns_mhdp_base *base, u8 val) ++{ ++ int ret, full; ++ ++ WARN_ON(!mutex_is_locked(base->mbox_mutex)); ++ ++ ret = readx_poll_timeout(readl, base->regs + CDNS_MAILBOX_FULL, ++ full, !full, MAILBOX_RETRY_US, ++ MAILBOX_TIMEOUT_US); ++ if (ret < 0) ++ return ret; ++ ++ writel(val, base->regs + CDNS_MAILBOX_TX_DATA); ++ ++ return 0; ++} ++ ++int cdns_mhdp_mailbox_recv_header(struct cdns_mhdp_base *base, ++ u8 module_id, u8 opcode, ++ u16 req_size) ++{ ++ u32 mbox_size, i; ++ u8 header[4]; ++ int ret; ++ ++ /* read the header of the message */ ++ for (i = 0; i < sizeof(header); i++) { ++ ret = cdns_mhdp_mailbox_read(base); ++ if (ret < 0) ++ return ret; ++ ++ header[i] = ret; ++ } ++ ++ mbox_size = get_unaligned_be16(header + 2); ++ ++ if (opcode != header[0] || module_id != header[1] || ++ req_size != mbox_size) { ++ /* ++ * If the message in mailbox is not what we want, we need to ++ * clear the mailbox by reading its contents. ++ */ ++ for (i = 0; i < mbox_size; i++) ++ if (cdns_mhdp_mailbox_read(base) < 0) ++ break; ++ ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(cdns_mhdp_mailbox_recv_header); ++ ++int cdns_mhdp_mailbox_recv_data(struct cdns_mhdp_base *base, ++ u8 *buff, u16 buff_size) ++{ ++ u32 i; ++ int ret; ++ ++ for (i = 0; i < buff_size; i++) { ++ ret = cdns_mhdp_mailbox_read(base); ++ if (ret < 0) ++ return ret; ++ ++ buff[i] = ret; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(cdns_mhdp_mailbox_recv_data); ++ ++int cdns_mhdp_mailbox_send(struct cdns_mhdp_base *base, u8 module_id, ++ u8 opcode, u16 size, u8 *message) ++{ ++ u8 header[4]; ++ int ret, i; ++ ++ header[0] = opcode; ++ header[1] = module_id; ++ put_unaligned_be16(size, header + 2); ++ ++ for (i = 0; i < sizeof(header); i++) { ++ ret = cdns_mhdp_mailbox_write(base, header[i]); ++ if (ret) ++ return ret; ++ } ++ ++ for (i = 0; i < size; i++) { ++ ret = cdns_mhdp_mailbox_write(base, message[i]); ++ if (ret) ++ return ret; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(cdns_mhdp_mailbox_send); ++ ++/* General helper functions */ ++int cdns_mhdp_reg_read(struct cdns_mhdp_base *base, u32 addr, u32 *value) ++{ ++ u8 msg[4], resp[8]; ++ int ret; ++ ++ put_unaligned_be32(addr, msg); ++ ++ mutex_lock(base->mbox_mutex); ++ ++ ret = cdns_mhdp_mailbox_send(base, MB_MODULE_ID_GENERAL, ++ GENERAL_REGISTER_READ, ++ sizeof(msg), msg); ++ if (ret) ++ goto out; ++ ++ ret = cdns_mhdp_mailbox_recv_header(base, MB_MODULE_ID_GENERAL, ++ GENERAL_REGISTER_READ, ++ sizeof(resp)); ++ if (ret) ++ goto out; ++ ++ ret = cdns_mhdp_mailbox_recv_data(base, resp, sizeof(resp)); ++ if (ret) ++ goto out; ++ ++ /* Returned address value should be the same as requested */ ++ if (memcmp(msg, resp, sizeof(msg))) { ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ *value = get_unaligned_be32(resp + 4); ++ ++out: ++ mutex_unlock(base->mbox_mutex); ++ if (ret) { ++ dev_err(base->dev, "Failed to read register\n"); ++ *value = 0; ++ } ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(cdns_mhdp_reg_read); ++ ++int cdns_mhdp_reg_write(struct cdns_mhdp_base *base, u32 addr, u32 val) ++{ ++ u8 msg[8]; ++ int ret; ++ ++ put_unaligned_be32(addr, msg); ++ put_unaligned_be32(val, msg + 4); ++ ++ mutex_lock(base->mbox_mutex); ++ ++ ret = cdns_mhdp_mailbox_send(base, MB_MODULE_ID_GENERAL, ++ GENERAL_REGISTER_WRITE, ++ sizeof(msg), msg); ++ ++ mutex_unlock(base->mbox_mutex); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(cdns_mhdp_reg_write); ++ ++/* DPTX helper functions */ ++int cdns_mhdp_dp_reg_write(struct cdns_mhdp_base *base, u16 addr, u32 val) ++{ ++ u8 msg[6]; ++ int ret; ++ ++ put_unaligned_be16(addr, msg); ++ put_unaligned_be32(val, msg + 2); ++ ++ mutex_lock(base->mbox_mutex); ++ ++ ret = cdns_mhdp_mailbox_send(base, MB_MODULE_ID_DP_TX, ++ DPTX_WRITE_REGISTER, sizeof(msg), msg); ++ ++ mutex_unlock(base->mbox_mutex); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(cdns_mhdp_dp_reg_write); ++ ++int cdns_mhdp_dp_reg_write_bit(struct cdns_mhdp_base *base, u16 addr, ++ u8 start_bit, u8 bits_no, u32 val) ++{ ++ u8 field[8]; ++ int ret; ++ ++ put_unaligned_be16(addr, field); ++ field[2] = start_bit; ++ field[3] = bits_no; ++ put_unaligned_be32(val, field + 4); ++ ++ mutex_lock(base->mbox_mutex); ++ ++ ret = cdns_mhdp_mailbox_send(base, MB_MODULE_ID_DP_TX, ++ DPTX_WRITE_FIELD, sizeof(field), field); ++ ++ mutex_unlock(base->mbox_mutex); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(cdns_mhdp_dp_reg_write_bit); ++ ++int cdns_mhdp_dpcd_read(struct cdns_mhdp_base *base, ++ u32 addr, u8 *data, u16 len) ++{ ++ u8 msg[5], reg[5]; ++ int ret; ++ ++ put_unaligned_be16(len, msg); ++ put_unaligned_be24(addr, msg + 2); ++ ++ mutex_lock(base->mbox_mutex); ++ ++ ret = cdns_mhdp_mailbox_send(base, MB_MODULE_ID_DP_TX, ++ DPTX_READ_DPCD, sizeof(msg), msg); ++ if (ret) ++ goto out; ++ ++ ret = cdns_mhdp_mailbox_recv_header(base, MB_MODULE_ID_DP_TX, ++ DPTX_READ_DPCD, ++ sizeof(reg) + len); ++ if (ret) ++ goto out; ++ ++ ret = cdns_mhdp_mailbox_recv_data(base, reg, sizeof(reg)); ++ if (ret) ++ goto out; ++ ++ ret = cdns_mhdp_mailbox_recv_data(base, data, len); ++ ++out: ++ mutex_unlock(base->mbox_mutex); ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(cdns_mhdp_dpcd_read); ++ ++int cdns_mhdp_dpcd_write(struct cdns_mhdp_base *base, u32 addr, u8 value) ++{ ++ u8 msg[6], reg[5]; ++ int ret; ++ ++ put_unaligned_be16(1, msg); ++ put_unaligned_be24(addr, msg + 2); ++ msg[5] = value; ++ ++ mutex_lock(base->mbox_mutex); ++ ++ ret = cdns_mhdp_mailbox_send(base, MB_MODULE_ID_DP_TX, ++ DPTX_WRITE_DPCD, sizeof(msg), msg); ++ if (ret) ++ goto out; ++ ++ ret = cdns_mhdp_mailbox_recv_header(base, MB_MODULE_ID_DP_TX, ++ DPTX_WRITE_DPCD, sizeof(reg)); ++ if (ret) ++ goto out; ++ ++ ret = cdns_mhdp_mailbox_recv_data(base, reg, sizeof(reg)); ++ if (ret) ++ goto out; ++ ++ if (addr != get_unaligned_be24(reg + 2)) ++ ret = -EINVAL; ++ ++out: ++ mutex_unlock(base->mbox_mutex); ++ ++ if (ret) ++ dev_err(base->dev, "dpcd write failed: %d\n", ret); ++ return ret; ++} ++EXPORT_SYMBOL_GPL(cdns_mhdp_dpcd_write); ++ ++MODULE_DESCRIPTION("Cadence MHDP Helper driver"); ++MODULE_AUTHOR("Sandor Yu "); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +index 8a91ef0ae065..1d627d8f274b 100644 +--- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c ++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +@@ -73,298 +73,28 @@ static void cdns_mhdp_bridge_hpd_disable(struct drm_bridge *bridge) + mhdp->regs + CDNS_APB_INT_MASK); + } + +-static int cdns_mhdp_mailbox_read(struct cdns_mhdp_device *mhdp) +-{ +- int ret, empty; +- +- WARN_ON(!mutex_is_locked(&mhdp->mbox_mutex)); +- +- ret = readx_poll_timeout(readl, mhdp->regs + CDNS_MAILBOX_EMPTY, +- empty, !empty, MAILBOX_RETRY_US, +- MAILBOX_TIMEOUT_US); +- if (ret < 0) +- return ret; +- +- return readl(mhdp->regs + CDNS_MAILBOX_RX_DATA) & 0xff; +-} +- +-static int cdns_mhdp_mailbox_write(struct cdns_mhdp_device *mhdp, u8 val) +-{ +- int ret, full; +- +- WARN_ON(!mutex_is_locked(&mhdp->mbox_mutex)); +- +- ret = readx_poll_timeout(readl, mhdp->regs + CDNS_MAILBOX_FULL, +- full, !full, MAILBOX_RETRY_US, +- MAILBOX_TIMEOUT_US); +- if (ret < 0) +- return ret; +- +- writel(val, mhdp->regs + CDNS_MAILBOX_TX_DATA); +- +- return 0; +-} +- +-static int cdns_mhdp_mailbox_recv_header(struct cdns_mhdp_device *mhdp, +- u8 module_id, u8 opcode, +- u16 req_size) +-{ +- u32 mbox_size, i; +- u8 header[4]; +- int ret; +- +- /* read the header of the message */ +- for (i = 0; i < sizeof(header); i++) { +- ret = cdns_mhdp_mailbox_read(mhdp); +- if (ret < 0) +- return ret; +- +- header[i] = ret; +- } +- +- mbox_size = get_unaligned_be16(header + 2); +- +- if (opcode != header[0] || module_id != header[1] || +- req_size != mbox_size) { +- /* +- * If the message in mailbox is not what we want, we need to +- * clear the mailbox by reading its contents. +- */ +- for (i = 0; i < mbox_size; i++) +- if (cdns_mhdp_mailbox_read(mhdp) < 0) +- break; +- +- return -EINVAL; +- } +- +- return 0; +-} +- +-static int cdns_mhdp_mailbox_recv_data(struct cdns_mhdp_device *mhdp, +- u8 *buff, u16 buff_size) +-{ +- u32 i; +- int ret; +- +- for (i = 0; i < buff_size; i++) { +- ret = cdns_mhdp_mailbox_read(mhdp); +- if (ret < 0) +- return ret; +- +- buff[i] = ret; +- } +- +- return 0; +-} +- +-static int cdns_mhdp_mailbox_send(struct cdns_mhdp_device *mhdp, u8 module_id, +- u8 opcode, u16 size, u8 *message) +-{ +- u8 header[4]; +- int ret, i; +- +- header[0] = opcode; +- header[1] = module_id; +- put_unaligned_be16(size, header + 2); +- +- for (i = 0; i < sizeof(header); i++) { +- ret = cdns_mhdp_mailbox_write(mhdp, header[i]); +- if (ret) +- return ret; +- } +- +- for (i = 0; i < size; i++) { +- ret = cdns_mhdp_mailbox_write(mhdp, message[i]); +- if (ret) +- return ret; +- } +- +- return 0; +-} +- +-static +-int cdns_mhdp_reg_read(struct cdns_mhdp_device *mhdp, u32 addr, u32 *value) +-{ +- u8 msg[4], resp[8]; +- int ret; +- +- put_unaligned_be32(addr, msg); +- +- mutex_lock(&mhdp->mbox_mutex); +- +- ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_GENERAL, +- GENERAL_REGISTER_READ, +- sizeof(msg), msg); +- if (ret) +- goto out; +- +- ret = cdns_mhdp_mailbox_recv_header(mhdp, MB_MODULE_ID_GENERAL, +- GENERAL_REGISTER_READ, +- sizeof(resp)); +- if (ret) +- goto out; +- +- ret = cdns_mhdp_mailbox_recv_data(mhdp, resp, sizeof(resp)); +- if (ret) +- goto out; +- +- /* Returned address value should be the same as requested */ +- if (memcmp(msg, resp, sizeof(msg))) { +- ret = -EINVAL; +- goto out; +- } +- +- *value = get_unaligned_be32(resp + 4); +- +-out: +- mutex_unlock(&mhdp->mbox_mutex); +- if (ret) { +- dev_err(mhdp->dev, "Failed to read register\n"); +- *value = 0; +- } +- +- return ret; +-} +- +-static +-int cdns_mhdp_reg_write(struct cdns_mhdp_device *mhdp, u16 addr, u32 val) +-{ +- u8 msg[6]; +- int ret; +- +- put_unaligned_be16(addr, msg); +- put_unaligned_be32(val, msg + 2); +- +- mutex_lock(&mhdp->mbox_mutex); +- +- ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, +- DPTX_WRITE_REGISTER, sizeof(msg), msg); +- +- mutex_unlock(&mhdp->mbox_mutex); +- +- return ret; +-} +- + static +-int cdns_mhdp_reg_write_bit(struct cdns_mhdp_device *mhdp, u16 addr, +- u8 start_bit, u8 bits_no, u32 val) +-{ +- u8 field[8]; +- int ret; +- +- put_unaligned_be16(addr, field); +- field[2] = start_bit; +- field[3] = bits_no; +- put_unaligned_be32(val, field + 4); +- +- mutex_lock(&mhdp->mbox_mutex); +- +- ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, +- DPTX_WRITE_FIELD, sizeof(field), field); +- +- mutex_unlock(&mhdp->mbox_mutex); +- +- return ret; +-} +- +-static +-int cdns_mhdp_dpcd_read(struct cdns_mhdp_device *mhdp, +- u32 addr, u8 *data, u16 len) +-{ +- u8 msg[5], reg[5]; +- int ret; +- +- put_unaligned_be16(len, msg); +- put_unaligned_be24(addr, msg + 2); +- +- mutex_lock(&mhdp->mbox_mutex); +- +- ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, +- DPTX_READ_DPCD, sizeof(msg), msg); +- if (ret) +- goto out; +- +- ret = cdns_mhdp_mailbox_recv_header(mhdp, MB_MODULE_ID_DP_TX, +- DPTX_READ_DPCD, +- sizeof(reg) + len); +- if (ret) +- goto out; +- +- ret = cdns_mhdp_mailbox_recv_data(mhdp, reg, sizeof(reg)); +- if (ret) +- goto out; +- +- ret = cdns_mhdp_mailbox_recv_data(mhdp, data, len); +- +-out: +- mutex_unlock(&mhdp->mbox_mutex); +- +- return ret; +-} +- +-static +-int cdns_mhdp_dpcd_write(struct cdns_mhdp_device *mhdp, u32 addr, u8 value) ++int cdns_mhdp_set_firmware_active(struct cdns_mhdp_device *mhdp, bool enable) + { +- u8 msg[6], reg[5]; ++ u8 status; + int ret; + +- put_unaligned_be16(1, msg); +- put_unaligned_be24(addr, msg + 2); +- msg[5] = value; ++ status = enable ? FW_ACTIVE : FW_STANDBY; + + mutex_lock(&mhdp->mbox_mutex); + +- ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, +- DPTX_WRITE_DPCD, sizeof(msg), msg); +- if (ret) +- goto out; +- +- ret = cdns_mhdp_mailbox_recv_header(mhdp, MB_MODULE_ID_DP_TX, +- DPTX_WRITE_DPCD, sizeof(reg)); ++ ret = cdns_mhdp_mailbox_send(&mhdp->base, MB_MODULE_ID_GENERAL, ++ GENERAL_MAIN_CONTROL, sizeof(status), &status); + if (ret) + goto out; + +- ret = cdns_mhdp_mailbox_recv_data(mhdp, reg, sizeof(reg)); +- if (ret) +- goto out; +- +- if (addr != get_unaligned_be24(reg + 2)) +- ret = -EINVAL; +- +-out: +- mutex_unlock(&mhdp->mbox_mutex); +- +- if (ret) +- dev_err(mhdp->dev, "dpcd write failed: %d\n", ret); +- return ret; +-} +- +-static +-int cdns_mhdp_set_firmware_active(struct cdns_mhdp_device *mhdp, bool enable) +-{ +- u8 msg[5]; +- int ret, i; +- +- msg[0] = GENERAL_MAIN_CONTROL; +- msg[1] = MB_MODULE_ID_GENERAL; +- msg[2] = 0; +- msg[3] = 1; +- msg[4] = enable ? FW_ACTIVE : FW_STANDBY; +- +- mutex_lock(&mhdp->mbox_mutex); +- +- for (i = 0; i < sizeof(msg); i++) { +- ret = cdns_mhdp_mailbox_write(mhdp, msg[i]); +- if (ret) +- goto out; +- } +- +- /* read the firmware state */ +- ret = cdns_mhdp_mailbox_recv_data(mhdp, msg, sizeof(msg)); ++ ret = cdns_mhdp_mailbox_recv_header(&mhdp->base, MB_MODULE_ID_GENERAL, ++ GENERAL_MAIN_CONTROL, ++ sizeof(status)); + if (ret) + goto out; + +- ret = 0; ++ ret = cdns_mhdp_mailbox_recv_data(&mhdp->base, &status, sizeof(status)); + + out: + mutex_unlock(&mhdp->mbox_mutex); +@@ -382,18 +112,18 @@ int cdns_mhdp_get_hpd_status(struct cdns_mhdp_device *mhdp) + + mutex_lock(&mhdp->mbox_mutex); + +- ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, ++ ret = cdns_mhdp_mailbox_send(&mhdp->base, MB_MODULE_ID_DP_TX, + DPTX_HPD_STATE, 0, NULL); + if (ret) + goto err_get_hpd; + +- ret = cdns_mhdp_mailbox_recv_header(mhdp, MB_MODULE_ID_DP_TX, ++ ret = cdns_mhdp_mailbox_recv_header(&mhdp->base, MB_MODULE_ID_DP_TX, + DPTX_HPD_STATE, + sizeof(status)); + if (ret) + goto err_get_hpd; + +- ret = cdns_mhdp_mailbox_recv_data(mhdp, &status, sizeof(status)); ++ ret = cdns_mhdp_mailbox_recv_data(&mhdp->base, &status, sizeof(status)); + if (ret) + goto err_get_hpd; + +@@ -424,22 +154,22 @@ int cdns_mhdp_get_edid_block(void *data, u8 *edid, + msg[0] = block / 2; + msg[1] = block % 2; + +- ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, ++ ret = cdns_mhdp_mailbox_send(&mhdp->base, MB_MODULE_ID_DP_TX, + DPTX_GET_EDID, sizeof(msg), msg); + if (ret) + continue; + +- ret = cdns_mhdp_mailbox_recv_header(mhdp, MB_MODULE_ID_DP_TX, ++ ret = cdns_mhdp_mailbox_recv_header(&mhdp->base, MB_MODULE_ID_DP_TX, + DPTX_GET_EDID, + sizeof(reg) + length); + if (ret) + continue; + +- ret = cdns_mhdp_mailbox_recv_data(mhdp, reg, sizeof(reg)); ++ ret = cdns_mhdp_mailbox_recv_data(&mhdp->base, reg, sizeof(reg)); + if (ret) + continue; + +- ret = cdns_mhdp_mailbox_recv_data(mhdp, edid, length); ++ ret = cdns_mhdp_mailbox_recv_data(&mhdp->base, edid, length); + if (ret) + continue; + +@@ -464,17 +194,17 @@ int cdns_mhdp_read_hpd_event(struct cdns_mhdp_device *mhdp) + + mutex_lock(&mhdp->mbox_mutex); + +- ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, ++ ret = cdns_mhdp_mailbox_send(&mhdp->base, MB_MODULE_ID_DP_TX, + DPTX_READ_EVENT, 0, NULL); + if (ret) + goto out; + +- ret = cdns_mhdp_mailbox_recv_header(mhdp, MB_MODULE_ID_DP_TX, ++ ret = cdns_mhdp_mailbox_recv_header(&mhdp->base, MB_MODULE_ID_DP_TX, + DPTX_READ_EVENT, sizeof(event)); + if (ret < 0) + goto out; + +- ret = cdns_mhdp_mailbox_recv_data(mhdp, &event, sizeof(event)); ++ ret = cdns_mhdp_mailbox_recv_data(&mhdp->base, &event, sizeof(event)); + out: + mutex_unlock(&mhdp->mbox_mutex); + +@@ -512,20 +242,20 @@ int cdns_mhdp_adjust_lt(struct cdns_mhdp_device *mhdp, unsigned int nlanes, + + mutex_lock(&mhdp->mbox_mutex); + +- ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, ++ ret = cdns_mhdp_mailbox_send(&mhdp->base, MB_MODULE_ID_DP_TX, + DPTX_ADJUST_LT, + sizeof(payload), payload); + if (ret) + goto out; + + /* Yes, read the DPCD read command response */ +- ret = cdns_mhdp_mailbox_recv_header(mhdp, MB_MODULE_ID_DP_TX, ++ ret = cdns_mhdp_mailbox_recv_header(&mhdp->base, MB_MODULE_ID_DP_TX, + DPTX_READ_DPCD, + sizeof(hdr) + DP_LINK_STATUS_SIZE); + if (ret) + goto out; + +- ret = cdns_mhdp_mailbox_recv_data(mhdp, hdr, sizeof(hdr)); ++ ret = cdns_mhdp_mailbox_recv_data(&mhdp->base, hdr, sizeof(hdr)); + if (ret) + goto out; + +@@ -533,7 +263,7 @@ int cdns_mhdp_adjust_lt(struct cdns_mhdp_device *mhdp, unsigned int nlanes, + if (addr != DP_LANE0_1_STATUS) + goto out; + +- ret = cdns_mhdp_mailbox_recv_data(mhdp, link_status, ++ ret = cdns_mhdp_mailbox_recv_data(&mhdp->base, link_status, + DP_LINK_STATUS_SIZE); + + out: +@@ -847,7 +577,7 @@ static ssize_t cdns_mhdp_transfer(struct drm_dp_aux *aux, + unsigned int i; + + for (i = 0; i < msg->size; ++i) { +- ret = cdns_mhdp_dpcd_write(mhdp, ++ ret = cdns_mhdp_dpcd_write(&mhdp->base, + msg->address + i, buf[i]); + if (!ret) + continue; +@@ -859,7 +589,7 @@ static ssize_t cdns_mhdp_transfer(struct drm_dp_aux *aux, + return ret; + } + } else { +- ret = cdns_mhdp_dpcd_read(mhdp, msg->address, ++ ret = cdns_mhdp_dpcd_read(&mhdp->base, msg->address, + msg->buffer, msg->size); + if (ret) { + dev_err(mhdp->dev, +@@ -887,12 +617,12 @@ static int cdns_mhdp_link_training_init(struct cdns_mhdp_device *mhdp) + if (!mhdp->host.scrambler) + reg32 |= CDNS_PHY_SCRAMBLER_BYPASS; + +- cdns_mhdp_reg_write(mhdp, CDNS_DPTX_PHY_CONFIG, reg32); ++ cdns_mhdp_reg_write(&mhdp->base, CDNS_DPTX_PHY_CONFIG, reg32); + +- cdns_mhdp_reg_write(mhdp, CDNS_DP_ENHNCD, ++ cdns_mhdp_reg_write(&mhdp->base, CDNS_DP_ENHNCD, + mhdp->sink.enhanced & mhdp->host.enhanced); + +- cdns_mhdp_reg_write(mhdp, CDNS_DP_LANE_EN, ++ cdns_mhdp_reg_write(&mhdp->base, CDNS_DP_LANE_EN, + CDNS_DP_LANE_EN_LANES(mhdp->link.num_lanes)); + + cdns_mhdp_link_configure(&mhdp->aux, &mhdp->link); +@@ -913,7 +643,7 @@ static int cdns_mhdp_link_training_init(struct cdns_mhdp_device *mhdp) + return ret; + } + +- cdns_mhdp_reg_write(mhdp, CDNS_DPTX_PHY_CONFIG, ++ cdns_mhdp_reg_write(&mhdp->base, CDNS_DPTX_PHY_CONFIG, + CDNS_PHY_COMMON_CONFIG | + CDNS_PHY_TRAINING_EN | + CDNS_PHY_TRAINING_TYPE(1) | +@@ -1058,7 +788,7 @@ static bool cdns_mhdp_link_training_channel_eq(struct cdns_mhdp_device *mhdp, + CDNS_PHY_TRAINING_TYPE(eq_tps); + if (eq_tps != 4) + reg32 |= CDNS_PHY_SCRAMBLER_BYPASS; +- cdns_mhdp_reg_write(mhdp, CDNS_DPTX_PHY_CONFIG, reg32); ++ cdns_mhdp_reg_write(&mhdp->base, CDNS_DPTX_PHY_CONFIG, reg32); + + drm_dp_dpcd_writeb(&mhdp->aux, DP_TRAINING_PATTERN_SET, + (eq_tps != 4) ? eq_tps | DP_LINK_SCRAMBLING_DISABLE : +@@ -1322,7 +1052,7 @@ static int cdns_mhdp_link_training(struct cdns_mhdp_device *mhdp, + mhdp->host.scrambler ? 0 : + DP_LINK_SCRAMBLING_DISABLE); + +- ret = cdns_mhdp_reg_read(mhdp, CDNS_DP_FRAMER_GLOBAL_CONFIG, ®32); ++ ret = cdns_mhdp_reg_read(&mhdp->base, CDNS_DP_FRAMER_GLOBAL_CONFIG, ®32); + if (ret < 0) { + dev_err(mhdp->dev, + "Failed to read CDNS_DP_FRAMER_GLOBAL_CONFIG %d\n", +@@ -1333,13 +1063,13 @@ static int cdns_mhdp_link_training(struct cdns_mhdp_device *mhdp, + reg32 |= CDNS_DP_NUM_LANES(mhdp->link.num_lanes); + reg32 |= CDNS_DP_WR_FAILING_EDGE_VSYNC; + reg32 |= CDNS_DP_FRAMER_EN; +- cdns_mhdp_reg_write(mhdp, CDNS_DP_FRAMER_GLOBAL_CONFIG, reg32); ++ cdns_mhdp_reg_write(&mhdp->base, CDNS_DP_FRAMER_GLOBAL_CONFIG, reg32); + + /* Reset PHY config */ + reg32 = CDNS_PHY_COMMON_CONFIG | CDNS_PHY_TRAINING_TYPE(1); + if (!mhdp->host.scrambler) + reg32 |= CDNS_PHY_SCRAMBLER_BYPASS; +- cdns_mhdp_reg_write(mhdp, CDNS_DPTX_PHY_CONFIG, reg32); ++ cdns_mhdp_reg_write(&mhdp->base, CDNS_DPTX_PHY_CONFIG, reg32); + + return 0; + err: +@@ -1347,7 +1077,7 @@ static int cdns_mhdp_link_training(struct cdns_mhdp_device *mhdp, + reg32 = CDNS_PHY_COMMON_CONFIG | CDNS_PHY_TRAINING_TYPE(1); + if (!mhdp->host.scrambler) + reg32 |= CDNS_PHY_SCRAMBLER_BYPASS; +- cdns_mhdp_reg_write(mhdp, CDNS_DPTX_PHY_CONFIG, reg32); ++ cdns_mhdp_reg_write(&mhdp->base, CDNS_DPTX_PHY_CONFIG, reg32); + + drm_dp_dpcd_writeb(&mhdp->aux, DP_TRAINING_PATTERN_SET, + DP_TRAINING_PATTERN_DISABLE); +@@ -1461,7 +1191,7 @@ static int cdns_mhdp_link_up(struct cdns_mhdp_device *mhdp) + mhdp->link.num_lanes = cdns_mhdp_max_num_lanes(mhdp); + + /* Disable framer for link training */ +- err = cdns_mhdp_reg_read(mhdp, CDNS_DP_FRAMER_GLOBAL_CONFIG, &resp); ++ err = cdns_mhdp_reg_read(&mhdp->base, CDNS_DP_FRAMER_GLOBAL_CONFIG, &resp); + if (err < 0) { + dev_err(mhdp->dev, + "Failed to read CDNS_DP_FRAMER_GLOBAL_CONFIG %d\n", +@@ -1470,7 +1200,7 @@ static int cdns_mhdp_link_up(struct cdns_mhdp_device *mhdp) + } + + resp &= ~CDNS_DP_FRAMER_EN; +- cdns_mhdp_reg_write(mhdp, CDNS_DP_FRAMER_GLOBAL_CONFIG, resp); ++ cdns_mhdp_reg_write(&mhdp->base, CDNS_DP_FRAMER_GLOBAL_CONFIG, resp); + + /* Spread AMP if required, enable 8b/10b coding */ + amp[0] = cdns_mhdp_get_ssc_supported(mhdp) ? DP_SPREAD_AMP_0_5 : 0; +@@ -1839,7 +1569,7 @@ static void cdns_mhdp_configure_video(struct cdns_mhdp_device *mhdp, + if (mode->flags & DRM_MODE_FLAG_INTERLACE) + bnd_hsync2vsync |= CDNS_IP_DET_INTERLACE_FORMAT; + +- cdns_mhdp_reg_write(mhdp, CDNS_BND_HSYNC2VSYNC(stream_id), ++ cdns_mhdp_reg_write(&mhdp->base, CDNS_BND_HSYNC2VSYNC(stream_id), + bnd_hsync2vsync); + + hsync2vsync_pol_ctrl = 0; +@@ -1847,10 +1577,10 @@ static void cdns_mhdp_configure_video(struct cdns_mhdp_device *mhdp, + hsync2vsync_pol_ctrl |= CDNS_H2V_HSYNC_POL_ACTIVE_LOW; + if (mode->flags & DRM_MODE_FLAG_NVSYNC) + hsync2vsync_pol_ctrl |= CDNS_H2V_VSYNC_POL_ACTIVE_LOW; +- cdns_mhdp_reg_write(mhdp, CDNS_HSYNC2VSYNC_POL_CTRL(stream_id), ++ cdns_mhdp_reg_write(&mhdp->base, CDNS_HSYNC2VSYNC_POL_CTRL(stream_id), + hsync2vsync_pol_ctrl); + +- cdns_mhdp_reg_write(mhdp, CDNS_DP_FRAMER_PXL_REPR(stream_id), pxl_repr); ++ cdns_mhdp_reg_write(&mhdp->base, CDNS_DP_FRAMER_PXL_REPR(stream_id), pxl_repr); + + if (mode->flags & DRM_MODE_FLAG_INTERLACE) + dp_framer_sp |= CDNS_DP_FRAMER_INTERLACE; +@@ -1858,19 +1588,19 @@ static void cdns_mhdp_configure_video(struct cdns_mhdp_device *mhdp, + dp_framer_sp |= CDNS_DP_FRAMER_HSYNC_POL_LOW; + if (mode->flags & DRM_MODE_FLAG_NVSYNC) + dp_framer_sp |= CDNS_DP_FRAMER_VSYNC_POL_LOW; +- cdns_mhdp_reg_write(mhdp, CDNS_DP_FRAMER_SP(stream_id), dp_framer_sp); ++ cdns_mhdp_reg_write(&mhdp->base, CDNS_DP_FRAMER_SP(stream_id), dp_framer_sp); + + front_porch = mode->crtc_hsync_start - mode->crtc_hdisplay; + back_porch = mode->crtc_htotal - mode->crtc_hsync_end; +- cdns_mhdp_reg_write(mhdp, CDNS_DP_FRONT_BACK_PORCH(stream_id), ++ cdns_mhdp_reg_write(&mhdp->base, CDNS_DP_FRONT_BACK_PORCH(stream_id), + CDNS_DP_FRONT_PORCH(front_porch) | + CDNS_DP_BACK_PORCH(back_porch)); + +- cdns_mhdp_reg_write(mhdp, CDNS_DP_BYTE_COUNT(stream_id), ++ cdns_mhdp_reg_write(&mhdp->base, CDNS_DP_BYTE_COUNT(stream_id), + mode->crtc_hdisplay * bpp / 8); + + msa_h0 = mode->crtc_htotal - mode->crtc_hsync_start; +- cdns_mhdp_reg_write(mhdp, CDNS_DP_MSA_HORIZONTAL_0(stream_id), ++ cdns_mhdp_reg_write(&mhdp->base, CDNS_DP_MSA_HORIZONTAL_0(stream_id), + CDNS_DP_MSAH0_H_TOTAL(mode->crtc_htotal) | + CDNS_DP_MSAH0_HSYNC_START(msa_h0)); + +@@ -1879,11 +1609,11 @@ static void cdns_mhdp_configure_video(struct cdns_mhdp_device *mhdp, + CDNS_DP_MSAH1_HDISP_WIDTH(mode->crtc_hdisplay); + if (mode->flags & DRM_MODE_FLAG_NHSYNC) + msa_horizontal_1 |= CDNS_DP_MSAH1_HSYNC_POL_LOW; +- cdns_mhdp_reg_write(mhdp, CDNS_DP_MSA_HORIZONTAL_1(stream_id), ++ cdns_mhdp_reg_write(&mhdp->base, CDNS_DP_MSA_HORIZONTAL_1(stream_id), + msa_horizontal_1); + + msa_v0 = mode->crtc_vtotal - mode->crtc_vsync_start; +- cdns_mhdp_reg_write(mhdp, CDNS_DP_MSA_VERTICAL_0(stream_id), ++ cdns_mhdp_reg_write(&mhdp->base, CDNS_DP_MSA_VERTICAL_0(stream_id), + CDNS_DP_MSAV0_V_TOTAL(mode->crtc_vtotal) | + CDNS_DP_MSAV0_VSYNC_START(msa_v0)); + +@@ -1892,7 +1622,7 @@ static void cdns_mhdp_configure_video(struct cdns_mhdp_device *mhdp, + CDNS_DP_MSAV1_VDISP_WIDTH(mode->crtc_vdisplay); + if (mode->flags & DRM_MODE_FLAG_NVSYNC) + msa_vertical_1 |= CDNS_DP_MSAV1_VSYNC_POL_LOW; +- cdns_mhdp_reg_write(mhdp, CDNS_DP_MSA_VERTICAL_1(stream_id), ++ cdns_mhdp_reg_write(&mhdp->base, CDNS_DP_MSA_VERTICAL_1(stream_id), + msa_vertical_1); + + if ((mode->flags & DRM_MODE_FLAG_INTERLACE) && +@@ -1904,14 +1634,14 @@ static void cdns_mhdp_configure_video(struct cdns_mhdp_device *mhdp, + if (pxlfmt == DRM_COLOR_FORMAT_YCBCR420) + misc1 = CDNS_DP_TEST_VSC_SDP; + +- cdns_mhdp_reg_write(mhdp, CDNS_DP_MSA_MISC(stream_id), ++ cdns_mhdp_reg_write(&mhdp->base, CDNS_DP_MSA_MISC(stream_id), + misc0 | (misc1 << 8)); + +- cdns_mhdp_reg_write(mhdp, CDNS_DP_HORIZONTAL(stream_id), ++ cdns_mhdp_reg_write(&mhdp->base, CDNS_DP_HORIZONTAL(stream_id), + CDNS_DP_H_HSYNC_WIDTH(hsync) | + CDNS_DP_H_H_TOTAL(mode->crtc_hdisplay)); + +- cdns_mhdp_reg_write(mhdp, CDNS_DP_VERTICAL_0(stream_id), ++ cdns_mhdp_reg_write(&mhdp->base, CDNS_DP_VERTICAL_0(stream_id), + CDNS_DP_V0_VHEIGHT(mode->crtc_vdisplay) | + CDNS_DP_V0_VSTART(msa_v0)); + +@@ -1920,13 +1650,13 @@ static void cdns_mhdp_configure_video(struct cdns_mhdp_device *mhdp, + mode->crtc_vtotal % 2 == 0) + dp_vertical_1 |= CDNS_DP_V1_VTOTAL_EVEN; + +- cdns_mhdp_reg_write(mhdp, CDNS_DP_VERTICAL_1(stream_id), dp_vertical_1); ++ cdns_mhdp_reg_write(&mhdp->base, CDNS_DP_VERTICAL_1(stream_id), dp_vertical_1); + +- cdns_mhdp_reg_write_bit(mhdp, CDNS_DP_VB_ID(stream_id), 2, 1, +- (mode->flags & DRM_MODE_FLAG_INTERLACE) ? +- CDNS_DP_VB_ID_INTERLACED : 0); ++ cdns_mhdp_dp_reg_write_bit(&mhdp->base, CDNS_DP_VB_ID(stream_id), 2, 1, ++ (mode->flags & DRM_MODE_FLAG_INTERLACE) ? ++ CDNS_DP_VB_ID_INTERLACED : 0); + +- ret = cdns_mhdp_reg_read(mhdp, CDNS_DP_FRAMER_GLOBAL_CONFIG, &framer); ++ ret = cdns_mhdp_reg_read(&mhdp->base, CDNS_DP_FRAMER_GLOBAL_CONFIG, &framer); + if (ret < 0) { + dev_err(mhdp->dev, + "Failed to read CDNS_DP_FRAMER_GLOBAL_CONFIG %d\n", +@@ -1935,7 +1665,7 @@ static void cdns_mhdp_configure_video(struct cdns_mhdp_device *mhdp, + } + framer |= CDNS_DP_FRAMER_EN; + framer &= ~CDNS_DP_NO_VIDEO_MODE; +- cdns_mhdp_reg_write(mhdp, CDNS_DP_FRAMER_GLOBAL_CONFIG, framer); ++ cdns_mhdp_reg_write(&mhdp->base, CDNS_DP_FRAMER_GLOBAL_CONFIG, framer); + } + + static void cdns_mhdp_sst_enable(struct cdns_mhdp_device *mhdp, +@@ -1968,15 +1698,15 @@ static void cdns_mhdp_sst_enable(struct cdns_mhdp_device *mhdp, + + mhdp->stream_id = 0; + +- cdns_mhdp_reg_write(mhdp, CDNS_DP_FRAMER_TU, ++ cdns_mhdp_reg_write(&mhdp->base, CDNS_DP_FRAMER_TU, + CDNS_DP_FRAMER_TU_VS(vs) | + CDNS_DP_FRAMER_TU_SIZE(tu_size) | + CDNS_DP_FRAMER_TU_CNT_RST_EN); + +- cdns_mhdp_reg_write(mhdp, CDNS_DP_LINE_THRESH(0), ++ cdns_mhdp_reg_write(&mhdp->base, CDNS_DP_LINE_THRESH(0), + line_thresh & GENMASK(5, 0)); + +- cdns_mhdp_reg_write(mhdp, CDNS_DP_STREAM_CONFIG_2(0), ++ cdns_mhdp_reg_write(&mhdp->base, CDNS_DP_STREAM_CONFIG_2(0), + CDNS_DP_SC2_TU_VS_DIFF((tu_size - vs > 3) ? + 0 : tu_size - vs)); + +@@ -2011,13 +1741,13 @@ static void cdns_mhdp_atomic_enable(struct drm_bridge *bridge, + mhdp->info->ops->enable(mhdp); + + /* Enable VIF clock for stream 0 */ +- ret = cdns_mhdp_reg_read(mhdp, CDNS_DPTX_CAR, &resp); ++ ret = cdns_mhdp_reg_read(&mhdp->base, CDNS_DPTX_CAR, &resp); + if (ret < 0) { + dev_err(mhdp->dev, "Failed to read CDNS_DPTX_CAR %d\n", ret); + goto out; + } + +- cdns_mhdp_reg_write(mhdp, CDNS_DPTX_CAR, ++ cdns_mhdp_reg_write(&mhdp->base, CDNS_DPTX_CAR, + resp | CDNS_VIF_CLK_EN | CDNS_VIF_CLK_RSTN); + + connector = drm_atomic_get_new_connector_for_encoder(state, +@@ -2088,16 +1818,16 @@ static void cdns_mhdp_atomic_disable(struct drm_bridge *bridge, + cdns_mhdp_hdcp_disable(mhdp); + + mhdp->bridge_enabled = false; +- cdns_mhdp_reg_read(mhdp, CDNS_DP_FRAMER_GLOBAL_CONFIG, &resp); ++ cdns_mhdp_reg_read(&mhdp->base, CDNS_DP_FRAMER_GLOBAL_CONFIG, &resp); + resp &= ~CDNS_DP_FRAMER_EN; + resp |= CDNS_DP_NO_VIDEO_MODE; +- cdns_mhdp_reg_write(mhdp, CDNS_DP_FRAMER_GLOBAL_CONFIG, resp); ++ cdns_mhdp_reg_write(&mhdp->base, CDNS_DP_FRAMER_GLOBAL_CONFIG, resp); + + cdns_mhdp_link_down(mhdp); + + /* Disable VIF clock for stream 0 */ +- cdns_mhdp_reg_read(mhdp, CDNS_DPTX_CAR, &resp); +- cdns_mhdp_reg_write(mhdp, CDNS_DPTX_CAR, ++ cdns_mhdp_reg_read(&mhdp->base, CDNS_DPTX_CAR, &resp); ++ cdns_mhdp_reg_write(&mhdp->base, CDNS_DPTX_CAR, + resp & ~(CDNS_VIF_CLK_EN | CDNS_VIF_CLK_RSTN)); + + if (mhdp->info && mhdp->info->ops && mhdp->info->ops->disable) +@@ -2507,6 +2237,11 @@ static int cdns_mhdp_probe(struct platform_device *pdev) + + platform_set_drvdata(pdev, mhdp); + ++ /* init base struct for access mailbox */ ++ mhdp->base.dev = mhdp->dev; ++ mhdp->base.regs = mhdp->regs; ++ mhdp->base.mbox_mutex = &mhdp->mbox_mutex; ++ + mhdp->info = of_device_get_match_data(dev); + + clk_prepare_enable(clk); +diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.h b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.h +index bad2fc0c7306..f08db38c82bb 100644 +--- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.h ++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.h +@@ -15,6 +15,7 @@ + #include + #include + ++#include + #include + #include + #include +@@ -27,10 +28,6 @@ struct phy; + #define CDNS_APB_CTRL 0x00000 + #define CDNS_CPU_STALL BIT(3) + +-#define CDNS_MAILBOX_FULL 0x00008 +-#define CDNS_MAILBOX_EMPTY 0x0000c +-#define CDNS_MAILBOX_TX_DATA 0x00010 +-#define CDNS_MAILBOX_RX_DATA 0x00014 + #define CDNS_KEEP_ALIVE 0x00018 + #define CDNS_KEEP_ALIVE_MASK GENMASK(7, 0) + +@@ -198,45 +195,10 @@ struct phy; + #define CDNS_DP_BYTE_COUNT(s) (CDNS_DPTX_STREAM(s) + 0x7c) + #define CDNS_DP_BYTE_COUNT_BYTES_IN_CHUNK_SHIFT 16 + +-/* mailbox */ +-#define MAILBOX_RETRY_US 1000 +-#define MAILBOX_TIMEOUT_US 2000000 +- +-#define MB_OPCODE_ID 0 +-#define MB_MODULE_ID 1 +-#define MB_SIZE_MSB_ID 2 +-#define MB_SIZE_LSB_ID 3 +-#define MB_DATA_ID 4 +- +-#define MB_MODULE_ID_DP_TX 0x01 +-#define MB_MODULE_ID_HDCP_TX 0x07 +-#define MB_MODULE_ID_HDCP_RX 0x08 +-#define MB_MODULE_ID_HDCP_GENERAL 0x09 +-#define MB_MODULE_ID_GENERAL 0x0a +- +-/* firmware and opcodes */ ++/* firmware */ + #define FW_NAME "cadence/mhdp8546.bin" + #define CDNS_MHDP_IMEM 0x10000 + +-#define GENERAL_MAIN_CONTROL 0x01 +-#define GENERAL_TEST_ECHO 0x02 +-#define GENERAL_BUS_SETTINGS 0x03 +-#define GENERAL_TEST_ACCESS 0x04 +-#define GENERAL_REGISTER_READ 0x07 +- +-#define DPTX_SET_POWER_MNG 0x00 +-#define DPTX_GET_EDID 0x02 +-#define DPTX_READ_DPCD 0x03 +-#define DPTX_WRITE_DPCD 0x04 +-#define DPTX_ENABLE_EVENT 0x05 +-#define DPTX_WRITE_REGISTER 0x06 +-#define DPTX_READ_REGISTER 0x07 +-#define DPTX_WRITE_FIELD 0x08 +-#define DPTX_READ_EVENT 0x0a +-#define DPTX_GET_LAST_AUX_STAUS 0x0e +-#define DPTX_HPD_STATE 0x11 +-#define DPTX_ADJUST_LT 0x12 +- + #define FW_STANDBY 0 + #define FW_ACTIVE 1 + +@@ -352,6 +314,8 @@ struct cdns_mhdp_hdcp { + }; + + struct cdns_mhdp_device { ++ struct cdns_mhdp_base base; ++ + void __iomem *regs; + void __iomem *sapb_regs; + void __iomem *j721e_regs; +diff --git a/include/drm/bridge/cdns-mhdp-helper.h b/include/drm/bridge/cdns-mhdp-helper.h +new file mode 100644 +index 000000000000..cdc124cd9c47 +--- /dev/null ++++ b/include/drm/bridge/cdns-mhdp-helper.h +@@ -0,0 +1,97 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++/* ++ * Copyright (C) 2023 NXP Semiconductor, Inc. ++ */ ++#ifndef __CDNS_MHDP_HELPER_H__ ++#define __CDNS_MHDP_HELPER_H__ ++ ++#include ++#include ++ ++/* mailbox regs offset */ ++#define CDNS_MAILBOX_FULL 0x00008 ++#define CDNS_MAILBOX_EMPTY 0x0000c ++#define CDNS_MAILBOX_TX_DATA 0x00010 ++#define CDNS_MAILBOX_RX_DATA 0x00014 ++ ++#define MAILBOX_RETRY_US 1000 ++#define MAILBOX_TIMEOUT_US 2000000 ++ ++/* Module ID Code */ ++#define MB_MODULE_ID_DP_TX 0x01 ++#define MB_MODULE_ID_HDMI_TX 0x03 ++#define MB_MODULE_ID_HDCP_TX 0x07 ++#define MB_MODULE_ID_HDCP_RX 0x08 ++#define MB_MODULE_ID_HDCP_GENERAL 0x09 ++#define MB_MODULE_ID_GENERAL 0x0A ++ ++/* General Commands */ ++#define GENERAL_MAIN_CONTROL 0x01 ++#define GENERAL_TEST_ECHO 0x02 ++#define GENERAL_BUS_SETTINGS 0x03 ++#define GENERAL_TEST_ACCESS 0x04 ++#define GENERAL_REGISTER_WRITE 0x05 ++#define GENERAL_WRITE_FIELD 0x06 ++#define GENERAL_REGISTER_READ 0x07 ++#define GENERAL_GET_HPD_STATE 0x11 ++ ++/* DPTX Commands */ ++#define DPTX_SET_POWER_MNG 0x00 ++#define DPTX_SET_HOST_CAPABILITIES 0x01 ++#define DPTX_GET_EDID 0x02 ++#define DPTX_READ_DPCD 0x03 ++#define DPTX_WRITE_DPCD 0x04 ++#define DPTX_ENABLE_EVENT 0x05 ++#define DPTX_WRITE_REGISTER 0x06 ++#define DPTX_READ_REGISTER 0x07 ++#define DPTX_WRITE_FIELD 0x08 ++#define DPTX_TRAINING_CONTROL 0x09 ++#define DPTX_READ_EVENT 0x0a ++#define DPTX_READ_LINK_STAT 0x0b ++#define DPTX_SET_VIDEO 0x0c ++#define DPTX_SET_AUDIO 0x0d ++#define DPTX_GET_LAST_AUX_STAUS 0x0e ++#define DPTX_SET_LINK_BREAK_POINT 0x0f ++#define DPTX_FORCE_LANES 0x10 ++#define DPTX_HPD_STATE 0x11 ++#define DPTX_ADJUST_LT 0x12 ++ ++/* HDMI TX Commands */ ++#define HDMI_TX_READ 0x00 ++#define HDMI_TX_WRITE 0x01 ++#define HDMI_TX_UPDATE_READ 0x02 ++#define HDMI_TX_EDID 0x03 ++#define HDMI_TX_EVENTS 0x04 ++#define HDMI_TX_HPD_STATUS 0x05 ++ ++struct cdns_mhdp_base { ++ struct device *dev; ++ void __iomem *regs; ++ /* protect mailbox communications with the firmware */ ++ struct mutex *mbox_mutex; ++}; ++ ++/* Mailbox helper functions ++ * mbox_mutex in struct cdns_mhdp_base should locked ++ * when access these functions. ++ */ ++int cdns_mhdp_mailbox_recv_data(struct cdns_mhdp_base *base, ++ u8 *buff, u16 buff_size); ++int cdns_mhdp_mailbox_recv_header(struct cdns_mhdp_base *base, ++ u8 module_id, u8 opcode, u16 req_size); ++int cdns_mhdp_mailbox_send(struct cdns_mhdp_base *base, u8 module_id, ++ u8 opcode, u16 size, u8 *message); ++ ++/* General commands helper functions */ ++int cdns_mhdp_reg_read(struct cdns_mhdp_base *base, u32 addr, u32 *value); ++int cdns_mhdp_reg_write(struct cdns_mhdp_base *base, u32 addr, u32 val); ++ ++/* DPTX commands helper functions */ ++int cdns_mhdp_dp_reg_write(struct cdns_mhdp_base *base, u16 addr, u32 val); ++int cdns_mhdp_dp_reg_write_bit(struct cdns_mhdp_base *base, u16 addr, ++ u8 start_bit, u8 bits_no, u32 val); ++int cdns_mhdp_dpcd_read(struct cdns_mhdp_base *base, ++ u32 addr, u8 *data, u16 len); ++int cdns_mhdp_dpcd_write(struct cdns_mhdp_base *base, u32 addr, u8 value); ++ ++#endif /* __CDNS_MHDP_HELPER_H__ */ + +From patchwork Tue Jul 2 12:22:34 2024 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [v16,2/8] phy: Add HDMI configuration options +From: Sandor Yu +X-Patchwork-Id: 601664 +Message-Id: + +To: dmitry.baryshkov@linaro.org, andrzej.hajda@intel.com, + neil.armstrong@linaro.org, Laurent.pinchart@ideasonboard.com, + jonas@kwiboo.se, jernej.skrabec@gmail.com, airlied@gmail.com, + daniel@ffwll.ch, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, + shawnguo@kernel.org, s.hauer@pengutronix.de, festevam@gmail.com, + vkoul@kernel.org, dri-devel@lists.freedesktop.org, + devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, + linux-kernel@vger.kernel.org, linux-phy@lists.infradead.org, + mripard@kernel.org +Cc: kernel@pengutronix.de, linux-imx@nxp.com, Sandor.yu@nxp.com, + oliver.brown@nxp.com, alexander.stein@ew.tq-group.com, sam@ravnborg.org +Date: Tue, 2 Jul 2024 20:22:34 +0800 + +Allow HDMI PHYs to be configured through the generic +functions through a custom structure added to the generic union. + +The parameters added here are based on HDMI PHY +implementation practices. The current set of parameters +should cover the potential users. + +Signed-off-by: Sandor Yu +--- +v15->v16: +- Remove pixel_clk_rate, bpc and color_space fields from struct + phy_configure_opts_hdmi, they were replaced by unsigned long long tmds_char_rate. +- Remove r-b and a-c tags because this patch have important change. + +v9->v15: + *No change. + + include/linux/phy/phy-hdmi.h | 20 ++++++++++++++++++++ + include/linux/phy/phy.h | 7 ++++++- + 2 files changed, 26 insertions(+), 1 deletion(-) + create mode 100644 include/linux/phy/phy-hdmi.h + +diff --git a/include/linux/phy/phy-hdmi.h b/include/linux/phy/phy-hdmi.h +new file mode 100644 +index 000000000000..dd923e19d17c +--- /dev/null ++++ b/include/linux/phy/phy-hdmi.h +@@ -0,0 +1,20 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright 2022 NXP ++ */ ++ ++#ifndef __PHY_HDMI_H_ ++#define __PHY_HDMI_H_ ++ ++#include ++/** ++ * struct phy_configure_opts_hdmi - HDMI configuration set ++ * @tmds_char_rate: HDMI TMDS Character Rate in Hertz. ++ * ++ * This structure is used to represent the configuration state of a HDMI phy. ++ */ ++struct phy_configure_opts_hdmi { ++ unsigned long long tmds_char_rate; ++}; ++ ++#endif /* __PHY_HDMI_H_ */ +diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h +index 03cd5bae92d3..4ac486b101fe 100644 +--- a/include/linux/phy/phy.h ++++ b/include/linux/phy/phy.h +@@ -17,6 +17,7 @@ + #include + + #include ++#include + #include + #include + +@@ -42,7 +43,8 @@ enum phy_mode { + PHY_MODE_MIPI_DPHY, + PHY_MODE_SATA, + PHY_MODE_LVDS, +- PHY_MODE_DP ++ PHY_MODE_DP, ++ PHY_MODE_HDMI, + }; + + enum phy_media { +@@ -60,11 +62,14 @@ enum phy_media { + * the DisplayPort protocol. + * @lvds: Configuration set applicable for phys supporting + * the LVDS phy mode. ++ * @hdmi: Configuration set applicable for phys supporting ++ * the HDMI phy mode. + */ + union phy_configure_opts { + struct phy_configure_opts_mipi_dphy mipi_dphy; + struct phy_configure_opts_dp dp; + struct phy_configure_opts_lvds lvds; ++ struct phy_configure_opts_hdmi hdmi; + }; + + /** + +From patchwork Tue Jul 2 12:22:35 2024 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [v16,3/8] dt-bindings: display: bridge: Add Cadence MHDP8501 +From: Sandor Yu +X-Patchwork-Id: 601665 +Message-Id: + +To: dmitry.baryshkov@linaro.org, andrzej.hajda@intel.com, + neil.armstrong@linaro.org, Laurent.pinchart@ideasonboard.com, + jonas@kwiboo.se, jernej.skrabec@gmail.com, airlied@gmail.com, + daniel@ffwll.ch, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, + shawnguo@kernel.org, s.hauer@pengutronix.de, festevam@gmail.com, + vkoul@kernel.org, dri-devel@lists.freedesktop.org, + devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, + linux-kernel@vger.kernel.org, linux-phy@lists.infradead.org, + mripard@kernel.org +Cc: kernel@pengutronix.de, linux-imx@nxp.com, Sandor.yu@nxp.com, + oliver.brown@nxp.com, alexander.stein@ew.tq-group.com, sam@ravnborg.org, + Krzysztof Kozlowski +Date: Tue, 2 Jul 2024 20:22:35 +0800 + +Add bindings for Cadence MHDP8501 DisplayPort/HDMI bridge. + +Signed-off-by: Sandor Yu +Reviewed-by: Krzysztof Kozlowski +--- +v9->v16: + *No change + + .../display/bridge/cdns,mhdp8501.yaml | 104 ++++++++++++++++++ + 1 file changed, 104 insertions(+) + create mode 100644 Documentation/devicetree/bindings/display/bridge/cdns,mhdp8501.yaml + +diff --git a/Documentation/devicetree/bindings/display/bridge/cdns,mhdp8501.yaml b/Documentation/devicetree/bindings/display/bridge/cdns,mhdp8501.yaml +new file mode 100644 +index 000000000000..8eff6c24fb87 +--- /dev/null ++++ b/Documentation/devicetree/bindings/display/bridge/cdns,mhdp8501.yaml +@@ -0,0 +1,104 @@ ++# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/display/bridge/cdns,mhdp8501.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Cadence MHDP8501 DP/HDMI bridge ++ ++maintainers: ++ - Sandor Yu ++ ++description: ++ Cadence MHDP8501 DisplayPort/HDMI interface. ++ ++properties: ++ compatible: ++ enum: ++ - fsl,imx8mq-mhdp8501 ++ ++ reg: ++ maxItems: 1 ++ ++ clocks: ++ maxItems: 1 ++ description: MHDP8501 DP/HDMI APB clock. ++ ++ phys: ++ maxItems: 1 ++ description: ++ phandle to the DP/HDMI PHY ++ ++ interrupts: ++ items: ++ - description: Hotplug cable plugin. ++ - description: Hotplug cable plugout. ++ ++ interrupt-names: ++ items: ++ - const: plug_in ++ - const: plug_out ++ ++ ports: ++ $ref: /schemas/graph.yaml#/properties/ports ++ ++ properties: ++ port@0: ++ $ref: /schemas/graph.yaml#/properties/port ++ description: ++ Input port from display controller output. ++ port@1: ++ $ref: /schemas/graph.yaml#/properties/port ++ description: ++ Output port to DisplayPort or HDMI connector. ++ ++ required: ++ - port@0 ++ - port@1 ++ ++required: ++ - compatible ++ - reg ++ - clocks ++ - interrupts ++ - interrupt-names ++ - phys ++ - ports ++ ++additionalProperties: false ++ ++examples: ++ - | ++ #include ++ #include ++ ++ mhdp: display-bridge@32c00000 { ++ compatible = "fsl,imx8mq-mhdp8501"; ++ reg = <0x32c00000 0x100000>; ++ interrupts = , ++ ; ++ interrupt-names = "plug_in", "plug_out"; ++ clocks = <&clk IMX8MQ_CLK_DISP_APB_ROOT>; ++ phys = <&mdhp_phy>; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ reg = <0>; ++ ++ mhdp_in: endpoint { ++ remote-endpoint = <&dcss_out>; ++ }; ++ }; ++ ++ port@1 { ++ reg = <1>; ++ ++ mhdp_out: endpoint { ++ remote-endpoint = <&dp_connector>; ++ }; ++ }; ++ }; ++ }; + +From patchwork Tue Jul 2 12:22:36 2024 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [v16,4/8] drm: bridge: Cadence: Add MHDP8501 DP/HDMI driver +From: Sandor Yu +X-Patchwork-Id: 601666 +Message-Id: + <359914108b879e995d4a39de32a33310009f0fab.1719903904.git.Sandor.yu@nxp.com> +To: dmitry.baryshkov@linaro.org, andrzej.hajda@intel.com, + neil.armstrong@linaro.org, Laurent.pinchart@ideasonboard.com, + jonas@kwiboo.se, jernej.skrabec@gmail.com, airlied@gmail.com, + daniel@ffwll.ch, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, + shawnguo@kernel.org, s.hauer@pengutronix.de, festevam@gmail.com, + vkoul@kernel.org, dri-devel@lists.freedesktop.org, + devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, + linux-kernel@vger.kernel.org, linux-phy@lists.infradead.org, + mripard@kernel.org +Cc: kernel@pengutronix.de, linux-imx@nxp.com, Sandor.yu@nxp.com, + oliver.brown@nxp.com, alexander.stein@ew.tq-group.com, sam@ravnborg.org +Date: Tue, 2 Jul 2024 20:22:36 +0800 + +Add a new DRM DisplayPort and HDMI bridge driver for Candence MHDP8501 +used in i.MX8MQ SOC. MHDP8501 could support HDMI or DisplayPort +standards according embedded Firmware running in the uCPU. + +For iMX8MQ SOC, the DisplayPort/HDMI FW was loaded and activated by +SOC's ROM code. Bootload binary included respective specific firmware +is required. + +Driver will check display connector type and +then load the corresponding driver. + +Signed-off-by: Sandor Yu +Tested-by: Alexander Stein +--- +v15->v16: +- rebase the patchset sits on top Dmitry's + 'make use of the HDMI connector infrastructure' patchset ([2]). +- Add DRM_BRIDGE_OP_HDMI flags for HDMI driver, +- Introduce the hdmi info frame helper functions, added hdmi_clear_infoframe(), + hdmi_write_infoframe() and hdmi_tmds_char_rate_valid(). +- mode_fixup() was replaced by atomic_check(). +- Fix video mode 4Kp30 did not work on some displays that support + LTE_340Mcsc_scramble. +- updated for tmds_char_rate added in patch #2. + +v13->v14: +- Rebase to next-20240219, replace get_edid function by edid_read + function. + +v12->v13: +- Explicitly include linux/platform_device.h for cdns-mhdp8501-core.c +- Fix build warning +- Order bit bpc and color_space in descending shit. + +v11->v12: +- Replace DRM_INFO with dev_info or dev_warn. +- Replace DRM_ERROR with dev_err. +- Return ret when cdns_mhdp_dpcd_read failed in function cdns_dp_aux_transferi(). +- Remove unused parmeter in function cdns_dp_get_msa_misc + and use two separate variables for color space and bpc. +- Add year 2024 to copyright. + + drivers/gpu/drm/bridge/cadence/Kconfig | 16 + + drivers/gpu/drm/bridge/cadence/Makefile | 2 + + .../drm/bridge/cadence/cdns-mhdp8501-core.c | 330 +++++++++ + .../drm/bridge/cadence/cdns-mhdp8501-core.h | 367 +++++++++ + .../gpu/drm/bridge/cadence/cdns-mhdp8501-dp.c | 700 ++++++++++++++++++ + .../drm/bridge/cadence/cdns-mhdp8501-hdmi.c | 595 +++++++++++++++ + 6 files changed, 2010 insertions(+) + create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp8501-core.c + create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp8501-core.h + create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp8501-dp.c + create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp8501-hdmi.c + +diff --git a/drivers/gpu/drm/bridge/cadence/Kconfig b/drivers/gpu/drm/bridge/cadence/Kconfig +index e0973339e9e3..45848e741f5f 100644 +--- a/drivers/gpu/drm/bridge/cadence/Kconfig ++++ b/drivers/gpu/drm/bridge/cadence/Kconfig +@@ -51,3 +51,19 @@ config DRM_CDNS_MHDP8546_J721E + initializes the J721E Display Port and sets up the + clock and data muxes. + endif ++ ++config DRM_CDNS_MHDP8501 ++ tristate "Cadence MHDP8501 DP/HDMI bridge" ++ select DRM_KMS_HELPER ++ select DRM_PANEL_BRIDGE ++ select DRM_DISPLAY_DP_HELPER ++ select DRM_DISPLAY_HELPER ++ select CDNS_MHDP_HELPER ++ select DRM_CDNS_AUDIO ++ depends on OF ++ help ++ Support Cadence MHDP8501 DisplayPort/HDMI bridge. ++ Cadence MHDP8501 support one or more protocols, ++ including DisplayPort and HDMI. ++ To use the DP and HDMI drivers, their respective ++ specific firmware is required. +diff --git a/drivers/gpu/drm/bridge/cadence/Makefile b/drivers/gpu/drm/bridge/cadence/Makefile +index 087dc074820d..02c1a9f3cf6f 100644 +--- a/drivers/gpu/drm/bridge/cadence/Makefile ++++ b/drivers/gpu/drm/bridge/cadence/Makefile +@@ -6,3 +6,5 @@ obj-$(CONFIG_CDNS_MHDP_HELPER) += cdns-mhdp-helper.o + obj-$(CONFIG_DRM_CDNS_MHDP8546) += cdns-mhdp8546.o + cdns-mhdp8546-y := cdns-mhdp8546-core.o cdns-mhdp8546-hdcp.o + cdns-mhdp8546-$(CONFIG_DRM_CDNS_MHDP8546_J721E) += cdns-mhdp8546-j721e.o ++obj-$(CONFIG_DRM_CDNS_MHDP8501) += cdns-mhdp8501.o ++cdns-mhdp8501-y := cdns-mhdp8501-core.o cdns-mhdp8501-dp.o cdns-mhdp8501-hdmi.o +diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8501-core.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8501-core.c +new file mode 100644 +index 000000000000..c306db982b76 +--- /dev/null ++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8501-core.c +@@ -0,0 +1,330 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Cadence Display Port Interface (DP) driver ++ * ++ * Copyright (C) 2023, 2024 NXP Semiconductor, Inc. ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cdns-mhdp8501-core.h" ++ ++static int cdns_mhdp8501_read_hpd(struct cdns_mhdp8501_device *mhdp) ++{ ++ u8 status; ++ int ret; ++ ++ mutex_lock(&mhdp->mbox_mutex); ++ ++ ret = cdns_mhdp_mailbox_send(&mhdp->base, MB_MODULE_ID_GENERAL, ++ GENERAL_GET_HPD_STATE, 0, NULL); ++ if (ret) ++ goto err_get_hpd; ++ ++ ret = cdns_mhdp_mailbox_recv_header(&mhdp->base, MB_MODULE_ID_GENERAL, ++ GENERAL_GET_HPD_STATE, ++ sizeof(status)); ++ if (ret) ++ goto err_get_hpd; ++ ++ ret = cdns_mhdp_mailbox_recv_data(&mhdp->base, &status, sizeof(status)); ++ if (ret) ++ goto err_get_hpd; ++ ++ mutex_unlock(&mhdp->mbox_mutex); ++ ++ return status; ++ ++err_get_hpd: ++ dev_err(mhdp->dev, "read hpd failed: %d\n", ret); ++ mutex_unlock(&mhdp->mbox_mutex); ++ ++ return ret; ++} ++ ++enum drm_connector_status cdns_mhdp8501_detect(struct cdns_mhdp8501_device *mhdp) ++{ ++ u8 hpd = 0xf; ++ ++ hpd = cdns_mhdp8501_read_hpd(mhdp); ++ if (hpd == 1) ++ return connector_status_connected; ++ else if (hpd == 0) ++ return connector_status_disconnected; ++ ++ dev_warn(mhdp->dev, "Unknown cable status, hdp=%u\n", hpd); ++ return connector_status_unknown; ++} ++ ++static void hotplug_work_func(struct work_struct *work) ++{ ++ struct cdns_mhdp8501_device *mhdp = container_of(work, ++ struct cdns_mhdp8501_device, ++ hotplug_work.work); ++ enum drm_connector_status status = cdns_mhdp8501_detect(mhdp); ++ ++ drm_bridge_hpd_notify(&mhdp->bridge, status); ++ ++ if (status == connector_status_connected) { ++ /* Cable connected */ ++ DRM_INFO("HDMI/DP Cable Plug In\n"); ++ enable_irq(mhdp->irq[IRQ_OUT]); ++ } else if (status == connector_status_disconnected) { ++ /* Cable Disconnected */ ++ DRM_INFO("HDMI/DP Cable Plug Out\n"); ++ enable_irq(mhdp->irq[IRQ_IN]); ++ } ++} ++ ++static irqreturn_t cdns_mhdp8501_irq_thread(int irq, void *data) ++{ ++ struct cdns_mhdp8501_device *mhdp = data; ++ ++ disable_irq_nosync(irq); ++ ++ mod_delayed_work(system_wq, &mhdp->hotplug_work, ++ msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS)); ++ ++ return IRQ_HANDLED; ++} ++ ++static int cdns_mhdp8501_dt_parse(struct cdns_mhdp8501_device *mhdp, ++ struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node; ++ struct device_node *remote; ++ ++ remote = of_graph_get_remote_node(np, 1, 0); ++ if (!remote) { ++ dev_err(dev, "fail to get remote node\n"); ++ of_node_put(remote); ++ return -EINVAL; ++ } ++ ++ /* get connector type */ ++ if (of_device_is_compatible(remote, "hdmi-connector")) { ++ mhdp->connector_type = DRM_MODE_CONNECTOR_HDMIA; ++ ++ } else if (of_device_is_compatible(remote, "dp-connector")) { ++ mhdp->connector_type = DRM_MODE_CONNECTOR_DisplayPort; ++ ++ } else { ++ dev_err(dev, "Unknown connector type\n"); ++ of_node_put(remote); ++ return -EINVAL; ++ } ++ ++ of_node_put(remote); ++ return true; ++} ++ ++static void cdns_mhdp8501_add_bridge(struct cdns_mhdp8501_device *mhdp) ++{ ++ mhdp->bridge.type = mhdp->connector_type; ++ mhdp->bridge.driver_private = mhdp; ++ mhdp->bridge.of_node = mhdp->dev->of_node; ++ mhdp->bridge.vendor = "NXP"; ++ mhdp->bridge.product = "i.MX8"; ++ mhdp->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID | ++ DRM_BRIDGE_OP_HPD; ++ ++ if (mhdp->connector_type == DRM_MODE_CONNECTOR_HDMIA) { ++ mhdp->bridge.funcs = &cdns_hdmi_bridge_funcs; ++ mhdp->bridge.ops |= DRM_BRIDGE_OP_HDMI; ++ } else if (mhdp->connector_type == DRM_MODE_CONNECTOR_DisplayPort) { ++ mhdp->bridge.funcs = &cdns_dp_bridge_funcs; ++ } else { ++ dev_err(mhdp->dev, "Unsupported connector type!\n"); ++ return; ++ } ++ ++ drm_bridge_add(&mhdp->bridge); ++} ++ ++static int cdns_mhdp8501_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct cdns_mhdp8501_device *mhdp; ++ struct resource *res; ++ enum phy_mode phy_mode; ++ u32 reg; ++ int ret; ++ ++ mhdp = devm_kzalloc(dev, sizeof(*mhdp), GFP_KERNEL); ++ if (!mhdp) ++ return -ENOMEM; ++ ++ mutex_init(&mhdp->mbox_mutex); ++ mhdp->dev = dev; ++ ++ INIT_DELAYED_WORK(&mhdp->hotplug_work, hotplug_work_func); ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) ++ return -ENODEV; ++ ++ mhdp->regs = devm_ioremap(dev, res->start, resource_size(res)); ++ if (IS_ERR(mhdp->regs)) ++ return PTR_ERR(mhdp->regs); ++ ++ ret = cdns_mhdp8501_dt_parse(mhdp, pdev); ++ if (ret < 0) ++ return -EINVAL; ++ ++ mhdp->phy = devm_of_phy_get_by_index(dev, pdev->dev.of_node, 0); ++ if (IS_ERR(mhdp->phy)) ++ return dev_err_probe(dev, PTR_ERR(mhdp->phy), "no PHY configured\n"); ++ ++ mhdp->irq[IRQ_IN] = platform_get_irq_byname(pdev, "plug_in"); ++ if (mhdp->irq[IRQ_IN] < 0) ++ return dev_err_probe(dev, mhdp->irq[IRQ_IN], "No plug_in irq number\n"); ++ ++ mhdp->irq[IRQ_OUT] = platform_get_irq_byname(pdev, "plug_out"); ++ if (mhdp->irq[IRQ_OUT] < 0) ++ return dev_err_probe(dev, mhdp->irq[IRQ_OUT], "No plug_out irq number\n"); ++ ++ irq_set_status_flags(mhdp->irq[IRQ_IN], IRQ_NOAUTOEN); ++ ret = devm_request_threaded_irq(dev, mhdp->irq[IRQ_IN], ++ NULL, cdns_mhdp8501_irq_thread, ++ IRQF_ONESHOT, dev_name(dev), mhdp); ++ if (ret < 0) { ++ dev_err(dev, "can't claim irq %d\n", mhdp->irq[IRQ_IN]); ++ return -EINVAL; ++ } ++ ++ irq_set_status_flags(mhdp->irq[IRQ_OUT], IRQ_NOAUTOEN); ++ ret = devm_request_threaded_irq(dev, mhdp->irq[IRQ_OUT], ++ NULL, cdns_mhdp8501_irq_thread, ++ IRQF_ONESHOT, dev_name(dev), mhdp); ++ if (ret < 0) { ++ dev_err(dev, "can't claim irq %d\n", mhdp->irq[IRQ_OUT]); ++ return -EINVAL; ++ } ++ ++ /* set default lane mapping */ ++ mhdp->lane_mapping = LANE_MAPPING_NORMAL; ++ ++ /* cdns_mhdp8501_dt_parse() ensures connector_type is valid */ ++ mhdp->plat_data = of_device_get_match_data(dev); ++ if (mhdp->connector_type == DRM_MODE_CONNECTOR_DisplayPort) { ++ mhdp->lane_mapping = mhdp->plat_data->dp_lane_mapping; ++ phy_mode = PHY_MODE_DP; ++ } else if (mhdp->connector_type == DRM_MODE_CONNECTOR_HDMIA) { ++ mhdp->lane_mapping = mhdp->plat_data->hdmi_lane_mapping; ++ phy_mode = PHY_MODE_HDMI; ++ } ++ ++ dev_set_drvdata(dev, mhdp); ++ ++ /* init base struct for access mhdp mailbox */ ++ mhdp->base.dev = mhdp->dev; ++ mhdp->base.regs = mhdp->regs; ++ mhdp->base.mbox_mutex = &mhdp->mbox_mutex; ++ ++ if (mhdp->connector_type == DRM_MODE_CONNECTOR_DisplayPort) { ++ drm_dp_aux_init(&mhdp->dp.aux); ++ mhdp->dp.aux.name = "mhdp8501_dp_aux"; ++ mhdp->dp.aux.dev = dev; ++ mhdp->dp.aux.transfer = cdns_dp_aux_transfer; ++ } ++ ++ /* Enable APB clock */ ++ mhdp->apb_clk = devm_clk_get(dev, NULL); ++ if (IS_ERR(mhdp->apb_clk)) ++ return dev_err_probe(dev, PTR_ERR(mhdp->apb_clk), ++ "couldn't get apb clk\n"); ++ ++ clk_prepare_enable(mhdp->apb_clk); ++ ++ /* ++ * Wait for the KEEP_ALIVE "message" on the first 8 bits. ++ * Updated each sched "tick" (~2ms) ++ */ ++ ret = readl_poll_timeout(mhdp->regs + KEEP_ALIVE, reg, ++ reg & CDNS_KEEP_ALIVE_MASK, 500, ++ CDNS_KEEP_ALIVE_TIMEOUT); ++ if (ret) { ++ dev_err(dev, "device didn't give any life sign: reg %d\n", reg); ++ goto clk_disable; ++ } ++ ++ /* Mailbox protect for HDMI PHY access */ ++ mutex_lock(&mhdp->mbox_mutex); ++ ret = phy_init(mhdp->phy); ++ mutex_unlock(&mhdp->mbox_mutex); ++ if (ret) { ++ dev_err(dev, "Failed to initialize PHY: %d\n", ret); ++ goto clk_disable; ++ } ++ ++ /* Mailbox protect for HDMI PHY access */ ++ mutex_lock(&mhdp->mbox_mutex); ++ ret = phy_set_mode(mhdp->phy, phy_mode); ++ mutex_unlock(&mhdp->mbox_mutex); ++ if (ret) { ++ dev_err(dev, "Failed to configure PHY: %d\n", ret); ++ goto clk_disable; ++ } ++ ++ /* Enable cable hotplug detect */ ++ if (cdns_mhdp8501_read_hpd(mhdp)) ++ enable_irq(mhdp->irq[IRQ_OUT]); ++ else ++ enable_irq(mhdp->irq[IRQ_IN]); ++ ++ cdns_mhdp8501_add_bridge(mhdp); ++ ++ return 0; ++ ++clk_disable: ++ clk_disable_unprepare(mhdp->apb_clk); ++ ++ return -EINVAL; ++} ++ ++static void cdns_mhdp8501_remove(struct platform_device *pdev) ++{ ++ struct cdns_mhdp8501_device *mhdp = platform_get_drvdata(pdev); ++ ++ if (mhdp->connector_type == DRM_MODE_CONNECTOR_DisplayPort) ++ cdns_dp_aux_destroy(mhdp); ++ ++ drm_bridge_remove(&mhdp->bridge); ++ clk_disable_unprepare(mhdp->apb_clk); ++} ++ ++static struct mhdp8501_plat_data imx8mq_mhdp_drv_data = { ++ .hdmi_lane_mapping = LANE_MAPPING_FLIPPED, ++ .dp_lane_mapping = LANE_MAPPING_IMX8MQ_DP, ++}; ++ ++static const struct of_device_id cdns_mhdp8501_dt_ids[] = { ++ { .compatible = "fsl,imx8mq-mhdp8501", ++ .data = &imx8mq_mhdp_drv_data ++ }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, cdns_mhdp8501_dt_ids); ++ ++static struct platform_driver cdns_mhdp8501_driver = { ++ .probe = cdns_mhdp8501_probe, ++ .remove = cdns_mhdp8501_remove, ++ .driver = { ++ .name = "cdns-mhdp8501", ++ .of_match_table = cdns_mhdp8501_dt_ids, ++ }, ++}; ++ ++module_platform_driver(cdns_mhdp8501_driver); ++ ++MODULE_AUTHOR("Sandor Yu "); ++MODULE_DESCRIPTION("Cadence MHDP8501 bridge driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8501-core.h b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8501-core.h +new file mode 100644 +index 000000000000..593071f36995 +--- /dev/null ++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8501-core.h +@@ -0,0 +1,367 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Cadence MHDP 8501 Common head file ++ * ++ * Copyright (C) 2019-2024 NXP Semiconductor, Inc. ++ * ++ */ ++ ++#ifndef _CDNS_MHDP8501_CORE_H_ ++#define _CDNS_MHDP8501_CORE_H_ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#define ADDR_IMEM 0x10000 ++#define ADDR_DMEM 0x20000 ++ ++/* APB CFG addr */ ++#define APB_CTRL 0 ++#define XT_INT_CTRL 0x04 ++#define MAILBOX_FULL_ADDR 0x08 ++#define MAILBOX_EMPTY_ADDR 0x0c ++#define MAILBOX0_WR_DATA 0x10 ++#define MAILBOX0_RD_DATA 0x14 ++#define KEEP_ALIVE 0x18 ++#define VER_L 0x1c ++#define VER_H 0x20 ++#define VER_LIB_L_ADDR 0x24 ++#define VER_LIB_H_ADDR 0x28 ++#define SW_DEBUG_L 0x2c ++#define SW_DEBUG_H 0x30 ++#define MAILBOX_INT_MASK 0x34 ++#define MAILBOX_INT_STATUS 0x38 ++#define SW_CLK_L 0x3c ++#define SW_CLK_H 0x40 ++#define SW_EVENTS0 0x44 ++#define SW_EVENTS1 0x48 ++#define SW_EVENTS2 0x4c ++#define SW_EVENTS3 0x50 ++#define XT_OCD_CTRL 0x60 ++#define APB_INT_MASK 0x6c ++#define APB_STATUS_MASK 0x70 ++ ++/* Source phy comp */ ++#define PHY_DATA_SEL 0x0818 ++#define LANES_CONFIG 0x0814 ++ ++/* Source CAR Addr */ ++#define SOURCE_HDTX_CAR 0x0900 ++#define SOURCE_DPTX_CAR 0x0904 ++#define SOURCE_PHY_CAR 0x0908 ++#define SOURCE_CEC_CAR 0x090c ++#define SOURCE_CBUS_CAR 0x0910 ++#define SOURCE_PKT_CAR 0x0918 ++#define SOURCE_AIF_CAR 0x091c ++#define SOURCE_CIPHER_CAR 0x0920 ++#define SOURCE_CRYPTO_CAR 0x0924 ++ ++/* clock meters addr */ ++#define CM_CTRL 0x0a00 ++#define CM_I2S_CTRL 0x0a04 ++#define CM_SPDIF_CTRL 0x0a08 ++#define CM_VID_CTRL 0x0a0c ++#define CM_LANE_CTRL 0x0a10 ++#define I2S_NM_STABLE 0x0a14 ++#define I2S_NCTS_STABLE 0x0a18 ++#define SPDIF_NM_STABLE 0x0a1c ++#define SPDIF_NCTS_STABLE 0x0a20 ++#define NMVID_MEAS_STABLE 0x0a24 ++#define I2S_MEAS 0x0a40 ++#define SPDIF_MEAS 0x0a80 ++#define NMVID_MEAS 0x0ac0 ++ ++/* source vif addr */ ++#define BND_HSYNC2VSYNC 0x0b00 ++#define HSYNC2VSYNC_F1_L1 0x0b04 ++#define HSYNC2VSYNC_STATUS 0x0b0c ++#define HSYNC2VSYNC_POL_CTRL 0x0b10 ++ ++/* MHDP TX_top_comp */ ++#define SCHEDULER_H_SIZE 0x1000 ++#define SCHEDULER_V_SIZE 0x1004 ++#define HDTX_SIGNAL_FRONT_WIDTH 0x100c ++#define HDTX_SIGNAL_SYNC_WIDTH 0x1010 ++#define HDTX_SIGNAL_BACK_WIDTH 0x1014 ++#define HDTX_CONTROLLER 0x1018 ++#define HDTX_HPD 0x1020 ++#define HDTX_CLOCK_REG_0 0x1024 ++#define HDTX_CLOCK_REG_1 0x1028 ++ ++/* DPTX hpd addr */ ++#define HPD_IRQ_DET_MIN_TIMER 0x2100 ++#define HPD_IRQ_DET_MAX_TIMER 0x2104 ++#define HPD_UNPLGED_DET_MIN_TIMER 0x2108 ++#define HPD_STABLE_TIMER 0x210c ++#define HPD_FILTER_TIMER 0x2110 ++#define HPD_EVENT_MASK 0x211c ++#define HPD_EVENT_DET 0x2120 ++ ++/* DPTX framer addr */ ++#define DP_FRAMER_GLOBAL_CONFIG 0x2200 ++#define DP_SW_RESET 0x2204 ++#define DP_FRAMER_TU 0x2208 ++#define DP_FRAMER_PXL_REPR 0x220c ++#define DP_FRAMER_SP 0x2210 ++#define AUDIO_PACK_CONTROL 0x2214 ++#define DP_VC_TABLE(x) (0x2218 + ((x) << 2)) ++#define DP_VB_ID 0x2258 ++#define DP_MTPH_LVP_CONTROL 0x225c ++#define DP_MTPH_SYMBOL_VALUES 0x2260 ++#define DP_MTPH_ECF_CONTROL 0x2264 ++#define DP_MTPH_ACT_CONTROL 0x2268 ++#define DP_MTPH_STATUS 0x226c ++#define DP_INTERRUPT_SOURCE 0x2270 ++#define DP_INTERRUPT_MASK 0x2274 ++#define DP_FRONT_BACK_PORCH 0x2278 ++#define DP_BYTE_COUNT 0x227c ++ ++/* DPTX stream addr */ ++#define MSA_HORIZONTAL_0 0x2280 ++#define MSA_HORIZONTAL_1 0x2284 ++#define MSA_VERTICAL_0 0x2288 ++#define MSA_VERTICAL_1 0x228c ++#define MSA_MISC 0x2290 ++#define STREAM_CONFIG 0x2294 ++#define AUDIO_PACK_STATUS 0x2298 ++#define VIF_STATUS 0x229c ++#define PCK_STUFF_STATUS_0 0x22a0 ++#define PCK_STUFF_STATUS_1 0x22a4 ++#define INFO_PACK_STATUS 0x22a8 ++#define RATE_GOVERNOR_STATUS 0x22ac ++#define DP_HORIZONTAL 0x22b0 ++#define DP_VERTICAL_0 0x22b4 ++#define DP_VERTICAL_1 0x22b8 ++#define DP_BLOCK_SDP 0x22bc ++ ++/* DPTX glbl addr */ ++#define DPTX_LANE_EN 0x2300 ++#define DPTX_ENHNCD 0x2304 ++#define DPTX_INT_MASK 0x2308 ++#define DPTX_INT_STATUS 0x230c ++ ++/* DP AUX Addr */ ++#define DP_AUX_HOST_CONTROL 0x2800 ++#define DP_AUX_INTERRUPT_SOURCE 0x2804 ++#define DP_AUX_INTERRUPT_MASK 0x2808 ++#define DP_AUX_SWAP_INVERSION_CONTROL 0x280c ++#define DP_AUX_SEND_NACK_TRANSACTION 0x2810 ++#define DP_AUX_CLEAR_RX 0x2814 ++#define DP_AUX_CLEAR_TX 0x2818 ++#define DP_AUX_TIMER_STOP 0x281c ++#define DP_AUX_TIMER_CLEAR 0x2820 ++#define DP_AUX_RESET_SW 0x2824 ++#define DP_AUX_DIVIDE_2M 0x2828 ++#define DP_AUX_TX_PREACHARGE_LENGTH 0x282c ++#define DP_AUX_FREQUENCY_1M_MAX 0x2830 ++#define DP_AUX_FREQUENCY_1M_MIN 0x2834 ++#define DP_AUX_RX_PRE_MIN 0x2838 ++#define DP_AUX_RX_PRE_MAX 0x283c ++#define DP_AUX_TIMER_PRESET 0x2840 ++#define DP_AUX_NACK_FORMAT 0x2844 ++#define DP_AUX_TX_DATA 0x2848 ++#define DP_AUX_RX_DATA 0x284c ++#define DP_AUX_TX_STATUS 0x2850 ++#define DP_AUX_RX_STATUS 0x2854 ++#define DP_AUX_RX_CYCLE_COUNTER 0x2858 ++#define DP_AUX_MAIN_STATES 0x285c ++#define DP_AUX_MAIN_TIMER 0x2860 ++#define DP_AUX_AFE_OUT 0x2864 ++ ++/* source pif addr */ ++#define SOURCE_PIF_WR_ADDR 0x30800 ++#define SOURCE_PIF_WR_REQ 0x30804 ++#define SOURCE_PIF_RD_ADDR 0x30808 ++#define SOURCE_PIF_RD_REQ 0x3080c ++#define SOURCE_PIF_DATA_WR 0x30810 ++#define SOURCE_PIF_DATA_RD 0x30814 ++#define SOURCE_PIF_FIFO1_FLUSH 0x30818 ++#define SOURCE_PIF_FIFO2_FLUSH 0x3081c ++#define SOURCE_PIF_STATUS 0x30820 ++#define SOURCE_PIF_INTERRUPT_SOURCE 0x30824 ++#define SOURCE_PIF_INTERRUPT_MASK 0x30828 ++#define SOURCE_PIF_PKT_ALLOC_REG 0x3082c ++#define SOURCE_PIF_PKT_ALLOC_WR_EN 0x30830 ++#define SOURCE_PIF_SW_RESET 0x30834 ++ ++#define LINK_TRAINING_NOT_ACTIV 0 ++#define LINK_TRAINING_RUN 1 ++#define LINK_TRAINING_RESTART 2 ++ ++#define CONTROL_VIDEO_IDLE 0 ++#define CONTROL_VIDEO_VALID 1 ++ ++#define INTERLACE_FMT_DET BIT(12) ++#define VIF_BYPASS_INTERLACE BIT(13) ++#define TU_CNT_RST_EN BIT(15) ++#define INTERLACE_DTCT_WIN 0x20 ++ ++#define DP_FRAMER_SP_INTERLACE_EN BIT(2) ++#define DP_FRAMER_SP_HSP BIT(1) ++#define DP_FRAMER_SP_VSP BIT(0) ++ ++/* Capability */ ++#define AUX_HOST_INVERT 3 ++#define FAST_LT_SUPPORT 1 ++#define FAST_LT_NOT_SUPPORT 0 ++#define LANE_MAPPING_NORMAL 0x1b ++#define LANE_MAPPING_FLIPPED 0xe4 ++#define LANE_MAPPING_IMX8MQ_DP 0xc6 ++#define ENHANCED 1 ++#define SCRAMBLER_EN BIT(4) ++ ++#define FULL_LT_STARTED BIT(0) ++#define FASE_LT_STARTED BIT(1) ++#define CLK_RECOVERY_FINISHED BIT(2) ++#define EQ_PHASE_FINISHED BIT(3) ++#define FASE_LT_START_FINISHED BIT(4) ++#define CLK_RECOVERY_FAILED BIT(5) ++#define EQ_PHASE_FAILED BIT(6) ++#define FASE_LT_FAILED BIT(7) ++ ++#define TU_SIZE 30 ++#define CDNS_DP_MAX_LINK_RATE 540000 ++ ++#define F_HDMI_ENCODING(x) (((x) & ((1 << 2) - 1)) << 16) ++#define F_VIF_DATA_WIDTH(x) (((x) & ((1 << 2) - 1)) << 2) ++#define F_HDMI_MODE(x) (((x) & ((1 << 2) - 1)) << 0) ++#define F_GCP_EN(x) (((x) & ((1 << 1) - 1)) << 12) ++#define F_DATA_EN(x) (((x) & ((1 << 1) - 1)) << 15) ++#define F_CLEAR_AVMUTE(x) (((x) & ((1 << 1) - 1)) << 14) ++#define F_HDMI2_PREAMBLE_EN(x) (((x) & ((1 << 1) - 1)) << 18) ++#define F_PIC_3D(x) (((x) & ((1 << 4) - 1)) << 7) ++#define F_BCH_EN(x) (((x) & ((1 << 1) - 1)) << 11) ++#define F_SOURCE_PHY_MHDP_SEL(x) (((x) & ((1 << 2) - 1)) << 3) ++#define F_HPD_VALID_WIDTH(x) (((x) & ((1 << 12) - 1)) << 0) ++#define F_HPD_GLITCH_WIDTH(x) (((x) & ((1 << 8) - 1)) << 12) ++#define F_HDMI2_CTRL_IL_MODE(x) (((x) & ((1 << 1) - 1)) << 19) ++#define F_SOURCE_PHY_LANE0_SWAP(x) (((x) & ((1 << 2) - 1)) << 0) ++#define F_SOURCE_PHY_LANE1_SWAP(x) (((x) & ((1 << 2) - 1)) << 2) ++#define F_SOURCE_PHY_LANE2_SWAP(x) (((x) & ((1 << 2) - 1)) << 4) ++#define F_SOURCE_PHY_LANE3_SWAP(x) (((x) & ((1 << 2) - 1)) << 6) ++#define F_SOURCE_PHY_COMB_BYPASS(x) (((x) & ((1 << 1) - 1)) << 21) ++#define F_SOURCE_PHY_20_10(x) (((x) & ((1 << 1) - 1)) << 22) ++#define F_PKT_ALLOC_ADDRESS(x) (((x) & ((1 << 4) - 1)) << 0) ++#define F_ACTIVE_IDLE_TYPE(x) (((x) & ((1 << 1) - 1)) << 17) ++#define F_FIFO1_FLUSH(x) (((x) & ((1 << 1) - 1)) << 0) ++#define F_PKT_ALLOC_WR_EN(x) (((x) & ((1 << 1) - 1)) << 0) ++#define F_DATA_WR(x) (x) ++#define F_WR_ADDR(x) (((x) & ((1 << 4) - 1)) << 0) ++#define F_HOST_WR(x) (((x) & ((1 << 1) - 1)) << 0) ++#define F_TYPE_VALID(x) (((x) & ((1 << 1) - 1)) << 16) ++#define F_PACKET_TYPE(x) (((x) & ((1 << 8) - 1)) << 8) ++ ++/* Reference cycles when using lane clock as reference */ ++#define LANE_REF_CYC 0x8000 ++ ++/* HPD Debounce */ ++#define HOTPLUG_DEBOUNCE_MS 200 ++ ++/* HPD IRQ Index */ ++#define IRQ_IN 0 ++#define IRQ_OUT 1 ++#define IRQ_NUM 2 ++ ++/* FW check alive timeout */ ++#define CDNS_KEEP_ALIVE_TIMEOUT 2000 ++#define CDNS_KEEP_ALIVE_MASK GENMASK(7, 0) ++ ++enum voltage_swing_level { ++ VOLTAGE_LEVEL_0, ++ VOLTAGE_LEVEL_1, ++ VOLTAGE_LEVEL_2, ++ VOLTAGE_LEVEL_3, ++}; ++ ++enum pre_emphasis_level { ++ PRE_EMPHASIS_LEVEL_0, ++ PRE_EMPHASIS_LEVEL_1, ++ PRE_EMPHASIS_LEVEL_2, ++ PRE_EMPHASIS_LEVEL_3, ++}; ++ ++enum pattern_set { ++ PTS1 = BIT(0), ++ PTS2 = BIT(1), ++ PTS3 = BIT(2), ++ PTS4 = BIT(3), ++ DP_NONE = BIT(4) ++}; ++ ++enum vic_color_depth { ++ BCS_6 = 0x1, ++ BCS_8 = 0x2, ++ BCS_10 = 0x4, ++ BCS_12 = 0x8, ++ BCS_16 = 0x10, ++}; ++ ++enum vic_bt_type { ++ BT_601 = 0x0, ++ BT_709 = 0x1, ++}; ++ ++enum { ++ MODE_DVI, ++ MODE_HDMI_1_4, ++ MODE_HDMI_2_0, ++}; ++ ++struct video_info { ++ int bpc; ++ int color_fmt; ++}; ++ ++struct mhdp8501_plat_data { ++ int hdmi_lane_mapping; ++ int dp_lane_mapping; ++}; ++ ++struct cdns_mhdp8501_device { ++ struct cdns_mhdp_base base; ++ ++ struct device *dev; ++ void __iomem *regs; ++ struct drm_connector *curr_conn; ++ struct drm_bridge bridge; ++ struct clk *apb_clk; ++ struct phy *phy; ++ ++ struct video_info video_info; ++ struct drm_display_mode mode; ++ ++ int irq[IRQ_NUM]; ++ struct delayed_work hotplug_work; ++ int connector_type; ++ u32 lane_mapping; ++ ++ /* protect mailbox communications with the firmware */ ++ struct mutex mbox_mutex; ++ ++ const struct mhdp8501_plat_data *plat_data; ++ ++ union { ++ struct _dp_data { ++ u32 rate; ++ u8 num_lanes; ++ struct drm_dp_aux aux; ++ u8 dpcd[DP_RECEIVER_CAP_SIZE]; ++ } dp; ++ struct _hdmi_data { ++ u32 hdmi_type; ++ unsigned long long char_rate; ++ } hdmi; ++ }; ++}; ++ ++extern const struct drm_bridge_funcs cdns_dp_bridge_funcs; ++extern const struct drm_bridge_funcs cdns_hdmi_bridge_funcs; ++ ++ssize_t cdns_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg); ++enum drm_connector_status cdns_mhdp8501_detect(struct cdns_mhdp8501_device *mhdp); ++int cdns_dp_aux_destroy(struct cdns_mhdp8501_device *mhdp); ++ ++#endif +diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8501-dp.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8501-dp.c +new file mode 100644 +index 000000000000..d8cc31daf322 +--- /dev/null ++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8501-dp.c +@@ -0,0 +1,700 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Cadence MHDP8501 DisplayPort(DP) bridge driver ++ * ++ * Copyright (C) 2019-2024 NXP Semiconductor, Inc. ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++ ++#include "cdns-mhdp8501-core.h" ++ ++#define LINK_TRAINING_TIMEOUT_MS 500 ++#define LINK_TRAINING_RETRY_MS 20 ++ ++ssize_t cdns_dp_aux_transfer(struct drm_dp_aux *aux, ++ struct drm_dp_aux_msg *msg) ++{ ++ struct cdns_mhdp8501_device *mhdp = dev_get_drvdata(aux->dev); ++ bool native = msg->request & (DP_AUX_NATIVE_WRITE & DP_AUX_NATIVE_READ); ++ int ret; ++ ++ /* Ignore address only message */ ++ if (!msg->size || !msg->buffer) { ++ msg->reply = native ? ++ DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK; ++ return msg->size; ++ } ++ ++ if (!native) { ++ dev_err(mhdp->dev, "%s: only native messages supported\n", __func__); ++ return -EINVAL; ++ } ++ ++ /* msg sanity check */ ++ if (msg->size > DP_AUX_MAX_PAYLOAD_BYTES) { ++ dev_err(mhdp->dev, "%s: invalid msg: size(%zu), request(%x)\n", ++ __func__, msg->size, (unsigned int)msg->request); ++ return -EINVAL; ++ } ++ ++ if (msg->request == DP_AUX_NATIVE_WRITE) { ++ const u8 *buf = msg->buffer; ++ int i; ++ ++ for (i = 0; i < msg->size; ++i) { ++ ret = cdns_mhdp_dpcd_write(&mhdp->base, ++ msg->address + i, buf[i]); ++ if (ret < 0) { ++ dev_err(mhdp->dev, "Failed to write DPCD\n"); ++ return ret; ++ } ++ } ++ msg->reply = DP_AUX_NATIVE_REPLY_ACK; ++ return msg->size; ++ } ++ ++ if (msg->request == DP_AUX_NATIVE_READ) { ++ ret = cdns_mhdp_dpcd_read(&mhdp->base, msg->address, ++ msg->buffer, msg->size); ++ if (ret < 0) ++ return ret; ++ msg->reply = DP_AUX_NATIVE_REPLY_ACK; ++ return msg->size; ++ } ++ return 0; ++} ++ ++int cdns_dp_aux_destroy(struct cdns_mhdp8501_device *mhdp) ++{ ++ drm_dp_aux_unregister(&mhdp->dp.aux); ++ ++ return 0; ++} ++ ++static int cdns_dp_get_msa_misc(struct video_info *video) ++{ ++ u32 msa_misc; ++ u8 color_space = 0; ++ u8 bpc = 0; ++ ++ switch (video->color_fmt) { ++ /* set YUV default color space conversion to BT601 */ ++ case DRM_COLOR_FORMAT_YCBCR444: ++ color_space = 6 + BT_601 * 8; ++ break; ++ case DRM_COLOR_FORMAT_YCBCR422: ++ color_space = 5 + BT_601 * 8; ++ break; ++ case DRM_COLOR_FORMAT_YCBCR420: ++ color_space = 5; ++ break; ++ case DRM_COLOR_FORMAT_RGB444: ++ default: ++ color_space = 0; ++ break; ++ }; ++ ++ switch (video->bpc) { ++ case 6: ++ bpc = 0; ++ break; ++ case 10: ++ bpc = 2; ++ break; ++ case 12: ++ bpc = 3; ++ break; ++ case 16: ++ bpc = 4; ++ break; ++ case 8: ++ default: ++ bpc = 1; ++ break; ++ }; ++ ++ msa_misc = (bpc << 5) | (color_space << 1); ++ ++ return msa_misc; ++} ++ ++static int cdns_dp_config_video(struct cdns_mhdp8501_device *mhdp) ++{ ++ struct video_info *video = &mhdp->video_info; ++ struct drm_display_mode *mode = &mhdp->mode; ++ bool h_sync_polarity, v_sync_polarity; ++ u64 symbol; ++ u32 val, link_rate, rem; ++ u8 bit_per_pix, tu_size_reg = TU_SIZE; ++ int ret; ++ ++ bit_per_pix = (video->color_fmt == DRM_COLOR_FORMAT_YCBCR422) ? ++ (video->bpc * 2) : (video->bpc * 3); ++ ++ link_rate = mhdp->dp.rate / 1000; ++ ++ ret = cdns_mhdp_reg_write(&mhdp->base, BND_HSYNC2VSYNC, VIF_BYPASS_INTERLACE); ++ if (ret) ++ goto err_config_video; ++ ++ ret = cdns_mhdp_reg_write(&mhdp->base, HSYNC2VSYNC_POL_CTRL, 0); ++ if (ret) ++ goto err_config_video; ++ ++ /* ++ * get a best tu_size and valid symbol: ++ * 1. chose Lclk freq(162Mhz, 270Mhz, 540Mhz), set TU to 32 ++ * 2. calculate VS(valid symbol) = TU * Pclk * Bpp / (Lclk * Lanes) ++ * 3. if VS > *.85 or VS < *.1 or VS < 2 or TU < VS + 4, then set ++ * TU += 2 and repeat 2nd step. ++ */ ++ do { ++ tu_size_reg += 2; ++ symbol = tu_size_reg * mode->clock * bit_per_pix; ++ do_div(symbol, mhdp->dp.num_lanes * link_rate * 8); ++ rem = do_div(symbol, 1000); ++ if (tu_size_reg > 64) { ++ ret = -EINVAL; ++ dev_err(mhdp->dev, "tu error, clk:%d, lanes:%d, rate:%d\n", ++ mode->clock, mhdp->dp.num_lanes, link_rate); ++ goto err_config_video; ++ } ++ } while ((symbol <= 1) || (tu_size_reg - symbol < 4) || ++ (rem > 850) || (rem < 100)); ++ ++ val = symbol + (tu_size_reg << 8); ++ val |= TU_CNT_RST_EN; ++ ret = cdns_mhdp_reg_write(&mhdp->base, DP_FRAMER_TU, val); ++ if (ret) ++ goto err_config_video; ++ ++ /* set the FIFO Buffer size */ ++ val = div_u64(mode->clock * (symbol + 1), 1000) + link_rate; ++ val /= (mhdp->dp.num_lanes * link_rate); ++ val = div_u64(8 * (symbol + 1), bit_per_pix) - val; ++ val += 2; ++ ret = cdns_mhdp_reg_write(&mhdp->base, DP_VC_TABLE(15), val); ++ ++ switch (video->bpc) { ++ case 6: ++ val = BCS_6; ++ break; ++ case 10: ++ val = BCS_10; ++ break; ++ case 12: ++ val = BCS_12; ++ break; ++ case 16: ++ val = BCS_16; ++ break; ++ case 8: ++ default: ++ val = BCS_8; ++ break; ++ }; ++ ++ val += video->color_fmt << 8; ++ ret = cdns_mhdp_reg_write(&mhdp->base, DP_FRAMER_PXL_REPR, val); ++ if (ret) ++ goto err_config_video; ++ ++ v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC); ++ h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC); ++ ++ val = h_sync_polarity ? DP_FRAMER_SP_HSP : 0; ++ val |= v_sync_polarity ? DP_FRAMER_SP_VSP : 0; ++ ret = cdns_mhdp_reg_write(&mhdp->base, DP_FRAMER_SP, val); ++ if (ret) ++ goto err_config_video; ++ ++ val = (mode->hsync_start - mode->hdisplay) << 16; ++ val |= mode->htotal - mode->hsync_end; ++ ret = cdns_mhdp_reg_write(&mhdp->base, DP_FRONT_BACK_PORCH, val); ++ if (ret) ++ goto err_config_video; ++ ++ val = mode->hdisplay * bit_per_pix / 8; ++ ret = cdns_mhdp_reg_write(&mhdp->base, DP_BYTE_COUNT, val); ++ if (ret) ++ goto err_config_video; ++ ++ val = mode->htotal | ((mode->htotal - mode->hsync_start) << 16); ++ ret = cdns_mhdp_reg_write(&mhdp->base, MSA_HORIZONTAL_0, val); ++ if (ret) ++ goto err_config_video; ++ ++ val = mode->hsync_end - mode->hsync_start; ++ val |= (mode->hdisplay << 16) | (h_sync_polarity << 15); ++ ret = cdns_mhdp_reg_write(&mhdp->base, MSA_HORIZONTAL_1, val); ++ if (ret) ++ goto err_config_video; ++ ++ val = mode->vtotal; ++ val |= (mode->vtotal - mode->vsync_start) << 16; ++ ret = cdns_mhdp_reg_write(&mhdp->base, MSA_VERTICAL_0, val); ++ if (ret) ++ goto err_config_video; ++ ++ val = mode->vsync_end - mode->vsync_start; ++ val |= (mode->vdisplay << 16) | (v_sync_polarity << 15); ++ ret = cdns_mhdp_reg_write(&mhdp->base, MSA_VERTICAL_1, val); ++ if (ret) ++ goto err_config_video; ++ ++ val = cdns_dp_get_msa_misc(video); ++ ret = cdns_mhdp_reg_write(&mhdp->base, MSA_MISC, val); ++ if (ret) ++ goto err_config_video; ++ ++ ret = cdns_mhdp_reg_write(&mhdp->base, STREAM_CONFIG, 1); ++ if (ret) ++ goto err_config_video; ++ ++ val = mode->hsync_end - mode->hsync_start; ++ val |= mode->hdisplay << 16; ++ ret = cdns_mhdp_reg_write(&mhdp->base, DP_HORIZONTAL, val); ++ if (ret) ++ goto err_config_video; ++ ++ val = mode->vdisplay; ++ val |= (mode->vtotal - mode->vsync_start) << 16; ++ ret = cdns_mhdp_reg_write(&mhdp->base, DP_VERTICAL_0, val); ++ if (ret) ++ goto err_config_video; ++ ++ val = mode->vtotal; ++ ret = cdns_mhdp_reg_write(&mhdp->base, DP_VERTICAL_1, val); ++ if (ret) ++ goto err_config_video; ++ ++ ret = cdns_mhdp_dp_reg_write_bit(&mhdp->base, DP_VB_ID, 2, 1, 0); ++ ++err_config_video: ++ if (ret) ++ dev_err(mhdp->dev, "config video failed: %d\n", ret); ++ return ret; ++} ++ ++static void cdns_dp_pixel_clk_reset(struct cdns_mhdp8501_device *mhdp) ++{ ++ u32 val; ++ ++ /* reset pixel clk */ ++ cdns_mhdp_reg_read(&mhdp->base, SOURCE_HDTX_CAR, &val); ++ cdns_mhdp_reg_write(&mhdp->base, SOURCE_HDTX_CAR, val & 0xFD); ++ cdns_mhdp_reg_write(&mhdp->base, SOURCE_HDTX_CAR, val); ++} ++ ++static int cdns_dp_set_video_status(struct cdns_mhdp8501_device *mhdp, int active) ++{ ++ u8 msg; ++ int ret; ++ ++ msg = !!active; ++ ++ mutex_lock(&mhdp->mbox_mutex); ++ ++ ret = cdns_mhdp_mailbox_send(&mhdp->base, MB_MODULE_ID_DP_TX, DPTX_SET_VIDEO, ++ sizeof(msg), &msg); ++ if (ret) ++ dev_err(mhdp->dev, "set video status failed: %d\n", ret); ++ ++ mutex_unlock(&mhdp->mbox_mutex); ++ ++ return ret; ++} ++ ++static int cdns_dp_training_start(struct cdns_mhdp8501_device *mhdp) ++{ ++ unsigned long timeout; ++ u8 msg, event[2]; ++ int ret; ++ ++ msg = LINK_TRAINING_RUN; ++ ++ mutex_lock(&mhdp->mbox_mutex); ++ ++ /* start training */ ++ ret = cdns_mhdp_mailbox_send(&mhdp->base, MB_MODULE_ID_DP_TX, ++ DPTX_TRAINING_CONTROL, sizeof(msg), &msg); ++ if (ret) ++ goto err_training_start; ++ ++ timeout = jiffies + msecs_to_jiffies(LINK_TRAINING_TIMEOUT_MS); ++ while (time_before(jiffies, timeout)) { ++ msleep(LINK_TRAINING_RETRY_MS); ++ ret = cdns_mhdp_mailbox_send(&mhdp->base, MB_MODULE_ID_DP_TX, ++ DPTX_READ_EVENT, 0, NULL); ++ if (ret) ++ goto err_training_start; ++ ++ ret = cdns_mhdp_mailbox_recv_header(&mhdp->base, MB_MODULE_ID_DP_TX, ++ DPTX_READ_EVENT, sizeof(event)); ++ if (ret) ++ goto err_training_start; ++ ++ ret = cdns_mhdp_mailbox_recv_data(&mhdp->base, event, sizeof(event)); ++ if (ret) ++ goto err_training_start; ++ ++ if (event[1] & CLK_RECOVERY_FAILED) { ++ dev_err(mhdp->dev, "clock recovery failed\n"); ++ } else if (event[1] & EQ_PHASE_FINISHED) { ++ mutex_unlock(&mhdp->mbox_mutex); ++ return 0; ++ } ++ } ++ ++ ret = -ETIMEDOUT; ++ ++err_training_start: ++ mutex_unlock(&mhdp->mbox_mutex); ++ ++ dev_err(mhdp->dev, "training failed: %d\n", ret); ++ return ret; ++} ++ ++static int cdns_dp_get_training_status(struct cdns_mhdp8501_device *mhdp) ++{ ++ u8 status[13]; ++ int ret; ++ ++ mutex_lock(&mhdp->mbox_mutex); ++ ++ ret = cdns_mhdp_mailbox_send(&mhdp->base, MB_MODULE_ID_DP_TX, ++ DPTX_READ_LINK_STAT, 0, NULL); ++ if (ret) ++ goto err_get_training_status; ++ ++ ret = cdns_mhdp_mailbox_recv_header(&mhdp->base, MB_MODULE_ID_DP_TX, ++ DPTX_READ_LINK_STAT, ++ sizeof(status)); ++ if (ret) ++ goto err_get_training_status; ++ ++ ret = cdns_mhdp_mailbox_recv_data(&mhdp->base, status, sizeof(status)); ++ if (ret) ++ goto err_get_training_status; ++ ++ mhdp->dp.rate = drm_dp_bw_code_to_link_rate(status[0]); ++ mhdp->dp.num_lanes = status[1]; ++ ++err_get_training_status: ++ mutex_unlock(&mhdp->mbox_mutex); ++ ++ if (ret) ++ dev_err(mhdp->dev, "get training status failed: %d\n", ret); ++ return ret; ++} ++ ++static int cdns_dp_train_link(struct cdns_mhdp8501_device *mhdp) ++{ ++ int ret; ++ ++ ret = cdns_dp_training_start(mhdp); ++ if (ret) { ++ dev_err(mhdp->dev, "Failed to start training %d\n", ret); ++ return ret; ++ } ++ ++ ret = cdns_dp_get_training_status(mhdp); ++ if (ret) { ++ dev_err(mhdp->dev, "Failed to get training stat %d\n", ret); ++ return ret; ++ } ++ ++ dev_dbg(mhdp->dev, "rate:0x%x, lanes:%d\n", mhdp->dp.rate, ++ mhdp->dp.num_lanes); ++ return ret; ++} ++ ++static int cdns_dp_set_host_cap(struct cdns_mhdp8501_device *mhdp) ++{ ++ u8 msg[8]; ++ int ret; ++ ++ msg[0] = drm_dp_link_rate_to_bw_code(mhdp->dp.rate); ++ msg[1] = mhdp->dp.num_lanes | SCRAMBLER_EN; ++ msg[2] = VOLTAGE_LEVEL_2; ++ msg[3] = PRE_EMPHASIS_LEVEL_3; ++ msg[4] = PTS1 | PTS2 | PTS3 | PTS4; ++ msg[5] = FAST_LT_NOT_SUPPORT; ++ msg[6] = mhdp->lane_mapping; ++ msg[7] = ENHANCED; ++ ++ mutex_lock(&mhdp->mbox_mutex); ++ ++ ret = cdns_mhdp_mailbox_send(&mhdp->base, MB_MODULE_ID_DP_TX, ++ DPTX_SET_HOST_CAPABILITIES, ++ sizeof(msg), msg); ++ ++ mutex_unlock(&mhdp->mbox_mutex); ++ ++ if (ret) ++ dev_err(mhdp->dev, "set host cap failed: %d\n", ret); ++ ++ return ret; ++} ++ ++static int cdns_dp_get_edid_block(void *data, u8 *edid, ++ unsigned int block, size_t length) ++{ ++ struct cdns_mhdp8501_device *mhdp = data; ++ u8 msg[2], reg[2], i; ++ int ret; ++ ++ mutex_lock(&mhdp->mbox_mutex); ++ ++ for (i = 0; i < 4; i++) { ++ msg[0] = block / 2; ++ msg[1] = block % 2; ++ ++ ret = cdns_mhdp_mailbox_send(&mhdp->base, MB_MODULE_ID_DP_TX, ++ DPTX_GET_EDID, sizeof(msg), msg); ++ if (ret) ++ continue; ++ ++ ret = cdns_mhdp_mailbox_recv_header(&mhdp->base, MB_MODULE_ID_DP_TX, ++ DPTX_GET_EDID, ++ sizeof(reg) + length); ++ if (ret) ++ continue; ++ ++ ret = cdns_mhdp_mailbox_recv_data(&mhdp->base, reg, sizeof(reg)); ++ if (ret) ++ continue; ++ ++ ret = cdns_mhdp_mailbox_recv_data(&mhdp->base, edid, length); ++ if (ret) ++ continue; ++ ++ if (reg[0] == length && reg[1] == block / 2) ++ break; ++ } ++ ++ if (ret) ++ dev_err(mhdp->dev, "get block[%d] edid failed: %d\n", block, ret); ++ ++ mutex_unlock(&mhdp->mbox_mutex); ++ return ret; ++} ++ ++static void cdns_dp_mode_set(struct cdns_mhdp8501_device *mhdp) ++{ ++ union phy_configure_opts phy_cfg; ++ int ret; ++ ++ cdns_dp_pixel_clk_reset(mhdp); ++ ++ /* Get DP Caps */ ++ ret = drm_dp_dpcd_read(&mhdp->dp.aux, DP_DPCD_REV, mhdp->dp.dpcd, ++ DP_RECEIVER_CAP_SIZE); ++ if (ret < 0) { ++ dev_err(mhdp->dev, "Failed to get caps %d\n", ret); ++ return; ++ } ++ ++ mhdp->dp.rate = drm_dp_max_link_rate(mhdp->dp.dpcd); ++ mhdp->dp.num_lanes = drm_dp_max_lane_count(mhdp->dp.dpcd); ++ ++ /* check the max link rate */ ++ if (mhdp->dp.rate > CDNS_DP_MAX_LINK_RATE) ++ mhdp->dp.rate = CDNS_DP_MAX_LINK_RATE; ++ ++ phy_cfg.dp.lanes = mhdp->dp.num_lanes; ++ phy_cfg.dp.link_rate = mhdp->dp.rate; ++ phy_cfg.dp.set_lanes = false; ++ phy_cfg.dp.set_rate = false; ++ phy_cfg.dp.set_voltages = true; ++ ++ /* Mailbox protect for DP PHY access */ ++ mutex_lock(&mhdp->mbox_mutex); ++ ret = phy_configure(mhdp->phy, &phy_cfg); ++ mutex_unlock(&mhdp->mbox_mutex); ++ if (ret) { ++ dev_err(mhdp->dev, "%s: phy_configure() failed: %d\n", ++ __func__, ret); ++ return; ++ } ++ ++ /* Video off */ ++ ret = cdns_dp_set_video_status(mhdp, CONTROL_VIDEO_IDLE); ++ if (ret) { ++ dev_err(mhdp->dev, "Failed to valid video %d\n", ret); ++ return; ++ } ++ ++ /* Line swapping */ ++ cdns_mhdp_reg_write(&mhdp->base, LANES_CONFIG, 0x00400000 | mhdp->lane_mapping); ++ ++ /* Set DP host capability */ ++ ret = cdns_dp_set_host_cap(mhdp); ++ if (ret) { ++ dev_err(mhdp->dev, "Failed to set host cap %d\n", ret); ++ return; ++ } ++ ++ ret = cdns_mhdp_reg_write(&mhdp->base, DP_AUX_SWAP_INVERSION_CONTROL, ++ AUX_HOST_INVERT); ++ if (ret) { ++ dev_err(mhdp->dev, "Failed to set host invert %d\n", ret); ++ return; ++ } ++ ++ ret = cdns_dp_config_video(mhdp); ++ if (ret) ++ dev_err(mhdp->dev, "Failed to config video %d\n", ret); ++} ++ ++static int cdns_dp_bridge_attach(struct drm_bridge *bridge, ++ enum drm_bridge_attach_flags flags) ++{ ++ struct cdns_mhdp8501_device *mhdp = bridge->driver_private; ++ ++ if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) { ++ dev_err(mhdp->dev, "do not support creating a drm_connector\n"); ++ return -EINVAL; ++ } ++ ++ mhdp->dp.aux.drm_dev = bridge->dev; ++ ++ return drm_dp_aux_register(&mhdp->dp.aux); ++} ++ ++static enum drm_mode_status ++cdns_dp_bridge_mode_valid(struct drm_bridge *bridge, ++ const struct drm_display_info *info, ++ const struct drm_display_mode *mode) ++{ ++ enum drm_mode_status mode_status = MODE_OK; ++ ++ /* We don't support double-clocked modes */ ++ if (mode->flags & DRM_MODE_FLAG_DBLCLK || ++ mode->flags & DRM_MODE_FLAG_INTERLACE) ++ return MODE_BAD; ++ ++ /* MAX support pixel clock rate 594MHz */ ++ if (mode->clock > 594000) ++ return MODE_CLOCK_HIGH; ++ ++ if (mode->hdisplay > 3840) ++ return MODE_BAD_HVALUE; ++ ++ if (mode->vdisplay > 2160) ++ return MODE_BAD_VVALUE; ++ ++ return mode_status; ++} ++ ++static enum drm_connector_status ++cdns_dp_bridge_detect(struct drm_bridge *bridge) ++{ ++ struct cdns_mhdp8501_device *mhdp = bridge->driver_private; ++ ++ return cdns_mhdp8501_detect(mhdp); ++} ++ ++static const struct drm_edid ++*cdns_dp_bridge_edid_read(struct drm_bridge *bridge, ++ struct drm_connector *connector) ++{ ++ struct cdns_mhdp8501_device *mhdp = bridge->driver_private; ++ ++ return drm_edid_read_custom(connector, cdns_dp_get_edid_block, mhdp); ++} ++ ++static void cdns_dp_bridge_atomic_disable(struct drm_bridge *bridge, ++ struct drm_bridge_state *old_state) ++{ ++ struct cdns_mhdp8501_device *mhdp = bridge->driver_private; ++ ++ cdns_dp_set_video_status(mhdp, CONTROL_VIDEO_IDLE); ++ mhdp->curr_conn = NULL; ++ ++ /* Mailbox protect for DP PHY access */ ++ mutex_lock(&mhdp->mbox_mutex); ++ phy_power_off(mhdp->phy); ++ mutex_unlock(&mhdp->mbox_mutex); ++} ++ ++static void cdns_dp_bridge_atomic_enable(struct drm_bridge *bridge, ++ struct drm_bridge_state *old_state) ++{ ++ struct cdns_mhdp8501_device *mhdp = bridge->driver_private; ++ struct drm_atomic_state *state = old_state->base.state; ++ struct drm_connector *connector; ++ struct video_info *video = &mhdp->video_info; ++ struct drm_crtc_state *crtc_state; ++ struct drm_connector_state *conn_state; ++ const struct drm_display_mode *mode; ++ int ret; ++ ++ connector = drm_atomic_get_new_connector_for_encoder(state, ++ bridge->encoder); ++ if (WARN_ON(!connector)) ++ return; ++ ++ mhdp->curr_conn = connector; ++ ++ conn_state = drm_atomic_get_new_connector_state(state, connector); ++ if (WARN_ON(!conn_state)) ++ return; ++ ++ crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc); ++ if (WARN_ON(!crtc_state)) ++ return; ++ ++ mode = &crtc_state->adjusted_mode; ++ ++ switch (connector->display_info.bpc) { ++ case 10: ++ video->bpc = 10; ++ break; ++ case 6: ++ video->bpc = 6; ++ break; ++ default: ++ video->bpc = 8; ++ break; ++ } ++ ++ /* The only currently supported format */ ++ video->color_fmt = DRM_COLOR_FORMAT_RGB444; ++ ++ dev_dbg(mhdp->dev, "Mode: %dx%dp%d\n", ++ mode->hdisplay, mode->vdisplay, mode->clock); ++ memcpy(&mhdp->mode, mode, sizeof(struct drm_display_mode)); ++ ++ cdns_dp_mode_set(mhdp); ++ ++ /* Link trainning */ ++ ret = cdns_dp_train_link(mhdp); ++ if (ret) { ++ dev_err(mhdp->dev, "Failed link train %d\n", ret); ++ return; ++ } ++ ++ ret = cdns_dp_set_video_status(mhdp, CONTROL_VIDEO_VALID); ++ if (ret) { ++ dev_err(mhdp->dev, "Failed to valid video %d\n", ret); ++ return; ++ } ++} ++ ++const struct drm_bridge_funcs cdns_dp_bridge_funcs = { ++ .attach = cdns_dp_bridge_attach, ++ .detect = cdns_dp_bridge_detect, ++ .edid_read = cdns_dp_bridge_edid_read, ++ .mode_valid = cdns_dp_bridge_mode_valid, ++ .atomic_enable = cdns_dp_bridge_atomic_enable, ++ .atomic_disable = cdns_dp_bridge_atomic_disable, ++ .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, ++ .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, ++ .atomic_reset = drm_atomic_helper_bridge_reset, ++}; +diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8501-hdmi.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8501-hdmi.c +new file mode 100644 +index 000000000000..834ca9788a5f +--- /dev/null ++++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8501-hdmi.c +@@ -0,0 +1,595 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Cadence MHDP8501 HDMI bridge driver ++ * ++ * Copyright (C) 2019-2024 NXP Semiconductor, Inc. ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cdns-mhdp8501-core.h" ++ ++/** ++ * cdns_hdmi_config_infoframe() - fill the HDMI infoframe ++ * @mhdp: phandle to mhdp device. ++ * @entry_id: The packet memory address in which the data is written. ++ * @len: length of infoframe. ++ * @buf: point to InfoFrame Packet. ++ * @type: Packet Type of InfoFrame in HDMI Specification. ++ * ++ */ ++static void cdns_hdmi_config_infoframe(struct cdns_mhdp8501_device *mhdp, ++ u8 entry_id, u8 len, ++ const u8 *buf, u8 type) ++{ ++ u8 packet[32], packet_len = 32; ++ u32 packet32, len32; ++ u32 val, i; ++ ++ /* ++ * only support 32 bytes now ++ * packet[0] = 0 ++ * packet[1-3] = HB[0-2] InfoFrame Packet Header ++ * packet[4-31 = PB[0-27] InfoFrame Packet Contents ++ */ ++ if (len >= (packet_len - 1)) ++ return; ++ packet[0] = 0; ++ memcpy(packet + 1, buf, len); ++ ++ /* invalidate entry */ ++ val = F_ACTIVE_IDLE_TYPE(1) | F_PKT_ALLOC_ADDRESS(entry_id); ++ writel(val, mhdp->regs + SOURCE_PIF_PKT_ALLOC_REG); ++ writel(F_PKT_ALLOC_WR_EN(1), mhdp->regs + SOURCE_PIF_PKT_ALLOC_WR_EN); ++ ++ /* flush fifo 1 */ ++ writel(F_FIFO1_FLUSH(1), mhdp->regs + SOURCE_PIF_FIFO1_FLUSH); ++ ++ /* write packet into memory */ ++ len32 = packet_len / 4; ++ for (i = 0; i < len32; i++) { ++ packet32 = get_unaligned_le32(packet + 4 * i); ++ writel(F_DATA_WR(packet32), mhdp->regs + SOURCE_PIF_DATA_WR); ++ } ++ ++ /* write entry id */ ++ writel(F_WR_ADDR(entry_id), mhdp->regs + SOURCE_PIF_WR_ADDR); ++ ++ /* write request */ ++ writel(F_HOST_WR(1), mhdp->regs + SOURCE_PIF_WR_REQ); ++ ++ /* update entry */ ++ val = F_ACTIVE_IDLE_TYPE(1) | F_TYPE_VALID(1) | ++ F_PACKET_TYPE(type) | F_PKT_ALLOC_ADDRESS(entry_id); ++ writel(val, mhdp->regs + SOURCE_PIF_PKT_ALLOC_REG); ++ ++ writel(F_PKT_ALLOC_WR_EN(1), mhdp->regs + SOURCE_PIF_PKT_ALLOC_WR_EN); ++} ++ ++static int cdns_hdmi_get_edid_block(void *data, u8 *edid, ++ u32 block, size_t length) ++{ ++ struct cdns_mhdp8501_device *mhdp = data; ++ u8 msg[2], reg[5], i; ++ int ret; ++ ++ mutex_lock(&mhdp->mbox_mutex); ++ ++ for (i = 0; i < 4; i++) { ++ msg[0] = block / 2; ++ msg[1] = block % 2; ++ ++ ret = cdns_mhdp_mailbox_send(&mhdp->base, MB_MODULE_ID_HDMI_TX, HDMI_TX_EDID, ++ sizeof(msg), msg); ++ if (ret) ++ continue; ++ ++ ret = cdns_mhdp_mailbox_recv_header(&mhdp->base, MB_MODULE_ID_HDMI_TX, ++ HDMI_TX_EDID, sizeof(reg) + length); ++ if (ret) ++ continue; ++ ++ ret = cdns_mhdp_mailbox_recv_data(&mhdp->base, reg, sizeof(reg)); ++ if (ret) ++ continue; ++ ++ ret = cdns_mhdp_mailbox_recv_data(&mhdp->base, edid, length); ++ if (ret) ++ continue; ++ ++ if ((reg[3] << 8 | reg[4]) == length) ++ break; ++ } ++ ++ mutex_unlock(&mhdp->mbox_mutex); ++ ++ if (ret) ++ dev_err(mhdp->dev, "get block[%d] edid failed: %d\n", block, ret); ++ return ret; ++} ++ ++static int cdns_hdmi_scdc_write(struct cdns_mhdp8501_device *mhdp, u8 addr, u8 value) ++{ ++ u8 msg[5], reg[5]; ++ int ret; ++ ++ msg[0] = 0x54; ++ msg[1] = addr; ++ msg[2] = 0; ++ msg[3] = 1; ++ msg[4] = value; ++ ++ mutex_lock(&mhdp->mbox_mutex); ++ ++ ret = cdns_mhdp_mailbox_send(&mhdp->base, MB_MODULE_ID_HDMI_TX, HDMI_TX_WRITE, ++ sizeof(msg), msg); ++ if (ret) ++ goto err_scdc_write; ++ ++ ret = cdns_mhdp_mailbox_recv_header(&mhdp->base, MB_MODULE_ID_HDMI_TX, ++ HDMI_TX_WRITE, sizeof(reg)); ++ if (ret) ++ goto err_scdc_write; ++ ++ ret = cdns_mhdp_mailbox_recv_data(&mhdp->base, reg, sizeof(reg)); ++ if (ret) ++ goto err_scdc_write; ++ ++ if (reg[0] != 0) ++ ret = -EINVAL; ++ ++err_scdc_write: ++ ++ mutex_unlock(&mhdp->mbox_mutex); ++ ++ if (ret) ++ dev_err(mhdp->dev, "scdc write failed: %d\n", ret); ++ return ret; ++} ++ ++static int cdns_hdmi_ctrl_init(struct cdns_mhdp8501_device *mhdp) ++{ ++ unsigned long long char_rate = mhdp->hdmi.char_rate; ++ u32 protocol = mhdp->hdmi.hdmi_type; ++ u32 reg0, reg1, val; ++ int ret; ++ ++ /* Set PHY to HDMI data */ ++ ret = cdns_mhdp_reg_write(&mhdp->base, PHY_DATA_SEL, F_SOURCE_PHY_MHDP_SEL(1)); ++ if (ret < 0) ++ return ret; ++ ++ ret = cdns_mhdp_reg_write(&mhdp->base, HDTX_HPD, ++ F_HPD_VALID_WIDTH(4) | F_HPD_GLITCH_WIDTH(0)); ++ if (ret < 0) ++ return ret; ++ ++ /* open CARS */ ++ ret = cdns_mhdp_reg_write(&mhdp->base, SOURCE_PHY_CAR, 0xF); ++ if (ret < 0) ++ return ret; ++ ret = cdns_mhdp_reg_write(&mhdp->base, SOURCE_HDTX_CAR, 0xFF); ++ if (ret < 0) ++ return ret; ++ ret = cdns_mhdp_reg_write(&mhdp->base, SOURCE_PKT_CAR, 0xF); ++ if (ret < 0) ++ return ret; ++ ret = cdns_mhdp_reg_write(&mhdp->base, SOURCE_AIF_CAR, 0xF); ++ if (ret < 0) ++ return ret; ++ ret = cdns_mhdp_reg_write(&mhdp->base, SOURCE_CIPHER_CAR, 0xF); ++ if (ret < 0) ++ return ret; ++ ret = cdns_mhdp_reg_write(&mhdp->base, SOURCE_CRYPTO_CAR, 0xF); ++ if (ret < 0) ++ return ret; ++ ret = cdns_mhdp_reg_write(&mhdp->base, SOURCE_CEC_CAR, 3); ++ if (ret < 0) ++ return ret; ++ ++ reg0 = 0x7c1f; ++ reg1 = 0x7c1f; ++ if (protocol == MODE_HDMI_2_0 && char_rate >= 340000000) { ++ reg0 = 0; ++ reg1 = 0xFFFFF; ++ } ++ ret = cdns_mhdp_reg_write(&mhdp->base, HDTX_CLOCK_REG_0, reg0); ++ if (ret < 0) ++ return ret; ++ ret = cdns_mhdp_reg_write(&mhdp->base, HDTX_CLOCK_REG_1, reg1); ++ if (ret < 0) ++ return ret; ++ ++ /* set HDMI mode and preemble mode data enable */ ++ val = F_HDMI_MODE(protocol) | F_HDMI2_PREAMBLE_EN(1) | ++ F_DATA_EN(1) | F_HDMI2_CTRL_IL_MODE(1) | F_BCH_EN(1) | ++ F_PIC_3D(0XF) | F_CLEAR_AVMUTE(1); ++ ret = cdns_mhdp_reg_write(&mhdp->base, HDTX_CONTROLLER, val); ++ ++ return ret; ++} ++ ++static int cdns_hdmi_mode_config(struct cdns_mhdp8501_device *mhdp, ++ struct drm_display_mode *mode, ++ struct video_info *video_info) ++{ ++ u32 vsync_lines = mode->vsync_end - mode->vsync_start; ++ u32 eof_lines = mode->vsync_start - mode->vdisplay; ++ u32 sof_lines = mode->vtotal - mode->vsync_end; ++ u32 hblank = mode->htotal - mode->hdisplay; ++ u32 hactive = mode->hdisplay; ++ u32 vblank = mode->vtotal - mode->vdisplay; ++ u32 vactive = mode->vdisplay; ++ u32 hfront = mode->hsync_start - mode->hdisplay; ++ u32 hback = mode->htotal - mode->hsync_end; ++ u32 vfront = eof_lines; ++ u32 hsync = hblank - hfront - hback; ++ u32 vsync = vsync_lines; ++ u32 vback = sof_lines; ++ u32 v_h_polarity = ((mode->flags & DRM_MODE_FLAG_NHSYNC) ? 0 : 1) + ++ ((mode->flags & DRM_MODE_FLAG_NVSYNC) ? 0 : 2); ++ int ret; ++ u32 val; ++ ++ ret = cdns_mhdp_reg_write(&mhdp->base, SCHEDULER_H_SIZE, (hactive << 16) + hblank); ++ if (ret < 0) ++ return ret; ++ ++ ret = cdns_mhdp_reg_write(&mhdp->base, SCHEDULER_V_SIZE, (vactive << 16) + vblank); ++ if (ret < 0) ++ return ret; ++ ++ ret = cdns_mhdp_reg_write(&mhdp->base, HDTX_SIGNAL_FRONT_WIDTH, (vfront << 16) + hfront); ++ if (ret < 0) ++ return ret; ++ ++ ret = cdns_mhdp_reg_write(&mhdp->base, HDTX_SIGNAL_SYNC_WIDTH, (vsync << 16) + hsync); ++ if (ret < 0) ++ return ret; ++ ++ ret = cdns_mhdp_reg_write(&mhdp->base, HDTX_SIGNAL_BACK_WIDTH, (vback << 16) + hback); ++ if (ret < 0) ++ return ret; ++ ++ ret = cdns_mhdp_reg_write(&mhdp->base, HSYNC2VSYNC_POL_CTRL, v_h_polarity); ++ if (ret < 0) ++ return ret; ++ ++ /* Reset Data Enable */ ++ cdns_mhdp_reg_read(&mhdp->base, HDTX_CONTROLLER, &val); ++ val &= ~F_DATA_EN(1); ++ ret = cdns_mhdp_reg_write(&mhdp->base, HDTX_CONTROLLER, val); ++ if (ret < 0) ++ return ret; ++ ++ /* Set bpc */ ++ val &= ~F_VIF_DATA_WIDTH(3); ++ switch (video_info->bpc) { ++ case 10: ++ val |= F_VIF_DATA_WIDTH(1); ++ break; ++ case 12: ++ val |= F_VIF_DATA_WIDTH(2); ++ break; ++ case 16: ++ val |= F_VIF_DATA_WIDTH(3); ++ break; ++ case 8: ++ default: ++ val |= F_VIF_DATA_WIDTH(0); ++ break; ++ } ++ ++ /* select color encoding */ ++ val &= ~F_HDMI_ENCODING(3); ++ switch (video_info->color_fmt) { ++ case HDMI_COLORSPACE_YUV444: ++ val |= F_HDMI_ENCODING(2); ++ break; ++ case HDMI_COLORSPACE_YUV422: ++ val |= F_HDMI_ENCODING(1); ++ break; ++ case HDMI_COLORSPACE_YUV420: ++ val |= F_HDMI_ENCODING(3); ++ break; ++ case HDMI_COLORSPACE_RGB: ++ default: ++ val |= F_HDMI_ENCODING(0); ++ break; ++ } ++ ++ ret = cdns_mhdp_reg_write(&mhdp->base, HDTX_CONTROLLER, val); ++ if (ret < 0) ++ return ret; ++ ++ /* set data enable */ ++ val |= F_DATA_EN(1); ++ ret = cdns_mhdp_reg_write(&mhdp->base, HDTX_CONTROLLER, val); ++ ++ return ret; ++} ++ ++static int cdns_hdmi_disable_gcp(struct cdns_mhdp8501_device *mhdp) ++{ ++ u32 val; ++ ++ cdns_mhdp_reg_read(&mhdp->base, HDTX_CONTROLLER, &val); ++ val &= ~F_GCP_EN(1); ++ ++ return cdns_mhdp_reg_write(&mhdp->base, HDTX_CONTROLLER, val); ++} ++ ++static int cdns_hdmi_enable_gcp(struct cdns_mhdp8501_device *mhdp) ++{ ++ u32 val; ++ ++ cdns_mhdp_reg_read(&mhdp->base, HDTX_CONTROLLER, &val); ++ val |= F_GCP_EN(1); ++ ++ return cdns_mhdp_reg_write(&mhdp->base, HDTX_CONTROLLER, val); ++} ++ ++static void cdns_hdmi_sink_config(struct cdns_mhdp8501_device *mhdp) ++{ ++ struct drm_scdc *scdc = &mhdp->curr_conn->display_info.hdmi.scdc; ++ u8 buff = 0; ++ ++ /* Default work in HDMI1.4 */ ++ mhdp->hdmi.hdmi_type = MODE_HDMI_1_4; ++ ++ /* check sink support SCDC or not */ ++ if (!scdc->supported) { ++ dev_info(mhdp->dev, "Sink Not Support SCDC\n"); ++ return; ++ } ++ ++ if (mhdp->hdmi.char_rate > 340000000) { ++ /* ++ * TMDS Character Rate above 340MHz should working in HDMI2.0 ++ * Enable scrambling and TMDS_Bit_Clock_Ratio ++ */ ++ buff = SCDC_TMDS_BIT_CLOCK_RATIO_BY_40 | SCDC_SCRAMBLING_ENABLE; ++ mhdp->hdmi.hdmi_type = MODE_HDMI_2_0; ++ } else if (scdc->scrambling.low_rates) { ++ /* ++ * Enable scrambling and HDMI2.0 when scrambling capability of sink ++ * be indicated in the HF-VSDB LTE_340Mcsc_scramble bit ++ */ ++ buff = SCDC_SCRAMBLING_ENABLE; ++ mhdp->hdmi.hdmi_type = MODE_HDMI_2_0; ++ } ++ ++ /* TMDS config */ ++ cdns_hdmi_scdc_write(mhdp, SCDC_TMDS_CONFIG, buff); ++} ++ ++static int cdns_hdmi_bridge_attach(struct drm_bridge *bridge, ++ enum drm_bridge_attach_flags flags) ++{ ++ struct cdns_mhdp8501_device *mhdp = bridge->driver_private; ++ ++ if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) { ++ dev_err(mhdp->dev, "do not support creating a drm_connector\n"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static enum drm_mode_status ++cdns_hdmi_tmds_char_rate_valid(const struct drm_bridge *bridge, ++ const struct drm_display_mode *mode, ++ unsigned long long tmds_rate) ++{ ++ struct cdns_mhdp8501_device *mhdp = bridge->driver_private; ++ union phy_configure_opts phy_cfg; ++ int ret; ++ ++ phy_cfg.hdmi.tmds_char_rate = tmds_rate; ++ ++ /* Mailbox protect for HDMI PHY access */ ++ mutex_lock(&mhdp->mbox_mutex); ++ ret = phy_validate(mhdp->phy, PHY_MODE_HDMI, 0, &phy_cfg); ++ mutex_unlock(&mhdp->mbox_mutex); ++ if (ret < 0) ++ return MODE_CLOCK_RANGE; ++ ++ return MODE_OK; ++} ++ ++static enum drm_mode_status ++cdns_hdmi_bridge_mode_valid(struct drm_bridge *bridge, ++ const struct drm_display_info *info, ++ const struct drm_display_mode *mode) ++{ ++ unsigned long long tmds_rate; ++ ++ /* We don't support double-clocked and Interlaced modes */ ++ if (mode->flags & DRM_MODE_FLAG_DBLCLK || ++ mode->flags & DRM_MODE_FLAG_INTERLACE) ++ return MODE_BAD; ++ ++ /* MAX support pixel clock rate 594MHz */ ++ if (mode->clock > 594000) ++ return MODE_CLOCK_HIGH; ++ ++ if (mode->hdisplay > 3840) ++ return MODE_BAD_HVALUE; ++ ++ if (mode->vdisplay > 2160) ++ return MODE_BAD_VVALUE; ++ ++ tmds_rate = mode->clock * 1000ULL; ++ return cdns_hdmi_tmds_char_rate_valid(bridge, mode, tmds_rate); ++} ++ ++static enum drm_connector_status ++cdns_hdmi_bridge_detect(struct drm_bridge *bridge) ++{ ++ struct cdns_mhdp8501_device *mhdp = bridge->driver_private; ++ ++ return cdns_mhdp8501_detect(mhdp); ++} ++ ++static const struct drm_edid ++*cdns_hdmi_bridge_edid_read(struct drm_bridge *bridge, ++ struct drm_connector *connector) ++{ ++ struct cdns_mhdp8501_device *mhdp = bridge->driver_private; ++ ++ return drm_edid_read_custom(connector, cdns_hdmi_get_edid_block, mhdp); ++} ++ ++static void cdns_hdmi_bridge_atomic_disable(struct drm_bridge *bridge, ++ struct drm_bridge_state *old_state) ++{ ++ struct cdns_mhdp8501_device *mhdp = bridge->driver_private; ++ ++ mhdp->curr_conn = NULL; ++ ++ /* Mailbox protect for HDMI PHY access */ ++ mutex_lock(&mhdp->mbox_mutex); ++ phy_power_off(mhdp->phy); ++ mutex_unlock(&mhdp->mbox_mutex); ++} ++ ++static void cdns_hdmi_bridge_atomic_enable(struct drm_bridge *bridge, ++ struct drm_bridge_state *old_state) ++{ ++ struct cdns_mhdp8501_device *mhdp = bridge->driver_private; ++ struct drm_atomic_state *state = old_state->base.state; ++ struct drm_connector *connector; ++ struct video_info *video = &mhdp->video_info; ++ struct drm_crtc_state *crtc_state; ++ struct drm_connector_state *conn_state; ++ struct drm_display_mode *mode = &mhdp->mode; ++ union phy_configure_opts phy_cfg; ++ int ret; ++ ++ connector = drm_atomic_get_new_connector_for_encoder(state, ++ bridge->encoder); ++ if (WARN_ON(!connector)) ++ return; ++ ++ mhdp->curr_conn = connector; ++ ++ conn_state = drm_atomic_get_new_connector_state(state, connector); ++ if (WARN_ON(!conn_state)) ++ return; ++ ++ crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc); ++ if (WARN_ON(!crtc_state)) ++ return; ++ ++ video->color_fmt = conn_state->hdmi.output_format; ++ video->bpc = conn_state->hdmi.output_bpc; ++ ++ drm_mode_copy(&mhdp->mode, &crtc_state->adjusted_mode); ++ ++ /* video mode check */ ++ if (mode->clock == 0 || mode->hdisplay == 0 || mode->vdisplay == 0) ++ return; ++ ++ dev_dbg(mhdp->dev, "Mode: %dx%dp%d\n", ++ mode->hdisplay, mode->vdisplay, mode->clock); ++ ++ drm_atomic_helper_connector_hdmi_update_infoframes(connector, state); ++ ++ /* Line swapping */ ++ cdns_mhdp_reg_write(&mhdp->base, LANES_CONFIG, 0x00400000 | mhdp->lane_mapping); ++ ++ mhdp->hdmi.char_rate = drm_hdmi_compute_mode_clock(mode, ++ mhdp->video_info.bpc, ++ mhdp->video_info.color_fmt); ++ phy_cfg.hdmi.tmds_char_rate = mhdp->hdmi.char_rate; ++ ++ /* Mailbox protect for HDMI PHY access */ ++ mutex_lock(&mhdp->mbox_mutex); ++ ret = phy_configure(mhdp->phy, &phy_cfg); ++ mutex_unlock(&mhdp->mbox_mutex); ++ if (ret) { ++ dev_err(mhdp->dev, "%s: phy_configure() failed: %d\n", ++ __func__, ret); ++ return; ++ } ++ ++ cdns_hdmi_sink_config(mhdp); ++ ++ ret = cdns_hdmi_ctrl_init(mhdp); ++ if (ret < 0) { ++ dev_err(mhdp->dev, "%s, ret = %d\n", __func__, ret); ++ return; ++ } ++ ++ /* Config GCP */ ++ if (mhdp->video_info.bpc == 8) ++ cdns_hdmi_disable_gcp(mhdp); ++ else ++ cdns_hdmi_enable_gcp(mhdp); ++ ++ ret = cdns_hdmi_mode_config(mhdp, mode, &mhdp->video_info); ++ if (ret < 0) { ++ dev_err(mhdp->dev, "CDN_API_HDMITX_SetVic_blocking ret = %d\n", ret); ++ return; ++ } ++} ++ ++static int cdns_hdmi_bridge_clear_infoframe(struct drm_bridge *bridge, ++ enum hdmi_infoframe_type type) ++{ ++ return 0; ++} ++ ++static int cdns_hdmi_bridge_write_infoframe(struct drm_bridge *bridge, ++ enum hdmi_infoframe_type type, ++ const u8 *buffer, size_t len) ++{ ++ struct cdns_mhdp8501_device *mhdp = bridge->driver_private; ++ ++ switch (type) { ++ case HDMI_INFOFRAME_TYPE_AVI: ++ cdns_hdmi_config_infoframe(mhdp, 0, len, buffer, HDMI_INFOFRAME_TYPE_AVI); ++ break; ++ case HDMI_INFOFRAME_TYPE_SPD: ++ cdns_hdmi_config_infoframe(mhdp, 1, len, buffer, HDMI_INFOFRAME_TYPE_SPD); ++ break; ++ case HDMI_INFOFRAME_TYPE_VENDOR: ++ cdns_hdmi_config_infoframe(mhdp, 2, len, buffer, HDMI_INFOFRAME_TYPE_VENDOR); ++ break; ++ default: ++ dev_dbg(mhdp->dev, "Unsupported infoframe type %x\n", type); ++ } ++ ++ return 0; ++} ++ ++static int cdns_hdmi_bridge_atomic_check(struct drm_bridge *bridge, ++ struct drm_bridge_state *bridge_state, ++ struct drm_crtc_state *crtc_state, ++ struct drm_connector_state *conn_state) ++{ ++ return drm_atomic_helper_connector_hdmi_check(conn_state->connector, conn_state->state); ++} ++ ++const struct drm_bridge_funcs cdns_hdmi_bridge_funcs = { ++ .attach = cdns_hdmi_bridge_attach, ++ .detect = cdns_hdmi_bridge_detect, ++ .edid_read = cdns_hdmi_bridge_edid_read, ++ .mode_valid = cdns_hdmi_bridge_mode_valid, ++ .atomic_enable = cdns_hdmi_bridge_atomic_enable, ++ .atomic_disable = cdns_hdmi_bridge_atomic_disable, ++ .atomic_check = cdns_hdmi_bridge_atomic_check, ++ .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, ++ .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, ++ .atomic_reset = drm_atomic_helper_bridge_reset, ++ .hdmi_clear_infoframe = cdns_hdmi_bridge_clear_infoframe, ++ .hdmi_write_infoframe = cdns_hdmi_bridge_write_infoframe, ++ .hdmi_tmds_char_rate_valid = cdns_hdmi_tmds_char_rate_valid, ++}; + +From patchwork Tue Jul 2 12:22:37 2024 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [v16,5/8] dt-bindings: phy: Add Freescale iMX8MQ DP and HDMI PHY +From: Sandor Yu +X-Patchwork-Id: 601667 +Message-Id: + <3f942b32bc3d34dcd922a6e4a5924c7ebfede2ef.1719903904.git.Sandor.yu@nxp.com> +To: dmitry.baryshkov@linaro.org, andrzej.hajda@intel.com, + neil.armstrong@linaro.org, Laurent.pinchart@ideasonboard.com, + jonas@kwiboo.se, jernej.skrabec@gmail.com, airlied@gmail.com, + daniel@ffwll.ch, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, + shawnguo@kernel.org, s.hauer@pengutronix.de, festevam@gmail.com, + vkoul@kernel.org, dri-devel@lists.freedesktop.org, + devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, + linux-kernel@vger.kernel.org, linux-phy@lists.infradead.org, + mripard@kernel.org +Cc: kernel@pengutronix.de, linux-imx@nxp.com, Sandor.yu@nxp.com, + oliver.brown@nxp.com, alexander.stein@ew.tq-group.com, sam@ravnborg.org, + Rob Herring +Date: Tue, 2 Jul 2024 20:22:37 +0800 + +Add bindings for Freescale iMX8MQ DP and HDMI PHY. + +Signed-off-by: Sandor Yu +Reviewed-by: Rob Herring +--- +v9->v16: + *No change. + + .../bindings/phy/fsl,imx8mq-dp-hdmi-phy.yaml | 51 +++++++++++++++++++ + 1 file changed, 51 insertions(+) + create mode 100644 Documentation/devicetree/bindings/phy/fsl,imx8mq-dp-hdmi-phy.yaml + +diff --git a/Documentation/devicetree/bindings/phy/fsl,imx8mq-dp-hdmi-phy.yaml b/Documentation/devicetree/bindings/phy/fsl,imx8mq-dp-hdmi-phy.yaml +new file mode 100644 +index 000000000000..c17a645e71ba +--- /dev/null ++++ b/Documentation/devicetree/bindings/phy/fsl,imx8mq-dp-hdmi-phy.yaml +@@ -0,0 +1,51 @@ ++# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/phy/fsl,imx8mq-dp-hdmi-phy.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Cadence HDP-TX DP/HDMI PHY for Freescale i.MX8MQ SoC ++ ++maintainers: ++ - Sandor Yu ++ ++properties: ++ compatible: ++ const: fsl,imx8mq-hdptx-phy ++ ++ reg: ++ maxItems: 1 ++ ++ clocks: ++ items: ++ - description: PHY reference clock. ++ - description: APB clock. ++ ++ clock-names: ++ items: ++ - const: ref ++ - const: apb ++ ++ "#phy-cells": ++ const: 0 ++ ++required: ++ - compatible ++ - reg ++ - clocks ++ - clock-names ++ - "#phy-cells" ++ ++additionalProperties: false ++ ++examples: ++ - | ++ #include ++ #include ++ dp_phy: phy@32c00000 { ++ compatible = "fsl,imx8mq-hdptx-phy"; ++ reg = <0x32c00000 0x100000>; ++ #phy-cells = <0>; ++ clocks = <&hdmi_phy_27m>, <&clk IMX8MQ_CLK_DISP_APB_ROOT>; ++ clock-names = "ref", "apb"; ++ }; + +From patchwork Tue Jul 2 12:22:38 2024 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [v16,6/8] phy: freescale: Add DisplayPort/HDMI Combo-PHY driver for + i.MX8MQ +From: Sandor Yu +X-Patchwork-Id: 601668 +Message-Id: + +To: dmitry.baryshkov@linaro.org, andrzej.hajda@intel.com, + neil.armstrong@linaro.org, Laurent.pinchart@ideasonboard.com, + jonas@kwiboo.se, jernej.skrabec@gmail.com, airlied@gmail.com, + daniel@ffwll.ch, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, + shawnguo@kernel.org, s.hauer@pengutronix.de, festevam@gmail.com, + vkoul@kernel.org, dri-devel@lists.freedesktop.org, + devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, + linux-kernel@vger.kernel.org, linux-phy@lists.infradead.org, + mripard@kernel.org +Cc: kernel@pengutronix.de, linux-imx@nxp.com, Sandor.yu@nxp.com, + oliver.brown@nxp.com, alexander.stein@ew.tq-group.com, sam@ravnborg.org +Date: Tue, 2 Jul 2024 20:22:38 +0800 + +Add Cadence HDP-TX DisplayPort and HDMI PHY driver for i.MX8MQ. + +Cadence HDP-TX PHY could be put in either DP mode or +HDMI mode base on the configuration chosen. +DisplayPort or HDMI PHY mode is configured in the driver. + +Signed-off-by: Sandor Yu +Signed-off-by: Alexander Stein +--- +v15->v16: +- updated for tmds_char_rate added to struct phy_configure_opts_hdmi in patch #2. + +v14->v15: +- Merged DP and HDMI PHY driver into a single combo PHY driver + + drivers/phy/freescale/Kconfig | 10 + + drivers/phy/freescale/Makefile | 1 + + drivers/phy/freescale/phy-fsl-imx8mq-hdptx.c | 1340 ++++++++++++++++++ + 3 files changed, 1351 insertions(+) + create mode 100644 drivers/phy/freescale/phy-fsl-imx8mq-hdptx.c + +diff --git a/drivers/phy/freescale/Kconfig b/drivers/phy/freescale/Kconfig +index 45aaaea14fb4..70431453af28 100644 +--- a/drivers/phy/freescale/Kconfig ++++ b/drivers/phy/freescale/Kconfig +@@ -35,6 +35,16 @@ config PHY_FSL_IMX8M_PCIE + Enable this to add support for the PCIE PHY as found on + i.MX8M family of SOCs. + ++config PHY_FSL_IMX8MQ_HDPTX ++ tristate "Freescale i.MX8MQ DP/HDMI PHY support" ++ depends on OF && HAS_IOMEM ++ depends on COMMON_CLK ++ select GENERIC_PHY ++ select CDNS_MHDP_HELPER ++ help ++ Enable this to support the Cadence HDPTX DP/HDMI PHY driver ++ on i.MX8MQ SOC. ++ + config PHY_FSL_SAMSUNG_HDMI_PHY + tristate "Samsung HDMI PHY support" + depends on OF && HAS_IOMEM && COMMON_CLK +diff --git a/drivers/phy/freescale/Makefile b/drivers/phy/freescale/Makefile +index c4386bfdb853..92f0cf50d0dc 100644 +--- a/drivers/phy/freescale/Makefile ++++ b/drivers/phy/freescale/Makefile +@@ -1,4 +1,5 @@ + # SPDX-License-Identifier: GPL-2.0-only ++obj-$(CONFIG_PHY_FSL_IMX8MQ_HDPTX) += phy-fsl-imx8mq-hdptx.o + obj-$(CONFIG_PHY_FSL_IMX8MQ_USB) += phy-fsl-imx8mq-usb.o + obj-$(CONFIG_PHY_MIXEL_LVDS_PHY) += phy-fsl-imx8qm-lvds-phy.o + obj-$(CONFIG_PHY_MIXEL_MIPI_DPHY) += phy-fsl-imx8-mipi-dphy.o +diff --git a/drivers/phy/freescale/phy-fsl-imx8mq-hdptx.c b/drivers/phy/freescale/phy-fsl-imx8mq-hdptx.c +new file mode 100644 +index 000000000000..7d43b0328a11 +--- /dev/null ++++ b/drivers/phy/freescale/phy-fsl-imx8mq-hdptx.c +@@ -0,0 +1,1340 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Cadence DP/HDMI PHY driver ++ * ++ * Copyright (C) 2022-2024 NXP Semiconductor, Inc. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define ADDR_PHY_AFE 0x80000 ++ ++/* PHY registers */ ++#define CMN_SSM_BIAS_TMR 0x0022 ++#define CMN_PLLSM0_PLLEN_TMR 0x0029 ++#define CMN_PLLSM0_PLLPRE_TMR 0x002a ++#define CMN_PLLSM0_PLLVREF_TMR 0x002b ++#define CMN_PLLSM0_PLLLOCK_TMR 0x002c ++#define CMN_PLLSM0_USER_DEF_CTRL 0x002f ++#define CMN_PSM_CLK_CTRL 0x0061 ++#define CMN_CDIAG_REFCLK_CTRL 0x0062 ++#define CMN_PLL0_VCOCAL_START 0x0081 ++#define CMN_PLL0_VCOCAL_INIT_TMR 0x0084 ++#define CMN_PLL0_VCOCAL_ITER_TMR 0x0085 ++#define CMN_PLL0_INTDIV 0x0094 ++#define CMN_PLL0_FRACDIV 0x0095 ++#define CMN_PLL0_HIGH_THR 0x0096 ++#define CMN_PLL0_DSM_DIAG 0x0097 ++#define CMN_PLL0_SS_CTRL2 0x0099 ++#define CMN_ICAL_INIT_TMR 0x00c4 ++#define CMN_ICAL_ITER_TMR 0x00c5 ++#define CMN_RXCAL_INIT_TMR 0x00d4 ++#define CMN_RXCAL_ITER_TMR 0x00d5 ++#define CMN_TXPUCAL_CTRL 0x00e0 ++#define CMN_TXPUCAL_INIT_TMR 0x00e4 ++#define CMN_TXPUCAL_ITER_TMR 0x00e5 ++#define CMN_TXPDCAL_CTRL 0x00f0 ++#define CMN_TXPDCAL_INIT_TMR 0x00f4 ++#define CMN_TXPDCAL_ITER_TMR 0x00f5 ++#define CMN_ICAL_ADJ_INIT_TMR 0x0102 ++#define CMN_ICAL_ADJ_ITER_TMR 0x0103 ++#define CMN_RX_ADJ_INIT_TMR 0x0106 ++#define CMN_RX_ADJ_ITER_TMR 0x0107 ++#define CMN_TXPU_ADJ_CTRL 0x0108 ++#define CMN_TXPU_ADJ_INIT_TMR 0x010a ++#define CMN_TXPU_ADJ_ITER_TMR 0x010b ++#define CMN_TXPD_ADJ_CTRL 0x010c ++#define CMN_TXPD_ADJ_INIT_TMR 0x010e ++#define CMN_TXPD_ADJ_ITER_TMR 0x010f ++#define CMN_DIAG_PLL0_FBH_OVRD 0x01c0 ++#define CMN_DIAG_PLL0_FBL_OVRD 0x01c1 ++#define CMN_DIAG_PLL0_OVRD 0x01c2 ++#define CMN_DIAG_PLL0_TEST_MODE 0x01c4 ++#define CMN_DIAG_PLL0_V2I_TUNE 0x01c5 ++#define CMN_DIAG_PLL0_CP_TUNE 0x01c6 ++#define CMN_DIAG_PLL0_LF_PROG 0x01c7 ++#define CMN_DIAG_PLL0_PTATIS_TUNE1 0x01c8 ++#define CMN_DIAG_PLL0_PTATIS_TUNE2 0x01c9 ++#define CMN_DIAG_PLL0_INCLK_CTRL 0x01ca ++#define CMN_DIAG_PLL0_PXL_DIVH 0x01cb ++#define CMN_DIAG_PLL0_PXL_DIVL 0x01cc ++#define CMN_DIAG_HSCLK_SEL 0x01e0 ++#define CMN_DIAG_PER_CAL_ADJ 0x01ec ++#define CMN_DIAG_CAL_CTRL 0x01ed ++#define CMN_DIAG_ACYA 0x01ff ++#define XCVR_PSM_RCTRL 0x4001 ++#define XCVR_PSM_CAL_TMR 0x4002 ++#define XCVR_PSM_A0IN_TMR 0x4003 ++#define TX_TXCC_CAL_SCLR_MULT_0 0x4047 ++#define TX_TXCC_CPOST_MULT_00_0 0x404c ++#define XCVR_DIAG_PLLDRC_CTRL 0x40e0 ++#define XCVR_DIAG_HSCLK_SEL 0x40e1 ++#define XCVR_DIAG_BIDI_CTRL 0x40e8 ++#define XCVR_DIAG_LANE_FCM_EN_MGN_TMR 0x40f2 ++#define TX_PSC_A0 0x4100 ++#define TX_PSC_A1 0x4101 ++#define TX_PSC_A2 0x4102 ++#define TX_PSC_A3 0x4103 ++#define TX_RCVDET_EN_TMR 0x4122 ++#define TX_RCVDET_ST_TMR 0x4123 ++#define TX_DIAG_TX_CTRL 0x41e0 ++#define TX_DIAG_TX_DRV 0x41e1 ++#define TX_DIAG_BGREF_PREDRV_DELAY 0x41e7 ++#define TX_DIAG_ACYA_0 0x41ff ++#define TX_DIAG_ACYA_1 0x43ff ++#define TX_DIAG_ACYA_2 0x45ff ++#define TX_DIAG_ACYA_3 0x47ff ++#define TX_ANA_CTRL_REG_1 0x5020 ++#define TX_ANA_CTRL_REG_2 0x5021 ++#define TX_DIG_CTRL_REG_1 0x5023 ++#define TX_DIG_CTRL_REG_2 0x5024 ++#define TXDA_CYA_AUXDA_CYA 0x5025 ++#define TX_ANA_CTRL_REG_3 0x5026 ++#define TX_ANA_CTRL_REG_4 0x5027 ++#define TX_ANA_CTRL_REG_5 0x5029 ++#define RX_PSC_A0 0x8000 ++#define RX_PSC_CAL 0x8006 ++#define PHY_HDP_MODE_CTRL 0xc008 ++#define PHY_HDP_CLK_CTL 0xc009 ++#define PHY_ISO_CMN_CTRL 0xc010 ++#define PHY_PMA_CMN_CTRL1 0xc800 ++#define PHY_PMA_ISO_CMN_CTRL 0xc810 ++#define PHY_PMA_ISO_PLL_CTRL1 0xc812 ++#define PHY_PMA_ISOLATION_CTRL 0xc81f ++ ++/* PHY_HDP_CLK_CTL */ ++#define PLL_DATA_RATE_CLK_DIV_MASK GENMASK(15, 8) ++#define PLL_DATA_RATE_CLK_DIV_HBR 0x24 ++#define PLL_DATA_RATE_CLK_DIV_HBR2 0x12 ++#define PLL_CLK_EN_ACK BIT(3) ++#define PLL_CLK_EN BIT(2) ++#define PLL_READY BIT(1) ++#define PLL_EN BIT(0) ++ ++/* PHY_PMA_CMN_CTRL1 */ ++#define CMA_REF_CLK_DIG_DIV_MASK GENMASK(13, 12) ++#define CMA_REF_CLK_SEL_MASK GENMASK(6, 4) ++#define CMA_REF_CLK_RCV_EN_MASK BIT(3) ++#define CMA_REF_CLK_RCV_EN 1 ++#define CMN_READY BIT(0) ++ ++/* PHY_PMA_ISO_PLL_CTRL1 */ ++#define CMN_PLL0_CLK_DATART_DIV_MASK GENMASK(7, 0) ++ ++/* TX_DIAG_TX_DRV */ ++#define TX_DRIVER_PROG_BOOST_ENABLE BIT(10) ++#define TX_DRIVER_PROG_BOOST_LEVEL_MASK GENMASK(9, 8) ++#define TX_DRIVER_LDO_BG_DEPENDENT_REF_ENABLE BIT(7) ++#define TX_DRIVER_LDO_BANDGAP_REF_ENABLE BIT(6) ++ ++/* TX_TXCC_CAL_SCLR_MULT_0 */ ++#define SCALED_RESISTOR_CALIBRATION_CODE_ADD BIT(8) ++#define RESISTOR_CAL_MULT_VAL_32_128 BIT(5) ++ ++/* CMN_CDIAG_REFCLK_CTRL */ ++#define DIG_REF_CLK_DIV_SCALER_MASK GENMASK(14, 12) ++#define REFCLK_TERMINATION_EN_OVERRIDE_EN BIT(7) ++#define REFCLK_TERMINATION_EN_OVERRIDE BIT(6) ++ ++/* CMN_DIAG_HSCLK_SEL */ ++#define HSCLK1_SEL_MASK GENMASK(5, 4) ++#define HSCLK0_SEL_MASK GENMASK(1, 0) ++#define HSCLK_PLL0_DIV2 1 ++ ++/* XCVR_DIAG_HSCLK_SEL */ ++#define HSCLK_SEL_MODE3_MASK GENMASK(13, 12) ++#define HSCLK_SEL_MODE3_HSCLK1 1 ++ ++/* CMN_PLL0_VCOCAL_START */ ++#define VCO_CALIB_CODE_START_POINT_VAL_MASK GENMASK(8, 0) ++ ++/* CMN_DIAG_PLL0_FBH_OVRD */ ++#define PLL_FEEDBACK_DIV_HI_OVERRIDE_EN BIT(15) ++ ++/* CMN_DIAG_PLL0_FBL_OVRD */ ++#define PLL_FEEDBACK_DIV_LO_OVERRIDE_EN BIT(15) ++ ++/* CMN_DIAG_PLL0_PXL_DIVH */ ++#define PLL_PCLK_DIV_EN BIT(15) ++ ++/* XCVR_DIAG_PLLDRC_CTRL */ ++#define DPLL_CLK_SEL_MODE3 BIT(14) ++#define DPLL_DATA_RATE_DIV_MODE3_MASK GENMASK(13, 12) ++ ++/* TX_DIAG_TX_CTRL */ ++#define TX_IF_SUBRATE_MODE3_MASK GENMASK(7, 6) ++ ++/* PHY_HDP_MODE_CTRL */ ++#define POWER_STATE_A3_ACK BIT(7) ++#define POWER_STATE_A2_ACK BIT(6) ++#define POWER_STATE_A1_ACK BIT(5) ++#define POWER_STATE_A0_ACK BIT(4) ++#define POWER_STATE_A3 BIT(3) ++#define POWER_STATE_A2 BIT(2) ++#define POWER_STATE_A1 BIT(1) ++#define POWER_STATE_A0 BIT(0) ++ ++/* PHY_PMA_ISO_CMN_CTRL */ ++#define CMN_MACRO_PWR_EN_ACK BIT(5) ++ ++#define KEEP_ALIVE 0x18 ++ ++#define REF_CLK_27MHZ 27000000 ++ ++/* HDMI TX clock control settings */ ++struct hdptx_hdmi_ctrl { ++ u32 pixel_clk_freq_min; ++ u32 pixel_clk_freq_max; ++ u32 feedback_factor; ++ u32 data_range_kbps_min; ++ u32 data_range_kbps_max; ++ u32 cmnda_pll0_ip_div; ++ u32 cmn_ref_clk_dig_div; ++ u32 ref_clk_divider_scaler; ++ u32 pll_fb_div_total; ++ u32 cmnda_pll0_fb_div_low; ++ u32 cmnda_pll0_fb_div_high; ++ u32 pixel_div_total; ++ u32 cmnda_pll0_pxdiv_low; ++ u32 cmnda_pll0_pxdiv_high; ++ u32 vco_freq_min; ++ u32 vco_freq_max; ++ u32 vco_ring_select; ++ u32 cmnda_hs_clk_0_sel; ++ u32 cmnda_hs_clk_1_sel; ++ u32 hsclk_div_at_xcvr; ++ u32 hsclk_div_tx_sub_rate; ++ u32 cmnda_pll0_hs_sym_div_sel; ++ u32 cmnda_pll0_clk_freq_min; ++ u32 cmnda_pll0_clk_freq_max; ++}; ++ ++struct cdns_hdptx_phy { ++ struct cdns_mhdp_base base; ++ ++ void __iomem *regs; /* DPTX registers base */ ++ struct mutex mbox_mutex; /* mutex to protect mailbox */ ++ struct device *dev; ++ struct phy *phy; ++ struct clk *ref_clk, *apb_clk; ++ u32 ref_clk_rate; ++ bool power_up; ++ union { ++ struct phy_configure_opts_hdmi hdmi; ++ struct phy_configure_opts_dp dp; ++ }; ++}; ++ ++/* HDMI TX clock control settings, pixel clock is output */ ++static const struct hdptx_hdmi_ctrl pixel_clk_output_ctrl_table[] = { ++/*Minclk Maxclk Fdbak DR_min DR_max ip_d dig DS Totl */ ++{ 27000, 27000, 1000, 270000, 270000, 0x03, 0x1, 0x1, 240, 0x0bc, 0x030, 80, 0x026, 0x026, 2160000, 2160000, 0, 2, 2, 2, 4, 0x3, 27000, 27000}, ++{ 27000, 27000, 1250, 337500, 337500, 0x03, 0x1, 0x1, 300, 0x0ec, 0x03c, 100, 0x030, 0x030, 2700000, 2700000, 0, 2, 2, 2, 4, 0x3, 33750, 33750}, ++{ 27000, 27000, 1500, 405000, 405000, 0x03, 0x1, 0x1, 360, 0x11c, 0x048, 120, 0x03a, 0x03a, 3240000, 3240000, 0, 2, 2, 2, 4, 0x3, 40500, 40500}, ++{ 27000, 27000, 2000, 540000, 540000, 0x03, 0x1, 0x1, 240, 0x0bc, 0x030, 80, 0x026, 0x026, 2160000, 2160000, 0, 2, 2, 2, 4, 0x2, 54000, 54000}, ++{ 54000, 54000, 1000, 540000, 540000, 0x03, 0x1, 0x1, 480, 0x17c, 0x060, 80, 0x026, 0x026, 4320000, 4320000, 1, 2, 2, 2, 4, 0x3, 54000, 54000}, ++{ 54000, 54000, 1250, 675000, 675000, 0x04, 0x1, 0x1, 400, 0x13c, 0x050, 50, 0x017, 0x017, 2700000, 2700000, 0, 1, 1, 2, 4, 0x2, 67500, 67500}, ++{ 54000, 54000, 1500, 810000, 810000, 0x04, 0x1, 0x1, 480, 0x17c, 0x060, 60, 0x01c, 0x01c, 3240000, 3240000, 0, 2, 2, 2, 2, 0x2, 81000, 81000}, ++{ 54000, 54000, 2000, 1080000, 1080000, 0x03, 0x1, 0x1, 240, 0x0bc, 0x030, 40, 0x012, 0x012, 2160000, 2160000, 0, 2, 2, 2, 1, 0x1, 108000, 108000}, ++{ 74250, 74250, 1000, 742500, 742500, 0x03, 0x1, 0x1, 660, 0x20c, 0x084, 80, 0x026, 0x026, 5940000, 5940000, 1, 2, 2, 2, 4, 0x3, 74250, 74250}, ++{ 74250, 74250, 1250, 928125, 928125, 0x04, 0x1, 0x1, 550, 0x1b4, 0x06e, 50, 0x017, 0x017, 3712500, 3712500, 1, 1, 1, 2, 4, 0x2, 92812, 92812}, ++{ 74250, 74250, 1500, 1113750, 1113750, 0x04, 0x1, 0x1, 660, 0x20c, 0x084, 60, 0x01c, 0x01c, 4455000, 4455000, 1, 2, 2, 2, 2, 0x2, 111375, 111375}, ++{ 74250, 74250, 2000, 1485000, 1485000, 0x03, 0x1, 0x1, 330, 0x104, 0x042, 40, 0x012, 0x012, 2970000, 2970000, 0, 2, 2, 2, 1, 0x1, 148500, 148500}, ++{ 99000, 99000, 1000, 990000, 990000, 0x03, 0x1, 0x1, 440, 0x15c, 0x058, 40, 0x012, 0x012, 3960000, 3960000, 1, 2, 2, 2, 2, 0x2, 99000, 99000}, ++{ 99000, 99000, 1250, 1237500, 1237500, 0x03, 0x1, 0x1, 275, 0x0d8, 0x037, 25, 0x00b, 0x00a, 2475000, 2475000, 0, 1, 1, 2, 2, 0x1, 123750, 123750}, ++{ 99000, 99000, 1500, 1485000, 1485000, 0x03, 0x1, 0x1, 330, 0x104, 0x042, 30, 0x00d, 0x00d, 2970000, 2970000, 0, 2, 2, 2, 1, 0x1, 148500, 148500}, ++{ 99000, 99000, 2000, 1980000, 1980000, 0x03, 0x1, 0x1, 440, 0x15c, 0x058, 40, 0x012, 0x012, 3960000, 3960000, 1, 2, 2, 2, 1, 0x1, 198000, 198000}, ++{148500, 148500, 1000, 1485000, 1485000, 0x03, 0x1, 0x1, 660, 0x20c, 0x084, 40, 0x012, 0x012, 5940000, 5940000, 1, 2, 2, 2, 2, 0x2, 148500, 148500}, ++{148500, 148500, 1250, 1856250, 1856250, 0x04, 0x1, 0x1, 550, 0x1b4, 0x06e, 25, 0x00b, 0x00a, 3712500, 3712500, 1, 1, 1, 2, 2, 0x1, 185625, 185625}, ++{148500, 148500, 1500, 2227500, 2227500, 0x03, 0x1, 0x1, 495, 0x188, 0x063, 30, 0x00d, 0x00d, 4455000, 4455000, 1, 1, 1, 2, 2, 0x1, 222750, 222750}, ++{148500, 148500, 2000, 2970000, 2970000, 0x03, 0x1, 0x1, 660, 0x20c, 0x084, 40, 0x012, 0x012, 5940000, 5940000, 1, 2, 2, 2, 1, 0x1, 297000, 297000}, ++{198000, 198000, 1000, 1980000, 1980000, 0x03, 0x1, 0x1, 220, 0x0ac, 0x02c, 10, 0x003, 0x003, 1980000, 1980000, 0, 1, 1, 2, 1, 0x0, 198000, 198000}, ++{198000, 198000, 1250, 2475000, 2475000, 0x03, 0x1, 0x1, 550, 0x1b4, 0x06e, 25, 0x00b, 0x00a, 4950000, 4950000, 1, 1, 1, 2, 2, 0x1, 247500, 247500}, ++{198000, 198000, 1500, 2970000, 2970000, 0x03, 0x1, 0x1, 330, 0x104, 0x042, 15, 0x006, 0x005, 2970000, 2970000, 0, 1, 1, 2, 1, 0x0, 297000, 297000}, ++{198000, 198000, 2000, 3960000, 3960000, 0x03, 0x1, 0x1, 440, 0x15c, 0x058, 20, 0x008, 0x008, 3960000, 3960000, 1, 1, 1, 2, 1, 0x0, 396000, 396000}, ++{297000, 297000, 1000, 2970000, 2970000, 0x03, 0x1, 0x1, 330, 0x104, 0x042, 10, 0x003, 0x003, 2970000, 2970000, 0, 1, 1, 2, 1, 0x0, 297000, 297000}, ++{297000, 297000, 1500, 4455000, 4455000, 0x03, 0x1, 0x1, 495, 0x188, 0x063, 15, 0x006, 0x005, 4455000, 4455000, 1, 1, 1, 2, 1, 0x0, 445500, 445500}, ++{297000, 297000, 2000, 5940000, 5940000, 0x03, 0x1, 0x1, 660, 0x20c, 0x084, 20, 0x008, 0x008, 5940000, 5940000, 1, 1, 1, 2, 1, 0x0, 594000, 594000}, ++{594000, 594000, 1000, 5940000, 5940000, 0x03, 0x1, 0x1, 660, 0x20c, 0x084, 10, 0x003, 0x003, 5940000, 5940000, 1, 1, 1, 2, 1, 0x0, 594000, 594000}, ++{594000, 594000, 750, 4455000, 4455000, 0x03, 0x1, 0x1, 495, 0x188, 0x063, 10, 0x003, 0x003, 4455000, 4455000, 1, 1, 1, 2, 1, 0x0, 445500, 445500}, ++{594000, 594000, 625, 3712500, 3712500, 0x04, 0x1, 0x1, 550, 0x1b4, 0x06e, 10, 0x003, 0x003, 3712500, 3712500, 1, 1, 1, 2, 1, 0x0, 371250, 371250}, ++{594000, 594000, 500, 2970000, 2970000, 0x03, 0x1, 0x1, 660, 0x20c, 0x084, 10, 0x003, 0x003, 5940000, 5940000, 1, 1, 1, 2, 2, 0x1, 297000, 297000}, ++}; ++ ++/* HDMI TX PLL tuning settings */ ++struct hdptx_hdmi_pll_tuning { ++ u32 vco_freq_bin; ++ u32 vco_freq_min; ++ u32 vco_freq_max; ++ u32 volt_to_current_coarse; ++ u32 volt_to_current; ++ u32 ndac_ctrl; ++ u32 pmos_ctrl; ++ u32 ptat_ndac_ctrl; ++ u32 feedback_div_total; ++ u32 charge_pump_gain; ++ u32 coarse_code; ++ u32 v2i_code; ++ u32 vco_cal_code; ++}; ++ ++/* HDMI TX PLL tuning settings, pixel clock is output */ ++static const struct hdptx_hdmi_pll_tuning pixel_clk_output_pll_table[] = { ++/*bin VCO_freq min/max coar cod NDAC PMOS PTAT div-T P-Gain Coa V2I CAL */ ++{ 1, 1980000, 1980000, 0x4, 0x3, 0x0, 0x09, 0x09, 220, 0x42, 160, 5, 183 }, ++{ 2, 2160000, 2160000, 0x4, 0x3, 0x0, 0x09, 0x09, 240, 0x42, 166, 6, 208 }, ++{ 3, 2475000, 2475000, 0x5, 0x3, 0x1, 0x00, 0x07, 275, 0x42, 167, 6, 209 }, ++{ 4, 2700000, 2700000, 0x5, 0x3, 0x1, 0x00, 0x07, 300, 0x42, 188, 6, 230 }, ++{ 4, 2700000, 2700000, 0x5, 0x3, 0x1, 0x00, 0x07, 400, 0x4c, 188, 6, 230 }, ++{ 5, 2970000, 2970000, 0x6, 0x3, 0x1, 0x00, 0x07, 330, 0x42, 183, 6, 225 }, ++{ 6, 3240000, 3240000, 0x6, 0x3, 0x1, 0x00, 0x07, 360, 0x42, 203, 7, 256 }, ++{ 6, 3240000, 3240000, 0x6, 0x3, 0x1, 0x00, 0x07, 480, 0x4c, 203, 7, 256 }, ++{ 7, 3712500, 3712500, 0x4, 0x3, 0x0, 0x07, 0x0F, 550, 0x4c, 212, 7, 257 }, ++{ 8, 3960000, 3960000, 0x5, 0x3, 0x0, 0x07, 0x0F, 440, 0x42, 184, 6, 226 }, ++{ 9, 4320000, 4320000, 0x5, 0x3, 0x1, 0x07, 0x0F, 480, 0x42, 205, 7, 258 }, ++{ 10, 4455000, 4455000, 0x5, 0x3, 0x0, 0x07, 0x0F, 495, 0x42, 219, 7, 272 }, ++{ 10, 4455000, 4455000, 0x5, 0x3, 0x0, 0x07, 0x0F, 660, 0x4c, 219, 7, 272 }, ++{ 11, 4950000, 4950000, 0x6, 0x3, 0x1, 0x00, 0x07, 550, 0x42, 213, 7, 258 }, ++{ 12, 5940000, 5940000, 0x7, 0x3, 0x1, 0x00, 0x07, 660, 0x42, 244, 8, 292 }, ++}; ++ ++enum dp_link_rate { ++ RATE_1_6 = 162000, ++ RATE_2_1 = 216000, ++ RATE_2_4 = 243000, ++ RATE_2_7 = 270000, ++ RATE_3_2 = 324000, ++ RATE_4_3 = 432000, ++ RATE_5_4 = 540000, ++}; ++ ++#define MAX_LINK_RATE RATE_5_4 ++ ++struct phy_pll_reg { ++ u16 val[7]; ++ u32 addr; ++}; ++ ++static const struct phy_pll_reg phy_pll_27m_cfg[] = { ++ /* 1.62 2.16 2.43 2.7 3.24 4.32 5.4 register address */ ++ {{ 0x010e, 0x010e, 0x010e, 0x010e, 0x010e, 0x010e, 0x010e }, CMN_PLL0_VCOCAL_INIT_TMR }, ++ {{ 0x001b, 0x001b, 0x001b, 0x001b, 0x001b, 0x001b, 0x001b }, CMN_PLL0_VCOCAL_ITER_TMR }, ++ {{ 0x30b9, 0x3087, 0x3096, 0x30b4, 0x30b9, 0x3087, 0x30b4 }, CMN_PLL0_VCOCAL_START }, ++ {{ 0x0077, 0x009f, 0x00b3, 0x00c7, 0x0077, 0x009f, 0x00c7 }, CMN_PLL0_INTDIV }, ++ {{ 0xf9da, 0xf7cd, 0xf6c7, 0xf5c1, 0xf9da, 0xf7cd, 0xf5c1 }, CMN_PLL0_FRACDIV }, ++ {{ 0x001e, 0x0028, 0x002d, 0x0032, 0x001e, 0x0028, 0x0032 }, CMN_PLL0_HIGH_THR }, ++ {{ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020 }, CMN_PLL0_DSM_DIAG }, ++ {{ 0x0000, 0x1000, 0x1000, 0x1000, 0x0000, 0x1000, 0x1000 }, CMN_PLLSM0_USER_DEF_CTRL }, ++ {{ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, CMN_DIAG_PLL0_OVRD }, ++ {{ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, CMN_DIAG_PLL0_FBH_OVRD }, ++ {{ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, CMN_DIAG_PLL0_FBL_OVRD }, ++ {{ 0x0006, 0x0007, 0x0007, 0x0007, 0x0006, 0x0007, 0x0007 }, CMN_DIAG_PLL0_V2I_TUNE }, ++ {{ 0x0043, 0x0043, 0x0043, 0x0042, 0x0043, 0x0043, 0x0042 }, CMN_DIAG_PLL0_CP_TUNE }, ++ {{ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008 }, CMN_DIAG_PLL0_LF_PROG }, ++ {{ 0x0100, 0x0001, 0x0001, 0x0001, 0x0100, 0x0001, 0x0001 }, CMN_DIAG_PLL0_PTATIS_TUNE1 }, ++ {{ 0x0007, 0x0001, 0x0001, 0x0001, 0x0007, 0x0001, 0x0001 }, CMN_DIAG_PLL0_PTATIS_TUNE2 }, ++ {{ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020 }, CMN_DIAG_PLL0_TEST_MODE}, ++ {{ 0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016 }, CMN_PSM_CLK_CTRL } ++}; ++ ++static int dp_link_rate_index(u32 rate) ++{ ++ switch (rate) { ++ case RATE_1_6: ++ return 0; ++ case RATE_2_1: ++ return 1; ++ case RATE_2_4: ++ return 2; ++ case RATE_2_7: ++ return 3; ++ case RATE_3_2: ++ return 4; ++ case RATE_4_3: ++ return 5; ++ case RATE_5_4: ++ default: ++ return 6; ++ } ++} ++ ++static int cdns_phy_reg_write(struct cdns_hdptx_phy *cdns_phy, u32 addr, u32 val) ++{ ++ return cdns_mhdp_reg_write(&cdns_phy->base, ADDR_PHY_AFE + (addr << 2), val); ++} ++ ++static u32 cdns_phy_reg_read(struct cdns_hdptx_phy *cdns_phy, u32 addr) ++{ ++ u32 reg32; ++ ++ cdns_mhdp_reg_read(&cdns_phy->base, ADDR_PHY_AFE + (addr << 2), ®32); ++ ++ return reg32; ++} ++ ++static void hdptx_dp_aux_cfg(struct cdns_hdptx_phy *cdns_phy) ++{ ++ /* Power up Aux */ ++ cdns_phy_reg_write(cdns_phy, TXDA_CYA_AUXDA_CYA, 1); ++ ++ cdns_phy_reg_write(cdns_phy, TX_DIG_CTRL_REG_1, 0x3); ++ ndelay(150); ++ cdns_phy_reg_write(cdns_phy, TX_DIG_CTRL_REG_2, 36); ++ ndelay(150); ++ cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_2, 0x0100); ++ ndelay(150); ++ cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_2, 0x0300); ++ ndelay(150); ++ cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_3, 0x0000); ++ ndelay(150); ++ cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_1, 0x2008); ++ ndelay(150); ++ cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_1, 0x2018); ++ ndelay(150); ++ cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_1, 0xa018); ++ ndelay(150); ++ cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_2, 0x030c); ++ ndelay(150); ++ cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_5, 0x0000); ++ ndelay(150); ++ cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_4, 0x1001); ++ ndelay(150); ++ cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_1, 0xa098); ++ ndelay(150); ++ cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_1, 0xa198); ++ ndelay(150); ++ cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_2, 0x030d); ++ ndelay(150); ++ cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_2, 0x030f); ++} ++ ++/* PMA common configuration for 27MHz */ ++static void hdptx_dp_phy_pma_cmn_cfg_27mhz(struct cdns_hdptx_phy *cdns_phy) ++{ ++ u32 num_lanes = cdns_phy->dp.lanes; ++ u16 val; ++ int k; ++ ++ /* Enable PMA input ref clk(CMN_REF_CLK_RCV_EN) */ ++ val = cdns_phy_reg_read(cdns_phy, PHY_PMA_CMN_CTRL1); ++ val &= ~CMA_REF_CLK_RCV_EN_MASK; ++ val |= FIELD_PREP(CMA_REF_CLK_RCV_EN_MASK, CMA_REF_CLK_RCV_EN); ++ cdns_phy_reg_write(cdns_phy, PHY_PMA_CMN_CTRL1, val); ++ ++ /* Startup state machine registers */ ++ cdns_phy_reg_write(cdns_phy, CMN_SSM_BIAS_TMR, 0x0087); ++ cdns_phy_reg_write(cdns_phy, CMN_PLLSM0_PLLEN_TMR, 0x001b); ++ cdns_phy_reg_write(cdns_phy, CMN_PLLSM0_PLLPRE_TMR, 0x0036); ++ cdns_phy_reg_write(cdns_phy, CMN_PLLSM0_PLLVREF_TMR, 0x001b); ++ cdns_phy_reg_write(cdns_phy, CMN_PLLSM0_PLLLOCK_TMR, 0x006c); ++ ++ /* Current calibration registers */ ++ cdns_phy_reg_write(cdns_phy, CMN_ICAL_INIT_TMR, 0x0044); ++ cdns_phy_reg_write(cdns_phy, CMN_ICAL_ITER_TMR, 0x0006); ++ cdns_phy_reg_write(cdns_phy, CMN_ICAL_ADJ_INIT_TMR, 0x0022); ++ cdns_phy_reg_write(cdns_phy, CMN_ICAL_ADJ_ITER_TMR, 0x0006); ++ ++ /* Resistor calibration registers */ ++ cdns_phy_reg_write(cdns_phy, CMN_TXPUCAL_INIT_TMR, 0x0022); ++ cdns_phy_reg_write(cdns_phy, CMN_TXPUCAL_ITER_TMR, 0x0006); ++ cdns_phy_reg_write(cdns_phy, CMN_TXPU_ADJ_INIT_TMR, 0x0022); ++ cdns_phy_reg_write(cdns_phy, CMN_TXPU_ADJ_ITER_TMR, 0x0006); ++ cdns_phy_reg_write(cdns_phy, CMN_TXPDCAL_INIT_TMR, 0x0022); ++ cdns_phy_reg_write(cdns_phy, CMN_TXPDCAL_ITER_TMR, 0x0006); ++ cdns_phy_reg_write(cdns_phy, CMN_TXPD_ADJ_INIT_TMR, 0x0022); ++ cdns_phy_reg_write(cdns_phy, CMN_TXPD_ADJ_ITER_TMR, 0x0006); ++ cdns_phy_reg_write(cdns_phy, CMN_RXCAL_INIT_TMR, 0x0022); ++ cdns_phy_reg_write(cdns_phy, CMN_RXCAL_ITER_TMR, 0x0006); ++ cdns_phy_reg_write(cdns_phy, CMN_RX_ADJ_INIT_TMR, 0x0022); ++ cdns_phy_reg_write(cdns_phy, CMN_RX_ADJ_ITER_TMR, 0x0006); ++ ++ for (k = 0; k < num_lanes; k = k + 1) { ++ /* Power state machine registers */ ++ cdns_phy_reg_write(cdns_phy, XCVR_PSM_CAL_TMR | (k << 9), 0x016d); ++ cdns_phy_reg_write(cdns_phy, XCVR_PSM_A0IN_TMR | (k << 9), 0x016d); ++ /* Transceiver control and diagnostic registers */ ++ cdns_phy_reg_write(cdns_phy, XCVR_DIAG_LANE_FCM_EN_MGN_TMR | (k << 9), 0x00a2); ++ cdns_phy_reg_write(cdns_phy, TX_DIAG_BGREF_PREDRV_DELAY | (k << 9), 0x0097); ++ /* Transmitter receiver detect registers */ ++ cdns_phy_reg_write(cdns_phy, TX_RCVDET_EN_TMR | (k << 9), 0x0a8c); ++ cdns_phy_reg_write(cdns_phy, TX_RCVDET_ST_TMR | (k << 9), 0x0036); ++ } ++ ++ cdns_phy_reg_write(cdns_phy, TX_DIAG_ACYA_0, 1); ++ cdns_phy_reg_write(cdns_phy, TX_DIAG_ACYA_1, 1); ++ cdns_phy_reg_write(cdns_phy, TX_DIAG_ACYA_2, 1); ++ cdns_phy_reg_write(cdns_phy, TX_DIAG_ACYA_3, 1); ++} ++ ++static void hdptx_dp_phy_pma_cmn_pll0_27mhz(struct cdns_hdptx_phy *cdns_phy) ++{ ++ u32 num_lanes = cdns_phy->dp.lanes; ++ u32 link_rate = cdns_phy->dp.link_rate; ++ u16 val; ++ int index, i, k; ++ ++ /* DP PLL data rate 0/1 clock divider value */ ++ val = cdns_phy_reg_read(cdns_phy, PHY_HDP_CLK_CTL); ++ val &= ~PLL_DATA_RATE_CLK_DIV_MASK; ++ if (link_rate <= RATE_2_7) ++ val |= FIELD_PREP(PLL_DATA_RATE_CLK_DIV_MASK, ++ PLL_DATA_RATE_CLK_DIV_HBR); ++ else ++ val |= FIELD_PREP(PLL_DATA_RATE_CLK_DIV_MASK, ++ PLL_DATA_RATE_CLK_DIV_HBR2); ++ cdns_phy_reg_write(cdns_phy, PHY_HDP_CLK_CTL, val); ++ ++ /* High speed clock 0/1 div */ ++ val = cdns_phy_reg_read(cdns_phy, CMN_DIAG_HSCLK_SEL); ++ val &= ~(HSCLK1_SEL_MASK | HSCLK0_SEL_MASK); ++ if (link_rate <= RATE_2_7) { ++ val |= FIELD_PREP(HSCLK1_SEL_MASK, HSCLK_PLL0_DIV2); ++ val |= FIELD_PREP(HSCLK0_SEL_MASK, HSCLK_PLL0_DIV2); ++ } ++ cdns_phy_reg_write(cdns_phy, CMN_DIAG_HSCLK_SEL, val); ++ ++ for (k = 0; k < num_lanes; k++) { ++ val = cdns_phy_reg_read(cdns_phy, (XCVR_DIAG_HSCLK_SEL | (k << 9))); ++ val &= ~HSCLK_SEL_MODE3_MASK; ++ if (link_rate <= RATE_2_7) ++ val |= FIELD_PREP(HSCLK_SEL_MODE3_MASK, HSCLK_SEL_MODE3_HSCLK1); ++ cdns_phy_reg_write(cdns_phy, (XCVR_DIAG_HSCLK_SEL | (k << 9)), val); ++ } ++ ++ /* DP PHY PLL 27MHz configuration */ ++ index = dp_link_rate_index(link_rate); ++ for (i = 0; i < ARRAY_SIZE(phy_pll_27m_cfg); i++) ++ cdns_phy_reg_write(cdns_phy, phy_pll_27m_cfg[i].addr, ++ phy_pll_27m_cfg[i].val[index]); ++ ++ /* Transceiver control and diagnostic registers */ ++ for (k = 0; k < num_lanes; k++) { ++ val = cdns_phy_reg_read(cdns_phy, (XCVR_DIAG_PLLDRC_CTRL | (k << 9))); ++ val &= ~(DPLL_DATA_RATE_DIV_MODE3_MASK | DPLL_CLK_SEL_MODE3); ++ if (link_rate <= RATE_2_7) ++ val |= FIELD_PREP(DPLL_DATA_RATE_DIV_MODE3_MASK, 2); ++ else ++ val |= FIELD_PREP(DPLL_DATA_RATE_DIV_MODE3_MASK, 1); ++ cdns_phy_reg_write(cdns_phy, (XCVR_DIAG_PLLDRC_CTRL | (k << 9)), val); ++ } ++ ++ for (k = 0; k < num_lanes; k = k + 1) { ++ /* Power state machine registers */ ++ cdns_phy_reg_write(cdns_phy, (XCVR_PSM_RCTRL | (k << 9)), 0xbefc); ++ cdns_phy_reg_write(cdns_phy, (TX_PSC_A0 | (k << 9)), 0x6799); ++ cdns_phy_reg_write(cdns_phy, (TX_PSC_A1 | (k << 9)), 0x6798); ++ cdns_phy_reg_write(cdns_phy, (TX_PSC_A2 | (k << 9)), 0x0098); ++ cdns_phy_reg_write(cdns_phy, (TX_PSC_A3 | (k << 9)), 0x0098); ++ /* Receiver calibration power state definition register */ ++ val = cdns_phy_reg_read(cdns_phy, RX_PSC_CAL | (k << 9)); ++ val &= 0xffbb; ++ cdns_phy_reg_write(cdns_phy, (RX_PSC_CAL | (k << 9)), val); ++ val = cdns_phy_reg_read(cdns_phy, RX_PSC_A0 | (k << 9)); ++ val &= 0xffbb; ++ cdns_phy_reg_write(cdns_phy, (RX_PSC_A0 | (k << 9)), val); ++ } ++} ++ ++static void hdptx_dp_phy_ref_clock_type(struct cdns_hdptx_phy *cdns_phy) ++{ ++ u32 val; ++ ++ val = cdns_phy_reg_read(cdns_phy, PHY_PMA_CMN_CTRL1); ++ val &= ~CMA_REF_CLK_SEL_MASK; ++ /* ++ * single ended reference clock (val |= 0x0030); ++ * differential clock (val |= 0x0000); ++ * ++ * for differential clock on the refclk_p and ++ * refclk_m off chip pins: CMN_DIAG_ACYA[8]=1'b1 ++ * cdns_phy_reg_write(cdns_phy, CMN_DIAG_ACYA, 0x0100); ++ */ ++ val |= FIELD_PREP(CMA_REF_CLK_SEL_MASK, 3); ++ cdns_phy_reg_write(cdns_phy, PHY_PMA_CMN_CTRL1, val); ++} ++ ++static int wait_for_ack(struct cdns_hdptx_phy *cdns_phy, u32 reg, u32 mask, ++ const char *err_msg) ++{ ++ u32 val, i; ++ ++ for (i = 0; i < 10; i++) { ++ val = cdns_phy_reg_read(cdns_phy, reg); ++ if (val & mask) ++ return 0; ++ msleep(20); ++ } ++ ++ dev_err(cdns_phy->dev, "%s\n", err_msg); ++ return -ETIMEDOUT; ++} ++ ++static int wait_for_ack_clear(struct cdns_hdptx_phy *cdns_phy, u32 reg, u32 mask, ++ const char *err_msg) ++{ ++ u32 val, i; ++ ++ for (i = 0; i < 10; i++) { ++ val = cdns_phy_reg_read(cdns_phy, reg); ++ if (!(val & mask)) ++ return 0; ++ msleep(20); ++ } ++ ++ dev_err(cdns_phy->dev, "%s\n", err_msg); ++ return -ETIMEDOUT; ++} ++ ++static int hdptx_dp_phy_power_up(struct cdns_hdptx_phy *cdns_phy) ++{ ++ u32 val; ++ int ret; ++ ++ /* Enable HDP PLL's for high speed clocks */ ++ val = cdns_phy_reg_read(cdns_phy, PHY_HDP_CLK_CTL); ++ val |= PLL_EN; ++ cdns_phy_reg_write(cdns_phy, PHY_HDP_CLK_CTL, val); ++ ret = wait_for_ack(cdns_phy, PHY_HDP_CLK_CTL, PLL_READY, ++ "Wait PLL Ack failed"); ++ if (ret < 0) ++ return ret; ++ ++ /* Enable HDP PLL's data rate and full rate clocks out of PMA. */ ++ val = cdns_phy_reg_read(cdns_phy, PHY_HDP_CLK_CTL); ++ val |= PLL_CLK_EN; ++ cdns_phy_reg_write(cdns_phy, PHY_HDP_CLK_CTL, val); ++ ret = wait_for_ack(cdns_phy, PHY_HDP_CLK_CTL, PLL_CLK_EN_ACK, ++ "Wait PLL clock enable ACK failed"); ++ if (ret < 0) ++ return ret; ++ ++ /* Configure PHY in A2 Mode */ ++ cdns_phy_reg_write(cdns_phy, PHY_HDP_MODE_CTRL, POWER_STATE_A2); ++ ret = wait_for_ack(cdns_phy, PHY_HDP_MODE_CTRL, POWER_STATE_A2_ACK, ++ "Wait A2 Ack failed"); ++ if (ret < 0) ++ return ret; ++ ++ /* Configure PHY in A0 mode (PHY must be in the A0 power ++ * state in order to transmit data) ++ */ ++ cdns_phy_reg_write(cdns_phy, PHY_HDP_MODE_CTRL, POWER_STATE_A0); ++ ret = wait_for_ack(cdns_phy, PHY_HDP_MODE_CTRL, POWER_STATE_A0_ACK, ++ "Wait A0 Ack failed"); ++ if (ret < 0) ++ return ret; ++ ++ cdns_phy->power_up = true; ++ ++ return ret; ++} ++ ++static int hdptx_dp_phy_power_down(struct cdns_hdptx_phy *cdns_phy) ++{ ++ u16 val; ++ int ret; ++ ++ if (!cdns_phy->power_up) ++ return 0; ++ ++ /* Place the PHY lanes in the A3 power state. */ ++ cdns_phy_reg_write(cdns_phy, PHY_HDP_MODE_CTRL, POWER_STATE_A3); ++ ret = wait_for_ack(cdns_phy, PHY_HDP_MODE_CTRL, POWER_STATE_A3_ACK, ++ "Wait A3 Ack failed"); ++ if (ret) ++ return ret; ++ ++ /* Disable HDP PLL's data rate and full rate clocks out of PMA. */ ++ val = cdns_phy_reg_read(cdns_phy, PHY_HDP_CLK_CTL); ++ val &= ~PLL_CLK_EN; ++ cdns_phy_reg_write(cdns_phy, PHY_HDP_CLK_CTL, val); ++ ret = wait_for_ack_clear(cdns_phy, PHY_HDP_CLK_CTL, PLL_CLK_EN_ACK, ++ "Wait PLL clock Ack clear failed"); ++ if (ret) ++ return ret; ++ ++ /* Disable HDP PLL's for high speed clocks */ ++ val = cdns_phy_reg_read(cdns_phy, PHY_HDP_CLK_CTL); ++ val &= ~PLL_EN; ++ cdns_phy_reg_write(cdns_phy, PHY_HDP_CLK_CTL, val); ++ ret = wait_for_ack_clear(cdns_phy, PHY_HDP_CLK_CTL, PLL_READY, ++ "Wait PLL Ack clear failed"); ++ if (ret) ++ return ret; ++ ++ cdns_phy->power_up = false; ++ return 0; ++} ++ ++static int cdns_hdptx_dp_configure(struct phy *phy, ++ union phy_configure_opts *opts) ++{ ++ struct cdns_hdptx_phy *cdns_phy = phy_get_drvdata(phy); ++ ++ cdns_phy->dp.link_rate = opts->dp.link_rate; ++ cdns_phy->dp.lanes = opts->dp.lanes; ++ ++ if (cdns_phy->dp.link_rate > MAX_LINK_RATE) { ++ dev_err(cdns_phy->dev, "Link Rate(%d) Not supported\n", cdns_phy->dp.link_rate); ++ return false; ++ } ++ ++ /* Disable phy clock if PHY in power up state */ ++ hdptx_dp_phy_power_down(cdns_phy); ++ ++ if (cdns_phy->ref_clk_rate == REF_CLK_27MHZ) { ++ hdptx_dp_phy_pma_cmn_cfg_27mhz(cdns_phy); ++ hdptx_dp_phy_pma_cmn_pll0_27mhz(cdns_phy); ++ } else { ++ dev_err(cdns_phy->dev, "Not support ref clock rate\n"); ++ } ++ ++ /* PHY power up */ ++ return hdptx_dp_phy_power_up(cdns_phy); ++} ++ ++static bool hdptx_phy_check_alive(struct cdns_hdptx_phy *cdns_phy) ++{ ++ u32 alive, newalive; ++ u8 retries_left = 50; ++ ++ alive = readl(cdns_phy->regs + KEEP_ALIVE); ++ ++ while (retries_left--) { ++ udelay(2); ++ ++ newalive = readl(cdns_phy->regs + KEEP_ALIVE); ++ if (alive == newalive) ++ continue; ++ return true; ++ } ++ return false; ++} ++ ++static int hdptx_clk_enable(struct cdns_hdptx_phy *cdns_phy) ++{ ++ struct device *dev = cdns_phy->dev; ++ u32 ref_clk_rate; ++ int ret; ++ ++ cdns_phy->ref_clk = devm_clk_get(dev, "ref"); ++ if (IS_ERR(cdns_phy->ref_clk)) { ++ dev_err(dev, "phy ref clock not found\n"); ++ return PTR_ERR(cdns_phy->ref_clk); ++ } ++ ++ cdns_phy->apb_clk = devm_clk_get(dev, "apb"); ++ if (IS_ERR(cdns_phy->apb_clk)) { ++ dev_err(dev, "phy apb clock not found\n"); ++ return PTR_ERR(cdns_phy->apb_clk); ++ } ++ ++ ret = clk_prepare_enable(cdns_phy->ref_clk); ++ if (ret) { ++ dev_err(cdns_phy->dev, "Failed to prepare ref clock\n"); ++ return ret; ++ } ++ ++ ref_clk_rate = clk_get_rate(cdns_phy->ref_clk); ++ if (!ref_clk_rate) { ++ dev_err(cdns_phy->dev, "Failed to get ref clock rate\n"); ++ goto err_ref_clk; ++ } ++ ++ if (ref_clk_rate == REF_CLK_27MHZ) { ++ cdns_phy->ref_clk_rate = ref_clk_rate; ++ } else { ++ dev_err(cdns_phy->dev, "Not support Ref Clock Rate(%dHz)\n", ref_clk_rate); ++ goto err_ref_clk; ++ } ++ ++ ret = clk_prepare_enable(cdns_phy->apb_clk); ++ if (ret) { ++ dev_err(cdns_phy->dev, "Failed to prepare apb clock\n"); ++ goto err_ref_clk; ++ } ++ ++ return 0; ++ ++err_ref_clk: ++ clk_disable_unprepare(cdns_phy->ref_clk); ++ return -EINVAL; ++} ++ ++static void hdptx_clk_disable(struct cdns_hdptx_phy *cdns_phy) ++{ ++ clk_disable_unprepare(cdns_phy->apb_clk); ++ clk_disable_unprepare(cdns_phy->ref_clk); ++} ++ ++static void hdptx_hdmi_arc_config(struct cdns_hdptx_phy *cdns_phy) ++{ ++ u16 txpu_calib_code; ++ u16 txpd_calib_code; ++ u16 txpu_adj_calib_code; ++ u16 txpd_adj_calib_code; ++ u16 prev_calib_code; ++ u16 new_calib_code; ++ u16 rdata; ++ ++ /* Power ARC */ ++ cdns_phy_reg_write(cdns_phy, TXDA_CYA_AUXDA_CYA, 0x0001); ++ ++ prev_calib_code = cdns_phy_reg_read(cdns_phy, TX_DIG_CTRL_REG_2); ++ txpu_calib_code = cdns_phy_reg_read(cdns_phy, CMN_TXPUCAL_CTRL); ++ txpd_calib_code = cdns_phy_reg_read(cdns_phy, CMN_TXPDCAL_CTRL); ++ txpu_adj_calib_code = cdns_phy_reg_read(cdns_phy, CMN_TXPU_ADJ_CTRL); ++ txpd_adj_calib_code = cdns_phy_reg_read(cdns_phy, CMN_TXPD_ADJ_CTRL); ++ ++ new_calib_code = ((txpu_calib_code + txpd_calib_code) / 2) ++ + txpu_adj_calib_code + txpd_adj_calib_code; ++ ++ if (new_calib_code != prev_calib_code) { ++ rdata = cdns_phy_reg_read(cdns_phy, TX_ANA_CTRL_REG_1); ++ rdata &= 0xdfff; ++ cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_1, rdata); ++ cdns_phy_reg_write(cdns_phy, TX_DIG_CTRL_REG_2, new_calib_code); ++ mdelay(10); ++ rdata |= 0x2000; ++ cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_1, rdata); ++ usleep_range(150, 250); ++ } ++ ++ cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_2, 0x0100); ++ usleep_range(100, 200); ++ cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_2, 0x0300); ++ usleep_range(100, 200); ++ cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_3, 0x0000); ++ usleep_range(100, 200); ++ cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_1, 0x2008); ++ usleep_range(100, 200); ++ cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_1, 0x2018); ++ usleep_range(100, 200); ++ cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_1, 0x2098); ++ cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_2, 0x030c); ++ cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_5, 0x0010); ++ usleep_range(100, 200); ++ cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_4, 0x4001); ++ mdelay(5); ++ cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_1, 0x2198); ++ mdelay(5); ++ cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_2, 0x030d); ++ usleep_range(100, 200); ++ cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_2, 0x030f); ++} ++ ++static void hdptx_hdmi_phy_set_vswing(struct cdns_hdptx_phy *cdns_phy) ++{ ++ u32 k; ++ const u32 num_lanes = 4; ++ ++ for (k = 0; k < num_lanes; k++) { ++ cdns_phy_reg_write(cdns_phy, (TX_DIAG_TX_DRV | (k << 9)), ++ TX_DRIVER_PROG_BOOST_ENABLE | ++ FIELD_PREP(TX_DRIVER_PROG_BOOST_LEVEL_MASK, 3) | ++ TX_DRIVER_LDO_BG_DEPENDENT_REF_ENABLE | ++ TX_DRIVER_LDO_BANDGAP_REF_ENABLE); ++ cdns_phy_reg_write(cdns_phy, (TX_TXCC_CPOST_MULT_00_0 | (k << 9)), 0x0); ++ cdns_phy_reg_write(cdns_phy, (TX_TXCC_CAL_SCLR_MULT_0 | (k << 9)), ++ SCALED_RESISTOR_CALIBRATION_CODE_ADD | ++ RESISTOR_CAL_MULT_VAL_32_128); ++ } ++} ++ ++static int hdptx_hdmi_phy_config(struct cdns_hdptx_phy *cdns_phy, ++ const struct hdptx_hdmi_ctrl *p_ctrl_table, ++ const struct hdptx_hdmi_pll_tuning *p_pll_table, ++ bool pclk_in) ++{ ++ const u32 num_lanes = 4; ++ u32 val, k; ++ int ret; ++ ++ /* enable PHY isolation mode only for CMN */ ++ cdns_phy_reg_write(cdns_phy, PHY_PMA_ISOLATION_CTRL, 0xd000); ++ ++ /* set cmn_pll0_clk_datart1_div/cmn_pll0_clk_datart0_div dividers */ ++ val = cdns_phy_reg_read(cdns_phy, PHY_PMA_ISO_PLL_CTRL1); ++ val &= ~CMN_PLL0_CLK_DATART_DIV_MASK; ++ val |= FIELD_PREP(CMN_PLL0_CLK_DATART_DIV_MASK, 0x12); ++ cdns_phy_reg_write(cdns_phy, PHY_PMA_ISO_PLL_CTRL1, val); ++ ++ /* assert PHY reset from isolation register */ ++ cdns_phy_reg_write(cdns_phy, PHY_ISO_CMN_CTRL, 0x0000); ++ /* assert PMA CMN reset */ ++ cdns_phy_reg_write(cdns_phy, PHY_PMA_ISO_CMN_CTRL, 0x0000); ++ ++ /* register XCVR_DIAG_BIDI_CTRL */ ++ for (k = 0; k < num_lanes; k++) ++ cdns_phy_reg_write(cdns_phy, XCVR_DIAG_BIDI_CTRL | (k << 9), 0x00ff); ++ ++ /* Describing Task phy_cfg_hdp */ ++ val = cdns_phy_reg_read(cdns_phy, PHY_PMA_CMN_CTRL1); ++ val &= ~CMA_REF_CLK_RCV_EN_MASK; ++ val |= FIELD_PREP(CMA_REF_CLK_RCV_EN_MASK, CMA_REF_CLK_RCV_EN); ++ cdns_phy_reg_write(cdns_phy, PHY_PMA_CMN_CTRL1, val); ++ ++ /* PHY Registers */ ++ val = cdns_phy_reg_read(cdns_phy, PHY_PMA_CMN_CTRL1); ++ val &= ~CMA_REF_CLK_DIG_DIV_MASK; ++ val |= FIELD_PREP(CMA_REF_CLK_DIG_DIV_MASK, p_ctrl_table->cmn_ref_clk_dig_div); ++ cdns_phy_reg_write(cdns_phy, PHY_PMA_CMN_CTRL1, val); ++ ++ val = cdns_phy_reg_read(cdns_phy, PHY_HDP_CLK_CTL); ++ val &= ~PLL_DATA_RATE_CLK_DIV_MASK; ++ val |= FIELD_PREP(PLL_DATA_RATE_CLK_DIV_MASK, ++ PLL_DATA_RATE_CLK_DIV_HBR2); ++ cdns_phy_reg_write(cdns_phy, PHY_HDP_CLK_CTL, val); ++ ++ /* Common control module control and diagnostic registers */ ++ val = cdns_phy_reg_read(cdns_phy, CMN_CDIAG_REFCLK_CTRL); ++ val &= ~DIG_REF_CLK_DIV_SCALER_MASK; ++ val |= FIELD_PREP(DIG_REF_CLK_DIV_SCALER_MASK, p_ctrl_table->ref_clk_divider_scaler); ++ val |= REFCLK_TERMINATION_EN_OVERRIDE_EN | REFCLK_TERMINATION_EN_OVERRIDE; ++ cdns_phy_reg_write(cdns_phy, CMN_CDIAG_REFCLK_CTRL, val); ++ ++ /* High speed clock used */ ++ val = cdns_phy_reg_read(cdns_phy, CMN_DIAG_HSCLK_SEL); ++ val &= ~(HSCLK1_SEL_MASK | HSCLK0_SEL_MASK); ++ val |= FIELD_PREP(HSCLK1_SEL_MASK, (p_ctrl_table->cmnda_hs_clk_1_sel >> 1)); ++ val |= FIELD_PREP(HSCLK0_SEL_MASK, (p_ctrl_table->cmnda_hs_clk_0_sel >> 1)); ++ cdns_phy_reg_write(cdns_phy, CMN_DIAG_HSCLK_SEL, val); ++ ++ for (k = 0; k < num_lanes; k++) { ++ val = cdns_phy_reg_read(cdns_phy, (XCVR_DIAG_HSCLK_SEL | (k << 9))); ++ val &= ~HSCLK_SEL_MODE3_MASK; ++ val |= FIELD_PREP(HSCLK_SEL_MODE3_MASK, ++ (p_ctrl_table->cmnda_hs_clk_0_sel >> 1)); ++ cdns_phy_reg_write(cdns_phy, (XCVR_DIAG_HSCLK_SEL | (k << 9)), val); ++ } ++ ++ /* PLL 0 control state machine registers */ ++ val = p_ctrl_table->vco_ring_select << 12; ++ cdns_phy_reg_write(cdns_phy, CMN_PLLSM0_USER_DEF_CTRL, val); ++ ++ if (pclk_in) { ++ val = 0x30a0; ++ } else { ++ val = cdns_phy_reg_read(cdns_phy, CMN_PLL0_VCOCAL_START); ++ val &= ~VCO_CALIB_CODE_START_POINT_VAL_MASK; ++ val |= FIELD_PREP(VCO_CALIB_CODE_START_POINT_VAL_MASK, ++ p_pll_table->vco_cal_code); ++ } ++ cdns_phy_reg_write(cdns_phy, CMN_PLL0_VCOCAL_START, val); ++ ++ cdns_phy_reg_write(cdns_phy, CMN_PLL0_VCOCAL_INIT_TMR, 0x0064); ++ cdns_phy_reg_write(cdns_phy, CMN_PLL0_VCOCAL_ITER_TMR, 0x000a); ++ ++ /* Common functions control and diagnostics registers */ ++ val = p_ctrl_table->cmnda_pll0_hs_sym_div_sel << 8; ++ val |= p_ctrl_table->cmnda_pll0_ip_div; ++ cdns_phy_reg_write(cdns_phy, CMN_DIAG_PLL0_INCLK_CTRL, val); ++ ++ cdns_phy_reg_write(cdns_phy, CMN_DIAG_PLL0_OVRD, 0x0000); ++ ++ val = p_ctrl_table->cmnda_pll0_fb_div_high; ++ val |= PLL_FEEDBACK_DIV_HI_OVERRIDE_EN; ++ cdns_phy_reg_write(cdns_phy, CMN_DIAG_PLL0_FBH_OVRD, val); ++ ++ val = p_ctrl_table->cmnda_pll0_fb_div_low; ++ val |= PLL_FEEDBACK_DIV_LO_OVERRIDE_EN; ++ cdns_phy_reg_write(cdns_phy, CMN_DIAG_PLL0_FBL_OVRD, val); ++ ++ if (!pclk_in) { ++ val = p_ctrl_table->cmnda_pll0_pxdiv_low; ++ cdns_phy_reg_write(cdns_phy, CMN_DIAG_PLL0_PXL_DIVL, val); ++ ++ val = p_ctrl_table->cmnda_pll0_pxdiv_high; ++ val |= PLL_PCLK_DIV_EN; ++ cdns_phy_reg_write(cdns_phy, CMN_DIAG_PLL0_PXL_DIVH, val); ++ } ++ ++ val = p_pll_table->volt_to_current_coarse; ++ val |= (p_pll_table->volt_to_current) << 4; ++ cdns_phy_reg_write(cdns_phy, CMN_DIAG_PLL0_V2I_TUNE, val); ++ ++ val = p_pll_table->charge_pump_gain; ++ cdns_phy_reg_write(cdns_phy, CMN_DIAG_PLL0_CP_TUNE, val); ++ ++ cdns_phy_reg_write(cdns_phy, CMN_DIAG_PLL0_LF_PROG, 0x0008); ++ ++ val = p_pll_table->pmos_ctrl; ++ val |= (p_pll_table->ndac_ctrl) << 8; ++ cdns_phy_reg_write(cdns_phy, CMN_DIAG_PLL0_PTATIS_TUNE1, val); ++ ++ val = p_pll_table->ptat_ndac_ctrl; ++ cdns_phy_reg_write(cdns_phy, CMN_DIAG_PLL0_PTATIS_TUNE2, val); ++ ++ if (pclk_in) ++ cdns_phy_reg_write(cdns_phy, CMN_DIAG_PLL0_TEST_MODE, 0x0022); ++ else ++ cdns_phy_reg_write(cdns_phy, CMN_DIAG_PLL0_TEST_MODE, 0x0020); ++ ++ cdns_phy_reg_write(cdns_phy, CMN_PSM_CLK_CTRL, 0x0016); ++ ++ /* Transceiver control and diagnostic registers */ ++ for (k = 0; k < num_lanes; k++) { ++ val = cdns_phy_reg_read(cdns_phy, (XCVR_DIAG_PLLDRC_CTRL | (k << 9))); ++ val &= ~DPLL_CLK_SEL_MODE3; ++ cdns_phy_reg_write(cdns_phy, (XCVR_DIAG_PLLDRC_CTRL | (k << 9)), val); ++ } ++ ++ for (k = 0; k < num_lanes; k++) { ++ val = cdns_phy_reg_read(cdns_phy, (TX_DIAG_TX_CTRL | (k << 9))); ++ val &= ~TX_IF_SUBRATE_MODE3_MASK; ++ val |= FIELD_PREP(TX_IF_SUBRATE_MODE3_MASK, ++ (p_ctrl_table->hsclk_div_tx_sub_rate >> 1)); ++ cdns_phy_reg_write(cdns_phy, (TX_DIAG_TX_CTRL | (k << 9)), val); ++ } ++ ++ val = cdns_phy_reg_read(cdns_phy, PHY_PMA_CMN_CTRL1); ++ val &= ~CMA_REF_CLK_SEL_MASK; ++ /* ++ * single ended reference clock (val |= 0x0030); ++ * differential clock (val |= 0x0000); ++ * for differential clock on the refclk_p and ++ * refclk_m off chip pins: CMN_DIAG_ACYA[8]=1'b1 ++ * cdns_phy_reg_write(cdns_phy, CMN_DIAG_ACYA, 0x0100); ++ */ ++ val |= FIELD_PREP(CMA_REF_CLK_SEL_MASK, 3); ++ cdns_phy_reg_write(cdns_phy, PHY_PMA_CMN_CTRL1, val); ++ ++ /* Deassert PHY reset */ ++ cdns_phy_reg_write(cdns_phy, PHY_ISO_CMN_CTRL, 0x0001); ++ cdns_phy_reg_write(cdns_phy, PHY_PMA_ISO_CMN_CTRL, 0x0003); ++ ++ /* Power state machine registers */ ++ for (k = 0; k < num_lanes; k++) ++ cdns_phy_reg_write(cdns_phy, XCVR_PSM_RCTRL | (k << 9), 0xfefc); ++ ++ /* Assert cmn_macro_pwr_en */ ++ cdns_phy_reg_write(cdns_phy, PHY_PMA_ISO_CMN_CTRL, 0x0013); ++ ++ /* wait for cmn_macro_pwr_en_ack */ ++ ret = wait_for_ack(cdns_phy, PHY_PMA_ISO_CMN_CTRL, CMN_MACRO_PWR_EN_ACK, ++ "MA output macro power up failed"); ++ if (ret < 0) ++ return ret; ++ ++ /* wait for cmn_ready */ ++ ret = wait_for_ack(cdns_phy, PHY_PMA_CMN_CTRL1, CMN_READY, ++ "PMA output ready failed"); ++ if (ret < 0) ++ return ret; ++ ++ for (k = 0; k < num_lanes; k++) { ++ cdns_phy_reg_write(cdns_phy, TX_PSC_A0 | (k << 9), 0x6791); ++ cdns_phy_reg_write(cdns_phy, TX_PSC_A1 | (k << 9), 0x6790); ++ cdns_phy_reg_write(cdns_phy, TX_PSC_A2 | (k << 9), 0x0090); ++ cdns_phy_reg_write(cdns_phy, TX_PSC_A3 | (k << 9), 0x0090); ++ ++ val = cdns_phy_reg_read(cdns_phy, RX_PSC_CAL | (k << 9)); ++ val &= 0xffbb; ++ cdns_phy_reg_write(cdns_phy, RX_PSC_CAL | (k << 9), val); ++ ++ val = cdns_phy_reg_read(cdns_phy, RX_PSC_A0 | (k << 9)); ++ val &= 0xffbb; ++ cdns_phy_reg_write(cdns_phy, RX_PSC_A0 | (k << 9), val); ++ } ++ ++ return 0; ++} ++ ++static int hdptx_hdmi_phy_cfg(struct cdns_hdptx_phy *cdns_phy, unsigned long long char_rate) ++{ ++ const struct hdptx_hdmi_ctrl *p_ctrl_table; ++ const struct hdptx_hdmi_pll_tuning *p_pll_table; ++ const u32 refclk_freq_khz = cdns_phy->ref_clk_rate / 1000; ++ const bool pclk_in = false; ++ u32 char_rate_khz = char_rate / 1000; ++ u32 vco_freq, rate; ++ u32 div_total, i; ++ ++ dev_dbg(cdns_phy->dev, "character clock: %d KHz\n ", char_rate_khz); ++ ++ /* Get right row from the ctrl_table table. ++ * check the character rate. ++ */ ++ for (i = 0; i < ARRAY_SIZE(pixel_clk_output_ctrl_table); i++) { ++ rate = pixel_clk_output_ctrl_table[i].feedback_factor * ++ pixel_clk_output_ctrl_table[i].pixel_clk_freq_min / 1000; ++ if (char_rate_khz == rate) { ++ p_ctrl_table = &pixel_clk_output_ctrl_table[i]; ++ break; ++ } ++ } ++ if (i == ARRAY_SIZE(pixel_clk_output_ctrl_table)) { ++ dev_warn(cdns_phy->dev, ++ "char clk (%d KHz) not supported\n", char_rate_khz); ++ return -EINVAL; ++ } ++ ++ div_total = p_ctrl_table->pll_fb_div_total; ++ vco_freq = refclk_freq_khz * div_total / p_ctrl_table->cmnda_pll0_ip_div; ++ ++ /* Get right row from the pixel_clk_output_pll_table table. ++ * Check if vco_freq_khz and feedback_div_total ++ * column matching with pixel_clk_output_pll_table. ++ */ ++ for (i = 0; i < ARRAY_SIZE(pixel_clk_output_pll_table); i++) { ++ if (vco_freq == pixel_clk_output_pll_table[i].vco_freq_min && ++ div_total == pixel_clk_output_pll_table[i].feedback_div_total) { ++ p_pll_table = &pixel_clk_output_pll_table[i]; ++ break; ++ } ++ } ++ if (i == ARRAY_SIZE(pixel_clk_output_pll_table)) { ++ dev_warn(cdns_phy->dev, "VCO (%d KHz) not supported\n", vco_freq); ++ return -EINVAL; ++ } ++ dev_dbg(cdns_phy->dev, "VCO frequency is (%d KHz)\n", vco_freq); ++ ++ return hdptx_hdmi_phy_config(cdns_phy, p_ctrl_table, p_pll_table, pclk_in); ++} ++ ++static int hdptx_hdmi_phy_power_up(struct cdns_hdptx_phy *cdns_phy) ++{ ++ int ret; ++ ++ /* set Power State to A2 */ ++ cdns_phy_reg_write(cdns_phy, PHY_HDP_MODE_CTRL, POWER_STATE_A2); ++ ++ cdns_phy_reg_write(cdns_phy, TX_DIAG_ACYA_0, 1); ++ cdns_phy_reg_write(cdns_phy, TX_DIAG_ACYA_1, 1); ++ cdns_phy_reg_write(cdns_phy, TX_DIAG_ACYA_2, 1); ++ cdns_phy_reg_write(cdns_phy, TX_DIAG_ACYA_3, 1); ++ ++ ret = wait_for_ack(cdns_phy, PHY_HDP_MODE_CTRL, POWER_STATE_A2_ACK, ++ "Wait A2 Ack failed"); ++ if (ret < 0) ++ return ret; ++ ++ /* Power up ARC */ ++ hdptx_hdmi_arc_config(cdns_phy); ++ ++ /* Configure PHY in A0 mode (PHY must be in the A0 power ++ * state in order to transmit data) ++ */ ++ cdns_phy_reg_write(cdns_phy, PHY_HDP_MODE_CTRL, POWER_STATE_A0); ++ ++ return wait_for_ack(cdns_phy, PHY_HDP_MODE_CTRL, POWER_STATE_A0_ACK, ++ "Wait A0 Ack failed"); ++} ++ ++static int hdptx_hdmi_phy_power_down(struct cdns_hdptx_phy *cdns_phy) ++{ ++ u32 val; ++ ++ val = cdns_phy_reg_read(cdns_phy, PHY_HDP_MODE_CTRL); ++ val &= ~(POWER_STATE_A0 | POWER_STATE_A1 | POWER_STATE_A2 | POWER_STATE_A3); ++ /* PHY_DP_MODE_CTL set to A3 power state */ ++ cdns_phy_reg_write(cdns_phy, PHY_HDP_MODE_CTRL, val | POWER_STATE_A3); ++ ++ return wait_for_ack(cdns_phy, PHY_HDP_MODE_CTRL, POWER_STATE_A3_ACK, ++ "Wait A3 Ack failed"); ++} ++ ++static int cdns_hdptx_phy_on(struct phy *phy) ++{ ++ struct cdns_hdptx_phy *cdns_phy = phy_get_drvdata(phy); ++ ++ if (phy->attrs.mode == PHY_MODE_DP) ++ return hdptx_dp_phy_power_up(cdns_phy); ++ else ++ return hdptx_hdmi_phy_power_up(cdns_phy); ++} ++ ++static int cdns_hdptx_phy_off(struct phy *phy) ++{ ++ struct cdns_hdptx_phy *cdns_phy = phy_get_drvdata(phy); ++ ++ if (phy->attrs.mode == PHY_MODE_DP) ++ return hdptx_dp_phy_power_down(cdns_phy); ++ else ++ return hdptx_hdmi_phy_power_down(cdns_phy); ++ return 0; ++} ++ ++static int ++cdns_hdptx_phy_valid(struct phy *phy, enum phy_mode mode, ++ int submode, union phy_configure_opts *opts) ++{ ++ u32 rate = opts->hdmi.tmds_char_rate / 1000; ++ int i; ++ ++ if (mode == PHY_MODE_DP) ++ return 0; ++ ++ for (i = 0; i < ARRAY_SIZE(pixel_clk_output_ctrl_table); i++) ++ if (rate == pixel_clk_output_ctrl_table[i].pixel_clk_freq_min) ++ return 0; ++ ++ return -EINVAL; ++} ++ ++static int cdns_hdptx_phy_init(struct phy *phy) ++{ ++ return 0; ++} ++ ++static int cdns_hdptx_phy_set_mode(struct phy *phy, enum phy_mode mode, int submode) ++{ ++ struct cdns_hdptx_phy *cdns_phy = phy_get_drvdata(phy); ++ int ret = 0; ++ ++ if (mode == PHY_MODE_DP) { ++ hdptx_dp_phy_ref_clock_type(cdns_phy); ++ ++ /* PHY power up */ ++ ret = hdptx_dp_phy_power_up(cdns_phy); ++ if (ret < 0) ++ return ret; ++ ++ hdptx_dp_aux_cfg(cdns_phy); ++ } else if (mode != PHY_MODE_HDMI) { ++ dev_err(&phy->dev, "Invalid PHY mode: %u\n", mode); ++ return -EINVAL; ++ } ++ ++ return ret; ++} ++ ++static int cdns_hdptx_hdmi_configure(struct phy *phy, ++ union phy_configure_opts *opts) ++{ ++ struct cdns_hdptx_phy *cdns_phy = phy_get_drvdata(phy); ++ int ret; ++ ++ cdns_phy->hdmi.tmds_char_rate = opts->hdmi.tmds_char_rate; ++ ++ /* Check HDMI FW alive before HDMI PHY init */ ++ ret = hdptx_phy_check_alive(cdns_phy); ++ if (!ret) { ++ dev_err(cdns_phy->dev, "NO HDMI FW running\n"); ++ return -ENXIO; ++ } ++ ++ /* Configure PHY */ ++ if (hdptx_hdmi_phy_cfg(cdns_phy, cdns_phy->hdmi.tmds_char_rate) < 0) { ++ dev_err(cdns_phy->dev, "failed to set phy pclock\n"); ++ return -EINVAL; ++ } ++ ++ ret = hdptx_hdmi_phy_power_up(cdns_phy); ++ if (ret < 0) ++ return ret; ++ ++ hdptx_hdmi_phy_set_vswing(cdns_phy); ++ ++ return 0; ++} ++ ++static int cdns_hdptx_configure(struct phy *phy, ++ union phy_configure_opts *opts) ++{ ++ if (phy->attrs.mode == PHY_MODE_DP) ++ return cdns_hdptx_dp_configure(phy, opts); ++ else ++ return cdns_hdptx_hdmi_configure(phy, opts); ++} ++ ++static const struct phy_ops cdns_hdptx_phy_ops = { ++ .init = cdns_hdptx_phy_init, ++ .set_mode = cdns_hdptx_phy_set_mode, ++ .configure = cdns_hdptx_configure, ++ .power_on = cdns_hdptx_phy_on, ++ .power_off = cdns_hdptx_phy_off, ++ .validate = cdns_hdptx_phy_valid, ++ .owner = THIS_MODULE, ++}; ++ ++static int cdns_hdptx_phy_probe(struct platform_device *pdev) ++{ ++ struct cdns_hdptx_phy *cdns_phy; ++ struct device *dev = &pdev->dev; ++ struct device_node *node = dev->of_node; ++ struct phy_provider *phy_provider; ++ struct resource *res; ++ struct phy *phy; ++ int ret; ++ ++ cdns_phy = devm_kzalloc(dev, sizeof(*cdns_phy), GFP_KERNEL); ++ if (!cdns_phy) ++ return -ENOMEM; ++ ++ dev_set_drvdata(dev, cdns_phy); ++ cdns_phy->dev = dev; ++ mutex_init(&cdns_phy->mbox_mutex); ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) ++ return -ENODEV; ++ cdns_phy->regs = devm_ioremap(dev, res->start, resource_size(res)); ++ if (IS_ERR(cdns_phy->regs)) ++ return PTR_ERR(cdns_phy->regs); ++ ++ phy = devm_phy_create(dev, node, &cdns_hdptx_phy_ops); ++ if (IS_ERR(phy)) ++ return PTR_ERR(phy); ++ ++ cdns_phy->phy = phy; ++ phy_set_drvdata(phy, cdns_phy); ++ ++ /* init base struct for access mhdp mailbox */ ++ cdns_phy->base.dev = cdns_phy->dev; ++ cdns_phy->base.regs = cdns_phy->regs; ++ cdns_phy->base.mbox_mutex = &cdns_phy->mbox_mutex; ++ ++ ret = hdptx_clk_enable(cdns_phy); ++ if (ret) { ++ dev_err(dev, "Init clk fail\n"); ++ return -EINVAL; ++ } ++ ++ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); ++ if (IS_ERR(phy_provider)) { ++ ret = PTR_ERR(phy_provider); ++ goto clk_disable; ++ } ++ ++ dev_dbg(dev, "probe success!\n"); ++ ++ return 0; ++ ++clk_disable: ++ hdptx_clk_disable(cdns_phy); ++ ++ return -EINVAL; ++} ++ ++static void cdns_hdptx_phy_remove(struct platform_device *pdev) ++{ ++ struct cdns_hdptx_phy *cdns_phy = platform_get_drvdata(pdev); ++ ++ hdptx_clk_disable(cdns_phy); ++} ++ ++static const struct of_device_id cdns_hdptx_phy_of_match[] = { ++ {.compatible = "fsl,imx8mq-hdptx-phy" }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, cdns_hdptx_phy_of_match); ++ ++static struct platform_driver cdns_hdptx_phy_driver = { ++ .probe = cdns_hdptx_phy_probe, ++ .remove = cdns_hdptx_phy_remove, ++ .driver = { ++ .name = "cdns-hdptx-phy", ++ .of_match_table = cdns_hdptx_phy_of_match, ++ } ++}; ++module_platform_driver(cdns_hdptx_phy_driver); ++ ++MODULE_AUTHOR("Sandor Yu "); ++MODULE_DESCRIPTION("Cadence HDP-TX DP/HDMI PHY driver"); ++MODULE_LICENSE("GPL"); + +From patchwork Tue Jul 2 12:22:39 2024 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [v16,7/8] arm64: dts: imx8mq: Add DCSS + HDMI/DP display pipeline +From: Sandor Yu +X-Patchwork-Id: 601669 +Message-Id: + <727edb97281798454951ddf03cfdab5a428bc9de.1719903904.git.Sandor.yu@nxp.com> +To: dmitry.baryshkov@linaro.org, andrzej.hajda@intel.com, + neil.armstrong@linaro.org, Laurent.pinchart@ideasonboard.com, + jonas@kwiboo.se, jernej.skrabec@gmail.com, airlied@gmail.com, + daniel@ffwll.ch, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, + shawnguo@kernel.org, s.hauer@pengutronix.de, festevam@gmail.com, + vkoul@kernel.org, dri-devel@lists.freedesktop.org, + devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, + linux-kernel@vger.kernel.org, linux-phy@lists.infradead.org, + mripard@kernel.org +Cc: kernel@pengutronix.de, linux-imx@nxp.com, Sandor.yu@nxp.com, + oliver.brown@nxp.com, alexander.stein@ew.tq-group.com, sam@ravnborg.org +Date: Tue, 2 Jul 2024 20:22:39 +0800 + +From: Alexander Stein + +This adds DCSS + MHDP + MHDP PHY nodes. PHY mode (DP/HDMI) is selected +by the connector type connected to mhdp port@1 endpoint. + +Signed-off-by: Alexander Stein +--- + arch/arm64/boot/dts/freescale/imx8mq.dtsi | 68 +++++++++++++++++++++++ + 1 file changed, 68 insertions(+) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mq.dtsi b/arch/arm64/boot/dts/freescale/imx8mq.dtsi +index e03186bbc415..6bd7d2b2aba2 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mq.dtsi ++++ b/arch/arm64/boot/dts/freescale/imx8mq.dtsi +@@ -1602,6 +1602,74 @@ aips4: bus@32c00000 { /* AIPS4 */ + #size-cells = <1>; + ranges = <0x32c00000 0x32c00000 0x400000>; + ++ mdhp_phy: phy@32c00000 { ++ compatible = "fsl,imx8mq-hdptx-phy"; ++ reg = <0x32c00000 0x100000>; ++ #phy-cells = <0>; ++ clocks = <&hdmi_phy_27m>, <&clk IMX8MQ_CLK_DISP_APB_ROOT>; ++ clock-names = "ref", "apb"; ++ }; ++ ++ mhdp: bridge@32c00000 { ++ compatible = "fsl,imx8mq-mhdp8501"; ++ reg = <0x32c00000 0x100000>; ++ interrupts = , ++ ; ++ interrupt-names = "plug_in", "plug_out"; ++ clocks = <&clk IMX8MQ_CLK_DISP_APB_ROOT>; ++ phys = <&mdhp_phy>; ++ status = "disabled"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ reg = <0>; ++ ++ mhdp_in: endpoint { ++ remote-endpoint = <&dcss_out>; ++ }; ++ }; ++ ++ port@1 { ++ reg = <1>; ++ ++ mhdp_out: endpoint { ++ }; ++ }; ++ }; ++ }; ++ ++ dcss: display-controller@32e00000 { ++ compatible = "nxp,imx8mq-dcss"; ++ reg = <0x32e00000 0x2d000>, <0x32e2f000 0x1000>; ++ interrupt-parent = <&irqsteer>; ++ interrupts = <6>, <8>, <9>; ++ interrupt-names = "ctxld", "ctxld_kick", "vblank"; ++ clocks = <&clk IMX8MQ_CLK_DISP_APB_ROOT>, ++ <&clk IMX8MQ_CLK_DISP_AXI_ROOT>, ++ <&clk IMX8MQ_CLK_DISP_RTRM_ROOT>, ++ <&clk IMX8MQ_VIDEO2_PLL_OUT>, ++ <&clk IMX8MQ_CLK_DISP_DTRC>; ++ clock-names = "apb", "axi", "rtrm", "pix", "dtrc"; ++ assigned-clocks = <&clk IMX8MQ_CLK_DISP_AXI>, ++ <&clk IMX8MQ_CLK_DISP_RTRM>, ++ <&clk IMX8MQ_VIDEO2_PLL1_REF_SEL>; ++ assigned-clock-parents = <&clk IMX8MQ_SYS1_PLL_800M>, ++ <&clk IMX8MQ_SYS1_PLL_800M>, ++ <&clk IMX8MQ_CLK_27M>; ++ assigned-clock-rates = <800000000>, ++ <400000000>; ++ status = "disabled"; ++ ++ port { ++ dcss_out: endpoint { ++ remote-endpoint = <&mhdp_in>; ++ }; ++ }; ++ }; ++ + irqsteer: interrupt-controller@32e2d000 { + compatible = "fsl,imx8m-irqsteer", "fsl,imx-irqsteer"; + reg = <0x32e2d000 0x1000>; + +From patchwork Tue Jul 2 12:22:40 2024 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +Subject: [v16,8/8] arm64: dts: imx8mq: tqma8mq-mba8mx: Enable HDMI support +From: Sandor Yu +X-Patchwork-Id: 601670 +Message-Id: + +To: dmitry.baryshkov@linaro.org, andrzej.hajda@intel.com, + neil.armstrong@linaro.org, Laurent.pinchart@ideasonboard.com, + jonas@kwiboo.se, jernej.skrabec@gmail.com, airlied@gmail.com, + daniel@ffwll.ch, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, + shawnguo@kernel.org, s.hauer@pengutronix.de, festevam@gmail.com, + vkoul@kernel.org, dri-devel@lists.freedesktop.org, + devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, + linux-kernel@vger.kernel.org, linux-phy@lists.infradead.org, + mripard@kernel.org +Cc: kernel@pengutronix.de, linux-imx@nxp.com, Sandor.yu@nxp.com, + oliver.brown@nxp.com, alexander.stein@ew.tq-group.com, sam@ravnborg.org +Date: Tue, 2 Jul 2024 20:22:40 +0800 + +From: Alexander Stein + +Add HDMI connector and connect it to MHDP output. Enable peripherals +for HDMI output. + +Signed-off-by: Alexander Stein +--- + .../dts/freescale/imx8mq-tqma8mq-mba8mx.dts | 20 +++++++++++++++++++ + arch/arm64/boot/dts/freescale/mba8mx.dtsi | 11 ++++++++++ + 2 files changed, 31 insertions(+) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mq-tqma8mq-mba8mx.dts b/arch/arm64/boot/dts/freescale/imx8mq-tqma8mq-mba8mx.dts +index 0165f3a25985..406c8229097c 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mq-tqma8mq-mba8mx.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mq-tqma8mq-mba8mx.dts +@@ -53,6 +53,10 @@ &btn2 { + gpios = <&gpio3 17 GPIO_ACTIVE_LOW>; + }; + ++&dcss { ++ status = "okay"; ++}; ++ + &gpio_leds { + led3 { + label = "led3"; +@@ -60,6 +64,14 @@ led3 { + }; + }; + ++&hdmi_connector { ++ port { ++ hdmi_connector_in: endpoint { ++ remote-endpoint = <&mhdp_out>; ++ }; ++ }; ++}; ++ + &i2c1 { + expander2: gpio@25 { + compatible = "nxp,pca9555"; +@@ -91,6 +103,14 @@ &led2 { + gpios = <&gpio3 16 GPIO_ACTIVE_HIGH>; + }; + ++&mhdp { ++ status = "okay"; ++}; ++ ++&mhdp_out { ++ remote-endpoint = <&hdmi_connector_in>; ++}; ++ + /* PCIe slot on X36 */ + &pcie0 { + reset-gpio = <&expander0 14 GPIO_ACTIVE_LOW>; +diff --git a/arch/arm64/boot/dts/freescale/mba8mx.dtsi b/arch/arm64/boot/dts/freescale/mba8mx.dtsi +index 815241526a0d..ebc479070b29 100644 +--- a/arch/arm64/boot/dts/freescale/mba8mx.dtsi ++++ b/arch/arm64/boot/dts/freescale/mba8mx.dtsi +@@ -89,6 +89,17 @@ gpio_delays: gpio-delays { + gpio-line-names = "LVDS_BRIDGE_EN_1V8"; + }; + ++ hdmi_connector: connector { ++ compatible = "hdmi-connector"; ++ label = "X11"; ++ type = "a"; ++ ++ port { ++ hdmi_connector_in: endpoint { ++ }; ++ }; ++ }; ++ + panel: panel-lvds { + /* + * Display is not fixed, so compatible has to be added from diff --git a/projects/NXP/devices/iMX8/patches/linux/0001-drm-bridge-mhdp-Add-cdns-mhdp-driver-bridge-driver.patch b/projects/NXP/devices/iMX8/patches/linux/0001-drm-bridge-mhdp-Add-cdns-mhdp-driver-bridge-driver.patch deleted file mode 100644 index 3a6f03520a..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0001-drm-bridge-mhdp-Add-cdns-mhdp-driver-bridge-driver.patch +++ /dev/null @@ -1,5938 +0,0 @@ -From c50c4f565797ac47544e1f0a2669d9cf1cb9d1c7 Mon Sep 17 00:00:00 2001 -From: Sandor Yu -Date: Mon, 20 Apr 2020 23:01:50 +0800 -Subject: [PATCH 01/49] drm: bridge: mhdp: Add cdns mhdp driver bridge driver - -Base on rockchip cdn-dp-reg.c code, -create cdns mhdp DP API functions driver. -Move the driver to a separate directory. -Added HDMI/Audio/CEC API functions. - -Signed-off-by: Sandor Yu -[ Aisheng: fix conflict due to below commit -611e22b1d9f6 ("drm/rockchip: Remove unneeded semicolon") ] -Signed-off-by: Dong Aisheng ---- - drivers/gpu/drm/bridge/cadence/Kconfig | 26 + - drivers/gpu/drm/bridge/cadence/Makefile | 9 + - drivers/gpu/drm/bridge/cadence/cdns-dp-core.c | 574 +++++++++++ - .../gpu/drm/bridge/cadence/cdns-hdmi-core.c | 690 +++++++++++++ - .../gpu/drm/bridge/cadence/cdns-mhdp-audio.c | 395 +++++++ - .../gpu/drm/bridge/cadence/cdns-mhdp-cec.c | 341 +++++++ - .../gpu/drm/bridge/cadence/cdns-mhdp-common.c | 795 +++++++++++++++ - drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c | 172 ++++ - .../gpu/drm/bridge/cadence/cdns-mhdp-hdmi.c | 332 ++++++ - drivers/gpu/drm/bridge/cadence/cdns-mhdp.h | 209 ++++ - drivers/gpu/drm/rockchip/Makefile | 2 +- - drivers/gpu/drm/rockchip/cdn-dp-core.c | 241 ++--- - drivers/gpu/drm/rockchip/cdn-dp-core.h | 44 +- - drivers/gpu/drm/rockchip/cdn-dp-reg.c | 960 ------------------ - .../drm/bridge/cdns-mhdp.h | 389 ++++++- - 15 files changed, 4034 insertions(+), 1145 deletions(-) - create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-dp-core.c - create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c - create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c - create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp-cec.c - create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c - create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c - create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdmi.c - create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp.h - delete mode 100644 drivers/gpu/drm/rockchip/cdn-dp-reg.c - rename drivers/gpu/drm/rockchip/cdn-dp-reg.h => include/drm/bridge/cdns-mhdp.h (53%) - -diff --git a/drivers/gpu/drm/bridge/cadence/Kconfig b/drivers/gpu/drm/bridge/cadence/Kconfig -index ef8c230e0f62..bb1865b15aca 100644 ---- a/drivers/gpu/drm/bridge/cadence/Kconfig -+++ b/drivers/gpu/drm/bridge/cadence/Kconfig -@@ -22,3 +22,31 @@ config DRM_CDNS_MHDP8546_J721E - initializes the J721E Display Port and sets up the - clock and data muxes. - endif -+ -+config DRM_CDNS_MHDP -+ tristate "Cadence MHDP COMMON API driver" -+ select DRM_KMS_HELPER -+ select DRM_PANEL_BRIDGE -+ depends on OF -+ help -+ Support Cadence MHDP API library. -+ -+config DRM_CDNS_HDMI -+ tristate "Cadence HDMI DRM driver" -+ depends on DRM_CDNS_MHDP -+ select DRM_DISPLAY_HDCP_HELPER -+ select DRM_DISPLAY_HDMI_HELPER -+ -+config DRM_CDNS_DP -+ tristate "Cadence DP DRM driver" -+ depends on DRM_CDNS_MHDP -+ -+config DRM_CDNS_AUDIO -+ tristate "Cadence MHDP Audio driver" -+ depends on DRM_CDNS_MHDP -+ -+config DRM_CDNS_HDMI_CEC -+ tristate "Cadence MHDP HDMI CEC driver" -+ depends on DRM_CDNS_HDMI -+ select CEC_CORE -+ select CEC_NOTIFIER -diff --git a/drivers/gpu/drm/bridge/cadence/Makefile b/drivers/gpu/drm/bridge/cadence/Makefile -index 8f647991b374..618290870ba5 100644 ---- a/drivers/gpu/drm/bridge/cadence/Makefile -+++ b/drivers/gpu/drm/bridge/cadence/Makefile -@@ -4,4 +4,13 @@ - cdns-dsi-$(CONFIG_DRM_CDNS_DSI_J721E) += cdns-dsi-j721e.o - obj-$(CONFIG_DRM_CDNS_MHDP8546) += cdns-mhdp8546.o - cdns-mhdp8546-y := cdns-mhdp8546-core.o cdns-mhdp8546-hdcp.o - cdns-mhdp8546-$(CONFIG_DRM_CDNS_MHDP8546_J721E) += cdns-mhdp8546-j721e.o -+ -+cdns_mhdp_drmcore-y := cdns-mhdp-common.o cdns-mhdp-dp.o cdns-mhdp-hdmi.o -+ -+cdns_mhdp_drmcore-$(CONFIG_DRM_CDNS_HDMI) += cdns-hdmi-core.o -+cdns_mhdp_drmcore-$(CONFIG_DRM_CDNS_DP) += cdns-dp-core.o -+cdns_mhdp_drmcore-$(CONFIG_DRM_CDNS_AUDIO) += cdns-mhdp-audio.o -+cdns_mhdp_drmcore-$(CONFIG_DRM_CDNS_HDMI_CEC) += cdns-mhdp-cec.o -+ -+obj-$(CONFIG_DRM_CDNS_MHDP) += cdns_mhdp_drmcore.o -diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c b/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c -new file mode 100644 -index 000000000000..acb5c860da73 ---- /dev/null -+++ b/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c -@@ -0,0 +1,574 @@ -+/* -+ * Cadence Display Port Interface (DP) driver -+ * -+ * Copyright (C) 2019 NXP Semiconductor, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* -+ * This function only implements native DPDC reads and writes -+ */ -+static ssize_t dp_aux_transfer(struct drm_dp_aux *aux, -+ struct drm_dp_aux_msg *msg) -+{ -+ struct cdns_mhdp_device *mhdp = dev_get_drvdata(aux->dev); -+ bool native = msg->request & (DP_AUX_NATIVE_WRITE & DP_AUX_NATIVE_READ); -+ int ret; -+ -+ /* Ignore address only message */ -+ if ((msg->size == 0) || (msg->buffer == NULL)) { -+ msg->reply = native ? -+ DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK; -+ return msg->size; -+ } -+ -+ if (!native) { -+ dev_err(mhdp->dev, "%s: only native messages supported\n", __func__); -+ return -EINVAL; -+ } -+ -+ /* msg sanity check */ -+ if (msg->size > DP_AUX_MAX_PAYLOAD_BYTES) { -+ dev_err(mhdp->dev, "%s: invalid msg: size(%zu), request(%x)\n", -+ __func__, msg->size, (unsigned int)msg->request); -+ return -EINVAL; -+ } -+ -+ if (msg->request == DP_AUX_NATIVE_WRITE) { -+ const u8 *buf = msg->buffer; -+ int i; -+ for (i = 0; i < msg->size; ++i) { -+ ret = cdns_mhdp_dpcd_write(mhdp, -+ msg->address + i, buf[i]); -+ if (!ret) -+ continue; -+ -+ DRM_DEV_ERROR(mhdp->dev, "Failed to write DPCD\n"); -+ -+ return ret; -+ } -+ } -+ -+ if (msg->request == DP_AUX_NATIVE_READ) { -+ ret = cdns_mhdp_dpcd_read(mhdp, msg->address, msg->buffer, msg->size); -+ if (ret < 0) -+ return -EIO; -+ msg->reply = DP_AUX_NATIVE_REPLY_ACK; -+ return msg->size; -+ } -+ return 0; -+} -+ -+static int dp_aux_init(struct cdns_mhdp_device *mhdp, -+ struct device *dev) -+{ -+ int ret; -+ -+ mhdp->dp.aux.name = "imx_dp_aux"; -+ mhdp->dp.aux.dev = dev; -+ mhdp->dp.aux.transfer = dp_aux_transfer; -+ -+ ret = drm_dp_aux_register(&mhdp->dp.aux); -+ -+ return ret; -+} -+ -+static int dp_aux_destroy(struct cdns_mhdp_device *mhdp) -+{ -+ drm_dp_aux_unregister(&mhdp->dp.aux); -+ return 0; -+} -+ -+static void dp_pixel_clk_reset(struct cdns_mhdp_device *mhdp) -+{ -+ u32 val; -+ -+ /* reset pixel clk */ -+ val = cdns_mhdp_reg_read(mhdp, SOURCE_HDTX_CAR); -+ cdns_mhdp_reg_write(mhdp, SOURCE_HDTX_CAR, val & 0xFD); -+ cdns_mhdp_reg_write(mhdp, SOURCE_HDTX_CAR, val); -+} -+ -+static void cdns_dp_mode_set(struct cdns_mhdp_device *mhdp) -+{ -+ u32 lane_mapping = mhdp->lane_mapping; -+ int ret; -+ -+ cdns_mhdp_plat_call(mhdp, pclk_rate); -+ -+ /* delay for DP FW stable after pixel clock relock */ -+ msleep(50); -+ -+ dp_pixel_clk_reset(mhdp); -+ -+ /* Get DP Caps */ -+ ret = drm_dp_dpcd_read(&mhdp->dp.aux, DP_DPCD_REV, mhdp->dp.dpcd, -+ DP_RECEIVER_CAP_SIZE); -+ if (ret < 0) { -+ DRM_ERROR("Failed to get caps %d\n", ret); -+ return; -+ } -+ -+ mhdp->dp.rate = drm_dp_max_link_rate(mhdp->dp.dpcd); -+ mhdp->dp.num_lanes = drm_dp_max_lane_count(mhdp->dp.dpcd); -+ -+ /* check the max link rate */ -+ if (mhdp->dp.rate > CDNS_DP_MAX_LINK_RATE) -+ mhdp->dp.rate = CDNS_DP_MAX_LINK_RATE; -+ -+ /* Initialize link rate/num_lanes as panel max link rate/max_num_lanes */ -+ cdns_mhdp_plat_call(mhdp, phy_set); -+ -+ /* Video off */ -+ ret = cdns_mhdp_set_video_status(mhdp, CONTROL_VIDEO_IDLE); -+ if (ret) { -+ DRM_DEV_ERROR(mhdp->dev, "Failed to valid video %d\n", ret); -+ return; -+ } -+ -+ /* Line swaping */ -+ cdns_mhdp_reg_write(mhdp, LANES_CONFIG, 0x00400000 | lane_mapping); -+ -+ /* Set DP host capability */ -+ ret = cdns_mhdp_set_host_cap(mhdp, false); -+ if (ret) { -+ DRM_DEV_ERROR(mhdp->dev, "Failed to set host cap %d\n", ret); -+ return; -+ } -+ -+ ret = cdns_mhdp_config_video(mhdp); -+ if (ret) { -+ DRM_DEV_ERROR(mhdp->dev, "Failed to config video %d\n", ret); -+ return; -+ } -+ -+ return; -+} -+ -+/* ----------------------------------------------------------------------------- -+ * dp TX Setup -+ */ -+static enum drm_connector_status -+cdns_dp_connector_detect(struct drm_connector *connector, bool force) -+{ -+ struct cdns_mhdp_device *mhdp = container_of(connector, -+ struct cdns_mhdp_device, connector.base); -+ u8 hpd = 0xf; -+ -+ hpd = cdns_mhdp_read_hpd(mhdp); -+ if (hpd == 1) -+ /* Cable Connected */ -+ return connector_status_connected; -+ else if (hpd == 0) -+ /* Cable Disconnedted */ -+ return connector_status_disconnected; -+ else { -+ /* Cable status unknown */ -+ DRM_INFO("Unknow cable status, hdp=%u\n", hpd); -+ return connector_status_unknown; -+ } -+} -+ -+static int cdns_dp_connector_get_modes(struct drm_connector *connector) -+{ -+ struct cdns_mhdp_device *mhdp = container_of(connector, -+ struct cdns_mhdp_device, connector.base); -+ int num_modes = 0; -+ struct edid *edid; -+ -+ edid = drm_do_get_edid(&mhdp->connector.base, -+ cdns_mhdp_get_edid_block, mhdp); -+ if (edid) { -+ dev_info(mhdp->dev, "%x,%x,%x,%x,%x,%x,%x,%x\n", -+ edid->header[0], edid->header[1], -+ edid->header[2], edid->header[3], -+ edid->header[4], edid->header[5], -+ edid->header[6], edid->header[7]); -+ drm_connector_update_edid_property(connector, edid); -+ num_modes = drm_add_edid_modes(connector, edid); -+ kfree(edid); -+ } -+ -+ if (num_modes == 0) -+ DRM_ERROR("Invalid edid\n"); -+ return num_modes; -+} -+ -+static const struct drm_connector_funcs cdns_dp_connector_funcs = { -+ .fill_modes = drm_helper_probe_single_connector_modes, -+ .detect = cdns_dp_connector_detect, -+ .destroy = drm_connector_cleanup, -+ .reset = drm_atomic_helper_connector_reset, -+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, -+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, -+}; -+ -+static const struct drm_connector_helper_funcs cdns_dp_connector_helper_funcs = { -+ .get_modes = cdns_dp_connector_get_modes, -+}; -+ -+static int cdns_dp_bridge_attach(struct drm_bridge *bridge, -+ enum drm_bridge_attach_flags flags) -+{ -+ struct cdns_mhdp_device *mhdp = bridge->driver_private; -+ struct drm_encoder *encoder = bridge->encoder; -+ struct drm_connector *connector = &mhdp->connector.base; -+ -+ connector->interlace_allowed = 1; -+ -+ if (mhdp->is_hpd) -+ connector->polled = DRM_CONNECTOR_POLL_HPD; -+ else -+ connector->polled = DRM_CONNECTOR_POLL_CONNECT | -+ DRM_CONNECTOR_POLL_DISCONNECT; -+ -+ drm_connector_helper_add(connector, &cdns_dp_connector_helper_funcs); -+ -+ drm_connector_init(bridge->dev, connector, &cdns_dp_connector_funcs, -+ DRM_MODE_CONNECTOR_DisplayPort); -+ -+ drm_connector_attach_encoder(connector, encoder); -+ -+ return 0; -+} -+ -+static enum drm_mode_status -+cdns_dp_bridge_mode_valid(struct drm_bridge *bridge, -+ const struct drm_display_mode *mode) -+{ -+ enum drm_mode_status mode_status = MODE_OK; -+ -+ /* We don't support double-clocked modes */ -+ if (mode->flags & DRM_MODE_FLAG_DBLCLK || -+ mode->flags & DRM_MODE_FLAG_INTERLACE) -+ return MODE_BAD; -+ -+ /* MAX support pixel clock rate 594MHz */ -+ if (mode->clock > 594000) -+ return MODE_CLOCK_HIGH; -+ -+ /* 4096x2160 is not supported now */ -+ if (mode->hdisplay > 3840) -+ return MODE_BAD_HVALUE; -+ -+ if (mode->vdisplay > 2160) -+ return MODE_BAD_VVALUE; -+ -+ return mode_status; -+} -+ -+static void cdns_dp_bridge_mode_set(struct drm_bridge *bridge, -+ const struct drm_display_mode *orig_mode, -+ const struct drm_display_mode *mode) -+{ -+ struct cdns_mhdp_device *mhdp = bridge->driver_private; -+ struct drm_display_info *display_info = &mhdp->connector.base.display_info; -+ struct video_info *video = &mhdp->video_info; -+ -+ switch (display_info->bpc) { -+ case 10: -+ video->color_depth = 10; -+ break; -+ case 6: -+ video->color_depth = 6; -+ break; -+ default: -+ video->color_depth = 8; -+ break; -+ } -+ -+ video->color_fmt = PXL_RGB; -+ video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC); -+ video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC); -+ -+ DRM_INFO("Mode: %dx%dp%d\n", mode->hdisplay, mode->vdisplay, mode->clock); -+ memcpy(&mhdp->mode, mode, sizeof(struct drm_display_mode)); -+ -+ mutex_lock(&mhdp->lock); -+ cdns_dp_mode_set(mhdp); -+ mutex_unlock(&mhdp->lock); -+ -+ /* reset force mode set flag */ -+ mhdp->force_mode_set = false; -+} -+ -+static void cdn_dp_bridge_enable(struct drm_bridge *bridge) -+{ -+ struct cdns_mhdp_device *mhdp = bridge->driver_private; -+ int ret; -+ -+ /* Link trainning */ -+ ret = cdns_mhdp_train_link(mhdp); -+ if (ret) { -+ DRM_DEV_ERROR(mhdp->dev, "Failed link train %d\n", ret); -+ return; -+ } -+ -+ ret = cdns_mhdp_set_video_status(mhdp, CONTROL_VIDEO_VALID); -+ if (ret) { -+ DRM_DEV_ERROR(mhdp->dev, "Failed to valid video %d\n", ret); -+ return; -+ } -+} -+ -+static void cdn_dp_bridge_disable(struct drm_bridge *bridge) -+{ -+ struct cdns_mhdp_device *mhdp = bridge->driver_private; -+ -+ cdns_mhdp_set_video_status(mhdp, CONTROL_VIDEO_IDLE); -+} -+ -+static const struct drm_bridge_funcs cdns_dp_bridge_funcs = { -+ .attach = cdns_dp_bridge_attach, -+ .enable = cdn_dp_bridge_enable, -+ .disable = cdn_dp_bridge_disable, -+ .mode_set = cdns_dp_bridge_mode_set, -+ .mode_valid = cdns_dp_bridge_mode_valid, -+}; -+ -+static void hotplug_work_func(struct work_struct *work) -+{ -+ struct cdns_mhdp_device *mhdp = container_of(work, -+ struct cdns_mhdp_device, hotplug_work.work); -+ struct drm_connector *connector = &mhdp->connector.base; -+ -+ drm_helper_hpd_irq_event(connector->dev); -+ -+ if (connector->status == connector_status_connected) { -+ /* Cable connedted */ -+ DRM_INFO("HDMI/DP Cable Plug In\n"); -+ enable_irq(mhdp->irq[IRQ_OUT]); -+ } else if (connector->status == connector_status_disconnected) { -+ /* Cable Disconnedted */ -+ DRM_INFO("HDMI/DP Cable Plug Out\n"); -+ /* force mode set for cable replugin to recovery DP video modes */ -+ mhdp->force_mode_set = true; -+ enable_irq(mhdp->irq[IRQ_IN]); -+ } -+} -+ -+static irqreturn_t cdns_dp_irq_thread(int irq, void *data) -+{ -+ struct cdns_mhdp_device *mhdp = data; -+ -+ disable_irq_nosync(irq); -+ -+ mod_delayed_work(system_wq, &mhdp->hotplug_work, -+ msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS)); -+ -+ return IRQ_HANDLED; -+} -+ -+static void cdns_dp_parse_dt(struct cdns_mhdp_device *mhdp) -+{ -+ struct device_node *of_node = mhdp->dev->of_node; -+ int ret; -+ -+ ret = of_property_read_u32(of_node, "lane-mapping", -+ &mhdp->lane_mapping); -+ if (ret) { -+ mhdp->lane_mapping = 0xc6; -+ dev_warn(mhdp->dev, "Failed to get lane_mapping - using default 0xc6\n"); -+ } -+ dev_info(mhdp->dev, "lane-mapping 0x%02x\n", mhdp->lane_mapping); -+} -+ -+static int __cdns_dp_probe(struct platform_device *pdev, -+ struct cdns_mhdp_device *mhdp) -+{ -+ struct device *dev = &pdev->dev; -+ struct resource *iores = NULL; -+ int ret; -+ -+ mutex_init(&mhdp->lock); -+ mutex_init(&mhdp->iolock); -+ -+ INIT_DELAYED_WORK(&mhdp->hotplug_work, hotplug_work_func); -+ -+ iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (iores) { -+ mhdp->regs_base = devm_ioremap(dev, iores->start, -+ resource_size(iores)); -+ if (IS_ERR(mhdp->regs_base)) -+ return -ENOMEM; -+ } -+ -+ iores = platform_get_resource(pdev, IORESOURCE_MEM, 1); -+ if (iores) { -+ mhdp->regs_sec = devm_ioremap(dev, iores->start, -+ resource_size(iores)); -+ if (IS_ERR(mhdp->regs_sec)) -+ return -ENOMEM; -+ } -+ -+ mhdp->is_hpd = true; -+ mhdp->is_ls1028a = false; -+ -+ mhdp->irq[IRQ_IN] = platform_get_irq_byname(pdev, "plug_in"); -+ if (mhdp->irq[IRQ_IN] < 0) { -+ mhdp->is_hpd = false; -+ dev_info(dev, "No plug_in irq number\n"); -+ } -+ -+ mhdp->irq[IRQ_OUT] = platform_get_irq_byname(pdev, "plug_out"); -+ if (mhdp->irq[IRQ_OUT] < 0) { -+ mhdp->is_hpd = false; -+ dev_info(dev, "No plug_out irq number\n"); -+ } -+ -+ cdns_dp_parse_dt(mhdp); -+ -+ if (of_device_is_compatible(dev->of_node, "cdn,ls1028a-dp")) -+ mhdp->is_ls1028a = true; -+ -+ cdns_mhdp_plat_call(mhdp, power_on); -+ -+ cdns_mhdp_plat_call(mhdp, firmware_init); -+ -+ /* DP FW alive check */ -+ ret = cdns_mhdp_check_alive(mhdp); -+ if (ret == false) { -+ DRM_ERROR("NO dp FW running\n"); -+ return -ENXIO; -+ } -+ -+ /* DP PHY init before AUX init */ -+ cdns_mhdp_plat_call(mhdp, phy_set); -+ -+ /* Enable Hotplug Detect IRQ thread */ -+ if (mhdp->is_hpd) { -+ irq_set_status_flags(mhdp->irq[IRQ_IN], IRQ_NOAUTOEN); -+ ret = devm_request_threaded_irq(dev, mhdp->irq[IRQ_IN], -+ NULL, cdns_dp_irq_thread, -+ IRQF_ONESHOT, dev_name(dev), -+ mhdp); -+ -+ if (ret) { -+ dev_err(dev, "can't claim irq %d\n", -+ mhdp->irq[IRQ_IN]); -+ return -EINVAL; -+ } -+ -+ irq_set_status_flags(mhdp->irq[IRQ_OUT], IRQ_NOAUTOEN); -+ ret = devm_request_threaded_irq(dev, mhdp->irq[IRQ_OUT], -+ NULL, cdns_dp_irq_thread, -+ IRQF_ONESHOT, dev_name(dev), -+ mhdp); -+ -+ if (ret) { -+ dev_err(dev, "can't claim irq %d\n", -+ mhdp->irq[IRQ_OUT]); -+ return -EINVAL; -+ } -+ -+ if (cdns_mhdp_read_hpd(mhdp)) -+ enable_irq(mhdp->irq[IRQ_OUT]); -+ else -+ enable_irq(mhdp->irq[IRQ_IN]); -+ } -+ -+ mhdp->bridge.base.driver_private = mhdp; -+ mhdp->bridge.base.funcs = &cdns_dp_bridge_funcs; -+#ifdef CONFIG_OF -+ mhdp->bridge.base.of_node = dev->of_node; -+#endif -+ -+ dev_set_drvdata(dev, mhdp); -+ -+ /* register audio driver */ -+ cdns_mhdp_register_audio_driver(dev); -+ -+ dp_aux_init(mhdp, dev); -+ -+ return 0; -+} -+ -+static void __cdns_dp_remove(struct cdns_mhdp_device *mhdp) -+{ -+ dp_aux_destroy(mhdp); -+ cdns_mhdp_unregister_audio_driver(mhdp->dev); -+} -+ -+/* ----------------------------------------------------------------------------- -+ * Probe/remove API, used from platforms based on the DRM bridge API. -+ */ -+int cdns_dp_probe(struct platform_device *pdev, -+ struct cdns_mhdp_device *mhdp) -+{ -+ int ret; -+ -+ ret = __cdns_dp_probe(pdev, mhdp); -+ if (ret) -+ return ret; -+ -+ drm_bridge_add(&mhdp->bridge.base); -+ -+ return 0; -+} -+EXPORT_SYMBOL_GPL(cdns_dp_probe); -+ -+void cdns_dp_remove(struct platform_device *pdev) -+{ -+ struct cdns_mhdp_device *mhdp = platform_get_drvdata(pdev); -+ -+ drm_bridge_remove(&mhdp->bridge.base); -+ -+ __cdns_dp_remove(mhdp); -+} -+EXPORT_SYMBOL_GPL(cdns_dp_remove); -+ -+/* ----------------------------------------------------------------------------- -+ * Bind/unbind API, used from platforms based on the component framework. -+ */ -+int cdns_dp_bind(struct platform_device *pdev, struct drm_encoder *encoder, -+ struct cdns_mhdp_device *mhdp) -+{ -+ int ret; -+ -+ ret = __cdns_dp_probe(pdev, mhdp); -+ if (ret < 0) -+ return ret; -+ -+ ret = drm_bridge_attach(encoder, &mhdp->bridge.base, NULL, 0); -+ if (ret) { -+ cdns_dp_remove(pdev); -+ DRM_ERROR("Failed to initialize bridge with drm\n"); -+ return ret; -+ } -+ -+ return 0; -+} -+EXPORT_SYMBOL_GPL(cdns_dp_bind); -+ -+void cdns_dp_unbind(struct device *dev) -+{ -+ struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev); -+ -+ __cdns_dp_remove(mhdp); -+} -+EXPORT_SYMBOL_GPL(cdns_dp_unbind); -+ -+MODULE_AUTHOR("Sandor Yu "); -+MODULE_DESCRIPTION("Cadence Display Port transmitter driver"); -+MODULE_LICENSE("GPL"); -+MODULE_ALIAS("platform:cdn-dp"); -diff --git a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c -new file mode 100644 -index 000000000000..da40f62617ef ---- /dev/null -+++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c -@@ -0,0 +1,690 @@ -+/* -+ * Cadence High-Definition Multimedia Interface (HDMI) driver -+ * -+ * Copyright (C) 2019 NXP Semiconductor, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+static void hdmi_sink_config(struct cdns_mhdp_device *mhdp) -+{ -+ struct drm_scdc *scdc = &mhdp->connector.base.display_info.hdmi.scdc; -+ u8 buff = 0; -+ -+ /* Default work in HDMI1.4 */ -+ mhdp->hdmi.hdmi_type = MODE_HDMI_1_4; -+ -+ /* check sink support SCDC or not */ -+ if (scdc->supported != true) { -+ DRM_INFO("Sink Not Support SCDC\n"); -+ return; -+ } -+ -+ if (mhdp->hdmi.char_rate > 340000) { -+ /* -+ * TMDS Character Rate above 340MHz should working in HDMI2.0 -+ * Enable scrambling and TMDS_Bit_Clock_Ratio -+ */ -+ buff = SCDC_TMDS_BIT_CLOCK_RATIO_BY_40 | SCDC_SCRAMBLING_ENABLE; -+ mhdp->hdmi.hdmi_type = MODE_HDMI_2_0; -+ } else if (scdc->scrambling.low_rates) { -+ /* -+ * Enable scrambling and HDMI2.0 when scrambling capability of sink -+ * be indicated in the HF-VSDB LTE_340Mcsc_scramble bit -+ */ -+ buff = SCDC_SCRAMBLING_ENABLE; -+ mhdp->hdmi.hdmi_type = MODE_HDMI_2_0; -+ } -+ -+ /* TMDS config */ -+ cdns_hdmi_scdc_write(mhdp, 0x20, buff); -+} -+ -+static void hdmi_lanes_config(struct cdns_mhdp_device *mhdp) -+{ -+ /* Line swaping */ -+ cdns_mhdp_reg_write(mhdp, LANES_CONFIG, 0x00400000 | mhdp->lane_mapping); -+} -+ -+static int hdmi_avi_info_set(struct cdns_mhdp_device *mhdp, -+ struct drm_display_mode *mode) -+{ -+ struct hdmi_avi_infoframe frame; -+ int format = mhdp->video_info.color_fmt; -+ struct drm_connector_state *conn_state = mhdp->connector.base.state; -+ struct drm_display_mode *adj_mode; -+ enum hdmi_quantization_range qr; -+ u8 buf[32]; -+ int ret; -+ -+ /* Initialise info frame from DRM mode */ -+ drm_hdmi_avi_infoframe_from_display_mode(&frame, &mhdp->connector.base, -+ mode); -+ -+ switch (format) { -+ case YCBCR_4_4_4: -+ frame.colorspace = HDMI_COLORSPACE_YUV444; -+ break; -+ case YCBCR_4_2_2: -+ frame.colorspace = HDMI_COLORSPACE_YUV422; -+ break; -+ case YCBCR_4_2_0: -+ frame.colorspace = HDMI_COLORSPACE_YUV420; -+ break; -+ default: -+ frame.colorspace = HDMI_COLORSPACE_RGB; -+ break; -+ } -+ -+ drm_hdmi_avi_infoframe_colorimetry(&frame, conn_state); -+ -+ adj_mode = &mhdp->bridge.base.encoder->crtc->state->adjusted_mode; -+ -+ qr = drm_default_rgb_quant_range(adj_mode); -+ -+ drm_hdmi_avi_infoframe_quant_range(&frame, &mhdp->connector.base, -+ adj_mode, qr); -+ -+ ret = hdmi_avi_infoframe_check(&frame); -+ if (WARN_ON(ret)) -+ return false; -+ -+ ret = hdmi_avi_infoframe_pack(&frame, buf + 1, sizeof(buf) - 1); -+ if (ret < 0) { -+ DRM_ERROR("failed to pack AVI infoframe: %d\n", ret); -+ return -1; -+ } -+ -+ buf[0] = 0; -+ cdns_mhdp_infoframe_set(mhdp, 0, sizeof(buf), buf, HDMI_INFOFRAME_TYPE_AVI); -+ return 0; -+} -+ -+static void hdmi_vendor_info_set(struct cdns_mhdp_device *mhdp, -+ struct drm_display_mode *mode) -+{ -+ struct hdmi_vendor_infoframe frame; -+ u8 buf[32]; -+ int ret; -+ -+ /* Initialise vendor frame from DRM mode */ -+ ret = drm_hdmi_vendor_infoframe_from_display_mode(&frame, &mhdp->connector.base, mode); -+ if (ret < 0) { -+ DRM_INFO("No vendor infoframe\n"); -+ return; -+ } -+ -+ ret = hdmi_vendor_infoframe_pack(&frame, buf + 1, sizeof(buf) - 1); -+ if (ret < 0) { -+ DRM_WARN("Unable to pack vendor infoframe: %d\n", ret); -+ return; -+ } -+ -+ buf[0] = 0; -+ cdns_mhdp_infoframe_set(mhdp, 3, sizeof(buf), buf, HDMI_INFOFRAME_TYPE_VENDOR); -+} -+ -+static void hdmi_drm_info_set(struct cdns_mhdp_device *mhdp) -+{ -+ struct drm_connector_state *conn_state; -+ struct hdmi_drm_infoframe frame; -+ u8 buf[32]; -+ int ret; -+ -+ conn_state = mhdp->connector.base.state; -+ -+ if (!conn_state->hdr_output_metadata) -+ return; -+ -+ ret = drm_hdmi_infoframe_set_hdr_metadata(&frame, conn_state); -+ if (ret < 0) { -+ DRM_DEBUG_KMS("couldn't set HDR metadata in infoframe\n"); -+ return; -+ } -+ -+ ret = hdmi_drm_infoframe_pack(&frame, buf + 1, sizeof(buf) - 1); -+ if (ret < 0) { -+ DRM_DEBUG_KMS("couldn't pack HDR infoframe\n"); -+ return; -+ } -+ -+ buf[0] = 0; -+ cdns_mhdp_infoframe_set(mhdp, 3, sizeof(buf), -+ buf, HDMI_INFOFRAME_TYPE_DRM); -+} -+ -+void cdns_hdmi_mode_set(struct cdns_mhdp_device *mhdp) -+{ -+ struct drm_display_mode *mode = &mhdp->mode; -+ int ret; -+ -+ /* video mode valid check */ -+ if (mode->clock == 0 || mode->hdisplay == 0 || mode->vdisplay == 0) -+ return; -+ -+ hdmi_lanes_config(mhdp); -+ -+ cdns_mhdp_plat_call(mhdp, pclk_rate); -+ -+ /* delay for HDMI FW stable after pixel clock relock */ -+ msleep(20); -+ -+ cdns_mhdp_plat_call(mhdp, phy_set); -+ -+ hdmi_sink_config(mhdp); -+ -+ ret = cdns_hdmi_ctrl_init(mhdp, mhdp->hdmi.hdmi_type, mhdp->hdmi.char_rate); -+ if (ret < 0) { -+ DRM_ERROR("%s, ret = %d\n", __func__, ret); -+ return; -+ } -+ -+ /* Config GCP */ -+ if (mhdp->video_info.color_depth == 8) -+ cdns_hdmi_disable_gcp(mhdp); -+ else -+ cdns_hdmi_enable_gcp(mhdp); -+ -+ ret = hdmi_avi_info_set(mhdp, mode); -+ if (ret < 0) { -+ DRM_ERROR("%s ret = %d\n", __func__, ret); -+ return; -+ } -+ -+ /* vendor info frame is enable only when HDMI1.4 4K mode */ -+ hdmi_vendor_info_set(mhdp, mode); -+ -+ hdmi_drm_info_set(mhdp); -+ -+ ret = cdns_hdmi_mode_config(mhdp, mode, &mhdp->video_info); -+ if (ret < 0) { -+ DRM_ERROR("CDN_API_HDMITX_SetVic_blocking ret = %d\n", ret); -+ return; -+ } -+} -+ -+static enum drm_connector_status -+cdns_hdmi_connector_detect(struct drm_connector *connector, bool force) -+{ -+ struct cdns_mhdp_device *mhdp = -+ container_of(connector, struct cdns_mhdp_device, connector.base); -+ -+ u8 hpd = 0xf; -+ -+ hpd = cdns_mhdp_read_hpd(mhdp); -+ -+ if (hpd == 1) -+ /* Cable Connected */ -+ return connector_status_connected; -+ else if (hpd == 0) -+ /* Cable Disconnedted */ -+ return connector_status_disconnected; -+ else { -+ /* Cable status unknown */ -+ DRM_INFO("Unknow cable status, hdp=%u\n", hpd); -+ return connector_status_unknown; -+ } -+} -+ -+static int cdns_hdmi_connector_get_modes(struct drm_connector *connector) -+{ -+ struct cdns_mhdp_device *mhdp = -+ container_of(connector, struct cdns_mhdp_device, connector.base); -+ int num_modes = 0; -+ struct edid *edid; -+ -+ edid = drm_do_get_edid(&mhdp->connector.base, -+ cdns_hdmi_get_edid_block, mhdp); -+ if (edid) { -+ dev_info(mhdp->dev, "%x,%x,%x,%x,%x,%x,%x,%x\n", -+ edid->header[0], edid->header[1], -+ edid->header[2], edid->header[3], -+ edid->header[4], edid->header[5], -+ edid->header[6], edid->header[7]); -+ drm_connector_update_edid_property(connector, edid); -+ num_modes = drm_add_edid_modes(connector, edid); -+ kfree(edid); -+ } -+ -+ if (num_modes == 0) -+ DRM_ERROR("Invalid edid\n"); -+ return num_modes; -+} -+ -+static bool blob_equal(const struct drm_property_blob *a, -+ const struct drm_property_blob *b) -+{ -+ if (a && b) -+ return a->length == b->length && -+ !memcmp(a->data, b->data, a->length); -+ -+ return !a == !b; -+} -+ -+static int cdns_hdmi_connector_atomic_check(struct drm_connector *connector, -+ struct drm_atomic_state *state) -+{ -+ struct drm_connector_state *new_con_state = -+ drm_atomic_get_new_connector_state(state, connector); -+ struct drm_connector_state *old_con_state = -+ drm_atomic_get_old_connector_state(state, connector); -+ struct drm_crtc *crtc = new_con_state->crtc; -+ struct drm_crtc_state *new_crtc_state; -+ -+ if (!blob_equal(new_con_state->hdr_output_metadata, -+ old_con_state->hdr_output_metadata) || -+ new_con_state->colorspace != old_con_state->colorspace) { -+ new_crtc_state = drm_atomic_get_crtc_state(state, crtc); -+ if (IS_ERR(new_crtc_state)) -+ return PTR_ERR(new_crtc_state); -+ -+ new_crtc_state->mode_changed = -+ !new_con_state->hdr_output_metadata || -+ !old_con_state->hdr_output_metadata || -+ new_con_state->colorspace != old_con_state->colorspace; -+ } -+ -+ return 0; -+} -+ -+static const struct drm_connector_funcs cdns_hdmi_connector_funcs = { -+ .fill_modes = drm_helper_probe_single_connector_modes, -+ .detect = cdns_hdmi_connector_detect, -+ .destroy = drm_connector_cleanup, -+ .reset = drm_atomic_helper_connector_reset, -+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, -+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, -+}; -+ -+static const struct drm_connector_helper_funcs cdns_hdmi_connector_helper_funcs = { -+ .get_modes = cdns_hdmi_connector_get_modes, -+ .atomic_check = cdns_hdmi_connector_atomic_check, -+}; -+ -+static int cdns_hdmi_bridge_attach(struct drm_bridge *bridge, -+ enum drm_bridge_attach_flags flags) -+{ -+ struct cdns_mhdp_device *mhdp = bridge->driver_private; -+ struct drm_mode_config *config = &bridge->dev->mode_config; -+ struct drm_encoder *encoder = bridge->encoder; -+ struct drm_connector *connector = &mhdp->connector.base; -+ -+ connector->interlace_allowed = 1; -+ connector->polled = DRM_CONNECTOR_POLL_HPD; -+ -+ drm_connector_helper_add(connector, &cdns_hdmi_connector_helper_funcs); -+ -+ drm_connector_init(bridge->dev, connector, &cdns_hdmi_connector_funcs, -+ DRM_MODE_CONNECTOR_HDMIA); -+ -+ if (!strncmp("imx8mq-hdmi", mhdp->plat_data->plat_name, 11)) { -+ drm_object_attach_property(&connector->base, -+ config->hdr_output_metadata_property, -+ 0); -+ -+ if (!drm_mode_create_hdmi_colorspace_property(connector, 0)) -+ drm_object_attach_property(&connector->base, -+ connector->colorspace_property, -+ 0); -+ } -+ -+ drm_connector_attach_encoder(connector, encoder); -+ -+ return 0; -+} -+ -+static enum drm_mode_status -+cdns_hdmi_bridge_mode_valid(struct drm_bridge *bridge, -+ const struct drm_display_mode *mode) -+{ -+ struct cdns_mhdp_device *mhdp = bridge->driver_private; -+ enum drm_mode_status mode_status = MODE_OK; -+ int ret; -+ -+ /* We don't support double-clocked and Interlaced modes */ -+ if (mode->flags & DRM_MODE_FLAG_DBLCLK || -+ mode->flags & DRM_MODE_FLAG_INTERLACE) -+ return MODE_BAD; -+ -+ /* MAX support pixel clock rate 594MHz */ -+ if (mode->clock > 594000) -+ return MODE_CLOCK_HIGH; -+ -+ /* 4096x2160 is not supported */ -+ if (mode->hdisplay > 3840 || mode->vdisplay > 2160) -+ return MODE_BAD_HVALUE; -+ -+ mhdp->valid_mode = mode; -+ ret = cdns_mhdp_plat_call(mhdp, phy_video_valid); -+ if (ret == false) -+ return MODE_CLOCK_RANGE; -+ -+ return mode_status; -+} -+ -+static void cdns_hdmi_bridge_mode_set(struct drm_bridge *bridge, -+ const struct drm_display_mode *orig_mode, -+ const struct drm_display_mode *mode) -+{ -+ struct cdns_mhdp_device *mhdp = bridge->driver_private; -+ struct video_info *video = &mhdp->video_info; -+ -+ video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC); -+ video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC); -+ -+ DRM_INFO("Mode: %dx%dp%d\n", mode->hdisplay, mode->vdisplay, mode->clock); -+ memcpy(&mhdp->mode, mode, sizeof(struct drm_display_mode)); -+ -+ mutex_lock(&mhdp->lock); -+ cdns_hdmi_mode_set(mhdp); -+ mutex_unlock(&mhdp->lock); -+ /* reset force mode set flag */ -+ mhdp->force_mode_set = false; -+} -+ -+bool cdns_hdmi_bridge_mode_fixup(struct drm_bridge *bridge, -+ const struct drm_display_mode *mode, -+ struct drm_display_mode *adjusted_mode) -+{ -+ struct cdns_mhdp_device *mhdp = bridge->driver_private; -+ struct drm_display_info *di = &mhdp->connector.base.display_info; -+ struct video_info *video = &mhdp->video_info; -+ int vic = drm_match_cea_mode(mode); -+ -+ video->color_depth = 8; -+ video->color_fmt = PXL_RGB; -+ -+ /* for all other platforms, other than imx8mq */ -+ if (strncmp("imx8mq-hdmi", mhdp->plat_data->plat_name, 11)) { -+ if (di->bpc == 10 || di->bpc == 6) -+ video->color_depth = di->bpc; -+ -+ return true; -+ } -+ -+ /* imx8mq */ -+ if (vic == 97 || vic == 96) { -+ if (di->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_36) -+ video->color_depth = 12; -+ else if (di->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_30) -+ video->color_depth = 10; -+ -+ if (drm_mode_is_420_only(di, mode) || -+ (drm_mode_is_420_also(di, mode) && -+ video->color_depth > 8)) { -+ video->color_fmt = YCBCR_4_2_0; -+ -+ adjusted_mode->private_flags = 1; -+ return true; -+ } -+ -+ video->color_depth = 8; -+ return true; -+ } -+ -+ /* Any defined maximum tmds clock limit we must not exceed*/ -+ if ((di->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_36) && -+ (mode->clock * 3 / 2 <= di->max_tmds_clock)) -+ video->color_depth = 12; -+ else if ((di->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_30) && -+ (mode->clock * 5 / 4 <= di->max_tmds_clock)) -+ video->color_depth = 10; -+ -+ /* 10-bit color depth for the following modes is not supported */ -+ if ((vic == 95 || vic == 94 || vic == 93) && video->color_depth == 10) -+ video->color_depth = 8; -+ -+ return true; -+} -+ -+static const struct drm_bridge_funcs cdns_hdmi_bridge_funcs = { -+ .attach = cdns_hdmi_bridge_attach, -+ .mode_set = cdns_hdmi_bridge_mode_set, -+ .mode_valid = cdns_hdmi_bridge_mode_valid, -+ .mode_fixup = cdns_hdmi_bridge_mode_fixup, -+}; -+ -+static void hotplug_work_func(struct work_struct *work) -+{ -+ struct cdns_mhdp_device *mhdp = container_of(work, -+ struct cdns_mhdp_device, hotplug_work.work); -+ struct drm_connector *connector = &mhdp->connector.base; -+ -+ drm_helper_hpd_irq_event(connector->dev); -+ -+ if (connector->status == connector_status_connected) { -+ DRM_INFO("HDMI Cable Plug In\n"); -+ mhdp->force_mode_set = true; -+ enable_irq(mhdp->irq[IRQ_OUT]); -+ } else if (connector->status == connector_status_disconnected) { -+ /* Cable Disconnedted */ -+ DRM_INFO("HDMI Cable Plug Out\n"); -+ /* force mode set for cable replugin to recovery HDMI2.0 video modes */ -+ mhdp->force_mode_set = true; -+ enable_irq(mhdp->irq[IRQ_IN]); -+ } -+} -+ -+static irqreturn_t cdns_hdmi_irq_thread(int irq, void *data) -+{ -+ struct cdns_mhdp_device *mhdp = data; -+ -+ disable_irq_nosync(irq); -+ -+ mod_delayed_work(system_wq, &mhdp->hotplug_work, -+ msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS)); -+ -+ return IRQ_HANDLED; -+} -+ -+static void cdns_hdmi_parse_dt(struct cdns_mhdp_device *mhdp) -+{ -+ struct device_node *of_node = mhdp->dev->of_node; -+ int ret; -+ -+ ret = of_property_read_u32(of_node, "lane-mapping", &mhdp->lane_mapping); -+ if (ret) { -+ mhdp->lane_mapping = 0xc6; -+ dev_warn(mhdp->dev, "Failed to get lane_mapping - using default 0xc6\n"); -+ } -+ dev_info(mhdp->dev, "lane-mapping 0x%02x\n", mhdp->lane_mapping); -+} -+ -+static int __cdns_hdmi_probe(struct platform_device *pdev, -+ struct cdns_mhdp_device *mhdp) -+{ -+ struct device *dev = &pdev->dev; -+ struct platform_device_info pdevinfo; -+ struct resource *iores = NULL; -+ int ret; -+ -+ mutex_init(&mhdp->lock); -+ mutex_init(&mhdp->iolock); -+ -+ INIT_DELAYED_WORK(&mhdp->hotplug_work, hotplug_work_func); -+ -+ iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ mhdp->regs_base = devm_ioremap(dev, iores->start, resource_size(iores)); -+ if (IS_ERR(mhdp->regs_base)) { -+ dev_err(dev, "No regs_base memory\n"); -+ return -ENOMEM; -+ } -+ -+ /* sec register base */ -+ iores = platform_get_resource(pdev, IORESOURCE_MEM, 1); -+ mhdp->regs_sec = devm_ioremap(dev, iores->start, resource_size(iores)); -+ if (IS_ERR(mhdp->regs_sec)) { -+ dev_err(dev, "No regs_sec memory\n"); -+ return -ENOMEM; -+ } -+ -+ mhdp->irq[IRQ_IN] = platform_get_irq_byname(pdev, "plug_in"); -+ if (mhdp->irq[IRQ_IN] < 0) { -+ dev_info(dev, "No plug_in irq number\n"); -+ return -EPROBE_DEFER; -+ } -+ -+ mhdp->irq[IRQ_OUT] = platform_get_irq_byname(pdev, "plug_out"); -+ if (mhdp->irq[IRQ_OUT] < 0) { -+ dev_info(dev, "No plug_out irq number\n"); -+ return -EPROBE_DEFER; -+ } -+ -+ cdns_mhdp_plat_call(mhdp, power_on); -+ -+ /* Initialize FW */ -+ cdns_mhdp_plat_call(mhdp, firmware_init); -+ -+ /* HDMI FW alive check */ -+ ret = cdns_mhdp_check_alive(mhdp); -+ if (ret == false) { -+ dev_err(dev, "NO HDMI FW running\n"); -+ return -ENXIO; -+ } -+ -+ /* Enable Hotplug Detect thread */ -+ irq_set_status_flags(mhdp->irq[IRQ_IN], IRQ_NOAUTOEN); -+ ret = devm_request_threaded_irq(dev, mhdp->irq[IRQ_IN], -+ NULL, cdns_hdmi_irq_thread, -+ IRQF_ONESHOT, dev_name(dev), -+ mhdp); -+ if (ret < 0) { -+ dev_err(dev, "can't claim irq %d\n", -+ mhdp->irq[IRQ_IN]); -+ return -EINVAL; -+ } -+ -+ irq_set_status_flags(mhdp->irq[IRQ_OUT], IRQ_NOAUTOEN); -+ ret = devm_request_threaded_irq(dev, mhdp->irq[IRQ_OUT], -+ NULL, cdns_hdmi_irq_thread, -+ IRQF_ONESHOT, dev_name(dev), -+ mhdp); -+ if (ret < 0) { -+ dev_err(dev, "can't claim irq %d\n", -+ mhdp->irq[IRQ_OUT]); -+ return -EINVAL; -+ } -+ -+ cdns_hdmi_parse_dt(mhdp); -+ -+ if (cdns_mhdp_read_hpd(mhdp)) -+ enable_irq(mhdp->irq[IRQ_OUT]); -+ else -+ enable_irq(mhdp->irq[IRQ_IN]); -+ -+ mhdp->bridge.base.driver_private = mhdp; -+ mhdp->bridge.base.funcs = &cdns_hdmi_bridge_funcs; -+#ifdef CONFIG_OF -+ mhdp->bridge.base.of_node = dev->of_node; -+#endif -+ -+ memset(&pdevinfo, 0, sizeof(pdevinfo)); -+ pdevinfo.parent = dev; -+ pdevinfo.id = PLATFORM_DEVID_AUTO; -+ -+ dev_set_drvdata(dev, mhdp); -+ -+ /* register audio driver */ -+ cdns_mhdp_register_audio_driver(dev); -+ -+ /* register cec driver */ -+#ifdef CONFIG_DRM_CDNS_HDMI_CEC -+ cdns_mhdp_register_cec_driver(dev); -+#endif -+ -+ return 0; -+} -+ -+static void __cdns_hdmi_remove(struct cdns_mhdp_device *mhdp) -+{ -+ /* unregister cec driver */ -+#ifdef CONFIG_DRM_CDNS_HDMI_CEC -+ cdns_mhdp_unregister_cec_driver(mhdp->dev); -+#endif -+ cdns_mhdp_unregister_audio_driver(mhdp->dev); -+} -+ -+/* ----------------------------------------------------------------------------- -+ * Probe/remove API, used from platforms based on the DRM bridge API. -+ */ -+int cdns_hdmi_probe(struct platform_device *pdev, -+ struct cdns_mhdp_device *mhdp) -+{ -+ int ret; -+ -+ ret = __cdns_hdmi_probe(pdev, mhdp); -+ if (ret < 0) -+ return ret; -+ -+ drm_bridge_add(&mhdp->bridge.base); -+ -+ return 0; -+} -+EXPORT_SYMBOL_GPL(cdns_hdmi_probe); -+ -+void cdns_hdmi_remove(struct platform_device *pdev) -+{ -+ struct cdns_mhdp_device *mhdp = platform_get_drvdata(pdev); -+ -+ drm_bridge_remove(&mhdp->bridge.base); -+ -+ __cdns_hdmi_remove(mhdp); -+} -+EXPORT_SYMBOL_GPL(cdns_hdmi_remove); -+ -+/* ----------------------------------------------------------------------------- -+ * Bind/unbind API, used from platforms based on the component framework. -+ */ -+int cdns_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder, -+ struct cdns_mhdp_device *mhdp) -+{ -+ int ret; -+ -+ ret = __cdns_hdmi_probe(pdev, mhdp); -+ if (ret) -+ return ret; -+ -+ ret = drm_bridge_attach(encoder, &mhdp->bridge.base, NULL, 0); -+ if (ret) { -+ cdns_hdmi_remove(pdev); -+ DRM_ERROR("Failed to initialize bridge with drm\n"); -+ return ret; -+ } -+ -+ return 0; -+} -+EXPORT_SYMBOL_GPL(cdns_hdmi_bind); -+ -+void cdns_hdmi_unbind(struct device *dev) -+{ -+ struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev); -+ -+ __cdns_hdmi_remove(mhdp); -+} -+EXPORT_SYMBOL_GPL(cdns_hdmi_unbind); -+ -+MODULE_AUTHOR("Sandor Yu "); -+MODULE_DESCRIPTION("Cadence HDMI transmitter driver"); -+MODULE_LICENSE("GPL"); -+MODULE_ALIAS("platform:cdn-hdmi"); -diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c -new file mode 100644 -index 000000000000..86174fb633bc ---- /dev/null -+++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c -@@ -0,0 +1,395 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd -+ * Author: Chris Zhong -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define CDNS_DP_SPDIF_CLK 200000000 -+ -+static u32 TMDS_rate_table[7] = { -+ 25200, 27000, 54000, 74250, 148500, 297000, 594000, -+}; -+ -+static u32 N_table_32k[7] = { -+/* 25200/27000/54000/74250/148500/297000/594000 */ -+ 4096, 4096, 4096, 4096, 4096, 3072, 3072, -+}; -+ -+static u32 N_table_44k[7] = { -+ 6272, 6272, 6272, 6272, 6272, 4704, 9408, -+}; -+ -+static u32 N_table_48k[7] = { -+ 6144, 6144, 6144, 6144, 6144, 5120, 6144, -+}; -+ -+static int select_N_index(u32 pclk) -+{ -+ int num = sizeof(TMDS_rate_table)/sizeof(int); -+ int i = 0; -+ -+ for (i = 0; i < num ; i++) -+ if (pclk == TMDS_rate_table[i]) -+ break; -+ -+ if (i == num) { -+ DRM_WARN("pclkc %d is not supported!\n", pclk); -+ return num-1; -+ } -+ -+ return i; -+} -+ -+static void hdmi_audio_avi_set(struct cdns_mhdp_device *mhdp, -+ u32 channels) -+{ -+ struct hdmi_audio_infoframe frame; -+ u8 buf[32]; -+ int ret; -+ -+ hdmi_audio_infoframe_init(&frame); -+ -+ frame.channels = channels; -+ frame.coding_type = HDMI_AUDIO_CODING_TYPE_STREAM; -+ -+ if (channels == 2) -+ frame.channel_allocation = 0; -+ else if (channels == 4) -+ frame.channel_allocation = 0x3; -+ else if (channels == 8) -+ frame.channel_allocation = 0x13; -+ -+ ret = hdmi_audio_infoframe_pack(&frame, buf + 1, sizeof(buf) - 1); -+ if (ret < 0) { -+ DRM_ERROR("failed to pack audio infoframe: %d\n", ret); -+ return; -+ } -+ -+ buf[0] = 0; -+ -+ cdns_mhdp_infoframe_set(mhdp, 1, sizeof(buf), buf, HDMI_INFOFRAME_TYPE_AUDIO); -+} -+ -+int cdns_mhdp_audio_stop(struct cdns_mhdp_device *mhdp, -+ struct audio_info *audio) -+{ -+ int ret; -+ -+ if (audio->connector_type == DRM_MODE_CONNECTOR_DisplayPort) { -+ ret = cdns_mhdp_reg_write(mhdp, AUDIO_PACK_CONTROL, 0); -+ if (ret) { -+ DRM_DEV_ERROR(mhdp->dev, "audio stop failed: %d\n", ret); -+ return ret; -+ } -+ } -+ -+ cdns_mhdp_bus_write(0, mhdp, SPDIF_CTRL_ADDR); -+ -+ /* clearn the audio config and reset */ -+ cdns_mhdp_bus_write(0, mhdp, AUDIO_SRC_CNTL); -+ cdns_mhdp_bus_write(0, mhdp, AUDIO_SRC_CNFG); -+ cdns_mhdp_bus_write(AUDIO_SW_RST, mhdp, AUDIO_SRC_CNTL); -+ cdns_mhdp_bus_write(0, mhdp, AUDIO_SRC_CNTL); -+ -+ /* reset smpl2pckt component */ -+ cdns_mhdp_bus_write(0, mhdp, SMPL2PKT_CNTL); -+ cdns_mhdp_bus_write(AUDIO_SW_RST, mhdp, SMPL2PKT_CNTL); -+ cdns_mhdp_bus_write(0, mhdp, SMPL2PKT_CNTL); -+ -+ /* reset FIFO */ -+ cdns_mhdp_bus_write(AUDIO_SW_RST, mhdp, FIFO_CNTL); -+ cdns_mhdp_bus_write(0, mhdp, FIFO_CNTL); -+ -+ if (audio->format == AFMT_SPDIF_INT) -+ clk_disable_unprepare(mhdp->spdif_clk); -+ -+ return 0; -+} -+EXPORT_SYMBOL(cdns_mhdp_audio_stop); -+ -+int cdns_mhdp_audio_mute(struct cdns_mhdp_device *mhdp, bool enable) -+{ -+ struct audio_info *audio = &mhdp->audio_info; -+ int ret = true; -+ -+ if (audio->connector_type == DRM_MODE_CONNECTOR_DisplayPort) { -+ ret = cdns_mhdp_reg_write_bit(mhdp, DP_VB_ID, 4, 1, enable); -+ if (ret) -+ DRM_DEV_ERROR(mhdp->dev, "audio mute failed: %d\n", ret); -+ } -+ -+ return ret; -+} -+EXPORT_SYMBOL(cdns_mhdp_audio_mute); -+ -+static void cdns_mhdp_audio_config_i2s(struct cdns_mhdp_device *mhdp, -+ struct audio_info *audio) -+{ -+ int sub_pckt_num = 1, i2s_port_en_val = 0xf, i; -+ int idx = select_N_index(mhdp->mode.clock); -+ u32 val, ncts; -+ -+ if (audio->channels == 2) { -+ if (mhdp->dp.num_lanes == 1) -+ sub_pckt_num = 2; -+ else -+ sub_pckt_num = 4; -+ -+ i2s_port_en_val = 1; -+ } else if (audio->channels == 4) { -+ i2s_port_en_val = 3; -+ } -+ -+ cdns_mhdp_bus_write(0x0, mhdp, SPDIF_CTRL_ADDR); -+ -+ cdns_mhdp_bus_write(SYNC_WR_TO_CH_ZERO, mhdp, FIFO_CNTL); -+ -+ val = MAX_NUM_CH(audio->channels); -+ val |= NUM_OF_I2S_PORTS(audio->channels); -+ val |= AUDIO_TYPE_LPCM; -+ val |= CFG_SUB_PCKT_NUM(sub_pckt_num); -+ cdns_mhdp_bus_write(val, mhdp, SMPL2PKT_CNFG); -+ -+ if (audio->sample_width == 16) -+ val = 0; -+ else if (audio->sample_width == 24) -+ val = 1 << 9; -+ else -+ val = 2 << 9; -+ -+ val |= AUDIO_CH_NUM(audio->channels); -+ val |= I2S_DEC_PORT_EN(i2s_port_en_val); -+ val |= TRANS_SMPL_WIDTH_32; -+ cdns_mhdp_bus_write(val, mhdp, AUDIO_SRC_CNFG); -+ -+ for (i = 0; i < (audio->channels + 1) / 2; i++) { -+ if (audio->sample_width == 16) -+ val = (0x02 << 8) | (0x02 << 20); -+ else if (audio->sample_width == 24) -+ val = (0x0b << 8) | (0x0b << 20); -+ -+ val |= ((2 * i) << 4) | ((2 * i + 1) << 16); -+ cdns_mhdp_bus_write(val, mhdp, STTS_BIT_CH(i)); -+ } -+ -+ switch (audio->sample_rate) { -+ case 32000: -+ val = SAMPLING_FREQ(3) | -+ ORIGINAL_SAMP_FREQ(0xc); -+ ncts = N_table_32k[idx]; -+ break; -+ case 44100: -+ val = SAMPLING_FREQ(0) | -+ ORIGINAL_SAMP_FREQ(0xf); -+ ncts = N_table_44k[idx]; -+ break; -+ case 48000: -+ val = SAMPLING_FREQ(2) | -+ ORIGINAL_SAMP_FREQ(0xd); -+ ncts = N_table_48k[idx]; -+ break; -+ case 88200: -+ val = SAMPLING_FREQ(8) | -+ ORIGINAL_SAMP_FREQ(0x7); -+ ncts = N_table_44k[idx] * 2; -+ break; -+ case 96000: -+ val = SAMPLING_FREQ(0xa) | -+ ORIGINAL_SAMP_FREQ(5); -+ ncts = N_table_48k[idx] * 2; -+ break; -+ case 176400: -+ val = SAMPLING_FREQ(0xc) | -+ ORIGINAL_SAMP_FREQ(3); -+ ncts = N_table_44k[idx] * 4; -+ break; -+ case 192000: -+ default: -+ val = SAMPLING_FREQ(0xe) | -+ ORIGINAL_SAMP_FREQ(1); -+ ncts = N_table_48k[idx] * 4; -+ break; -+ } -+ val |= 4; -+ cdns_mhdp_bus_write(val, mhdp, COM_CH_STTS_BITS); -+ -+ if (audio->connector_type == DRM_MODE_CONNECTOR_HDMIA) -+ cdns_mhdp_reg_write(mhdp, CM_I2S_CTRL, ncts | 0x4000000); -+ -+ cdns_mhdp_bus_write(SMPL2PKT_EN, mhdp, SMPL2PKT_CNTL); -+ cdns_mhdp_bus_write(I2S_DEC_START, mhdp, AUDIO_SRC_CNTL); -+} -+ -+static void cdns_mhdp_audio_config_spdif(struct cdns_mhdp_device *mhdp) -+{ -+ u32 val; -+ -+ cdns_mhdp_bus_write(SYNC_WR_TO_CH_ZERO, mhdp, FIFO_CNTL); -+ -+ val = MAX_NUM_CH(2) | AUDIO_TYPE_LPCM | CFG_SUB_PCKT_NUM(4); -+ cdns_mhdp_bus_write(val, mhdp, SMPL2PKT_CNFG); -+ cdns_mhdp_bus_write(SMPL2PKT_EN, mhdp, SMPL2PKT_CNTL); -+ -+ val = SPDIF_ENABLE | SPDIF_AVG_SEL | SPDIF_JITTER_BYPASS; -+ cdns_mhdp_bus_write(val, mhdp, SPDIF_CTRL_ADDR); -+ -+ clk_prepare_enable(mhdp->spdif_clk); -+ clk_set_rate(mhdp->spdif_clk, CDNS_DP_SPDIF_CLK); -+} -+ -+int cdns_mhdp_audio_config(struct cdns_mhdp_device *mhdp, -+ struct audio_info *audio) -+{ -+ int ret; -+ -+ /* reset the spdif clk before config */ -+ if (audio->format == AFMT_SPDIF_INT) { -+ reset_control_assert(mhdp->spdif_rst); -+ reset_control_deassert(mhdp->spdif_rst); -+ } -+ -+ if (audio->connector_type == DRM_MODE_CONNECTOR_DisplayPort) { -+ ret = cdns_mhdp_reg_write(mhdp, CM_LANE_CTRL, LANE_REF_CYC); -+ if (ret) -+ goto err_audio_config; -+ -+ ret = cdns_mhdp_reg_write(mhdp, CM_CTRL, 0); -+ if (ret) -+ goto err_audio_config; -+ } else { -+ /* HDMI Mode */ -+ ret = cdns_mhdp_reg_write(mhdp, CM_CTRL, 8); -+ if (ret) -+ goto err_audio_config; -+ } -+ -+ if (audio->format == AFMT_I2S) -+ cdns_mhdp_audio_config_i2s(mhdp, audio); -+ else if (audio->format == AFMT_SPDIF_INT) -+ cdns_mhdp_audio_config_spdif(mhdp); -+ -+ if (audio->connector_type == DRM_MODE_CONNECTOR_DisplayPort) -+ ret = cdns_mhdp_reg_write(mhdp, AUDIO_PACK_CONTROL, AUDIO_PACK_EN); -+ -+ if (audio->connector_type == DRM_MODE_CONNECTOR_HDMIA) -+ hdmi_audio_avi_set(mhdp, audio->channels); -+ -+err_audio_config: -+ if (ret) -+ DRM_DEV_ERROR(mhdp->dev, "audio config failed: %d\n", ret); -+ return ret; -+} -+EXPORT_SYMBOL(cdns_mhdp_audio_config); -+ -+static int audio_hw_params(struct device *dev, void *data, -+ struct hdmi_codec_daifmt *daifmt, -+ struct hdmi_codec_params *params) -+{ -+ struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev); -+ struct audio_info audio = { -+ .sample_width = params->sample_width, -+ .sample_rate = params->sample_rate, -+ .channels = params->channels, -+ .connector_type = mhdp->connector.base.connector_type, -+ }; -+ int ret; -+ -+ switch (daifmt->fmt) { -+ case HDMI_I2S: -+ audio.format = AFMT_I2S; -+ break; -+ case HDMI_SPDIF: -+ audio.format = AFMT_SPDIF_EXT; -+ break; -+ default: -+ DRM_DEV_ERROR(dev, "Invalid format %d\n", daifmt->fmt); -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ ret = cdns_mhdp_audio_config(mhdp, &audio); -+ if (!ret) -+ mhdp->audio_info = audio; -+ -+out: -+ return ret; -+} -+ -+static void audio_shutdown(struct device *dev, void *data) -+{ -+ struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev); -+ int ret; -+ -+ ret = cdns_mhdp_audio_stop(mhdp, &mhdp->audio_info); -+ if (!ret) -+ mhdp->audio_info.format = AFMT_UNUSED; -+} -+ -+static int audio_digital_mute(struct device *dev, void *data, -+ bool enable) -+{ -+ struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev); -+ int ret; -+ -+ ret = cdns_mhdp_audio_mute(mhdp, enable); -+ -+ return ret; -+} -+ -+static int audio_get_eld(struct device *dev, void *data, -+ u8 *buf, size_t len) -+{ -+ struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev); -+ -+ memcpy(buf, mhdp->connector.base.eld, -+ min(sizeof(mhdp->connector.base.eld), len)); -+ -+ return 0; -+} -+ -+static const struct hdmi_codec_ops audio_codec_ops = { -+ .hw_params = audio_hw_params, -+ .audio_shutdown = audio_shutdown, -+ .digital_mute = audio_digital_mute, -+ .get_eld = audio_get_eld, -+}; -+ -+int cdns_mhdp_register_audio_driver(struct device *dev) -+{ -+ struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev); -+ struct hdmi_codec_pdata codec_data = { -+ .i2s = 1, -+ .spdif = 1, -+ .ops = &audio_codec_ops, -+ .max_i2s_channels = 8, -+ }; -+ -+ mhdp->audio_pdev = platform_device_register_data( -+ dev, HDMI_CODEC_DRV_NAME, 1, -+ &codec_data, sizeof(codec_data)); -+ -+ return PTR_ERR_OR_ZERO(mhdp->audio_pdev); -+} -+ -+void cdns_mhdp_unregister_audio_driver(struct device *dev) -+{ -+ struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev); -+ -+ platform_device_unregister(mhdp->audio_pdev); -+} -diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-cec.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-cec.c -new file mode 100644 -index 000000000000..5717bb0bcb75 ---- /dev/null -+++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-cec.c -@@ -0,0 +1,341 @@ -+/* -+ * Copyright 2019 NXP -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version 2 -+ * of the License, or (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+#include -+#include -+#include -+#include -+#include -+ -+#define CEC_NAME "cdns-mhdp-cec" -+ -+#define REG_ADDR_OFF 4 -+ -+/* regsiter define */ -+#define TX_MSG_HEADER 0x33800 -+#define TX_MSG_LENGTH 0x33840 -+#define TX_MSG_CMD 0x33844 -+#define RX_MSG_CMD 0x33850 -+#define RX_CLEAR_BUF 0x33854 -+#define LOGICAL_ADDRESS_LA0 0x33858 -+ -+#define CLK_DIV_MSB 0x3386c -+#define CLK_DIV_LSB 0x33870 -+#define RX_MSG_DATA1 0x33900 -+#define RX_MSG_LENGTH 0x33940 -+#define RX_MSG_STATUS 0x33944 -+#define NUM_OF_MSG_RX_BUF 0x33948 -+#define TX_MSG_STATUS 0x3394c -+#define DB_L_TIMER 0x33980 -+ -+/** -+ * CEC Transceiver operation. -+ */ -+enum { -+ CEC_TX_STOP, -+ CEC_TX_TRANSMIT, -+ CEC_TX_ABORT, -+ CEC_TX_ABORT_AND_TRANSMIT -+}; -+ -+/** -+ * CEC Transceiver status. -+ */ -+enum { -+ CEC_STS_IDLE, -+ CEC_STS_BUSY, -+ CEC_STS_SUCCESS, -+ CEC_STS_ERROR -+}; -+ -+/** -+ * CEC Receiver operation. -+ */ -+enum { -+ CEC_RX_STOP, -+ CEC_RX_READ, -+ CEC_RX_DISABLE, -+ CEC_RX_ABORT_AND_CLR_FIFO -+}; -+/** -+ * Maximum number of Messages in the RX Buffers. -+ */ -+#define CEC_MAX_RX_MSGS 2 -+ -+static u32 mhdp_cec_read(struct cdns_mhdp_cec *cec, u32 offset) -+{ -+ struct cdns_mhdp_device *mhdp = -+ container_of(cec, struct cdns_mhdp_device, hdmi.cec); -+ return cdns_mhdp_bus_read(mhdp, offset); -+} -+ -+static void mhdp_cec_write(struct cdns_mhdp_cec *cec, u32 offset, u32 val) -+{ -+ struct cdns_mhdp_device *mhdp = -+ container_of(cec, struct cdns_mhdp_device, hdmi.cec); -+ cdns_mhdp_bus_write(val, mhdp, offset); -+} -+ -+static void mhdp_cec_clear_rx_buffer(struct cdns_mhdp_cec *cec) -+{ -+ mhdp_cec_write(cec, RX_CLEAR_BUF, 1); -+ mhdp_cec_write(cec, RX_CLEAR_BUF, 0); -+} -+ -+static void mhdp_cec_set_divider(struct cdns_mhdp_cec *cec) -+{ -+ struct cdns_mhdp_device *mhdp = -+ container_of(cec, struct cdns_mhdp_device, hdmi.cec); -+ u32 clk_div; -+ -+ /* Set clock divider */ -+ clk_div = cdns_mhdp_get_fw_clk(mhdp) * 10; -+ -+ mhdp_cec_write(cec, CLK_DIV_MSB, -+ (clk_div >> 8) & 0xFF); -+ mhdp_cec_write(cec, CLK_DIV_LSB, clk_div & 0xFF); -+} -+ -+static u32 mhdp_cec_read_message(struct cdns_mhdp_cec *cec) -+{ -+ struct cec_msg *msg = &cec->msg; -+ int len; -+ int i; -+ -+ mhdp_cec_write(cec, RX_MSG_CMD, CEC_RX_READ); -+ -+ len = mhdp_cec_read(cec, RX_MSG_LENGTH); -+ msg->len = len + 1; -+ dev_dbg(cec->dev, "RX MSG len =%d\n", len); -+ -+ /* Read RX MSG bytes */ -+ for (i = 0; i < msg->len; ++i) { -+ msg->msg[i] = (u8) mhdp_cec_read(cec, RX_MSG_DATA1 + (i * REG_ADDR_OFF)); -+ dev_dbg(cec->dev, "RX MSG[%d]=0x%x\n", i, msg->msg[i]); -+ } -+ -+ mhdp_cec_write(cec, RX_MSG_CMD, CEC_RX_STOP); -+ -+ return true; -+} -+ -+static u32 mhdp_cec_write_message(struct cdns_mhdp_cec *cec, struct cec_msg *msg) -+{ -+ u8 i; -+ -+ mhdp_cec_write(cec, TX_MSG_CMD, CEC_TX_STOP); -+ -+ if (msg->len > CEC_MAX_MSG_SIZE) { -+ dev_err(cec->dev, "Invalid MSG size!\n"); -+ return -EINVAL; -+ } -+ -+ for (i = 0; i < msg->len; ++i) -+ printk("msg[%d]=0x%x\n",i, msg->msg[i]); -+ -+ /* Write Message to register */ -+ for (i = 0; i < msg->len; ++i) { -+ mhdp_cec_write(cec, TX_MSG_HEADER + (i * REG_ADDR_OFF), -+ msg->msg[i]); -+ } -+ /* Write Message Length (payload + opcode) */ -+ mhdp_cec_write(cec, TX_MSG_LENGTH, msg->len - 1); -+ -+ mhdp_cec_write(cec, TX_MSG_CMD, CEC_TX_TRANSMIT); -+ -+ return true; -+} -+ -+static int mhdp_cec_set_logical_addr(struct cdns_mhdp_cec *cec, u32 la) -+{ -+ u8 la_reg; -+ u8 i; -+ -+ if (la == CEC_LOG_ADDR_INVALID) -+ /* invalid all LA address */ -+ for (i = 0; i < CEC_MAX_LOG_ADDRS; ++i) { -+ mhdp_cec_write(cec, LOGICAL_ADDRESS_LA0 + (i * REG_ADDR_OFF), 0); -+ return 0; -+ } -+ -+ /* In fact cdns mhdp cec could support max 5 La address */ -+ for (i = 0; i < CEC_MAX_LOG_ADDRS; ++i) { -+ la_reg = mhdp_cec_read(cec, LOGICAL_ADDRESS_LA0 + (i * REG_ADDR_OFF)); -+ /* Check LA already used */ -+ if (la_reg & 0x10) -+ continue; -+ -+ if ((la_reg & 0xF) == la) { -+ dev_warn(cec->dev, "Warning. LA already in use.\n"); -+ return 0; -+ } -+ -+ la = (la & 0xF) | (1 << 4); -+ -+ mhdp_cec_write(cec, LOGICAL_ADDRESS_LA0 + (i * REG_ADDR_OFF), la); -+ return 0; -+ } -+ -+ dev_warn(cec->dev, "All LA in use\n"); -+ -+ return -ENXIO; -+} -+ -+static int mhdp_cec_poll_worker(void *_cec) -+{ -+ struct cdns_mhdp_cec *cec = (struct cdns_mhdp_cec *)_cec; -+ int num_rx_msgs, i; -+ int sts; -+ -+ set_freezable(); -+ -+ for (;;) { -+ if (kthread_freezable_should_stop(NULL)) -+ break; -+ -+ /* Check TX State */ -+ sts = mhdp_cec_read(cec, TX_MSG_STATUS); -+ switch (sts) { -+ case CEC_STS_SUCCESS: -+ cec_transmit_done(cec->adap, CEC_TX_STATUS_OK, 0, 0, 0, -+ 0); -+ mhdp_cec_write(cec, TX_MSG_CMD, CEC_TX_STOP); -+ break; -+ case CEC_STS_ERROR: -+ mhdp_cec_write(cec, TX_MSG_CMD, CEC_TX_STOP); -+ cec_transmit_done(cec->adap, -+ CEC_TX_STATUS_MAX_RETRIES | -+ CEC_TX_STATUS_NACK, 0, 1, 0, 0); -+ break; -+ case CEC_STS_BUSY: -+ default: -+ break; -+ } -+ -+ /* Check RX State */ -+ sts = mhdp_cec_read(cec, RX_MSG_STATUS); -+ num_rx_msgs = mhdp_cec_read(cec, NUM_OF_MSG_RX_BUF); -+ switch (sts) { -+ case CEC_STS_SUCCESS: -+ if (num_rx_msgs == 0xf) -+ num_rx_msgs = CEC_MAX_RX_MSGS; -+ -+ if (num_rx_msgs > CEC_MAX_RX_MSGS) { -+ dev_err(cec->dev, "Error rx msg num %d\n", -+ num_rx_msgs); -+ mhdp_cec_clear_rx_buffer(cec); -+ break; -+ } -+ -+ /* Rx FIFO Depth 2 RX MSG */ -+ for (i = 0; i < num_rx_msgs; i++) { -+ mhdp_cec_read_message(cec); -+ cec->msg.rx_status = CEC_RX_STATUS_OK; -+ cec_received_msg(cec->adap, &cec->msg); -+ } -+ break; -+ default: -+ break; -+ } -+ -+ if (!kthread_should_stop()) -+ schedule_timeout_idle(20); -+ } -+ -+ return 0; -+} -+ -+static int mhdp_cec_adap_enable(struct cec_adapter *adap, bool enable) -+{ -+ struct cdns_mhdp_cec *cec = cec_get_drvdata(adap); -+ -+ if (enable) { -+ mhdp_cec_write(cec, DB_L_TIMER, 0x10); -+ mhdp_cec_set_divider(cec); -+ } else -+ mhdp_cec_set_divider(cec); -+ -+ return 0; -+} -+ -+static int mhdp_cec_adap_log_addr(struct cec_adapter *adap, u8 addr) -+{ -+ struct cdns_mhdp_cec *cec = cec_get_drvdata(adap); -+ -+ return mhdp_cec_set_logical_addr(cec, addr); -+} -+ -+static int mhdp_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, -+ u32 signal_free_time, struct cec_msg *msg) -+{ -+ struct cdns_mhdp_cec *cec = cec_get_drvdata(adap); -+ -+ mhdp_cec_write_message(cec, msg); -+ -+ return 0; -+} -+ -+static const struct cec_adap_ops cdns_mhdp_cec_adap_ops = { -+ .adap_enable = mhdp_cec_adap_enable, -+ .adap_log_addr = mhdp_cec_adap_log_addr, -+ .adap_transmit = mhdp_cec_adap_transmit, -+}; -+ -+int cdns_mhdp_register_cec_driver(struct device *dev) -+{ -+ struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev); -+ struct cdns_mhdp_cec *cec = &mhdp->hdmi.cec; -+ int ret; -+ -+ cec->adap = cec_allocate_adapter(&cdns_mhdp_cec_adap_ops, cec, -+ CEC_NAME, -+ CEC_CAP_PHYS_ADDR | CEC_CAP_LOG_ADDRS | -+ CEC_CAP_TRANSMIT | CEC_CAP_PASSTHROUGH -+ | CEC_CAP_RC, CEC_MAX_LOG_ADDRS); -+ ret = PTR_ERR_OR_ZERO(cec->adap); -+ if (ret) -+ return ret; -+ ret = cec_register_adapter(cec->adap, dev); -+ if (ret) { -+ cec_delete_adapter(cec->adap); -+ return ret; -+ } -+ -+ cec->dev = dev; -+ -+ cec->cec_worker = kthread_create(mhdp_cec_poll_worker, cec, "cdns-mhdp-cec"); -+ if (IS_ERR(cec->cec_worker)) -+ dev_err(cec->dev, "failed create hdp cec thread\n"); -+ -+ wake_up_process(cec->cec_worker); -+ -+ dev_dbg(dev, "CEC successfuly probed\n"); -+ return 0; -+} -+ -+int cdns_mhdp_unregister_cec_driver(struct device *dev) -+{ -+ struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev); -+ struct cdns_mhdp_cec *cec = &mhdp->hdmi.cec; -+ -+ if (cec->cec_worker) { -+ kthread_stop(cec->cec_worker); -+ cec->cec_worker = NULL; -+ } -+ cec_unregister_adapter(cec->adap); -+ return 0; -+} -+ -+MODULE_AUTHOR("Sandor.Yu@NXP.com"); -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("NXP CDNS MHDP HDMI CEC driver"); -diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c -new file mode 100644 -index 000000000000..91d1cfd4b2af ---- /dev/null -+++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c -@@ -0,0 +1,795 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd -+ * Author: Chris Zhong -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#include -+#include -+#include -+#include -+ -+#define CDNS_DP_SPDIF_CLK 200000000 -+#define FW_ALIVE_TIMEOUT_US 1000000 -+#define MAILBOX_RETRY_US 1000 -+#define MAILBOX_TIMEOUT_US 5000000 -+ -+#define mhdp_readx_poll_timeout(op, addr, offset, val, cond, sleep_us, timeout_us) \ -+({ \ -+ u64 __timeout_us = (timeout_us); \ -+ unsigned long __sleep_us = (sleep_us); \ -+ ktime_t __timeout = ktime_add_us(ktime_get(), __timeout_us); \ -+ might_sleep_if((__sleep_us) != 0); \ -+ for (;;) { \ -+ (val) = op(addr, offset); \ -+ if (cond) \ -+ break; \ -+ if (__timeout_us && \ -+ ktime_compare(ktime_get(), __timeout) > 0) { \ -+ (val) = op(addr, offset); \ -+ break; \ -+ } \ -+ if (__sleep_us) \ -+ usleep_range((__sleep_us >> 2) + 1, __sleep_us); \ -+ } \ -+ (cond) ? 0 : -ETIMEDOUT; \ -+}) -+ -+u32 cdns_mhdp_bus_read(struct cdns_mhdp_device *mhdp, u32 offset) -+{ -+ u32 val; -+ -+ mutex_lock(&mhdp->iolock); -+ -+ if (mhdp->bus_type == BUS_TYPE_LOW4K_SAPB) { -+ /* Remap address to low 4K SAPB bus */ -+ writel(offset >> 12, mhdp->regs_sec + 0xc); -+ val = readl((offset & 0xfff) + mhdp->regs_base); -+ } else if (mhdp->bus_type == BUS_TYPE_LOW4K_APB) { -+ /* Remap address to low 4K memory */ -+ writel(offset >> 12, mhdp->regs_sec + 8); -+ val = readl((offset & 0xfff) + mhdp->regs_base); -+ } else if (mhdp->bus_type == BUS_TYPE_NORMAL_SAPB) -+ val = readl(mhdp->regs_sec + offset); -+ else -+ val = readl(mhdp->regs_base + offset); -+ -+ mutex_unlock(&mhdp->iolock); -+ -+ return val; -+} -+EXPORT_SYMBOL(cdns_mhdp_bus_read); -+ -+void cdns_mhdp_bus_write(u32 val, struct cdns_mhdp_device *mhdp, u32 offset) -+{ -+ mutex_lock(&mhdp->iolock); -+ -+ if (mhdp->bus_type == BUS_TYPE_LOW4K_SAPB) { -+ /* Remap address to low 4K SAPB bus */ -+ writel(offset >> 12, mhdp->regs_sec + 0xc); -+ writel(val, (offset & 0xfff) + mhdp->regs_base); -+ } else if (mhdp->bus_type == BUS_TYPE_LOW4K_APB) { -+ /* Remap address to low 4K memory */ -+ writel(offset >> 12, mhdp->regs_sec + 8); -+ writel(val, (offset & 0xfff) + mhdp->regs_base); -+ } else if (mhdp->bus_type == BUS_TYPE_NORMAL_SAPB) -+ writel(val, mhdp->regs_sec + offset); -+ else -+ writel(val, mhdp->regs_base + offset); -+ -+ mutex_unlock(&mhdp->iolock); -+} -+EXPORT_SYMBOL(cdns_mhdp_bus_write); -+ -+u32 cdns_mhdp_get_fw_clk(struct cdns_mhdp_device *mhdp) -+{ -+ return cdns_mhdp_bus_read(mhdp, SW_CLK_H); -+} -+EXPORT_SYMBOL(cdns_mhdp_get_fw_clk); -+ -+void cdns_mhdp_set_fw_clk(struct cdns_mhdp_device *mhdp, unsigned long clk) -+{ -+ cdns_mhdp_bus_write(clk / 1000000, mhdp, SW_CLK_H); -+} -+EXPORT_SYMBOL(cdns_mhdp_set_fw_clk); -+ -+void cdns_mhdp_clock_reset(struct cdns_mhdp_device *mhdp) -+{ -+ u32 val; -+ -+ val = DPTX_FRMR_DATA_CLK_RSTN_EN | -+ DPTX_FRMR_DATA_CLK_EN | -+ DPTX_PHY_DATA_RSTN_EN | -+ DPTX_PHY_DATA_CLK_EN | -+ DPTX_PHY_CHAR_RSTN_EN | -+ DPTX_PHY_CHAR_CLK_EN | -+ SOURCE_AUX_SYS_CLK_RSTN_EN | -+ SOURCE_AUX_SYS_CLK_EN | -+ DPTX_SYS_CLK_RSTN_EN | -+ DPTX_SYS_CLK_EN | -+ CFG_DPTX_VIF_CLK_RSTN_EN | -+ CFG_DPTX_VIF_CLK_EN; -+ cdns_mhdp_bus_write(val, mhdp, SOURCE_DPTX_CAR); -+ -+ val = SOURCE_PHY_RSTN_EN | SOURCE_PHY_CLK_EN; -+ cdns_mhdp_bus_write(val, mhdp, SOURCE_PHY_CAR); -+ -+ val = SOURCE_PKT_SYS_RSTN_EN | -+ SOURCE_PKT_SYS_CLK_EN | -+ SOURCE_PKT_DATA_RSTN_EN | -+ SOURCE_PKT_DATA_CLK_EN; -+ cdns_mhdp_bus_write(val, mhdp, SOURCE_PKT_CAR); -+ -+ val = SPDIF_CDR_CLK_RSTN_EN | -+ SPDIF_CDR_CLK_EN | -+ SOURCE_AIF_SYS_RSTN_EN | -+ SOURCE_AIF_SYS_CLK_EN | -+ SOURCE_AIF_CLK_RSTN_EN | -+ SOURCE_AIF_CLK_EN; -+ cdns_mhdp_bus_write(val, mhdp, SOURCE_AIF_CAR); -+ -+ val = SOURCE_CIPHER_SYSTEM_CLK_RSTN_EN | -+ SOURCE_CIPHER_SYS_CLK_EN | -+ SOURCE_CIPHER_CHAR_CLK_RSTN_EN | -+ SOURCE_CIPHER_CHAR_CLK_EN; -+ cdns_mhdp_bus_write(val, mhdp, SOURCE_CIPHER_CAR); -+ -+ val = SOURCE_CRYPTO_SYS_CLK_RSTN_EN | -+ SOURCE_CRYPTO_SYS_CLK_EN; -+ cdns_mhdp_bus_write(val, mhdp, SOURCE_CRYPTO_CAR); -+ -+ /* enable Mailbox and PIF interrupt */ -+ cdns_mhdp_bus_write(0, mhdp, APB_INT_MASK); -+} -+EXPORT_SYMBOL(cdns_mhdp_clock_reset); -+ -+bool cdns_mhdp_check_alive(struct cdns_mhdp_device *mhdp) -+{ -+ u32 alive, newalive; -+ u8 retries_left = 50; -+ -+ alive = cdns_mhdp_bus_read(mhdp, KEEP_ALIVE); -+ -+ while (retries_left--) { -+ udelay(2); -+ -+ newalive = cdns_mhdp_bus_read(mhdp, KEEP_ALIVE); -+ if (alive == newalive) -+ continue; -+ return true; -+ } -+ return false; -+} -+EXPORT_SYMBOL(cdns_mhdp_check_alive); -+ -+static int mhdp_mailbox_read(struct cdns_mhdp_device *mhdp) -+{ -+ int val, ret; -+ -+ ret = mhdp_readx_poll_timeout(cdns_mhdp_bus_read, mhdp, MAILBOX_EMPTY_ADDR, -+ val, !val, MAILBOX_RETRY_US, -+ MAILBOX_TIMEOUT_US); -+ if (ret < 0) -+ return ret; -+ -+ return cdns_mhdp_bus_read(mhdp, MAILBOX0_RD_DATA) & 0xff; -+} -+ -+static int mhdp_mailbox_write(struct cdns_mhdp_device *mhdp, u8 val) -+{ -+ int ret, full; -+ -+ ret = mhdp_readx_poll_timeout(cdns_mhdp_bus_read, mhdp, MAILBOX_FULL_ADDR, -+ full, !full, MAILBOX_RETRY_US, -+ MAILBOX_TIMEOUT_US); -+ if (ret < 0) -+ return ret; -+ -+ cdns_mhdp_bus_write(val, mhdp, MAILBOX0_WR_DATA); -+ -+ return 0; -+} -+ -+int cdns_mhdp_mailbox_validate_receive(struct cdns_mhdp_device *mhdp, -+ u8 module_id, u8 opcode, -+ u16 req_size) -+{ -+ u32 mbox_size, i; -+ u8 header[4]; -+ int ret; -+ -+ /* read the header of the message */ -+ for (i = 0; i < 4; i++) { -+ ret = mhdp_mailbox_read(mhdp); -+ if (ret < 0) -+ return ret; -+ -+ header[i] = ret; -+ } -+ -+ mbox_size = get_unaligned_be16(header + 2); -+ -+ if (opcode != header[0] || module_id != header[1] || -+ req_size != mbox_size) { -+ /* -+ * If the message in mailbox is not what we want, we need to -+ * clear the mailbox by reading its contents. -+ */ -+ for (i = 0; i < mbox_size; i++) -+ if (mhdp_mailbox_read(mhdp) < 0) -+ break; -+ -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+EXPORT_SYMBOL(cdns_mhdp_mailbox_validate_receive); -+ -+int cdns_mhdp_mailbox_read_receive(struct cdns_mhdp_device *mhdp, -+ u8 *buff, u16 buff_size) -+{ -+ u32 i; -+ int ret; -+ -+ for (i = 0; i < buff_size; i++) { -+ ret = mhdp_mailbox_read(mhdp); -+ if (ret < 0) -+ return ret; -+ -+ buff[i] = ret; -+ } -+ -+ return 0; -+} -+EXPORT_SYMBOL(cdns_mhdp_mailbox_read_receive); -+ -+int cdns_mhdp_mailbox_send(struct cdns_mhdp_device *mhdp, u8 module_id, -+ u8 opcode, u16 size, u8 *message) -+{ -+ u8 header[4]; -+ int ret, i; -+ -+ header[0] = opcode; -+ header[1] = module_id; -+ put_unaligned_be16(size, header + 2); -+ -+ for (i = 0; i < 4; i++) { -+ ret = mhdp_mailbox_write(mhdp, header[i]); -+ if (ret) -+ return ret; -+ } -+ -+ for (i = 0; i < size; i++) { -+ ret = mhdp_mailbox_write(mhdp, message[i]); -+ if (ret) -+ return ret; -+ } -+ -+ return 0; -+} -+EXPORT_SYMBOL(cdns_mhdp_mailbox_send); -+ -+int cdns_mhdp_reg_read(struct cdns_mhdp_device *mhdp, u32 addr) -+{ -+ u8 msg[4], resp[8]; -+ u32 val; -+ int ret; -+ -+ if (addr == 0) { -+ ret = -EINVAL; -+ goto err_reg_read; -+ } -+ -+ put_unaligned_be32(addr, msg); -+ -+ ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_GENERAL, -+ GENERAL_READ_REGISTER, -+ sizeof(msg), msg); -+ if (ret) -+ goto err_reg_read; -+ -+ ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_GENERAL, -+ GENERAL_READ_REGISTER, -+ sizeof(resp)); -+ if (ret) -+ goto err_reg_read; -+ -+ ret = cdns_mhdp_mailbox_read_receive(mhdp, resp, sizeof(resp)); -+ if (ret) -+ goto err_reg_read; -+ -+ /* Returned address value should be the same as requested */ -+ if (memcmp(msg, resp, sizeof(msg))) { -+ ret = -EINVAL; -+ goto err_reg_read; -+ } -+ -+ val = get_unaligned_be32(resp + 4); -+ -+ return val; -+err_reg_read: -+ DRM_DEV_ERROR(mhdp->dev, "Failed to read register.\n"); -+ -+ return ret; -+} -+EXPORT_SYMBOL(cdns_mhdp_reg_read); -+ -+int cdns_mhdp_reg_write(struct cdns_mhdp_device *mhdp, u32 addr, u32 val) -+{ -+ u8 msg[8]; -+ -+ put_unaligned_be32(addr, msg); -+ put_unaligned_be32(val, msg + 4); -+ -+ return cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_GENERAL, -+ GENERAL_WRITE_REGISTER, sizeof(msg), msg); -+} -+EXPORT_SYMBOL(cdns_mhdp_reg_write); -+ -+int cdns_mhdp_reg_write_bit(struct cdns_mhdp_device *mhdp, u16 addr, -+ u8 start_bit, u8 bits_no, u32 val) -+{ -+ u8 field[8]; -+ -+ put_unaligned_be16(addr, field); -+ field[2] = start_bit; -+ field[3] = bits_no; -+ put_unaligned_be32(val, field + 4); -+ -+ return cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, -+ DPTX_WRITE_FIELD, sizeof(field), field); -+} -+EXPORT_SYMBOL(cdns_mhdp_reg_write_bit); -+ -+int cdns_mhdp_load_firmware(struct cdns_mhdp_device *mhdp, const u32 *i_mem, -+ u32 i_size, const u32 *d_mem, u32 d_size) -+{ -+ u32 reg; -+ int i, ret; -+ -+ /* reset ucpu before load firmware*/ -+ cdns_mhdp_bus_write(APB_IRAM_PATH | APB_DRAM_PATH | APB_XT_RESET, -+ mhdp, APB_CTRL); -+ -+ for (i = 0; i < i_size; i += 4) -+ cdns_mhdp_bus_write(*i_mem++, mhdp, ADDR_IMEM + i); -+ -+ for (i = 0; i < d_size; i += 4) -+ cdns_mhdp_bus_write(*d_mem++, mhdp, ADDR_DMEM + i); -+ -+ /* un-reset ucpu */ -+ cdns_mhdp_bus_write(0, mhdp, APB_CTRL); -+ -+ /* check the keep alive register to make sure fw working */ -+ ret = mhdp_readx_poll_timeout(cdns_mhdp_bus_read, mhdp, KEEP_ALIVE, -+ reg, reg, 2000, FW_ALIVE_TIMEOUT_US); -+ if (ret < 0) { -+ DRM_DEV_ERROR(mhdp->dev, "failed to loaded the FW reg = %x\n", -+ reg); -+ return -EINVAL; -+ } -+ -+ reg = cdns_mhdp_bus_read(mhdp, VER_L) & 0xff; -+ mhdp->fw_version = reg; -+ reg = cdns_mhdp_bus_read(mhdp, VER_H) & 0xff; -+ mhdp->fw_version |= reg << 8; -+ reg = cdns_mhdp_bus_read(mhdp, VER_LIB_L_ADDR) & 0xff; -+ mhdp->fw_version |= reg << 16; -+ reg = cdns_mhdp_bus_read(mhdp, VER_LIB_H_ADDR) & 0xff; -+ mhdp->fw_version |= reg << 24; -+ -+ DRM_DEV_DEBUG(mhdp->dev, "firmware version: %x\n", mhdp->fw_version); -+ -+ return 0; -+} -+EXPORT_SYMBOL(cdns_mhdp_load_firmware); -+ -+int cdns_mhdp_set_firmware_active(struct cdns_mhdp_device *mhdp, bool enable) -+{ -+ u8 msg[5]; -+ int ret, i; -+ -+ msg[0] = GENERAL_MAIN_CONTROL; -+ msg[1] = MB_MODULE_ID_GENERAL; -+ msg[2] = 0; -+ msg[3] = 1; -+ msg[4] = enable ? FW_ACTIVE : FW_STANDBY; -+ -+ for (i = 0; i < sizeof(msg); i++) { -+ ret = mhdp_mailbox_write(mhdp, msg[i]); -+ if (ret) -+ goto err_set_firmware_active; -+ } -+ -+ /* read the firmware state */ -+ for (i = 0; i < sizeof(msg); i++) { -+ ret = mhdp_mailbox_read(mhdp); -+ if (ret < 0) -+ goto err_set_firmware_active; -+ -+ msg[i] = ret; -+ } -+ -+ ret = 0; -+ -+err_set_firmware_active: -+ if (ret < 0) -+ DRM_DEV_ERROR(mhdp->dev, "set firmware active failed\n"); -+ return ret; -+} -+EXPORT_SYMBOL(cdns_mhdp_set_firmware_active); -+ -+int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp, bool flip) -+{ -+ u8 msg[8]; -+ int ret; -+ -+ msg[0] = drm_dp_link_rate_to_bw_code(mhdp->dp.rate); -+ msg[1] = mhdp->dp.num_lanes | SCRAMBLER_EN; -+ msg[2] = VOLTAGE_LEVEL_2; -+ msg[3] = PRE_EMPHASIS_LEVEL_3; -+ msg[4] = PTS1 | PTS2 | PTS3 | PTS4; -+ msg[5] = FAST_LT_NOT_SUPPORT; -+ msg[6] = flip ? LANE_MAPPING_FLIPPED : LANE_MAPPING_NORMAL; -+ msg[7] = ENHANCED; -+ -+ ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, -+ DPTX_SET_HOST_CAPABILITIES, -+ sizeof(msg), msg); -+ if (ret) -+ goto err_set_host_cap; -+ -+/* TODO Sandor */ -+// ret = cdns_mhdp_reg_write(mhdp, DP_AUX_SWAP_INVERSION_CONTROL, -+// AUX_HOST_INVERT); -+ -+err_set_host_cap: -+ if (ret) -+ DRM_DEV_ERROR(mhdp->dev, "set host cap failed: %d\n", ret); -+ return ret; -+} -+EXPORT_SYMBOL(cdns_mhdp_set_host_cap); -+ -+int cdns_mhdp_event_config(struct cdns_mhdp_device *mhdp) -+{ -+ u8 msg[5]; -+ int ret; -+ -+ memset(msg, 0, sizeof(msg)); -+ -+ msg[0] = MHDP_EVENT_ENABLE_HPD | MHDP_EVENT_ENABLE_TRAINING; -+ -+ ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, -+ DPTX_ENABLE_EVENT, sizeof(msg), msg); -+ if (ret) -+ DRM_DEV_ERROR(mhdp->dev, "set event config failed: %d\n", ret); -+ -+ return ret; -+} -+EXPORT_SYMBOL(cdns_mhdp_event_config); -+ -+u32 cdns_mhdp_get_event(struct cdns_mhdp_device *mhdp) -+{ -+ return cdns_mhdp_bus_read(mhdp, SW_EVENTS0); -+} -+EXPORT_SYMBOL(cdns_mhdp_get_event); -+ -+int cdns_mhdp_read_hpd(struct cdns_mhdp_device *mhdp) -+{ -+ u8 status; -+ int ret; -+ -+ ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_GENERAL, GENERAL_GET_HPD_STATE, -+ 0, NULL); -+ if (ret) -+ goto err_get_hpd; -+ -+ ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_GENERAL, -+ GENERAL_GET_HPD_STATE, sizeof(status)); -+ if (ret) -+ goto err_get_hpd; -+ -+ ret = cdns_mhdp_mailbox_read_receive(mhdp, &status, sizeof(status)); -+ if (ret) -+ goto err_get_hpd; -+ -+ return status; -+ -+err_get_hpd: -+ DRM_ERROR("read hpd failed: %d\n", ret); -+ return ret; -+} -+EXPORT_SYMBOL(cdns_mhdp_read_hpd); -+ -+int cdns_mhdp_get_edid_block(void *data, u8 *edid, -+ unsigned int block, size_t length) -+{ -+ struct cdns_mhdp_device *mhdp = data; -+ u8 msg[2], reg[2], i; -+ int ret; -+ -+ for (i = 0; i < 4; i++) { -+ msg[0] = block / 2; -+ msg[1] = block % 2; -+ -+ ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, -+ DPTX_GET_EDID, sizeof(msg), msg); -+ if (ret) -+ continue; -+ -+ ret = cdns_mhdp_mailbox_validate_receive(mhdp, -+ MB_MODULE_ID_DP_TX, -+ DPTX_GET_EDID, -+ sizeof(reg) + length); -+ if (ret) -+ continue; -+ -+ ret = cdns_mhdp_mailbox_read_receive(mhdp, reg, sizeof(reg)); -+ if (ret) -+ continue; -+ -+ ret = cdns_mhdp_mailbox_read_receive(mhdp, edid, length); -+ if (ret) -+ continue; -+ -+ if (reg[0] == length && reg[1] == block / 2) -+ break; -+ } -+ -+ if (ret) -+ DRM_DEV_ERROR(mhdp->dev, "get block[%d] edid failed: %d\n", -+ block, ret); -+ -+ return ret; -+} -+EXPORT_SYMBOL(cdns_mhdp_get_edid_block); -+ -+int cdns_mhdp_set_video_status(struct cdns_mhdp_device *mhdp, int active) -+{ -+ u8 msg; -+ int ret; -+ -+ msg = !!active; -+ -+ ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, -+ DPTX_SET_VIDEO, sizeof(msg), &msg); -+ if (ret) -+ DRM_DEV_ERROR(mhdp->dev, "set video status failed: %d\n", ret); -+ -+ return ret; -+} -+EXPORT_SYMBOL(cdns_mhdp_set_video_status); -+ -+static int mhdp_get_msa_misc(struct video_info *video, -+ struct drm_display_mode *mode) -+{ -+ u32 msa_misc; -+ u8 val[2] = {0}; -+ -+ switch (video->color_fmt) { -+ case PXL_RGB: -+ case Y_ONLY: -+ val[0] = 0; -+ break; -+ /* set YUV default color space conversion to BT601 */ -+ case YCBCR_4_4_4: -+ val[0] = 6 + BT_601 * 8; -+ break; -+ case YCBCR_4_2_2: -+ val[0] = 5 + BT_601 * 8; -+ break; -+ case YCBCR_4_2_0: -+ val[0] = 5; -+ break; -+ } -+ -+ switch (video->color_depth) { -+ case 6: -+ val[1] = 0; -+ break; -+ case 8: -+ val[1] = 1; -+ break; -+ case 10: -+ val[1] = 2; -+ break; -+ case 12: -+ val[1] = 3; -+ break; -+ case 16: -+ val[1] = 4; -+ break; -+ } -+ -+ msa_misc = 2 * val[0] + 32 * val[1] + -+ ((video->color_fmt == Y_ONLY) ? (1 << 14) : 0); -+ -+ return msa_misc; -+} -+ -+int cdns_mhdp_config_video(struct cdns_mhdp_device *mhdp) -+{ -+ struct video_info *video = &mhdp->video_info; -+ struct drm_display_mode *mode = &mhdp->mode; -+ u64 symbol; -+ u32 val, link_rate, rem; -+ u8 bit_per_pix, tu_size_reg = TU_SIZE; -+ int ret; -+ -+ bit_per_pix = (video->color_fmt == YCBCR_4_2_2) ? -+ (video->color_depth * 2) : (video->color_depth * 3); -+ -+ link_rate = mhdp->dp.rate / 1000; -+ -+ ret = cdns_mhdp_reg_write(mhdp, BND_HSYNC2VSYNC, VIF_BYPASS_INTERLACE); -+ if (ret) -+ goto err_config_video; -+ -+ ret = cdns_mhdp_reg_write(mhdp, HSYNC2VSYNC_POL_CTRL, 0); -+ if (ret) -+ goto err_config_video; -+ -+ /* -+ * get a best tu_size and valid symbol: -+ * 1. chose Lclk freq(162Mhz, 270Mhz, 540Mhz), set TU to 32 -+ * 2. calculate VS(valid symbol) = TU * Pclk * Bpp / (Lclk * Lanes) -+ * 3. if VS > *.85 or VS < *.1 or VS < 2 or TU < VS + 4, then set -+ * TU += 2 and repeat 2nd step. -+ */ -+ do { -+ tu_size_reg += 2; -+ symbol = tu_size_reg * mode->clock * bit_per_pix; -+ do_div(symbol, mhdp->dp.num_lanes * link_rate * 8); -+ rem = do_div(symbol, 1000); -+ if (tu_size_reg > 64) { -+ ret = -EINVAL; -+ DRM_DEV_ERROR(mhdp->dev, -+ "tu error, clk:%d, lanes:%d, rate:%d\n", -+ mode->clock, mhdp->dp.num_lanes, -+ link_rate); -+ goto err_config_video; -+ } -+ } while ((symbol <= 1) || (tu_size_reg - symbol < 4) || -+ (rem > 850) || (rem < 100)); -+ -+ val = symbol + (tu_size_reg << 8); -+ val |= TU_CNT_RST_EN; -+ ret = cdns_mhdp_reg_write(mhdp, DP_FRAMER_TU, val); -+ if (ret) -+ goto err_config_video; -+ -+ /* set the FIFO Buffer size */ -+ val = div_u64(mode->clock * (symbol + 1), 1000) + link_rate; -+ val /= (mhdp->dp.num_lanes * link_rate); -+ val = div_u64(8 * (symbol + 1), bit_per_pix) - val; -+ val += 2; -+ ret = cdns_mhdp_reg_write(mhdp, DP_VC_TABLE(15), val); -+ -+ switch (video->color_depth) { -+ case 6: -+ val = BCS_6; -+ break; -+ case 8: -+ val = BCS_8; -+ break; -+ case 10: -+ val = BCS_10; -+ break; -+ case 12: -+ val = BCS_12; -+ break; -+ case 16: -+ val = BCS_16; -+ break; -+ } -+ -+ val += video->color_fmt << 8; -+ ret = cdns_mhdp_reg_write(mhdp, DP_FRAMER_PXL_REPR, val); -+ if (ret) -+ goto err_config_video; -+ -+ val = video->h_sync_polarity ? DP_FRAMER_SP_HSP : 0; -+ val |= video->v_sync_polarity ? DP_FRAMER_SP_VSP : 0; -+ ret = cdns_mhdp_reg_write(mhdp, DP_FRAMER_SP, val); -+ if (ret) -+ goto err_config_video; -+ -+ val = (mode->hsync_start - mode->hdisplay) << 16; -+ val |= mode->htotal - mode->hsync_end; -+ ret = cdns_mhdp_reg_write(mhdp, DP_FRONT_BACK_PORCH, val); -+ if (ret) -+ goto err_config_video; -+ -+ val = mode->hdisplay * bit_per_pix / 8; -+ ret = cdns_mhdp_reg_write(mhdp, DP_BYTE_COUNT, val); -+ if (ret) -+ goto err_config_video; -+ -+ val = mode->htotal | ((mode->htotal - mode->hsync_start) << 16); -+ ret = cdns_mhdp_reg_write(mhdp, MSA_HORIZONTAL_0, val); -+ if (ret) -+ goto err_config_video; -+ -+ val = mode->hsync_end - mode->hsync_start; -+ val |= (mode->hdisplay << 16) | (video->h_sync_polarity << 15); -+ ret = cdns_mhdp_reg_write(mhdp, MSA_HORIZONTAL_1, val); -+ if (ret) -+ goto err_config_video; -+ -+ val = mode->vtotal; -+ val |= (mode->vtotal - mode->vsync_start) << 16; -+ ret = cdns_mhdp_reg_write(mhdp, MSA_VERTICAL_0, val); -+ if (ret) -+ goto err_config_video; -+ -+ val = mode->vsync_end - mode->vsync_start; -+ val |= (mode->vdisplay << 16) | (video->v_sync_polarity << 15); -+ ret = cdns_mhdp_reg_write(mhdp, MSA_VERTICAL_1, val); -+ if (ret) -+ goto err_config_video; -+ -+ val = mhdp_get_msa_misc(video, mode); -+ ret = cdns_mhdp_reg_write(mhdp, MSA_MISC, val); -+ if (ret) -+ goto err_config_video; -+ -+ ret = cdns_mhdp_reg_write(mhdp, STREAM_CONFIG, 1); -+ if (ret) -+ goto err_config_video; -+ -+ val = mode->hsync_end - mode->hsync_start; -+ val |= mode->hdisplay << 16; -+ ret = cdns_mhdp_reg_write(mhdp, DP_HORIZONTAL, val); -+ if (ret) -+ goto err_config_video; -+ -+ val = mode->vdisplay; -+ val |= (mode->vtotal - mode->vsync_start) << 16; -+ ret = cdns_mhdp_reg_write(mhdp, DP_VERTICAL_0, val); -+ if (ret) -+ goto err_config_video; -+ -+ val = mode->vtotal; -+ ret = cdns_mhdp_reg_write(mhdp, DP_VERTICAL_1, val); -+ if (ret) -+ goto err_config_video; -+ -+ ret = cdns_mhdp_reg_write_bit(mhdp, DP_VB_ID, 2, 1, 0); -+ -+err_config_video: -+ if (ret) -+ DRM_DEV_ERROR(mhdp->dev, "config video failed: %d\n", ret); -+ return ret; -+} -+EXPORT_SYMBOL(cdns_mhdp_config_video); -+ -+int cdns_phy_reg_write(struct cdns_mhdp_device *mhdp, u32 addr, u32 val) -+{ -+ return cdns_mhdp_reg_write(mhdp, ADDR_PHY_AFE + (addr << 2), val); -+} -+EXPORT_SYMBOL(cdns_phy_reg_write); -+ -+u32 cdns_phy_reg_read(struct cdns_mhdp_device *mhdp, u32 addr) -+{ -+ return cdns_mhdp_reg_read(mhdp, ADDR_PHY_AFE + (addr << 2)); -+} -+EXPORT_SYMBOL(cdns_phy_reg_read); -diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c -new file mode 100644 -index 000000000000..f025c39d12ea ---- /dev/null -+++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c -@@ -0,0 +1,172 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+ -+#include -+#include -+#include -+#include -+ -+#define LINK_TRAINING_TIMEOUT_MS 500 -+#define LINK_TRAINING_RETRY_MS 20 -+ -+int cdns_mhdp_dpcd_read(struct cdns_mhdp_device *mhdp, -+ u32 addr, u8 *data, u16 len) -+{ -+ u8 msg[5], reg[5]; -+ int ret; -+ -+ put_unaligned_be16(len, msg); -+ put_unaligned_be24(addr, msg + 2); -+ -+ ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, -+ DPTX_READ_DPCD, sizeof(msg), msg); -+ if (ret) -+ goto err_dpcd_read; -+ -+ ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_DP_TX, -+ DPTX_READ_DPCD, -+ sizeof(reg) + len); -+ if (ret) -+ goto err_dpcd_read; -+ -+ ret = cdns_mhdp_mailbox_read_receive(mhdp, reg, sizeof(reg)); -+ if (ret) -+ goto err_dpcd_read; -+ -+ ret = cdns_mhdp_mailbox_read_receive(mhdp, data, len); -+ -+err_dpcd_read: -+ return ret; -+} -+EXPORT_SYMBOL(cdns_mhdp_dpcd_read); -+ -+int cdns_mhdp_dpcd_write(struct cdns_mhdp_device *mhdp, u32 addr, u8 value) -+{ -+ u8 msg[6], reg[5]; -+ int ret; -+ -+ put_unaligned_be16(1, msg); -+ put_unaligned_be24(addr, msg + 2); -+ msg[5] = value; -+ -+ ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, -+ DPTX_WRITE_DPCD, sizeof(msg), msg); -+ if (ret) -+ goto err_dpcd_write; -+ -+ ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_DP_TX, -+ DPTX_WRITE_DPCD, sizeof(reg)); -+ if (ret) -+ goto err_dpcd_write; -+ -+ ret = cdns_mhdp_mailbox_read_receive(mhdp, reg, sizeof(reg)); -+ if (ret) -+ goto err_dpcd_write; -+ -+ if (addr != get_unaligned_be24(reg + 2)) -+ ret = -EINVAL; -+ -+err_dpcd_write: -+ if (ret) -+ DRM_DEV_ERROR(mhdp->dev, "dpcd write failed: %d\n", ret); -+ return ret; -+} -+EXPORT_SYMBOL(cdns_mhdp_dpcd_write); -+ -+static int cdns_mhdp_training_start(struct cdns_mhdp_device *mhdp) -+{ -+ unsigned long timeout; -+ u8 msg, event[2]; -+ int ret; -+ -+ msg = LINK_TRAINING_RUN; -+ -+ /* start training */ -+ ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, -+ DPTX_TRAINING_CONTROL, sizeof(msg), &msg); -+ if (ret) -+ goto err_training_start; -+ -+ timeout = jiffies + msecs_to_jiffies(LINK_TRAINING_TIMEOUT_MS); -+ while (time_before(jiffies, timeout)) { -+ msleep(LINK_TRAINING_RETRY_MS); -+ ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, -+ DPTX_READ_EVENT, 0, NULL); -+ if (ret) -+ goto err_training_start; -+ -+ ret = cdns_mhdp_mailbox_validate_receive(mhdp, -+ MB_MODULE_ID_DP_TX, -+ DPTX_READ_EVENT, -+ sizeof(event)); -+ if (ret) -+ goto err_training_start; -+ -+ ret = cdns_mhdp_mailbox_read_receive(mhdp, event, -+ sizeof(event)); -+ if (ret) -+ goto err_training_start; -+ -+ if (event[1] & EQ_PHASE_FINISHED) -+ return 0; -+ } -+ -+ ret = -ETIMEDOUT; -+ -+err_training_start: -+ DRM_DEV_ERROR(mhdp->dev, "training failed: %d\n", ret); -+ return ret; -+} -+ -+static int cdns_mhdp_get_training_status(struct cdns_mhdp_device *mhdp) -+{ -+ u8 status[10]; -+ int ret; -+ -+ ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, -+ DPTX_READ_LINK_STAT, 0, NULL); -+ if (ret) -+ goto err_get_training_status; -+ -+ ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_DP_TX, -+ DPTX_READ_LINK_STAT, -+ sizeof(status)); -+ if (ret) -+ goto err_get_training_status; -+ -+ ret = cdns_mhdp_mailbox_read_receive(mhdp, status, sizeof(status)); -+ if (ret) -+ goto err_get_training_status; -+ -+ mhdp->dp.rate = drm_dp_bw_code_to_link_rate(status[0]); -+ mhdp->dp.num_lanes = status[1]; -+ -+err_get_training_status: -+ if (ret) -+ DRM_DEV_ERROR(mhdp->dev, "get training status failed: %d\n", -+ ret); -+ return ret; -+} -+ -+int cdns_mhdp_train_link(struct cdns_mhdp_device *mhdp) -+{ -+ int ret; -+ -+ ret = cdns_mhdp_training_start(mhdp); -+ if (ret) { -+ DRM_DEV_ERROR(mhdp->dev, "Failed to start training %d\n", -+ ret); -+ return ret; -+ } -+ -+ ret = cdns_mhdp_get_training_status(mhdp); -+ if (ret) { -+ DRM_DEV_ERROR(mhdp->dev, "Failed to get training stat %d\n", -+ ret); -+ return ret; -+ } -+ -+ DRM_DEV_DEBUG_KMS(mhdp->dev, "rate:0x%x, lanes:%d\n", mhdp->dp.rate, -+ mhdp->dp.num_lanes); -+ return ret; -+} -+EXPORT_SYMBOL(cdns_mhdp_train_link); -diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdmi.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdmi.c -new file mode 100644 -index 000000000000..c37a7ac6af9b ---- /dev/null -+++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdmi.c -@@ -0,0 +1,332 @@ -+/* -+ * Copyright (C) 2019 NXP Semiconductor, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+void cdns_mhdp_infoframe_set(struct cdns_mhdp_device *mhdp, -+ u8 entry_id, u8 packet_len, u8 *packet, u8 packet_type) -+{ -+ u32 *packet32, len32; -+ u32 val, i; -+ -+ /* invalidate entry */ -+ val = F_ACTIVE_IDLE_TYPE(1) | F_PKT_ALLOC_ADDRESS(entry_id); -+ cdns_mhdp_bus_write(val, mhdp, SOURCE_PIF_PKT_ALLOC_REG); -+ cdns_mhdp_bus_write(F_PKT_ALLOC_WR_EN(1), mhdp, SOURCE_PIF_PKT_ALLOC_WR_EN); -+ -+ /* flush fifo 1 */ -+ cdns_mhdp_bus_write(F_FIFO1_FLUSH(1), mhdp, SOURCE_PIF_FIFO1_FLUSH); -+ -+ /* write packet into memory */ -+ packet32 = (u32 *)packet; -+ len32 = packet_len / 4; -+ for (i = 0; i < len32; i++) -+ cdns_mhdp_bus_write(F_DATA_WR(packet32[i]), mhdp, SOURCE_PIF_DATA_WR); -+ -+ /* write entry id */ -+ cdns_mhdp_bus_write(F_WR_ADDR(entry_id), mhdp, SOURCE_PIF_WR_ADDR); -+ -+ /* write request */ -+ cdns_mhdp_bus_write(F_HOST_WR(1), mhdp, SOURCE_PIF_WR_REQ); -+ -+ /* update entry */ -+ val = F_ACTIVE_IDLE_TYPE(1) | F_TYPE_VALID(1) | -+ F_PACKET_TYPE(packet_type) | F_PKT_ALLOC_ADDRESS(entry_id); -+ cdns_mhdp_bus_write(val, mhdp, SOURCE_PIF_PKT_ALLOC_REG); -+ -+ cdns_mhdp_bus_write(F_PKT_ALLOC_WR_EN(1), mhdp, SOURCE_PIF_PKT_ALLOC_WR_EN); -+} -+ -+int cdns_hdmi_get_edid_block(void *data, u8 *edid, -+ u32 block, size_t length) -+{ -+ struct cdns_mhdp_device *mhdp = data; -+ u8 msg[2], reg[5], i; -+ int ret; -+ -+ for (i = 0; i < 4; i++) { -+ msg[0] = block / 2; -+ msg[1] = block % 2; -+ -+ ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_HDMI_TX, HDMI_TX_EDID, -+ sizeof(msg), msg); -+ if (ret) -+ continue; -+ -+ ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_HDMI_TX, -+ HDMI_TX_EDID, sizeof(reg) + length); -+ if (ret) -+ continue; -+ -+ ret = cdns_mhdp_mailbox_read_receive(mhdp, reg, sizeof(reg)); -+ if (ret) -+ continue; -+ -+ ret = cdns_mhdp_mailbox_read_receive(mhdp, edid, length); -+ if (ret) -+ continue; -+ -+ if ((reg[3] << 8 | reg[4]) == length) -+ break; -+ } -+ -+ if (ret) -+ DRM_ERROR("get block[%d] edid failed: %d\n", block, ret); -+ return ret; -+} -+ -+int cdns_hdmi_scdc_read(struct cdns_mhdp_device *mhdp, u8 addr, u8 *data) -+{ -+ u8 msg[4], reg[6]; -+ int ret; -+ -+ msg[0] = 0x54; -+ msg[1] = addr; -+ msg[2] = 0; -+ msg[3] = 1; -+ ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_HDMI_TX, HDMI_TX_READ, -+ sizeof(msg), msg); -+ if (ret) -+ goto err_scdc_read; -+ -+ ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_HDMI_TX, -+ HDMI_TX_READ, sizeof(reg)); -+ if (ret) -+ goto err_scdc_read; -+ -+ ret = cdns_mhdp_mailbox_read_receive(mhdp, reg, sizeof(reg)); -+ if (ret) -+ goto err_scdc_read; -+ -+ *data = reg[5]; -+ -+err_scdc_read: -+ if (ret) -+ DRM_ERROR("scdc read failed: %d\n", ret); -+ return ret; -+} -+ -+int cdns_hdmi_scdc_write(struct cdns_mhdp_device *mhdp, u8 addr, u8 value) -+{ -+ u8 msg[5], reg[5]; -+ int ret; -+ -+ msg[0] = 0x54; -+ msg[1] = addr; -+ msg[2] = 0; -+ msg[3] = 1; -+ msg[4] = value; -+ ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_HDMI_TX, HDMI_TX_WRITE, -+ sizeof(msg), msg); -+ if (ret) -+ goto err_scdc_write; -+ -+ ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_HDMI_TX, -+ HDMI_TX_WRITE, sizeof(reg)); -+ if (ret) -+ goto err_scdc_write; -+ -+ ret = cdns_mhdp_mailbox_read_receive(mhdp, reg, sizeof(reg)); -+ if (ret) -+ goto err_scdc_write; -+ -+ if (reg[0] != 0) -+ ret = -EINVAL; -+ -+err_scdc_write: -+ if (ret) -+ DRM_ERROR("scdc write failed: %d\n", ret); -+ return ret; -+} -+ -+int cdns_hdmi_ctrl_init(struct cdns_mhdp_device *mhdp, -+ int protocol, -+ u32 char_rate) -+{ -+ u32 reg0; -+ u32 reg1; -+ u32 val; -+ int ret; -+ -+ /* Set PHY to HDMI data */ -+ ret = cdns_mhdp_reg_write(mhdp, PHY_DATA_SEL, F_SOURCE_PHY_MHDP_SEL(1)); -+ if (ret < 0) -+ return ret; -+ -+ ret = cdns_mhdp_reg_write(mhdp, HDTX_HPD, -+ F_HPD_VALID_WIDTH(4) | F_HPD_GLITCH_WIDTH(0)); -+ if (ret < 0) -+ return ret; -+ -+ /* open CARS */ -+ ret = cdns_mhdp_reg_write(mhdp, SOURCE_PHY_CAR, 0xF); -+ if (ret < 0) -+ return ret; -+ ret = cdns_mhdp_reg_write(mhdp, SOURCE_HDTX_CAR, 0xFF); -+ if (ret < 0) -+ return ret; -+ ret = cdns_mhdp_reg_write(mhdp, SOURCE_PKT_CAR, 0xF); -+ if (ret < 0) -+ return ret; -+ ret = cdns_mhdp_reg_write(mhdp, SOURCE_AIF_CAR, 0xF); -+ if (ret < 0) -+ return ret; -+ ret = cdns_mhdp_reg_write(mhdp, SOURCE_CIPHER_CAR, 0xF); -+ if (ret < 0) -+ return ret; -+ ret = cdns_mhdp_reg_write(mhdp, SOURCE_CRYPTO_CAR, 0xF); -+ if (ret < 0) -+ return ret; -+ ret = cdns_mhdp_reg_write(mhdp, SOURCE_CEC_CAR, 3); -+ if (ret < 0) -+ return ret; -+ -+ reg0 = reg1 = 0x7c1f; -+ if (protocol == MODE_HDMI_2_0 && char_rate >= 340000) { -+ reg0 = 0; -+ reg1 = 0xFFFFF; -+ } -+ ret = cdns_mhdp_reg_write(mhdp, HDTX_CLOCK_REG_0, reg0); -+ if (ret < 0) -+ return ret; -+ ret = cdns_mhdp_reg_write(mhdp, HDTX_CLOCK_REG_1, reg1); -+ if (ret < 0) -+ return ret; -+ -+ /* set hdmi mode and preemble mode data enable */ -+ val = F_HDMI_MODE(protocol) | F_HDMI2_PREAMBLE_EN(1) | F_DATA_EN(1) | -+ F_HDMI2_CTRL_IL_MODE(1) | F_BCH_EN(1) | F_PIC_3D(0XF); -+ ret = cdns_mhdp_reg_write(mhdp, HDTX_CONTROLLER, val); -+ -+ return ret; -+} -+ -+int cdns_hdmi_mode_config(struct cdns_mhdp_device *mhdp, -+ struct drm_display_mode *mode, -+ struct video_info *video_info) -+{ -+ int ret; -+ u32 val; -+ u32 vsync_lines = mode->vsync_end - mode->vsync_start; -+ u32 eof_lines = mode->vsync_start - mode->vdisplay; -+ u32 sof_lines = mode->vtotal - mode->vsync_end; -+ u32 hblank = mode->htotal - mode->hdisplay; -+ u32 hactive = mode->hdisplay; -+ u32 vblank = mode->vtotal - mode->vdisplay; -+ u32 vactive = mode->vdisplay; -+ u32 hfront = mode->hsync_start - mode->hdisplay; -+ u32 hback = mode->htotal - mode->hsync_end; -+ u32 vfront = eof_lines; -+ u32 hsync = hblank - hfront - hback; -+ u32 vsync = vsync_lines; -+ u32 vback = sof_lines; -+ u32 v_h_polarity = ((mode->flags & DRM_MODE_FLAG_NHSYNC) ? 0 : 1) + -+ ((mode->flags & DRM_MODE_FLAG_NVSYNC) ? 0 : 2); -+ -+ ret = cdns_mhdp_reg_write(mhdp, SCHEDULER_H_SIZE, (hactive << 16) + hblank); -+ if (ret < 0) -+ return ret; -+ -+ ret = cdns_mhdp_reg_write(mhdp, SCHEDULER_V_SIZE, (vactive << 16) + vblank); -+ if (ret < 0) -+ return ret; -+ -+ ret = cdns_mhdp_reg_write(mhdp, HDTX_SIGNAL_FRONT_WIDTH, (vfront << 16) + hfront); -+ if (ret < 0) -+ return ret; -+ -+ ret = cdns_mhdp_reg_write(mhdp, HDTX_SIGNAL_SYNC_WIDTH, (vsync << 16) + hsync); -+ if (ret < 0) -+ return ret; -+ -+ ret = cdns_mhdp_reg_write(mhdp, HDTX_SIGNAL_BACK_WIDTH, (vback << 16) + hback); -+ if (ret < 0) -+ return ret; -+ -+ ret = cdns_mhdp_reg_write(mhdp, HSYNC2VSYNC_POL_CTRL, v_h_polarity); -+ if (ret < 0) -+ return ret; -+ -+ /* Reset Data Enable */ -+ val = cdns_mhdp_reg_read(mhdp, HDTX_CONTROLLER); -+ val &= ~F_DATA_EN(1); -+ ret = cdns_mhdp_reg_write(mhdp, HDTX_CONTROLLER, val); -+ if (ret < 0) -+ return ret; -+ -+ /* Set bpc */ -+ val &= ~F_VIF_DATA_WIDTH(3); -+ switch (video_info->color_depth) { -+ case 10: -+ val |= F_VIF_DATA_WIDTH(1); -+ break; -+ case 12: -+ val |= F_VIF_DATA_WIDTH(2); -+ break; -+ case 16: -+ val |= F_VIF_DATA_WIDTH(3); -+ break; -+ case 8: -+ default: -+ val |= F_VIF_DATA_WIDTH(0); -+ break; -+ } -+ -+ /* select color encoding */ -+ val &= ~F_HDMI_ENCODING(3); -+ switch (video_info->color_fmt) { -+ case YCBCR_4_4_4: -+ val |= F_HDMI_ENCODING(2); -+ break; -+ case YCBCR_4_2_2: -+ val |= F_HDMI_ENCODING(1); -+ break; -+ case YCBCR_4_2_0: -+ val |= F_HDMI_ENCODING(3); -+ break; -+ case PXL_RGB: -+ default: -+ val |= F_HDMI_ENCODING(0); -+ break; -+ } -+ -+ ret = cdns_mhdp_reg_write(mhdp, HDTX_CONTROLLER, val); -+ if (ret < 0) -+ return ret; -+ -+ /* set data enable */ -+ val |= F_DATA_EN(1); -+ ret = cdns_mhdp_reg_write(mhdp, HDTX_CONTROLLER, val); -+ -+ return ret; -+} -+ -+int cdns_hdmi_disable_gcp(struct cdns_mhdp_device *mhdp) -+{ -+ u32 val; -+ -+ val = cdns_mhdp_reg_read(mhdp, HDTX_CONTROLLER); -+ val &= ~F_GCP_EN(1); -+ -+ return cdns_mhdp_reg_write(mhdp, HDTX_CONTROLLER, val); -+} -+ -+int cdns_hdmi_enable_gcp(struct cdns_mhdp_device *mhdp) -+{ -+ u32 val; -+ -+ val = cdns_mhdp_reg_read(mhdp, HDTX_CONTROLLER); -+ val |= F_GCP_EN(1); -+ -+ return cdns_mhdp_reg_write(mhdp, HDTX_CONTROLLER, val); -+} -diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp.h b/drivers/gpu/drm/bridge/cadence/cdns-mhdp.h -new file mode 100644 -index 000000000000..399c3f6f86ad ---- /dev/null -+++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp.h -@@ -0,0 +1,209 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Cadence MHDP DP MST bridge driver. -+ * -+ * Copyright: 2018 Cadence Design Systems, Inc. -+ * -+ * Author: Quentin Schulz -+ */ -+ -+ -+#ifndef CDNS_MHDP_H -+#define CDNS_MHDP_H -+ -+#include -+ -+#define CDNS_APB_CFG 0x00000 -+#define CDNS_APB_CTRL (CDNS_APB_CFG + 0x00) -+#define CDNS_MAILBOX_FULL (CDNS_APB_CFG + 0x08) -+#define CDNS_MAILBOX_EMPTY (CDNS_APB_CFG + 0x0c) -+#define CDNS_MAILBOX_TX_DATA (CDNS_APB_CFG + 0x10) -+#define CDNS_MAILBOX_RX_DATA (CDNS_APB_CFG + 0x14) -+#define CDNS_KEEP_ALIVE (CDNS_APB_CFG + 0x18) -+#define CDNS_KEEP_ALIVE_MASK GENMASK(7, 0) -+ -+#define CDNS_MB_INT_MASK (CDNS_APB_CFG + 0x34) -+ -+#define CDNS_SW_CLK_L (CDNS_APB_CFG + 0x3c) -+#define CDNS_SW_CLK_H (CDNS_APB_CFG + 0x40) -+#define CDNS_SW_EVENT0 (CDNS_APB_CFG + 0x44) -+#define CDNS_DPTX_HPD BIT(0) -+ -+#define CDNS_SW_EVENT1 (CDNS_APB_CFG + 0x48) -+#define CDNS_SW_EVENT2 (CDNS_APB_CFG + 0x4c) -+#define CDNS_SW_EVENT3 (CDNS_APB_CFG + 0x50) -+ -+#define CDNS_APB_INT_MASK (CDNS_APB_CFG + 0x6C) -+#define CDNS_APB_INT_MASK_MAILBOX_INT BIT(0) -+#define CDNS_APB_INT_MASK_SW_EVENT_INT BIT(1) -+ -+#define CDNS_DPTX_CAR (CDNS_APB_CFG + 0x904) -+#define CDNS_VIF_CLK_EN BIT(0) -+#define CDNS_VIF_CLK_RSTN BIT(1) -+ -+#define CDNS_SOURCE_VIDEO_IF(s) (0x00b00 + (s * 0x20)) -+#define CDNS_BND_HSYNC2VSYNC(s) (CDNS_SOURCE_VIDEO_IF(s) + \ -+ 0x00) -+#define CDNS_IP_DTCT_WIN GENMASK(11, 0) -+#define CDNS_IP_DET_INTERLACE_FORMAT BIT(12) -+#define CDNS_IP_BYPASS_V_INTERFACE BIT(13) -+ -+#define CDNS_HSYNC2VSYNC_POL_CTRL(s) (CDNS_SOURCE_VIDEO_IF(s) + \ -+ 0x10) -+#define CDNS_H2V_HSYNC_POL_ACTIVE_LOW BIT(1) -+#define CDNS_H2V_VSYNC_POL_ACTIVE_LOW BIT(2) -+ -+#define CDNS_DPTX_PHY_CONFIG 0x02000 -+#define CDNS_PHY_TRAINING_EN BIT(0) -+#define CDNS_PHY_TRAINING_TYPE(x) (((x) & GENMASK(3, 0)) << 1) -+#define CDNS_PHY_SCRAMBLER_BYPASS BIT(5) -+#define CDNS_PHY_ENCODER_BYPASS BIT(6) -+#define CDNS_PHY_SKEW_BYPASS BIT(7) -+#define CDNS_PHY_TRAINING_AUTO BIT(8) -+#define CDNS_PHY_LANE0_SKEW(x) (((x) & GENMASK(2, 0)) << 9) -+#define CDNS_PHY_LANE1_SKEW(x) (((x) & GENMASK(2, 0)) << 12) -+#define CDNS_PHY_LANE2_SKEW(x) (((x) & GENMASK(2, 0)) << 15) -+#define CDNS_PHY_LANE3_SKEW(x) (((x) & GENMASK(2, 0)) << 18) -+#define CDNS_PHY_COMMON_CONFIG (CDNS_PHY_LANE1_SKEW(1) | \ -+ CDNS_PHY_LANE2_SKEW(2) | \ -+ CDNS_PHY_LANE3_SKEW(3)) -+#define CDNS_PHY_10BIT_EN BIT(21) -+ -+#define CDNS_DPTX_FRAMER 0x02200 -+#define CDNS_DP_FRAMER_GLOBAL_CONFIG (CDNS_DPTX_FRAMER + 0x00) -+#define CDNS_DP_NUM_LANES(x) (x - 1) -+#define CDNS_DP_MST_EN BIT(2) -+#define CDNS_DP_FRAMER_EN BIT(3) -+#define CDNS_DP_RATE_GOVERNOR_EN BIT(4) -+#define CDNS_DP_NO_VIDEO_MODE BIT(5) -+#define CDNS_DP_DISABLE_PHY_RST BIT(6) -+#define CDNS_DP_WR_FAILING_EDGE_VSYNC BIT(7) -+ -+#define CDNS_DP_SW_RESET (CDNS_DPTX_FRAMER + 0x04) -+#define CDNS_DP_FRAMER_TU (CDNS_DPTX_FRAMER + 0x08) -+#define CDNS_DP_FRAMER_TU_SIZE(x) (((x) & GENMASK(6, 0)) << 8) -+#define CDNS_DP_FRAMER_TU_VS(x) ((x) & GENMASK(5, 0)) -+#define CDNS_DP_FRAMER_TU_CNT_RST_EN BIT(15) -+ -+#define CDNS_DPTX_STREAM(s) (0x03000 + s * 0x80) -+#define CDNS_DP_MSA_HORIZONTAL_0(s) (CDNS_DPTX_STREAM(s) + 0x00) -+#define CDNS_DP_MSAH0_H_TOTAL(x) (x) -+#define CDNS_DP_MSAH0_HSYNC_START(x) ((x) << 16) -+ -+#define CDNS_DP_MSA_HORIZONTAL_1(s) (CDNS_DPTX_STREAM(s) + 0x04) -+#define CDNS_DP_MSAH1_HSYNC_WIDTH(x) (x) -+#define CDNS_DP_MSAH1_HSYNC_POL_LOW BIT(15) -+#define CDNS_DP_MSAH1_HDISP_WIDTH(x) ((x) << 16) -+ -+#define CDNS_DP_MSA_VERTICAL_0(s) (CDNS_DPTX_STREAM(s) + 0x08) -+#define CDNS_DP_MSAV0_V_TOTAL(x) (x) -+#define CDNS_DP_MSAV0_VSYNC_START(x) ((x) << 16) -+ -+#define CDNS_DP_MSA_VERTICAL_1(s) (CDNS_DPTX_STREAM(s) + 0x0c) -+#define CDNS_DP_MSAV1_VSYNC_WIDTH(x) (x) -+#define CDNS_DP_MSAV1_VSYNC_POL_LOW BIT(15) -+#define CDNS_DP_MSAV1_VDISP_WIDTH(x) ((x) << 16) -+ -+#define CDNS_DP_MSA_MISC(s) (CDNS_DPTX_STREAM(s) + 0x10) -+#define CDNS_DP_STREAM_CONFIGs(s) (CDNS_DPTX_STREAM(s) + 0x14) -+#define CDNS_DP_STREAM_CONFIG_2(s) (CDNS_DPTX_STREAM(s) + 0x2c) -+#define CDNS_DP_SC2_TU_VS_DIFF(x) ((x) << 8) -+ -+#define CDNS_DP_HORIZONTAL(s) (CDNS_DPTX_STREAM(s) + 0x30) -+#define CDNS_DP_H_HSYNC_WIDTH(x) (x) -+#define CDNS_DP_H_H_TOTAL(x) ((x) << 16) -+ -+#define CDNS_DP_VERTICAL_0(s) (CDNS_DPTX_STREAM(s) + 0x34) -+#define CDNS_DP_V0_VHEIGHT(x) (x) -+#define CDNS_DP_V0_VSTART(x) ((x) << 16) -+ -+#define CDNS_DP_VERTICAL_1(s) (CDNS_DPTX_STREAM(s) + 0x38) -+#define CDNS_DP_V1_VTOTAL(x) (x) -+#define CDNS_DP_V1_VTOTAL_EVEN BIT(16) -+ -+#define CDNS_DP_FRAMER_PXL_REPR(s) (CDNS_DPTX_STREAM(s) + 0x4c) -+#define CDNS_DP_FRAMER_6_BPC BIT(0) -+#define CDNS_DP_FRAMER_8_BPC BIT(1) -+#define CDNS_DP_FRAMER_10_BPC BIT(2) -+#define CDNS_DP_FRAMER_12_BPC BIT(3) -+#define CDNS_DP_FRAMER_16_BPC BIT(4) -+#define CDNS_DP_FRAMER_PXL_FORMAT 0x8 -+#define CDNS_DP_FRAMER_RGB BIT(0) -+#define CDNS_DP_FRAMER_YCBCR444 BIT(1) -+#define CDNS_DP_FRAMER_YCBCR422 BIT(2) -+#define CDNS_DP_FRAMER_YCBCR420 BIT(3) -+#define CDNS_DP_FRAMER_Y_ONLY BIT(4) -+ -+#define CDNS_DP_FRAMER_SP(s) (CDNS_DPTX_STREAM(s) + 0x10) -+#define CDNS_DP_FRAMER_VSYNC_POL_LOW BIT(0) -+#define CDNS_DP_FRAMER_HSYNC_POL_LOW BIT(1) -+#define CDNS_DP_FRAMER_INTERLACE BIT(2) -+ -+#define CDNS_DP_LINE_THRESH(s) (CDNS_DPTX_STREAM(s) + 0x64) -+#define CDNS_DP_ACTIVE_LINE_THRESH(x) (x) -+ -+#define CDNS_DP_VB_ID(s) (CDNS_DPTX_STREAM(s) + 0x68) -+#define CDNS_DP_VB_ID_INTERLACED BIT(2) -+#define CDNS_DP_VB_ID_COMPRESSED BIT(6) -+ -+#define CDNS_DP_FRONT_BACK_PORCH(s) (CDNS_DPTX_STREAM(s) + 0x78) -+#define CDNS_DP_BACK_PORCH(x) (x) -+#define CDNS_DP_FRONT_PORCH(x) ((x) << 16) -+ -+#define CDNS_DP_BYTE_COUNT(s) (CDNS_DPTX_STREAM(s) + 0x7c) -+#define CDNS_DP_BYTE_COUNT_BYTES_IN_CHUNK_SHIFT 16 -+ -+#define CDNS_DP_MST_STREAM_CONFIG(s) (CDNS_DPTX_STREAM(s) + 0x14) -+#define CDNS_DP_MST_STRM_CFG_STREAM_EN BIT(0) -+#define CDNS_DP_MST_STRM_CFG_NO_VIDEO BIT(1) -+ -+#define CDNS_DP_MST_SLOT_ALLOCATE(s) (CDNS_DPTX_STREAM(s) + 0x44) -+#define CDNS_DP_S_ALLOC_START_SLOT(x) (x) -+#define CDNS_DP_S_ALLOC_END_SLOT(x) ((x) << 8) -+ -+#define CDNS_DP_RATE_GOVERNING(s) (CDNS_DPTX_STREAM(s) + 0x48) -+#define CDNS_DP_RG_TARG_AV_SLOTS_Y(x) (x) -+#define CDNS_DP_RG_TARG_AV_SLOTS_X(x) (x << 4) -+#define CDNS_DP_RG_ENABLE BIT(10) -+ -+#define CDNS_DP_MTPH_CONTROL 0x2264 -+#define CDNS_DP_MTPH_ECF_EN BIT(0) -+#define CDNS_DP_MTPH_ACT_EN BIT(1) -+#define CDNS_DP_MTPH_LVP_EN BIT(2) -+ -+#define CDNS_DP_MTPH_STATUS 0x226C -+#define CDNS_DP_MTPH_ACT_STATUS BIT(0) -+ -+ -+#define CDNS_DPTX_GLOBAL 0x02300 -+#define CDNS_DP_LANE_EN (CDNS_DPTX_GLOBAL + 0x00) -+#define CDNS_DP_LANE_EN_LANES(x) GENMASK(x - 1, 0) -+#define CDNS_DP_ENHNCD (CDNS_DPTX_GLOBAL + 0x04) -+ -+ -+#define to_mhdp_connector(x) container_of(x, struct cdns_mhdp_connector, base) -+#define to_mhdp_bridge(x) container_of(x, struct cdns_mhdp_bridge, base) -+#define mgr_to_mhdp(x) container_of(x, struct cdns_mhdp_device, mst_mgr) -+ -+#define CDNS_MHDP_MAX_STREAMS 4 -+ -+enum pixel_format { -+ PIXEL_FORMAT_RGB = 1, -+ PIXEL_FORMAT_YCBCR_444 = 2, -+ PIXEL_FORMAT_YCBCR_422 = 4, -+ PIXEL_FORMAT_YCBCR_420 = 8, -+ PIXEL_FORMAT_Y_ONLY = 16, -+}; -+ -+ -+int cdns_mhdp_mst_init(struct cdns_mhdp_device *mhdp); -+void cdns_mhdp_mst_deinit(struct cdns_mhdp_device *mhdp); -+bool cdns_mhdp_mst_probe(struct cdns_mhdp_device *mhdp); -+enum pixel_format cdns_mhdp_get_pxlfmt(u32 color_formats); -+u32 cdns_mhdp_get_bpp(u32 bpc, u32 color_formats); -+void cdns_mhdp_configure_video(struct drm_bridge *bridge); -+void cdns_mhdp_mst_enable(struct drm_bridge *bridge); -+void cdns_mhdp_mst_disable(struct drm_bridge *bridge); -+void cdns_mhdp_enable(struct drm_bridge *bridge); -+ -+#endif -diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile -index 17a9e7eb2130..bd013659404f 100644 ---- a/drivers/gpu/drm/rockchip/Makefile -+++ b/drivers/gpu/drm/rockchip/Makefile -@@ -8,7 +8,7 @@ rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \ - rockchipdrm-$(CONFIG_ROCKCHIP_VOP2) += rockchip_drm_vop2.o rockchip_vop2_reg.o - rockchipdrm-$(CONFIG_ROCKCHIP_VOP) += rockchip_drm_vop.o rockchip_vop_reg.o - rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o --rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o -+rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o - rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o - rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi-rockchip.o - rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o -diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c -index a4a45daf93f2..058bc372f02b 100644 ---- a/drivers/gpu/drm/rockchip/cdn-dp-core.c -+++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c -@@ -23,10 +23,9 @@ - #include - - #include "cdn-dp-core.h" --#include "cdn-dp-reg.h" - - static inline struct cdn_dp_device *connector_to_dp(struct drm_connector *connector) - { -- return container_of(connector, struct cdn_dp_device, connector); -+ return container_of(connector, struct cdn_dp_device, mhdp.connector.base); - } - -@@ -62,17 +61,18 @@ MODULE_DEVICE_TABLE(of, cdn_dp_dt_ids); - static int cdn_dp_grf_write(struct cdn_dp_device *dp, - unsigned int reg, unsigned int val) - { -+ struct device *dev = dp->mhdp.dev; - int ret; - - ret = clk_prepare_enable(dp->grf_clk); - if (ret) { -- DRM_DEV_ERROR(dp->dev, "Failed to prepare_enable grf clock\n"); -+ DRM_DEV_ERROR(dev, "Failed to prepare_enable grf clock\n"); - return ret; - } - - ret = regmap_write(dp->grf, reg, val); - if (ret) { -- DRM_DEV_ERROR(dp->dev, "Could not write to GRF: %d\n", ret); -+ DRM_DEV_ERROR(dev, "Could not write to GRF: %d\n", ret); - clk_disable_unprepare(dp->grf_clk); - return ret; - } -@@ -83,24 +83,25 @@ static int cdn_dp_grf_write(struct cdn_dp_device *dp, - - static int cdn_dp_clk_enable(struct cdn_dp_device *dp) - { -+ struct device *dev = dp->mhdp.dev; - int ret; - unsigned long rate; - - ret = clk_prepare_enable(dp->pclk); - if (ret < 0) { -- DRM_DEV_ERROR(dp->dev, "cannot enable dp pclk %d\n", ret); -+ DRM_DEV_ERROR(dev, "cannot enable dp pclk %d\n", ret); - goto err_pclk; - } - - ret = clk_prepare_enable(dp->core_clk); - if (ret < 0) { -- DRM_DEV_ERROR(dp->dev, "cannot enable core_clk %d\n", ret); -+ DRM_DEV_ERROR(dev, "cannot enable core_clk %d\n", ret); - goto err_core_clk; - } - -- ret = pm_runtime_get_sync(dp->dev); -+ ret = pm_runtime_get_sync(dev); - if (ret < 0) { -- DRM_DEV_ERROR(dp->dev, "cannot get pm runtime %d\n", ret); -+ DRM_DEV_ERROR(dev, "cannot get pm runtime %d\n", ret); - goto err_pm_runtime_get; - } - -@@ -113,18 +114,18 @@ static int cdn_dp_clk_enable(struct cdn_dp_device *dp) - - rate = clk_get_rate(dp->core_clk); - if (!rate) { -- DRM_DEV_ERROR(dp->dev, "get clk rate failed\n"); -+ DRM_DEV_ERROR(dev, "get clk rate failed\n"); - ret = -EINVAL; - goto err_set_rate; - } - -- cdn_dp_set_fw_clk(dp, rate); -- cdn_dp_clock_reset(dp); -+ cdns_mhdp_set_fw_clk(&dp->mhdp, rate); -+ cdns_mhdp_clock_reset(&dp->mhdp); - - return 0; - - err_set_rate: -- pm_runtime_put(dp->dev); -+ pm_runtime_put(dev); - err_pm_runtime_get: - clk_disable_unprepare(dp->core_clk); - err_core_clk: -@@ -135,7 +136,7 @@ static int cdn_dp_clk_enable(struct cdn_dp_device *dp) - - static void cdn_dp_clk_disable(struct cdn_dp_device *dp) - { -- pm_runtime_put_sync(dp->dev); -+ pm_runtime_put_sync(dp->mhdp.dev); - clk_disable_unprepare(dp->pclk); - clk_disable_unprepare(dp->core_clk); - } -@@ -168,7 +169,7 @@ static int cdn_dp_get_sink_count(struct cdn_dp_device *dp, u8 *sink_count) - u8 value; - - *sink_count = 0; -- ret = cdn_dp_dpcd_read(dp, DP_SINK_COUNT, &value, 1); -+ ret = drm_dp_dpcd_read(&dp->mhdp.dp.aux, DP_SINK_COUNT, &value, 1); - if (ret) - return ret; - -@@ -192,12 +193,13 @@ static struct cdn_dp_port *cdn_dp_connected_port(struct cdn_dp_device *dp) - - static bool cdn_dp_check_sink_connection(struct cdn_dp_device *dp) - { -+ struct device *dev = dp->mhdp.dev; - unsigned long timeout = jiffies + msecs_to_jiffies(CDN_DPCD_TIMEOUT_MS); - struct cdn_dp_port *port; - u8 sink_count = 0; - - if (dp->active_port < 0 || dp->active_port >= dp->ports) { -- DRM_DEV_ERROR(dp->dev, "active_port is wrong!\n"); -+ DRM_DEV_ERROR(dev, "active_port is wrong!\n"); - return false; - } - -@@ -219,7 +221,7 @@ static bool cdn_dp_check_sink_connection(struct cdn_dp_device *dp) - usleep_range(5000, 10000); - } - -- DRM_DEV_ERROR(dp->dev, "Get sink capability timed out\n"); -+ DRM_DEV_ERROR(dev, "Get sink capability timed out\n"); - return false; - } - -@@ -261,7 +263,8 @@ static int cdn_dp_connector_get_modes(struct drm_connector *connector) - /* FIXME: get rid of drm_edid_raw() */ - const struct edid *edid = drm_edid_raw(dp->drm_edid); - -- DRM_DEV_DEBUG_KMS(dp->dev, "got edid: width[%d] x height[%d]\n", -+ DRM_DEV_DEBUG_KMS(dp->mhdp.dev, -+ "got edid: width[%d] x height[%d]\n", - edid->width_cm, edid->height_cm); - - } -@@ -279,7 +282,8 @@ cdn_dp_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) - { - struct cdn_dp_device *dp = connector_to_dp(connector); -- struct drm_display_info *display_info = &dp->connector.display_info; -+ struct drm_display_info *display_info = -+ &dp->mhdp.connector.base.display_info; - u32 requested, actual, rate, sink_max, source_max = 0; - u8 lanes, bpc; - -@@ -302,11 +306,11 @@ static int cdn_dp_connector_mode_valid(struct drm_connector *connector, - requested = mode->clock * bpc * 3 / 1000; - - source_max = dp->lanes; -- sink_max = drm_dp_max_lane_count(dp->dpcd); -+ sink_max = drm_dp_max_lane_count(dp->mhdp.dp.dpcd); - lanes = min(source_max, sink_max); - -- source_max = drm_dp_bw_code_to_link_rate(CDN_DP_MAX_LINK_RATE); -- sink_max = drm_dp_max_link_rate(dp->dpcd); -+ source_max = CDNS_DP_MAX_LINK_RATE; -+ sink_max = drm_dp_max_link_rate(dp->mhdp.dp.dpcd); - rate = min(source_max, sink_max); - - actual = rate * lanes / 100; -@@ -315,7 +319,7 @@ static int cdn_dp_connector_mode_valid(struct drm_connector *connector, - actual = actual * 8 / 10; - - if (requested > actual) { -- DRM_DEV_DEBUG_KMS(dp->dev, -+ DRM_DEV_DEBUG_KMS(dp->mhdp.dev, - "requested=%d, actual=%d, clock=%d\n", - requested, actual, mode->clock); - return MODE_CLOCK_HIGH; -@@ -335,63 +339,66 @@ static int cdn_dp_firmware_init(struct cdn_dp_device *dp) - const u32 *iram_data, *dram_data; - const struct firmware *fw = dp->fw; - const struct cdn_firmware_header *hdr; -+ struct device *dev = dp->mhdp.dev; - - hdr = (struct cdn_firmware_header *)fw->data; - if (fw->size != le32_to_cpu(hdr->size_bytes)) { -- DRM_DEV_ERROR(dp->dev, "firmware is invalid\n"); -+ DRM_DEV_ERROR(dev, "firmware is invalid\n"); - return -EINVAL; - } - - iram_data = (const u32 *)(fw->data + hdr->header_size); - dram_data = (const u32 *)(fw->data + hdr->header_size + hdr->iram_size); - -- ret = cdn_dp_load_firmware(dp, iram_data, hdr->iram_size, -- dram_data, hdr->dram_size); -+ ret = cdns_mhdp_load_firmware(&dp->mhdp, iram_data, hdr->iram_size, -+ dram_data, hdr->dram_size); - if (ret) - return ret; - -- ret = cdn_dp_set_firmware_active(dp, true); -+ ret = cdns_mhdp_set_firmware_active(&dp->mhdp, true); - if (ret) { -- DRM_DEV_ERROR(dp->dev, "active ucpu failed: %d\n", ret); -+ DRM_DEV_ERROR(dev, "active ucpu failed: %d\n", ret); - return ret; - } - -- return cdn_dp_event_config(dp); -+ return cdns_mhdp_event_config(&dp->mhdp); - } - - static int cdn_dp_get_sink_capability(struct cdn_dp_device *dp) - { -+ struct cdns_mhdp_device *mhdp = &dp->mhdp; - int ret; - - if (!cdn_dp_check_sink_connection(dp)) - return -ENODEV; - -- ret = cdn_dp_dpcd_read(dp, DP_DPCD_REV, dp->dpcd, -+ ret = drm_dp_dpcd_read(&mhdp->dp.aux, DP_DPCD_REV, mhdp->dp.dpcd, - DP_RECEIVER_CAP_SIZE); - if (ret) { -- DRM_DEV_ERROR(dp->dev, "Failed to get caps %d\n", ret); -+ DRM_DEV_ERROR(mhdp->dev, "Failed to get caps %d\n", ret); - return ret; - } - - drm_edid_free(dp->drm_edid); -- dp->drm_edid = drm_edid_read_custom(&dp->connector, -- cdn_dp_get_edid_block, dp); -- drm_edid_connector_update(&dp->connector, dp->drm_edid); -+ dp->drm_edid = drm_edid_read_custom(&mhdp->connector.base, -+ cdns_mhdp_get_edid_block, mhdp); -+ drm_edid_connector_update(&mhdp->connector, dp->drm_edid); - -- dp->sink_has_audio = dp->connector.display_info.has_audio; -+ dp->sink_has_audio = mhdp->connector.display_info.has_audio; - - return 0; - } - - static int cdn_dp_enable_phy(struct cdn_dp_device *dp, struct cdn_dp_port *port) - { -+ struct device *dev = dp->mhdp.dev; - union extcon_property_value property; - int ret; - - if (!port->phy_enabled) { - ret = phy_power_on(port->phy); - if (ret) { -- DRM_DEV_ERROR(dp->dev, "phy power on failed: %d\n", -+ DRM_DEV_ERROR(dev, "phy power on failed: %d\n", - ret); - goto err_phy; - } -@@ -397,28 +404,28 @@ static int cdn_dp_enable_phy(struct cdn_dp_device *dp, struct cdn_dp_port *port) - ret = cdn_dp_grf_write(dp, GRF_SOC_CON26, - DPTX_HPD_SEL_MASK | DPTX_HPD_SEL); - if (ret) { -- DRM_DEV_ERROR(dp->dev, "Failed to write HPD_SEL %d\n", ret); -+ DRM_DEV_ERROR(dev, "Failed to write HPD_SEL %d\n", ret); - goto err_power_on; - } - -- ret = cdn_dp_get_hpd_status(dp); -+ ret = cdns_mhdp_read_hpd(&dp->mhdp); - if (ret <= 0) { - if (!ret) -- DRM_DEV_ERROR(dp->dev, "hpd does not exist\n"); -+ DRM_DEV_ERROR(dev, "hpd does not exist\n"); - goto err_power_on; - } - - ret = extcon_get_property(port->extcon, EXTCON_DISP_DP, - EXTCON_PROP_USB_TYPEC_POLARITY, &property); - if (ret) { -- DRM_DEV_ERROR(dp->dev, "get property failed\n"); -+ DRM_DEV_ERROR(dev, "get property failed\n"); - goto err_power_on; - } - - port->lanes = cdn_dp_get_port_lanes(port); -- ret = cdn_dp_set_host_cap(dp, port->lanes, property.intval); -+ ret = cdns_mhdp_set_host_cap(&dp->mhdp, property.intval); - if (ret) { -- DRM_DEV_ERROR(dp->dev, "set host capabilities failed: %d\n", -+ DRM_DEV_ERROR(dev, "set host capabilities failed: %d\n", - ret); - goto err_power_on; - } -@@ -440,7 +447,7 @@ static int cdn_dp_enable_phy(struct cdn_dp_device *dp, struct cdn_dp_port *port) - - err_power_on: - if (phy_power_off(port->phy)) -- DRM_DEV_ERROR(dp->dev, "phy power off failed: %d", ret); -+ DRM_DEV_ERROR(dev, "phy power off failed: %d", ret); - else - port->phy_enabled = false; - -@@ -458,7 +465,8 @@ static int cdn_dp_disable_phy(struct cdn_dp_device *dp, - if (port->phy_enabled) { - ret = phy_power_off(port->phy); - if (ret) { -- DRM_DEV_ERROR(dp->dev, "phy power off failed: %d", ret); -+ DRM_DEV_ERROR(dp->mhdp.dev, -+ "phy power off failed: %d", ret); - return ret; - } - } -@@ -470,16 +478,16 @@ static int cdn_dp_disable(struct cdn_dp_device *dp) - ret = cdn_dp_grf_write(dp, GRF_SOC_CON26, - DPTX_HPD_SEL_MASK | DPTX_HPD_DEL); - if (ret) { -- DRM_DEV_ERROR(dp->dev, "Failed to clear hpd sel %d\n", -+ DRM_DEV_ERROR(dp->mhdp.dev, "Failed to clear hpd sel %d\n", - ret); - return ret; - } - -- cdn_dp_set_firmware_active(dp, false); -+ cdns_mhdp_set_firmware_active(&dp->mhdp, false); - cdn_dp_clk_disable(dp); - dp->active = false; -- dp->max_lanes = 0; -- dp->max_rate = 0; -+ dp->mhdp.dp.rate = 0; -+ dp->mhdp.dp.num_lanes = 0; - if (!dp->connected) { - drm_edid_free(dp->drm_edid); - dp->drm_edid = NULL; -@@ -492,11 +500,11 @@ static int cdn_dp_enable(struct cdn_dp_device *dp) - { - int ret, i, lanes; - struct cdn_dp_port *port; -+ struct device *dev = dp->mhdp.dev; - - port = cdn_dp_connected_port(dp); - if (!port) { -- DRM_DEV_ERROR(dp->dev, -- "Can't enable without connection\n"); -+ DRM_DEV_ERROR(dev, "Can't enable without connection\n"); - return -ENODEV; - } - -@@ -509,7 +517,7 @@ static int cdn_dp_enable(struct cdn_dp_device *dp) - - ret = cdn_dp_firmware_init(dp); - if (ret) { -- DRM_DEV_ERROR(dp->dev, "firmware init failed: %d", ret); -+ DRM_DEV_ERROR(dp->mhdp.dev, "firmware init failed: %d", ret); - goto err_clk_disable; - } - -@@ -543,8 +551,9 @@ static void cdn_dp_encoder_mode_set(struct drm_encoder *encoder, - struct drm_display_mode *adjusted) - { - struct cdn_dp_device *dp = encoder_to_dp(encoder); -- struct drm_display_info *display_info = &dp->connector.display_info; -- struct video_info *video = &dp->video_info; -+ struct drm_display_info *display_info = -+ &dp->mhdp.connector.base.display_info; -+ struct video_info *video = &dp->mhdp.video_info; - - switch (display_info->bpc) { - case 10: -@@ -562,20 +571,20 @@ static void cdn_dp_encoder_mode_set(struct drm_encoder *encoder, - video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC); - video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC); - -- drm_mode_copy(&dp->mode, adjusted); -+ drm_mode_copy(&dp->mhdp.mode, adjusted); - } - - static bool cdn_dp_check_link_status(struct cdn_dp_device *dp) - { - u8 link_status[DP_LINK_STATUS_SIZE]; - struct cdn_dp_port *port = cdn_dp_connected_port(dp); -- u8 sink_lanes = drm_dp_max_lane_count(dp->dpcd); -+ u8 sink_lanes = drm_dp_max_lane_count(dp->mhdp.dp.dpcd); - -- if (!port || !dp->max_rate || !dp->max_lanes) -+ if (!port || !dp->mhdp.dp.rate || !dp->mhdp.dp.num_lanes) - return false; - -- if (cdn_dp_dpcd_read(dp, DP_LANE0_1_STATUS, link_status, -- DP_LINK_STATUS_SIZE)) { -+ if (drm_dp_dpcd_read(&dp->mhdp.dp.aux, DP_LANE0_1_STATUS, link_status, -+ DP_LINK_STATUS_SIZE)) { - DRM_ERROR("Failed to get link status\n"); - return false; - } -@@ -587,15 +596,16 @@ static bool cdn_dp_check_link_status(struct cdn_dp_device *dp) - static void cdn_dp_encoder_enable(struct drm_encoder *encoder) - { - struct cdn_dp_device *dp = encoder_to_dp(encoder); -+ struct device *dev = dp->mhdp.dev; - int ret, val; - -- ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, encoder); -+ ret = drm_of_encoder_active_endpoint_id(dev->of_node, encoder); - if (ret < 0) { -- DRM_DEV_ERROR(dp->dev, "Could not get vop id, %d", ret); -+ DRM_DEV_ERROR(dev, "Could not get vop id, %d", ret); - return; - } - -- DRM_DEV_DEBUG_KMS(dp->dev, "vop %s output to cdn-dp\n", -+ DRM_DEV_DEBUG_KMS(dev, "vop %s output to cdn-dp\n", - (ret) ? "LIT" : "BIG"); - if (ret) - val = DP_SEL_VOP_LIT | (DP_SEL_VOP_LIT << 16); -@@ -610,33 +620,33 @@ static void cdn_dp_encoder_enable(struct drm_encoder *encoder) - - ret = cdn_dp_enable(dp); - if (ret) { -- DRM_DEV_ERROR(dp->dev, "Failed to enable encoder %d\n", -+ DRM_DEV_ERROR(dev, "Failed to enable encoder %d\n", - ret); - goto out; - } - if (!cdn_dp_check_link_status(dp)) { -- ret = cdn_dp_train_link(dp); -+ ret = cdns_mhdp_train_link(&dp->mhdp); - if (ret) { -- DRM_DEV_ERROR(dp->dev, "Failed link train %d\n", ret); -+ DRM_DEV_ERROR(dev, "Failed link train %d\n", ret); - goto out; - } - } - -- ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE); -+ ret = cdns_mhdp_set_video_status(&dp->mhdp, CONTROL_VIDEO_IDLE); - if (ret) { -- DRM_DEV_ERROR(dp->dev, "Failed to idle video %d\n", ret); -+ DRM_DEV_ERROR(dev, "Failed to idle video %d\n", ret); - goto out; - } - -- ret = cdn_dp_config_video(dp); -+ ret = cdns_mhdp_config_video(&dp->mhdp); - if (ret) { -- DRM_DEV_ERROR(dp->dev, "Failed to config video %d\n", ret); -+ DRM_DEV_ERROR(dev, "Failed to config video %d\n", ret); - goto out; - } - -- ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID); -+ ret = cdns_mhdp_set_video_status(&dp->mhdp, CONTROL_VIDEO_VALID); - if (ret) { -- DRM_DEV_ERROR(dp->dev, "Failed to valid video %d\n", ret); -+ DRM_DEV_ERROR(dev, "Failed to valid video %d\n", ret); - goto out; - } - -@@ -652,7 +662,8 @@ static void cdn_dp_encoder_disable(struct drm_encoder *encoder) - if (dp->active) { - ret = cdn_dp_disable(dp); - if (ret) { -- DRM_DEV_ERROR(dp->dev, "Failed to disable encoder %d\n", -+ DRM_DEV_ERROR(dp->mhdp.dev, -+ "Failed to disable encoder %d\n", - ret); - } - } -@@ -692,7 +703,7 @@ static const struct drm_encoder_helper_funcs cdn_dp_encoder_helper_funcs = { - - static int cdn_dp_parse_dt(struct cdn_dp_device *dp) - { -- struct device *dev = dp->dev; -+ struct device *dev = dp->mhdp.dev; - struct device_node *np = dev->of_node; - struct platform_device *pdev = to_platform_device(dev); - -@@ -704,10 +715,10 @@ static int cdn_dp_parse_dt(struct cdn_dp_device *dp) - return PTR_ERR(dp->grf); - } - -- dp->regs = devm_platform_ioremap_resource(pdev, 0); -- if (IS_ERR(dp->regs)) { -+ dp->mhdp.regs_base = devm_platform_ioremap_resource(pdev, 0); -+ if (IS_ERR(dp->mhdp.regs_base)) { - DRM_DEV_ERROR(dev, "ioremap reg failed\n"); -- return PTR_ERR(dp->regs); -+ return PTR_ERR(dp->mhdp.regs_base); - } - - dp->core_clk = devm_clk_get(dev, "core-clk"); -@@ -722,10 +733,10 @@ static int cdn_dp_parse_dt(struct cdn_dp_device *dp) - return PTR_ERR(dp->pclk); - } - -- dp->spdif_clk = devm_clk_get(dev, "spdif"); -- if (IS_ERR(dp->spdif_clk)) { -+ dp->mhdp.spdif_clk = devm_clk_get(dev, "spdif"); -+ if (IS_ERR(dp->mhdp.spdif_clk)) { - DRM_DEV_ERROR(dev, "cannot get spdif_clk\n"); -- return PTR_ERR(dp->spdif_clk); -+ return PTR_ERR(dp->mhdp.spdif_clk); - } - - dp->grf_clk = devm_clk_get(dev, "grf"); -@@ -734,10 +745,10 @@ static int cdn_dp_parse_dt(struct cdn_dp_device *dp) - return PTR_ERR(dp->grf_clk); - } - -- dp->spdif_rst = devm_reset_control_get(dev, "spdif"); -- if (IS_ERR(dp->spdif_rst)) { -+ dp->mhdp.spdif_rst = devm_reset_control_get(dev, "spdif"); -+ if (IS_ERR(dp->mhdp.spdif_rst)) { - DRM_DEV_ERROR(dev, "no spdif reset control found\n"); -- return PTR_ERR(dp->spdif_rst); -+ return PTR_ERR(dp->mhdp.spdif_rst); - } - - dp->dptx_rst = devm_reset_control_get(dev, "dptx"); -@@ -784,7 +795,7 @@ static int cdn_dp_audio_hw_params(struct device *dev, void *data, - audio.format = AFMT_I2S; - break; - case HDMI_SPDIF: -- audio.format = AFMT_SPDIF; -+ audio.format = AFMT_SPDIF_INT; - break; - default: - DRM_DEV_ERROR(dev, "Invalid format %d\n", daifmt->fmt); -@@ -792,9 +803,9 @@ static int cdn_dp_audio_hw_params(struct device *dev, void *data, - goto out; - } - -- ret = cdn_dp_audio_config(dp, &audio); -+ ret = cdns_mhdp_audio_config(&dp->mhdp, &audio); - if (!ret) -- dp->audio_info = audio; -+ dp->mhdp.audio_info = audio; - - out: - mutex_unlock(&dp->lock); -@@ -810,9 +821,9 @@ static void cdn_dp_audio_shutdown(struct device *dev, void *data) - if (!dp->active) - goto out; - -- ret = cdn_dp_audio_stop(dp, &dp->audio_info); -+ ret = cdns_mhdp_audio_stop(&dp->mhdp, &dp->mhdp.audio_info); - if (!ret) -- dp->audio_info.format = AFMT_UNUSED; -+ dp->mhdp.audio_info.format = AFMT_UNUSED; - out: - mutex_unlock(&dp->lock); - } -@@ -829,7 +840,7 @@ static int cdn_dp_audio_mute_stream(struct device *dev, void *data, - goto out; - } - -- ret = cdn_dp_audio_mute(dp, enable); -+ ret = cdns_mhdp_audio_mute(&dp->mhdp, enable); - - out: - mutex_unlock(&dp->lock); -@@ -841,7 +852,8 @@ static int cdn_dp_audio_get_eld(struct device *dev, void *data, - { - struct cdn_dp_device *dp = dev_get_drvdata(dev); - -- memcpy(buf, dp->connector.eld, min(sizeof(dp->connector.eld), len)); -+ memcpy(buf, dp->mhdp.connector.base.eld, -+ min(sizeof(dp->mhdp.connector.base.eld), len)); - - return 0; - } -@@ -864,11 +876,11 @@ static int cdn_dp_audio_codec_init(struct cdn_dp_device *dp, - .max_i2s_channels = 8, - }; - -- dp->audio_pdev = platform_device_register_data( -- dev, HDMI_CODEC_DRV_NAME, PLATFORM_DEVID_AUTO, -- &codec_data, sizeof(codec_data)); -+ dp->mhdp.audio_pdev = platform_device_register_data( -+ dev, HDMI_CODEC_DRV_NAME, PLATFORM_DEVID_AUTO, -+ &codec_data, sizeof(codec_data)); - -- return PTR_ERR_OR_ZERO(dp->audio_pdev); -+ return PTR_ERR_OR_ZERO(dp->mhdp.audio_pdev); - } - - static int cdn_dp_request_firmware(struct cdn_dp_device *dp) -@@ -876,6 +888,7 @@ static int cdn_dp_request_firmware(struct cdn_dp_device *dp) - int ret; - unsigned long timeout = jiffies + msecs_to_jiffies(CDN_FW_TIMEOUT_MS); - unsigned long sleep = 1000; -+ struct device *dev = dp->mhdp.dev; - - WARN_ON(!mutex_is_locked(&dp->lock)); - -@@ -886,13 +899,13 @@ static int cdn_dp_request_firmware(struct cdn_dp_device *dp) - mutex_unlock(&dp->lock); - - while (time_before(jiffies, timeout)) { -- ret = request_firmware(&dp->fw, CDN_DP_FIRMWARE, dp->dev); -+ ret = request_firmware(&dp->fw, CDN_DP_FIRMWARE, dev); - if (ret == -ENOENT) { - msleep(sleep); - sleep *= 2; - continue; - } else if (ret) { -- DRM_DEV_ERROR(dp->dev, -+ DRM_DEV_ERROR(dev, - "failed to request firmware: %d\n", ret); - goto out; - } -@@ -902,7 +915,7 @@ static int cdn_dp_request_firmware(struct cdn_dp_device *dp) - goto out; - } - -- DRM_DEV_ERROR(dp->dev, "Timed out trying to load firmware\n"); -+ DRM_DEV_ERROR(dev, "Timed out trying to load firmware\n"); - ret = -ETIMEDOUT; - out: - mutex_lock(&dp->lock); -@@ -913,8 +926,9 @@ static void cdn_dp_pd_event_work(struct work_struct *work) - { - struct cdn_dp_device *dp = container_of(work, struct cdn_dp_device, - event_work); -- struct drm_connector *connector = &dp->connector; -+ struct drm_connector *connector = &dp->mhdp.connector.base; - enum drm_connector_status old_status; -+ struct device *dev = dp->mhdp.dev; - - int ret; - -@@ -931,44 +945,45 @@ static void cdn_dp_pd_event_work(struct work_struct *work) - - /* Not connected, notify userspace to disable the block */ - if (!cdn_dp_connected_port(dp)) { -- DRM_DEV_INFO(dp->dev, "Not connected. Disabling cdn\n"); -+ DRM_DEV_INFO(dev, "Not connected. Disabling cdn\n"); - dp->connected = false; - - /* Connected but not enabled, enable the block */ - } else if (!dp->active) { -- DRM_DEV_INFO(dp->dev, "Connected, not enabled. Enabling cdn\n"); -+ DRM_DEV_INFO(dev, "Connected, not enabled. Enabling cdn\n"); - ret = cdn_dp_enable(dp); - if (ret) { -- DRM_DEV_ERROR(dp->dev, "Enable dp failed %d\n", ret); -+ DRM_DEV_ERROR(dev, "Enable dp failed %d\n", ret); - dp->connected = false; - } - - /* Enabled and connected to a dongle without a sink, notify userspace */ - } else if (!cdn_dp_check_sink_connection(dp)) { -- DRM_DEV_INFO(dp->dev, "Connected without sink. Assert hpd\n"); -+ DRM_DEV_INFO(dev, "Connected without sink. Assert hpd\n"); - dp->connected = false; - - /* Enabled and connected with a sink, re-train if requested */ - } else if (!cdn_dp_check_link_status(dp)) { -- unsigned int rate = dp->max_rate; -- unsigned int lanes = dp->max_lanes; -- struct drm_display_mode *mode = &dp->mode; -+ unsigned int rate = dp->mhdp.dp.rate; -+ unsigned int lanes = dp->mhdp.dp.num_lanes; -+ struct drm_display_mode *mode = &dp->mhdp.mode; - -- DRM_DEV_INFO(dp->dev, "Connected with sink. Re-train link\n"); -- ret = cdn_dp_train_link(dp); -+ DRM_DEV_INFO(dev, "Connected with sink. Re-train link\n"); -+ ret = cdns_mhdp_train_link(&dp->mhdp); - if (ret) { - dp->connected = false; -- DRM_DEV_ERROR(dp->dev, "Train link failed %d\n", ret); -+ DRM_DEV_ERROR(dev, "Train link failed %d\n", ret); - goto out; - } - - /* If training result is changed, update the video config */ - if (mode->clock && -- (rate != dp->max_rate || lanes != dp->max_lanes)) { -- ret = cdn_dp_config_video(dp); -+ (rate != dp->mhdp.dp.rate || -+ lanes != dp->mhdp.dp.num_lanes)) { -+ ret = cdns_mhdp_config_video(&dp->mhdp); - if (ret) { - dp->connected = false; -- DRM_DEV_ERROR(dp->dev, -+ DRM_DEV_ERROR(dev, - "Failed to config video %d\n", - ret); - } -@@ -1037,7 +1052,7 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data) - - drm_encoder_helper_add(encoder, &cdn_dp_encoder_helper_funcs); - -- connector = &dp->connector; -+ connector = &dp->mhdp.connector.base; - connector->polled = DRM_CONNECTOR_POLL_HPD; - connector->dpms = DRM_MODE_DPMS_OFF; - -@@ -1061,7 +1076,7 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data) - port = dp->port[i]; - - port->event_nb.notifier_call = cdn_dp_pd_event; -- ret = devm_extcon_register_notifier(dp->dev, port->extcon, -+ ret = devm_extcon_register_notifier(dp->mhdp.dev, port->extcon, - EXTCON_DISP_DP, - &port->event_nb); - if (ret) { -@@ -1088,7 +1103,7 @@ static void cdn_dp_unbind(struct device *dev, struct device *master, void *data) - { - struct cdn_dp_device *dp = dev_get_drvdata(dev); - struct drm_encoder *encoder = &dp->encoder.encoder; -- struct drm_connector *connector = &dp->connector; -+ struct drm_connector *connector = &dp->mhdp.connector.base; - - cancel_work_sync(&dp->event_work); - cdn_dp_encoder_disable(encoder); -@@ -1148,7 +1163,7 @@ static int cdn_dp_probe(struct platform_device *pdev) - dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL); - if (!dp) - return -ENOMEM; -- dp->dev = dev; -+ dp->mhdp.dev = dev; - - match = of_match_node(cdn_dp_dt_ids, pdev->dev.of_node); - dp_data = (struct cdn_dp_data *)match->data; -@@ -1192,8 +1207,8 @@ static int cdn_dp_remove(struct platform_device *pdev) - { - struct cdn_dp_device *dp = platform_get_drvdata(pdev); - -- platform_device_unregister(dp->audio_pdev); -- cdn_dp_suspend(dp->dev); -+ platform_device_unregister(dp->mhdp.audio_pdev); -+ cdn_dp_suspend(dp->mhdp.dev); - component_del(&pdev->dev, &cdn_dp_component_ops); - } - -@@ -1203,7 +1218,7 @@ static void cdn_dp_shutdown(struct platform_device *pdev) - { - struct cdn_dp_device *dp = platform_get_drvdata(pdev); - -- cdn_dp_suspend(dp->dev); -+ cdn_dp_suspend(dp->mhdp.dev); - } - - static const struct dev_pm_ops cdn_dp_pm_ops = { -diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h -index 81ac9b658a70..8b1b15b92503 100644 ---- a/drivers/gpu/drm/rockchip/cdn-dp-core.h -+++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h -@@ -7,6 +7,7 @@ - #ifndef _CDN_DP_CORE_H - #define _CDN_DP_CORE_H - -+#include - #include - #include - #include -@@ -15,35 +16,6 @@ - - #define MAX_PHY 2 - --enum audio_format { -- AFMT_I2S = 0, -- AFMT_SPDIF = 1, -- AFMT_UNUSED, --}; -- --struct audio_info { -- enum audio_format format; -- int sample_rate; -- int channels; -- int sample_width; --}; -- --enum vic_pxl_encoding_format { -- PXL_RGB = 0x1, -- YCBCR_4_4_4 = 0x2, -- YCBCR_4_2_2 = 0x4, -- YCBCR_4_2_0 = 0x8, -- Y_ONLY = 0x10, --}; -- --struct video_info { -- bool h_sync_polarity; -- bool v_sync_polarity; -- bool interlaced; -- int color_depth; -- enum vic_pxl_encoding_format color_fmt; --}; -- - struct cdn_firmware_header { - u32 size_bytes; /* size of the entire header+image(s) in bytes */ - u32 header_size; /* size of just the header in bytes */ -@@ -62,12 +34,9 @@ struct cdn_dp_port { - }; - - struct cdn_dp_device { -- struct device *dev; -+ struct cdns_mhdp_device mhdp; - struct drm_device *drm_dev; -- struct drm_connector connector; - struct rockchip_encoder encoder; -- struct drm_display_mode mode; -- struct platform_device *audio_pdev; - struct work_struct event_work; - const struct drm_edid *drm_edid; - -@@ -77,29 +46,20 @@ struct cdn_dp_device { - bool suspended; - - const struct firmware *fw; /* cdn dp firmware */ -- unsigned int fw_version; /* cdn fw version */ - bool fw_loaded; - -- void __iomem *regs; - struct regmap *grf; - struct clk *core_clk; - struct clk *pclk; -- struct clk *spdif_clk; - struct clk *grf_clk; -- struct reset_control *spdif_rst; - struct reset_control *dptx_rst; - struct reset_control *apb_rst; - struct reset_control *core_rst; -- struct audio_info audio_info; -- struct video_info video_info; - struct cdn_dp_port *port[MAX_PHY]; - u8 ports; -- u8 max_lanes; -- unsigned int max_rate; - u8 lanes; - int active_port; - -- u8 dpcd[DP_RECEIVER_CAP_SIZE]; - bool sink_has_audio; - - hdmi_codec_plugged_cb plugged_cb; -diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.c b/drivers/gpu/drm/rockchip/cdn-dp-reg.c -deleted file mode 100644 -index 9d2163ef4d6e..000000000000 ---- a/drivers/gpu/drm/rockchip/cdn-dp-reg.c -+++ /dev/null -@@ -1,960 +0,0 @@ --// SPDX-License-Identifier: GPL-2.0-only --/* -- * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd -- * Author: Chris Zhong -- */ -- --#include --#include --#include --#include --#include --#include -- --#include "cdn-dp-core.h" --#include "cdn-dp-reg.h" -- --#define CDN_DP_SPDIF_CLK 200000000 --#define FW_ALIVE_TIMEOUT_US 1000000 --#define MAILBOX_RETRY_US 1000 --#define MAILBOX_TIMEOUT_US 5000000 --#define LINK_TRAINING_RETRY_MS 20 --#define LINK_TRAINING_TIMEOUT_MS 500 -- --void cdn_dp_set_fw_clk(struct cdn_dp_device *dp, unsigned long clk) --{ -- writel(clk / 1000000, dp->regs + SW_CLK_H); --} -- --void cdn_dp_clock_reset(struct cdn_dp_device *dp) --{ -- u32 val; -- -- val = DPTX_FRMR_DATA_CLK_RSTN_EN | -- DPTX_FRMR_DATA_CLK_EN | -- DPTX_PHY_DATA_RSTN_EN | -- DPTX_PHY_DATA_CLK_EN | -- DPTX_PHY_CHAR_RSTN_EN | -- DPTX_PHY_CHAR_CLK_EN | -- SOURCE_AUX_SYS_CLK_RSTN_EN | -- SOURCE_AUX_SYS_CLK_EN | -- DPTX_SYS_CLK_RSTN_EN | -- DPTX_SYS_CLK_EN | -- CFG_DPTX_VIF_CLK_RSTN_EN | -- CFG_DPTX_VIF_CLK_EN; -- writel(val, dp->regs + SOURCE_DPTX_CAR); -- -- val = SOURCE_PHY_RSTN_EN | SOURCE_PHY_CLK_EN; -- writel(val, dp->regs + SOURCE_PHY_CAR); -- -- val = SOURCE_PKT_SYS_RSTN_EN | -- SOURCE_PKT_SYS_CLK_EN | -- SOURCE_PKT_DATA_RSTN_EN | -- SOURCE_PKT_DATA_CLK_EN; -- writel(val, dp->regs + SOURCE_PKT_CAR); -- -- val = SPDIF_CDR_CLK_RSTN_EN | -- SPDIF_CDR_CLK_EN | -- SOURCE_AIF_SYS_RSTN_EN | -- SOURCE_AIF_SYS_CLK_EN | -- SOURCE_AIF_CLK_RSTN_EN | -- SOURCE_AIF_CLK_EN; -- writel(val, dp->regs + SOURCE_AIF_CAR); -- -- val = SOURCE_CIPHER_SYSTEM_CLK_RSTN_EN | -- SOURCE_CIPHER_SYS_CLK_EN | -- SOURCE_CIPHER_CHAR_CLK_RSTN_EN | -- SOURCE_CIPHER_CHAR_CLK_EN; -- writel(val, dp->regs + SOURCE_CIPHER_CAR); -- -- val = SOURCE_CRYPTO_SYS_CLK_RSTN_EN | -- SOURCE_CRYPTO_SYS_CLK_EN; -- writel(val, dp->regs + SOURCE_CRYPTO_CAR); -- -- /* enable Mailbox and PIF interrupt */ -- writel(0, dp->regs + APB_INT_MASK); --} -- --static int cdn_dp_mailbox_read(struct cdn_dp_device *dp) --{ -- int val, ret; -- -- ret = readx_poll_timeout(readl, dp->regs + MAILBOX_EMPTY_ADDR, -- val, !val, MAILBOX_RETRY_US, -- MAILBOX_TIMEOUT_US); -- if (ret < 0) -- return ret; -- -- return readl(dp->regs + MAILBOX0_RD_DATA) & 0xff; --} -- --static int cdp_dp_mailbox_write(struct cdn_dp_device *dp, u8 val) --{ -- int ret, full; -- -- ret = readx_poll_timeout(readl, dp->regs + MAILBOX_FULL_ADDR, -- full, !full, MAILBOX_RETRY_US, -- MAILBOX_TIMEOUT_US); -- if (ret < 0) -- return ret; -- -- writel(val, dp->regs + MAILBOX0_WR_DATA); -- -- return 0; --} -- --static int cdn_dp_mailbox_validate_receive(struct cdn_dp_device *dp, -- u8 module_id, u8 opcode, -- u16 req_size) --{ -- u32 mbox_size, i; -- u8 header[4]; -- int ret; -- -- /* read the header of the message */ -- for (i = 0; i < 4; i++) { -- ret = cdn_dp_mailbox_read(dp); -- if (ret < 0) -- return ret; -- -- header[i] = ret; -- } -- -- mbox_size = (header[2] << 8) | header[3]; -- -- if (opcode != header[0] || module_id != header[1] || -- req_size != mbox_size) { -- /* -- * If the message in mailbox is not what we want, we need to -- * clear the mailbox by reading its contents. -- */ -- for (i = 0; i < mbox_size; i++) -- if (cdn_dp_mailbox_read(dp) < 0) -- break; -- -- return -EINVAL; -- } -- -- return 0; --} -- --static int cdn_dp_mailbox_read_receive(struct cdn_dp_device *dp, -- u8 *buff, u16 buff_size) --{ -- u32 i; -- int ret; -- -- for (i = 0; i < buff_size; i++) { -- ret = cdn_dp_mailbox_read(dp); -- if (ret < 0) -- return ret; -- -- buff[i] = ret; -- } -- -- return 0; --} -- --static int cdn_dp_mailbox_send(struct cdn_dp_device *dp, u8 module_id, -- u8 opcode, u16 size, u8 *message) --{ -- u8 header[4]; -- int ret, i; -- -- header[0] = opcode; -- header[1] = module_id; -- header[2] = (size >> 8) & 0xff; -- header[3] = size & 0xff; -- -- for (i = 0; i < 4; i++) { -- ret = cdp_dp_mailbox_write(dp, header[i]); -- if (ret) -- return ret; -- } -- -- for (i = 0; i < size; i++) { -- ret = cdp_dp_mailbox_write(dp, message[i]); -- if (ret) -- return ret; -- } -- -- return 0; --} -- --static int cdn_dp_reg_write(struct cdn_dp_device *dp, u16 addr, u32 val) --{ -- u8 msg[6]; -- -- msg[0] = (addr >> 8) & 0xff; -- msg[1] = addr & 0xff; -- msg[2] = (val >> 24) & 0xff; -- msg[3] = (val >> 16) & 0xff; -- msg[4] = (val >> 8) & 0xff; -- msg[5] = val & 0xff; -- return cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_WRITE_REGISTER, -- sizeof(msg), msg); --} -- --static int cdn_dp_reg_write_bit(struct cdn_dp_device *dp, u16 addr, -- u8 start_bit, u8 bits_no, u32 val) --{ -- u8 field[8]; -- -- field[0] = (addr >> 8) & 0xff; -- field[1] = addr & 0xff; -- field[2] = start_bit; -- field[3] = bits_no; -- field[4] = (val >> 24) & 0xff; -- field[5] = (val >> 16) & 0xff; -- field[6] = (val >> 8) & 0xff; -- field[7] = val & 0xff; -- -- return cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_WRITE_FIELD, -- sizeof(field), field); --} -- --int cdn_dp_dpcd_read(struct cdn_dp_device *dp, u32 addr, u8 *data, u16 len) --{ -- u8 msg[5], reg[5]; -- int ret; -- -- msg[0] = (len >> 8) & 0xff; -- msg[1] = len & 0xff; -- msg[2] = (addr >> 16) & 0xff; -- msg[3] = (addr >> 8) & 0xff; -- msg[4] = addr & 0xff; -- ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_READ_DPCD, -- sizeof(msg), msg); -- if (ret) -- goto err_dpcd_read; -- -- ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX, -- DPTX_READ_DPCD, -- sizeof(reg) + len); -- if (ret) -- goto err_dpcd_read; -- -- ret = cdn_dp_mailbox_read_receive(dp, reg, sizeof(reg)); -- if (ret) -- goto err_dpcd_read; -- -- ret = cdn_dp_mailbox_read_receive(dp, data, len); -- --err_dpcd_read: -- return ret; --} -- --int cdn_dp_dpcd_write(struct cdn_dp_device *dp, u32 addr, u8 value) --{ -- u8 msg[6], reg[5]; -- int ret; -- -- msg[0] = 0; -- msg[1] = 1; -- msg[2] = (addr >> 16) & 0xff; -- msg[3] = (addr >> 8) & 0xff; -- msg[4] = addr & 0xff; -- msg[5] = value; -- ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_WRITE_DPCD, -- sizeof(msg), msg); -- if (ret) -- goto err_dpcd_write; -- -- ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX, -- DPTX_WRITE_DPCD, sizeof(reg)); -- if (ret) -- goto err_dpcd_write; -- -- ret = cdn_dp_mailbox_read_receive(dp, reg, sizeof(reg)); -- if (ret) -- goto err_dpcd_write; -- -- if (addr != (reg[2] << 16 | reg[3] << 8 | reg[4])) -- ret = -EINVAL; -- --err_dpcd_write: -- if (ret) -- DRM_DEV_ERROR(dp->dev, "dpcd write failed: %d\n", ret); -- return ret; --} -- --int cdn_dp_load_firmware(struct cdn_dp_device *dp, const u32 *i_mem, -- u32 i_size, const u32 *d_mem, u32 d_size) --{ -- u32 reg; -- int i, ret; -- -- /* reset ucpu before load firmware*/ -- writel(APB_IRAM_PATH | APB_DRAM_PATH | APB_XT_RESET, -- dp->regs + APB_CTRL); -- -- for (i = 0; i < i_size; i += 4) -- writel(*i_mem++, dp->regs + ADDR_IMEM + i); -- -- for (i = 0; i < d_size; i += 4) -- writel(*d_mem++, dp->regs + ADDR_DMEM + i); -- -- /* un-reset ucpu */ -- writel(0, dp->regs + APB_CTRL); -- -- /* check the keep alive register to make sure fw working */ -- ret = readx_poll_timeout(readl, dp->regs + KEEP_ALIVE, -- reg, reg, 2000, FW_ALIVE_TIMEOUT_US); -- if (ret < 0) { -- DRM_DEV_ERROR(dp->dev, "failed to loaded the FW reg = %x\n", -- reg); -- return -EINVAL; -- } -- -- reg = readl(dp->regs + VER_L) & 0xff; -- dp->fw_version = reg; -- reg = readl(dp->regs + VER_H) & 0xff; -- dp->fw_version |= reg << 8; -- reg = readl(dp->regs + VER_LIB_L_ADDR) & 0xff; -- dp->fw_version |= reg << 16; -- reg = readl(dp->regs + VER_LIB_H_ADDR) & 0xff; -- dp->fw_version |= reg << 24; -- -- DRM_DEV_DEBUG(dp->dev, "firmware version: %x\n", dp->fw_version); -- -- return 0; --} -- --int cdn_dp_set_firmware_active(struct cdn_dp_device *dp, bool enable) --{ -- u8 msg[5]; -- int ret, i; -- -- msg[0] = GENERAL_MAIN_CONTROL; -- msg[1] = MB_MODULE_ID_GENERAL; -- msg[2] = 0; -- msg[3] = 1; -- msg[4] = enable ? FW_ACTIVE : FW_STANDBY; -- -- for (i = 0; i < sizeof(msg); i++) { -- ret = cdp_dp_mailbox_write(dp, msg[i]); -- if (ret) -- goto err_set_firmware_active; -- } -- -- /* read the firmware state */ -- for (i = 0; i < sizeof(msg); i++) { -- ret = cdn_dp_mailbox_read(dp); -- if (ret < 0) -- goto err_set_firmware_active; -- -- msg[i] = ret; -- } -- -- ret = 0; -- --err_set_firmware_active: -- if (ret < 0) -- DRM_DEV_ERROR(dp->dev, "set firmware active failed\n"); -- return ret; --} -- --int cdn_dp_set_host_cap(struct cdn_dp_device *dp, u8 lanes, bool flip) --{ -- u8 msg[8]; -- int ret; -- -- msg[0] = CDN_DP_MAX_LINK_RATE; -- msg[1] = lanes | SCRAMBLER_EN; -- msg[2] = VOLTAGE_LEVEL_2; -- msg[3] = PRE_EMPHASIS_LEVEL_3; -- msg[4] = PTS1 | PTS2 | PTS3 | PTS4; -- msg[5] = FAST_LT_NOT_SUPPORT; -- msg[6] = flip ? LANE_MAPPING_FLIPPED : LANE_MAPPING_NORMAL; -- msg[7] = ENHANCED; -- -- ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, -- DPTX_SET_HOST_CAPABILITIES, -- sizeof(msg), msg); -- if (ret) -- goto err_set_host_cap; -- -- ret = cdn_dp_reg_write(dp, DP_AUX_SWAP_INVERSION_CONTROL, -- AUX_HOST_INVERT); -- --err_set_host_cap: -- if (ret) -- DRM_DEV_ERROR(dp->dev, "set host cap failed: %d\n", ret); -- return ret; --} -- --int cdn_dp_event_config(struct cdn_dp_device *dp) --{ -- u8 msg[5]; -- int ret; -- -- memset(msg, 0, sizeof(msg)); -- -- msg[0] = DPTX_EVENT_ENABLE_HPD | DPTX_EVENT_ENABLE_TRAINING; -- -- ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_ENABLE_EVENT, -- sizeof(msg), msg); -- if (ret) -- DRM_DEV_ERROR(dp->dev, "set event config failed: %d\n", ret); -- -- return ret; --} -- --u32 cdn_dp_get_event(struct cdn_dp_device *dp) --{ -- return readl(dp->regs + SW_EVENTS0); --} -- --int cdn_dp_get_hpd_status(struct cdn_dp_device *dp) --{ -- u8 status; -- int ret; -- -- ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_HPD_STATE, -- 0, NULL); -- if (ret) -- goto err_get_hpd; -- -- ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX, -- DPTX_HPD_STATE, sizeof(status)); -- if (ret) -- goto err_get_hpd; -- -- ret = cdn_dp_mailbox_read_receive(dp, &status, sizeof(status)); -- if (ret) -- goto err_get_hpd; -- -- return status; -- --err_get_hpd: -- DRM_DEV_ERROR(dp->dev, "get hpd status failed: %d\n", ret); -- return ret; --} -- --int cdn_dp_get_edid_block(void *data, u8 *edid, -- unsigned int block, size_t length) --{ -- struct cdn_dp_device *dp = data; -- u8 msg[2], reg[2], i; -- int ret; -- -- for (i = 0; i < 4; i++) { -- msg[0] = block / 2; -- msg[1] = block % 2; -- -- ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_GET_EDID, -- sizeof(msg), msg); -- if (ret) -- continue; -- -- ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX, -- DPTX_GET_EDID, -- sizeof(reg) + length); -- if (ret) -- continue; -- -- ret = cdn_dp_mailbox_read_receive(dp, reg, sizeof(reg)); -- if (ret) -- continue; -- -- ret = cdn_dp_mailbox_read_receive(dp, edid, length); -- if (ret) -- continue; -- -- if (reg[0] == length && reg[1] == block / 2) -- break; -- } -- -- if (ret) -- DRM_DEV_ERROR(dp->dev, "get block[%d] edid failed: %d\n", block, -- ret); -- -- return ret; --} -- --static int cdn_dp_training_start(struct cdn_dp_device *dp) --{ -- unsigned long timeout; -- u8 msg, event[2]; -- int ret; -- -- msg = LINK_TRAINING_RUN; -- -- /* start training */ -- ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_TRAINING_CONTROL, -- sizeof(msg), &msg); -- if (ret) -- goto err_training_start; -- -- timeout = jiffies + msecs_to_jiffies(LINK_TRAINING_TIMEOUT_MS); -- while (time_before(jiffies, timeout)) { -- msleep(LINK_TRAINING_RETRY_MS); -- ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, -- DPTX_READ_EVENT, 0, NULL); -- if (ret) -- goto err_training_start; -- -- ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX, -- DPTX_READ_EVENT, -- sizeof(event)); -- if (ret) -- goto err_training_start; -- -- ret = cdn_dp_mailbox_read_receive(dp, event, sizeof(event)); -- if (ret) -- goto err_training_start; -- -- if (event[1] & EQ_PHASE_FINISHED) -- return 0; -- } -- -- ret = -ETIMEDOUT; -- --err_training_start: -- DRM_DEV_ERROR(dp->dev, "training failed: %d\n", ret); -- return ret; --} -- --static int cdn_dp_get_training_status(struct cdn_dp_device *dp) --{ -- u8 status[10]; -- int ret; -- -- ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_READ_LINK_STAT, -- 0, NULL); -- if (ret) -- goto err_get_training_status; -- -- ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX, -- DPTX_READ_LINK_STAT, -- sizeof(status)); -- if (ret) -- goto err_get_training_status; -- -- ret = cdn_dp_mailbox_read_receive(dp, status, sizeof(status)); -- if (ret) -- goto err_get_training_status; -- -- dp->max_rate = drm_dp_bw_code_to_link_rate(status[0]); -- dp->max_lanes = status[1]; -- --err_get_training_status: -- if (ret) -- DRM_DEV_ERROR(dp->dev, "get training status failed: %d\n", ret); -- return ret; --} -- --int cdn_dp_train_link(struct cdn_dp_device *dp) --{ -- int ret; -- -- ret = cdn_dp_training_start(dp); -- if (ret) { -- DRM_DEV_ERROR(dp->dev, "Failed to start training %d\n", ret); -- return ret; -- } -- -- ret = cdn_dp_get_training_status(dp); -- if (ret) { -- DRM_DEV_ERROR(dp->dev, "Failed to get training stat %d\n", ret); -- return ret; -- } -- -- DRM_DEV_DEBUG_KMS(dp->dev, "rate:0x%x, lanes:%d\n", dp->max_rate, -- dp->max_lanes); -- return ret; --} -- --int cdn_dp_set_video_status(struct cdn_dp_device *dp, int active) --{ -- u8 msg; -- int ret; -- -- msg = !!active; -- -- ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_SET_VIDEO, -- sizeof(msg), &msg); -- if (ret) -- DRM_DEV_ERROR(dp->dev, "set video status failed: %d\n", ret); -- -- return ret; --} -- --static int cdn_dp_get_msa_misc(struct video_info *video, -- struct drm_display_mode *mode) --{ -- u32 msa_misc; -- u8 val[2] = {0}; -- -- switch (video->color_fmt) { -- case PXL_RGB: -- case Y_ONLY: -- val[0] = 0; -- break; -- /* set YUV default color space conversion to BT601 */ -- case YCBCR_4_4_4: -- val[0] = 6 + BT_601 * 8; -- break; -- case YCBCR_4_2_2: -- val[0] = 5 + BT_601 * 8; -- break; -- case YCBCR_4_2_0: -- val[0] = 5; -- break; -- } -- -- switch (video->color_depth) { -- case 6: -- val[1] = 0; -- break; -- case 8: -- val[1] = 1; -- break; -- case 10: -- val[1] = 2; -- break; -- case 12: -- val[1] = 3; -- break; -- case 16: -- val[1] = 4; -- break; -- } -- -- msa_misc = 2 * val[0] + 32 * val[1] + -- ((video->color_fmt == Y_ONLY) ? (1 << 14) : 0); -- -- return msa_misc; --} -- --int cdn_dp_config_video(struct cdn_dp_device *dp) --{ -- struct video_info *video = &dp->video_info; -- struct drm_display_mode *mode = &dp->mode; -- u64 symbol; -- u32 val, link_rate, rem; -- u8 bit_per_pix, tu_size_reg = TU_SIZE; -- int ret; -- -- bit_per_pix = (video->color_fmt == YCBCR_4_2_2) ? -- (video->color_depth * 2) : (video->color_depth * 3); -- -- link_rate = dp->max_rate / 1000; -- -- ret = cdn_dp_reg_write(dp, BND_HSYNC2VSYNC, VIF_BYPASS_INTERLACE); -- if (ret) -- goto err_config_video; -- -- ret = cdn_dp_reg_write(dp, HSYNC2VSYNC_POL_CTRL, 0); -- if (ret) -- goto err_config_video; -- -- /* -- * get a best tu_size and valid symbol: -- * 1. chose Lclk freq(162Mhz, 270Mhz, 540Mhz), set TU to 32 -- * 2. calculate VS(valid symbol) = TU * Pclk * Bpp / (Lclk * Lanes) -- * 3. if VS > *.85 or VS < *.1 or VS < 2 or TU < VS + 4, then set -- * TU += 2 and repeat 2nd step. -- */ -- do { -- tu_size_reg += 2; -- symbol = (u64)tu_size_reg * mode->clock * bit_per_pix; -- do_div(symbol, dp->max_lanes * link_rate * 8); -- rem = do_div(symbol, 1000); -- if (tu_size_reg > 64) { -- ret = -EINVAL; -- DRM_DEV_ERROR(dp->dev, -- "tu error, clk:%d, lanes:%d, rate:%d\n", -- mode->clock, dp->max_lanes, link_rate); -- goto err_config_video; -- } -- } while ((symbol <= 1) || (tu_size_reg - symbol < 4) || -- (rem > 850) || (rem < 100)); -- -- val = symbol + (tu_size_reg << 8); -- val |= TU_CNT_RST_EN; -- ret = cdn_dp_reg_write(dp, DP_FRAMER_TU, val); -- if (ret) -- goto err_config_video; -- -- /* set the FIFO Buffer size */ -- val = div_u64(mode->clock * (symbol + 1), 1000) + link_rate; -- val /= (dp->max_lanes * link_rate); -- val = div_u64(8 * (symbol + 1), bit_per_pix) - val; -- val += 2; -- ret = cdn_dp_reg_write(dp, DP_VC_TABLE(15), val); -- -- switch (video->color_depth) { -- case 6: -- val = BCS_6; -- break; -- case 8: -- val = BCS_8; -- break; -- case 10: -- val = BCS_10; -- break; -- case 12: -- val = BCS_12; -- break; -- case 16: -- val = BCS_16; -- break; -- } -- -- val += video->color_fmt << 8; -- ret = cdn_dp_reg_write(dp, DP_FRAMER_PXL_REPR, val); -- if (ret) -- goto err_config_video; -- -- val = video->h_sync_polarity ? DP_FRAMER_SP_HSP : 0; -- val |= video->v_sync_polarity ? DP_FRAMER_SP_VSP : 0; -- ret = cdn_dp_reg_write(dp, DP_FRAMER_SP, val); -- if (ret) -- goto err_config_video; -- -- val = (mode->hsync_start - mode->hdisplay) << 16; -- val |= mode->htotal - mode->hsync_end; -- ret = cdn_dp_reg_write(dp, DP_FRONT_BACK_PORCH, val); -- if (ret) -- goto err_config_video; -- -- val = mode->hdisplay * bit_per_pix / 8; -- ret = cdn_dp_reg_write(dp, DP_BYTE_COUNT, val); -- if (ret) -- goto err_config_video; -- -- val = mode->htotal | ((mode->htotal - mode->hsync_start) << 16); -- ret = cdn_dp_reg_write(dp, MSA_HORIZONTAL_0, val); -- if (ret) -- goto err_config_video; -- -- val = mode->hsync_end - mode->hsync_start; -- val |= (mode->hdisplay << 16) | (video->h_sync_polarity << 15); -- ret = cdn_dp_reg_write(dp, MSA_HORIZONTAL_1, val); -- if (ret) -- goto err_config_video; -- -- val = mode->vtotal; -- val |= (mode->vtotal - mode->vsync_start) << 16; -- ret = cdn_dp_reg_write(dp, MSA_VERTICAL_0, val); -- if (ret) -- goto err_config_video; -- -- val = mode->vsync_end - mode->vsync_start; -- val |= (mode->vdisplay << 16) | (video->v_sync_polarity << 15); -- ret = cdn_dp_reg_write(dp, MSA_VERTICAL_1, val); -- if (ret) -- goto err_config_video; -- -- val = cdn_dp_get_msa_misc(video, mode); -- ret = cdn_dp_reg_write(dp, MSA_MISC, val); -- if (ret) -- goto err_config_video; -- -- ret = cdn_dp_reg_write(dp, STREAM_CONFIG, 1); -- if (ret) -- goto err_config_video; -- -- val = mode->hsync_end - mode->hsync_start; -- val |= mode->hdisplay << 16; -- ret = cdn_dp_reg_write(dp, DP_HORIZONTAL, val); -- if (ret) -- goto err_config_video; -- -- val = mode->vdisplay; -- val |= (mode->vtotal - mode->vsync_start) << 16; -- ret = cdn_dp_reg_write(dp, DP_VERTICAL_0, val); -- if (ret) -- goto err_config_video; -- -- val = mode->vtotal; -- ret = cdn_dp_reg_write(dp, DP_VERTICAL_1, val); -- if (ret) -- goto err_config_video; -- -- ret = cdn_dp_reg_write_bit(dp, DP_VB_ID, 2, 1, 0); -- --err_config_video: -- if (ret) -- DRM_DEV_ERROR(dp->dev, "config video failed: %d\n", ret); -- return ret; --} -- --int cdn_dp_audio_stop(struct cdn_dp_device *dp, struct audio_info *audio) --{ -- int ret; -- -- ret = cdn_dp_reg_write(dp, AUDIO_PACK_CONTROL, 0); -- if (ret) { -- DRM_DEV_ERROR(dp->dev, "audio stop failed: %d\n", ret); -- return ret; -- } -- -- writel(0, dp->regs + SPDIF_CTRL_ADDR); -- -- /* clearn the audio config and reset */ -- writel(0, dp->regs + AUDIO_SRC_CNTL); -- writel(0, dp->regs + AUDIO_SRC_CNFG); -- writel(AUDIO_SW_RST, dp->regs + AUDIO_SRC_CNTL); -- writel(0, dp->regs + AUDIO_SRC_CNTL); -- -- /* reset smpl2pckt component */ -- writel(0, dp->regs + SMPL2PKT_CNTL); -- writel(AUDIO_SW_RST, dp->regs + SMPL2PKT_CNTL); -- writel(0, dp->regs + SMPL2PKT_CNTL); -- -- /* reset FIFO */ -- writel(AUDIO_SW_RST, dp->regs + FIFO_CNTL); -- writel(0, dp->regs + FIFO_CNTL); -- -- if (audio->format == AFMT_SPDIF) -- clk_disable_unprepare(dp->spdif_clk); -- -- return 0; --} -- --int cdn_dp_audio_mute(struct cdn_dp_device *dp, bool enable) --{ -- int ret; -- -- ret = cdn_dp_reg_write_bit(dp, DP_VB_ID, 4, 1, enable); -- if (ret) -- DRM_DEV_ERROR(dp->dev, "audio mute failed: %d\n", ret); -- -- return ret; --} -- --static void cdn_dp_audio_config_i2s(struct cdn_dp_device *dp, -- struct audio_info *audio) --{ -- int sub_pckt_num = 1, i2s_port_en_val = 0xf, i; -- u32 val; -- -- if (audio->channels == 2) { -- if (dp->max_lanes == 1) -- sub_pckt_num = 2; -- else -- sub_pckt_num = 4; -- -- i2s_port_en_val = 1; -- } else if (audio->channels == 4) { -- i2s_port_en_val = 3; -- } -- -- writel(0x0, dp->regs + SPDIF_CTRL_ADDR); -- -- writel(SYNC_WR_TO_CH_ZERO, dp->regs + FIFO_CNTL); -- -- val = MAX_NUM_CH(audio->channels); -- val |= NUM_OF_I2S_PORTS(audio->channels); -- val |= AUDIO_TYPE_LPCM; -- val |= CFG_SUB_PCKT_NUM(sub_pckt_num); -- writel(val, dp->regs + SMPL2PKT_CNFG); -- -- if (audio->sample_width == 16) -- val = 0; -- else if (audio->sample_width == 24) -- val = 1 << 9; -- else -- val = 2 << 9; -- -- val |= AUDIO_CH_NUM(audio->channels); -- val |= I2S_DEC_PORT_EN(i2s_port_en_val); -- val |= TRANS_SMPL_WIDTH_32; -- writel(val, dp->regs + AUDIO_SRC_CNFG); -- -- for (i = 0; i < (audio->channels + 1) / 2; i++) { -- if (audio->sample_width == 16) -- val = (0x02 << 8) | (0x02 << 20); -- else if (audio->sample_width == 24) -- val = (0x0b << 8) | (0x0b << 20); -- -- val |= ((2 * i) << 4) | ((2 * i + 1) << 16); -- writel(val, dp->regs + STTS_BIT_CH(i)); -- } -- -- switch (audio->sample_rate) { -- case 32000: -- val = SAMPLING_FREQ(3) | -- ORIGINAL_SAMP_FREQ(0xc); -- break; -- case 44100: -- val = SAMPLING_FREQ(0) | -- ORIGINAL_SAMP_FREQ(0xf); -- break; -- case 48000: -- val = SAMPLING_FREQ(2) | -- ORIGINAL_SAMP_FREQ(0xd); -- break; -- case 88200: -- val = SAMPLING_FREQ(8) | -- ORIGINAL_SAMP_FREQ(0x7); -- break; -- case 96000: -- val = SAMPLING_FREQ(0xa) | -- ORIGINAL_SAMP_FREQ(5); -- break; -- case 176400: -- val = SAMPLING_FREQ(0xc) | -- ORIGINAL_SAMP_FREQ(3); -- break; -- case 192000: -- val = SAMPLING_FREQ(0xe) | -- ORIGINAL_SAMP_FREQ(1); -- break; -- } -- val |= 4; -- writel(val, dp->regs + COM_CH_STTS_BITS); -- -- writel(SMPL2PKT_EN, dp->regs + SMPL2PKT_CNTL); -- writel(I2S_DEC_START, dp->regs + AUDIO_SRC_CNTL); --} -- --static void cdn_dp_audio_config_spdif(struct cdn_dp_device *dp) --{ -- u32 val; -- -- writel(SYNC_WR_TO_CH_ZERO, dp->regs + FIFO_CNTL); -- -- val = MAX_NUM_CH(2) | AUDIO_TYPE_LPCM | CFG_SUB_PCKT_NUM(4); -- writel(val, dp->regs + SMPL2PKT_CNFG); -- writel(SMPL2PKT_EN, dp->regs + SMPL2PKT_CNTL); -- -- val = SPDIF_ENABLE | SPDIF_AVG_SEL | SPDIF_JITTER_BYPASS; -- writel(val, dp->regs + SPDIF_CTRL_ADDR); -- -- clk_prepare_enable(dp->spdif_clk); -- clk_set_rate(dp->spdif_clk, CDN_DP_SPDIF_CLK); --} -- --int cdn_dp_audio_config(struct cdn_dp_device *dp, struct audio_info *audio) --{ -- int ret; -- -- /* reset the spdif clk before config */ -- if (audio->format == AFMT_SPDIF) { -- reset_control_assert(dp->spdif_rst); -- reset_control_deassert(dp->spdif_rst); -- } -- -- ret = cdn_dp_reg_write(dp, CM_LANE_CTRL, LANE_REF_CYC); -- if (ret) -- goto err_audio_config; -- -- ret = cdn_dp_reg_write(dp, CM_CTRL, 0); -- if (ret) -- goto err_audio_config; -- -- if (audio->format == AFMT_I2S) -- cdn_dp_audio_config_i2s(dp, audio); -- else if (audio->format == AFMT_SPDIF) -- cdn_dp_audio_config_spdif(dp); -- -- ret = cdn_dp_reg_write(dp, AUDIO_PACK_CONTROL, AUDIO_PACK_EN); -- --err_audio_config: -- if (ret) -- DRM_DEV_ERROR(dp->dev, "audio config failed: %d\n", ret); -- return ret; --} -diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.h b/include/drm/bridge/cdns-mhdp.h -similarity index 53% -rename from drivers/gpu/drm/rockchip/cdn-dp-reg.h -rename to include/drm/bridge/cdns-mhdp.h -index 441248b7a79e..d76716d4edc6 100644 ---- a/drivers/gpu/drm/rockchip/cdn-dp-reg.h -+++ b/include/drm/bridge/cdns-mhdp.h -@@ -1,16 +1,31 @@ --/* SPDX-License-Identifier: GPL-2.0-only */ -+/* SPDX-License-Identifier: GPL-2.0 */ - /* - * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd - * Author: Chris Zhong -+ * -+ * This software is licensed under the terms of the GNU General Public -+ * License version 2, as published by the Free Software Foundation, and -+ * may be copied, distributed, and modified under those terms. -+ * -+ * 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 _CDN_DP_REG_H --#define _CDN_DP_REG_H -+#ifndef CDNS_MHDP_H_ -+#define CDNS_MHDP_H_ - -+#include -+#include -+#include -+#include -+#include - #include - - #define ADDR_IMEM 0x10000 - #define ADDR_DMEM 0x20000 -+#define ADDR_PHY_AFE 0x80000 - - /* APB CFG addr */ - #define APB_CTRL 0 -@@ -78,6 +93,10 @@ - #define SOURCE_PIF_SW_RESET 0x30834 - - /* bellow registers need access by mailbox */ -+/* source phy comp */ -+#define PHY_DATA_SEL 0x0818 -+#define LANES_CONFIG 0x0814 -+ - /* source car addr */ - #define SOURCE_HDTX_CAR 0x0900 - #define SOURCE_DPTX_CAR 0x0904 -@@ -89,6 +108,17 @@ - #define SOURCE_CIPHER_CAR 0x0920 - #define SOURCE_CRYPTO_CAR 0x0924 - -+/* mhdp tx_top_comp */ -+#define SCHEDULER_H_SIZE 0x1000 -+#define SCHEDULER_V_SIZE 0x1004 -+#define HDTX_SIGNAL_FRONT_WIDTH 0x100c -+#define HDTX_SIGNAL_SYNC_WIDTH 0x1010 -+#define HDTX_SIGNAL_BACK_WIDTH 0x1014 -+#define HDTX_CONTROLLER 0x1018 -+#define HDTX_HPD 0x1020 -+#define HDTX_CLOCK_REG_0 0x1024 -+#define HDTX_CLOCK_REG_1 0x1028 -+ - /* clock meters addr */ - #define CM_CTRL 0x0a00 - #define CM_I2S_CTRL 0x0a04 -@@ -308,18 +338,24 @@ - #define MB_SIZE_LSB_ID 3 - #define MB_DATA_ID 4 - --#define MB_MODULE_ID_DP_TX 0x01 -+#define MB_MODULE_ID_DP_TX 0x01 -+#define MB_MODULE_ID_HDMI_TX 0x03 - #define MB_MODULE_ID_HDCP_TX 0x07 - #define MB_MODULE_ID_HDCP_RX 0x08 - #define MB_MODULE_ID_HDCP_GENERAL 0x09 --#define MB_MODULE_ID_GENERAL 0x0a -+#define MB_MODULE_ID_GENERAL 0x0A - - /* general opcode */ - #define GENERAL_MAIN_CONTROL 0x01 - #define GENERAL_TEST_ECHO 0x02 - #define GENERAL_BUS_SETTINGS 0x03 - #define GENERAL_TEST_ACCESS 0x04 -+#define GENERAL_WRITE_REGISTER 0x05 -+#define GENERAL_WRITE_FIELD 0x06 -+#define GENERAL_READ_REGISTER 0x07 -+#define GENERAL_GET_HPD_STATE 0x11 - -+/* DPTX opcode */ - #define DPTX_SET_POWER_MNG 0x00 - #define DPTX_SET_HOST_CAPABILITIES 0x01 - #define DPTX_GET_EDID 0x02 -@@ -338,12 +374,24 @@ - #define DPTX_SET_LINK_BREAK_POINT 0x0f - #define DPTX_FORCE_LANES 0x10 - #define DPTX_HPD_STATE 0x11 -+#define DPTX_ADJUST_LT 0x12 -+ -+/* HDMI TX opcode */ -+#define HDMI_TX_READ 0x00 -+#define HDMI_TX_WRITE 0x01 -+#define HDMI_TX_UPDATE_READ 0x02 -+#define HDMI_TX_EDID 0x03 -+#define HDMI_TX_EVENTS 0x04 -+#define HDMI_TX_HPD_STATUS 0x05 -+#define HDMI_TX_DEBUG_ECHO 0xAA -+#define HDMI_TX_TEST 0xBB -+#define HDMI_TX_EDID_INTERNAL 0xF0 - - #define FW_STANDBY 0 - #define FW_ACTIVE 1 - --#define DPTX_EVENT_ENABLE_HPD BIT(0) --#define DPTX_EVENT_ENABLE_TRAINING BIT(1) -+#define MHDP_EVENT_ENABLE_HPD BIT(0) -+#define MHDP_EVENT_ENABLE_TRAINING BIT(1) - - #define LINK_TRAINING_NOT_ACTIVE 0 - #define LINK_TRAINING_RUN 1 -@@ -387,7 +435,35 @@ - #define HDCP_TX_IS_RECEIVER_ID_VALID_EVENT BIT(7) - - #define TU_SIZE 30 --#define CDN_DP_MAX_LINK_RATE DP_LINK_BW_5_4 -+#define CDNS_DP_MAX_LINK_RATE 540000 -+ -+#define F_HDMI_ENCODING(x) (((x) & ((1 << 2) - 1)) << 16) -+#define F_VIF_DATA_WIDTH(x) (((x) & ((1 << 2) - 1)) << 2) -+#define F_HDMI_MODE(x) (((x) & ((1 << 2) - 1)) << 0) -+#define F_GCP_EN(x) (((x) & ((1 << 1) - 1)) << 12) -+#define F_DATA_EN(x) (((x) & ((1 << 1) - 1)) << 15) -+#define F_HDMI2_PREAMBLE_EN(x) (((x) & ((1 << 1) - 1)) << 18) -+#define F_PIC_3D(x) (((x) & ((1 << 4) - 1)) << 7) -+#define F_BCH_EN(x) (((x) & ((1 << 1) - 1)) << 11) -+#define F_SOURCE_PHY_MHDP_SEL(x) (((x) & ((1 << 2) - 1)) << 3) -+#define F_HPD_VALID_WIDTH(x) (((x) & ((1 << 12) - 1)) << 0) -+#define F_HPD_GLITCH_WIDTH(x) (((x) & ((1 << 8) - 1)) << 12) -+#define F_HDMI2_CTRL_IL_MODE(x) (((x) & ((1 << 1) - 1)) << 19) -+#define F_SOURCE_PHY_LANE0_SWAP(x) (((x) & ((1 << 2) - 1)) << 0) -+#define F_SOURCE_PHY_LANE1_SWAP(x) (((x) & ((1 << 2) - 1)) << 2) -+#define F_SOURCE_PHY_LANE2_SWAP(x) (((x) & ((1 << 2) - 1)) << 4) -+#define F_SOURCE_PHY_LANE3_SWAP(x) (((x) & ((1 << 2) - 1)) << 6) -+#define F_SOURCE_PHY_COMB_BYPASS(x) (((x) & ((1 << 1) - 1)) << 21) -+#define F_SOURCE_PHY_20_10(x) (((x) & ((1 << 1) - 1)) << 22) -+#define F_PKT_ALLOC_ADDRESS(x) (((x) & ((1 << 4) - 1)) << 0) -+#define F_ACTIVE_IDLE_TYPE(x) (((x) & ((1 << 1) - 1)) << 17) -+#define F_FIFO1_FLUSH(x) (((x) & ((1 << 1) - 1)) << 0) -+#define F_PKT_ALLOC_WR_EN(x) (((x) & ((1 << 1) - 1)) << 0) -+#define F_DATA_WR(x) (x) -+#define F_WR_ADDR(x) (((x) & ((1 << 4) - 1)) << 0) -+#define F_HOST_WR(x) (((x) & ((1 << 1) - 1)) << 0) -+#define F_TYPE_VALID(x) (((x) & ((1 << 1) - 1)) << 16) -+#define F_PACKET_TYPE(x) (((x) & ((1 << 8) - 1)) << 8) - - /* audio */ - #define AUDIO_PACK_EN BIT(8) -@@ -416,6 +492,24 @@ - /* Reference cycles when using lane clock as reference */ - #define LANE_REF_CYC 0x8000 - -+#define HOTPLUG_DEBOUNCE_MS 200 -+ -+#define IRQ_IN 0 -+#define IRQ_OUT 1 -+#define IRQ_NUM 2 -+ -+#define cdns_mhdp_plat_call(mhdp, operation) \ -+ (!(mhdp) ? -ENODEV : (((mhdp)->plat_data && (mhdp)->plat_data->operation) ? \ -+ (mhdp)->plat_data->operation(mhdp) : ENOIOCTLCMD)) -+ -+/* bus access type */ -+enum { -+ BUS_TYPE_NORMAL_APB = 0, -+ BUS_TYPE_NORMAL_SAPB = 1, -+ BUS_TYPE_LOW4K_APB = 2, -+ BUS_TYPE_LOW4K_SAPB = 3, -+}; -+ - enum voltage_swing_level { - VOLTAGE_LEVEL_0, - VOLTAGE_LEVEL_1, -@@ -451,24 +545,261 @@ enum vic_bt_type { - BT_709 = 0x1, - }; - --void cdn_dp_clock_reset(struct cdn_dp_device *dp); -+enum audio_format { -+ AFMT_I2S = 0, -+ AFMT_SPDIF_INT = 1, -+ AFMT_SPDIF_EXT = 2, -+ AFMT_UNUSED, -+}; -+ -+enum { -+ MODE_DVI, -+ MODE_HDMI_1_4, -+ MODE_HDMI_2_0, -+}; -+ -+struct audio_info { -+ enum audio_format format; -+ int sample_rate; -+ int channels; -+ int sample_width; -+ int connector_type; -+}; -+ -+enum vic_pxl_encoding_format { -+ PXL_RGB = 0x1, -+ YCBCR_4_4_4 = 0x2, -+ YCBCR_4_2_2 = 0x4, -+ YCBCR_4_2_0 = 0x8, -+ Y_ONLY = 0x10, -+}; -+ -+struct video_info { -+ bool h_sync_polarity; -+ bool v_sync_polarity; -+ bool interlaced; -+ int color_depth; -+ enum vic_pxl_encoding_format color_fmt; -+}; -+ -+struct cdns_mhdp_host { -+ unsigned int link_rate; -+ u8 lanes_cnt; -+ u8 volt_swing; -+ u8 pre_emphasis; -+ u8 pattern_supp; -+ u8 fast_link; -+ u8 lane_mapping; -+ u8 enhanced; -+}; -+ -+struct cdns_mhdp_sink { -+ unsigned int link_rate; -+ u8 lanes_cnt; -+ u8 pattern_supp; -+ u8 fast_link; -+ u8 enhanced; -+}; -+ -+struct cdns_mhdp_bridge; -+struct cdns_mhdp_connector; -+ -+struct cdns_mhdp_bridge { -+ struct cdns_mhdp_device *mhdp; -+ struct drm_bridge base; -+ int pbn; -+ int8_t stream_id; -+ struct cdns_mhdp_connector *connector; -+ bool is_active; -+}; -+ -+struct cdns_mhdp_connector { -+ struct drm_connector base; -+ bool is_mst_connector; -+ struct drm_dp_mst_port *port; -+ struct cdns_mhdp_bridge *bridge; -+}; -+ -+struct cdns_mhdp_cec { -+ struct cec_adapter *adap; -+ struct device *dev; -+ struct mutex lock; -+ -+ struct cec_msg msg; -+ struct task_struct *cec_worker; -+}; -+ -+struct cdns_plat_data { -+ /* Vendor PHY support */ -+ int (*bind)(struct platform_device *pdev, -+ struct drm_encoder *encoder, -+ struct cdns_mhdp_device *mhdp); -+ void (*unbind)(struct device *dev); -+ -+ void (*plat_init)(struct cdns_mhdp_device *mhdp); -+ void (*plat_deinit)(struct cdns_mhdp_device *mhdp); -+ -+ int (*phy_set)(struct cdns_mhdp_device *mhdp); -+ bool (*phy_video_valid)(struct cdns_mhdp_device *mhdp); -+ int (*firmware_init)(struct cdns_mhdp_device *mhdp); -+ void (*pclk_rate)(struct cdns_mhdp_device *mhdp); -+ -+ int (*suspend)(struct cdns_mhdp_device *mhdp); -+ int (*resume)(struct cdns_mhdp_device *mhdp); -+ -+ int (*power_on)(struct cdns_mhdp_device *mhdp); -+ int (*power_off)(struct cdns_mhdp_device *mhdp); -+ -+ int bus_type; -+ int video_format; -+ char is_dp; -+ char *plat_name; -+}; -+ -+struct cdns_mhdp_device { -+ void __iomem *regs_base; -+ void __iomem *regs_sec; -+ -+ int bus_type; -+ -+ struct device *dev; -+ -+ struct cdns_mhdp_connector connector; -+ struct clk *spdif_clk; -+ struct reset_control *spdif_rst; -+ -+ struct platform_device *audio_pdev; -+ struct audio_info audio_info; -+ -+ struct cdns_mhdp_bridge bridge; -+ struct phy *phy; -+ -+ struct video_info video_info; -+ struct drm_display_mode mode; -+ const struct drm_display_mode *valid_mode; -+ unsigned int fw_version; -+ -+ struct drm_dp_mst_topology_mgr mst_mgr; -+ struct delayed_work hotplug_work; -+ -+ u32 lane_mapping; -+ bool link_up; -+ bool power_up; -+ bool plugged; -+ bool force_mode_set; -+ bool is_hpd; -+ bool is_ls1028a; -+ struct mutex lock; -+ struct mutex iolock; -+ -+ int irq[IRQ_NUM]; -+ -+ union { -+ struct _dp_data { -+ u8 dpcd[DP_RECEIVER_CAP_SIZE]; -+ u32 rate; -+ u8 num_lanes; -+ struct drm_dp_aux aux; -+ struct cdns_mhdp_host host; -+ struct cdns_mhdp_sink sink; -+ bool is_mst; -+ bool can_mst; -+ } dp; -+ struct _hdmi_data { -+ struct cdns_mhdp_cec cec; -+ u32 char_rate; -+ u32 hdmi_type; -+ } hdmi; -+ }; -+ const struct cdns_plat_data *plat_data; -+ -+}; -+ -+u32 cdns_mhdp_bus_read(struct cdns_mhdp_device *mhdp, u32 offset); -+void cdns_mhdp_bus_write(u32 val, struct cdns_mhdp_device *mhdp, u32 offset); -+void cdns_mhdp_clock_reset(struct cdns_mhdp_device *mhdp); -+void cdns_mhdp_set_fw_clk(struct cdns_mhdp_device *mhdp, unsigned long clk); -+u32 cdns_mhdp_get_fw_clk(struct cdns_mhdp_device *mhdp); -+int cdns_mhdp_load_firmware(struct cdns_mhdp_device *mhdp, const u32 *i_mem, -+ u32 i_size, const u32 *d_mem, u32 d_size); -+int cdns_mhdp_set_firmware_active(struct cdns_mhdp_device *mhdp, bool enable); -+int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp, bool flip); -+int cdns_mhdp_event_config(struct cdns_mhdp_device *mhdp); -+u32 cdns_mhdp_get_event(struct cdns_mhdp_device *mhdp); -+int cdns_mhdp_dpcd_write(struct cdns_mhdp_device *mhdp, u32 addr, u8 value); -+int cdns_mhdp_dpcd_read(struct cdns_mhdp_device *mhdp, -+ u32 addr, u8 *data, u16 len); -+int cdns_mhdp_get_edid_block(void *mhdp, u8 *edid, -+ unsigned int block, size_t length); -+int cdns_mhdp_train_link(struct cdns_mhdp_device *mhdp); -+int cdns_mhdp_set_video_status(struct cdns_mhdp_device *mhdp, int active); -+int cdns_mhdp_config_video(struct cdns_mhdp_device *mhdp); -+ -+/* Audio */ -+int cdns_mhdp_audio_stop(struct cdns_mhdp_device *mhdp, -+ struct audio_info *audio); -+int cdns_mhdp_audio_mute(struct cdns_mhdp_device *mhdp, bool enable); -+int cdns_mhdp_audio_config(struct cdns_mhdp_device *mhdp, -+ struct audio_info *audio); -+int cdns_mhdp_register_audio_driver(struct device *dev); -+void cdns_mhdp_unregister_audio_driver(struct device *dev); -+ -+int cdns_mhdp_reg_read(struct cdns_mhdp_device *mhdp, u32 addr); -+int cdns_mhdp_reg_write(struct cdns_mhdp_device *mhdp, u32 addr, u32 val); -+int cdns_mhdp_reg_write_bit(struct cdns_mhdp_device *mhdp, u16 addr, -+ u8 start_bit, u8 bits_no, u32 val); -+int cdns_mhdp_adjust_lt(struct cdns_mhdp_device *mhdp, u8 nlanes, -+ u16 udelay, u8 *lanes_data, -+ u8 *dpcd); -+ -+int cdns_mhdp_read_hpd(struct cdns_mhdp_device *mhdp); -+u32 cdns_phy_reg_read(struct cdns_mhdp_device *mhdp, u32 addr); -+int cdns_phy_reg_write(struct cdns_mhdp_device *mhdp, u32 addr, u32 val); -+int cdns_mhdp_mailbox_send(struct cdns_mhdp_device *mhdp, u8 module_id, -+ u8 opcode, u16 size, u8 *message); -+int cdns_mhdp_mailbox_read_receive(struct cdns_mhdp_device *mhdp, -+ u8 *buff, u16 buff_size); -+int cdns_mhdp_mailbox_validate_receive(struct cdns_mhdp_device *mhdp, -+ u8 module_id, u8 opcode, -+ u16 req_size); -+int cdns_mhdp_mailbox_read(struct cdns_mhdp_device *mhdp); -+ -+void cdns_mhdp_infoframe_set(struct cdns_mhdp_device *mhdp, -+ u8 entry_id, u8 packet_len, u8 *packet, u8 packet_type); -+int cdns_hdmi_get_edid_block(void *data, u8 *edid, u32 block, size_t length); -+int cdns_hdmi_scdc_read(struct cdns_mhdp_device *mhdp, u8 addr, u8 *data); -+int cdns_hdmi_scdc_write(struct cdns_mhdp_device *mhdp, u8 addr, u8 value); -+int cdns_hdmi_ctrl_init(struct cdns_mhdp_device *mhdp, int protocol, u32 char_rate); -+int cdns_hdmi_mode_config(struct cdns_mhdp_device *mhdp, struct drm_display_mode *mode, -+ struct video_info *video_info); -+int cdns_hdmi_disable_gcp(struct cdns_mhdp_device *mhdp); -+int cdns_hdmi_enable_gcp(struct cdns_mhdp_device *mhdp); -+ -+bool cdns_mhdp_check_alive(struct cdns_mhdp_device *mhdp); -+ -+/* HDMI */ -+int cdns_hdmi_probe(struct platform_device *pdev, -+ struct cdns_mhdp_device *mhdp); -+void cdns_hdmi_remove(struct platform_device *pdev); -+void cdns_hdmi_unbind(struct device *dev); -+int cdns_hdmi_bind(struct platform_device *pdev, -+ struct drm_encoder *encoder, struct cdns_mhdp_device *mhdp); -+void cdns_hdmi_set_sample_rate(struct cdns_mhdp_device *mhdp, unsigned int rate); -+void cdns_hdmi_audio_enable(struct cdns_mhdp_device *mhdp); -+void cdns_hdmi_audio_disable(struct cdns_mhdp_device *mhdp); -+ -+/* DP */ -+int cdns_dp_probe(struct platform_device *pdev, -+ struct cdns_mhdp_device *mhdp); -+void cdns_dp_remove(struct platform_device *pdev); -+void cdns_dp_unbind(struct device *dev); -+int cdns_dp_bind(struct platform_device *pdev, -+ struct drm_encoder *encoder, struct cdns_mhdp_device *mhdp); -+ -+/* CEC */ -+#ifdef CONFIG_DRM_CDNS_HDMI_CEC -+int cdns_mhdp_register_cec_driver(struct device *dev); -+int cdns_mhdp_unregister_cec_driver(struct device *dev); -+#endif - --void cdn_dp_set_fw_clk(struct cdn_dp_device *dp, unsigned long clk); --int cdn_dp_load_firmware(struct cdn_dp_device *dp, const u32 *i_mem, -- u32 i_size, const u32 *d_mem, u32 d_size); --int cdn_dp_set_firmware_active(struct cdn_dp_device *dp, bool enable); --int cdn_dp_set_host_cap(struct cdn_dp_device *dp, u8 lanes, bool flip); --int cdn_dp_event_config(struct cdn_dp_device *dp); --u32 cdn_dp_get_event(struct cdn_dp_device *dp); --int cdn_dp_get_hpd_status(struct cdn_dp_device *dp); --int cdn_dp_dpcd_write(struct cdn_dp_device *dp, u32 addr, u8 value); --int cdn_dp_dpcd_read(struct cdn_dp_device *dp, u32 addr, u8 *data, u16 len); --int cdn_dp_get_edid_block(void *dp, u8 *edid, -- unsigned int block, size_t length); --int cdn_dp_train_link(struct cdn_dp_device *dp); --int cdn_dp_set_video_status(struct cdn_dp_device *dp, int active); --int cdn_dp_config_video(struct cdn_dp_device *dp); --int cdn_dp_audio_stop(struct cdn_dp_device *dp, struct audio_info *audio); --int cdn_dp_audio_mute(struct cdn_dp_device *dp, bool enable); --int cdn_dp_audio_config(struct cdn_dp_device *dp, struct audio_info *audio); --#endif /* _CDN_DP_REG_H */ -+#endif /* CDNS_MHDP_H_ */ --- -2.29.2 - diff --git a/projects/NXP/devices/iMX8/patches/linux/0002-MLK-24065-1-drm-bridge-cadence-fix-dp_aux_transfer-w.patch b/projects/NXP/devices/iMX8/patches/linux/0002-MLK-24065-1-drm-bridge-cadence-fix-dp_aux_transfer-w.patch deleted file mode 100644 index 1b560edf51..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0002-MLK-24065-1-drm-bridge-cadence-fix-dp_aux_transfer-w.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 55eb19200d650ead73139ee8444db9119718fd31 Mon Sep 17 00:00:00 2001 -From: Sergey Zhuravlevich -Date: Tue, 12 May 2020 14:23:15 +0200 -Subject: [PATCH 02/49] MLK-24065-1: drm: bridge: cadence: fix dp_aux_transfer - write return value - -After exiting the loop in DP_AUX_NATIVE_WRITE it was returning 0. It's supposed -to return the number of bytes transferred on success. - -Signed-off-by: Sergey Zhuravlevich -Acked-by: Sandor Yu -Tested-By: Sandor Yu ---- - drivers/gpu/drm/bridge/cadence/cdns-dp-core.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c b/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c -index acb5c860da73..aa92029f44e9 100644 ---- a/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c -+++ b/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c -@@ -67,6 +67,8 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *aux, - - return ret; - } -+ msg->reply = DP_AUX_NATIVE_REPLY_ACK; -+ return msg->size; - } - - if (msg->request == DP_AUX_NATIVE_READ) { --- -2.29.2 - diff --git a/projects/NXP/devices/iMX8/patches/linux/0002-arm64-dts-fsl-imx8mq-evk-enable-DCSS-and-HDMI.patch b/projects/NXP/devices/iMX8/patches/linux/0002-arm64-dts-fsl-imx8mq-evk-enable-DCSS-and-HDMI.patch new file mode 100644 index 0000000000..9f8e943a48 --- /dev/null +++ b/projects/NXP/devices/iMX8/patches/linux/0002-arm64-dts-fsl-imx8mq-evk-enable-DCSS-and-HDMI.patch @@ -0,0 +1,64 @@ +From 5825e6107062b231f1c7449502e04e559f8266e8 Mon Sep 17 00:00:00 2001 +From: Lucas Stach +Date: Tue, 13 Feb 2018 12:47:09 +0100 +Subject: [PATCH 1/4] arm64: dts: fsl: imx8mq-evk: enable DCSS and HDMI + +Adapted for [PATCH v16] Initial support Cadence MHDP8501(HDMI/DP) for i.MX8MQ + +Signed-off-by: Lucas Stach +--- + arch/arm64/boot/dts/freescale/imx8mq-evk.dts | 31 ++++++++++++++++++++ + 1 file changed, 31 insertions(+) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mq-evk.dts b/arch/arm64/boot/dts/freescale/imx8mq-evk.dts +index 7507548cdb16..267e32895aa0 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mq-evk.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mq-evk.dts +@@ -139,6 +139,17 @@ sound-hdmi-arc { + spdif-controller = <&spdif2>; + spdif-in; + }; ++ ++ hdmi_connector: connector { ++ compatible = "hdmi-connector"; ++ label = "X11"; ++ type = "a"; ++ ++ port { ++ hdmi_connector_in: endpoint { ++ }; ++ }; ++ }; + }; + + &A53_0 { +@@ -226,6 +237,26 @@ wl-reg-on-hog { + }; + }; + ++&dcss { ++ status = "okay"; ++}; ++ ++&hdmi_connector { ++ port { ++ hdmi_connector_in: endpoint { ++ remote-endpoint = <&mhdp_out>; ++ }; ++ }; ++}; ++ ++&mhdp { ++ status = "okay"; ++}; ++ ++&mhdp_out { ++ remote-endpoint = <&hdmi_connector_in>; ++}; ++ + &i2c1 { + clock-frequency = <100000>; + pinctrl-names = "default"; +-- +2.43.0 + diff --git a/projects/NXP/devices/iMX8/patches/linux/0003-MLK-24065-3-drm-bridge-cadence-use-the-lane-mapping-.patch b/projects/NXP/devices/iMX8/patches/linux/0003-MLK-24065-3-drm-bridge-cadence-use-the-lane-mapping-.patch deleted file mode 100644 index 76aad36aeb..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0003-MLK-24065-3-drm-bridge-cadence-use-the-lane-mapping-.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 90e1a010995c0a87b0216706b1255ca5d0c36286 Mon Sep 17 00:00:00 2001 -From: Sergey Zhuravlevich -Date: Tue, 12 May 2020 14:23:15 +0200 -Subject: [PATCH 03/49] MLK-24065-3: drm: bridge: cadence: use the lane mapping - from dt when setting host capabilities - -Signed-off-by: Sergey Zhuravlevich -Acked-by: Sandor Yu -Tested-By: Sandor Yu ---- - drivers/gpu/drm/bridge/cadence/cdns-dp-core.c | 2 +- - drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c | 4 ++-- - include/drm/bridge/cdns-mhdp.h | 2 +- - 3 files changed, 4 insertions(+), 4 deletions(-) - -diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c b/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c -index aa92029f44e9..c059d56b4f46 100644 ---- a/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c -+++ b/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c -@@ -152,7 +152,7 @@ static void cdns_dp_mode_set(struct cdns_mhdp_device *mhdp) - cdns_mhdp_reg_write(mhdp, LANES_CONFIG, 0x00400000 | lane_mapping); - - /* Set DP host capability */ -- ret = cdns_mhdp_set_host_cap(mhdp, false); -+ ret = cdns_mhdp_set_host_cap(mhdp); - if (ret) { - DRM_DEV_ERROR(mhdp->dev, "Failed to set host cap %d\n", ret); - return; -diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c -index 91d1cfd4b2af..9c0a2668e494 100644 ---- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c -+++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c -@@ -438,7 +438,7 @@ int cdns_mhdp_set_firmware_active(struct cdns_mhdp_device *mhdp, bool enable) - } - EXPORT_SYMBOL(cdns_mhdp_set_firmware_active); - --int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp, bool flip) -+int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp) - { - u8 msg[8]; - int ret; -@@ -449,7 +449,7 @@ int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp, bool flip) - msg[3] = PRE_EMPHASIS_LEVEL_3; - msg[4] = PTS1 | PTS2 | PTS3 | PTS4; - msg[5] = FAST_LT_NOT_SUPPORT; -- msg[6] = flip ? LANE_MAPPING_FLIPPED : LANE_MAPPING_NORMAL; -+ msg[6] = mhdp->lane_mapping; - msg[7] = ENHANCED; - - ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, -diff --git a/include/drm/bridge/cdns-mhdp.h b/include/drm/bridge/cdns-mhdp.h -index d76716d4edc6..4dc6e428b5f7 100644 ---- a/include/drm/bridge/cdns-mhdp.h -+++ b/include/drm/bridge/cdns-mhdp.h -@@ -723,7 +723,7 @@ u32 cdns_mhdp_get_fw_clk(struct cdns_mhdp_device *mhdp); - int cdns_mhdp_load_firmware(struct cdns_mhdp_device *mhdp, const u32 *i_mem, - u32 i_size, const u32 *d_mem, u32 d_size); - int cdns_mhdp_set_firmware_active(struct cdns_mhdp_device *mhdp, bool enable); --int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp, bool flip); -+int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp); - int cdns_mhdp_event_config(struct cdns_mhdp_device *mhdp); - u32 cdns_mhdp_get_event(struct cdns_mhdp_device *mhdp); - int cdns_mhdp_dpcd_write(struct cdns_mhdp_device *mhdp, u32 addr, u8 value); --- -2.29.2 - diff --git a/projects/NXP/devices/iMX8/patches/linux/0003-arm64-dts-fsl-imx8mq-pico-pi-enable-DCSS-and-HDMI.patch b/projects/NXP/devices/iMX8/patches/linux/0003-arm64-dts-fsl-imx8mq-pico-pi-enable-DCSS-and-HDMI.patch new file mode 100644 index 0000000000..24cc0e2844 --- /dev/null +++ b/projects/NXP/devices/iMX8/patches/linux/0003-arm64-dts-fsl-imx8mq-pico-pi-enable-DCSS-and-HDMI.patch @@ -0,0 +1,55 @@ +From 6b9309988072e3b5b7b3900a1254507316eb72cf Mon Sep 17 00:00:00 2001 +From: Lukas Rusak +Date: Tue, 9 Mar 2021 10:47:27 -0800 +Subject: [PATCH 2/4] arm64: dts: fsl: imx8mq-pico-pi: enable DCSS and HDMI + +Adapted for [PATCH v16] Initial support Cadence MHDP8501(HDMI/DP) for i.MX8MQ +--- + .../boot/dts/freescale/imx8mq-pico-pi.dts | 31 +++++++++++++++++++ + 1 file changed, 31 insertions(+) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mq-pico-pi.dts b/arch/arm64/boot/dts/freescale/imx8mq-pico-pi.dts +index 89cbec5c41b2..5e2b1a84a85e 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mq-pico-pi.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mq-pico-pi.dts +@@ -54,6 +54,37 @@ ethphy0: ethernet-phy@1 { + reg = <1>; + }; + }; ++ ++ hdmi_connector: connector { ++ compatible = "hdmi-connector"; ++ label = "X11"; ++ type = "a"; ++ ++ port { ++ hdmi_connector_in: endpoint { ++ }; ++ }; ++ }; ++}; ++ ++&dcss { ++ status = "okay"; ++}; ++ ++&hdmi_connector { ++ port { ++ hdmi_connector_in: endpoint { ++ remote-endpoint = <&mhdp_out>; ++ }; ++ }; ++}; ++ ++&mhdp { ++ status = "okay"; ++}; ++ ++&mhdp_out { ++ remote-endpoint = <&hdmi_connector_in>; + }; + + &i2c1 { +-- +2.43.0 + diff --git a/projects/NXP/devices/iMX8/patches/linux/0004-MLK-24065-2-drm-bridge-cadence-print-error-when-cloc.patch b/projects/NXP/devices/iMX8/patches/linux/0004-MLK-24065-2-drm-bridge-cadence-print-error-when-cloc.patch deleted file mode 100644 index 23aa13e191..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0004-MLK-24065-2-drm-bridge-cadence-print-error-when-cloc.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 62c1852bc0f94efb6884d34c2c27dcf1efa3b282 Mon Sep 17 00:00:00 2001 -From: Sergey Zhuravlevich -Date: Tue, 12 May 2020 14:23:15 +0200 -Subject: [PATCH 04/49] MLK-24065-2: drm: bridge: cadence: print error when - clock recovery fails - -Signed-off-by: Sergey Zhuravlevich -Acked-by: Sandor Yu -Tested-By: Sandor Yu ---- - drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c -index f025c39d12ea..a032e19765a4 100644 ---- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c -+++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c -@@ -106,7 +106,9 @@ static int cdns_mhdp_training_start(struct cdns_mhdp_device *mhdp) - if (ret) - goto err_training_start; - -- if (event[1] & EQ_PHASE_FINISHED) -+ if (event[1] & CLK_RECOVERY_FAILED) -+ DRM_DEV_ERROR(mhdp->dev, "clock recovery failed\n"); -+ else if (event[1] & EQ_PHASE_FINISHED) - return 0; - } - --- -2.29.2 - diff --git a/projects/NXP/devices/iMX8/patches/linux/0004-arm64-dts-fsl-imx8mq-phanbell.dts-enable-DCSS-and-HD.patch b/projects/NXP/devices/iMX8/patches/linux/0004-arm64-dts-fsl-imx8mq-phanbell.dts-enable-DCSS-and-HD.patch new file mode 100644 index 0000000000..70b8e5f19b --- /dev/null +++ b/projects/NXP/devices/iMX8/patches/linux/0004-arm64-dts-fsl-imx8mq-phanbell.dts-enable-DCSS-and-HD.patch @@ -0,0 +1,62 @@ +From d7a46875e8cc330cc3f1082c054ecfb0c1b32727 Mon Sep 17 00:00:00 2001 +From: Rudi Heitbaum +Date: Sun, 29 Sep 2024 21:08:57 +1000 +Subject: [PATCH 3/4] arm64: dts: fsl: imx8mq-phanbell.dts: enable DCSS and + HDMI + +--- + .../boot/dts/freescale/imx8mq-phanbell.dts | 31 +++++++++++++++++++ + 1 file changed, 31 insertions(+) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mq-phanbell.dts b/arch/arm64/boot/dts/freescale/imx8mq-phanbell.dts +index a3b9d615a3b4..deba4a6f65d5 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mq-phanbell.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mq-phanbell.dts +@@ -46,6 +46,17 @@ fan: gpio-fan { + pinctrl-0 = <&pinctrl_gpio_fan>; + status = "okay"; + }; ++ ++ hdmi_connector: connector { ++ compatible = "hdmi-connector"; ++ label = "X11"; ++ type = "a"; ++ ++ port { ++ hdmi_connector_in: endpoint { ++ }; ++ }; ++ }; + }; + + &A53_0 { +@@ -111,6 +122,26 @@ map4 { + }; + }; + ++&dcss { ++ status = "okay"; ++}; ++ ++&hdmi_connector { ++ port { ++ hdmi_connector_in: endpoint { ++ remote-endpoint = <&mhdp_out>; ++ }; ++ }; ++}; ++ ++&mhdp { ++ status = "okay"; ++}; ++ ++&mhdp_out { ++ remote-endpoint = <&hdmi_connector_in>; ++}; ++ + &i2c1 { + clock-frequency = <400000>; + pinctrl-names = "default"; +-- +2.43.0 + diff --git a/projects/NXP/devices/iMX8/patches/linux/0005-LF-1511-drm-cdn-cec-replace-i-with-i-in-loop.patch b/projects/NXP/devices/iMX8/patches/linux/0005-LF-1511-drm-cdn-cec-replace-i-with-i-in-loop.patch deleted file mode 100644 index d3cbe09cb7..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0005-LF-1511-drm-cdn-cec-replace-i-with-i-in-loop.patch +++ /dev/null @@ -1,37 +0,0 @@ -From eb19fd99254d6a0aa97bb08c09b9f82ebff306c5 Mon Sep 17 00:00:00 2001 -From: Sandor Yu -Date: Fri, 19 Jun 2020 15:32:28 +0800 -Subject: [PATCH 05/49] LF-1511: drm: cdn-cec: replace ++i with i++ in loop - -replace ++i with i++ in loop to prevent Coverity issue. -Coverity ID 9000767 - -Signed-off-by: Sandor Yu -Reviewed-by: Fancy Fang ---- - drivers/gpu/drm/bridge/cadence/cdns-mhdp-cec.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-cec.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-cec.c -index 5717bb0bcb75..029ad761606a 100644 ---- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-cec.c -+++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-cec.c -@@ -163,13 +163,13 @@ static int mhdp_cec_set_logical_addr(struct cdns_mhdp_cec *cec, u32 la) - - if (la == CEC_LOG_ADDR_INVALID) - /* invalid all LA address */ -- for (i = 0; i < CEC_MAX_LOG_ADDRS; ++i) { -+ for (i = 0; i < CEC_MAX_LOG_ADDRS; i++) { - mhdp_cec_write(cec, LOGICAL_ADDRESS_LA0 + (i * REG_ADDR_OFF), 0); - return 0; - } - - /* In fact cdns mhdp cec could support max 5 La address */ -- for (i = 0; i < CEC_MAX_LOG_ADDRS; ++i) { -+ for (i = 0; i < CEC_MAX_LOG_ADDRS; i++) { - la_reg = mhdp_cec_read(cec, LOGICAL_ADDRESS_LA0 + (i * REG_ADDR_OFF)); - /* Check LA already used */ - if (la_reg & 0x10) --- -2.29.2 - diff --git a/projects/NXP/devices/iMX8/patches/linux/0005-arm64-dts-fsl-imx8mq-phanbell.dts-enable-PCI.patch b/projects/NXP/devices/iMX8/patches/linux/0005-arm64-dts-fsl-imx8mq-phanbell.dts-enable-PCI.patch new file mode 100644 index 0000000000..4e681909f6 --- /dev/null +++ b/projects/NXP/devices/iMX8/patches/linux/0005-arm64-dts-fsl-imx8mq-phanbell.dts-enable-PCI.patch @@ -0,0 +1,28 @@ +From 352c7ed9d658a793eba747744e5ec330877e7f50 Mon Sep 17 00:00:00 2001 +From: Rudi Heitbaum +Date: Tue, 1 Oct 2024 06:53:51 +0000 +Subject: [PATCH 4/4] arm64: dts: fsl: imx8mq-phanbell.dts: enable PCI + +--- + arch/arm64/boot/dts/freescale/imx8mq-phanbell.dts | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/arch/arm64/boot/dts/freescale/imx8mq-phanbell.dts b/arch/arm64/boot/dts/freescale/imx8mq-phanbell.dts +index deba4a6f65d5..ed7d3e39af9a 100644 +--- a/arch/arm64/boot/dts/freescale/imx8mq-phanbell.dts ++++ b/arch/arm64/boot/dts/freescale/imx8mq-phanbell.dts +@@ -510,3 +510,11 @@ MX8MQ_IOMUXC_GPIO1_IO02_WDOG1_WDOG_B 0xc6 + >; + }; + }; ++ ++&pcie0 { ++ status = "disabled"; ++}; ++ ++&pcie1 { ++ status = "okay"; ++}; +-- +2.43.0 + diff --git a/projects/NXP/devices/iMX8/patches/linux/0006-LF-1512-drm-cdns-mhdp-avoid-potentially-overflowing.patch b/projects/NXP/devices/iMX8/patches/linux/0006-LF-1512-drm-cdns-mhdp-avoid-potentially-overflowing.patch deleted file mode 100644 index 9e78a7707e..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0006-LF-1512-drm-cdns-mhdp-avoid-potentially-overflowing.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 09dfa5b8ba1a38050e4e95faab1cf07c6a509dad Mon Sep 17 00:00:00 2001 -From: Sandor Yu -Date: Fri, 19 Jun 2020 16:05:42 +0800 -Subject: [PATCH 06/49] LF-1512: drm: cdns mhdp: avoid potentially overflowing - -covert to unsigned 64 bits to avoid potentially overflowing. -Report by Coverity ID 6652952 6652952. - -Signed-off-by: Sandor Yu -Reviewed-by: Fancy Fang ---- - drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c -index 9c0a2668e494..890add9b7c67 100644 ---- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c -+++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c -@@ -657,7 +657,7 @@ int cdns_mhdp_config_video(struct cdns_mhdp_device *mhdp) - */ - do { - tu_size_reg += 2; -- symbol = tu_size_reg * mode->clock * bit_per_pix; -+ symbol = (u64) tu_size_reg * mode->clock * bit_per_pix; - do_div(symbol, mhdp->dp.num_lanes * link_rate * 8); - rem = do_div(symbol, 1000); - if (tu_size_reg > 64) { --- -2.29.2 - diff --git a/projects/NXP/devices/iMX8/patches/linux/0007-MLK-24335-drm-bridge-cdns-hdmi-support-work-in-DVI-m.patch b/projects/NXP/devices/iMX8/patches/linux/0007-MLK-24335-drm-bridge-cdns-hdmi-support-work-in-DVI-m.patch deleted file mode 100644 index 32ae11b0e6..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0007-MLK-24335-drm-bridge-cdns-hdmi-support-work-in-DVI-m.patch +++ /dev/null @@ -1,41 +0,0 @@ -From a1b02ef19cbc24603e1e212f4f4258ca2c59aaad Mon Sep 17 00:00:00 2001 -From: Sandor Yu -Date: Thu, 18 Jun 2020 14:18:04 +0800 -Subject: [PATCH 07/49] MLK-24335: drm: bridge: cdns: hdmi support work in DVI - mode - -hdmi support work in DVI mode. - -Signed-off-by: Sandor Yu ---- - drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c | 7 +++++-- - 1 file changed, 5 insertions(+), 2 deletions(-) - -diff --git a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c -index da40f62617ef..5f2442fa761f 100644 ---- a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c -+++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c -@@ -32,8 +32,9 @@ static void hdmi_sink_config(struct cdns_mhdp_device *mhdp) - struct drm_scdc *scdc = &mhdp->connector.base.display_info.hdmi.scdc; - u8 buff = 0; - -- /* Default work in HDMI1.4 */ -- mhdp->hdmi.hdmi_type = MODE_HDMI_1_4; -+ /* return if hdmi work in DVI mode */ -+ if (mhdp->hdmi.hdmi_type == MODE_DVI) -+ return; - - /* check sink support SCDC or not */ - if (scdc->supported != true) { -@@ -264,6 +265,8 @@ static int cdns_hdmi_connector_get_modes(struct drm_connector *connector) - edid->header[6], edid->header[7]); - drm_connector_update_edid_property(connector, edid); - num_modes = drm_add_edid_modes(connector, edid); -+ mhdp->hdmi.hdmi_type = drm_detect_hdmi_monitor(edid) ? -+ MODE_HDMI_1_4 : MODE_DVI; - kfree(edid); - } - --- -2.29.2 - diff --git a/projects/NXP/devices/iMX8/patches/linux/0008-LF-1762-21-gpu-drm-bridge-cadence-hdmi-update-API-.m.patch b/projects/NXP/devices/iMX8/patches/linux/0008-LF-1762-21-gpu-drm-bridge-cadence-hdmi-update-API-.m.patch deleted file mode 100644 index 114fa3184b..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0008-LF-1762-21-gpu-drm-bridge-cadence-hdmi-update-API-.m.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 83f932299b9969a1823b085d2269db677362f897 Mon Sep 17 00:00:00 2001 -From: Dong Aisheng -Date: Tue, 14 Jul 2020 19:18:25 +0800 -Subject: [PATCH 08/49] LF-1762-21 gpu: drm: bridge: cadence: hdmi: update API - .mode_valid() - -API changed since: -12c683e12cd8 ("drm: bridge: Pass drm_display_info to drm_bridge_funcs .mode_valid()") - -Signed-off-by: Dong Aisheng ---- - drivers/gpu/drm/bridge/cadence/cdns-dp-core.c | 1 + - drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c | 1 + - 2 files changed, 2 insertions(+) - -diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c b/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c -index c059d56b4f46..cb4897c664f0 100644 ---- a/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c -+++ b/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c -@@ -256,6 +256,7 @@ static int cdns_dp_bridge_attach(struct drm_bridge *bridge, - - static enum drm_mode_status - cdns_dp_bridge_mode_valid(struct drm_bridge *bridge, -+ const struct drm_display_info *info, - const struct drm_display_mode *mode) - { - enum drm_mode_status mode_status = MODE_OK; -diff --git a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c -index 5f2442fa761f..1e5130e295f7 100644 ---- a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c -+++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c -@@ -359,6 +359,7 @@ static int cdns_hdmi_bridge_attach(struct drm_bridge *bridge, - - static enum drm_mode_status - cdns_hdmi_bridge_mode_valid(struct drm_bridge *bridge, -+ const struct drm_display_info *info, - const struct drm_display_mode *mode) - { - struct cdns_mhdp_device *mhdp = bridge->driver_private; --- -2.29.2 - diff --git a/projects/NXP/devices/iMX8/patches/linux/0009-LF-2271-1-drm-bridge-cdns-Use-colorspace-connector-p.patch b/projects/NXP/devices/iMX8/patches/linux/0009-LF-2271-1-drm-bridge-cdns-Use-colorspace-connector-p.patch deleted file mode 100644 index 0c1a6a7166..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0009-LF-2271-1-drm-bridge-cdns-Use-colorspace-connector-p.patch +++ /dev/null @@ -1,107 +0,0 @@ -From 150d291f3e5cb47a97790b89e79d8f1a5aa797dd Mon Sep 17 00:00:00 2001 -From: Laurentiu Palcu -Date: Fri, 28 Aug 2020 10:26:31 +0300 -Subject: [PATCH 09/49] LF-2271-1: drm/bridge/cdns: Use colorspace connector - property for imx8mq - -This patch achieves 2 goals: - * Make use of colorspace property when setting up the color_depth and - color_fmt. The userspace can now choose which colorspace to use by changing - the colorspace property; - * Do not use drm_display_mode private_flags to signal CRTC which pixel encoding - is being used by connector. Upstream is getting rid of 'private_flags' usage - and the declaration will probably be removed in the next release; - -Signed-off-by: Laurentiu Palcu -Reviewed-by: Robert Chiras ---- - .../gpu/drm/bridge/cadence/cdns-hdmi-core.c | 58 ++++++++++++------- - 1 file changed, 36 insertions(+), 22 deletions(-) - -diff --git a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c -index 1e5130e295f7..2796252adf68 100644 ---- a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c -+++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c -@@ -412,6 +412,7 @@ bool cdns_hdmi_bridge_mode_fixup(struct drm_bridge *bridge, - struct drm_display_mode *adjusted_mode) - { - struct cdns_mhdp_device *mhdp = bridge->driver_private; -+ struct drm_connector_state *conn_state = mhdp->connector.base.state; - struct drm_display_info *di = &mhdp->connector.base.display_info; - struct video_info *video = &mhdp->video_info; - int vic = drm_match_cea_mode(mode); -@@ -428,36 +429,49 @@ bool cdns_hdmi_bridge_mode_fixup(struct drm_bridge *bridge, - } - - /* imx8mq */ -- if (vic == 97 || vic == 96) { -- if (di->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_36) -- video->color_depth = 12; -- else if (di->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_30) -- video->color_depth = 10; -- -- if (drm_mode_is_420_only(di, mode) || -- (drm_mode_is_420_also(di, mode) && -- video->color_depth > 8)) { -+ if (conn_state->colorspace == DRM_MODE_COLORIMETRY_DEFAULT) -+ return !drm_mode_is_420_only(di, mode); -+ -+ if (conn_state->colorspace == DRM_MODE_COLORIMETRY_BT2020_RGB) { -+ if (drm_mode_is_420_only(di, mode)) -+ return false; -+ -+ /* 10b RGB is not supported for following VICs */ -+ if (vic == 97 || vic == 96 || vic == 95 || vic == 93 || vic == 94) -+ return false; -+ -+ video->color_depth = 10; -+ -+ return true; -+ } -+ -+ if (conn_state->colorspace == DRM_MODE_COLORIMETRY_BT2020_CYCC || -+ conn_state->colorspace == DRM_MODE_COLORIMETRY_BT2020_YCC) { -+ if (drm_mode_is_420_only(di, mode)) { - video->color_fmt = YCBCR_4_2_0; - -- adjusted_mode->private_flags = 1; -+ if (di->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_36) -+ video->color_depth = 12; -+ else if (di->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_30) -+ video->color_depth = 10; -+ else -+ return false; -+ - return true; - } - -- video->color_depth = 8; -- return true; -- } -+ video->color_fmt = YCBCR_4_2_2; -+ -+ if (!(di->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_36)) -+ return false; - -- /* Any defined maximum tmds clock limit we must not exceed*/ -- if ((di->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_36) && -- (mode->clock * 3 / 2 <= di->max_tmds_clock)) - video->color_depth = 12; -- else if ((di->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_30) && -- (mode->clock * 5 / 4 <= di->max_tmds_clock)) -- video->color_depth = 10; - -- /* 10-bit color depth for the following modes is not supported */ -- if ((vic == 95 || vic == 94 || vic == 93) && video->color_depth == 10) -- video->color_depth = 8; -+ return true; -+ } -+ -+ video->color_fmt = drm_mode_is_420_only(di, mode) ? YCBCR_4_2_0 : YCBCR_4_4_4; -+ video->color_depth = 8; - - return true; - } --- -2.29.2 - diff --git a/projects/NXP/devices/iMX8/patches/linux/0010-MLK-24770-drm-mhdp-Sync-DPTX-capability-with-Cadence.patch b/projects/NXP/devices/iMX8/patches/linux/0010-MLK-24770-drm-mhdp-Sync-DPTX-capability-with-Cadence.patch deleted file mode 100644 index efc243e6f3..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0010-MLK-24770-drm-mhdp-Sync-DPTX-capability-with-Cadence.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 04a71f1da60e51f277d4979c698e52cacb028666 Mon Sep 17 00:00:00 2001 -From: Sandor Yu -Date: Mon, 14 Sep 2020 15:06:35 +0800 -Subject: [PATCH 10/49] MLK-24770: drm: mhdp: Sync DPTX capability with Cadence - sample code - -Sync the max vswing and pre-emphasis setting with Cadence sample code. -The max vswing is VOLTAGE_LEVEL_3 and -the max pre-emphasis is PRE_EMPHASIS_LEVEL_2 now. - -Signed-off-by: Sandor Yu -Reviewed-by: Robby Cai ---- - drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c -index 890add9b7c67..2043016f176b 100644 ---- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c -+++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c -@@ -445,8 +445,8 @@ int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp) - - msg[0] = drm_dp_link_rate_to_bw_code(mhdp->dp.rate); - msg[1] = mhdp->dp.num_lanes | SCRAMBLER_EN; -- msg[2] = VOLTAGE_LEVEL_2; -- msg[3] = PRE_EMPHASIS_LEVEL_3; -+ msg[2] = VOLTAGE_LEVEL_3; -+ msg[3] = PRE_EMPHASIS_LEVEL_2; - msg[4] = PTS1 | PTS2 | PTS3 | PTS4; - msg[5] = FAST_LT_NOT_SUPPORT; - msg[6] = mhdp->lane_mapping; --- -2.29.2 - diff --git a/projects/NXP/devices/iMX8/patches/linux/0011-MLK-24520-drm-bridge-cdns-increase-maximum-width-fro.patch b/projects/NXP/devices/iMX8/patches/linux/0011-MLK-24520-drm-bridge-cdns-increase-maximum-width-fro.patch deleted file mode 100644 index baf7c0f9dc..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0011-MLK-24520-drm-bridge-cdns-increase-maximum-width-fro.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 11b66e4bdb8ba6dc4e6981ecef69534c3d6d8df8 Mon Sep 17 00:00:00 2001 -From: "Oliver F. Brown" -Date: Thu, 23 Jul 2020 18:24:23 -0500 -Subject: [PATCH 11/49] MLK-24520: drm: bridge: cdns: increase maximum width - from 4096 to 5120. - -This patch increases the maximum width to 5120. - -Signed-off-by: Oliver F. Brown -Reviewed-by: Liu Ying ---- - drivers/gpu/drm/bridge/cadence/cdns-dp-core.c | 4 ++-- - drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c | 4 ++-- - 2 files changed, 4 insertions(+), 4 deletions(-) - -diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c b/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c -index cb4897c664f0..0f2a38d19a57 100644 ---- a/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c -+++ b/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c -@@ -270,8 +270,8 @@ cdns_dp_bridge_mode_valid(struct drm_bridge *bridge, - if (mode->clock > 594000) - return MODE_CLOCK_HIGH; - -- /* 4096x2160 is not supported now */ -- if (mode->hdisplay > 3840) -+ /* 5120 x 2160 is the maximum supported resulution */ -+ if (mode->hdisplay > 5120) - return MODE_BAD_HVALUE; - - if (mode->vdisplay > 2160) -diff --git a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c -index 2796252adf68..442df6284c49 100644 ---- a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c -+++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c -@@ -375,8 +375,8 @@ cdns_hdmi_bridge_mode_valid(struct drm_bridge *bridge, - if (mode->clock > 594000) - return MODE_CLOCK_HIGH; - -- /* 4096x2160 is not supported */ -- if (mode->hdisplay > 3840 || mode->vdisplay > 2160) -+ /* 5120 x 2160 is the maximum supported resolution */ -+ if (mode->hdisplay > 5120 || mode->vdisplay > 2160) - return MODE_BAD_HVALUE; - - mhdp->valid_mode = mode; --- -2.29.2 - diff --git a/projects/NXP/devices/iMX8/patches/linux/0012-MLK-24521-drm-bridge-hdmi-Prevent-the-driver-from-re.patch b/projects/NXP/devices/iMX8/patches/linux/0012-MLK-24521-drm-bridge-hdmi-Prevent-the-driver-from-re.patch deleted file mode 100644 index 00199349fd..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0012-MLK-24521-drm-bridge-hdmi-Prevent-the-driver-from-re.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 4cb4fe3262fbbf6b31731b6b076698bcf951b9a1 Mon Sep 17 00:00:00 2001 -From: "Oliver F. Brown" -Date: Fri, 24 Jul 2020 14:28:05 -0500 -Subject: [PATCH 12/49] MLK-24521: drm: bridge: hdmi: Prevent the driver from - rejecting VIC 0 modes - -iMX8QM can support the non CEA modes, iMX8M cannot support non CEA modes. -So driver should allow non CEA modes for iMX8QM. - -Signed-off-by: Oliver F. Brown -Reviewed-by: Liu Ying ---- - drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c -index 442df6284c49..a8fa559de9e9 100644 ---- a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c -+++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c -@@ -364,6 +364,7 @@ cdns_hdmi_bridge_mode_valid(struct drm_bridge *bridge, - { - struct cdns_mhdp_device *mhdp = bridge->driver_private; - enum drm_mode_status mode_status = MODE_OK; -+ u32 vic; - int ret; - - /* We don't support double-clocked and Interlaced modes */ -@@ -379,6 +380,13 @@ cdns_hdmi_bridge_mode_valid(struct drm_bridge *bridge, - if (mode->hdisplay > 5120 || mode->vdisplay > 2160) - return MODE_BAD_HVALUE; - -+ /* imx8mq-hdmi does not support non CEA modes */ -+ if (!strncmp("imx8mq-hdmi", mhdp->plat_data->plat_name, 11)) { -+ vic = drm_match_cea_mode(mode); -+ if (vic == 0) -+ return MODE_BAD; -+ } -+ - mhdp->valid_mode = mode; - ret = cdns_mhdp_plat_call(mhdp, phy_video_valid); - if (ret == false) --- -2.29.2 - diff --git a/projects/NXP/devices/iMX8/patches/linux/0013-MLK-23642-1-drm-bridge-cadence-support-HBR-and-6-cha.patch b/projects/NXP/devices/iMX8/patches/linux/0013-MLK-23642-1-drm-bridge-cadence-support-HBR-and-6-cha.patch deleted file mode 100644 index 7c97e9aabe..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0013-MLK-23642-1-drm-bridge-cadence-support-HBR-and-6-cha.patch +++ /dev/null @@ -1,116 +0,0 @@ -From cd7804fc3777e0b53d69d34058fee39accc72072 Mon Sep 17 00:00:00 2001 -From: Shengjiu Wang -Date: Wed, 29 Apr 2020 17:34:07 +0800 -Subject: [PATCH 13/49] MLK-23642-1: drm: bridge: cadence: support HBR and 6 - channel - -Support HBR and 6 channel. - -For HBR, it only support compressed bitstream, sample rate -is 192kHz, and 8 channels. - -Signed-off-by: Shengjiu Wang -Reviewed-by: Viorel Suman ---- - .../gpu/drm/bridge/cadence/cdns-mhdp-audio.c | 33 ++++++++++++++----- - include/drm/bridge/cdns-mhdp.h | 1 + - 2 files changed, 26 insertions(+), 8 deletions(-) - -diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c -index 86174fb633bc..fa1dcf781539 100644 ---- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c -+++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c -@@ -72,6 +72,8 @@ static void hdmi_audio_avi_set(struct cdns_mhdp_device *mhdp, - frame.channel_allocation = 0; - else if (channels == 4) - frame.channel_allocation = 0x3; -+ else if (channels == 6) -+ frame.channel_allocation = 0xB; - else if (channels == 8) - frame.channel_allocation = 0x13; - -@@ -143,26 +145,38 @@ static void cdns_mhdp_audio_config_i2s(struct cdns_mhdp_device *mhdp, - { - int sub_pckt_num = 1, i2s_port_en_val = 0xf, i; - int idx = select_N_index(mhdp->mode.clock); -+ int numofchannels = audio->channels; - u32 val, ncts; -+ u32 disable_port3 = 0; -+ u32 audio_type = 0x2; /* L-PCM */ -+ u32 transmission_type = 0; /* not required for L-PCM */ - -- if (audio->channels == 2) { -+ if (numofchannels == 2) { - if (mhdp->dp.num_lanes == 1) - sub_pckt_num = 2; - else - sub_pckt_num = 4; - - i2s_port_en_val = 1; -- } else if (audio->channels == 4) { -+ } else if (numofchannels == 4) { - i2s_port_en_val = 3; -+ } else if (numofchannels == 6) { -+ numofchannels = 8; -+ disable_port3 = 1; -+ } else if ((numofchannels == 8) && (audio->non_pcm)) { -+ audio_type = 0x9; /* HBR packet type */ -+ transmission_type = 0x9; /* HBR packet type */ - } - - cdns_mhdp_bus_write(0x0, mhdp, SPDIF_CTRL_ADDR); - -- cdns_mhdp_bus_write(SYNC_WR_TO_CH_ZERO, mhdp, FIFO_CNTL); -+ val = SYNC_WR_TO_CH_ZERO; -+ val |= disable_port3 << 4; -+ cdns_mhdp_bus_write(val, mhdp, FIFO_CNTL); - -- val = MAX_NUM_CH(audio->channels); -- val |= NUM_OF_I2S_PORTS(audio->channels); -- val |= AUDIO_TYPE_LPCM; -+ val = MAX_NUM_CH(numofchannels); -+ val |= NUM_OF_I2S_PORTS(numofchannels); -+ val |= audio_type << 7; - val |= CFG_SUB_PCKT_NUM(sub_pckt_num); - cdns_mhdp_bus_write(val, mhdp, SMPL2PKT_CNFG); - -@@ -173,12 +187,13 @@ static void cdns_mhdp_audio_config_i2s(struct cdns_mhdp_device *mhdp, - else - val = 2 << 9; - -- val |= AUDIO_CH_NUM(audio->channels); -+ val |= AUDIO_CH_NUM(numofchannels); - val |= I2S_DEC_PORT_EN(i2s_port_en_val); - val |= TRANS_SMPL_WIDTH_32; -+ val |= transmission_type << 13; - cdns_mhdp_bus_write(val, mhdp, AUDIO_SRC_CNFG); - -- for (i = 0; i < (audio->channels + 1) / 2; i++) { -+ for (i = 0; i < (numofchannels + 1) / 2; i++) { - if (audio->sample_width == 16) - val = (0x02 << 8) | (0x02 << 20); - else if (audio->sample_width == 24) -@@ -323,6 +338,8 @@ static int audio_hw_params(struct device *dev, void *data, - goto out; - } - -+ audio.non_pcm = params->iec.status[0] & IEC958_AES0_NONAUDIO; -+ - ret = cdns_mhdp_audio_config(mhdp, &audio); - if (!ret) - mhdp->audio_info = audio; -diff --git a/include/drm/bridge/cdns-mhdp.h b/include/drm/bridge/cdns-mhdp.h -index 4dc6e428b5f7..1f8fd024cdfa 100644 ---- a/include/drm/bridge/cdns-mhdp.h -+++ b/include/drm/bridge/cdns-mhdp.h -@@ -564,6 +564,7 @@ struct audio_info { - int channels; - int sample_width; - int connector_type; -+ bool non_pcm; - }; - - enum vic_pxl_encoding_format { --- -2.29.2 - diff --git a/projects/NXP/devices/iMX8/patches/linux/0014-MLK-24611-2-drm-bridge-cdns-Add-callback-function-fo.patch b/projects/NXP/devices/iMX8/patches/linux/0014-MLK-24611-2-drm-bridge-cdns-Add-callback-function-fo.patch deleted file mode 100644 index 1b2c1413b0..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0014-MLK-24611-2-drm-bridge-cdns-Add-callback-function-fo.patch +++ /dev/null @@ -1,157 +0,0 @@ -From 46bf1dc2ba34440e8f83b3f70e3e4d6b3f9e6183 Mon Sep 17 00:00:00 2001 -From: Shengjiu Wang -Date: Mon, 31 Aug 2020 14:50:29 +0800 -Subject: [PATCH 14/49] MLK-24611-2: drm: bridge: cdns: Add callback function - for plug/unplug event - -cdns-hdmi-core exports a function cdns_hdmi_set_plugged_cb so -platform device can register the callback - -implement hook_plugged_cb to register callback function for hdmi cable -plug/unplug event. - -Signed-off-by: Shengjiu Wang -Reviewed-by: Sandor Yu ---- - .../gpu/drm/bridge/cadence/cdns-hdmi-core.c | 41 +++++++++++++++++-- - .../gpu/drm/bridge/cadence/cdns-mhdp-audio.c | 10 +++++ - include/drm/bridge/cdns-mhdp.h | 6 +++ - 3 files changed, 54 insertions(+), 3 deletions(-) - -diff --git a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c -index a8fa559de9e9..5890da8aa1a1 100644 ---- a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c -+++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c -@@ -225,11 +225,35 @@ void cdns_hdmi_mode_set(struct cdns_mhdp_device *mhdp) - } - } - -+static void handle_plugged_change(struct cdns_mhdp_device *mhdp, bool plugged) -+{ -+ if (mhdp->plugged_cb && mhdp->codec_dev) -+ mhdp->plugged_cb(mhdp->codec_dev, plugged); -+} -+ -+int cdns_hdmi_set_plugged_cb(struct cdns_mhdp_device *mhdp, -+ hdmi_codec_plugged_cb fn, -+ struct device *codec_dev) -+{ -+ bool plugged; -+ -+ mutex_lock(&mhdp->lock); -+ mhdp->plugged_cb = fn; -+ mhdp->codec_dev = codec_dev; -+ plugged = mhdp->last_connector_result == connector_status_connected; -+ handle_plugged_change(mhdp, plugged); -+ mutex_unlock(&mhdp->lock); -+ -+ return 0; -+} -+EXPORT_SYMBOL_GPL(cdns_hdmi_set_plugged_cb); -+ - static enum drm_connector_status - cdns_hdmi_connector_detect(struct drm_connector *connector, bool force) - { - struct cdns_mhdp_device *mhdp = - container_of(connector, struct cdns_mhdp_device, connector.base); -+ enum drm_connector_status result; - - u8 hpd = 0xf; - -@@ -237,15 +261,25 @@ cdns_hdmi_connector_detect(struct drm_connector *connector, bool force) - - if (hpd == 1) - /* Cable Connected */ -- return connector_status_connected; -+ result = connector_status_connected; - else if (hpd == 0) - /* Cable Disconnedted */ -- return connector_status_disconnected; -+ result = connector_status_disconnected; - else { - /* Cable status unknown */ - DRM_INFO("Unknow cable status, hdp=%u\n", hpd); -- return connector_status_unknown; -+ result = connector_status_unknown; -+ } -+ -+ mutex_lock(&mhdp->lock); -+ if (result != mhdp->last_connector_result) { -+ handle_plugged_change(mhdp, -+ result == connector_status_connected); -+ mhdp->last_connector_result = result; - } -+ mutex_unlock(&mhdp->lock); -+ -+ return result; - } - - static int cdns_hdmi_connector_get_modes(struct drm_connector *connector) -@@ -624,6 +658,7 @@ static int __cdns_hdmi_probe(struct platform_device *pdev, - #ifdef CONFIG_OF - mhdp->bridge.base.of_node = dev->of_node; - #endif -+ mhdp->last_connector_result = connector_status_disconnected; - - memset(&pdevinfo, 0, sizeof(pdevinfo)); - pdevinfo.parent = dev; -diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c -index fa1dcf781539..f4f3f9ca437c 100644 ---- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c -+++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c -@@ -380,11 +380,21 @@ static int audio_get_eld(struct device *dev, void *data, - return 0; - } - -+static int audio_hook_plugged_cb(struct device *dev, void *data, -+ hdmi_codec_plugged_cb fn, -+ struct device *codec_dev) -+{ -+ struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev); -+ -+ return cdns_hdmi_set_plugged_cb(mhdp, fn, codec_dev); -+} -+ - static const struct hdmi_codec_ops audio_codec_ops = { - .hw_params = audio_hw_params, - .audio_shutdown = audio_shutdown, - .digital_mute = audio_digital_mute, - .get_eld = audio_get_eld, -+ .hook_plugged_cb = audio_hook_plugged_cb, - }; - - int cdns_mhdp_register_audio_driver(struct device *dev) -diff --git a/include/drm/bridge/cdns-mhdp.h b/include/drm/bridge/cdns-mhdp.h -index 1f8fd024cdfa..6bfd82a3d9a2 100644 ---- a/include/drm/bridge/cdns-mhdp.h -+++ b/include/drm/bridge/cdns-mhdp.h -@@ -22,6 +22,7 @@ - #include - #include - #include -+#include - - #define ADDR_IMEM 0x10000 - #define ADDR_DMEM 0x20000 -@@ -714,6 +715,9 @@ struct cdns_mhdp_device { - }; - const struct cdns_plat_data *plat_data; - -+ hdmi_codec_plugged_cb plugged_cb; -+ struct device *codec_dev; -+ enum drm_connector_status last_connector_result; - }; - - u32 cdns_mhdp_bus_read(struct cdns_mhdp_device *mhdp, u32 offset); -@@ -796,6 +800,8 @@ void cdns_dp_remove(struct platform_device *pdev); - void cdns_dp_unbind(struct device *dev); - int cdns_dp_bind(struct platform_device *pdev, - struct drm_encoder *encoder, struct cdns_mhdp_device *mhdp); -+int cdns_hdmi_set_plugged_cb(struct cdns_mhdp_device *mhdp, hdmi_codec_plugged_cb fn, -+ struct device *codec_dev); - - /* CEC */ - #ifdef CONFIG_DRM_CDNS_HDMI_CEC --- -2.29.2 - diff --git a/projects/NXP/devices/iMX8/patches/linux/0015-gpu-drm-dridge-hdp-audio-change-to-mute_stream.patch b/projects/NXP/devices/iMX8/patches/linux/0015-gpu-drm-dridge-hdp-audio-change-to-mute_stream.patch deleted file mode 100644 index 9745c16806..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0015-gpu-drm-dridge-hdp-audio-change-to-mute_stream.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 1b0a179061890c0a2f6748426f03e8cd2176d3e2 Mon Sep 17 00:00:00 2001 -From: Dong Aisheng -Date: Wed, 5 Aug 2020 21:31:04 +0800 -Subject: [PATCH 15/49] gpu: drm: dridge: hdp-audio: change to mute_stream - -To cope with upstream API change: -e2978c45e5ed ("ASoC: soc-dai: remove .digital_mute") - -Signed-off-by: Dong Aisheng ---- - drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c | 7 ++++--- - 1 file changed, 4 insertions(+), 3 deletions(-) - -diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c -index f4f3f9ca437c..85f526175439 100644 ---- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c -+++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c -@@ -358,8 +358,8 @@ static void audio_shutdown(struct device *dev, void *data) - mhdp->audio_info.format = AFMT_UNUSED; - } - --static int audio_digital_mute(struct device *dev, void *data, -- bool enable) -+static int audio_mute_stream(struct device *dev, void *data, -+ bool enable, int direction) - { - struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev); - int ret; -@@ -392,9 +392,10 @@ static int audio_hook_plugged_cb(struct device *dev, void *data, - static const struct hdmi_codec_ops audio_codec_ops = { - .hw_params = audio_hw_params, - .audio_shutdown = audio_shutdown, -- .digital_mute = audio_digital_mute, -+ .mute_stream = audio_mute_stream, - .get_eld = audio_get_eld, - .hook_plugged_cb = audio_hook_plugged_cb, -+ .no_capture_mute = 1, - }; - - int cdns_mhdp_register_audio_driver(struct device *dev) --- -2.29.2 - diff --git a/projects/NXP/devices/iMX8/patches/linux/0016-LF-2744-drm-cdns-reset-force_mode_set-flag-in-atomic.patch b/projects/NXP/devices/iMX8/patches/linux/0016-LF-2744-drm-cdns-reset-force_mode_set-flag-in-atomic.patch deleted file mode 100644 index 6be40ad2f3..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0016-LF-2744-drm-cdns-reset-force_mode_set-flag-in-atomic.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 4a406e182a709718a769c37d33530ed2e6b23b39 Mon Sep 17 00:00:00 2001 -From: Sandor Yu -Date: Tue, 17 Nov 2020 15:47:36 +0800 -Subject: [PATCH 16/49] LF-2744: drm: cdns: reset force_mode_set flag in - atomic_check - -Reset force_mode_set flag in atomic_check function -to avoid set mode_changed flag multi times when cable plugin. - -Signed-off-by: Sandor Yu -Reviewed-by: Robby Cai ---- - drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c | 4 +--- - 1 file changed, 1 insertion(+), 3 deletions(-) - -diff --git a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c -index 5890da8aa1a1..e796c2c0e895 100644 ---- a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c -+++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c -@@ -1,7 +1,7 @@ - /* - * Cadence High-Definition Multimedia Interface (HDMI) driver - * -- * Copyright (C) 2019 NXP Semiconductor, Inc. -+ * Copyright (C) 2019-2020 NXP Semiconductor, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -445,8 +445,6 @@ static void cdns_hdmi_bridge_mode_set(struct drm_bridge *bridge, - mutex_lock(&mhdp->lock); - cdns_hdmi_mode_set(mhdp); - mutex_unlock(&mhdp->lock); -- /* reset force mode set flag */ -- mhdp->force_mode_set = false; - } - - bool cdns_hdmi_bridge_mode_fixup(struct drm_bridge *bridge, --- -2.29.2 - diff --git a/projects/NXP/devices/iMX8/patches/linux/0017-MLK-24081-03-drm-bridge-cdns-cec-support-hdmi-rx-cec.patch b/projects/NXP/devices/iMX8/patches/linux/0017-MLK-24081-03-drm-bridge-cdns-cec-support-hdmi-rx-cec.patch deleted file mode 100644 index 69014b43b7..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0017-MLK-24081-03-drm-bridge-cdns-cec-support-hdmi-rx-cec.patch +++ /dev/null @@ -1,271 +0,0 @@ -From f7f5ec54b815df2c9a92f0fd6edea4f5d0700937 Mon Sep 17 00:00:00 2001 -From: Sandor Yu -Date: Mon, 16 Nov 2020 10:56:44 +0800 -Subject: [PATCH 17/49] MLK-24081-03: drm: bridge: cdns-cec: support hdmi rx - cec - -Create struct cdns_mhdp_cec and cec specific bus_read/write function. -CEC driver could be reuse by hdmi rx. - -Signed-off-by: Sandor Yu -Reviewed-by: Robby Cai ---- - drivers/gpu/drm/bridge/cadence/Kconfig | 1 - - .../gpu/drm/bridge/cadence/cdns-hdmi-core.c | 18 ++++- - .../gpu/drm/bridge/cadence/cdns-mhdp-cec.c | 66 +++++++++++++------ - .../gpu/drm/bridge/cadence/cdns-mhdp-common.c | 6 -- - include/drm/bridge/cdns-mhdp.h | 19 +++--- - 5 files changed, 72 insertions(+), 38 deletions(-) - -diff --git a/drivers/gpu/drm/bridge/cadence/Kconfig b/drivers/gpu/drm/bridge/cadence/Kconfig -index bb1865b15aca..c271ab24a99a 100644 ---- a/drivers/gpu/drm/bridge/cadence/Kconfig -+++ b/drivers/gpu/drm/bridge/cadence/Kconfig -@@ -45,6 +45,5 @@ config DRM_CDNS_AUDIO - - config DRM_CDNS_HDMI_CEC - tristate "Cadence MHDP HDMI CEC driver" -- depends on DRM_CDNS_HDMI - select CEC_CORE - select CEC_NOTIFIER -diff --git a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c -index e796c2c0e895..84c175997740 100644 ---- a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c -+++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c -@@ -569,6 +569,19 @@ static void cdns_hdmi_parse_dt(struct cdns_mhdp_device *mhdp) - dev_info(mhdp->dev, "lane-mapping 0x%02x\n", mhdp->lane_mapping); - } - -+#ifdef CONFIG_DRM_CDNS_HDMI_CEC -+static void cdns_mhdp_cec_init(struct cdns_mhdp_device *mhdp) -+{ -+ struct cdns_mhdp_cec *cec = &mhdp->hdmi.cec; -+ -+ cec->dev = mhdp->dev; -+ cec->iolock = &mhdp->iolock; -+ cec->regs_base = mhdp->regs_base; -+ cec->regs_sec = mhdp->regs_sec; -+ cec->bus_type = mhdp->bus_type; -+} -+#endif -+ - static int __cdns_hdmi_probe(struct platform_device *pdev, - struct cdns_mhdp_device *mhdp) - { -@@ -669,7 +682,8 @@ static int __cdns_hdmi_probe(struct platform_device *pdev, - - /* register cec driver */ - #ifdef CONFIG_DRM_CDNS_HDMI_CEC -- cdns_mhdp_register_cec_driver(dev); -+ cdns_mhdp_cec_init(mhdp); -+ cdns_mhdp_register_cec_driver(&mhdp->hdmi.cec); - #endif - - return 0; -@@ -679,7 +693,7 @@ static void __cdns_hdmi_remove(struct cdns_mhdp_device *mhdp) - { - /* unregister cec driver */ - #ifdef CONFIG_DRM_CDNS_HDMI_CEC -- cdns_mhdp_unregister_cec_driver(mhdp->dev); -+ cdns_mhdp_unregister_cec_driver(&mhdp->hdmi.cec); - #endif - cdns_mhdp_unregister_audio_driver(mhdp->dev); - } -diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-cec.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-cec.c -index 029ad761606a..25cf9e91e64f 100644 ---- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-cec.c -+++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-cec.c -@@ -1,5 +1,5 @@ - /* -- * Copyright 2019 NXP -+ * Copyright 2019-2020 NXP - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License -@@ -74,16 +74,49 @@ enum { - - static u32 mhdp_cec_read(struct cdns_mhdp_cec *cec, u32 offset) - { -- struct cdns_mhdp_device *mhdp = -- container_of(cec, struct cdns_mhdp_device, hdmi.cec); -- return cdns_mhdp_bus_read(mhdp, offset); -+ u32 val; -+ -+ mutex_lock(cec->iolock); -+ -+ if (cec->bus_type == BUS_TYPE_LOW4K_HDMI_RX) { -+ /* Remap address to low 4K HDMI RX */ -+ writel(offset >> 12, cec->regs_sec + 4); -+ val = readl((offset & 0xfff) + cec->regs_base); -+ } else if (cec->bus_type == BUS_TYPE_LOW4K_APB) { -+ /* Remap address to low 4K memory */ -+ writel(offset >> 12, cec->regs_sec + 8); -+ val = readl((offset & 0xfff) + cec->regs_base); -+ } else -+ val = readl(cec->regs_base + offset); -+ -+ mutex_unlock(cec->iolock); -+ -+ return val; - } - - static void mhdp_cec_write(struct cdns_mhdp_cec *cec, u32 offset, u32 val) - { -- struct cdns_mhdp_device *mhdp = -- container_of(cec, struct cdns_mhdp_device, hdmi.cec); -- cdns_mhdp_bus_write(val, mhdp, offset); -+ mutex_lock(cec->iolock); -+ -+ if (cec->bus_type == BUS_TYPE_LOW4K_HDMI_RX) { -+ /* Remap address to low 4K SAPB bus */ -+ writel(offset >> 12, cec->regs_sec + 4); -+ writel(val, (offset & 0xfff) + cec->regs_base); -+ } else if (cec->bus_type == BUS_TYPE_LOW4K_APB) { -+ /* Remap address to low 4K memory */ -+ writel(offset >> 12, cec->regs_sec + 8); -+ writel(val, (offset & 0xfff) + cec->regs_base); -+ } else if (cec->bus_type == BUS_TYPE_NORMAL_SAPB) -+ writel(val, cec->regs_sec + offset); -+ else -+ writel(val, cec->regs_base + offset); -+ -+ mutex_unlock(cec->iolock); -+} -+ -+static u32 mhdp_get_fw_clk(struct cdns_mhdp_cec *cec) -+{ -+ return mhdp_cec_read(cec, SW_CLK_H); - } - - static void mhdp_cec_clear_rx_buffer(struct cdns_mhdp_cec *cec) -@@ -94,12 +127,10 @@ static void mhdp_cec_clear_rx_buffer(struct cdns_mhdp_cec *cec) - - static void mhdp_cec_set_divider(struct cdns_mhdp_cec *cec) - { -- struct cdns_mhdp_device *mhdp = -- container_of(cec, struct cdns_mhdp_device, hdmi.cec); - u32 clk_div; - - /* Set clock divider */ -- clk_div = cdns_mhdp_get_fw_clk(mhdp) * 10; -+ clk_div = mhdp_get_fw_clk(cec) * 10; - - mhdp_cec_write(cec, CLK_DIV_MSB, - (clk_div >> 8) & 0xFF); -@@ -291,10 +322,8 @@ static const struct cec_adap_ops cdns_mhdp_cec_adap_ops = { - .adap_transmit = mhdp_cec_adap_transmit, - }; - --int cdns_mhdp_register_cec_driver(struct device *dev) -+int cdns_mhdp_register_cec_driver(struct cdns_mhdp_cec *cec) - { -- struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev); -- struct cdns_mhdp_cec *cec = &mhdp->hdmi.cec; - int ret; - - cec->adap = cec_allocate_adapter(&cdns_mhdp_cec_adap_ops, cec, -@@ -305,29 +334,24 @@ int cdns_mhdp_register_cec_driver(struct device *dev) - ret = PTR_ERR_OR_ZERO(cec->adap); - if (ret) - return ret; -- ret = cec_register_adapter(cec->adap, dev); -+ ret = cec_register_adapter(cec->adap, cec->dev); - if (ret) { - cec_delete_adapter(cec->adap); - return ret; - } - -- cec->dev = dev; -- - cec->cec_worker = kthread_create(mhdp_cec_poll_worker, cec, "cdns-mhdp-cec"); - if (IS_ERR(cec->cec_worker)) - dev_err(cec->dev, "failed create hdp cec thread\n"); - - wake_up_process(cec->cec_worker); - -- dev_dbg(dev, "CEC successfuly probed\n"); -+ dev_dbg(cec->dev, "CEC successfuly probed\n"); - return 0; - } - --int cdns_mhdp_unregister_cec_driver(struct device *dev) -+int cdns_mhdp_unregister_cec_driver(struct cdns_mhdp_cec *cec) - { -- struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev); -- struct cdns_mhdp_cec *cec = &mhdp->hdmi.cec; -- - if (cec->cec_worker) { - kthread_stop(cec->cec_worker); - cec->cec_worker = NULL; -diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c -index 2043016f176b..ff37cc4e57e6 100644 ---- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c -+++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c -@@ -99,12 +99,6 @@ void cdns_mhdp_bus_write(u32 val, struct cdns_mhdp_device *mhdp, u32 offset) - } - EXPORT_SYMBOL(cdns_mhdp_bus_write); - --u32 cdns_mhdp_get_fw_clk(struct cdns_mhdp_device *mhdp) --{ -- return cdns_mhdp_bus_read(mhdp, SW_CLK_H); --} --EXPORT_SYMBOL(cdns_mhdp_get_fw_clk); -- - void cdns_mhdp_set_fw_clk(struct cdns_mhdp_device *mhdp, unsigned long clk) - { - cdns_mhdp_bus_write(clk / 1000000, mhdp, SW_CLK_H); -diff --git a/include/drm/bridge/cdns-mhdp.h b/include/drm/bridge/cdns-mhdp.h -index 6bfd82a3d9a2..338fa55b8bdf 100644 ---- a/include/drm/bridge/cdns-mhdp.h -+++ b/include/drm/bridge/cdns-mhdp.h -@@ -509,6 +509,7 @@ enum { - BUS_TYPE_NORMAL_SAPB = 1, - BUS_TYPE_LOW4K_APB = 2, - BUS_TYPE_LOW4K_SAPB = 3, -+ BUS_TYPE_LOW4K_HDMI_RX = 4, - }; - - enum voltage_swing_level { -@@ -623,12 +624,15 @@ struct cdns_mhdp_connector { - }; - - struct cdns_mhdp_cec { -- struct cec_adapter *adap; -- struct device *dev; -- struct mutex lock; -+ struct cec_adapter *adap; -+ struct device *dev; -+ struct mutex *iolock; -+ void __iomem *regs_base; -+ void __iomem *regs_sec; -+ int bus_type; - -- struct cec_msg msg; -- struct task_struct *cec_worker; -+ struct cec_msg msg; -+ struct task_struct *cec_worker; - }; - - struct cdns_plat_data { -@@ -724,7 +728,6 @@ u32 cdns_mhdp_bus_read(struct cdns_mhdp_device *mhdp, u32 offset); - void cdns_mhdp_bus_write(u32 val, struct cdns_mhdp_device *mhdp, u32 offset); - void cdns_mhdp_clock_reset(struct cdns_mhdp_device *mhdp); - void cdns_mhdp_set_fw_clk(struct cdns_mhdp_device *mhdp, unsigned long clk); --u32 cdns_mhdp_get_fw_clk(struct cdns_mhdp_device *mhdp); - int cdns_mhdp_load_firmware(struct cdns_mhdp_device *mhdp, const u32 *i_mem, - u32 i_size, const u32 *d_mem, u32 d_size); - int cdns_mhdp_set_firmware_active(struct cdns_mhdp_device *mhdp, bool enable); -@@ -805,8 +808,8 @@ int cdns_hdmi_set_plugged_cb(struct cdns_mhdp_device *mhdp, hdmi_codec_plugged_c - - /* CEC */ - #ifdef CONFIG_DRM_CDNS_HDMI_CEC --int cdns_mhdp_register_cec_driver(struct device *dev); --int cdns_mhdp_unregister_cec_driver(struct device *dev); -+int cdns_mhdp_register_cec_driver(struct cdns_mhdp_cec *cec); -+int cdns_mhdp_unregister_cec_driver(struct cdns_mhdp_cec *cec); - #endif - - #endif /* CDNS_MHDP_H_ */ --- -2.29.2 - diff --git a/projects/NXP/devices/iMX8/patches/linux/0018-MLK-25199-3-drm-bridge-mhdp_common-add-apb-config-fu.patch b/projects/NXP/devices/iMX8/patches/linux/0018-MLK-25199-3-drm-bridge-mhdp_common-add-apb-config-fu.patch deleted file mode 100644 index 100881ce2a..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0018-MLK-25199-3-drm-bridge-mhdp_common-add-apb-config-fu.patch +++ /dev/null @@ -1,143 +0,0 @@ -From 0021b4b1afc0d88c013e2484009004b19bc2ece4 Mon Sep 17 00:00:00 2001 -From: Sandor Yu -Date: Wed, 30 Dec 2020 16:04:20 +0800 -Subject: [PATCH 18/49] MLK-25199-3: drm: bridge: mhdp_common: add apb config - function - -Add apb config function, move mhdp poll function -to mhdp head file, they will be used by hdcp driver. - -Signed-off-by: Sandor Yu -Reviewed-by: Robby Cai ---- - .../gpu/drm/bridge/cadence/cdns-mhdp-common.c | 54 ++++++++++--------- - drivers/gpu/drm/bridge/cadence/cdns-mhdp.h | 25 ++++++++- - 2 files changed, 54 insertions(+), 25 deletions(-) - -diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c -index ff37cc4e57e6..2a8ab0872f25 100644 ---- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c -+++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c -@@ -27,31 +27,10 @@ - #include - #include - -+#include "cdns-mhdp.h" -+ - #define CDNS_DP_SPDIF_CLK 200000000 - #define FW_ALIVE_TIMEOUT_US 1000000 --#define MAILBOX_RETRY_US 1000 --#define MAILBOX_TIMEOUT_US 5000000 -- --#define mhdp_readx_poll_timeout(op, addr, offset, val, cond, sleep_us, timeout_us) \ --({ \ -- u64 __timeout_us = (timeout_us); \ -- unsigned long __sleep_us = (sleep_us); \ -- ktime_t __timeout = ktime_add_us(ktime_get(), __timeout_us); \ -- might_sleep_if((__sleep_us) != 0); \ -- for (;;) { \ -- (val) = op(addr, offset); \ -- if (cond) \ -- break; \ -- if (__timeout_us && \ -- ktime_compare(ktime_get(), __timeout) > 0) { \ -- (val) = op(addr, offset); \ -- break; \ -- } \ -- if (__sleep_us) \ -- usleep_range((__sleep_us >> 2) + 1, __sleep_us); \ -- } \ -- (cond) ? 0 : -ETIMEDOUT; \ --}) - - u32 cdns_mhdp_bus_read(struct cdns_mhdp_device *mhdp, u32 offset) - { -@@ -174,7 +153,7 @@ bool cdns_mhdp_check_alive(struct cdns_mhdp_device *mhdp) - } - EXPORT_SYMBOL(cdns_mhdp_check_alive); - --static int mhdp_mailbox_read(struct cdns_mhdp_device *mhdp) -+int mhdp_mailbox_read(struct cdns_mhdp_device *mhdp) - { - int val, ret; - -@@ -432,6 +411,33 @@ int cdns_mhdp_set_firmware_active(struct cdns_mhdp_device *mhdp, bool enable) - } - EXPORT_SYMBOL(cdns_mhdp_set_firmware_active); - -+int cdns_mhdp_apb_conf(struct cdns_mhdp_device *mhdp, u8 sel) -+{ -+ u8 status; -+ int ret; -+ -+ ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_GENERAL, GENERAL_BUS_SETTINGS, -+ sizeof(sel), &sel); -+ if (ret) -+ goto err_apb_conf; -+ -+ ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_GENERAL, -+ GENERAL_BUS_SETTINGS, sizeof(status)); -+ if (ret) -+ goto err_apb_conf; -+ -+ ret = cdns_mhdp_mailbox_read_receive(mhdp, &status, sizeof(status)); -+ if (ret) -+ goto err_apb_conf; -+ -+ return status; -+ -+err_apb_conf: -+ DRM_ERROR("apb conf failed: %d\n", ret); -+ return ret; -+} -+EXPORT_SYMBOL(cdns_mhdp_apb_conf); -+ - int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp) - { - u8 msg[8]; -diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp.h b/drivers/gpu/drm/bridge/cadence/cdns-mhdp.h -index 399c3f6f86ad..8ad99eb8f86e 100644 ---- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp.h -+++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp.h -@@ -174,7 +174,6 @@ - #define CDNS_DP_MTPH_STATUS 0x226C - #define CDNS_DP_MTPH_ACT_STATUS BIT(0) - -- - #define CDNS_DPTX_GLOBAL 0x02300 - #define CDNS_DP_LANE_EN (CDNS_DPTX_GLOBAL + 0x00) - #define CDNS_DP_LANE_EN_LANES(x) GENMASK(x - 1, 0) -@@ -187,6 +186,30 @@ - - #define CDNS_MHDP_MAX_STREAMS 4 - -+#define MAILBOX_RETRY_US 1000 -+#define MAILBOX_TIMEOUT_US 5000000 -+ -+#define mhdp_readx_poll_timeout(op, addr, offset, val, cond, sleep_us, timeout_us) \ -+({ \ -+ u64 __timeout_us = (timeout_us); \ -+ unsigned long __sleep_us = (sleep_us); \ -+ ktime_t __timeout = ktime_add_us(ktime_get(), __timeout_us); \ -+ might_sleep_if((__sleep_us) != 0); \ -+ for (;;) { \ -+ (val) = op(addr, offset); \ -+ if (cond) \ -+ break; \ -+ if (__timeout_us && \ -+ ktime_compare(ktime_get(), __timeout) > 0) { \ -+ (val) = op(addr, offset); \ -+ break; \ -+ } \ -+ if (__sleep_us) \ -+ usleep_range((__sleep_us >> 2) + 1, __sleep_us); \ -+ } \ -+ (cond) ? 0 : -ETIMEDOUT; \ -+}) -+ - enum pixel_format { - PIXEL_FORMAT_RGB = 1, - PIXEL_FORMAT_YCBCR_444 = 2, --- -2.29.2 - diff --git a/projects/NXP/devices/iMX8/patches/linux/0019-MLK-25199-4-drm-bridge-mhdp_hdmi-set-clear-avmute-bi.patch b/projects/NXP/devices/iMX8/patches/linux/0019-MLK-25199-4-drm-bridge-mhdp_hdmi-set-clear-avmute-bi.patch deleted file mode 100644 index 4da60d1acc..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0019-MLK-25199-4-drm-bridge-mhdp_hdmi-set-clear-avmute-bi.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 1793e95601a15f93e5d9e2846281f86eb19e8fe4 Mon Sep 17 00:00:00 2001 -From: Sandor Yu -Date: Wed, 30 Dec 2020 16:05:29 +0800 -Subject: [PATCH 19/49] MLK-25199-4: drm: bridge: mhdp_hdmi: set clear avmute - bit - -Sync HDMI TX configuation with 4.14 hdmi driver. -Clear avmute bit must be set otherwise imx8qm hdcp not work. - -Signed-off-by: Sandor Yu -Reviewed-by: Robby Cai ---- - drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdmi.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdmi.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdmi.c -index c37a7ac6af9b..3ff43f7fb0a6 100644 ---- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdmi.c -+++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdmi.c -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2019 NXP Semiconductor, Inc. -+ * Copyright (C) 2019-2021 NXP Semiconductor, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -205,7 +205,7 @@ int cdns_hdmi_ctrl_init(struct cdns_mhdp_device *mhdp, - - /* set hdmi mode and preemble mode data enable */ - val = F_HDMI_MODE(protocol) | F_HDMI2_PREAMBLE_EN(1) | F_DATA_EN(1) | -- F_HDMI2_CTRL_IL_MODE(1) | F_BCH_EN(1) | F_PIC_3D(0XF); -+ F_HDMI2_CTRL_IL_MODE(1) | F_BCH_EN(1) | F_PIC_3D(0XF) | F_CLEAR_AVMUTE(1); - ret = cdns_mhdp_reg_write(mhdp, HDTX_CONTROLLER, val); - - return ret; --- -2.29.2 - diff --git a/projects/NXP/devices/iMX8/patches/linux/0020-MLK-25199-5-drm-bridge-mhdp_hdcp-add-HDMI-TX-HDCP-dr.patch b/projects/NXP/devices/iMX8/patches/linux/0020-MLK-25199-5-drm-bridge-mhdp_hdcp-add-HDMI-TX-HDCP-dr.patch deleted file mode 100644 index 47c75be296..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0020-MLK-25199-5-drm-bridge-mhdp_hdcp-add-HDMI-TX-HDCP-dr.patch +++ /dev/null @@ -1,2007 +0,0 @@ -From 9d940175bbffc82b5ec70b195312c6f32b35f51f Mon Sep 17 00:00:00 2001 -From: Sandor Yu -Date: Wed, 30 Dec 2020 16:07:41 +0800 -Subject: [PATCH 20/49] MLK-25199-5: drm: bridge: mhdp_hdcp: add HDMI TX HDCP - driver - -This patch adds an initial HDMI TX HDCP driver -for Cadence MHDP HDMI TX hardware. - -Both HDCP2.2 and HDCP1.4 are supported. - -HDCP function could be enabled by command: -modetest -w CONNECTOR_ID:"Content Protection":1 - -Signed-off-by: Sandor Yu -Reviewed-by: Robby Cai ---- - drivers/gpu/drm/bridge/cadence/Kconfig | 4 + - drivers/gpu/drm/bridge/cadence/Makefile | 1 + - .../gpu/drm/bridge/cadence/cdns-hdmi-core.c | 190 ++- - .../gpu/drm/bridge/cadence/cdns-hdmi-hdcp.c | 1167 +++++++++++++++++ - .../gpu/drm/bridge/cadence/cdns-mhdp-hdcp.c | 300 +++++ - .../gpu/drm/bridge/cadence/cdns-mhdp-hdcp.h | 36 + - include/drm/bridge/cdns-mhdp.h | 92 +- - 7 files changed, 1776 insertions(+), 14 deletions(-) - create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-hdmi-hdcp.c - create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdcp.c - create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdcp.h - -diff --git a/drivers/gpu/drm/bridge/cadence/Kconfig b/drivers/gpu/drm/bridge/cadence/Kconfig -index c271ab24a99a..4c27836eb367 100644 ---- a/drivers/gpu/drm/bridge/cadence/Kconfig -+++ b/drivers/gpu/drm/bridge/cadence/Kconfig -@@ -43,6 +43,11 @@ config DRM_CDNS_AUDIO - tristate "Cadence MHDP Audio driver" - depends on DRM_CDNS_MHDP - -+config DRM_CDNS_HDMI_HDCP -+ tristate "Cadence MHDP HDMI HDCP driver" -+ depends on DRM_CDNS_HDMI -+ select DRM_DISPLAY_HDCP_HELPER -+ - config DRM_CDNS_HDMI_CEC - tristate "Cadence MHDP HDMI CEC driver" - select CEC_CORE -diff --git a/drivers/gpu/drm/bridge/cadence/Makefile b/drivers/gpu/drm/bridge/cadence/Makefile -index 618290870ba5..1b824252ae76 100644 ---- a/drivers/gpu/drm/bridge/cadence/Makefile -+++ b/drivers/gpu/drm/bridge/cadence/Makefile -@@ -8,6 +8,7 @@ cdns_mhdp_drmcore-y := cdns-mhdp-common.o cdns-mhdp-dp.o cdns-mhdp-hdmi.o - cdns_mhdp_drmcore-$(CONFIG_DRM_CDNS_HDMI) += cdns-hdmi-core.o - cdns_mhdp_drmcore-$(CONFIG_DRM_CDNS_DP) += cdns-dp-core.o - cdns_mhdp_drmcore-$(CONFIG_DRM_CDNS_AUDIO) += cdns-mhdp-audio.o -+cdns_mhdp_drmcore-$(CONFIG_DRM_CDNS_HDMI_HDCP) += cdns-mhdp-hdcp.o cdns-hdmi-hdcp.o - cdns_mhdp_drmcore-$(CONFIG_DRM_CDNS_HDMI_CEC) += cdns-mhdp-cec.o - - obj-$(CONFIG_DRM_CDNS_MHDP) += cdns_mhdp_drmcore.o -diff --git a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c -index 84c175997740..dc393f6b75e7 100644 ---- a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c -+++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c -@@ -1,7 +1,7 @@ - /* - * Cadence High-Definition Multimedia Interface (HDMI) driver - * -- * Copyright (C) 2019-2020 NXP Semiconductor, Inc. -+ * Copyright (C) 2019-2021 NXP Semiconductor, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -13,6 +13,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -27,6 +28,131 @@ - #include - #include - -+#include "cdns-mhdp-hdcp.h" -+ -+static ssize_t HDCPTX_do_reauth_store(struct device *dev, -+ struct device_attribute *attr, const char *buf, size_t count); -+static struct device_attribute HDCPTX_do_reauth = __ATTR_WO(HDCPTX_do_reauth); -+ -+static ssize_t HDCPTX_do_reauth_store(struct device *dev, -+ struct device_attribute *attr, const char *buf, size_t count) -+{ -+ int value, ret; -+ struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev); -+ -+ ret = cdns_mhdp_hdcp_tx_reauth(mhdp, 1); -+ -+ sscanf(buf, "%d", &value); -+ -+ if (ret < 0) { -+ dev_err(dev, "%s cdns_mhdp_hdcp_tx_reauth failed\n", __func__); -+ return -1; -+ } -+ return count; -+} -+ -+static ssize_t HDCPTX_Version_show(struct device *dev, -+ struct device_attribute *attr, char *buf); -+static ssize_t HDCPTX_Version_store(struct device *dev, -+ struct device_attribute *attr, const char *buf, size_t count); -+static struct device_attribute HDCPTX_Version = __ATTR_RW(HDCPTX_Version); -+ -+static ssize_t HDCPTX_Version_store(struct device *dev, -+ struct device_attribute *attr, const char *buf, size_t count) -+{ -+ struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev); -+ int value; -+ -+ sscanf(buf, "%d", &value); -+ if (value == 2) -+ mhdp->hdcp.config = 2; -+ else if (value == 1) -+ mhdp->hdcp.config = 1; -+ else if (value == 3) -+ mhdp->hdcp.config = 3; -+ else -+ mhdp->hdcp.config = 0; -+ -+ return count; -+} -+ -+ssize_t HDCPTX_Version_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev); -+ return sprintf(buf, "%d\n", mhdp->hdcp.config); -+} -+ -+static ssize_t HDCPTX_Status_show(struct device *dev, -+ struct device_attribute *attr, char *buf); -+static ssize_t HDCPTX_Status_store(struct device *dev, -+ struct device_attribute *attr, const char *buf, size_t count); -+static struct device_attribute HDCPTX_Status = __ATTR_RW(HDCPTX_Status); -+ -+ssize_t HDCPTX_Status_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev); -+ -+ switch (mhdp->hdcp.state) { -+ case HDCP_STATE_NO_AKSV: -+ return sprintf(buf, "%d :HDCP_STATE_NO_AKSV \n", mhdp->hdcp.state); -+ case HDCP_STATE_INACTIVE: -+ return sprintf(buf, "%d :HDCP_STATE_INACTIVE \n", mhdp->hdcp.state); -+ case HDCP_STATE_ENABLING: -+ return sprintf(buf, "%d :HDCP_STATE_ENABLING \n", mhdp->hdcp.state); -+ case HDCP_STATE_AUTHENTICATING: -+ return sprintf(buf, "%d :HDCP_STATE_AUTHENTICATING \n", mhdp->hdcp.state); -+ case HDCP_STATE_AUTHENTICATED: -+ return sprintf(buf, "%d :HDCP_STATE_AUTHENTICATED \n", mhdp->hdcp.state); -+ case HDCP_STATE_DISABLING: -+ return sprintf(buf, "%d :HDCP_STATE_DISABLING \n", mhdp->hdcp.state); -+ case HDCP_STATE_AUTH_FAILED: -+ return sprintf(buf, "%d :HDCP_STATE_AUTH_FAILED \n", mhdp->hdcp.state); -+ default: -+ return sprintf(buf, "%d :HDCP_STATE don't exist \n", mhdp->hdcp.state); -+ } -+} -+ -+ssize_t HDCPTX_Status_store(struct device *dev, -+ struct device_attribute *attr, const char *buf, size_t count) -+{ -+ struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev); -+ int value; -+ -+ if (count == 2) { -+ sscanf(buf, "%d", &value); -+ if ((value >= HDCP_STATE_NO_AKSV) && (value <= HDCP_STATE_AUTH_FAILED)) { -+ mhdp->hdcp.state = value; -+ return count; -+ } else { -+ dev_err(dev, "%s &hdp->state invalid\n", __func__); -+ return -1; -+ } -+ } -+ -+ dev_info(dev, "%s &hdp->state desired %s count=%d\n ", __func__, buf, (int)count); -+ -+ if (strncmp(buf, "HDCP_STATE_NO_AKSV", count - 1) == 0) -+ mhdp->hdcp.state = HDCP_STATE_NO_AKSV; -+ else if (strncmp(buf, "HDCP_STATE_INACTIVE", count - 1) == 0) -+ mhdp->hdcp.state = HDCP_STATE_INACTIVE; -+ else if (strncmp(buf, "HDCP_STATE_ENABLING", count - 1) == 0) -+ mhdp->hdcp.state = HDCP_STATE_ENABLING; -+ else if (strncmp(buf, "HDCP_STATE_AUTHENTICATING", count - 1) == 0) -+ mhdp->hdcp.state = HDCP_STATE_AUTHENTICATING; -+ else if (strncmp(buf, "HDCP_STATE_AUTHENTICATED", count - 1) == 0) -+ mhdp->hdcp.state = HDCP_STATE_AUTHENTICATED; -+ else if (strncmp(buf, "HDCP_STATE_DISABLING", count - 1) == 0) -+ mhdp->hdcp.state = HDCP_STATE_DISABLING; -+ else if (strncmp(buf, "HDCP_STATE_AUTH_FAILED", count - 1) == 0) -+ mhdp->hdcp.state = HDCP_STATE_AUTH_FAILED; -+ else -+ dev_err(dev, "%s &hdp->state invalid\n", __func__); -+ return -1; -+ return count; -+} -+ - static void hdmi_sink_config(struct cdns_mhdp_device *mhdp) - { - struct drm_scdc *scdc = &mhdp->connector.base.display_info.hdmi.scdc; -@@ -319,6 +445,22 @@ static bool blob_equal(const struct drm_property_blob *a, - return !a == !b; - } - -+static void cdns_hdmi_bridge_disable(struct drm_bridge *bridge) -+{ -+ struct cdns_mhdp_device *mhdp = bridge->driver_private; -+ -+ cdns_hdmi_hdcp_disable(mhdp); -+} -+ -+static void cdns_hdmi_bridge_enable(struct drm_bridge *bridge) -+{ -+ struct cdns_mhdp_device *mhdp = bridge->driver_private; -+ struct drm_connector_state *conn_state = mhdp->connector.base.state; -+ -+ if (conn_state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED) -+ cdns_hdmi_hdcp_enable(mhdp); -+} -+ - static int cdns_hdmi_connector_atomic_check(struct drm_connector *connector, - struct drm_atomic_state *state) - { -@@ -329,12 +471,17 @@ static int cdns_hdmi_connector_atomic_check(struct drm_connector *connector, - struct drm_crtc *crtc = new_con_state->crtc; - struct drm_crtc_state *new_crtc_state; - -+ cdns_hdmi_hdcp_atomic_check(connector, old_con_state, new_con_state); -+ if (!new_con_state->crtc) -+ return 0; -+ -+ new_crtc_state = drm_atomic_get_crtc_state(state, crtc); -+ if (IS_ERR(new_crtc_state)) -+ return PTR_ERR(new_crtc_state); -+ - if (!blob_equal(new_con_state->hdr_output_metadata, - old_con_state->hdr_output_metadata) || - new_con_state->colorspace != old_con_state->colorspace) { -- new_crtc_state = drm_atomic_get_crtc_state(state, crtc); -- if (IS_ERR(new_crtc_state)) -- return PTR_ERR(new_crtc_state); - - new_crtc_state->mode_changed = - !new_con_state->hdr_output_metadata || -@@ -342,6 +489,15 @@ static int cdns_hdmi_connector_atomic_check(struct drm_connector *connector, - new_con_state->colorspace != old_con_state->colorspace; - } - -+ /* -+ * These properties are handled by fastset, and might not end up in a -+ * modeset. -+ */ -+ if (new_con_state->picture_aspect_ratio != -+ old_con_state->picture_aspect_ratio || -+ new_con_state->content_type != old_con_state->content_type || -+ new_con_state->scaling_mode != old_con_state->scaling_mode) -+ new_crtc_state->mode_changed = true; - return 0; - } - -@@ -388,6 +544,7 @@ static int cdns_hdmi_bridge_attach(struct drm_bridge *bridge, - - drm_connector_attach_encoder(connector, encoder); - -+ drm_connector_attach_content_protection_property(connector, true); - return 0; - } - -@@ -439,7 +596,7 @@ static void cdns_hdmi_bridge_mode_set(struct drm_bridge *bridge, - video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC); - video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC); - -- DRM_INFO("Mode: %dx%dp%d\n", mode->hdisplay, mode->vdisplay, mode->clock); -+ DRM_INFO("Mode: %dx%dp%d\n", mode->hdisplay, mode->vdisplay, mode->clock); - memcpy(&mhdp->mode, mode, sizeof(struct drm_display_mode)); - - mutex_lock(&mhdp->lock); -@@ -518,6 +675,8 @@ bool cdns_hdmi_bridge_mode_fixup(struct drm_bridge *bridge, - - static const struct drm_bridge_funcs cdns_hdmi_bridge_funcs = { - .attach = cdns_hdmi_bridge_attach, -+ .enable = cdns_hdmi_bridge_enable, -+ .disable = cdns_hdmi_bridge_disable, - .mode_set = cdns_hdmi_bridge_mode_set, - .mode_valid = cdns_hdmi_bridge_mode_valid, - .mode_fixup = cdns_hdmi_bridge_mode_fixup, -@@ -645,7 +804,7 @@ static int __cdns_hdmi_probe(struct platform_device *pdev, - mhdp->irq[IRQ_IN]); - return -EINVAL; - } -- -+ - irq_set_status_flags(mhdp->irq[IRQ_OUT], IRQ_NOAUTOEN); - ret = devm_request_threaded_irq(dev, mhdp->irq[IRQ_OUT], - NULL, cdns_hdmi_irq_thread, -@@ -659,6 +818,25 @@ static int __cdns_hdmi_probe(struct platform_device *pdev, - - cdns_hdmi_parse_dt(mhdp); - -+ ret = cdns_hdmi_hdcp_init(mhdp, pdev->dev.of_node); -+ if (ret < 0) -+ DRM_WARN("Failed to initialize HDCP\n"); -+ -+ if (device_create_file(mhdp->dev, &HDCPTX_do_reauth)) { -+ printk(KERN_ERR "Unable to create HDCPTX_do_reauth sysfs\n"); -+ device_remove_file(mhdp->dev, &HDCPTX_do_reauth); -+ } -+ -+ if (device_create_file(mhdp->dev, &HDCPTX_Version)) { -+ printk(KERN_ERR "Unable to create HDCPTX_Version sysfs\n"); -+ device_remove_file(mhdp->dev, &HDCPTX_Version); -+ } -+ -+ if (device_create_file(mhdp->dev, &HDCPTX_Status)) { -+ printk(KERN_ERR "Unable to create HDCPTX_Status sysfs\n"); -+ device_remove_file(mhdp->dev, &HDCPTX_Status); -+ } -+ - if (cdns_mhdp_read_hpd(mhdp)) - enable_irq(mhdp->irq[IRQ_OUT]); - else -diff --git a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-hdcp.c b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-hdcp.c -new file mode 100644 -index 000000000000..e2a3bc7fb42b ---- /dev/null -+++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-hdcp.c -@@ -0,0 +1,1167 @@ -+/* -+ * Cadence HDMI HDCP driver -+ * -+ * Copyright (C) 2021 NXP Semiconductor, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ */ -+#include -+#include -+#include -+#include -+ -+#include "cdns-mhdp-hdcp.h" -+ -+/* Default will be to use KM unless it has been explicitly */ -+#ifndef HDCP_USE_KMKEY -+ #define HDCP_USE_KMKEY 1 -+#endif -+ -+#define CDNS_HDCP_ACTIVATE (0x1 << 2) -+ -+#define IMX_FW_TIMEOUT_MS (64 * 1000) -+#define IMX_HDCP_PAIRING_FIRMWARE "imx/hdcp-pairing.bin" -+ -+#define GENERAL_BUS_SETTINGS_DPCD_BUS_BIT 0 -+#define GENERAL_BUS_SETTINGS_DPCD_BUS_LOCK_BIT 1 -+#define GENERAL_BUS_SETTINGS_HDCP_BUS_BIT 2 -+#define GENERAL_BUS_SETTINGS_HDCP_BUS_LOCK_BIT 3 -+#define GENERAL_BUS_SETTINGS_CAPB_OWNER_BIT 4 -+#define GENERAL_BUS_SETTINGS_CAPB_OWNER_LOCK_BIT 5 -+ -+#define GENERAL_BUS_SETTINGS_RESP_DPCD_BUS_BIT 0 -+#define GENERAL_BUS_SETTINGS_RESP_HDCP_BUS_BIT 1 -+#define GENERAL_BUS_SETTINGS_RESP_CAPB_OWNER_BIT 2 -+ -+/* HDCP TX ports working mode (HDCP 2.2 or 1.4) */ -+enum { -+ HDCP_TX_2, /* lock only with HDCP2 */ -+ HDCP_TX_1, /* lock only with HDCP1 */ -+ HDCP_TX_BOTH, /* lock on HDCP2 or 1 depend on other side */ -+}; -+ -+/* HDCP TX ports stream type (relevant if receiver is repeater) */ -+enum { -+ HDCP_CONTENT_TYPE_0, /* May be transmitted by -+ The HDCP Repeater to all HDCP Devices. */ -+ HDCP_CONTENT_TYPE_1, /* Must not be transmitted by the HDCP Repeater to -+ HDCP 1.x-compliant Devices and HDCP 2.0-compliant Repeaters */ -+}; -+ -+/* different error types for HDCP_TX_STATUS_CHANGE */ -+enum { -+ HDCP_TRAN_ERR_NO_ERROR, -+ HDCP_TRAN_ERR_HPD_IS_DOWN, -+ HDCP_TRAN_ERR_SRM_FAILURE, -+ HDCP_TRAN_ERR_SIGNATURE_VERIFICATION, -+ HDCP_TRAN_ERR_H_TAG_DIFF_H, -+ HDCP_TRAN_ERR_V_TAG_DIFF_V, -+ HDCP_TRAN_ERR_LOCALITY_CHECK, -+ HDCP_TRAN_ERR_DDC, -+ HDCP_TRAN_ERR_REAUTH_REQ, -+ HDCP_TRAN_ERR_TOPOLOGY, -+ HDCP_TRAN_ERR_HDCP_RSVD1, -+ HDCP_TRAN_ERR_HDMI_CAPABILITY, -+ HDCP_TRAN_ERR_RI, -+ HDCP_TRAN_ERR_WATCHDOG_EXPIRED, -+}; -+ -+static char const *g_last_error[16] = { -+ "No Error", -+ "HPD is down", -+ "SRM failure", -+ "Signature verification error", -+ "h tag != h", -+ "V tag diff v", -+ "Locality check", -+ "DDC error", -+ "REAUTH_REQ", -+ "Topology error", -+ "Verify receiver ID list failed", -+ "HDCP_RSVD1 was not 0,0,0", -+ "HDMI capability or mode", -+ "RI result was different than expected", -+ "WatchDog expired", -+ "Repeater integrity failed" -+}; -+ -+#define HDCP_MAX_RECEIVERS 32 -+#define HDCP_RECEIVER_ID_SIZE_BYTES 5 -+#define HPD_EVENT 1 -+#define HDCP_STATUS_SIZE 0x5 -+#define HDCP_PORT_STS_AUTH 0x1 -+#define HDCP_PORT_STS_REPEATER 0x2 -+#define HDCP_PORT_STS_TYPE_MASK 0xc -+#define HDCP_PORT_STS_TYPE_SHIFT 0x2 -+#define HDCP_PORT_STS_AUTH_STREAM_ID_SHIFT 0x4 -+#define HDCP_PORT_STS_AUTH_STREAM_ID_MASK 0x10 -+#define HDCP_PORT_STS_LAST_ERR_SHIFT 0x5 -+#define HDCP_PORT_STS_LAST_ERR_MASK (0x0F << 5) -+#define GET_HDCP_PORT_STS_LAST_ERR(__sts__) \ -+ (((__sts__) & HDCP_PORT_STS_LAST_ERR_MASK) >> \ -+ HDCP_PORT_STS_LAST_ERR_SHIFT) -+#define HDCP_PORT_STS_1_1_FEATURES 0x200 -+ -+#define HDCP_CONFIG_NONE ((u8) 0) -+#define HDCP_CONFIG_1_4 ((u8) 1) /* use HDCP 1.4 only */ -+#define HDCP_CONFIG_2_2 ((u8) 2) /* use HDCP 2.2 only */ -+ -+/* Default timeout to use for wait4event in milliseconds */ -+#define HDCP_EVENT_TO_DEF 800 -+/* Timeout value to use for repeater receiver ID check, spec says 3s */ -+#define HDCP_EVENT_TO_RPT 3500 -+ -+static int hdmi_hdcp_check_link(struct cdns_mhdp_device *mhdp); -+ -+static void print_port_status(u16 sts) -+{ -+ char const *rx_type[4] = { "Unknown", "HDCP 1", "HDCP 2", "Unknown" }; -+ -+ DRM_DEBUG_KMS("INFO: HDCP Port Status: 0x%04x\n", sts); -+ DRM_DEBUG_KMS(" Authenticated: %d\n", sts & HDCP_PORT_STS_AUTH); -+ DRM_DEBUG_KMS(" Receiver is repeater: %d\n", sts & HDCP_PORT_STS_REPEATER); -+ DRM_DEBUG_KMS(" RX Type: %s\n", -+ rx_type[(sts & HDCP_PORT_STS_TYPE_MASK) >> HDCP_PORT_STS_TYPE_SHIFT]); -+ DRM_DEBUG_KMS(" AuthStreamId: %d\n", sts & HDCP_PORT_STS_AUTH_STREAM_ID_MASK); -+ DRM_DEBUG_KMS(" Last Error: %s\n", -+ g_last_error[(sts & HDCP_PORT_STS_LAST_ERR_MASK) >> HDCP_PORT_STS_LAST_ERR_SHIFT]); -+ DRM_DEBUG_KMS(" Enable 1.1 Features: %d\n", sts & HDCP_PORT_STS_1_1_FEATURES); -+} -+ -+static void print_events(u8 events) -+{ -+ if (events & HDMI_TX_HPD_EVENT) -+ DRM_INFO("INFO: HDMI_TX_HPD_EVENT\n"); -+ if (events & HDCPTX_STATUS_EVENT) -+ DRM_INFO("INFO: HDCPTX_STATUS_EVENT\n"); -+ if (events & HDCPTX_IS_KM_STORED_EVENT) -+ DRM_INFO("INFO: HDCPTX_IS_KM_STORED_EVENT\n"); -+ if (events & HDCPTX_STORE_KM_EVENT) -+ DRM_INFO("INFO: HDCPTX_STORE_KM_EVENT\n"); -+ if (events & HDCPTX_IS_RECEIVER_ID_VALID_EVENT) -+ DRM_INFO("INFO: HDCPTX_IS_RECEIVER_ID_VALID_EVENT\n"); -+} -+ -+static u8 wait4event(struct cdns_mhdp_device *mhdp, u8 *events, -+ u32 event_to_wait, u32 timeout_ms) -+{ -+ u8 reg_events; -+ u8 returned_events; -+ u8 event_mask = event_to_wait | HDCPTX_STATUS_EVENT; -+ unsigned timeout; -+ -+ timeout = timeout_ms; -+ do { -+ if (timeout == 0) -+ goto timeout_err; -+ timeout--; -+ udelay(1000); -+ reg_events = cdns_mhdp_get_event(mhdp); -+ *events |= reg_events; -+ } while (((event_mask & *events) == 0) && (event_to_wait > HDMI_TX_HPD_EVENT)); -+ -+ returned_events = *events & event_mask; -+ if (*events != returned_events) { -+ u32 unexpected_events = ~event_mask & *events; -+ -+ DRM_INFO("INFO: %s() all 0x%08x expected 0x%08x unexpected 0x%08x", -+ __func__, *events, returned_events, unexpected_events); -+ DRM_INFO("INFO: %s() All events:\n", __func__); -+ print_events(*events); -+ -+ DRM_INFO("INFO: %s() expected events:\n", __func__); -+ print_events(returned_events); -+ -+ DRM_INFO("INFO: %s() unexpected events:\n", __func__); -+ print_events(unexpected_events); -+ } else -+ print_events(*events); -+ -+ *events &= ~event_mask; -+ -+ return returned_events; -+ -+timeout_err: -+ DRM_INFO("INFO: %s() Timed out with events:\n", __func__); -+ print_events(event_to_wait); -+ return 0; -+} -+ -+static u16 hdmi_hdcp_get_status(struct cdns_mhdp_device *mhdp) -+{ -+ u8 hdcp_status[HDCP_STATUS_SIZE]; -+ u16 hdcp_port_status; -+ -+ cdns_mhdp_hdcp_tx_status_req(mhdp, hdcp_status, HDCP_STATUS_SIZE); -+ hdcp_port_status = (hdcp_status[0] << 8) | hdcp_status[1]; -+ -+ return hdcp_port_status; -+} -+ -+static inline u8 check_event(u8 events, u8 tested) -+{ -+ if ((events & tested) == 0) -+ return 0; -+ return 1; -+} -+ -+/* Prints status. Returns error code (0 = no error) */ -+static u8 hdmi_hdcp_handle_status(u16 status) -+{ -+ print_port_status(status); -+ if (status & HDCP_PORT_STS_LAST_ERR_MASK) -+ DRM_ERROR("ERROR: HDCP error was set to %s\n", -+ g_last_error[((status & HDCP_PORT_STS_LAST_ERR_MASK) -+ >> HDCP_PORT_STS_LAST_ERR_SHIFT)]); -+ return GET_HDCP_PORT_STS_LAST_ERR(status); -+} -+ -+static int hdmi_hdcp_set_config(struct cdns_mhdp_device *mhdp, u8 hdcp_config) -+{ -+ u8 bus_config, retEvents; -+ u16 hdcp_port_status; -+ int ret; -+ -+ /* Clearing out existing events */ -+ wait4event(mhdp, &mhdp->hdcp.events, HDMI_TX_HPD_EVENT, HDCP_EVENT_TO_DEF); -+ mhdp->hdcp.events = 0; -+ -+ if (!strncmp("imx8mq-hdmi", mhdp->plat_data->plat_name, 11)) { -+ DRM_DEBUG_KMS("INFO: Switching HDCP Commands to SAPB.\n"); -+ bus_config = (1 << GENERAL_BUS_SETTINGS_HDCP_BUS_BIT); -+ ret = cdns_mhdp_apb_conf(mhdp, bus_config); -+ if (ret) { -+ DRM_ERROR("Failed to set APB configuration.\n"); -+ if (ret & (1 << GENERAL_BUS_SETTINGS_RESP_HDCP_BUS_BIT))/* 1 - locked */ -+ DRM_ERROR("Failed to switch HDCP to SAPB Mailbox\n"); -+ return -1; -+ } -+ DRM_DEBUG_KMS("INFO: HDCP switched to SAPB\n"); -+ } -+ -+ /* HDCP 2.2(and/or 1.4) | activate | km-key | 0 */ -+ hdcp_config |= CDNS_HDCP_ACTIVATE | (HDCP_USE_KMKEY << 4) | (HDCP_CONTENT_TYPE_0 << 3); -+ -+ DRM_DEBUG_KMS("INFO: Enabling HDCP...\n"); -+ ret = cdns_mhdp_hdcp_tx_config(mhdp, hdcp_config); -+ if (ret < 0) -+ DRM_DEBUG_KMS("cdns_mhdp_hdcp_tx_config failed\n"); -+ -+ /* Wait until HDCP_TX_STATUS EVENT appears */ -+ DRM_DEBUG_KMS("INFO: wait4event -> HDCPTX_STATUS_EVENT\n"); -+ retEvents = wait4event(mhdp, &mhdp->hdcp.events, HDCPTX_STATUS_EVENT, HDCP_EVENT_TO_DEF); -+ -+ /* Set TX STATUS REQUEST */ -+ DRM_DEBUG_KMS("INFO: Getting port status\n"); -+ hdcp_port_status = hdmi_hdcp_get_status(mhdp); -+ if (hdmi_hdcp_handle_status(hdcp_port_status) != 0) -+ return -1; -+ -+ return 0; -+} -+ -+static int hdmi_hdcp_auth_check(struct cdns_mhdp_device *mhdp) -+{ -+ u16 hdcp_port_status; -+ int ret; -+ -+ DRM_DEBUG_KMS("INFO: wait4event -> HDCPTX_STATUS_EVENT\n"); -+ mhdp->hdcp.events = wait4event(mhdp, &mhdp->hdcp.events, HDCPTX_STATUS_EVENT, HDCP_EVENT_TO_DEF+HDCP_EVENT_TO_DEF); -+ if (mhdp->hdcp.events == 0) -+ return -1; -+ -+ DRM_DEBUG_KMS("HDCP: HDCPTX_STATUS_EVENT\n"); -+ hdcp_port_status = hdmi_hdcp_get_status(mhdp); -+ ret = hdmi_hdcp_handle_status(hdcp_port_status); -+ if (ret != 0) { -+ if (ret == HDCP_TRAN_ERR_REAUTH_REQ) { -+ DRM_ERROR("HDCP_TRAN_ERR_REAUTH_REQ-->one more try!\n"); -+ return 1; -+ } else -+ return -1; -+ } -+ -+ if (hdcp_port_status & HDCP_PORT_STS_AUTH) { -+ DRM_INFO("Authentication completed successfully!\n"); -+ /* Dump hdmi and phy register */ -+ mhdp->hdcp.state = HDCP_STATE_AUTHENTICATED; -+ return 0; -+ } -+ -+ DRM_WARN("Authentication failed\n"); -+ mhdp->hdcp.state = HDCP_STATE_AUTH_FAILED; -+ return -1; -+} -+ -+inline void hdmi_hdcp_swap_id(u8 *in, u8 *out) -+{ -+ int i; -+ -+ for (i = 0; i < HDCP_RECEIVER_ID_SIZE_BYTES; i++) -+ out[HDCP_RECEIVER_ID_SIZE_BYTES - (i + 1)] = in[i]; -+} -+ -+inline void hdmi_hdcp_swap_list(u8 *list_in, u8 *list_out, int num_ids) -+{ -+ int i; -+ -+ for (i = 0; i < num_ids; i++) -+ hdmi_hdcp_swap_id(&list_in[i * HDCP_RECEIVER_ID_SIZE_BYTES], -+ &list_out[i * HDCP_RECEIVER_ID_SIZE_BYTES]); -+} -+ -+static int hdmi_hdcp_check_receviers(struct cdns_mhdp_device *mhdp) -+{ -+ u8 ret_events; -+ u8 hdcp_num_rec, i; -+ u8 hdcp_rec_id[HDCP_MAX_RECEIVERS][HDCP_RECEIVER_ID_SIZE_BYTES]; -+ u8 hdcp_rec_id_temp[HDCP_MAX_RECEIVERS][HDCP_RECEIVER_ID_SIZE_BYTES]; -+ u16 hdcp_port_status = 0; -+ int ret; -+ -+ DRM_INFO("INFO: Waiting for Receiver ID valid event\n"); -+ ret_events = 0; -+ do { -+ u8 events = 0; -+ u8 hdcp_last_error = 0; -+ events = check_event(ret_events, -+ HDCPTX_IS_RECEIVER_ID_VALID_EVENT); -+ DRM_DEBUG_KMS("INFO: Waiting HDCPTX_IS_RECEIVER_ID_VALID_EVENT\n"); -+ ret_events = wait4event(mhdp, &mhdp->hdcp.events, -+ HDCPTX_IS_RECEIVER_ID_VALID_EVENT, -+ (mhdp->hdcp.sink_is_repeater ? -+ HDCP_EVENT_TO_RPT : HDCP_EVENT_TO_DEF)); -+ if (ret_events == 0) { -+ /* time out occurred, return error */ -+ DRM_ERROR("HDCP error did not get receiver IDs\n"); -+ return -1; -+ } -+ if (check_event(ret_events, HDCPTX_STATUS_EVENT) != 0) { -+ /* There was a status update, could be due to HPD -+ going down or some other error, check if an error -+ was set, if so exit. -+ */ -+ hdcp_port_status = hdmi_hdcp_get_status(mhdp); -+ hdcp_last_error = GET_HDCP_PORT_STS_LAST_ERR(hdcp_port_status); -+ if (hdmi_hdcp_handle_status(hdcp_port_status)) { -+ DRM_ERROR("HDCP error no: %u\n", hdcp_last_error); -+ return -1; -+ } else { -+ /* No error logged, keep going. -+ * If this somehow happened at same time, then need to -+ * put the HDCPTX_STATUS_EVENT back into the global -+ * events pool and checked later. */ -+ mhdp->hdcp.events |= HDCPTX_STATUS_EVENT; -+ -+ /* Special condition when connected to HDCP 1.4 repeater -+ * with no downstream devices attached, then will not -+ * get receiver ID list but instead will reach -+ * authenticated state. */ -+ if ((mhdp->hdcp.hdcp_version == HDCP_TX_1) && (mhdp->hdcp.sink_is_repeater == 1) && -+ ((hdcp_port_status & HDCP_PORT_STS_AUTH) == HDCP_PORT_STS_AUTH)) { -+ DRM_INFO("Connected to HDCP 1.4 repeater with no downstream devices!\n"); -+ return 0; -+ } -+ -+ msleep(20); -+ } -+ } -+ } while (check_event(ret_events, -+ HDCPTX_IS_RECEIVER_ID_VALID_EVENT) == 0); -+ -+ DRM_INFO("INFO: Requesting Receivers ID's\n"); -+ -+ hdcp_num_rec = 0; -+ memset(&hdcp_rec_id, 0, sizeof(hdcp_rec_id)); -+ -+ ret = cdns_mhdp_hdcp_tx_is_receiver_id_valid(mhdp, (u8 *)hdcp_rec_id, &hdcp_num_rec); -+ if (ret) { -+ DRM_DEV_ERROR(mhdp->dev, "Failed to hdcp tx receiver ID.\n"); -+ return -1; -+ } -+ -+ if (hdcp_num_rec == 0) { -+ DRM_DEBUG_KMS("WARN: Failed to get receiver list\n"); -+ /* Unknown problem, return error */ -+ return -1; -+ } -+ -+ DRM_INFO("INFO: Number of Receivers: %d\n", hdcp_num_rec); -+ -+ for (i = 0; i < hdcp_num_rec; ++i) { -+ DRM_INFO("\tReveiver ID%2d: %.2X%.2X%.2X%.2X%.2X\n", -+ i, -+ hdcp_rec_id[i][0], -+ hdcp_rec_id[i][1], -+ hdcp_rec_id[i][2], -+ hdcp_rec_id[i][3], -+ hdcp_rec_id[i][4] -+ ); -+ } -+ -+ /* swap ids byte order */ -+ hdmi_hdcp_swap_list(&hdcp_rec_id[0][0], -+ &hdcp_rec_id_temp[0][0], hdcp_num_rec); -+ -+ /* Check Receiver ID's against revocation list in SRM */ -+ if (drm_hdcp_check_ksvs_revoked(mhdp->drm_dev, (u8 *)hdcp_rec_id_temp, hdcp_num_rec)) { -+ mhdp->hdcp.state = HDCP_STATE_AUTH_FAILED; -+ DRM_ERROR("INFO: Receiver check fails\n"); -+ return -1; -+ } -+ -+ ret = cdns_mhdp_hdcp_tx_respond_receiver_id_valid(mhdp, 1); -+ DRM_INFO("INFO: Responding with Receiver ID's OK!, ret=%d\n", ret); -+ return ret; -+} -+ -+#ifdef STORE_PAIRING -+static int hdmi_hdcp_get_stored_pairing(struct cdns_mhdp_device *mhdp) -+{ -+ int ret = 0; -+ unsigned long timeout = jiffies + msecs_to_jiffies(IMX_FW_TIMEOUT_MS); -+ unsigned long sleep = 1000; -+ const struct firmware *fw; -+ -+ DRM_DEBUG_KMS("%s()\n", __func__); -+ -+ while (time_before(jiffies, timeout)) { -+ ret = request_firmware(&fw, hdmi_hdcp_PAIRING_FIRMWARE, mhdp->dev); -+ if (ret == -ENOENT) { -+ msleep(sleep); -+ sleep *= 2; -+ continue; -+ } else if (ret) { -+ DRM_DEV_INFO(mhdp->dev, "HDCP pairing data not found\n"); -+ goto out; -+ } -+ -+ mhdp->hdcp.num_paired = fw->size / -+ sizeof(struct hdcp_trans_pairing_data); -+ if (mhdp->hdcp.num_paired > MAX_STORED_KM) { -+ /* todo: handle dropping */ -+ mhdp->hdcp.num_paired = MAX_STORED_KM; -+ DRM_DEV_INFO(mhdp->dev, -+ "too many paired receivers - dropping older entries\n"); -+ } -+ memcpy(&mhdp->hdcp.pairing[0], fw->data, -+ sizeof(struct hdcp_trans_pairing_data) * mhdp->hdcp.num_paired); -+ release_firmware(fw); -+ goto out; -+ } -+ -+ DRM_DEV_ERROR(mhdp->dev, "Timed out trying to load firmware\n"); -+ ret = -ETIMEDOUT; -+ out: -+ return ret; -+} -+#endif -+ -+static int hdmi_hdcp_find_km_store(struct cdns_mhdp_device *mhdp, -+ u8 receiver[HDCP_PAIRING_R_ID]) -+{ -+ int i; -+ -+ DRM_DEBUG_KMS("%s()\n", __func__); -+ for (i = 0; i < mhdp->hdcp.num_paired; i++) { -+ if (memcmp(receiver, mhdp->hdcp.pairing[i].receiver_id, -+ HDCP_PAIRING_R_ID) == 0) { -+ DRM_INFO("HDCP: found receiver id: 0x%x%x%x%x%x\n", -+ receiver[0], receiver[1], receiver[2], receiver[3], receiver[4]); -+ return i; -+ } -+ } -+ DRM_INFO("HDCP: receiver id: 0x%x%x%x%x%x not stored\n", -+ receiver[0], receiver[1], receiver[2], receiver[3], receiver[4]); -+ return -1; -+} -+ -+static int hdmi_hdcp_store_km(struct cdns_mhdp_device *mhdp, -+ struct hdcp_trans_pairing_data *pairing, -+ int stored_km_index) -+{ -+ int i, temp_index; -+ struct hdcp_trans_pairing_data temp_pairing; -+ -+ DRM_DEBUG_KMS("%s()\n", __func__); -+ -+ if (stored_km_index < 0) { -+ /* drop one entry if array is full */ -+ if (mhdp->hdcp.num_paired == MAX_STORED_KM) -+ mhdp->hdcp.num_paired--; -+ -+ temp_index = mhdp->hdcp.num_paired; -+ mhdp->hdcp.num_paired++; -+ if (!pairing) { -+ DRM_ERROR("NULL HDCP pairing data!\n"); -+ return -1; -+ } else -+ /* save the new stored km */ -+ temp_pairing = *pairing; -+ } else { -+ /* save the current stored km */ -+ temp_index = stored_km_index; -+ temp_pairing = mhdp->hdcp.pairing[stored_km_index]; -+ } -+ -+ /* move entries one slot to the end */ -+ for (i = temp_index; i > 0; i--) -+ mhdp->hdcp.pairing[i] = mhdp->hdcp.pairing[i - 1]; -+ -+ /* save the current/new entry at the beginning */ -+ mhdp->hdcp.pairing[0] = temp_pairing; -+ -+ return 0; -+} -+ -+static inline int hdmi_hdcp_auth_22(struct cdns_mhdp_device *mhdp) -+{ -+ int km_idx = -1; -+ u8 retEvents; -+ u16 hdcp_port_status; -+ u8 resp[HDCP_STATUS_SIZE]; -+ struct hdcp_trans_pairing_data pairing; -+ int ret; -+ -+ DRM_DEBUG_KMS("HDCP: Start 2.2 Authentication\n"); -+ mhdp->hdcp.sink_is_repeater = 0; -+ -+ /* Wait until HDCP2_TX_IS_KM_STORED EVENT appears */ -+ retEvents = 0; -+ DRM_DEBUG_KMS("INFO: Wait until HDCP2_TX_IS_KM_STORED EVENT appears\n"); -+ while (check_event(retEvents, HDCPTX_IS_KM_STORED_EVENT) == 0) { -+ DRM_DEBUG_KMS("INFO: Waiting FOR _IS_KM_STORED EVENT\n"); -+ retEvents = wait4event(mhdp, &mhdp->hdcp.events, -+ HDCPTX_IS_KM_STORED_EVENT, HDCP_EVENT_TO_DEF); -+ if (retEvents == 0) -+ /* time out occurred, return error */ -+ return -1; -+ if (check_event(retEvents, HDCPTX_STATUS_EVENT) != 0) { -+ /* There was a status update, could be due to HPD -+ going down or some other error, check if an error -+ was set, if so exit. -+ */ -+ hdcp_port_status = hdmi_hdcp_get_status(mhdp); -+ if (hdmi_hdcp_handle_status(hdcp_port_status) != 0) -+ return -1; -+ } -+ } -+ -+ DRM_DEBUG_KMS("HDCP: HDCPTX_IS_KM_STORED_EVENT\n"); -+ -+ /* Set HDCP2 TX KM STORED REQUEST */ -+ ret = cdns_mhdp_hdcp2_tx_is_km_stored_req(mhdp, resp, HDCP_STATUS_SIZE); -+ if (ret) { -+ DRM_DEV_ERROR(mhdp->dev, "Failed to hdcp2 tx km stored.\n"); -+ return -1; -+ } -+ -+ DRM_DEBUG_KMS("HDCP: CDN_API_HDCP2_TX_IS_KM_STORED_REQ_blocking\n"); -+ DRM_DEBUG_KMS("HDCP: Receiver ID: 0x%x%x%x%x%x\n", -+ resp[0], resp[1], resp[2], resp[3], resp[4]); -+ -+ km_idx = hdmi_hdcp_find_km_store(mhdp, resp); -+ -+ /* Check if KM is stored */ -+ if (km_idx >= 0) { -+ DRM_DEBUG_KMS("INFO: KM is stored\n"); -+ /* Set HDCP2 TX RESPOND KM with stored KM */ -+ ret = cdns_mhdp_hdcp2_tx_respond_km(mhdp, (u8 *)&mhdp->hdcp.pairing[km_idx], -+ sizeof(struct hdcp_trans_pairing_data)); -+ -+ DRM_DEBUG_KMS("HDCP: CDN_API_HDCP2_TX_RESPOND_KM_blocking, ret=%d\n", ret); -+ } else { /* KM is not stored */ -+ /* Set HDCP2 TX RESPOND KM with empty data */ -+ ret = cdns_mhdp_hdcp2_tx_respond_km(mhdp, NULL, 0); -+ DRM_DEBUG_KMS("INFO: KM is not stored ret=%d\n", ret); -+ } -+ -+ if (hdmi_hdcp_check_receviers(mhdp)) -+ return -1; -+ -+ /* Check if KM is not stored */ -+ if (km_idx < 0) { -+ int loop_cnt = 0; -+ -+ /* Wait until HDCP2_TX_STORE_KM EVENT appears */ -+ retEvents = 0; -+ DRM_DEBUG_KMS("INFO: wait4event -> HDCPTX_STORE_KM_EVENT\n"); -+ while (check_event(retEvents, HDCPTX_STORE_KM_EVENT) == 0) { -+ retEvents = wait4event(mhdp, &mhdp->hdcp.events, -+ HDCPTX_STORE_KM_EVENT, HDCP_EVENT_TO_DEF); -+ if (check_event(retEvents, HDCPTX_STATUS_EVENT) -+ != 0) { -+ hdcp_port_status = hdmi_hdcp_get_status(mhdp); -+ if (hdmi_hdcp_handle_status(hdcp_port_status) -+ != 0) -+ return -1; -+ } -+ if (loop_cnt > 2) { -+ DRM_ERROR("Did not get event HDCPTX_STORE_KM_EVENT in time\n"); -+ return -1; -+ } else -+ loop_cnt++; -+ } -+ DRM_DEBUG_KMS("HDCP: HDCPTX_STORE_KM_EVENT\n"); -+ -+ /* Set HDCP2_TX_STORE_KM REQUEST */ -+ ret = cdns_mhdp_hdcp2_tx_store_km(mhdp, (u8 *)&pairing, sizeof(struct hdcp_trans_pairing_data)); -+ DRM_DEBUG_KMS("HDCP: CDN_API_HDCP2_TX_STORE_KM_REQ_blocking ret=%d\n", ret); -+ hdmi_hdcp_store_km(mhdp, &pairing, km_idx); -+ } else -+ hdmi_hdcp_store_km(mhdp, NULL, km_idx); -+ -+ /* Check if device was a repeater */ -+ hdcp_port_status = hdmi_hdcp_get_status(mhdp); -+ -+ /* Exit if there was any errors logged at this point... */ -+ if (GET_HDCP_PORT_STS_LAST_ERR(hdcp_port_status) > 0) { -+ hdmi_hdcp_handle_status(hdcp_port_status); -+ return -1; -+ } -+ -+ if (hdcp_port_status & HDCP_PORT_STS_REPEATER) -+ mhdp->hdcp.sink_is_repeater = 1; -+ -+ /* If sink was a repeater, we will be getting additional IDs to validate... -+ * Note that this one may take some time since spec allows up to 3s... */ -+ if (mhdp->hdcp.sink_is_repeater) -+ if (hdmi_hdcp_check_receviers(mhdp)) -+ return -1; -+ -+ /* Slight delay to allow firmware to finish setting up authenticated state */ -+ msleep(300); -+ -+ DRM_INFO("Finished hdmi_hdcp_auth_22\n"); -+ return 0; -+} -+ -+static inline int hdmi_hdcp_auth_14(struct cdns_mhdp_device *mhdp) -+{ -+ u16 hdcp_port_status; -+ int ret = 0; -+ -+ DRM_DEBUG_KMS("HDCP: Starting 1.4 Authentication\n"); -+ mhdp->hdcp.sink_is_repeater = 0; -+ -+ ret = hdmi_hdcp_check_receviers(mhdp); -+ if (ret) -+ return -1; -+ -+ /* Check if device was a repeater */ -+ hdcp_port_status = hdmi_hdcp_get_status(mhdp); -+ -+ /* Exit if there was any errors logged at this point... */ -+ if (GET_HDCP_PORT_STS_LAST_ERR(hdcp_port_status) > 0) { -+ hdmi_hdcp_handle_status(hdcp_port_status); -+ return -1; -+ } -+ -+ if (hdcp_port_status & HDCP_PORT_STS_REPEATER) { -+ DRM_INFO("Connected to a repeater\n"); -+ mhdp->hdcp.sink_is_repeater = 1; -+ } else -+ DRM_INFO("Connected to a normal sink\n"); -+ -+ /* If sink was a repeater, we will be getting additional IDs to validate... -+ * Note that this one may take some time since spec allows up to 3s... */ -+ if (mhdp->hdcp.sink_is_repeater) -+ ret = hdmi_hdcp_check_receviers(mhdp); -+ -+ /* Slight delay to allow firmware to finish setting up authenticated state */ -+ msleep(300); -+ -+ return ret; -+} -+ -+static int hdmi_hdcp_auth(struct cdns_mhdp_device *mhdp, u8 hdcp_config) -+{ -+ int ret = 0; -+ -+ DRM_DEBUG_KMS("HDCP: Start Authentication\n"); -+ -+ if (mhdp->hdcp.reauth_in_progress == 0) { -+ ret = hdmi_hdcp_set_config(mhdp, hdcp_config); -+ if (ret) { -+ DRM_ERROR("hdmi_hdcp_set_config failed\n"); -+ return -1; -+ } -+ } -+ -+ mhdp->hdcp.reauth_in_progress = 0; -+ mhdp->hdcp.sink_is_repeater = 0; -+ mhdp->hdcp.hdcp_version = hdcp_config; -+ -+ do { -+ if (mhdp->hdcp.cancel == 1) { -+ DRM_ERROR("mhdp->hdcp.cancel is TRUE\n"); -+ return -ECANCELED; -+ } -+ -+ if (hdcp_config == HDCP_TX_1) -+ ret = hdmi_hdcp_auth_14(mhdp); -+ else -+ ret = hdmi_hdcp_auth_22(mhdp); -+ if (ret) { -+ u16 hdcp_port_status; -+ DRM_ERROR("hdmi_hdcp_auth_%s failed\n", -+ (hdcp_config == HDCP_TX_1) ? "14" : "22"); -+ hdcp_port_status = hdmi_hdcp_get_status(mhdp); -+ hdmi_hdcp_handle_status(hdcp_port_status); -+ return -1; -+ } -+ -+ ret = hdmi_hdcp_auth_check(mhdp); -+ } while (ret == 1); -+ -+ return ret; -+} -+ -+static int _hdmi_hdcp_disable(struct cdns_mhdp_device *mhdp) -+{ -+ int ret = 0; -+ u8 hdcp_cfg = (HDCP_USE_KMKEY << 4); -+ -+ DRM_DEBUG_KMS("[%s:%d] HDCP is being disabled...\n", -+ mhdp->connector.base.name, mhdp->connector.base.base.id); -+ DRM_DEBUG_KMS("INFO: Disabling HDCP...\n"); -+ -+ ret = cdns_mhdp_hdcp_tx_config(mhdp, hdcp_cfg); -+ if (ret < 0) -+ DRM_DEBUG_KMS("cdns_mhdp_hdcp_tx_config failed\n"); -+ -+ DRM_DEBUG_KMS("HDCP is disabled\n"); -+ -+ mhdp->hdcp.events = 0; -+ -+ return ret; -+} -+ -+static int _hdmi_hdcp_enable(struct cdns_mhdp_device *mhdp) -+{ -+ int i, ret = 0, tries = 9; -+ u8 hpd_sts; -+ -+ hpd_sts = cdns_mhdp_read_hpd(mhdp); -+ if (1 != hpd_sts) { -+ dev_info(mhdp->dev, "%s HDP detected low, set state to DISABLING\n", __func__); -+ mhdp->hdcp.state = HDCP_STATE_DISABLING; -+ return -1; -+ } -+ -+ DRM_DEBUG_KMS("[%s:%d] HDCP is being enabled...\n", -+ mhdp->connector.base.name, mhdp->connector.base.base.id); -+ -+ mhdp->hdcp.events = 0; -+ -+ /* Incase of authentication failures, HDCP spec expects reauth. */ -+ /* TBD should this actually try 2.2 n times then 1.4? */ -+ for (i = 0; i < tries; i++) { -+ if (mhdp->hdcp.config & HDCP_CONFIG_2_2) { -+ ret = hdmi_hdcp_auth(mhdp, HDCP_TX_2); -+ if (ret == 0) -+ return 0; -+ else if (ret == -ECANCELED) -+ return ret; -+ _hdmi_hdcp_disable(mhdp); -+ } -+ } -+ -+ for (i = 0; i < tries; i++) { -+ if (mhdp->hdcp.config & HDCP_CONFIG_1_4) { -+ ret = hdmi_hdcp_auth(mhdp, HDCP_TX_1); -+ if (ret == 0) -+ return 0; -+ else if (ret == -ECANCELED) -+ return ret; -+ _hdmi_hdcp_disable(mhdp); -+ } -+ DRM_DEBUG_KMS("HDCP Auth failure (%d)\n", ret); -+ } -+ -+ DRM_ERROR("HDCP authentication failed (%d tries/%d)\n", tries, ret); -+ return ret; -+} -+ -+static void hdmi_hdcp_check_work(struct work_struct *work) -+{ -+ struct cdns_mhdp_hdcp *hdcp = container_of(work, -+ struct cdns_mhdp_hdcp, check_work.work); -+ struct cdns_mhdp_device *mhdp = container_of(hdcp, -+ struct cdns_mhdp_device, hdcp); -+ -+ /* todo: maybe we don't need to always schedule */ -+ hdmi_hdcp_check_link(mhdp); -+ schedule_delayed_work(&hdcp->check_work, 50); -+} -+ -+static void hdmi_hdcp_prop_work(struct work_struct *work) -+{ -+ struct cdns_mhdp_hdcp *hdcp = container_of(work, -+ struct cdns_mhdp_hdcp, prop_work); -+ struct cdns_mhdp_device *mhdp = container_of(hdcp, -+ struct cdns_mhdp_device, hdcp); -+ -+ struct drm_device *dev = mhdp->drm_dev; -+ struct drm_connector_state *state; -+ -+ drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); -+ mutex_lock(&mhdp->hdcp.mutex); -+ -+ /* -+ * This worker is only used to flip between ENABLED/DESIRED. Either of -+ * those to UNDESIRED is handled by core. If hdcp_value == UNDESIRED, -+ * we're running just after hdcp has been disabled, so just exit -+ */ -+ if (mhdp->hdcp.value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { -+ state = mhdp->connector.base.state; -+ state->content_protection = mhdp->hdcp.value; -+ } -+ -+ mutex_unlock(&mhdp->hdcp.mutex); -+ drm_modeset_unlock(&dev->mode_config.connection_mutex); -+} -+ -+static void show_hdcp_supported(struct cdns_mhdp_device *mhdp) -+{ -+ if ((mhdp->hdcp.config & (HDCP_CONFIG_1_4 | HDCP_CONFIG_2_2)) == -+ (HDCP_CONFIG_1_4 | HDCP_CONFIG_2_2)) -+ DRM_INFO("Both HDCP 1.4 and 2 2 are enabled\n"); -+ else if (mhdp->hdcp.config & HDCP_CONFIG_1_4) -+ DRM_INFO("Only HDCP 1.4 is enabled\n"); -+ else if (mhdp->hdcp.config & HDCP_CONFIG_2_2) -+ DRM_INFO("Only HDCP 2.2 is enabled\n"); -+ else -+ DRM_INFO("HDCP is disabled\n"); -+} -+ -+#ifdef DEBUG -+void hdmi_hdcp_show_pairing(struct cdns_mhdp_device *mhdp, struct hdcp_trans_pairing_data *p) -+{ -+ char s[80]; -+ int i, k; -+ -+ DRM_INFO("Reveiver ID: %.2X%.2X%.2X%.2X%.2X\n", -+ p->receiver_id[0], -+ p->receiver_id[1], -+ p->receiver_id[2], -+ p->receiver_id[3], -+ p->receiver_id[4]); -+ for (k = 0, i = 0; k < 16; k++) -+ i += snprintf(&s[i], sizeof(s), "%02x", p->m[k]); -+ -+ DRM_INFO("\tm: %s\n", s); -+ -+ for (k = 0, i = 0; k < 16; k++) -+ i += snprintf(&s[i], sizeof(s), "%02x", p->km[k]); -+ -+ DRM_INFO("\tkm: %s\n", s); -+ -+ for (k = 0, i = 0; k < 16; k++) -+ i += snprintf(&s[i], sizeof(s), "%02x", p->ekh[k]); -+ -+ DRM_INFO("\tekh: %s\n", s); -+} -+#endif -+ -+void hdmi_hdcp_dump_pairing(struct seq_file *s, void *data) -+{ -+ struct cdns_mhdp_device *mhdp = data; -+#ifdef DEBUG -+ int i; -+ for (i = 0; i < mhdp->hdcp.num_paired; i++) -+ hdmi_hdcp_show_pairing(mhdp, &mhdp->hdcp.pairing[i]); -+#endif -+ seq_write(s, &mhdp->hdcp.pairing[0], -+ mhdp->hdcp.num_paired * sizeof(struct hdcp_trans_pairing_data)); -+} -+ -+static int hdmi_hdcp_pairing_show(struct seq_file *s, void *data) -+{ -+ hdmi_hdcp_dump_pairing(s, s->private); -+ return 0; -+} -+ -+static int hdmi_hdcp_dump_pairing_open(struct inode *inode, struct file *file) -+{ -+ return single_open(file, hdmi_hdcp_pairing_show, inode->i_private); -+} -+ -+static const struct file_operations hdmi_hdcp_dump_fops = { -+ .open = hdmi_hdcp_dump_pairing_open, -+ .read = seq_read, -+ .llseek = seq_lseek, -+ .release = single_release, -+}; -+ -+static void hdmi_hdcp_debugfs_init(struct cdns_mhdp_device *mhdp) -+{ -+ struct dentry *d, *root; -+ -+ root = debugfs_create_dir("imx-hdcp", NULL); -+ if (IS_ERR(root) || !root) -+ goto err; -+ -+ d = debugfs_create_file("dump_pairing", 0444, root, mhdp, -+ &hdmi_hdcp_dump_fops); -+ if (!d) -+ goto err; -+ return; -+ -+err: -+ dev_err(mhdp->dev, "Unable to create debugfs entries\n"); -+} -+ -+int cdns_hdmi_hdcp_init(struct cdns_mhdp_device *mhdp, struct device_node *of_node) -+{ -+ const char *compat; -+ u32 temp; -+ int ret; -+ -+ ret = of_property_read_string(of_node, "compatible", &compat); -+ if (ret) { -+ DRM_ERROR("Failed to compatible dts string\n"); -+ return ret; -+ } -+ if (!strstr(compat, "hdmi")) -+ return -EPERM; -+ -+ ret = of_property_read_u32(of_node, "hdcp-config", &temp); -+ if (ret) { -+ /* using highest level by default */ -+ mhdp->hdcp.config = HDCP_CONFIG_2_2; -+ DRM_INFO("Failed to get HDCP config - using HDCP 2.2 only\n"); -+ } else { -+ mhdp->hdcp.config = temp; -+ show_hdcp_supported(mhdp); -+ } -+ -+ hdmi_hdcp_debugfs_init(mhdp); -+ -+#ifdef USE_DEBUG_KEYS /* reserve for hdcp test key */ -+ { -+ u8 hdcp_cfg; -+ hdcp_cfg = HDCP_TX_2 | (HDCP_USE_KMKEY << 4) | (HDCP_CONTENT_TYPE_0 << 3); -+ imx_hdmi_load_test_keys(mhdp, &hdcp_cfg); -+ } -+#endif -+ -+ mhdp->hdcp.state = HDCP_STATE_INACTIVE; -+ -+ mutex_init(&mhdp->hdcp.mutex); -+ INIT_DELAYED_WORK(&mhdp->hdcp.check_work, hdmi_hdcp_check_work); -+ INIT_WORK(&mhdp->hdcp.prop_work, hdmi_hdcp_prop_work); -+ -+ return 0; -+} -+ -+int cdns_hdmi_hdcp_enable(struct cdns_mhdp_device *mhdp) -+{ -+ int ret = 0; -+ -+ mhdp->hdcp.reauth_in_progress = 0; -+ -+#ifdef STORE_PAIRING -+ hdmi_hdcp_get_stored_pairing(mhdp); -+#endif -+ msleep(500); -+ -+ mutex_lock(&mhdp->hdcp.mutex); -+ -+ mhdp->hdcp.value = DRM_MODE_CONTENT_PROTECTION_DESIRED; -+ mhdp->hdcp.state = HDCP_STATE_ENABLING; -+ mhdp->hdcp.cancel = 0; -+ -+ schedule_work(&mhdp->hdcp.prop_work); -+ schedule_delayed_work(&mhdp->hdcp.check_work, 50); -+ -+ mutex_unlock(&mhdp->hdcp.mutex); -+ -+ return ret; -+} -+ -+int cdns_hdmi_hdcp_disable(struct cdns_mhdp_device *mhdp) -+{ -+ int ret = 0; -+ -+ mutex_lock(&mhdp->hdcp.mutex); -+ if (mhdp->hdcp.value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { -+ mhdp->hdcp.value = DRM_MODE_CONTENT_PROTECTION_UNDESIRED; -+ mhdp->hdcp.state = HDCP_STATE_DISABLING; -+ mhdp->hdcp.cancel = 1; -+ schedule_work(&mhdp->hdcp.prop_work); -+ } -+ -+ mutex_unlock(&mhdp->hdcp.mutex); -+ -+ cancel_delayed_work_sync(&mhdp->hdcp.check_work); -+ -+ return ret; -+} -+ -+void cdns_hdmi_hdcp_atomic_check(struct drm_connector *connector, -+ struct drm_connector_state *old_state, -+ struct drm_connector_state *new_state) -+{ -+ u64 old_cp = old_state->content_protection; -+ u64 new_cp = new_state->content_protection; -+ struct drm_crtc_state *crtc_state; -+ -+ if (!new_state->crtc) { -+ /* -+ * If the connector is being disabled with CP enabled, mark it -+ * desired so it's re-enabled when the connector is brought back -+ */ -+ if (old_cp == DRM_MODE_CONTENT_PROTECTION_ENABLED) -+ new_state->content_protection = -+ DRM_MODE_CONTENT_PROTECTION_DESIRED; -+ return; -+ } -+ -+ /* -+ * Nothing to do if the state didn't change, or HDCP was activated since -+ * the last commit -+ */ -+ if (old_cp == new_cp || -+ (old_cp == DRM_MODE_CONTENT_PROTECTION_DESIRED && -+ new_cp == DRM_MODE_CONTENT_PROTECTION_ENABLED)) -+ return; -+ -+ crtc_state = drm_atomic_get_new_crtc_state(new_state->state, new_state->crtc); -+ crtc_state->mode_changed = true; -+} -+ -+static int hdmi_hdcp_check_link(struct cdns_mhdp_device *mhdp) -+{ -+ u16 hdcp_port_status = 0; -+ u8 hdcp_last_error = 0; -+ u8 hpd_sts; -+ int ret = 0; -+ -+ mhdp->hdcp.reauth_in_progress = 0; -+ mutex_lock(&mhdp->lock); -+ -+ if ((mhdp->hdcp.state == HDCP_STATE_AUTHENTICATED) || -+ (mhdp->hdcp.state == HDCP_STATE_AUTHENTICATING) || -+ (mhdp->hdcp.state == HDCP_STATE_REAUTHENTICATING) || -+ (mhdp->hdcp.state == HDCP_STATE_ENABLING)) { -+ -+ /* In active states, check the HPD signal. Because of the IRQ -+ * debounce delay, the state might not reflect the disconnection. -+ * The FW could already have detected the HDP down and reported error */ -+ hpd_sts = cdns_mhdp_read_hpd(mhdp); -+ if (1 != hpd_sts) -+ mhdp->hdcp.state = HDCP_STATE_DISABLING; -+ } -+ -+ if (mhdp->hdcp.state == HDCP_STATE_INACTIVE) -+ goto out; -+ -+ if (mhdp->hdcp.state == HDCP_STATE_DISABLING) { -+ _hdmi_hdcp_disable(mhdp); -+ mhdp->hdcp.state = HDCP_STATE_INACTIVE; -+ goto out; -+ } -+ -+/* TODO items: -+ Need to make sure that any requests from the firmware are actually -+ processed so want to remove this first jump to 'out', i.e. process -+ reauthentication requests, cleanup errors and repeater receiver id -+ checks. -+*/ -+ if (mhdp->hdcp.state == HDCP_STATE_AUTHENTICATED) { -+ /* get port status */ -+ hdcp_port_status = hdmi_hdcp_get_status(mhdp); -+ hdcp_last_error = GET_HDCP_PORT_STS_LAST_ERR(hdcp_port_status); -+ if (hdcp_last_error == HDCP_TRAN_ERR_REAUTH_REQ) { -+ DRM_INFO("Sink requesting re-authentication\n"); -+ mhdp->hdcp.state = HDCP_STATE_REAUTHENTICATING; -+ } else if (hdcp_last_error) { -+ DRM_ERROR("HDCP error no: %u\n", hdcp_last_error); -+ -+ if (mhdp->hdcp.value == DRM_MODE_CONTENT_PROTECTION_UNDESIRED) -+ goto out; -+ if (hdcp_port_status & HDCP_PORT_STS_AUTH) { -+ if (mhdp->hdcp.value != -+ DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { -+ mhdp->hdcp.value = -+ DRM_MODE_CONTENT_PROTECTION_ENABLED; -+ schedule_work(&mhdp->hdcp.prop_work); -+ goto out; -+ } -+ } -+ -+ mhdp->hdcp.state = HDCP_STATE_AUTH_FAILED; -+ -+ } else if (mhdp->hdcp.sink_is_repeater) { -+ u8 new_events; -+ /* Check events... and process if HDCPTX_IS_RECEIVER_ID_VALID_EVENT. */ -+ new_events = cdns_mhdp_get_event(mhdp); -+ mhdp->hdcp.events |= new_events; -+ if (check_event(mhdp->hdcp.events, HDCPTX_IS_RECEIVER_ID_VALID_EVENT)) { -+ DRM_INFO("Sink repeater updating receiver ID list...\n"); -+ if (hdmi_hdcp_check_receviers(mhdp)) -+ mhdp->hdcp.state = HDCP_STATE_AUTH_FAILED; -+ } -+ } -+ } -+ -+ if (mhdp->hdcp.state == HDCP_STATE_REAUTHENTICATING) { -+ /* For now just deal with HDCP2.2 */ -+ if (mhdp->hdcp.hdcp_version == HDCP_TX_2) -+ mhdp->hdcp.reauth_in_progress = 1; -+ else -+ mhdp->hdcp.state = HDCP_STATE_AUTH_FAILED; -+ } -+ -+ if (mhdp->hdcp.state == HDCP_STATE_ENABLING) { -+ mhdp->hdcp.state = HDCP_STATE_AUTHENTICATING; -+ ret = _hdmi_hdcp_enable(mhdp); -+ if (ret == -ECANCELED) -+ goto out; -+ else if (ret) { -+ DRM_ERROR("Failed to enable hdcp (%d)\n", ret); -+ mhdp->hdcp.value = DRM_MODE_CONTENT_PROTECTION_DESIRED; -+ schedule_work(&mhdp->hdcp.prop_work); -+ goto out; -+ } -+ } -+ -+ if ((mhdp->hdcp.state == HDCP_STATE_AUTH_FAILED) || -+ (mhdp->hdcp.state == HDCP_STATE_REAUTHENTICATING)) { -+ -+ print_port_status(hdcp_port_status); -+ if (mhdp->hdcp.state == HDCP_STATE_AUTH_FAILED) { -+ DRM_DEBUG_KMS("[%s:%d] HDCP link failed, retrying authentication 0x%2x\n", -+ mhdp->connector.base.name, mhdp->connector.base.base.id, hdcp_port_status); -+ ret = _hdmi_hdcp_disable(mhdp); -+ if (ret) { -+ DRM_ERROR("Failed to disable hdcp (%d)\n", ret); -+ mhdp->hdcp.value = DRM_MODE_CONTENT_PROTECTION_DESIRED; -+ schedule_work(&mhdp->hdcp.prop_work); -+ goto out; -+ } -+ } else -+ DRM_DEBUG_KMS("[%s:%d] HDCP attempt reauthentication 0x%2x\n", -+ mhdp->connector.base.name, mhdp->connector.base.base.id, hdcp_port_status); -+ -+ ret = _hdmi_hdcp_enable(mhdp); -+ if (ret == -ECANCELED) -+ goto out; -+ else if (ret) { -+ DRM_ERROR("Failed to enable hdcp (%d)\n", ret); -+ mhdp->hdcp.value = DRM_MODE_CONTENT_PROTECTION_DESIRED; -+ schedule_work(&mhdp->hdcp.prop_work); -+ goto out; -+ } -+ } -+ -+out: -+ mutex_unlock(&mhdp->lock); -+ -+ return ret; -+} -diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdcp.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdcp.c -new file mode 100644 -index 000000000000..587c5f953489 ---- /dev/null -+++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdcp.c -@@ -0,0 +1,300 @@ -+/* -+ * Cadence HDCP API driver -+ * -+ * Copyright (C) 2021 NXP Semiconductor, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ */ -+ -+#include -+#include -+#include -+ -+#include "cdns-mhdp.h" -+ -+static u32 mhdp_hdcp_bus_read(struct cdns_mhdp_device *mhdp, u32 offset) -+{ -+ u32 val; -+ -+ mutex_lock(&mhdp->iolock); -+ -+ if (mhdp->bus_type == BUS_TYPE_LOW4K_APB) { -+ /* Remap address to low 4K APB bus */ -+ writel(offset >> 12, mhdp->regs_sec + 8); -+ val = readl((offset & 0xfff) + mhdp->regs_base); -+ } else if (mhdp->bus_type == BUS_TYPE_NORMAL_APB) -+ val = readl(mhdp->regs_sec + offset); -+ -+ mutex_unlock(&mhdp->iolock); -+ -+ return val; -+} -+ -+static void mhdp_hdcp_bus_write(u32 val, struct cdns_mhdp_device *mhdp, u32 offset) -+{ -+ mutex_lock(&mhdp->iolock); -+ -+ if (mhdp->bus_type == BUS_TYPE_LOW4K_APB) { -+ /* Remap address to low 4K APB bus */ -+ writel(offset >> 12, mhdp->regs_sec + 8); -+ writel(val, (offset & 0xfff) + mhdp->regs_base); -+ } else if (mhdp->bus_type == BUS_TYPE_NORMAL_APB) -+ writel(val, mhdp->regs_sec + offset); -+ -+ mutex_unlock(&mhdp->iolock); -+} -+ -+static int mhdp_hdcp_mailbox_read(struct cdns_mhdp_device *mhdp) -+{ -+ int val, ret; -+ -+ ret = mhdp_readx_poll_timeout(mhdp_hdcp_bus_read, mhdp, MAILBOX_EMPTY_ADDR, -+ val, !val, MAILBOX_RETRY_US, -+ MAILBOX_TIMEOUT_US); -+ if (ret < 0) -+ return ret; -+ -+ return mhdp_hdcp_bus_read(mhdp, MAILBOX0_RD_DATA) & 0xff; -+} -+ -+static int mhdp_hdcp_mailbox_write(struct cdns_mhdp_device *mhdp, u8 val) -+{ -+ int ret, full; -+ -+ ret = mhdp_readx_poll_timeout(mhdp_hdcp_bus_read, mhdp, MAILBOX_FULL_ADDR, -+ full, !full, MAILBOX_RETRY_US, -+ MAILBOX_TIMEOUT_US); -+ if (ret < 0) -+ return ret; -+ -+ mhdp_hdcp_bus_write(val, mhdp, MAILBOX0_WR_DATA); -+ -+ return 0; -+} -+ -+static int mhdp_hdcp_mailbox_validate_receive(struct cdns_mhdp_device *mhdp, -+ u8 module_id, u8 opcode, u16 req_size) -+{ -+ u32 mbox_size, i; -+ u8 header[4]; -+ int ret; -+ -+ /* read the header of the message */ -+ for (i = 0; i < 4; i++) { -+ ret = mhdp_hdcp_mailbox_read(mhdp); -+ if (ret < 0) -+ return ret; -+ -+ header[i] = ret; -+ } -+ -+ mbox_size = get_unaligned_be16(header + 2); -+ -+ if (opcode != header[0] || module_id != header[1] || -+ req_size != mbox_size) { -+ /* -+ * If the message in mailbox is not what we want, we need to -+ * clear the mailbox by reading its contents. -+ */ -+ for (i = 0; i < mbox_size; i++) -+ if (mhdp_hdcp_mailbox_read(mhdp) < 0) -+ break; -+ -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int mhdp_hdcp_mailbox_read_receive(struct cdns_mhdp_device *mhdp, -+ u8 *buff, u16 buff_size) -+{ -+ u32 i; -+ int ret; -+ -+ for (i = 0; i < buff_size; i++) { -+ ret = mhdp_hdcp_mailbox_read(mhdp); -+ if (ret < 0) -+ return ret; -+ -+ buff[i] = ret; -+ } -+ -+ return 0; -+} -+ -+static int mhdp_hdcp_mailbox_send(struct cdns_mhdp_device *mhdp, u8 module_id, -+ u8 opcode, u16 size, u8 *message) -+{ -+ u8 header[4]; -+ int ret, i; -+ -+ header[0] = opcode; -+ header[1] = module_id; -+ put_unaligned_be16(size, header + 2); -+ -+ for (i = 0; i < 4; i++) { -+ ret = mhdp_hdcp_mailbox_write(mhdp, header[i]); -+ if (ret) -+ return ret; -+ } -+ -+ for (i = 0; i < size; i++) { -+ ret = mhdp_hdcp_mailbox_write(mhdp, message[i]); -+ if (ret) -+ return ret; -+ } -+ -+ return 0; -+} -+ -+/* HDCP API */ -+int cdns_mhdp_hdcp_tx_config(struct cdns_mhdp_device *mhdp, u8 config) -+{ -+ return mhdp_hdcp_mailbox_send(mhdp, MB_MODULE_ID_HDCP_TX, -+ HDCP_TX_CONFIGURATION, sizeof(config), &config); -+} -+EXPORT_SYMBOL(cdns_mhdp_hdcp_tx_config); -+ -+int cdns_mhdp_hdcp2_tx_respond_km(struct cdns_mhdp_device *mhdp, -+ u8 *msg, u16 len) -+{ -+ return mhdp_hdcp_mailbox_send(mhdp, MB_MODULE_ID_HDCP_TX, -+ HDCP2_TX_RESPOND_KM, len, msg); -+} -+EXPORT_SYMBOL(cdns_mhdp_hdcp2_tx_respond_km); -+ -+int cdns_mhdp_hdcp_tx_status_req(struct cdns_mhdp_device *mhdp, -+ u8 *status, u16 len) -+{ -+ int ret; -+ -+ ret = mhdp_hdcp_mailbox_send(mhdp, MB_MODULE_ID_HDCP_TX, -+ HDCP_TX_STATUS_CHANGE, 0, NULL); -+ if (ret) -+ goto err_tx_req; -+ -+ ret = mhdp_hdcp_mailbox_validate_receive(mhdp, MB_MODULE_ID_HDCP_TX, -+ HDCP_TX_STATUS_CHANGE, len); -+ if (ret) -+ goto err_tx_req; -+ -+ ret = mhdp_hdcp_mailbox_read_receive(mhdp, status, len); -+ if (ret) -+ goto err_tx_req; -+ -+err_tx_req: -+ if (ret) -+ DRM_ERROR("hdcp tx status req failed: %d\n", ret); -+ return ret; -+} -+EXPORT_SYMBOL(cdns_mhdp_hdcp_tx_status_req); -+ -+int cdns_mhdp_hdcp2_tx_is_km_stored_req(struct cdns_mhdp_device *mhdp, u8 *data, u16 len) -+{ -+ int ret; -+ -+ ret = mhdp_hdcp_mailbox_send(mhdp, MB_MODULE_ID_HDCP_TX, -+ HDCP2_TX_IS_KM_STORED, 0, NULL); -+ if (ret) -+ goto err_is_km; -+ -+ ret = mhdp_hdcp_mailbox_validate_receive(mhdp, MB_MODULE_ID_HDCP_TX, -+ HDCP2_TX_IS_KM_STORED, len); -+ if (ret) -+ goto err_is_km; -+ -+ ret = mhdp_hdcp_mailbox_read_receive(mhdp, data, len); -+ -+err_is_km: -+ if (ret) -+ DRM_ERROR("hdcp2 tx is km stored req failed: %d\n", ret); -+ return ret; -+} -+EXPORT_SYMBOL(cdns_mhdp_hdcp2_tx_is_km_stored_req); -+ -+int cdns_mhdp_hdcp2_tx_store_km(struct cdns_mhdp_device *mhdp, -+ u8 *resp, u16 len) -+{ -+ int ret; -+ -+ ret = mhdp_hdcp_mailbox_send(mhdp, MB_MODULE_ID_HDCP_TX, -+ HDCP2_TX_STORE_KM, 0, NULL); -+ if (ret) -+ goto err_store_km; -+ -+ ret = mhdp_hdcp_mailbox_validate_receive(mhdp, MB_MODULE_ID_HDCP_TX, -+ HDCP2_TX_STORE_KM, len); -+ if (ret) -+ goto err_store_km; -+ -+ ret = mhdp_hdcp_mailbox_read_receive(mhdp, resp, len); -+ -+err_store_km: -+ return ret; -+} -+EXPORT_SYMBOL(cdns_mhdp_hdcp2_tx_store_km); -+ -+int cdns_mhdp_hdcp_tx_is_receiver_id_valid(struct cdns_mhdp_device *mhdp, -+ u8 *rx_id, u8 *num) -+{ -+ u32 mbox_size, i; -+ u8 header[4]; -+ u8 temp; -+ int ret; -+ -+ ret = mhdp_hdcp_mailbox_send(mhdp, MB_MODULE_ID_HDCP_TX, -+ HDCP_TX_IS_RECEIVER_ID_VALID, 0, NULL); -+ if (ret) -+ goto err_rx_id; -+ -+ /* read the header of the message */ -+ for (i = 0; i < 4; i++) { -+ ret = mhdp_hdcp_mailbox_read(mhdp); -+ if (ret < 0) -+ return ret; -+ -+ header[i] = ret; -+ } -+ -+ mbox_size = get_unaligned_be16(header + 2); -+ -+ if (HDCP_TX_IS_RECEIVER_ID_VALID != header[0] || -+ MB_MODULE_ID_HDCP_TX != header[1]) -+ return -EINVAL; -+ -+ /* First get num of receivers */ -+ ret = mhdp_hdcp_mailbox_read_receive(mhdp, num, 1); -+ if (ret) -+ goto err_rx_id; -+ -+ /* skip second data */ -+ ret = mhdp_hdcp_mailbox_read_receive(mhdp, &temp, 1); -+ if (ret) -+ goto err_rx_id; -+ -+ /* get receivers ID */ -+ ret = mhdp_hdcp_mailbox_read_receive(mhdp, rx_id, mbox_size - 2); -+ -+err_rx_id: -+ return ret; -+} -+EXPORT_SYMBOL(cdns_mhdp_hdcp_tx_is_receiver_id_valid); -+ -+int cdns_mhdp_hdcp_tx_respond_receiver_id_valid( -+ struct cdns_mhdp_device *mhdp, u8 val) -+{ -+ return mhdp_hdcp_mailbox_send(mhdp, MB_MODULE_ID_HDCP_TX, -+ HDCP_TX_RESPOND_RECEIVER_ID_VALID, sizeof(val), &val); -+} -+EXPORT_SYMBOL(cdns_mhdp_hdcp_tx_respond_receiver_id_valid); -+ -+int cdns_mhdp_hdcp_tx_reauth(struct cdns_mhdp_device *mhdp, u8 msg) -+{ -+ return mhdp_hdcp_mailbox_send(mhdp, MB_MODULE_ID_HDCP_TX, -+ HDCP_TX_DO_AUTH_REQ, sizeof(msg), &msg); -+} -+EXPORT_SYMBOL(cdns_mhdp_hdcp_tx_reauth); -diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdcp.h b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdcp.h -new file mode 100644 -index 000000000000..4ce76dd1ee58 ---- /dev/null -+++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdcp.h -@@ -0,0 +1,36 @@ -+/* -+ * Copyright (C) 2021 NXP Semiconductor, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ */ -+ -+#ifndef CDNS_HDMI_HDCP_H -+#define CDNS_HDMI_HDCP_H -+ -+int cdns_mhdp_hdcp2_tx_respond_km(struct cdns_mhdp_device *mhdp, -+ u8 *msg, u16 len); -+int cdns_mhdp_hdcp_tx_config(struct cdns_mhdp_device *mhdp, u8 config); -+int cdns_mhdp_hdcp_tx_status_req(struct cdns_mhdp_device *mhdp, -+ u8 *status, u16 len); -+int cdns_mhdp_hdcp2_tx_is_km_stored_req(struct cdns_mhdp_device *mhdp, u8 *data, u16 len); -+int cdns_mhdp_hdcp2_tx_store_km(struct cdns_mhdp_device *mhdp, -+ u8 *reg, u16 len); -+int cdns_mhdp_hdcp_tx_is_receiver_id_valid(struct cdns_mhdp_device *mhdp, -+ u8 *rx_id, u8 *num); -+int cdns_mhdp_hdcp_tx_respond_receiver_id_valid(struct cdns_mhdp_device *mhdp, -+ u8 val); -+int cdns_mhdp_hdcp_tx_test_keys(struct cdns_mhdp_device *mhdp, u8 type, u8 resp); -+int cdns_mhdp_hdcp_tx_reauth(struct cdns_mhdp_device *mhdp, u8 msg); -+ -+int cdns_hdmi_hdcp_init(struct cdns_mhdp_device *mhdp, struct device_node *of_node); -+int cdns_hdmi_hdcp_enable(struct cdns_mhdp_device *mhdp); -+int cdns_hdmi_hdcp_disable(struct cdns_mhdp_device *mhdp); -+void cdns_hdmi_hdcp_atomic_check(struct drm_connector *connector, -+ struct drm_connector_state *old_state, -+ struct drm_connector_state *new_state); -+ -+#endif /* CDNS_HDMI_HDCP_H */ -diff --git a/include/drm/bridge/cdns-mhdp.h b/include/drm/bridge/cdns-mhdp.h -index 338fa55b8bdf..5752c47b1a16 100644 ---- a/include/drm/bridge/cdns-mhdp.h -+++ b/include/drm/bridge/cdns-mhdp.h -@@ -388,6 +388,27 @@ - #define HDMI_TX_TEST 0xBB - #define HDMI_TX_EDID_INTERNAL 0xF0 - -+/* HDCP General opcode */ -+#define HDCP_GENERAL_SET_LC_128 0x00 -+#define HDCP_GENERAL_SET_SEED 0x01 -+ -+/* HDCP TX opcode */ -+#define HDCP_TX_CONFIGURATION 0x00 -+#define HDCP2_TX_SET_PUBLIC_KEY_PARAMS 0x01 -+#define HDCP2_TX_SET_DEBUG_RANDOM_NUMBERS 0x02 -+#define HDCP2_TX_RESPOND_KM 0x03 -+#define HDCP1_TX_SEND_KEYS 0x04 -+#define HDCP1_TX_SEND_RANDOM_AN 0x05 -+#define HDCP_TX_STATUS_CHANGE 0x06 -+#define HDCP2_TX_IS_KM_STORED 0x07 -+#define HDCP2_TX_STORE_KM 0x08 -+#define HDCP_TX_IS_RECEIVER_ID_VALID 0x09 -+#define HDCP_TX_RESPOND_RECEIVER_ID_VALID 0x0A -+#define HDCP_TX_TEST_KEYS 0x0B -+#define HDCP2_TX_SET_KM_KEY_PARAMS 0x0C -+#define HDCP_TX_SET_CP_IRQ 0x0D -+#define HDCP_TX_DO_AUTH_REQ 0x0E -+ - #define FW_STANDBY 0 - #define FW_ACTIVE 1 - -@@ -428,12 +449,16 @@ - #define EQ_PHASE_FAILED BIT(6) - #define FASE_LT_FAILED BIT(7) - --#define DPTX_HPD_EVENT BIT(0) --#define DPTX_TRAINING_EVENT BIT(1) --#define HDCP_TX_STATUS_EVENT BIT(4) --#define HDCP2_TX_IS_KM_STORED_EVENT BIT(5) --#define HDCP2_TX_STORE_KM_EVENT BIT(6) --#define HDCP_TX_IS_RECEIVER_ID_VALID_EVENT BIT(7) -+#define DPTX_HPD_EVENT BIT(0) -+#define HDMI_TX_HPD_EVENT BIT(0) -+#define HDMI_RX_5V_EVENT BIT(0) -+#define DPTX_TRAINING_EVENT BIT(1) -+#define HDMI_RX_SCDC_CHANGE_EVENT BIT(1) -+#define HDCPTX_STATUS_EVENT BIT(4) -+#define HDCPRX_STATUS_EVENT BIT(4) -+#define HDCPTX_IS_KM_STORED_EVENT BIT(5) -+#define HDCPTX_STORE_KM_EVENT BIT(6) -+#define HDCPTX_IS_RECEIVER_ID_VALID_EVENT BIT(7) - - #define TU_SIZE 30 - #define CDNS_DP_MAX_LINK_RATE 540000 -@@ -442,6 +467,7 @@ - #define F_VIF_DATA_WIDTH(x) (((x) & ((1 << 2) - 1)) << 2) - #define F_HDMI_MODE(x) (((x) & ((1 << 2) - 1)) << 0) - #define F_GCP_EN(x) (((x) & ((1 << 1) - 1)) << 12) -+#define F_CLEAR_AVMUTE(x) (((x) & ((1 << 1) - 1)) << 14) - #define F_DATA_EN(x) (((x) & ((1 << 1) - 1)) << 15) - #define F_HDMI2_PREAMBLE_EN(x) (((x) & ((1 << 1) - 1)) << 18) - #define F_PIC_3D(x) (((x) & ((1 << 4) - 1)) << 7) -@@ -662,6 +688,55 @@ struct cdns_plat_data { - char *plat_name; - }; - -+/* HDCP */ -+#define MAX_STORED_KM 64 -+#define HDCP_PAIRING_M_LEN 16 -+#define HDCP_PAIRING_M_EKH 16 -+#define HDCP_PAIRING_R_ID 5 -+ -+/* HDCP2_TX_SET_DEBUG_RANDOM_NUMBERS */ -+#define DEBUG_RANDOM_NUMBERS_KM_LEN 16 -+#define DEBUG_RANDOM_NUMBERS_RN_LEN 8 -+#define DEBUG_RANDOM_NUMBERS_KS_LEN 16 -+#define DEBUG_RANDOM_NUMBERS_RIV_LEN 8 -+#define DEBUG_RANDOM_NUMBERS_RTX_LEN 8 -+ -+struct hdcp_trans_pairing_data { -+ u8 receiver_id[HDCP_PAIRING_R_ID]; -+ u8 m[HDCP_PAIRING_M_LEN]; -+ u8 km[DEBUG_RANDOM_NUMBERS_KM_LEN]; -+ u8 ekh[HDCP_PAIRING_M_EKH]; -+}; -+ -+enum hdmi_hdcp_state { -+ HDCP_STATE_NO_AKSV, -+ HDCP_STATE_INACTIVE, -+ HDCP_STATE_ENABLING, -+ HDCP_STATE_AUTHENTICATING, -+ HDCP_STATE_REAUTHENTICATING, -+ HDCP_STATE_AUTHENTICATED, -+ HDCP_STATE_DISABLING, -+ HDCP_STATE_AUTH_FAILED -+}; -+ -+struct cdns_mhdp_hdcp { -+ struct mutex mutex; -+ u64 value; /* protected by hdcp_mutex */ -+ struct delayed_work check_work; -+ struct work_struct prop_work; -+ u8 state; -+ u8 cancel; -+ u8 bus_type; -+ u8 config; -+ struct hdcp_trans_pairing_data pairing[MAX_STORED_KM]; -+ u8 num_paired; -+ -+ u8 events; -+ u8 sink_is_repeater; -+ u8 reauth_in_progress; -+ u8 hdcp_version; -+}; -+ - struct cdns_mhdp_device { - void __iomem *regs_base; - void __iomem *regs_sec; -@@ -669,6 +744,7 @@ struct cdns_mhdp_device { - int bus_type; - - struct device *dev; -+ struct drm_device *drm_dev; - - struct cdns_mhdp_connector connector; - struct clk *spdif_clk; -@@ -722,6 +798,7 @@ struct cdns_mhdp_device { - hdmi_codec_plugged_cb plugged_cb; - struct device *codec_dev; - enum drm_connector_status last_connector_result; -+ struct cdns_mhdp_hdcp hdcp; - }; - - u32 cdns_mhdp_bus_read(struct cdns_mhdp_device *mhdp, u32 offset); -@@ -742,6 +819,7 @@ int cdns_mhdp_get_edid_block(void *mhdp, u8 *edid, - int cdns_mhdp_train_link(struct cdns_mhdp_device *mhdp); - int cdns_mhdp_set_video_status(struct cdns_mhdp_device *mhdp, int active); - int cdns_mhdp_config_video(struct cdns_mhdp_device *mhdp); -+int cdns_mhdp_apb_conf(struct cdns_mhdp_device *mhdp, u8 sel); - - /* Audio */ - int cdns_mhdp_audio_stop(struct cdns_mhdp_device *mhdp, -@@ -770,8 +848,6 @@ int cdns_mhdp_mailbox_read_receive(struct cdns_mhdp_device *mhdp, - int cdns_mhdp_mailbox_validate_receive(struct cdns_mhdp_device *mhdp, - u8 module_id, u8 opcode, - u16 req_size); --int cdns_mhdp_mailbox_read(struct cdns_mhdp_device *mhdp); -- - void cdns_mhdp_infoframe_set(struct cdns_mhdp_device *mhdp, - u8 entry_id, u8 packet_len, u8 *packet, u8 packet_type); - int cdns_hdmi_get_edid_block(void *data, u8 *edid, u32 block, size_t length); --- -2.29.2 - diff --git a/projects/NXP/devices/iMX8/patches/linux/0021-LF-3272-drm-cdns_mhdp-fix-Coverity-Issue-11566406.patch b/projects/NXP/devices/iMX8/patches/linux/0021-LF-3272-drm-cdns_mhdp-fix-Coverity-Issue-11566406.patch deleted file mode 100644 index bf124e8f71..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0021-LF-3272-drm-cdns_mhdp-fix-Coverity-Issue-11566406.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 2a093769a29f03103195b34c269411ee21b646e2 Mon Sep 17 00:00:00 2001 -From: Sandor Yu -Date: Wed, 20 Jan 2021 10:37:09 +0800 -Subject: [PATCH 21/49] LF-3272: drm: cdns_mhdp: fix Coverity Issue: 11566406 - -Add default access hdcp bus to fix -Coverity Issue: 11566406 Uninitialized scalar variable. - -Signed-off-by: Sandor Yu -Reviewed-by: Robby Cai ---- - drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdcp.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdcp.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdcp.c -index 587c5f953489..b3c931382013 100644 ---- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdcp.c -+++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdcp.c -@@ -27,6 +27,8 @@ static u32 mhdp_hdcp_bus_read(struct cdns_mhdp_device *mhdp, u32 offset) - val = readl((offset & 0xfff) + mhdp->regs_base); - } else if (mhdp->bus_type == BUS_TYPE_NORMAL_APB) - val = readl(mhdp->regs_sec + offset); -+ else -+ val = readl(mhdp->regs_base + offset); - - mutex_unlock(&mhdp->iolock); - --- -2.29.2 - diff --git a/projects/NXP/devices/iMX8/patches/linux/0022-LF-3271-drm-cdns-hdmi-fix-Coverity-Issue-11566407.patch b/projects/NXP/devices/iMX8/patches/linux/0022-LF-3271-drm-cdns-hdmi-fix-Coverity-Issue-11566407.patch deleted file mode 100644 index af85c51c9d..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0022-LF-3271-drm-cdns-hdmi-fix-Coverity-Issue-11566407.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 85ad1a878118a8dbaf9da5f85a2e088880d5ea01 Mon Sep 17 00:00:00 2001 -From: Sandor Yu -Date: Wed, 20 Jan 2021 10:44:17 +0800 -Subject: [PATCH 22/49] LF-3271: drm: cdns-hdmi: fix Coverity Issue: 11566407 - -Delete dead code to fix Coverity Issue: 11566407. - -Signed-off-by: Sandor Yu -Reviewed-by: Robby Cai ---- - drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c -index dc393f6b75e7..a89c8cba4788 100644 ---- a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c -+++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c -@@ -150,7 +150,6 @@ ssize_t HDCPTX_Status_store(struct device *dev, - else - dev_err(dev, "%s &hdp->state invalid\n", __func__); - return -1; -- return count; - } - - static void hdmi_sink_config(struct cdns_mhdp_device *mhdp) --- -2.29.2 - diff --git a/projects/NXP/devices/iMX8/patches/linux/0023-LF-3270-drm-cdns-hdmi-fix-coverity-Issue-11566405.patch b/projects/NXP/devices/iMX8/patches/linux/0023-LF-3270-drm-cdns-hdmi-fix-coverity-Issue-11566405.patch deleted file mode 100644 index 2ece85029d..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0023-LF-3270-drm-cdns-hdmi-fix-coverity-Issue-11566405.patch +++ /dev/null @@ -1,40 +0,0 @@ -From ddfa5aeb97c12fb7a67e6507ef2ae051658f112b Mon Sep 17 00:00:00 2001 -From: Sandor Yu -Date: Wed, 20 Jan 2021 10:49:13 +0800 -Subject: [PATCH 23/49] LF-3270: drm: cdns-hdmi: fix coverity Issue: 11566405 - -Delete unused code to fix coverity Issue: 11566405. - -Signed-off-by: Sandor Yu -Reviewed-by: Robby Cai ---- - drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c | 6 ++---- - 1 file changed, 2 insertions(+), 4 deletions(-) - -diff --git a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c -index a89c8cba4788..2300c3d8a91d 100644 ---- a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c -+++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c -@@ -37,17 +37,15 @@ static struct device_attribute HDCPTX_do_reauth = __ATTR_WO(HDCPTX_do_reauth); - static ssize_t HDCPTX_do_reauth_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) - { -- int value, ret; -+ int ret; - struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev); - - ret = cdns_mhdp_hdcp_tx_reauth(mhdp, 1); -- -- sscanf(buf, "%d", &value); -- - if (ret < 0) { - dev_err(dev, "%s cdns_mhdp_hdcp_tx_reauth failed\n", __func__); - return -1; - } -+ - return count; - } - --- -2.29.2 - diff --git a/projects/NXP/devices/iMX8/patches/linux/0024-LF-3269-drm-cdns-hdmi-fix-coverity-Issue-11566404.patch b/projects/NXP/devices/iMX8/patches/linux/0024-LF-3269-drm-cdns-hdmi-fix-coverity-Issue-11566404.patch deleted file mode 100644 index 1395849b6f..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0024-LF-3269-drm-cdns-hdmi-fix-coverity-Issue-11566404.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 2812d071eb348d903620f7ebadaf848024b3c672 Mon Sep 17 00:00:00 2001 -From: Sandor Yu -Date: Wed, 20 Jan 2021 11:04:41 +0800 -Subject: [PATCH 24/49] LF-3269: drm: cdns-hdmi: fix coverity Issue: 11566404 - -Check return value to fix coverity Issue: 11566404. - -Signed-off-by: Sandor Yu -Reviewed-by: Robby Cai ---- - drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c | 7 +++++-- - 1 file changed, 5 insertions(+), 2 deletions(-) - -diff --git a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c -index 2300c3d8a91d..df8ac87b3a54 100644 ---- a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c -+++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c -@@ -59,9 +59,12 @@ static ssize_t HDCPTX_Version_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) - { - struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev); -- int value; -+ int value, ret; -+ -+ ret = sscanf(buf, "%d", &value); -+ if (ret != 1) -+ return -EINVAL; - -- sscanf(buf, "%d", &value); - if (value == 2) - mhdp->hdcp.config = 2; - else if (value == 1) --- -2.29.2 - diff --git a/projects/NXP/devices/iMX8/patches/linux/0025-LF-3268-drm-cdns-hdmi-fix-Coverity-Issue-11566403.patch b/projects/NXP/devices/iMX8/patches/linux/0025-LF-3268-drm-cdns-hdmi-fix-Coverity-Issue-11566403.patch deleted file mode 100644 index 0a3c6444ab..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0025-LF-3268-drm-cdns-hdmi-fix-Coverity-Issue-11566403.patch +++ /dev/null @@ -1,36 +0,0 @@ -From cd49375db5c05acb824fa18ae9d19290073cda08 Mon Sep 17 00:00:00 2001 -From: Sandor Yu -Date: Wed, 20 Jan 2021 11:07:32 +0800 -Subject: [PATCH 25/49] LF-3268: drm: cdns-hdmi: fix Coverity Issue: 11566403 - -Check return value to fix Coverity Issue: 11566403. - -Signed-off-by: Sandor Yu -Reviewed-by: Robby Cai ---- - drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c | 7 +++++-- - 1 file changed, 5 insertions(+), 2 deletions(-) - -diff --git a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c -index df8ac87b3a54..28193178140f 100644 ---- a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c -+++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c -@@ -119,10 +119,13 @@ ssize_t HDCPTX_Status_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) - { - struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev); -- int value; -+ int value, ret; - - if (count == 2) { -- sscanf(buf, "%d", &value); -+ ret = sscanf(buf, "%d", &value); -+ if (ret != 1) -+ return -EINVAL; -+ - if ((value >= HDCP_STATE_NO_AKSV) && (value <= HDCP_STATE_AUTH_FAILED)) { - mhdp->hdcp.state = value; - return count; --- -2.29.2 - diff --git a/projects/NXP/devices/iMX8/patches/linux/0026-LF-3367-1-drm-cdns_hdmi-HDCP_STATE_DISABLING-may-mis.patch b/projects/NXP/devices/iMX8/patches/linux/0026-LF-3367-1-drm-cdns_hdmi-HDCP_STATE_DISABLING-may-mis.patch deleted file mode 100644 index 774398207e..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0026-LF-3367-1-drm-cdns_hdmi-HDCP_STATE_DISABLING-may-mis.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 54a5d4d3ba2de923fa4a4e5ef5e90151fb7f2fd8 Mon Sep 17 00:00:00 2001 -From: Sandor Yu -Date: Thu, 18 Feb 2021 16:25:52 +0800 -Subject: [PATCH 26/49] LF-3367-1: drm: cdns_hdmi: HDCP_STATE_DISABLING may - missed by check link - -Polling thread check_work is designed to handle all hdcp state change. -In HDCP disable function, check_work thread will be stopped after -hdcp.state is set to HDCP_STATE_DISABLING. check_work thread may miss -the state change, call check link function make sure HDCP_STATE_DISABLING -state is properly handled. - -Signed-off-by: Sandor Yu -Reviewed-by: Robby Cai -Acked-by: Jason Liu ---- - drivers/gpu/drm/bridge/cadence/cdns-hdmi-hdcp.c | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-hdcp.c b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-hdcp.c -index e2a3bc7fb42b..9119f2063098 100644 ---- a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-hdcp.c -+++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-hdcp.c -@@ -988,6 +988,8 @@ int cdns_hdmi_hdcp_disable(struct cdns_mhdp_device *mhdp) - { - int ret = 0; - -+ cancel_delayed_work_sync(&mhdp->hdcp.check_work); -+ - mutex_lock(&mhdp->hdcp.mutex); - if (mhdp->hdcp.value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { - mhdp->hdcp.value = DRM_MODE_CONTENT_PROTECTION_UNDESIRED; -@@ -998,7 +1000,8 @@ int cdns_hdmi_hdcp_disable(struct cdns_mhdp_device *mhdp) - - mutex_unlock(&mhdp->hdcp.mutex); - -- cancel_delayed_work_sync(&mhdp->hdcp.check_work); -+ /* Make sure HDCP_STATE_DISABLING state is handled */ -+ hdmi_hdcp_check_link(mhdp); - - return ret; - } --- -2.29.2 - diff --git a/projects/NXP/devices/iMX8/patches/linux/0027-LF-3367-2-drm-mhdp-more-time-for-FW-alive-check.patch b/projects/NXP/devices/iMX8/patches/linux/0027-LF-3367-2-drm-mhdp-more-time-for-FW-alive-check.patch deleted file mode 100644 index 9c39cf8250..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0027-LF-3367-2-drm-mhdp-more-time-for-FW-alive-check.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 42394af5975326eb20901d65eac47963847006e2 Mon Sep 17 00:00:00 2001 -From: Sandor Yu -Date: Fri, 19 Feb 2021 16:41:31 +0800 -Subject: [PATCH 27/49] LF-3367-2: drm: mhdp: more time for FW alive check - -FW alive check function may return false in hdcp enable/disable stress test. -Add more time for FW alive check, make sure get correct state. - -Signed-off-by: Sandor Yu -Reviewed-by: Robby Cai -Acked-by: Jason Liu ---- - drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c -index 2a8ab0872f25..3487a2fa335c 100644 ---- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c -+++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c -@@ -142,7 +142,7 @@ bool cdns_mhdp_check_alive(struct cdns_mhdp_device *mhdp) - alive = cdns_mhdp_bus_read(mhdp, KEEP_ALIVE); - - while (retries_left--) { -- udelay(2); -+ msleep(1); - - newalive = cdns_mhdp_bus_read(mhdp, KEEP_ALIVE); - if (alive == newalive) --- -2.29.2 - diff --git a/projects/NXP/devices/iMX8/patches/linux/0028-LF-3367-3-drm-mhdp-hdcp-adjust-state-handle-priority.patch b/projects/NXP/devices/iMX8/patches/linux/0028-LF-3367-3-drm-mhdp-hdcp-adjust-state-handle-priority.patch deleted file mode 100644 index deeaae4375..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0028-LF-3367-3-drm-mhdp-hdcp-adjust-state-handle-priority.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 60f6b8c90766663303f6005468502798eb2b0f44 Mon Sep 17 00:00:00 2001 -From: Sandor Yu -Date: Fri, 19 Feb 2021 17:53:54 +0800 -Subject: [PATCH 28/49] LF-3367-3: drm: mhdp-hdcp: adjust state handle priority - -Handle HDCP_STATE_INACTIVE and HDCP_STATE_DISABLING state priority -to avoid unnecessary HPD state check, drm has check it when hdcp -enable/disable. - -Signed-off-by: Sandor Yu -Reviewed-by: Robby Cai -Acked-by: Jason Liu ---- - .../gpu/drm/bridge/cadence/cdns-hdmi-hdcp.c | 24 ++++++++++--------- - 1 file changed, 13 insertions(+), 11 deletions(-) - -diff --git a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-hdcp.c b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-hdcp.c -index 9119f2063098..5dfbd7943306 100644 ---- a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-hdcp.c -+++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-hdcp.c -@@ -1048,6 +1048,15 @@ static int hdmi_hdcp_check_link(struct cdns_mhdp_device *mhdp) - mhdp->hdcp.reauth_in_progress = 0; - mutex_lock(&mhdp->lock); - -+ if (mhdp->hdcp.state == HDCP_STATE_INACTIVE) -+ goto out; -+ -+ if (mhdp->hdcp.state == HDCP_STATE_DISABLING) { -+ _hdmi_hdcp_disable(mhdp); -+ mhdp->hdcp.state = HDCP_STATE_INACTIVE; -+ goto out; -+ } -+ - if ((mhdp->hdcp.state == HDCP_STATE_AUTHENTICATED) || - (mhdp->hdcp.state == HDCP_STATE_AUTHENTICATING) || - (mhdp->hdcp.state == HDCP_STATE_REAUTHENTICATING) || -@@ -1056,18 +1065,11 @@ static int hdmi_hdcp_check_link(struct cdns_mhdp_device *mhdp) - /* In active states, check the HPD signal. Because of the IRQ - * debounce delay, the state might not reflect the disconnection. - * The FW could already have detected the HDP down and reported error */ -- hpd_sts = cdns_mhdp_read_hpd(mhdp); -- if (1 != hpd_sts) -+ hpd_sts = cdns_mhdp_read_hpd(mhdp); -+ if (1 != hpd_sts) { - mhdp->hdcp.state = HDCP_STATE_DISABLING; -- } -- -- if (mhdp->hdcp.state == HDCP_STATE_INACTIVE) -- goto out; -- -- if (mhdp->hdcp.state == HDCP_STATE_DISABLING) { -- _hdmi_hdcp_disable(mhdp); -- mhdp->hdcp.state = HDCP_STATE_INACTIVE; -- goto out; -+ goto out; -+ } - } - - /* TODO items: --- -2.29.2 - diff --git a/projects/NXP/devices/iMX8/patches/linux/0029-clk-imx8mq-add-27MHz-PHY-ref-clock.patch b/projects/NXP/devices/iMX8/patches/linux/0029-clk-imx8mq-add-27MHz-PHY-ref-clock.patch deleted file mode 100644 index 6175eb5148..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0029-clk-imx8mq-add-27MHz-PHY-ref-clock.patch +++ /dev/null @@ -1,42 +0,0 @@ -From afbe8e0ae318f407d64bbc48b784d93c782b6564 Mon Sep 17 00:00:00 2001 -From: Laurentiu Palcu -Date: Thu, 5 Sep 2019 13:07:22 +0300 -Subject: [PATCH 29/49] clk: imx8mq: add 27MHz PHY ref clock - -This clock is a high precision clock on imx8mq-evk board that will be used by -HDMI phy. - -Signed-off-by: Laurentiu Palcu ---- - drivers/clk/imx/clk-imx8mq.c | 3 ++- - include/dt-bindings/clock/imx8mq-clock.h | 4 +++- - 2 files changed, 5 insertions(+), 2 deletions(-) - -diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c -index 06292d4a98ff..6bd2fe0ae71d 100644 ---- a/drivers/clk/imx/clk-imx8mq.c -+++ b/drivers/clk/imx/clk-imx8mq.c -@@ -304,6 +304,7 @@ static int imx8mq_clocks_probe(struct platform_device *pdev) - hws[IMX8MQ_CLK_EXT2] = imx_get_clk_hw_by_name(np, "clk_ext2"); - hws[IMX8MQ_CLK_EXT3] = imx_get_clk_hw_by_name(np, "clk_ext3"); - hws[IMX8MQ_CLK_EXT4] = imx_get_clk_hw_by_name(np, "clk_ext4"); -+ hws[IMX8MQ_CLK_PHY_27MHZ] = imx_get_clk_hw_by_name(np, "hdmi_phy_27m"); - - np = of_find_compatible_node(NULL, NULL, "fsl,imx8mq-anatop"); - base = of_iomap(np, 0); -diff --git a/include/dt-bindings/clock/imx8mq-clock.h b/include/dt-bindings/clock/imx8mq-clock.h -index 9b8045d75b8b..2a81f96b7c74 100644 ---- a/include/dt-bindings/clock/imx8mq-clock.h -+++ b/include/dt-bindings/clock/imx8mq-clock.h -@@ -431,6 +431,7 @@ - #define IMX8MQ_CLK_MON_SEL 301 - #define IMX8MQ_CLK_MON_CLK2_OUT 302 -+#define IMX8MQ_CLK_PHY_27MHZ 303 - --#define IMX8MQ_CLK_END 303 -+#define IMX8MQ_CLK_END 304 - - #endif /* __DT_BINDINGS_CLOCK_IMX8MQ_H */ --- -2.29.2 - diff --git a/projects/NXP/devices/iMX8/patches/linux/0030-drm-imx-Add-mhdp-dp-hdmi-driver-for-imx8x-platform.patch b/projects/NXP/devices/iMX8/patches/linux/0030-drm-imx-Add-mhdp-dp-hdmi-driver-for-imx8x-platform.patch deleted file mode 100644 index 2e4a4acb31..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0030-drm-imx-Add-mhdp-dp-hdmi-driver-for-imx8x-platform.patch +++ /dev/null @@ -1,2656 +0,0 @@ -From 09102ec28d08ae95d476ee241ed016d2fe9da894 Mon Sep 17 00:00:00 2001 -From: Sandor Yu -Date: Mon, 20 Apr 2020 22:47:36 +0800 -Subject: [PATCH 30/49] drm: imx: Add mhdp dp/hdmi driver for imx8x platform - -Added i.MX8MQ HDMI/DP driver. -Added i.MX8MQ HDMI/DP driver. -Added LS1028A DP driver. - -Signed-off-by: Sandor Yu ---- - drivers/gpu/drm/imx/Kconfig | 1 + - drivers/gpu/drm/imx/Makefile | 1 + - drivers/gpu/drm/imx/mhdp/Kconfig | 11 + - drivers/gpu/drm/imx/mhdp/Makefile | 5 + - drivers/gpu/drm/imx/mhdp/cdns-mhdp-dp-phy.c | 531 ++++++++++++ - drivers/gpu/drm/imx/mhdp/cdns-mhdp-hdmi-phy.c | 764 ++++++++++++++++++ - drivers/gpu/drm/imx/mhdp/cdns-mhdp-imx.h | 75 ++ - drivers/gpu/drm/imx/mhdp/cdns-mhdp-imx8qm.c | 638 +++++++++++++++ - drivers/gpu/drm/imx/mhdp/cdns-mhdp-imxdrv.c | 257 ++++++ - drivers/gpu/drm/imx/mhdp/cdns-mhdp-ls1028a.c | 110 +++ - drivers/gpu/drm/imx/mhdp/cdns-mhdp-phy.h | 155 ++++ - 11 files changed, 2548 insertions(+) - create mode 100644 drivers/gpu/drm/imx/mhdp/Kconfig - create mode 100644 drivers/gpu/drm/imx/mhdp/Makefile - create mode 100644 drivers/gpu/drm/imx/mhdp/cdns-mhdp-dp-phy.c - create mode 100644 drivers/gpu/drm/imx/mhdp/cdns-mhdp-hdmi-phy.c - create mode 100644 drivers/gpu/drm/imx/mhdp/cdns-mhdp-imx.h - create mode 100644 drivers/gpu/drm/imx/mhdp/cdns-mhdp-imx8qm.c - create mode 100644 drivers/gpu/drm/imx/mhdp/cdns-mhdp-imxdrv.c - create mode 100644 drivers/gpu/drm/imx/mhdp/cdns-mhdp-ls1028a.c - create mode 100644 drivers/gpu/drm/imx/mhdp/cdns-mhdp-phy.h - -diff --git a/drivers/gpu/drm/imx/Kconfig b/drivers/gpu/drm/imx/Kconfig -index 6231048aa5aa..4af2f575f04b 100644 ---- a/drivers/gpu/drm/imx/Kconfig -+++ b/drivers/gpu/drm/imx/Kconfig -@@ -2,3 +2,4 @@ config DRM_IMX_HDMI - source "drivers/gpu/drm/imx/dcss/Kconfig" - source "drivers/gpu/drm/imx/ipuv3/Kconfig" - source "drivers/gpu/drm/imx/lcdc/Kconfig" -+source "drivers/gpu/drm/imx/mhdp/Kconfig" -diff --git a/drivers/gpu/drm/imx/Makefile b/drivers/gpu/drm/imx/Makefile -index b644deffe948..0b46c46b19a8 100644 ---- a/drivers/gpu/drm/imx/Makefile -+++ b/drivers/gpu/drm/imx/Makefile -@@ -2,3 +2,4 @@ obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o - obj-$(CONFIG_DRM_IMX_DCSS) += dcss/ - obj-$(CONFIG_DRM_IMX) += ipuv3/ - obj-$(CONFIG_DRM_IMX_LCDC) += lcdc/ -+obj-$(CONFIG_DRM_IMX_CDNS_MHDP) += mhdp/ -diff --git a/drivers/gpu/drm/imx/mhdp/Kconfig b/drivers/gpu/drm/imx/mhdp/Kconfig -new file mode 100644 -index 000000000000..86950badb947 ---- /dev/null -+++ b/drivers/gpu/drm/imx/mhdp/Kconfig -@@ -0,0 +1,11 @@ -+# SPDX-License-Identifier: GPL-2.0-only -+ -+config DRM_IMX_CDNS_MHDP -+ tristate "NXP i.MX MX8 DRM HDMI/DP" -+ select DRM_CDNS_MHDP -+ select DRM_CDNS_DP -+ select DRM_CDNS_HDMI -+ select DRM_CDNS_AUDIO -+ depends on DRM_IMX -+ help -+ Choose this if you want to use HDMI on i.MX8. -diff --git a/drivers/gpu/drm/imx/mhdp/Makefile b/drivers/gpu/drm/imx/mhdp/Makefile -new file mode 100644 -index 000000000000..235fa2d515e9 ---- /dev/null -+++ b/drivers/gpu/drm/imx/mhdp/Makefile -@@ -0,0 +1,5 @@ -+# SPDX-License-Identifier: GPL-2.0 -+ -+cdns_mhdp_imx-objs := cdns-mhdp-imxdrv.o cdns-mhdp-dp-phy.o \ -+ cdns-mhdp-hdmi-phy.o cdns-mhdp-imx8qm.o cdns-mhdp-ls1028a.o -+obj-$(CONFIG_DRM_IMX_CDNS_MHDP) += cdns_mhdp_imx.o -diff --git a/drivers/gpu/drm/imx/mhdp/cdns-mhdp-dp-phy.c b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-dp-phy.c -new file mode 100644 -index 000000000000..a6d03c94d196 ---- /dev/null -+++ b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-dp-phy.c -@@ -0,0 +1,531 @@ -+/* -+ * Cadence Display Port Interface (DP) PHY driver -+ * -+ * Copyright (C) 2019 NXP Semiconductor, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ */ -+#include -+#include -+#include -+#include -+#include "cdns-mhdp-phy.h" -+ -+enum dp_link_rate { -+ RATE_1_6 = 162000, -+ RATE_2_1 = 216000, -+ RATE_2_4 = 243000, -+ RATE_2_7 = 270000, -+ RATE_3_2 = 324000, -+ RATE_4_3 = 432000, -+ RATE_5_4 = 540000, -+ RATE_8_1 = 810000, -+}; -+ -+struct phy_pll_reg { -+ u16 val[7]; -+ u32 addr; -+}; -+ -+static const struct phy_pll_reg phy_pll_27m_cfg[] = { -+ /* 1.62 2.16 2.43 2.7 3.24 4.32 5.4 register address */ -+ {{ 0x010E, 0x010E, 0x010E, 0x010E, 0x010E, 0x010E, 0x010E }, CMN_PLL0_VCOCAL_INIT_TMR }, -+ {{ 0x001B, 0x001B, 0x001B, 0x001B, 0x001B, 0x001B, 0x001B }, CMN_PLL0_VCOCAL_ITER_TMR }, -+ {{ 0x30B9, 0x3087, 0x3096, 0x30B4, 0x30B9, 0x3087, 0x30B4 }, CMN_PLL0_VCOCAL_START }, -+ {{ 0x0077, 0x009F, 0x00B3, 0x00C7, 0x0077, 0x009F, 0x00C7 }, CMN_PLL0_INTDIV }, -+ {{ 0xF9DA, 0xF7CD, 0xF6C7, 0xF5C1, 0xF9DA, 0xF7CD, 0xF5C1 }, CMN_PLL0_FRACDIV }, -+ {{ 0x001E, 0x0028, 0x002D, 0x0032, 0x001E, 0x0028, 0x0032 }, CMN_PLL0_HIGH_THR }, -+ {{ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020 }, CMN_PLL0_DSM_DIAG }, -+ {{ 0x0000, 0x1000, 0x1000, 0x1000, 0x0000, 0x1000, 0x1000 }, CMN_PLLSM0_USER_DEF_CTRL }, -+ {{ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, CMN_DIAG_PLL0_OVRD }, -+ {{ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, CMN_DIAG_PLL0_FBH_OVRD }, -+ {{ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, CMN_DIAG_PLL0_FBL_OVRD }, -+ {{ 0x0006, 0x0007, 0x0007, 0x0007, 0x0006, 0x0007, 0x0007 }, CMN_DIAG_PLL0_V2I_TUNE }, -+ {{ 0x0043, 0x0043, 0x0043, 0x0042, 0x0043, 0x0043, 0x0042 }, CMN_DIAG_PLL0_CP_TUNE }, -+ {{ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008 }, CMN_DIAG_PLL0_LF_PROG }, -+ {{ 0x0100, 0x0001, 0x0001, 0x0001, 0x0100, 0x0001, 0x0001 }, CMN_DIAG_PLL0_PTATIS_TUNE1 }, -+ {{ 0x0007, 0x0001, 0x0001, 0x0001, 0x0007, 0x0001, 0x0001 }, CMN_DIAG_PLL0_PTATIS_TUNE2 }, -+ {{ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020 }, CMN_DIAG_PLL0_TEST_MODE}, -+ {{ 0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016 }, CMN_PSM_CLK_CTRL } -+}; -+ -+static const struct phy_pll_reg phy_pll_24m_cfg[] = { -+ /* 1.62 2.16 2.43 2.7 3.24 4.32 5.4 register address */ -+ {{ 0x00F0, 0x00F0, 0x00F0, 0x00F0, 0x00F0, 0x00F0, 0x00F0 }, CMN_PLL0_VCOCAL_INIT_TMR }, -+ {{ 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018 }, CMN_PLL0_VCOCAL_ITER_TMR }, -+ {{ 0x3061, 0x3092, 0x30B3, 0x30D0, 0x3061, 0x3092, 0x30D0 }, CMN_PLL0_VCOCAL_START }, -+ {{ 0x0086, 0x00B3, 0x00CA, 0x00E0, 0x0086, 0x00B3, 0x00E0 }, CMN_PLL0_INTDIV }, -+ {{ 0xF917, 0xF6C7, 0x75A1, 0xF479, 0xF917, 0xF6C7, 0xF479 }, CMN_PLL0_FRACDIV }, -+ {{ 0x0022, 0x002D, 0x0033, 0x0038, 0x0022, 0x002D, 0x0038 }, CMN_PLL0_HIGH_THR }, -+ {{ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020 }, CMN_PLL0_DSM_DIAG }, -+ {{ 0x0000, 0x1000, 0x1000, 0x1000, 0x0000, 0x1000, 0x1000 }, CMN_PLLSM0_USER_DEF_CTRL }, -+ {{ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, CMN_DIAG_PLL0_OVRD }, -+ {{ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, CMN_DIAG_PLL0_FBH_OVRD }, -+ {{ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, CMN_DIAG_PLL0_FBL_OVRD }, -+ {{ 0x0006, 0x0007, 0x0007, 0x0007, 0x0006, 0x0007, 0x0007 }, CMN_DIAG_PLL0_V2I_TUNE }, -+ {{ 0x0026, 0x0029, 0x0029, 0x0029, 0x0026, 0x0029, 0x0029 }, CMN_DIAG_PLL0_CP_TUNE }, -+ {{ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008 }, CMN_DIAG_PLL0_LF_PROG }, -+ {{ 0x008C, 0x008C, 0x008C, 0x008C, 0x008C, 0x008C, 0x008C }, CMN_DIAG_PLL0_PTATIS_TUNE1 }, -+ {{ 0x002E, 0x002E, 0x002E, 0x002E, 0x002E, 0x002E, 0x002E }, CMN_DIAG_PLL0_PTATIS_TUNE2 }, -+ {{ 0x0022, 0x0022, 0x0022, 0x0022, 0x0022, 0x0022, 0x0022 }, CMN_DIAG_PLL0_TEST_MODE}, -+ {{ 0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016 }, CMN_PSM_CLK_CTRL } -+}; -+ -+static int link_rate_index(u32 rate) -+{ -+ switch (rate) { -+ case RATE_1_6: -+ return 0; -+ case RATE_2_1: -+ return 1; -+ case RATE_2_4: -+ return 2; -+ case RATE_2_7: -+ return 3; -+ case RATE_3_2: -+ return 4; -+ case RATE_4_3: -+ return 5; -+ case RATE_5_4: -+ return 6; -+ default: -+ return -1; -+ } -+} -+ -+static void dp_aux_cfg(struct cdns_mhdp_device *mhdp) -+{ -+ /* Power up Aux */ -+ cdns_phy_reg_write(mhdp, TXDA_CYA_AUXDA_CYA, 1); -+ -+ cdns_phy_reg_write(mhdp, TX_DIG_CTRL_REG_1, 0x3); -+ ndelay(150); -+ cdns_phy_reg_write(mhdp, TX_DIG_CTRL_REG_2, 36); -+ ndelay(150); -+ cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x0100); -+ ndelay(150); -+ cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x0300); -+ ndelay(150); -+ cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_3, 0x0000); -+ ndelay(150); -+ cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, 0x2008); -+ ndelay(150); -+ cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, 0x2018); -+ ndelay(150); -+ cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, 0xA018); -+ ndelay(150); -+ cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x030C); -+ ndelay(150); -+ cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_5, 0x0000); -+ ndelay(150); -+ cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_4, 0x1001); -+ ndelay(150); -+ cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, 0xA098); -+ ndelay(150); -+ cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, 0xA198); -+ ndelay(150); -+ cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x030d); -+ ndelay(150); -+ cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x030f); -+} -+ -+/* PMA common configuration for 24MHz */ -+static void dp_phy_pma_cmn_cfg_24mhz(struct cdns_mhdp_device *mhdp) -+{ -+ int k; -+ u32 num_lanes = mhdp->dp.num_lanes; -+ u16 val; -+ -+ val = cdns_phy_reg_read(mhdp, PHY_PMA_CMN_CTRL1); -+ val &= 0xFFF7; -+ val |= 0x0008; -+ cdns_phy_reg_write(mhdp, PHY_PMA_CMN_CTRL1, val); -+ -+ for (k = 0; k < num_lanes; k++) { -+ /* Transceiver control and diagnostic registers */ -+ cdns_phy_reg_write(mhdp, XCVR_DIAG_LANE_FCM_EN_MGN_TMR | (k << 9), 0x0090); -+ /* Transmitter receiver detect registers */ -+ cdns_phy_reg_write(mhdp, TX_RCVDET_EN_TMR | (k << 9), 0x0960); -+ cdns_phy_reg_write(mhdp, TX_RCVDET_ST_TMR | (k << 9), 0x0030); -+ } -+} -+ -+/* Valid for 24 MHz only */ -+static void dp_phy_pma_cmn_pll0_24mhz(struct cdns_mhdp_device *mhdp) -+{ -+ u32 num_lanes = mhdp->dp.num_lanes; -+ u32 link_rate = mhdp->dp.rate; -+ u16 val; -+ int index, i, k; -+ -+ /* -+ * PLL reference clock source select -+ * for single ended reference clock val |= 0x0030; -+ * for differential clock val |= 0x0000; -+ */ -+ val = cdns_phy_reg_read(mhdp, PHY_PMA_CMN_CTRL1); -+ val = val & 0xFF8F; -+ val = val | 0x0030; -+ cdns_phy_reg_write(mhdp, PHY_PMA_CMN_CTRL1, val); -+ -+ /* DP PLL data rate 0/1 clock divider value */ -+ val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL); -+ val &= 0x00FF; -+ if (link_rate <= RATE_2_7) -+ val |= 0x2400; -+ else -+ val |= 0x1200; -+ cdns_phy_reg_write(mhdp, PHY_HDP_CLK_CTL, val); -+ -+ /* High speed clock 0/1 div */ -+ val = cdns_phy_reg_read(mhdp, CMN_DIAG_HSCLK_SEL); -+ val &= 0xFFCC; -+ if (link_rate <= RATE_2_7) -+ val |= 0x0011; -+ cdns_phy_reg_write(mhdp, CMN_DIAG_HSCLK_SEL, val); -+ -+ for (k = 0; k < num_lanes; k = k + 1) { -+ val = cdns_phy_reg_read(mhdp, (XCVR_DIAG_HSCLK_SEL | (k << 9))); -+ val &= 0xCFFF; -+ if (link_rate <= RATE_2_7) -+ val |= 0x1000; -+ cdns_phy_reg_write(mhdp, (XCVR_DIAG_HSCLK_SEL | (k << 9)), val); -+ } -+ -+ /* DP PHY PLL 24MHz configuration */ -+ index = link_rate_index(link_rate); -+ for (i = 0; i < ARRAY_SIZE(phy_pll_24m_cfg); i++) -+ cdns_phy_reg_write(mhdp, phy_pll_24m_cfg[i].addr, phy_pll_24m_cfg[i].val[index]); -+ -+ /* Transceiver control and diagnostic registers */ -+ for (k = 0; k < num_lanes; k = k + 1) { -+ val = cdns_phy_reg_read(mhdp, (XCVR_DIAG_PLLDRC_CTRL | (k << 9))); -+ val &= 0x8FFF; -+ if (link_rate <= RATE_2_7) -+ val |= 0x2000; -+ else -+ val |= 0x1000; -+ cdns_phy_reg_write(mhdp, (XCVR_DIAG_PLLDRC_CTRL | (k << 9)), val); -+ } -+ -+ for (k = 0; k < num_lanes; k = k + 1) { -+ cdns_phy_reg_write(mhdp, (XCVR_PSM_RCTRL | (k << 9)), 0xBEFC); -+ cdns_phy_reg_write(mhdp, (TX_PSC_A0 | (k << 9)), 0x6799); -+ cdns_phy_reg_write(mhdp, (TX_PSC_A1 | (k << 9)), 0x6798); -+ cdns_phy_reg_write(mhdp, (TX_PSC_A2 | (k << 9)), 0x0098); -+ cdns_phy_reg_write(mhdp, (TX_PSC_A3 | (k << 9)), 0x0098); -+ } -+} -+ -+/* PMA common configuration for 27MHz */ -+static void dp_phy_pma_cmn_cfg_27mhz(struct cdns_mhdp_device *mhdp) -+{ -+ u32 num_lanes = mhdp->dp.num_lanes; -+ u16 val; -+ int k; -+ -+ val = cdns_phy_reg_read(mhdp, PHY_PMA_CMN_CTRL1); -+ val &= 0xFFF7; -+ val |= 0x0008; -+ cdns_phy_reg_write(mhdp, PHY_PMA_CMN_CTRL1, val); -+ -+ /* Startup state machine registers */ -+ cdns_phy_reg_write(mhdp, CMN_SSM_BIAS_TMR, 0x0087); -+ cdns_phy_reg_write(mhdp, CMN_PLLSM0_PLLEN_TMR, 0x001B); -+ cdns_phy_reg_write(mhdp, CMN_PLLSM0_PLLPRE_TMR, 0x0036); -+ cdns_phy_reg_write(mhdp, CMN_PLLSM0_PLLVREF_TMR, 0x001B); -+ cdns_phy_reg_write(mhdp, CMN_PLLSM0_PLLLOCK_TMR, 0x006C); -+ -+ /* Current calibration registers */ -+ cdns_phy_reg_write(mhdp, CMN_ICAL_INIT_TMR, 0x0044); -+ cdns_phy_reg_write(mhdp, CMN_ICAL_ITER_TMR, 0x0006); -+ cdns_phy_reg_write(mhdp, CMN_ICAL_ADJ_INIT_TMR, 0x0022); -+ cdns_phy_reg_write(mhdp, CMN_ICAL_ADJ_ITER_TMR, 0x0006); -+ -+ /* Resistor calibration registers */ -+ cdns_phy_reg_write(mhdp, CMN_TXPUCAL_INIT_TMR, 0x0022); -+ cdns_phy_reg_write(mhdp, CMN_TXPUCAL_ITER_TMR, 0x0006); -+ cdns_phy_reg_write(mhdp, CMN_TXPU_ADJ_INIT_TMR, 0x0022); -+ cdns_phy_reg_write(mhdp, CMN_TXPU_ADJ_ITER_TMR, 0x0006); -+ cdns_phy_reg_write(mhdp, CMN_TXPDCAL_INIT_TMR, 0x0022); -+ cdns_phy_reg_write(mhdp, CMN_TXPDCAL_ITER_TMR, 0x0006); -+ cdns_phy_reg_write(mhdp, CMN_TXPD_ADJ_INIT_TMR, 0x0022); -+ cdns_phy_reg_write(mhdp, CMN_TXPD_ADJ_ITER_TMR, 0x0006); -+ cdns_phy_reg_write(mhdp, CMN_RXCAL_INIT_TMR, 0x0022); -+ cdns_phy_reg_write(mhdp, CMN_RXCAL_ITER_TMR, 0x0006); -+ cdns_phy_reg_write(mhdp, CMN_RX_ADJ_INIT_TMR, 0x0022); -+ cdns_phy_reg_write(mhdp, CMN_RX_ADJ_ITER_TMR, 0x0006); -+ -+ for (k = 0; k < num_lanes; k = k + 1) { -+ /* Power state machine registers */ -+ cdns_phy_reg_write(mhdp, XCVR_PSM_CAL_TMR | (k << 9), 0x016D); -+ cdns_phy_reg_write(mhdp, XCVR_PSM_A0IN_TMR | (k << 9), 0x016D); -+ /* Transceiver control and diagnostic registers */ -+ cdns_phy_reg_write(mhdp, XCVR_DIAG_LANE_FCM_EN_MGN_TMR | (k << 9), 0x00A2); -+ cdns_phy_reg_write(mhdp, TX_DIAG_BGREF_PREDRV_DELAY | (k << 9), 0x0097); -+ /* Transmitter receiver detect registers */ -+ cdns_phy_reg_write(mhdp, TX_RCVDET_EN_TMR | (k << 9), 0x0A8C); -+ cdns_phy_reg_write(mhdp, TX_RCVDET_ST_TMR | (k << 9), 0x0036); -+ } -+} -+ -+static void dp_phy_pma_cmn_pll0_27mhz(struct cdns_mhdp_device *mhdp) -+{ -+ u32 num_lanes = mhdp->dp.num_lanes; -+ u32 link_rate = mhdp->dp.rate; -+ u16 val; -+ int index, i, k; -+ -+ /* -+ * PLL reference clock source select -+ * for single ended reference clock val |= 0x0030; -+ * for differential clock val |= 0x0000; -+ */ -+ val = cdns_phy_reg_read(mhdp, PHY_PMA_CMN_CTRL1); -+ val &= 0xFF8F; -+ cdns_phy_reg_write(mhdp, PHY_PMA_CMN_CTRL1, val); -+ -+ /* for differential clock on the refclk_p and refclk_m off chip pins: -+ * CMN_DIAG_ACYA[8]=1'b1 -+ */ -+ cdns_phy_reg_write(mhdp, CMN_DIAG_ACYA, 0x0100); -+ -+ /* DP PLL data rate 0/1 clock divider value */ -+ val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL); -+ val &= 0x00FF; -+ if (link_rate <= RATE_2_7) -+ val |= 0x2400; -+ else -+ val |= 0x1200; -+ cdns_phy_reg_write(mhdp, PHY_HDP_CLK_CTL, val); -+ -+ /* High speed clock 0/1 div */ -+ val = cdns_phy_reg_read(mhdp, CMN_DIAG_HSCLK_SEL); -+ val &= 0xFFCC; -+ if (link_rate <= RATE_2_7) -+ val |= 0x0011; -+ cdns_phy_reg_write(mhdp, CMN_DIAG_HSCLK_SEL, val); -+ -+ for (k = 0; k < num_lanes; k++) { -+ val = cdns_phy_reg_read(mhdp, (XCVR_DIAG_HSCLK_SEL | (k << 9))); -+ val = val & 0xCFFF; -+ if (link_rate <= RATE_2_7) -+ val |= 0x1000; -+ cdns_phy_reg_write(mhdp, (XCVR_DIAG_HSCLK_SEL | (k << 9)), val); -+ } -+ -+ /* DP PHY PLL 27MHz configuration */ -+ index = link_rate_index(link_rate); -+ for (i = 0; i < ARRAY_SIZE(phy_pll_27m_cfg); i++) -+ cdns_phy_reg_write(mhdp, phy_pll_27m_cfg[i].addr, phy_pll_27m_cfg[i].val[index]); -+ -+ /* Transceiver control and diagnostic registers */ -+ for (k = 0; k < num_lanes; k++) { -+ val = cdns_phy_reg_read(mhdp, (XCVR_DIAG_PLLDRC_CTRL | (k << 9))); -+ val = val & 0x8FFF; -+ if (link_rate <= RATE_2_7) -+ val |= 0x2000; -+ else -+ val |= 0x1000; -+ cdns_phy_reg_write(mhdp, (XCVR_DIAG_PLLDRC_CTRL | (k << 9)), val); -+ } -+ -+ for (k = 0; k < num_lanes; k = k + 1) { -+ /* Power state machine registers */ -+ cdns_phy_reg_write(mhdp, (XCVR_PSM_RCTRL | (k << 9)), 0xBEFC); -+ cdns_phy_reg_write(mhdp, (TX_PSC_A0 | (k << 9)), 0x6799); -+ cdns_phy_reg_write(mhdp, (TX_PSC_A1 | (k << 9)), 0x6798); -+ cdns_phy_reg_write(mhdp, (TX_PSC_A2 | (k << 9)), 0x0098); -+ cdns_phy_reg_write(mhdp, (TX_PSC_A3 | (k << 9)), 0x0098); -+ /* Receiver calibration power state definition register */ -+ val = cdns_phy_reg_read(mhdp, RX_PSC_CAL | (k << 9)); -+ val &= 0xFFBB; -+ cdns_phy_reg_write(mhdp, (RX_PSC_CAL | (k << 9)), val); -+ val = cdns_phy_reg_read(mhdp, RX_PSC_A0 | (k << 9)); -+ val &= 0xFFBB; -+ cdns_phy_reg_write(mhdp, (RX_PSC_A0 | (k << 9)), val); -+ } -+} -+ -+static void dp_phy_power_down(struct cdns_mhdp_device *mhdp) -+{ -+ u16 val; -+ int i; -+ -+ if (!mhdp->power_up) -+ return; -+ -+ /* Place the PHY lanes in the A3 power state. */ -+ cdns_phy_reg_write(mhdp, PHY_HDP_MODE_CTRL, 0x8); -+ /* Wait for Power State A3 Ack */ -+ for (i = 0; i < 10; i++) { -+ val = cdns_phy_reg_read(mhdp, PHY_HDP_MODE_CTRL); -+ if (val & (1 << 7)) -+ break; -+ msleep(20); -+ } -+ if (i == 10) { -+ dev_err(mhdp->dev, "Wait A3 Ack failed\n"); -+ return; -+ } -+ -+ /* Disable HDP PLL’s data rate and full rate clocks out of PMA. */ -+ val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL); -+ val &= ~(1 << 2); -+ cdns_phy_reg_write(mhdp, PHY_HDP_CLK_CTL, val); -+ /* Wait for PLL clock gate ACK */ -+ for (i = 0; i < 10; i++) { -+ val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL); -+ if (!(val & (1 << 3))) -+ break; -+ msleep(20); -+ } -+ if (i == 10) { -+ dev_err(mhdp->dev, "Wait PLL clock gate Ack failed\n"); -+ return; -+ } -+ -+ /* Disable HDP PLL’s for high speed clocks */ -+ val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL); -+ val &= ~(1 << 0); -+ cdns_phy_reg_write(mhdp, PHY_HDP_CLK_CTL, val); -+ /* Wait for PLL disable ACK */ -+ for (i = 0; i < 10; i++) { -+ val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL); -+ if (!(val & (1 << 1))) -+ break; -+ msleep(20); -+ } -+ if (i == 10) { -+ dev_err(mhdp->dev, "Wait PLL disable Ack failed\n"); -+ return; -+ } -+} -+ -+static int dp_phy_power_up(struct cdns_mhdp_device *mhdp) -+{ -+ u32 val, i; -+ -+ /* Enable HDP PLL’s for high speed clocks */ -+ val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL); -+ val |= (1 << 0); -+ cdns_phy_reg_write(mhdp, PHY_HDP_CLK_CTL, val); -+ /* Wait for PLL ready ACK */ -+ for (i = 0; i < 10; i++) { -+ val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL); -+ if (val & (1 << 1)) -+ break; -+ msleep(20); -+ } -+ if (i == 10) { -+ dev_err(mhdp->dev, "Wait PLL Ack failed\n"); -+ return -1; -+ } -+ -+ /* Enable HDP PLL’s data rate and full rate clocks out of PMA. */ -+ val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL); -+ val |= (1 << 2); -+ cdns_phy_reg_write(mhdp, PHY_HDP_CLK_CTL, val); -+ /* Wait for PLL clock enable ACK */ -+ for (i = 0; i < 10; i++) { -+ val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL); -+ if (val & (1 << 3)) -+ break; -+ msleep(20); -+ } -+ if (i == 10) { -+ dev_err(mhdp->dev, "Wait PLL clock enable ACk failed\n"); -+ return -1; -+ } -+ -+ /* Configure PHY in A2 Mode */ -+ cdns_phy_reg_write(mhdp, PHY_HDP_MODE_CTRL, 0x0004); -+ /* Wait for Power State A2 Ack */ -+ for (i = 0; i < 10; i++) { -+ val = cdns_phy_reg_read(mhdp, PHY_HDP_MODE_CTRL); -+ if (val & (1 << 6)) -+ break; -+ msleep(20); -+ } -+ if (i == 10) { -+ dev_err(mhdp->dev, "Wait A2 Ack failed\n"); -+ return -1; -+ } -+ -+ /* Configure PHY in A0 mode (PHY must be in the A0 power -+ * state in order to transmit data) -+ */ -+ cdns_phy_reg_write(mhdp, PHY_HDP_MODE_CTRL, 0x0101); -+ -+ /* Wait for Power State A0 Ack */ -+ for (i = 0; i < 10; i++) { -+ val = cdns_phy_reg_read(mhdp, PHY_HDP_MODE_CTRL); -+ if (val & (1 << 4)) -+ break; -+ msleep(20); -+ } -+ if (i == 10) { -+ dev_err(mhdp->dev, "Wait A0 Ack failed\n"); -+ return -1; -+ } -+ -+ mhdp->power_up = true; -+ -+ return 0; -+} -+ -+int cdns_dp_phy_set_imx8mq(struct cdns_mhdp_device *mhdp) -+{ -+ int ret; -+ -+ /* Disable phy clock if PHY in power up state */ -+ dp_phy_power_down(mhdp); -+ -+ dp_phy_pma_cmn_cfg_27mhz(mhdp); -+ -+ dp_phy_pma_cmn_pll0_27mhz(mhdp); -+ -+ cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_0, 1); -+ cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_1, 1); -+ cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_2, 1); -+ cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_3, 1); -+ -+ /* PHY power up */ -+ ret = dp_phy_power_up(mhdp); -+ if (ret < 0) -+ return ret; -+ -+ dp_aux_cfg(mhdp); -+ -+ return ret; -+} -+ -+int cdns_dp_phy_set_imx8qm(struct cdns_mhdp_device *mhdp) -+{ -+ int ret; -+ -+ /* Disable phy clock if PHY in power up state */ -+ dp_phy_power_down(mhdp); -+ -+ dp_phy_pma_cmn_cfg_24mhz(mhdp); -+ -+ dp_phy_pma_cmn_pll0_24mhz(mhdp); -+ -+ cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_0, 1); -+ cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_1, 1); -+ cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_2, 1); -+ cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_3, 1); -+ -+ /* PHY power up */ -+ ret = dp_phy_power_up(mhdp); -+ if (ret < 0) -+ return ret; -+ -+ dp_aux_cfg(mhdp); -+ -+ return true; -+} -diff --git a/drivers/gpu/drm/imx/mhdp/cdns-mhdp-hdmi-phy.c b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-hdmi-phy.c -new file mode 100644 -index 000000000000..120300e6a2df ---- /dev/null -+++ b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-hdmi-phy.c -@@ -0,0 +1,764 @@ -+/* -+ * Cadence High-Definition Multimedia Interface (HDMI) driver -+ * -+ * Copyright (C) 2019 NXP Semiconductor, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include "cdns-mhdp-phy.h" -+ -+/* HDMI TX clock control settings */ -+struct hdmi_ctrl { -+ u32 pixel_clk_freq_min; -+ u32 pixel_clk_freq_max; -+ u32 feedback_factor; -+ u32 data_range_kbps_min; -+ u32 data_range_kbps_max; -+ u32 cmnda_pll0_ip_div; -+ u32 cmn_ref_clk_dig_div; -+ u32 ref_clk_divider_scaler; -+ u32 pll_fb_div_total; -+ u32 cmnda_pll0_fb_div_low; -+ u32 cmnda_pll0_fb_div_high; -+ u32 pixel_div_total; -+ u32 cmnda_pll0_pxdiv_low; -+ u32 cmnda_pll0_pxdiv_high; -+ u32 vco_freq_min; -+ u32 vco_freq_max; -+ u32 vco_ring_select; -+ u32 cmnda_hs_clk_0_sel; -+ u32 cmnda_hs_clk_1_sel; -+ u32 hsclk_div_at_xcvr; -+ u32 hsclk_div_tx_sub_rate; -+ u32 cmnda_pll0_hs_sym_div_sel; -+ u32 cmnda_pll0_clk_freq_min; -+ u32 cmnda_pll0_clk_freq_max; -+}; -+ -+/* HDMI TX clock control settings, pixel clock is output */ -+static const struct hdmi_ctrl imx8mq_ctrl_table[] = { -+/*Minclk Maxclk Fdbak DR_min DR_max ip_d dig DS Totl */ -+{ 27000, 27000, 1000, 270000, 270000, 0x03, 0x1, 0x1, 240, 0x0BC, 0x030, 80, 0x026, 0x026, 2160000, 2160000, 0, 2, 2, 2, 4, 0x3, 27000, 27000}, -+{ 27000, 27000, 1250, 337500, 337500, 0x03, 0x1, 0x1, 300, 0x0EC, 0x03C, 100, 0x030, 0x030, 2700000, 2700000, 0, 2, 2, 2, 4, 0x3, 33750, 33750}, -+{ 27000, 27000, 1500, 405000, 405000, 0x03, 0x1, 0x1, 360, 0x11C, 0x048, 120, 0x03A, 0x03A, 3240000, 3240000, 0, 2, 2, 2, 4, 0x3, 40500, 40500}, -+{ 27000, 27000, 2000, 540000, 540000, 0x03, 0x1, 0x1, 240, 0x0BC, 0x030, 80, 0x026, 0x026, 2160000, 2160000, 0, 2, 2, 2, 4, 0x2, 54000, 54000}, -+{ 54000, 54000, 1000, 540000, 540000, 0x03, 0x1, 0x1, 480, 0x17C, 0x060, 80, 0x026, 0x026, 4320000, 4320000, 1, 2, 2, 2, 4, 0x3, 54000, 54000}, -+{ 54000, 54000, 1250, 675000, 675000, 0x04, 0x1, 0x1, 400, 0x13C, 0x050, 50, 0x017, 0x017, 2700000, 2700000, 0, 1, 1, 2, 4, 0x2, 67500, 67500}, -+{ 54000, 54000, 1500, 810000, 810000, 0x04, 0x1, 0x1, 480, 0x17C, 0x060, 60, 0x01C, 0x01C, 3240000, 3240000, 0, 2, 2, 2, 2, 0x2, 81000, 81000}, -+{ 54000, 54000, 2000, 1080000, 1080000, 0x03, 0x1, 0x1, 240, 0x0BC, 0x030, 40, 0x012, 0x012, 2160000, 2160000, 0, 2, 2, 2, 1, 0x1, 108000, 108000}, -+{ 74250, 74250, 1000, 742500, 742500, 0x03, 0x1, 0x1, 660, 0x20C, 0x084, 80, 0x026, 0x026, 5940000, 5940000, 1, 2, 2, 2, 4, 0x3, 74250, 74250}, -+{ 74250, 74250, 1250, 928125, 928125, 0x04, 0x1, 0x1, 550, 0x1B4, 0x06E, 50, 0x017, 0x017, 3712500, 3712500, 1, 1, 1, 2, 4, 0x2, 92812, 92812}, -+{ 74250, 74250, 1500, 1113750, 1113750, 0x04, 0x1, 0x1, 660, 0x20C, 0x084, 60, 0x01C, 0x01C, 4455000, 4455000, 1, 2, 2, 2, 2, 0x2, 111375, 111375}, -+{ 74250, 74250, 2000, 1485000, 1485000, 0x03, 0x1, 0x1, 330, 0x104, 0x042, 40, 0x012, 0x012, 2970000, 2970000, 0, 2, 2, 2, 1, 0x1, 148500, 148500}, -+{ 99000, 99000, 1000, 990000, 990000, 0x03, 0x1, 0x1, 440, 0x15C, 0x058, 40, 0x012, 0x012, 3960000, 3960000, 1, 2, 2, 2, 2, 0x2, 99000, 99000}, -+{ 99000, 99000, 1250, 1237500, 1237500, 0x03, 0x1, 0x1, 275, 0x0D8, 0x037, 25, 0x00B, 0x00A, 2475000, 2475000, 0, 1, 1, 2, 2, 0x1, 123750, 123750}, -+{ 99000, 99000, 1500, 1485000, 1485000, 0x03, 0x1, 0x1, 330, 0x104, 0x042, 30, 0x00D, 0x00D, 2970000, 2970000, 0, 2, 2, 2, 1, 0x1, 148500, 148500}, -+{ 99000, 99000, 2000, 1980000, 1980000, 0x03, 0x1, 0x1, 440, 0x15C, 0x058, 40, 0x012, 0x012, 3960000, 3960000, 1, 2, 2, 2, 1, 0x1, 198000, 198000}, -+{148500, 148500, 1000, 1485000, 1485000, 0x03, 0x1, 0x1, 660, 0x20C, 0x084, 40, 0x012, 0x012, 5940000, 5940000, 1, 2, 2, 2, 2, 0x2, 148500, 148500}, -+{148500, 148500, 1250, 1856250, 1856250, 0x04, 0x1, 0x1, 550, 0x1B4, 0x06E, 25, 0x00B, 0x00A, 3712500, 3712500, 1, 1, 1, 2, 2, 0x1, 185625, 185625}, -+{148500, 148500, 1500, 2227500, 2227500, 0x03, 0x1, 0x1, 495, 0x188, 0x063, 30, 0x00D, 0x00D, 4455000, 4455000, 1, 1, 1, 2, 2, 0x1, 222750, 222750}, -+{148500, 148500, 2000, 2970000, 2970000, 0x03, 0x1, 0x1, 660, 0x20C, 0x084, 40, 0x012, 0x012, 5940000, 5940000, 1, 2, 2, 2, 1, 0x1, 297000, 297000}, -+{198000, 198000, 1000, 1980000, 1980000, 0x03, 0x1, 0x1, 220, 0x0AC, 0x02C, 10, 0x003, 0x003, 1980000, 1980000, 0, 1, 1, 2, 1, 0x0, 198000, 198000}, -+{198000, 198000, 1250, 2475000, 2475000, 0x03, 0x1, 0x1, 550, 0x1B4, 0x06E, 25, 0x00B, 0x00A, 4950000, 4950000, 1, 1, 1, 2, 2, 0x1, 247500, 247500}, -+{198000, 198000, 1500, 2970000, 2970000, 0x03, 0x1, 0x1, 330, 0x104, 0x042, 15, 0x006, 0x005, 2970000, 2970000, 0, 1, 1, 2, 1, 0x0, 297000, 297000}, -+{198000, 198000, 2000, 3960000, 3960000, 0x03, 0x1, 0x1, 440, 0x15C, 0x058, 20, 0x008, 0x008, 3960000, 3960000, 1, 1, 1, 2, 1, 0x0, 396000, 396000}, -+{297000, 297000, 1000, 2970000, 2970000, 0x03, 0x1, 0x1, 330, 0x104, 0x042, 10, 0x003, 0x003, 2970000, 2970000, 0, 1, 1, 2, 1, 0x0, 297000, 297000}, -+{297000, 297000, 1500, 4455000, 4455000, 0x03, 0x1, 0x1, 495, 0x188, 0x063, 15, 0x006, 0x005, 4455000, 4455000, 1, 1, 1, 2, 1, 0x0, 445500, 445500}, -+{297000, 297000, 2000, 5940000, 5940000, 0x03, 0x1, 0x1, 660, 0x20C, 0x084, 20, 0x008, 0x008, 5940000, 5940000, 1, 1, 1, 2, 1, 0x0, 594000, 594000}, -+{594000, 594000, 1000, 5940000, 5940000, 0x03, 0x1, 0x1, 660, 0x20C, 0x084, 10, 0x003, 0x003, 5940000, 5940000, 1, 1, 1, 2, 1, 0x0, 594000, 594000}, -+{594000, 594000, 750, 4455000, 4455000, 0x03, 0x1, 0x1, 495, 0x188, 0x063, 10, 0x003, 0x003, 4455000, 4455000, 1, 1, 1, 2, 1, 0x0, 445500, 445500}, -+{594000, 594000, 625, 3712500, 3712500, 0x04, 0x1, 0x1, 550, 0x1B4, 0x06E, 10, 0x003, 0x003, 3712500, 3712500, 1, 1, 1, 2, 1, 0x0, 371250, 371250}, -+{594000, 594000, 500, 2970000, 2970000, 0x03, 0x1, 0x1, 660, 0x20C, 0x084, 10, 0x003, 0x003, 5940000, 5940000, 1, 1, 1, 2, 2, 0x1, 297000, 297000}, -+}; -+ -+/* HDMI TX clock control settings, pixel clock is input */ -+static const struct hdmi_ctrl imx8qm_ctrl_table[] = { -+/*pclk_l pclk_h fd DRR_L DRR_H PLLD */ -+{ 25000, 42500, 1000, 250000, 425000, 0x05, 0x01, 0x01, 400, 0x182, 0x00A, 0, 0, 0, 2000000, 3400000, 0, 2, 2, 2, 4, 0x03, 25000, 42500}, -+{ 42500, 85000, 1000, 425000, 850000, 0x08, 0x03, 0x01, 320, 0x132, 0x00A, 0, 0, 0, 1700000, 3400000, 0, 1, 1, 2, 4, 0x02, 42500, 85000}, -+{ 85000, 170000, 1000, 850000, 1700000, 0x11, 0x00, 0x07, 340, 0x146, 0x00A, 0, 0, 0, 1700000, 3400000, 0, 1, 1, 2, 2, 0x01, 85000, 170000}, -+{170000, 340000, 1000, 1700000, 3400000, 0x22, 0x01, 0x07, 340, 0x146, 0x00A, 0, 0, 0, 1700000, 3400000, 0, 1, 1, 2, 1, 0x00, 170000, 340000}, -+{340000, 600000, 1000, 3400000, 6000000, 0x3C, 0x03, 0x06, 600, 0x24A, 0x00A, 0, 0, 0, 3400000, 6000000, 1, 1, 1, 2, 1, 0x00, 340000, 600000}, -+{ 25000, 34000, 1205, 312500, 425000, 0x04, 0x01, 0x01, 400, 0x182, 0x00A, 0, 0, 0, 2500000, 3400000, 0, 2, 2, 2, 4, 0x03, 31250, 42500}, -+{ 34000, 68000, 1205, 425000, 850000, 0x06, 0x02, 0x01, 300, 0x11E, 0x00A, 0, 0, 0, 1700000, 3400000, 0, 1, 1, 2, 4, 0x02, 42500, 85000}, -+{ 68000, 136000, 1205, 850000, 1700000, 0x0D, 0x02, 0x02, 325, 0x137, 0x00A, 0, 0, 0, 1700000, 3400000, 0, 1, 1, 2, 2, 0x01, 85000, 170000}, -+{136000, 272000, 1205, 1700000, 3400000, 0x1A, 0x02, 0x04, 325, 0x137, 0x00A, 0, 0, 0, 1700000, 3400000, 0, 1, 1, 2, 1, 0x00, 170000, 340000}, -+{272000, 480000, 1205, 3400000, 6000000, 0x30, 0x03, 0x05, 600, 0x24A, 0x00A, 0, 0, 0, 3400000, 6000000, 1, 1, 1, 2, 1, 0x00, 340000, 600000}, -+{ 25000, 28000, 1500, 375000, 420000, 0x03, 0x01, 0x01, 360, 0x15A, 0x00A, 0, 0, 0, 3000000, 3360000, 0, 2, 2, 2, 4, 0x03, 37500, 42000}, -+{ 28000, 56000, 1500, 420000, 840000, 0x06, 0x02, 0x01, 360, 0x15A, 0x00A, 0, 0, 0, 1680000, 3360000, 0, 1, 1, 2, 4, 0x02, 42000, 84000}, -+{ 56000, 113000, 1500, 840000, 1695000, 0x0B, 0x00, 0x05, 330, 0x13C, 0x00A, 0, 0, 0, 1680000, 3390000, 0, 1, 1, 2, 2, 0x01, 84000, 169500}, -+{113000, 226000, 1500, 1695000, 3390000, 0x16, 0x01, 0x05, 330, 0x13C, 0x00A, 0, 0, 0, 1695000, 3390000, 0, 1, 1, 2, 1, 0x00, 169500, 339000}, -+{226000, 400000, 1500, 3390000, 6000000, 0x28, 0x03, 0x04, 600, 0x24A, 0x00A, 0, 0, 0, 3390000, 6000000, 1, 1, 1, 2, 1, 0x00, 339000, 600000}, -+{ 25000, 42500, 2000, 500000, 850000, 0x05, 0x01, 0x01, 400, 0x182, 0x00A, 0, 0, 0, 2000000, 3400000, 0, 1, 1, 2, 4, 0x02, 50000, 85000}, -+{ 42500, 85000, 2000, 850000, 1700000, 0x08, 0x03, 0x01, 320, 0x132, 0x00A, 0, 0, 0, 1700000, 3400000, 0, 1, 1, 2, 2, 0x01, 85000, 170000}, -+{ 85000, 170000, 2000, 1700000, 3400000, 0x11, 0x00, 0x07, 340, 0x146, 0x00A, 0, 0, 0, 1700000, 3400000, 0, 1, 1, 2, 1, 0x00, 170000, 340000}, -+{170000, 300000, 2000, 3400000, 6000000, 0x22, 0x01, 0x06, 680, 0x29A, 0x00A, 0, 0, 0, 3400000, 6000000, 1, 1, 1, 2, 1, 0x00, 340000, 600000}, -+{594000, 594000, 5000, 2970000, 2970000, 0x3C, 0x03, 0x06, 600, 0x24A, 0x00A, 0, 0, 0, 5940000, 5940000, 1, 1, 1, 2, 2, 0x01, 297000, 297000}, -+{594000, 594000, 6250, 3712500, 3712500, 0x3C, 0x03, 0x06, 375, 0x169, 0x00A, 0, 0, 0, 3712500, 3712500, 1, 1, 1, 2, 1, 0x00, 371250, 371250}, -+{594000, 594000, 7500, 4455000, 4455000, 0x3C, 0x03, 0x06, 450, 0x1B4, 0x00A, 0, 0, 0, 4455000, 4455000, 1, 1, 1, 2, 1, 0x00, 445500, 445500}, -+}; -+ -+/* HDMI TX PLL tuning settings */ -+struct hdmi_pll_tuning { -+ u32 vco_freq_bin; -+ u32 vco_freq_min; -+ u32 vco_freq_max; -+ u32 volt_to_current_coarse; -+ u32 volt_to_current; -+ u32 ndac_ctrl; -+ u32 pmos_ctrl; -+ u32 ptat_ndac_ctrl; -+ u32 feedback_div_total; -+ u32 charge_pump_gain; -+ u32 coarse_code; -+ u32 v2i_code; -+ u32 vco_cal_code; -+}; -+ -+/* HDMI TX PLL tuning settings, pixel clock is output */ -+static const struct hdmi_pll_tuning imx8mq_pll_table[] = { -+/* bin VCO_freq min/max coar cod NDAC PMOS PTAT div-T P-Gain Coa V2I CAL */ -+ { 1, 1980000, 1980000, 0x4, 0x3, 0x0, 0x09, 0x09, 220, 0x42, 160, 5, 183 }, -+ { 2, 2160000, 2160000, 0x4, 0x3, 0x0, 0x09, 0x09, 240, 0x42, 166, 6, 208 }, -+ { 3, 2475000, 2475000, 0x5, 0x3, 0x1, 0x00, 0x07, 275, 0x42, 167, 6, 209 }, -+ { 4, 2700000, 2700000, 0x5, 0x3, 0x1, 0x00, 0x07, 300, 0x42, 188, 6, 230 }, -+ { 4, 2700000, 2700000, 0x5, 0x3, 0x1, 0x00, 0x07, 400, 0x4C, 188, 6, 230 }, -+ { 5, 2970000, 2970000, 0x6, 0x3, 0x1, 0x00, 0x07, 330, 0x42, 183, 6, 225 }, -+ { 6, 3240000, 3240000, 0x6, 0x3, 0x1, 0x00, 0x07, 360, 0x42, 203, 7, 256 }, -+ { 6, 3240000, 3240000, 0x6, 0x3, 0x1, 0x00, 0x07, 480, 0x4C, 203, 7, 256 }, -+ { 7, 3712500, 3712500, 0x4, 0x3, 0x0, 0x07, 0x0F, 550, 0x4C, 212, 7, 257 }, -+ { 8, 3960000, 3960000, 0x5, 0x3, 0x0, 0x07, 0x0F, 440, 0x42, 184, 6, 226 }, -+ { 9, 4320000, 4320000, 0x5, 0x3, 0x1, 0x07, 0x0F, 480, 0x42, 205, 7, 258 }, -+ { 10, 4455000, 4455000, 0x5, 0x3, 0x0, 0x07, 0x0F, 495, 0x42, 219, 7, 272 }, -+ { 10, 4455000, 4455000, 0x5, 0x3, 0x0, 0x07, 0x0F, 660, 0x4C, 219, 7, 272 }, -+ { 11, 4950000, 4950000, 0x6, 0x3, 0x1, 0x00, 0x07, 550, 0x42, 213, 7, 258 }, -+ { 12, 5940000, 5940000, 0x7, 0x3, 0x1, 0x00, 0x07, 660, 0x42, 244, 8, 292 }, -+}; -+ -+/* HDMI TX PLL tuning settings, pixel clock is input */ -+static const struct hdmi_pll_tuning imx8qm_pll_table[] = { -+/* bin VCO_freq min/max coar cod NDAC PMOS PTAT div-T P-Gain pad only */ -+ { 0, 1700000, 2000000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 300, 0x08D, 0, 0, 0 }, -+ { 0, 1700000, 2000000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 320, 0x08E, 0, 0, 0 }, -+ { 0, 1700000, 2000000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 325, 0x08E, 0, 0, 0 }, -+ { 0, 1700000, 2000000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 330, 0x08E, 0, 0, 0 }, -+ { 0, 1700000, 2000000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 340, 0x08F, 0, 0, 0 }, -+ { 0, 1700000, 2000000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 360, 0x0A7, 0, 0, 0 }, -+ { 0, 1700000, 2000000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 400, 0x0C5, 0, 0, 0 }, -+ { 1, 2000000, 2400000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 300, 0x086, 0, 0, 0 }, -+ { 1, 2000000, 2400000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 320, 0x087, 0, 0, 0 }, -+ { 1, 2000000, 2400000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 325, 0x087, 0, 0, 0 }, -+ { 1, 2000000, 2400000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 330, 0x104, 0, 0, 0 }, -+ { 1, 2000000, 2400000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 340, 0x08B, 0, 0, 0 }, -+ { 1, 2000000, 2400000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 360, 0x08D, 0, 0, 0 }, -+ { 1, 2000000, 2400000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 400, 0x0A6, 0, 0, 0 }, -+ { 2, 2400000, 2800000, 0x3, 0x1, 0x0, 0x04, 0x0D, 300, 0x04E, 0, 0, 0 }, -+ { 2, 2400000, 2800000, 0x3, 0x1, 0x0, 0x04, 0x0D, 320, 0x04F, 0, 0, 0 }, -+ { 2, 2400000, 2800000, 0x3, 0x1, 0x0, 0x04, 0x0D, 325, 0x04F, 0, 0, 0 }, -+ { 2, 2400000, 2800000, 0x3, 0x1, 0x0, 0x04, 0x0D, 330, 0x085, 0, 0, 0 }, -+ { 2, 2400000, 2800000, 0x3, 0x1, 0x0, 0x04, 0x0D, 340, 0x085, 0, 0, 0 }, -+ { 2, 2400000, 2800000, 0x3, 0x1, 0x0, 0x04, 0x0D, 360, 0x086, 0, 0, 0 }, -+ { 2, 2400000, 2800000, 0x3, 0x1, 0x0, 0x04, 0x0D, 400, 0x08B, 0, 0, 0 }, -+ { 3, 2800000, 3400000, 0x3, 0x1, 0x0, 0x04, 0x0D, 300, 0x047, 0, 0, 0 }, -+ { 3, 2800000, 3400000, 0x3, 0x1, 0x0, 0x04, 0x0D, 320, 0x04B, 0, 0, 0 }, -+ { 3, 2800000, 3400000, 0x3, 0x1, 0x0, 0x04, 0x0D, 325, 0x04B, 0, 0, 0 }, -+ { 3, 2800000, 3400000, 0x3, 0x1, 0x0, 0x04, 0x0D, 330, 0x04B, 0, 0, 0 }, -+ { 3, 2800000, 3400000, 0x3, 0x1, 0x0, 0x04, 0x0D, 340, 0x04D, 0, 0, 0 }, -+ { 3, 2800000, 3400000, 0x3, 0x1, 0x0, 0x04, 0x0D, 360, 0x04E, 0, 0, 0 }, -+ { 3, 2800000, 3400000, 0x3, 0x1, 0x0, 0x04, 0x0D, 400, 0x085, 0, 0, 0 }, -+ { 4, 3400000, 3900000, 0x7, 0x1, 0x0, 0x8E, 0x2F, 375, 0x041, 0, 0, 0 }, -+ { 4, 3400000, 3900000, 0x7, 0x1, 0x0, 0x8E, 0x2F, 600, 0x08D, 0, 0, 0 }, -+ { 4, 3400000, 3900000, 0x7, 0x1, 0x0, 0x8E, 0x2F, 680, 0x0A6, 0, 0, 0 }, -+ { 5, 3900000, 4500000, 0x7, 0x1, 0x0, 0x8E, 0x2F, 450, 0x041, 0, 0, 0 }, -+ { 5, 3900000, 4500000, 0x7, 0x1, 0x0, 0x8E, 0x2F, 600, 0x087, 0, 0, 0 }, -+ { 5, 3900000, 4500000, 0x7, 0x1, 0x0, 0x8E, 0x2F, 680, 0x0A4, 0, 0, 0 }, -+ { 6, 4500000, 5200000, 0x7, 0x1, 0x0, 0x04, 0x0D, 600, 0x04F, 0, 0, 0 }, -+ { 6, 4500000, 5200000, 0x7, 0x1, 0x0, 0x04, 0x0D, 680, 0x086, 0, 0, 0 }, -+ { 7, 5200000, 6000000, 0x7, 0x1, 0x0, 0x04, 0x0D, 600, 0x04D, 0, 0, 0 }, -+ { 7, 5200000, 6000000, 0x7, 0x1, 0x0, 0x04, 0x0D, 680, 0x04F, 0, 0, 0 } -+}; -+ -+static void hdmi_arc_config(struct cdns_mhdp_device *mhdp) -+{ -+ u16 txpu_calib_code; -+ u16 txpd_calib_code; -+ u16 txpu_adj_calib_code; -+ u16 txpd_adj_calib_code; -+ u16 prev_calib_code; -+ u16 new_calib_code; -+ u16 rdata; -+ -+ /* Power ARC */ -+ cdns_phy_reg_write(mhdp, TXDA_CYA_AUXDA_CYA, 0x0001); -+ -+ prev_calib_code = cdns_phy_reg_read(mhdp, TX_DIG_CTRL_REG_2); -+ txpu_calib_code = cdns_phy_reg_read(mhdp, CMN_TXPUCAL_CTRL); -+ txpd_calib_code = cdns_phy_reg_read(mhdp, CMN_TXPDCAL_CTRL); -+ txpu_adj_calib_code = cdns_phy_reg_read(mhdp, CMN_TXPU_ADJ_CTRL); -+ txpd_adj_calib_code = cdns_phy_reg_read(mhdp, CMN_TXPD_ADJ_CTRL); -+ -+ new_calib_code = ((txpu_calib_code + txpd_calib_code) / 2) -+ + txpu_adj_calib_code + txpd_adj_calib_code; -+ -+ if (new_calib_code != prev_calib_code) { -+ rdata = cdns_phy_reg_read(mhdp, TX_ANA_CTRL_REG_1); -+ rdata &= 0xDFFF; -+ cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, rdata); -+ cdns_phy_reg_write(mhdp, TX_DIG_CTRL_REG_2, new_calib_code); -+ mdelay(10); -+ rdata |= 0x2000; -+ cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, rdata); -+ udelay(150); -+ } -+ -+ cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x0100); -+ udelay(100); -+ cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x0300); -+ udelay(100); -+ cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_3, 0x0000); -+ udelay(100); -+ cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, 0x2008); -+ udelay(100); -+ cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, 0x2018); -+ udelay(100); -+ cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, 0x2098); -+ cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x030C); -+ cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_5, 0x0010); -+ udelay(100); -+ cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_4, 0x4001); -+ mdelay(5); -+ cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, 0x2198); -+ mdelay(5); -+ cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x030D); -+ udelay(100); -+ cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x030F); -+} -+ -+static void hdmi_phy_set_vswing(struct cdns_mhdp_device *mhdp) -+{ -+ const u32 num_lanes = 4; -+ u32 k; -+ -+ for (k = 0; k < num_lanes; k++) { -+ cdns_phy_reg_write(mhdp, (TX_DIAG_TX_DRV | (k << 9)), 0x7c0); -+ cdns_phy_reg_write(mhdp, (TX_TXCC_CPOST_MULT_00_0 | (k << 9)), 0x0); -+ cdns_phy_reg_write(mhdp, (TX_TXCC_CAL_SCLR_MULT_0 | (k << 9)), 0x120); -+ } -+} -+ -+static int hdmi_feedback_factor(struct cdns_mhdp_device *mhdp) -+{ -+ u32 feedback_factor; -+ -+ switch (mhdp->video_info.color_fmt) { -+ case YCBCR_4_2_2: -+ feedback_factor = 1000; -+ break; -+ case YCBCR_4_2_0: -+ switch (mhdp->video_info.color_depth) { -+ case 8: -+ feedback_factor = 500; -+ break; -+ case 10: -+ feedback_factor = 625; -+ break; -+ case 12: -+ feedback_factor = 750; -+ break; -+ case 16: -+ feedback_factor = 1000; -+ break; -+ default: -+ DRM_ERROR("Invalid ColorDepth\n"); -+ return 0; -+ } -+ break; -+ default: -+ /* Assume RGB/YUV444 */ -+ switch (mhdp->video_info.color_depth) { -+ case 10: -+ feedback_factor = 1250; -+ break; -+ case 12: -+ feedback_factor = 1500; -+ break; -+ case 16: -+ feedback_factor = 2000; -+ break; -+ default: -+ feedback_factor = 1000; -+ } -+ } -+ return feedback_factor; -+} -+ -+static int hdmi_phy_config(struct cdns_mhdp_device *mhdp, -+ const struct hdmi_ctrl *p_ctrl_table, -+ const struct hdmi_pll_tuning *p_pll_table, -+ char pclk_in) -+{ -+ const u32 num_lanes = 4; -+ u32 val, i, k; -+ -+ /* enable PHY isolation mode only for CMN */ -+ cdns_phy_reg_write(mhdp, PHY_PMA_ISOLATION_CTRL, 0xD000); -+ -+ /* set cmn_pll0_clk_datart1_div/cmn_pll0_clk_datart0_div dividers */ -+ val = cdns_phy_reg_read(mhdp, PHY_PMA_ISO_PLL_CTRL1); -+ val &= 0xFF00; -+ val |= 0x0012; -+ cdns_phy_reg_write(mhdp, PHY_PMA_ISO_PLL_CTRL1, val); -+ -+ /* assert PHY reset from isolation register */ -+ cdns_phy_reg_write(mhdp, PHY_ISO_CMN_CTRL, 0x0000); -+ /* assert PMA CMN reset */ -+ cdns_phy_reg_write(mhdp, PHY_PMA_ISO_CMN_CTRL, 0x0000); -+ -+ /* register XCVR_DIAG_BIDI_CTRL */ -+ for (k = 0; k < num_lanes; k++) -+ cdns_phy_reg_write(mhdp, XCVR_DIAG_BIDI_CTRL | (k << 9), 0x00FF); -+ -+ /* Describing Task phy_cfg_hdp */ -+ -+ val = cdns_phy_reg_read(mhdp, PHY_PMA_CMN_CTRL1); -+ val &= 0xFFF7; -+ val |= 0x0008; -+ cdns_phy_reg_write(mhdp, PHY_PMA_CMN_CTRL1, val); -+ -+ /* PHY Registers */ -+ val = cdns_phy_reg_read(mhdp, PHY_PMA_CMN_CTRL1); -+ val &= 0xCFFF; -+ val |= p_ctrl_table->cmn_ref_clk_dig_div << 12; -+ cdns_phy_reg_write(mhdp, PHY_PMA_CMN_CTRL1, val); -+ -+ val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL); -+ val &= 0x00FF; -+ val |= 0x1200; -+ cdns_phy_reg_write(mhdp, PHY_HDP_CLK_CTL, val); -+ -+ /* Common control module control and diagnostic registers */ -+ val = cdns_phy_reg_read(mhdp, CMN_CDIAG_REFCLK_CTRL); -+ val &= 0x8FFF; -+ val |= p_ctrl_table->ref_clk_divider_scaler << 12; -+ val |= 0x00C0; -+ cdns_phy_reg_write(mhdp, CMN_CDIAG_REFCLK_CTRL, val); -+ -+ /* High speed clock used */ -+ val = cdns_phy_reg_read(mhdp, CMN_DIAG_HSCLK_SEL); -+ val &= 0xFF00; -+ val |= (p_ctrl_table->cmnda_hs_clk_0_sel >> 1) << 0; -+ val |= (p_ctrl_table->cmnda_hs_clk_1_sel >> 1) << 4; -+ cdns_phy_reg_write(mhdp, CMN_DIAG_HSCLK_SEL, val); -+ -+ for (k = 0; k < num_lanes; k++) { -+ val = cdns_phy_reg_read(mhdp, (XCVR_DIAG_HSCLK_SEL | (k << 9))); -+ val &= 0xCFFF; -+ val |= (p_ctrl_table->cmnda_hs_clk_0_sel >> 1) << 12; -+ cdns_phy_reg_write(mhdp, (XCVR_DIAG_HSCLK_SEL | (k << 9)), val); -+ } -+ -+ /* PLL 0 control state machine registers */ -+ val = p_ctrl_table->vco_ring_select << 12; -+ cdns_phy_reg_write(mhdp, CMN_PLLSM0_USER_DEF_CTRL, val); -+ -+ if (pclk_in == true) -+ val = 0x30A0; -+ else { -+ val = cdns_phy_reg_read(mhdp, CMN_PLL0_VCOCAL_START); -+ val &= 0xFE00; -+ val |= p_pll_table->vco_cal_code; -+ } -+ cdns_phy_reg_write(mhdp, CMN_PLL0_VCOCAL_START, val); -+ -+ cdns_phy_reg_write(mhdp, CMN_PLL0_VCOCAL_INIT_TMR, 0x0064); -+ cdns_phy_reg_write(mhdp, CMN_PLL0_VCOCAL_ITER_TMR, 0x000A); -+ -+ /* Common functions control and diagnostics registers */ -+ val = p_ctrl_table->cmnda_pll0_hs_sym_div_sel << 8; -+ val |= p_ctrl_table->cmnda_pll0_ip_div; -+ cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_INCLK_CTRL, val); -+ -+ cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_OVRD, 0x0000); -+ -+ val = p_ctrl_table->cmnda_pll0_fb_div_high; -+ val |= (1 << 15); -+ cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_FBH_OVRD, val); -+ -+ val = p_ctrl_table->cmnda_pll0_fb_div_low; -+ val |= (1 << 15); -+ cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_FBL_OVRD, val); -+ -+ if (pclk_in == false) { -+ val = p_ctrl_table->cmnda_pll0_pxdiv_low; -+ cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_PXL_DIVL, val); -+ -+ val = p_ctrl_table->cmnda_pll0_pxdiv_high; -+ val |= (1 << 15); -+ cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_PXL_DIVH, val); -+ } -+ -+ val = p_pll_table->volt_to_current_coarse; -+ val |= (p_pll_table->volt_to_current) << 4; -+ cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_V2I_TUNE, val); -+ -+ val = p_pll_table->charge_pump_gain; -+ cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_CP_TUNE, val); -+ -+ cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_LF_PROG, 0x0008); -+ -+ val = p_pll_table->pmos_ctrl; -+ val |= (p_pll_table->ndac_ctrl) << 8; -+ cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_PTATIS_TUNE1, val); -+ -+ val = p_pll_table->ptat_ndac_ctrl; -+ cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_PTATIS_TUNE2, val); -+ -+ if (pclk_in == true) -+ cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_TEST_MODE, 0x0022); -+ else -+ cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_TEST_MODE, 0x0020); -+ cdns_phy_reg_write(mhdp, CMN_PSM_CLK_CTRL, 0x0016); -+ -+ /* Transceiver control and diagnostic registers */ -+ for (k = 0; k < num_lanes; k++) { -+ val = cdns_phy_reg_read(mhdp, (XCVR_DIAG_PLLDRC_CTRL | (k << 9))); -+ val &= 0xBFFF; -+ cdns_phy_reg_write(mhdp, (XCVR_DIAG_PLLDRC_CTRL | (k << 9)), val); -+ } -+ -+ for (k = 0; k < num_lanes; k++) { -+ val = cdns_phy_reg_read(mhdp, (TX_DIAG_TX_CTRL | (k << 9))); -+ val &= 0xFF3F; -+ val |= (p_ctrl_table->hsclk_div_tx_sub_rate >> 1) << 6; -+ cdns_phy_reg_write(mhdp, (TX_DIAG_TX_CTRL | (k << 9)), val); -+ } -+ -+ /* -+ * for single ended reference clock val |= 0x0030; -+ * for differential clock val |= 0x0000; -+ */ -+ val = cdns_phy_reg_read(mhdp, PHY_PMA_CMN_CTRL1); -+ val &= 0xFF8F; -+ if (pclk_in == true) -+ val |= 0x0030; -+ cdns_phy_reg_write(mhdp, PHY_PMA_CMN_CTRL1, val); -+ -+ /* for differential clock on the refclk_p and -+ * refclk_m off chip pins: CMN_DIAG_ACYA[8]=1'b1 */ -+ cdns_phy_reg_write(mhdp, CMN_DIAG_ACYA, 0x0100); -+ -+ /* Deassert PHY reset */ -+ cdns_phy_reg_write(mhdp, PHY_ISO_CMN_CTRL, 0x0001); -+ cdns_phy_reg_write(mhdp, PHY_PMA_ISO_CMN_CTRL, 0x0003); -+ -+ /* Power state machine registers */ -+ for (k = 0; k < num_lanes; k++) -+ cdns_phy_reg_write(mhdp, XCVR_PSM_RCTRL | (k << 9), 0xFEFC); -+ -+ /* Assert cmn_macro_pwr_en */ -+ cdns_phy_reg_write(mhdp, PHY_PMA_ISO_CMN_CTRL, 0x0013); -+ -+ /* wait for cmn_macro_pwr_en_ack */ -+ for (i = 0; i < 10; i++) { -+ val = cdns_phy_reg_read(mhdp, PHY_PMA_ISO_CMN_CTRL); -+ if (val & (1 << 5)) -+ break; -+ msleep(20); -+ } -+ if (i == 10) { -+ DRM_ERROR("PMA ouput macro power up failed\n"); -+ return false; -+ } -+ -+ /* wait for cmn_ready */ -+ for (i = 0; i < 10; i++) { -+ val = cdns_phy_reg_read(mhdp, PHY_PMA_CMN_CTRL1); -+ if (val & (1 << 0)) -+ break; -+ msleep(20); -+ } -+ if (i == 10) { -+ DRM_ERROR("PMA output ready failed\n"); -+ return false; -+ } -+ -+ for (k = 0; k < num_lanes; k++) { -+ cdns_phy_reg_write(mhdp, TX_PSC_A0 | (k << 9), 0x6791); -+ cdns_phy_reg_write(mhdp, TX_PSC_A1 | (k << 9), 0x6790); -+ cdns_phy_reg_write(mhdp, TX_PSC_A2 | (k << 9), 0x0090); -+ cdns_phy_reg_write(mhdp, TX_PSC_A3 | (k << 9), 0x0090); -+ -+ val = cdns_phy_reg_read(mhdp, RX_PSC_CAL | (k << 9)); -+ val &= 0xFFBB; -+ cdns_phy_reg_write(mhdp, RX_PSC_CAL | (k << 9), val); -+ -+ val = cdns_phy_reg_read(mhdp, RX_PSC_A0 | (k << 9)); -+ val &= 0xFFBB; -+ cdns_phy_reg_write(mhdp, RX_PSC_A0 | (k << 9), val); -+ } -+ return true; -+} -+ -+static int hdmi_phy_cfg_t28hpc(struct cdns_mhdp_device *mhdp, -+ struct drm_display_mode *mode) -+{ -+ const struct hdmi_ctrl *p_ctrl_table; -+ const struct hdmi_pll_tuning *p_pll_table; -+ const u32 refclk_freq_khz = 27000; -+ const u8 pclk_in = false; -+ u32 pixel_freq = mode->clock; -+ u32 vco_freq, char_freq; -+ u32 div_total, feedback_factor; -+ u32 i, ret; -+ -+ feedback_factor = hdmi_feedback_factor(mhdp); -+ -+ char_freq = pixel_freq * feedback_factor / 1000; -+ -+ DRM_INFO("Pixel clock: %d KHz, character clock: %d, bpc is %0d-bit.\n", -+ pixel_freq, char_freq, mhdp->video_info.color_depth); -+ -+ /* Get right row from the ctrl_table table. -+ * Check if 'pixel_freq_khz' value matches the PIXEL_CLK_FREQ column. -+ * Consider only the rows with FEEDBACK_FACTOR column matching feedback_factor. */ -+ for (i = 0; i < ARRAY_SIZE(imx8mq_ctrl_table); i++) { -+ if (feedback_factor == imx8mq_ctrl_table[i].feedback_factor && -+ pixel_freq == imx8mq_ctrl_table[i].pixel_clk_freq_min) { -+ p_ctrl_table = &imx8mq_ctrl_table[i]; -+ break; -+ } -+ } -+ if (i == ARRAY_SIZE(imx8mq_ctrl_table)) { -+ DRM_WARN("Pixel clk (%d KHz) not supported, color depth (%0d-bit)\n", -+ pixel_freq, mhdp->video_info.color_depth); -+ return 0; -+ } -+ -+ div_total = p_ctrl_table->pll_fb_div_total; -+ vco_freq = refclk_freq_khz * div_total / p_ctrl_table->cmnda_pll0_ip_div; -+ -+ /* Get right row from the imx8mq_pll_table table. -+ * Check if vco_freq_khz and feedback_div_total -+ * column matching with imx8mq_pll_table. */ -+ for (i = 0; i < ARRAY_SIZE(imx8mq_pll_table); i++) { -+ if (vco_freq == imx8mq_pll_table[i].vco_freq_min && -+ div_total == imx8mq_pll_table[i].feedback_div_total) { -+ p_pll_table = &imx8mq_pll_table[i]; -+ break; -+ } -+ } -+ if (i == ARRAY_SIZE(imx8mq_pll_table)) { -+ DRM_WARN("VCO (%d KHz) not supported\n", vco_freq); -+ return 0; -+ } -+ DRM_INFO("VCO frequency is %d KHz\n", vco_freq); -+ -+ ret = hdmi_phy_config(mhdp, p_ctrl_table, p_pll_table, pclk_in); -+ if (ret == false) -+ return 0; -+ -+ return char_freq; -+} -+ -+static int hdmi_phy_cfg_ss28fdsoi(struct cdns_mhdp_device *mhdp, -+ struct drm_display_mode *mode) -+{ -+ const struct hdmi_ctrl *p_ctrl_table; -+ const struct hdmi_pll_tuning *p_pll_table; -+ const u8 pclk_in = true; -+ u32 pixel_freq = mode->clock; -+ u32 vco_freq, char_freq; -+ u32 div_total, feedback_factor; -+ u32 ret, i; -+ -+ feedback_factor = hdmi_feedback_factor(mhdp); -+ -+ char_freq = pixel_freq * feedback_factor / 1000; -+ -+ DRM_INFO("Pixel clock: %d KHz, character clock: %d, bpc is %0d-bit.\n", -+ pixel_freq, char_freq, mhdp->video_info.color_depth); -+ -+ /* Get right row from the ctrl_table table. -+ * Check if 'pixel_freq_khz' value matches the PIXEL_CLK_FREQ column. -+ * Consider only the rows with FEEDBACK_FACTOR column matching feedback_factor. */ -+ for (i = 0; i < ARRAY_SIZE(imx8qm_ctrl_table); i++) { -+ if (feedback_factor == imx8qm_ctrl_table[i].feedback_factor && -+ pixel_freq >= imx8qm_ctrl_table[i].pixel_clk_freq_min && -+ pixel_freq <= imx8qm_ctrl_table[i].pixel_clk_freq_max) { -+ p_ctrl_table = &imx8qm_ctrl_table[i]; -+ break; -+ } -+ } -+ if (i == ARRAY_SIZE(imx8qm_ctrl_table)) { -+ DRM_WARN("Pixel clk (%d KHz) not supported, color depth (%0d-bit)\n", -+ pixel_freq, mhdp->video_info.color_depth); -+ return 0; -+ } -+ -+ div_total = p_ctrl_table->pll_fb_div_total; -+ vco_freq = pixel_freq * div_total / p_ctrl_table->cmnda_pll0_ip_div; -+ -+ /* Get right row from the imx8mq_pll_table table. -+ * Check if vco_freq_khz and feedback_div_total -+ * column matching with imx8mq_pll_table. */ -+ for (i = 0; i < ARRAY_SIZE(imx8qm_pll_table); i++) { -+ if (vco_freq >= imx8qm_pll_table[i].vco_freq_min && -+ vco_freq < imx8qm_pll_table[i].vco_freq_max && -+ div_total == imx8qm_pll_table[i].feedback_div_total) { -+ p_pll_table = &imx8qm_pll_table[i]; -+ break; -+ } -+ } -+ if (i == ARRAY_SIZE(imx8qm_pll_table)) { -+ DRM_WARN("VCO (%d KHz) not supported\n", vco_freq); -+ return 0; -+ } -+ DRM_INFO("VCO frequency is %d KHz\n", vco_freq); -+ -+ ret = hdmi_phy_config(mhdp, p_ctrl_table, p_pll_table, pclk_in); -+ if (ret == false) -+ return 0; -+ -+ return char_freq; -+} -+ -+static int hdmi_phy_power_up(struct cdns_mhdp_device *mhdp) -+{ -+ u32 val, i; -+ -+ /* set Power State to A2 */ -+ cdns_phy_reg_write(mhdp, PHY_HDP_MODE_CTRL, 0x0004); -+ -+ cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_0, 1); -+ cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_1, 1); -+ cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_2, 1); -+ cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_3, 1); -+ -+ /* Wait for Power State A2 Ack */ -+ for (i = 0; i < 10; i++) { -+ val = cdns_phy_reg_read(mhdp, PHY_HDP_MODE_CTRL); -+ if (val & (1 << 6)) -+ break; -+ msleep(20); -+ } -+ if (i == 10) { -+ dev_err(mhdp->dev, "Wait A2 Ack failed\n"); -+ return -1; -+ } -+ -+ /* Power up ARC */ -+ hdmi_arc_config(mhdp); -+ -+ /* Configure PHY in A0 mode (PHY must be in the A0 power -+ * state in order to transmit data) -+ */ -+ //cdns_phy_reg_write(mhdp, PHY_HDP_MODE_CTRL, 0x0101); //imx8mq -+ cdns_phy_reg_write(mhdp, PHY_HDP_MODE_CTRL, 0x0001); -+ -+ /* Wait for Power State A0 Ack */ -+ for (i = 0; i < 10; i++) { -+ val = cdns_phy_reg_read(mhdp, PHY_HDP_MODE_CTRL); -+ if (val & (1 << 4)) -+ break; -+ msleep(20); -+ } -+ if (i == 10) { -+ dev_err(mhdp->dev, "Wait A0 Ack failed\n"); -+ return -1; -+ } -+ return 0; -+} -+ -+bool cdns_hdmi_phy_video_valid_imx8mq(struct cdns_mhdp_device *mhdp) -+{ -+ u32 rate = mhdp->valid_mode->clock; -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(imx8mq_ctrl_table); i++) -+ if(rate == imx8mq_ctrl_table[i].pixel_clk_freq_min) -+ return true; -+ return false; -+} -+ -+int cdns_hdmi_phy_set_imx8mq(struct cdns_mhdp_device *mhdp) -+{ -+ struct drm_display_mode *mode = &mhdp->mode; -+ int ret; -+ -+ /* Check HDMI FW alive before HDMI PHY init */ -+ ret = cdns_mhdp_check_alive(mhdp); -+ if (ret == false) { -+ DRM_ERROR("NO HDMI FW running\n"); -+ return -ENXIO; -+ } -+ -+ /* Configure PHY */ -+ mhdp->hdmi.char_rate = hdmi_phy_cfg_t28hpc(mhdp, mode); -+ if (mhdp->hdmi.char_rate == 0) { -+ DRM_ERROR("failed to set phy pclock\n"); -+ return -EINVAL; -+ } -+ -+ ret = hdmi_phy_power_up(mhdp); -+ if (ret < 0) -+ return ret; -+ -+ hdmi_phy_set_vswing(mhdp); -+ -+ return true; -+} -+ -+bool cdns_hdmi_phy_video_valid_imx8qm(struct cdns_mhdp_device *mhdp) -+{ -+ u32 rate = mhdp->valid_mode->clock; -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(imx8qm_ctrl_table); i++) -+ if(rate >= imx8qm_ctrl_table[i].pixel_clk_freq_min && -+ rate <= imx8qm_ctrl_table[i].pixel_clk_freq_max) -+ return true; -+ return false; -+} -+ -+int cdns_hdmi_phy_set_imx8qm(struct cdns_mhdp_device *mhdp) -+{ -+ struct drm_display_mode *mode = &mhdp->mode; -+ int ret; -+ -+ /* Check HDMI FW alive before HDMI PHY init */ -+ ret = cdns_mhdp_check_alive(mhdp); -+ if (ret == false) { -+ DRM_ERROR("NO HDMI FW running\n"); -+ return -ENXIO; -+ } -+ -+ /* Configure PHY */ -+ mhdp->hdmi.char_rate = hdmi_phy_cfg_ss28fdsoi(mhdp, mode); -+ if (mhdp->hdmi.char_rate == 0) { -+ DRM_ERROR("failed to set phy pclock\n"); -+ return -EINVAL; -+ } -+ -+ ret = hdmi_phy_power_up(mhdp); -+ if (ret < 0) -+ return ret; -+ -+ hdmi_phy_set_vswing(mhdp); -+ -+ return true; -+} -diff --git a/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imx.h b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imx.h -new file mode 100644 -index 000000000000..fc3247dada2d ---- /dev/null -+++ b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imx.h -@@ -0,0 +1,75 @@ -+/* -+ * Cadence High-Definition Multimedia Interface (HDMI) driver -+ * -+ * Copyright (C) 2019 NXP Semiconductor, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ */ -+#ifndef CDNS_MHDP_IMX_H_ -+#define CDNS_MHDP_IMX_H_ -+ -+#include -+#include -+ -+ -+struct imx_mhdp_device; -+ -+struct imx_hdp_clks { -+ struct clk *av_pll; -+ struct clk *dig_pll; -+ struct clk *clk_ipg; -+ struct clk *clk_core; -+ struct clk *clk_pxl; -+ struct clk *clk_pxl_mux; -+ struct clk *clk_pxl_link; -+ -+ struct clk *lpcg_hdp; -+ struct clk *lpcg_msi; -+ struct clk *lpcg_pxl; -+ struct clk *lpcg_vif; -+ struct clk *lpcg_lis; -+ struct clk *lpcg_apb; -+ struct clk *lpcg_apb_csr; -+ struct clk *lpcg_apb_ctrl; -+ -+ struct clk *lpcg_i2s; -+ struct clk *clk_i2s_bypass; -+}; -+ -+struct imx_mhdp_device { -+ struct cdns_mhdp_device mhdp; -+ struct drm_encoder encoder; -+ -+ struct mutex audio_mutex; -+ spinlock_t audio_lock; -+ bool connected; -+ bool active; -+ bool suspended; -+ struct imx_hdp_clks clks; -+ const struct firmware *fw; -+ const char *firmware_name; -+ -+ int bus_type; -+ -+ struct device *pd_mhdp_dev; -+ struct device *pd_pll0_dev; -+ struct device *pd_pll1_dev; -+ struct device_link *pd_mhdp_link; -+ struct device_link *pd_pll0_link; -+ struct device_link *pd_pll1_link; -+}; -+ -+void cdns_mhdp_plat_init_imx8qm(struct cdns_mhdp_device *mhdp); -+void cdns_mhdp_plat_deinit_imx8qm(struct cdns_mhdp_device *mhdp); -+void cdns_mhdp_pclk_rate_imx8qm(struct cdns_mhdp_device *mhdp); -+int cdns_mhdp_firmware_init_imx8qm(struct cdns_mhdp_device *mhdp); -+int cdns_mhdp_resume_imx8qm(struct cdns_mhdp_device *mhdp); -+int cdns_mhdp_suspend_imx8qm(struct cdns_mhdp_device *mhdp); -+int cdns_mhdp_power_on_imx8qm(struct cdns_mhdp_device *mhdp); -+int cdns_mhdp_power_on_ls1028a(struct cdns_mhdp_device *mhdp); -+void cdns_mhdp_pclk_rate_ls1028a(struct cdns_mhdp_device *mhdp); -+#endif /* CDNS_MHDP_IMX_H_ */ -diff --git a/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imx8qm.c b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imx8qm.c -new file mode 100644 -index 000000000000..a3ba3da4b05d ---- /dev/null -+++ b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imx8qm.c -@@ -0,0 +1,638 @@ -+/* -+ * copyright (c) 2019 nxp semiconductor, inc. -+ * -+ * this program is free software; you can redistribute it and/or modify -+ * it under the terms of the gnu general public license version 2 as -+ * published by the free software foundation. -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "cdns-mhdp-imx.h" -+ -+#define FW_IRAM_OFFSET 0x2000 -+#define FW_IRAM_SIZE 0x10000 -+#define FW_DRAM_SIZE 0x8000 -+ -+#define PLL_800MHZ (800000000) -+ -+#define HDP_DUAL_MODE_MIN_PCLK_RATE 300000 /* KHz */ -+#define HDP_SINGLE_MODE_MAX_WIDTH 1920 -+ -+#define CSR_PIXEL_LINK_MUX_CTL 0x00 -+#define CSR_PIXEL_LINK_MUX_VCP_OFFSET 5 -+#define CSR_PIXEL_LINK_MUX_HCP_OFFSET 4 -+ -+static bool imx8qm_video_dual_mode(struct cdns_mhdp_device *mhdp) -+{ -+ struct drm_display_mode *mode = &mhdp->mode; -+ return (mode->clock > HDP_DUAL_MODE_MIN_PCLK_RATE || -+ mode->hdisplay > HDP_SINGLE_MODE_MAX_WIDTH) ? true : false; -+} -+ -+static void imx8qm_pixel_link_mux(struct imx_mhdp_device *imx_mhdp) -+{ -+ struct drm_display_mode *mode = &imx_mhdp->mhdp.mode; -+ bool dual_mode; -+ u32 val; -+ -+ dual_mode = imx8qm_video_dual_mode(&imx_mhdp->mhdp); -+ -+ val = 0x4; /* RGB */ -+ if (dual_mode) -+ val |= 0x2; /* pixel link 0 and 1 are active */ -+ if (mode->flags & DRM_MODE_FLAG_PVSYNC) -+ val |= 1 << CSR_PIXEL_LINK_MUX_VCP_OFFSET; -+ if (mode->flags & DRM_MODE_FLAG_PHSYNC) -+ val |= 1 << CSR_PIXEL_LINK_MUX_HCP_OFFSET; -+ if (mode->flags & DRM_MODE_FLAG_INTERLACE) -+ val |= 0x2; -+ -+ writel(val, imx_mhdp->mhdp.regs_sec); -+} -+ -+static void imx8qm_pixel_link_valid(u32 dual_mode) -+{ -+ struct imx_sc_ipc *handle; -+ -+ imx_scu_get_handle(&handle); -+ -+ imx_sc_misc_set_control(handle, IMX_SC_R_DC_0, IMX_SC_C_PXL_LINK_MST1_VLD, 1); -+ if (dual_mode) -+ imx_sc_misc_set_control(handle, IMX_SC_R_DC_0, IMX_SC_C_PXL_LINK_MST2_VLD, 1); -+} -+ -+static void imx8qm_pixel_link_invalid(u32 dual_mode) -+{ -+ struct imx_sc_ipc *handle; -+ -+ imx_scu_get_handle(&handle); -+ -+ imx_sc_misc_set_control(handle, IMX_SC_R_DC_0, IMX_SC_C_PXL_LINK_MST1_VLD, 0); -+ if (dual_mode) -+ imx_sc_misc_set_control(handle, IMX_SC_R_DC_0, IMX_SC_C_PXL_LINK_MST2_VLD, 0); -+} -+ -+static void imx8qm_pixel_link_sync_enable(u32 dual_mode) -+{ -+ struct imx_sc_ipc *handle; -+ -+ imx_scu_get_handle(&handle); -+ -+ if (dual_mode) -+ imx_sc_misc_set_control(handle, IMX_SC_R_DC_0, IMX_SC_C_SYNC_CTRL, 3); -+ else -+ imx_sc_misc_set_control(handle, IMX_SC_R_DC_0, IMX_SC_C_SYNC_CTRL0, 1); -+} -+ -+static void imx8qm_pixel_link_sync_disable(u32 dual_mode) -+{ -+ struct imx_sc_ipc *handle; -+ -+ imx_scu_get_handle(&handle); -+ -+ if (dual_mode) -+ imx_sc_misc_set_control(handle, IMX_SC_R_DC_0, IMX_SC_C_SYNC_CTRL, 0); -+ else -+ imx_sc_misc_set_control(handle, IMX_SC_R_DC_0, IMX_SC_C_SYNC_CTRL0, 0); -+} -+ -+static void imx8qm_phy_reset(u8 reset) -+{ -+ struct imx_sc_ipc *handle; -+ -+ imx_scu_get_handle(&handle); -+ -+ /* set the pixel link mode and pixel type */ -+ imx_sc_misc_set_control(handle, IMX_SC_R_HDMI, IMX_SC_C_PHY_RESET, reset); -+} -+ -+static void imx8qm_clk_mux(u8 is_dp) -+{ -+ struct imx_sc_ipc *handle; -+ -+ imx_scu_get_handle(&handle); -+ -+ if (is_dp) -+ /* Enable the 24MHz for HDP PHY */ -+ imx_sc_misc_set_control(handle, IMX_SC_R_HDMI, IMX_SC_C_MODE, 1); -+ else -+ imx_sc_misc_set_control(handle, IMX_SC_R_HDMI, IMX_SC_C_MODE, 0); -+} -+ -+int imx8qm_clocks_init(struct imx_mhdp_device *imx_mhdp) -+{ -+ struct device *dev = imx_mhdp->mhdp.dev; -+ struct imx_hdp_clks *clks = &imx_mhdp->clks; -+ -+ clks->dig_pll = devm_clk_get(dev, "dig_pll"); -+ if (IS_ERR(clks->dig_pll)) { -+ dev_warn(dev, "failed to get dig pll clk\n"); -+ return PTR_ERR(clks->dig_pll); -+ } -+ -+ clks->av_pll = devm_clk_get(dev, "av_pll"); -+ if (IS_ERR(clks->av_pll)) { -+ dev_warn(dev, "failed to get av pll clk\n"); -+ return PTR_ERR(clks->av_pll); -+ } -+ -+ clks->clk_ipg = devm_clk_get(dev, "clk_ipg"); -+ if (IS_ERR(clks->clk_ipg)) { -+ dev_warn(dev, "failed to get dp ipg clk\n"); -+ return PTR_ERR(clks->clk_ipg); -+ } -+ -+ clks->clk_core = devm_clk_get(dev, "clk_core"); -+ if (IS_ERR(clks->clk_core)) { -+ dev_warn(dev, "failed to get hdp core clk\n"); -+ return PTR_ERR(clks->clk_core); -+ } -+ -+ clks->clk_pxl = devm_clk_get(dev, "clk_pxl"); -+ if (IS_ERR(clks->clk_pxl)) { -+ dev_warn(dev, "failed to get pxl clk\n"); -+ return PTR_ERR(clks->clk_pxl); -+ } -+ -+ clks->clk_pxl_mux = devm_clk_get(dev, "clk_pxl_mux"); -+ if (IS_ERR(clks->clk_pxl_mux)) { -+ dev_warn(dev, "failed to get pxl mux clk\n"); -+ return PTR_ERR(clks->clk_pxl_mux); -+ } -+ -+ clks->clk_pxl_link = devm_clk_get(dev, "clk_pxl_link"); -+ if (IS_ERR(clks->clk_pxl_mux)) { -+ dev_warn(dev, "failed to get pxl link clk\n"); -+ return PTR_ERR(clks->clk_pxl_link); -+ } -+ -+ clks->lpcg_hdp = devm_clk_get(dev, "lpcg_hdp"); -+ if (IS_ERR(clks->lpcg_hdp)) { -+ dev_warn(dev, "failed to get lpcg hdp clk\n"); -+ return PTR_ERR(clks->lpcg_hdp); -+ } -+ -+ clks->lpcg_msi = devm_clk_get(dev, "lpcg_msi"); -+ if (IS_ERR(clks->lpcg_msi)) { -+ dev_warn(dev, "failed to get lpcg msi clk\n"); -+ return PTR_ERR(clks->lpcg_msi); -+ } -+ -+ clks->lpcg_pxl = devm_clk_get(dev, "lpcg_pxl"); -+ if (IS_ERR(clks->lpcg_pxl)) { -+ dev_warn(dev, "failed to get lpcg pxl clk\n"); -+ return PTR_ERR(clks->lpcg_pxl); -+ } -+ -+ clks->lpcg_vif = devm_clk_get(dev, "lpcg_vif"); -+ if (IS_ERR(clks->lpcg_vif)) { -+ dev_warn(dev, "failed to get lpcg vif clk\n"); -+ return PTR_ERR(clks->lpcg_vif); -+ } -+ -+ clks->lpcg_lis = devm_clk_get(dev, "lpcg_lis"); -+ if (IS_ERR(clks->lpcg_lis)) { -+ dev_warn(dev, "failed to get lpcg lis clk\n"); -+ return PTR_ERR(clks->lpcg_lis); -+ } -+ -+ clks->lpcg_apb = devm_clk_get(dev, "lpcg_apb"); -+ if (IS_ERR(clks->lpcg_apb)) { -+ dev_warn(dev, "failed to get lpcg apb clk\n"); -+ return PTR_ERR(clks->lpcg_apb); -+ } -+ -+ clks->lpcg_apb_csr = devm_clk_get(dev, "lpcg_apb_csr"); -+ if (IS_ERR(clks->lpcg_apb_csr)) { -+ dev_warn(dev, "failed to get apb csr clk\n"); -+ return PTR_ERR(clks->lpcg_apb_csr); -+ } -+ -+ clks->lpcg_apb_ctrl = devm_clk_get(dev, "lpcg_apb_ctrl"); -+ if (IS_ERR(clks->lpcg_apb_ctrl)) { -+ dev_warn(dev, "failed to get lpcg apb ctrl clk\n"); -+ return PTR_ERR(clks->lpcg_apb_ctrl); -+ } -+ -+ clks->clk_i2s_bypass = devm_clk_get(dev, "clk_i2s_bypass"); -+ if (IS_ERR(clks->clk_i2s_bypass)) { -+ dev_err(dev, "failed to get i2s bypass clk\n"); -+ return PTR_ERR(clks->clk_i2s_bypass); -+ } -+ -+ clks->lpcg_i2s = devm_clk_get(dev, "lpcg_i2s"); -+ if (IS_ERR(clks->lpcg_i2s)) { -+ dev_err(dev, "failed to get lpcg i2s clk\n"); -+ return PTR_ERR(clks->lpcg_i2s); -+ } -+ return true; -+} -+ -+static int imx8qm_pixel_clk_enable(struct imx_mhdp_device *imx_mhdp) -+{ -+ struct imx_hdp_clks *clks = &imx_mhdp->clks; -+ struct device *dev = imx_mhdp->mhdp.dev; -+ int ret; -+ -+ ret = clk_prepare_enable(clks->av_pll); -+ if (ret < 0) { -+ dev_err(dev, "%s, pre av pll error\n", __func__); -+ return ret; -+ } -+ -+ ret = clk_prepare_enable(clks->clk_pxl); -+ if (ret < 0) { -+ dev_err(dev, "%s, pre clk pxl error\n", __func__); -+ return ret; -+ } -+ ret = clk_prepare_enable(clks->clk_pxl_mux); -+ if (ret < 0) { -+ dev_err(dev, "%s, pre clk pxl mux error\n", __func__); -+ return ret; -+ } -+ -+ ret = clk_prepare_enable(clks->clk_pxl_link); -+ if (ret < 0) { -+ dev_err(dev, "%s, pre clk pxl link error\n", __func__); -+ return ret; -+ } -+ ret = clk_prepare_enable(clks->lpcg_vif); -+ if (ret < 0) { -+ dev_err(dev, "%s, pre clk vif error\n", __func__); -+ return ret; -+ } -+ ret = clk_prepare_enable(clks->lpcg_pxl); -+ if (ret < 0) { -+ dev_err(dev, "%s, pre lpcg pxl error\n", __func__); -+ return ret; -+ } -+ ret = clk_prepare_enable(clks->lpcg_hdp); -+ if (ret < 0) { -+ dev_err(dev, "%s, pre lpcg hdp error\n", __func__); -+ return ret; -+ } -+ return ret; -+} -+ -+static void imx8qm_pixel_clk_disable(struct imx_mhdp_device *imx_mhdp) -+{ -+ struct imx_hdp_clks *clks = &imx_mhdp->clks; -+ -+ clk_disable_unprepare(clks->lpcg_pxl); -+ clk_disable_unprepare(clks->lpcg_hdp); -+ clk_disable_unprepare(clks->lpcg_vif); -+ clk_disable_unprepare(clks->clk_pxl); -+ clk_disable_unprepare(clks->clk_pxl_link); -+ clk_disable_unprepare(clks->clk_pxl_mux); -+ clk_disable_unprepare(clks->av_pll); -+} -+ -+static void imx8qm_pixel_clk_set_rate(struct imx_mhdp_device *imx_mhdp, u32 pclock) -+{ -+ bool dual_mode = imx8qm_video_dual_mode(&imx_mhdp->mhdp); -+ struct imx_hdp_clks *clks = &imx_mhdp->clks; -+ -+ /* pixel clock for HDMI */ -+ clk_set_rate(clks->av_pll, pclock); -+ -+ if (dual_mode == true) { -+ clk_set_rate(clks->clk_pxl, pclock/2); -+ clk_set_rate(clks->clk_pxl_link, pclock/2); -+ } else { -+ clk_set_rate(clks->clk_pxl_link, pclock); -+ clk_set_rate(clks->clk_pxl, pclock); -+ } -+ clk_set_rate(clks->clk_pxl_mux, pclock); -+} -+ -+static int imx8qm_ipg_clk_enable(struct imx_mhdp_device *imx_mhdp) -+{ -+ int ret; -+ struct imx_hdp_clks *clks = &imx_mhdp->clks; -+ struct device *dev = imx_mhdp->mhdp.dev; -+ -+ ret = clk_prepare_enable(clks->dig_pll); -+ if (ret < 0) { -+ dev_err(dev, "%s, pre dig pll error\n", __func__); -+ return ret; -+ } -+ -+ ret = clk_prepare_enable(clks->clk_ipg); -+ if (ret < 0) { -+ dev_err(dev, "%s, pre clk_ipg error\n", __func__); -+ return ret; -+ } -+ -+ ret = clk_prepare_enable(clks->clk_core); -+ if (ret < 0) { -+ dev_err(dev, "%s, pre clk core error\n", __func__); -+ return ret; -+ } -+ -+ ret = clk_prepare_enable(clks->lpcg_apb); -+ if (ret < 0) { -+ dev_err(dev, "%s, pre clk apb error\n", __func__); -+ return ret; -+ } -+ ret = clk_prepare_enable(clks->lpcg_lis); -+ if (ret < 0) { -+ dev_err(dev, "%s, pre clk lis error\n", __func__); -+ return ret; -+ } -+ ret = clk_prepare_enable(clks->lpcg_msi); -+ if (ret < 0) { -+ dev_err(dev, "%s, pre clk msierror\n", __func__); -+ return ret; -+ } -+ ret = clk_prepare_enable(clks->lpcg_apb_csr); -+ if (ret < 0) { -+ dev_err(dev, "%s, pre clk apb csr error\n", __func__); -+ return ret; -+ } -+ ret = clk_prepare_enable(clks->lpcg_apb_ctrl); -+ if (ret < 0) { -+ dev_err(dev, "%s, pre clk apb ctrl error\n", __func__); -+ return ret; -+ } -+ ret = clk_prepare_enable(clks->lpcg_i2s); -+ if (ret < 0) { -+ dev_err(dev, "%s, pre clk i2s error\n", __func__); -+ return ret; -+ } -+ ret = clk_prepare_enable(clks->clk_i2s_bypass); -+ if (ret < 0) { -+ dev_err(dev, "%s, pre clk i2s bypass error\n", __func__); -+ return ret; -+ } -+ return ret; -+} -+ -+static void imx8qm_ipg_clk_set_rate(struct imx_mhdp_device *imx_mhdp) -+{ -+ struct imx_hdp_clks *clks = &imx_mhdp->clks; -+ -+ /* ipg/core clock */ -+ clk_set_rate(clks->dig_pll, PLL_800MHZ); -+ clk_set_rate(clks->clk_core, PLL_800MHZ/4); -+ clk_set_rate(clks->clk_ipg, PLL_800MHZ/8); -+} -+ -+static void imx8qm_detach_pm_domains(struct imx_mhdp_device *imx_mhdp) -+{ -+ if (imx_mhdp->pd_pll1_link && !IS_ERR(imx_mhdp->pd_pll1_link)) -+ device_link_del(imx_mhdp->pd_pll1_link); -+ if (imx_mhdp->pd_pll1_dev && !IS_ERR(imx_mhdp->pd_pll1_dev)) -+ dev_pm_domain_detach(imx_mhdp->pd_pll1_dev, true); -+ -+ if (imx_mhdp->pd_pll0_link && !IS_ERR(imx_mhdp->pd_pll0_link)) -+ device_link_del(imx_mhdp->pd_pll0_link); -+ if (imx_mhdp->pd_pll0_dev && !IS_ERR(imx_mhdp->pd_pll0_dev)) -+ dev_pm_domain_detach(imx_mhdp->pd_pll0_dev, true); -+ -+ if (imx_mhdp->pd_mhdp_link && !IS_ERR(imx_mhdp->pd_mhdp_link)) -+ device_link_del(imx_mhdp->pd_mhdp_link); -+ if (imx_mhdp->pd_mhdp_dev && !IS_ERR(imx_mhdp->pd_mhdp_dev)) -+ dev_pm_domain_detach(imx_mhdp->pd_mhdp_dev, true); -+ -+ imx_mhdp->pd_mhdp_dev = NULL; -+ imx_mhdp->pd_mhdp_link = NULL; -+ imx_mhdp->pd_pll0_dev = NULL; -+ imx_mhdp->pd_pll0_link = NULL; -+ imx_mhdp->pd_pll1_dev = NULL; -+ imx_mhdp->pd_pll1_link = NULL; -+} -+ -+static int imx8qm_attach_pm_domains(struct imx_mhdp_device *imx_mhdp) -+{ -+ struct device *dev = imx_mhdp->mhdp.dev; -+ u32 flags = DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE; -+ int ret = 0; -+ -+ imx_mhdp->pd_mhdp_dev = dev_pm_domain_attach_by_name(dev, "hdmi"); -+ if (IS_ERR(imx_mhdp->pd_mhdp_dev)) { -+ ret = PTR_ERR(imx_mhdp->pd_mhdp_dev); -+ dev_err(dev, "Failed to attach dc pd dev: %d\n", ret); -+ goto fail; -+ } -+ imx_mhdp->pd_mhdp_link = device_link_add(dev, imx_mhdp->pd_mhdp_dev, flags); -+ if (IS_ERR(imx_mhdp->pd_mhdp_link)) { -+ ret = PTR_ERR(imx_mhdp->pd_mhdp_link); -+ dev_err(dev, "Failed to add device link to dc pd dev: %d\n", -+ ret); -+ goto fail; -+ } -+ -+ imx_mhdp->pd_pll0_dev = dev_pm_domain_attach_by_name(dev, "pll0"); -+ if (IS_ERR(imx_mhdp->pd_pll0_dev)) { -+ ret = PTR_ERR(imx_mhdp->pd_pll0_dev); -+ dev_err(dev, "Failed to attach pll0 pd dev: %d\n", ret); -+ goto fail; -+ } -+ imx_mhdp->pd_pll0_link = device_link_add(dev, imx_mhdp->pd_pll0_dev, flags); -+ if (IS_ERR(imx_mhdp->pd_pll0_link)) { -+ ret = PTR_ERR(imx_mhdp->pd_pll0_link); -+ dev_err(dev, "Failed to add device link to pll0 pd dev: %d\n", -+ ret); -+ goto fail; -+ } -+ -+ imx_mhdp->pd_pll1_dev = dev_pm_domain_attach_by_name(dev, "pll1"); -+ if (IS_ERR(imx_mhdp->pd_pll1_dev)) { -+ ret = PTR_ERR(imx_mhdp->pd_pll1_dev); -+ dev_err(dev, "Failed to attach pll0 pd dev: %d\n", ret); -+ goto fail; -+ } -+ imx_mhdp->pd_pll1_link = device_link_add(dev, imx_mhdp->pd_pll1_dev, flags); -+ if (IS_ERR(imx_mhdp->pd_pll1_link)) { -+ ret = PTR_ERR(imx_mhdp->pd_pll1_link); -+ dev_err(dev, "Failed to add device link to pll1 pd dev: %d\n", -+ ret); -+ goto fail; -+ } -+fail: -+ imx8qm_detach_pm_domains(imx_mhdp); -+ return ret; -+} -+ -+int cdns_mhdp_power_on_imx8qm(struct cdns_mhdp_device *mhdp) -+{ -+ struct imx_mhdp_device *imx_mhdp = -+ container_of(mhdp, struct imx_mhdp_device, mhdp); -+ /* Power on PM Domains */ -+ -+ imx8qm_attach_pm_domains(imx_mhdp); -+ -+ /* clock init and rate set */ -+ imx8qm_clocks_init(imx_mhdp); -+ -+ imx8qm_ipg_clk_set_rate(imx_mhdp); -+ -+ /* Init pixel clock with 148.5MHz before FW init */ -+ imx8qm_pixel_clk_set_rate(imx_mhdp, 148500000); -+ -+ imx8qm_ipg_clk_enable(imx_mhdp); -+ -+ imx8qm_clk_mux(imx_mhdp->mhdp.plat_data->is_dp); -+ -+ imx8qm_pixel_clk_enable(imx_mhdp); -+ -+ imx8qm_phy_reset(1); -+ -+ return 0; -+} -+ -+void cdns_mhdp_plat_init_imx8qm(struct cdns_mhdp_device *mhdp) -+{ -+ struct imx_mhdp_device *imx_mhdp = -+ container_of(mhdp, struct imx_mhdp_device, mhdp); -+ bool dual_mode = imx8qm_video_dual_mode(&imx_mhdp->mhdp); -+ -+ imx8qm_pixel_link_sync_disable(dual_mode); -+ imx8qm_pixel_link_invalid(dual_mode); -+} -+ -+void cdns_mhdp_plat_deinit_imx8qm(struct cdns_mhdp_device *mhdp) -+{ -+ struct imx_mhdp_device *imx_mhdp = -+ container_of(mhdp, struct imx_mhdp_device, mhdp); -+ bool dual_mode = imx8qm_video_dual_mode(&imx_mhdp->mhdp); -+ -+ imx8qm_pixel_link_valid(dual_mode); -+ imx8qm_pixel_link_sync_enable(dual_mode); -+} -+ -+void cdns_mhdp_pclk_rate_imx8qm(struct cdns_mhdp_device *mhdp) -+{ -+ struct imx_mhdp_device *imx_mhdp = -+ container_of(mhdp, struct imx_mhdp_device, mhdp); -+ -+ /* set pixel clock before video mode setup */ -+ imx8qm_pixel_clk_disable(imx_mhdp); -+ -+ imx8qm_pixel_clk_set_rate(imx_mhdp, imx_mhdp->mhdp.mode.clock * 1000); -+ -+ imx8qm_pixel_clk_enable(imx_mhdp); -+ -+ /* Config pixel link mux */ -+ imx8qm_pixel_link_mux(imx_mhdp); -+} -+ -+int cdns_mhdp_firmware_write_section(struct imx_mhdp_device *imx_mhdp, -+ const u8 *data, int size, int addr) -+{ -+ int i; -+ -+ for (i = 0; i < size; i += 4) { -+ u32 val = (unsigned int)data[i] << 0 | -+ (unsigned int)data[i + 1] << 8 | -+ (unsigned int)data[i + 2] << 16 | -+ (unsigned int)data[i + 3] << 24; -+ cdns_mhdp_bus_write(val, &imx_mhdp->mhdp, addr + i); -+ } -+ -+ return 0; -+} -+ -+static void cdns_mhdp_firmware_load_cont(const struct firmware *fw, void *context) -+{ -+ struct imx_mhdp_device *imx_mhdp = context; -+ -+ imx_mhdp->fw = fw; -+} -+ -+static int cdns_mhdp_firmware_load(struct imx_mhdp_device *imx_mhdp) -+{ -+ const u8 *iram; -+ const u8 *dram; -+ u32 rate; -+ int ret; -+ -+ /* configure HDMI/DP core clock */ -+ rate = clk_get_rate(imx_mhdp->clks.clk_core); -+ if (imx_mhdp->mhdp.is_ls1028a) -+ rate = rate / 4; -+ -+ cdns_mhdp_set_fw_clk(&imx_mhdp->mhdp, rate); -+ -+ /* skip fw loading if none is specified */ -+ if (!imx_mhdp->firmware_name) -+ goto out; -+ -+ if (!imx_mhdp->fw) { -+ ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_NOUEVENT, -+ imx_mhdp->firmware_name, -+ imx_mhdp->mhdp.dev, GFP_KERNEL, -+ imx_mhdp, -+ cdns_mhdp_firmware_load_cont); -+ if (ret < 0) { -+ DRM_ERROR("failed to load firmware\n"); -+ return -ENOENT; -+ } -+ } else { -+ iram = imx_mhdp->fw->data + FW_IRAM_OFFSET; -+ dram = iram + FW_IRAM_SIZE; -+ -+ cdns_mhdp_firmware_write_section(imx_mhdp, iram, FW_IRAM_SIZE, ADDR_IMEM); -+ cdns_mhdp_firmware_write_section(imx_mhdp, dram, FW_DRAM_SIZE, ADDR_DMEM); -+ } -+ -+out: -+ /* un-reset ucpu */ -+ cdns_mhdp_bus_write(0, &imx_mhdp->mhdp, APB_CTRL); -+ DRM_INFO("Started firmware!\n"); -+ -+ return 0; -+} -+ -+int cdns_mhdp_firmware_init_imx8qm(struct cdns_mhdp_device *mhdp) -+{ -+ struct imx_mhdp_device *imx_mhdp = -+ container_of(mhdp, struct imx_mhdp_device, mhdp); -+ int ret; -+ -+ /* load firmware */ -+ ret = cdns_mhdp_firmware_load(imx_mhdp); -+ if (ret) -+ return ret; -+ -+ ret = cdns_mhdp_check_alive(&imx_mhdp->mhdp); -+ if (ret == false) { -+ DRM_ERROR("NO HDMI FW running\n"); -+ return -ENXIO; -+ } -+ -+ /* turn on IP activity */ -+ cdns_mhdp_set_firmware_active(&imx_mhdp->mhdp, 1); -+ -+ DRM_INFO("HDP FW Version - ver %d verlib %d\n", -+ cdns_mhdp_bus_read(mhdp, VER_L) + (cdns_mhdp_bus_read(mhdp, VER_H) << 8), -+ cdns_mhdp_bus_read(mhdp, VER_LIB_H_ADDR) + (cdns_mhdp_bus_read(mhdp, VER_LIB_H_ADDR) << 8)); -+ -+ return 0; -+} -+ -+int cdns_mhdp_suspend_imx8qm(struct cdns_mhdp_device *mhdp) -+{ -+ struct imx_mhdp_device *imx_mhdp = -+ container_of(mhdp, struct imx_mhdp_device, mhdp); -+ -+ imx8qm_pixel_clk_disable(imx_mhdp); -+ -+ return 0; -+} -+ -+int cdns_mhdp_resume_imx8qm(struct cdns_mhdp_device *mhdp) -+{ -+ struct imx_mhdp_device *imx_mhdp = -+ container_of(mhdp, struct imx_mhdp_device, mhdp); -+ -+ imx8qm_pixel_clk_enable(imx_mhdp); -+ -+ return cdns_mhdp_firmware_init_imx8qm(mhdp); -+} -diff --git a/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imxdrv.c b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imxdrv.c -new file mode 100644 -index 000000000000..3acbdf575ee2 ---- /dev/null -+++ b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imxdrv.c -@@ -0,0 +1,259 @@ -+/* -+ * copyright (c) 2019 nxp semiconductor, inc. -+ * -+ * this program is free software; you can redistribute it and/or modify -+ * it under the terms of the gnu general public license version 2 as -+ * published by the free software foundation. -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#include "cdns-mhdp-imx.h" -+#include "cdns-mhdp-phy.h" -+#include "../ipuv3/imx-drm.h" -+ -+static void cdns_mhdp_imx_encoder_disable(struct drm_encoder *encoder) -+{ -+ struct drm_bridge *bridge = drm_bridge_chain_get_first_bridge(encoder); -+ struct cdns_mhdp_device *mhdp = bridge->driver_private; -+ -+ cdns_mhdp_plat_call(mhdp, plat_init); -+} -+ -+static void cdns_mhdp_imx_encoder_enable(struct drm_encoder *encoder) -+{ -+ struct drm_bridge *bridge = drm_bridge_chain_get_first_bridge(encoder); -+ struct cdns_mhdp_device *mhdp = bridge->driver_private; -+ -+ cdns_mhdp_plat_call(mhdp, plat_deinit); -+} -+ -+static int cdns_mhdp_imx_encoder_atomic_check(struct drm_encoder *encoder, -+ struct drm_crtc_state *crtc_state, -+ struct drm_connector_state *conn_state) -+{ -+ struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc_state); -+ struct drm_bridge *bridge = drm_bridge_chain_get_first_bridge(encoder); -+ struct cdns_mhdp_device *mhdp = bridge->driver_private; -+ -+ if (mhdp->plat_data->video_format != 0) -+ imx_crtc_state->bus_format = mhdp->plat_data->video_format; -+ -+ if (mhdp->force_mode_set) -+ crtc_state->mode_changed = true; -+ -+ return 0; -+} -+ -+static const struct drm_encoder_helper_funcs cdns_mhdp_imx_encoder_helper_funcs = { -+ .enable = cdns_mhdp_imx_encoder_enable, -+ .disable = cdns_mhdp_imx_encoder_disable, -+ .atomic_check = cdns_mhdp_imx_encoder_atomic_check, -+}; -+ -+static const struct drm_encoder_funcs cdns_mhdp_imx_encoder_funcs = { -+ .destroy = drm_encoder_cleanup, -+}; -+ -+static struct cdns_plat_data imx8mq_hdmi_drv_data = { -+ .plat_name = "imx8mq-hdmi", -+ .bind = cdns_hdmi_bind, -+ .unbind = cdns_hdmi_unbind, -+ .phy_set = cdns_hdmi_phy_set_imx8mq, -+ .phy_video_valid = cdns_hdmi_phy_video_valid_imx8mq, -+ .bus_type = BUS_TYPE_NORMAL_APB, -+}; -+ -+static struct cdns_plat_data imx8mq_dp_drv_data = { -+ .plat_name = "imx8mq-dp", -+ .bind = cdns_dp_bind, -+ .unbind = cdns_dp_unbind, -+ .phy_set = cdns_dp_phy_set_imx8mq, -+ .bus_type = BUS_TYPE_NORMAL_APB, -+}; -+ -+static struct cdns_plat_data imx8qm_hdmi_drv_data = { -+ .plat_name = "imx8qm-hdmi", -+ .bind = cdns_hdmi_bind, -+ .unbind = cdns_hdmi_unbind, -+ .phy_set = cdns_hdmi_phy_set_imx8qm, -+ .phy_video_valid = cdns_hdmi_phy_video_valid_imx8qm, -+ .power_on = cdns_mhdp_power_on_imx8qm, -+ .firmware_init = cdns_mhdp_firmware_init_imx8qm, -+ .resume = cdns_mhdp_resume_imx8qm, -+ .suspend = cdns_mhdp_suspend_imx8qm, -+ .pclk_rate = cdns_mhdp_pclk_rate_imx8qm, -+ .plat_init = cdns_mhdp_plat_init_imx8qm, -+ .plat_deinit = cdns_mhdp_plat_deinit_imx8qm, -+ .bus_type = BUS_TYPE_LOW4K_APB, -+ .video_format = MEDIA_BUS_FMT_RGB101010_1X30, -+}; -+ -+static struct cdns_plat_data imx8qm_dp_drv_data = { -+ .plat_name = "imx8qm-dp", -+ .bind = cdns_dp_bind, -+ .unbind = cdns_dp_unbind, -+ .phy_set = cdns_dp_phy_set_imx8qm, -+ .power_on = cdns_mhdp_power_on_imx8qm, -+ .firmware_init = cdns_mhdp_firmware_init_imx8qm, -+ .pclk_rate = cdns_mhdp_pclk_rate_imx8qm, -+ .plat_init = cdns_mhdp_plat_init_imx8qm, -+ .plat_deinit = cdns_mhdp_plat_deinit_imx8qm, -+ .bus_type = BUS_TYPE_LOW4K_APB, -+ .video_format = MEDIA_BUS_FMT_RGB101010_1X30, -+ .is_dp = true, -+}; -+ -+static struct cdns_plat_data ls1028a_dp_drv_data = { -+ .bind = cdns_dp_bind, -+ .unbind = cdns_dp_unbind, -+ .phy_set = cdns_dp_phy_set_imx8mq, -+ .power_on = cdns_mhdp_power_on_ls1028a, -+ .firmware_init = cdns_mhdp_firmware_init_imx8qm, -+ .pclk_rate = cdns_mhdp_pclk_rate_ls1028a, -+ .bus_type = BUS_TYPE_NORMAL_APB, -+}; -+ -+static const struct of_device_id cdns_mhdp_imx_dt_ids[] = { -+ { .compatible = "cdn,imx8mq-hdmi", -+ .data = &imx8mq_hdmi_drv_data -+ }, -+ { .compatible = "cdn,imx8mq-dp", -+ .data = &imx8mq_dp_drv_data -+ }, -+ { .compatible = "cdn,imx8qm-hdmi", -+ .data = &imx8qm_hdmi_drv_data -+ }, -+ { .compatible = "cdn,imx8qm-dp", -+ .data = &imx8qm_dp_drv_data -+ }, -+ { .compatible = "cdn,ls1028a-dp", -+ .data = &ls1028a_dp_drv_data -+ }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, cdns_mhdp_imx_dt_ids); -+ -+static int cdns_mhdp_imx_bind(struct device *dev, struct device *master, -+ void *data) -+{ -+ struct platform_device *pdev = to_platform_device(dev); -+ const struct cdns_plat_data *plat_data; -+ const struct of_device_id *match; -+ struct drm_device *drm = data; -+ struct drm_encoder *encoder; -+ struct imx_mhdp_device *imx_mhdp; -+ int ret; -+ -+ if (!pdev->dev.of_node) -+ return -ENODEV; -+ -+ imx_mhdp = devm_kzalloc(&pdev->dev, sizeof(*imx_mhdp), GFP_KERNEL); -+ if (!imx_mhdp) -+ return -ENOMEM; -+ -+ match = of_match_node(cdns_mhdp_imx_dt_ids, pdev->dev.of_node); -+ plat_data = match->data; -+ encoder = &imx_mhdp->encoder; -+ -+ encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node); -+ -+ ret = of_property_read_string(pdev->dev.of_node, "firmware-name", -+ &imx_mhdp->firmware_name); -+ /* -+ * If we failed to find the CRTC(s) which this encoder is -+ * supposed to be connected to, it's because the CRTC has -+ * not been registered yet. Defer probing, and hope that -+ * the required CRTC is added later. -+ */ -+ if (encoder->possible_crtcs == 0) -+ return -EPROBE_DEFER; -+ -+ drm_encoder_helper_add(encoder, &cdns_mhdp_imx_encoder_helper_funcs); -+ drm_encoder_init(drm, encoder, &cdns_mhdp_imx_encoder_funcs, -+ DRM_MODE_ENCODER_TMDS, NULL); -+ -+ -+ imx_mhdp->mhdp.plat_data = plat_data; -+ imx_mhdp->mhdp.dev = dev; -+ imx_mhdp->mhdp.bus_type = plat_data->bus_type; -+ ret = plat_data->bind(pdev, encoder, &imx_mhdp->mhdp); -+ /* -+ * If cdns_mhdp_bind() fails we'll never call cdns_mhdp_unbind(), -+ * which would have called the encoder cleanup. Do it manually. -+ */ -+ if (ret < 0) -+ drm_encoder_cleanup(encoder); -+ -+ return ret; -+} -+ -+static void cdns_mhdp_imx_unbind(struct device *dev, struct device *master, -+ void *data) -+{ -+ struct imx_mhdp_device *imx_mhdp = dev_get_drvdata(dev); -+ -+ imx_mhdp->mhdp.plat_data->unbind(dev); -+} -+ -+static const struct component_ops cdns_mhdp_imx_ops = { -+ .bind = cdns_mhdp_imx_bind, -+ .unbind = cdns_mhdp_imx_unbind, -+}; -+ -+static int cdns_mhdp_imx_suspend(struct device *dev) -+{ -+ struct imx_mhdp_device *imx_mhdp = dev_get_drvdata(dev); -+ -+ cdns_mhdp_plat_call(&imx_mhdp->mhdp, suspend); -+ -+ return 0; -+} -+ -+static int cdns_mhdp_imx_resume(struct device *dev) -+{ -+ struct imx_mhdp_device *imx_mhdp = dev_get_drvdata(dev); -+ -+ cdns_mhdp_plat_call(&imx_mhdp->mhdp, resume); -+ -+ return 0; -+} -+ -+static int cdns_mhdp_imx_probe(struct platform_device *pdev) -+{ -+ return component_add(&pdev->dev, &cdns_mhdp_imx_ops); -+} -+ -+static int cdns_mhdp_imx_remove(struct platform_device *pdev) -+{ -+ component_del(&pdev->dev, &cdns_mhdp_imx_ops); -+ -+ return 0; -+} -+ -+static const struct dev_pm_ops cdns_mhdp_imx_pm_ops = { -+ SET_LATE_SYSTEM_SLEEP_PM_OPS(cdns_mhdp_imx_suspend, cdns_mhdp_imx_resume) -+}; -+ -+static struct platform_driver cdns_mhdp_imx_platform_driver = { -+ .probe = cdns_mhdp_imx_probe, -+ .remove = cdns_mhdp_imx_remove, -+ .driver = { -+ .name = "cdns-mhdp-imx", -+ .of_match_table = cdns_mhdp_imx_dt_ids, -+ .pm = &cdns_mhdp_imx_pm_ops, -+ }, -+}; -+ -+module_platform_driver(cdns_mhdp_imx_platform_driver); -+ -+MODULE_AUTHOR("Sandor YU "); -+MODULE_LICENSE("GPL"); -+MODULE_ALIAS("platform:cdnhdmi-imx"); -diff --git a/drivers/gpu/drm/imx/mhdp/cdns-mhdp-ls1028a.c b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-ls1028a.c -new file mode 100644 -index 000000000000..4cc71301f5fe ---- /dev/null -+++ b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-ls1028a.c -@@ -0,0 +1,110 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright 2019 NXP -+ * -+ */ -+#include -+#include -+#include -+#include -+#include -+ -+#include "cdns-mhdp-imx.h" -+ -+static const struct of_device_id scfg_device_ids[] = { -+ { .compatible = "fsl,ls1028a-scfg", }, -+ {} -+}; -+ -+static void ls1028a_phy_reset(u8 reset) -+{ -+ struct device_node *scfg_node; -+ void __iomem *scfg_base = NULL; -+ -+ scfg_node = of_find_matching_node(NULL, scfg_device_ids); -+ if (scfg_node) -+ scfg_base = of_iomap(scfg_node, 0); -+ -+ iowrite32(reset, scfg_base + 0x230); -+} -+ -+int ls1028a_clocks_init(struct imx_mhdp_device *imx_mhdp) -+{ -+ struct device *dev = imx_mhdp->mhdp.dev; -+ struct imx_hdp_clks *clks = &imx_mhdp->clks; -+ -+ clks->clk_core = devm_clk_get(dev, "clk_core"); -+ if (IS_ERR(clks->clk_core)) { -+ dev_warn(dev, "failed to get hdp core clk\n"); -+ return PTR_ERR(clks->clk_core); -+ } -+ -+ clks->clk_pxl = devm_clk_get(dev, "clk_pxl"); -+ if (IS_ERR(clks->clk_pxl)) { -+ dev_warn(dev, "failed to get pxl clk\n"); -+ return PTR_ERR(clks->clk_pxl); -+ } -+ -+ return true; -+} -+ -+static int ls1028a_pixel_clk_enable(struct imx_mhdp_device *imx_mhdp) -+{ -+ struct imx_hdp_clks *clks = &imx_mhdp->clks; -+ struct device *dev = imx_mhdp->mhdp.dev; -+ int ret; -+ -+ ret = clk_prepare_enable(clks->clk_pxl); -+ if (ret < 0) { -+ dev_err(dev, "%s, pre clk pxl error\n", __func__); -+ return ret; -+ } -+ -+ return ret; -+} -+ -+static void ls1028a_pixel_clk_disable(struct imx_mhdp_device *imx_mhdp) -+{ -+ struct imx_hdp_clks *clks = &imx_mhdp->clks; -+ -+ clk_disable_unprepare(clks->clk_pxl); -+} -+ -+static void ls1028a_pixel_clk_set_rate(struct imx_mhdp_device *imx_mhdp, -+ u32 pclock) -+{ -+ struct imx_hdp_clks *clks = &imx_mhdp->clks; -+ -+ clk_set_rate(clks->clk_pxl, pclock); -+} -+ -+int cdns_mhdp_power_on_ls1028a(struct cdns_mhdp_device *mhdp) -+{ -+ struct imx_mhdp_device *imx_mhdp = container_of -+ (mhdp, struct imx_mhdp_device, mhdp); -+ -+ /* clock init and rate set */ -+ ls1028a_clocks_init(imx_mhdp); -+ -+ ls1028a_pixel_clk_enable(imx_mhdp); -+ -+ /* Init pixel clock with 148.5MHz before FW init */ -+ ls1028a_pixel_clk_set_rate(imx_mhdp, 148500000); -+ -+ ls1028a_phy_reset(1); -+ -+ return 0; -+} -+ -+void cdns_mhdp_pclk_rate_ls1028a(struct cdns_mhdp_device *mhdp) -+{ -+ struct imx_mhdp_device *imx_mhdp = container_of -+ (mhdp, struct imx_mhdp_device, mhdp); -+ -+ /* set pixel clock before video mode setup */ -+ ls1028a_pixel_clk_disable(imx_mhdp); -+ -+ ls1028a_pixel_clk_set_rate(imx_mhdp, imx_mhdp->mhdp.mode.clock * 1000); -+ -+ ls1028a_pixel_clk_enable(imx_mhdp); -+} -diff --git a/drivers/gpu/drm/imx/mhdp/cdns-mhdp-phy.h b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-phy.h -new file mode 100644 -index 000000000000..5682b9fbc90f ---- /dev/null -+++ b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-phy.h -@@ -0,0 +1,155 @@ -+/* -+ * Copyright (C) 2019 NXP Semiconductor, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ */ -+ -+#ifndef _CDN_DP_PHY_H -+#define _CDN_DP_PHY_H -+ -+#include -+ -+#define CMN_SSM_BIAS_TMR 0x0022 -+#define CMN_PLLSM0_PLLEN_TMR 0x0029 -+#define CMN_PLLSM0_PLLPRE_TMR 0x002A -+#define CMN_PLLSM0_PLLVREF_TMR 0x002B -+#define CMN_PLLSM0_PLLLOCK_TMR 0x002C -+#define CMN_PLLSM0_USER_DEF_CTRL 0x002F -+#define CMN_PSM_CLK_CTRL 0x0061 -+#define CMN_CDIAG_REFCLK_CTRL 0x0062 -+#define CMN_PLL0_VCOCAL_START 0x0081 -+#define CMN_PLL0_VCOCAL_INIT_TMR 0x0084 -+#define CMN_PLL0_VCOCAL_ITER_TMR 0x0085 -+#define CMN_PLL0_INTDIV 0x0094 -+#define CMN_PLL0_FRACDIV 0x0095 -+#define CMN_PLL0_HIGH_THR 0x0096 -+#define CMN_PLL0_DSM_DIAG 0x0097 -+#define CMN_PLL0_SS_CTRL1 0x0098 -+#define CMN_PLL0_SS_CTRL2 0x0099 -+#define CMN_ICAL_INIT_TMR 0x00C4 -+#define CMN_ICAL_ITER_TMR 0x00C5 -+#define CMN_RXCAL_INIT_TMR 0x00D4 -+#define CMN_RXCAL_ITER_TMR 0x00D5 -+#define CMN_TXPUCAL_CTRL 0x00E0 -+#define CMN_TXPUCAL_INIT_TMR 0x00E4 -+#define CMN_TXPUCAL_ITER_TMR 0x00E5 -+#define CMN_TXPDCAL_CTRL 0x00F0 -+#define CMN_TXPDCAL_INIT_TMR 0x00F4 -+#define CMN_TXPDCAL_ITER_TMR 0x00F5 -+#define CMN_ICAL_ADJ_INIT_TMR 0x0102 -+#define CMN_ICAL_ADJ_ITER_TMR 0x0103 -+#define CMN_RX_ADJ_INIT_TMR 0x0106 -+#define CMN_RX_ADJ_ITER_TMR 0x0107 -+#define CMN_TXPU_ADJ_CTRL 0x0108 -+#define CMN_TXPU_ADJ_INIT_TMR 0x010A -+#define CMN_TXPU_ADJ_ITER_TMR 0x010B -+#define CMN_TXPD_ADJ_CTRL 0x010c -+#define CMN_TXPD_ADJ_INIT_TMR 0x010E -+#define CMN_TXPD_ADJ_ITER_TMR 0x010F -+#define CMN_DIAG_PLL0_FBH_OVRD 0x01C0 -+#define CMN_DIAG_PLL0_FBL_OVRD 0x01C1 -+#define CMN_DIAG_PLL0_OVRD 0x01C2 -+#define CMN_DIAG_PLL0_TEST_MODE 0x01C4 -+#define CMN_DIAG_PLL0_V2I_TUNE 0x01C5 -+#define CMN_DIAG_PLL0_CP_TUNE 0x01C6 -+#define CMN_DIAG_PLL0_LF_PROG 0x01C7 -+#define CMN_DIAG_PLL0_PTATIS_TUNE1 0x01C8 -+#define CMN_DIAG_PLL0_PTATIS_TUNE2 0x01C9 -+#define CMN_DIAG_PLL0_INCLK_CTRL 0x01CA -+#define CMN_DIAG_PLL0_PXL_DIVH 0x01CB -+#define CMN_DIAG_PLL0_PXL_DIVL 0x01CC -+#define CMN_DIAG_HSCLK_SEL 0x01E0 -+#define CMN_DIAG_PER_CAL_ADJ 0x01EC -+#define CMN_DIAG_CAL_CTRL 0x01ED -+#define CMN_DIAG_ACYA 0x01FF -+#define XCVR_PSM_RCTRL 0x4001 -+#define XCVR_PSM_CAL_TMR 0x4002 -+#define XCVR_PSM_A0IN_TMR 0x4003 -+#define TX_TXCC_CAL_SCLR_MULT_0 0x4047 -+#define TX_TXCC_CPOST_MULT_00_0 0x404C -+#define TX_TXCC_MGNFS_MULT_000_0 0x4050 -+#define XCVR_DIAG_PLLDRC_CTRL 0x40E0 -+#define XCVR_DIAG_PLLDRC_CTRL 0x40E0 -+#define XCVR_DIAG_HSCLK_SEL 0x40E1 -+#define XCVR_DIAG_BIDI_CTRL 0x40E8 -+#define XCVR_DIAG_LANE_FCM_EN_MGN_TMR 0x40F2 -+#define XCVR_DIAG_LANE_FCM_EN_MGN 0x40F2 -+#define TX_PSC_A0 0x4100 -+#define TX_PSC_A1 0x4101 -+#define TX_PSC_A2 0x4102 -+#define TX_PSC_A3 0x4103 -+#define TX_RCVDET_CTRL 0x4120 -+#define TX_RCVDET_EN_TMR 0x4122 -+#define TX_RCVDET_EN_TMR 0x4122 -+#define TX_RCVDET_ST_TMR 0x4123 -+#define TX_RCVDET_ST_TMR 0x4123 -+#define TX_BIST_CTRL 0x4140 -+#define TX_BIST_UDDWR 0x4141 -+#define TX_DIAG_TX_CTRL 0x41E0 -+#define TX_DIAG_TX_DRV 0x41E1 -+#define TX_DIAG_BGREF_PREDRV_DELAY 0x41E7 -+#define TX_DIAG_BGREF_PREDRV_DELAY 0x41E7 -+#define XCVR_PSM_RCTRL_1 0x4201 -+#define TX_TXCC_CAL_SCLR_MULT_1 0x4247 -+#define TX_TXCC_CPOST_MULT_00_1 0x424C -+#define TX_TXCC_MGNFS_MULT_000_1 0x4250 -+#define XCVR_DIAG_PLLDRC_CTRL_1 0x42E0 -+#define XCVR_DIAG_HSCLK_SEL_1 0x42E1 -+#define XCVR_DIAG_LANE_FCM_EN_MGN_TMR_1 0x42F2 -+#define TX_RCVDET_EN_TMR_1 0x4322 -+#define TX_RCVDET_ST_TMR_1 0x4323 -+#define TX_DIAG_ACYA_0 0x41FF -+#define TX_DIAG_ACYA_1 0x43FF -+#define TX_DIAG_ACYA_2 0x45FF -+#define TX_DIAG_ACYA_3 0x47FF -+#define TX_ANA_CTRL_REG_1 0x5020 -+#define TX_ANA_CTRL_REG_2 0x5021 -+#define TXDA_COEFF_CALC 0x5022 -+#define TX_DIG_CTRL_REG_1 0x5023 -+#define TX_DIG_CTRL_REG_2 0x5024 -+#define TXDA_CYA_AUXDA_CYA 0x5025 -+#define TX_ANA_CTRL_REG_3 0x5026 -+#define TX_ANA_CTRL_REG_4 0x5027 -+#define TX_ANA_CTRL_REG_5 0x5029 -+#define RX_PSC_A0 0x8000 -+#define RX_PSC_CAL 0x8006 -+#define PMA_LANE_CFG 0xC000 -+#define PIPE_CMN_CTRL1 0xC001 -+#define PIPE_CMN_CTRL2 0xC002 -+#define PIPE_COM_LOCK_CFG1 0xC003 -+#define PIPE_COM_LOCK_CFG2 0xC004 -+#define PIPE_RCV_DET_INH 0xC005 -+#define PHY_HDP_MODE_CTRL 0xC008 -+#define PHY_HDP_CLK_CTL 0xC009 -+#define STS 0xC00F -+#define PHY_ISO_CMN_CTRL 0xC010 -+#define PHY_ISO_CMN_CTRL 0xC010 -+#define PHY_HDP_TX_CTL_L0 0xC408 -+#define PHY_DP_TX_CTL 0xC408 -+#define PHY_HDP_TX_CTL_L1 0xC448 -+#define PHY_HDP_TX_CTL_L2 0xC488 -+#define PHY_HDP_TX_CTL_L3 0xC4C8 -+#define PHY_PMA_CMN_CTRL1 0xC800 -+#define PMA_CMN_CTRL1 0xC800 -+#define PHY_PMA_ISO_CMN_CTRL 0xC810 -+#define PHY_PMA_ISO_PLL_CTRL1 0xC812 -+#define PHY_PMA_ISOLATION_CTRL 0xC81F -+#define PHY_ISOLATION_CTRL 0xC81F -+#define PHY_PMA_ISO_XCVR_CTRL 0xCC11 -+#define PHY_PMA_ISO_LINK_MODE 0xCC12 -+#define PHY_PMA_ISO_PWRST_CTRL 0xCC13 -+#define PHY_PMA_ISO_TX_DATA_LO 0xCC14 -+#define PHY_PMA_ISO_TX_DATA_HI 0xCC15 -+#define PHY_PMA_ISO_RX_DATA_LO 0xCC16 -+#define PHY_PMA_ISO_RX_DATA_HI 0xCC17 -+ -+int cdns_dp_phy_set_imx8mq(struct cdns_mhdp_device *hdp); -+int cdns_dp_phy_set_imx8qm(struct cdns_mhdp_device *hdp); -+bool cdns_hdmi_phy_video_valid_imx8mq(struct cdns_mhdp_device *hdp); -+bool cdns_hdmi_phy_video_valid_imx8qm(struct cdns_mhdp_device *hdp); -+int cdns_hdmi_phy_set_imx8mq(struct cdns_mhdp_device *hdp); -+int cdns_hdmi_phy_set_imx8qm(struct cdns_mhdp_device *hdp); -+#endif /* _CDNS_MHDP_PHY_H */ --- -2.29.2 - diff --git a/projects/NXP/devices/iMX8/patches/linux/0031-LF-1514-drm-cdns-mhdp-check-link-rate-index.patch b/projects/NXP/devices/iMX8/patches/linux/0031-LF-1514-drm-cdns-mhdp-check-link-rate-index.patch deleted file mode 100644 index 180ec68d82..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0031-LF-1514-drm-cdns-mhdp-check-link-rate-index.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 8aa7d7baa5eb142261ddafc91b0ba884aa670421 Mon Sep 17 00:00:00 2001 -From: Sandor Yu -Date: Fri, 19 Jun 2020 16:17:55 +0800 -Subject: [PATCH 31/49] LF-1514: drm: cdns-mhdp: check link rate index - -Check link rate index to advoid negative array index read. -report by Coverity ID:6652950 6652949. - -Signed-off-by: Sandor Yu -Reviewed-by: Fancy Fang ---- - drivers/gpu/drm/imx/mhdp/cdns-mhdp-dp-phy.c | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/drivers/gpu/drm/imx/mhdp/cdns-mhdp-dp-phy.c b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-dp-phy.c -index a6d03c94d196..5c75e7d40cc0 100644 ---- a/drivers/gpu/drm/imx/mhdp/cdns-mhdp-dp-phy.c -+++ b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-dp-phy.c -@@ -198,6 +198,10 @@ static void dp_phy_pma_cmn_pll0_24mhz(struct cdns_mhdp_device *mhdp) - - /* DP PHY PLL 24MHz configuration */ - index = link_rate_index(link_rate); -+ if (index < 0) { -+ dev_err(mhdp->dev, "wrong link rate index\n"); -+ return; -+ } - for (i = 0; i < ARRAY_SIZE(phy_pll_24m_cfg); i++) - cdns_phy_reg_write(mhdp, phy_pll_24m_cfg[i].addr, phy_pll_24m_cfg[i].val[index]); - -@@ -320,6 +324,10 @@ static void dp_phy_pma_cmn_pll0_27mhz(struct cdns_mhdp_device *mhdp) - - /* DP PHY PLL 27MHz configuration */ - index = link_rate_index(link_rate); -+ if (index < 0) { -+ dev_err(mhdp->dev, "wrong link rate index\n"); -+ return; -+ } - for (i = 0; i < ARRAY_SIZE(phy_pll_27m_cfg); i++) - cdns_phy_reg_write(mhdp, phy_pll_27m_cfg[i].addr, phy_pll_27m_cfg[i].val[index]); - --- -2.29.2 - diff --git a/projects/NXP/devices/iMX8/patches/linux/0032-LF-1516-drm-cdns-mhdp-fix-error-check-variable-name-.patch b/projects/NXP/devices/iMX8/patches/linux/0032-LF-1516-drm-cdns-mhdp-fix-error-check-variable-name-.patch deleted file mode 100644 index f42d867842..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0032-LF-1516-drm-cdns-mhdp-fix-error-check-variable-name-.patch +++ /dev/null @@ -1,31 +0,0 @@ -From b2ea44969c5e51a5809622384728859d7f3a2b8a Mon Sep 17 00:00:00 2001 -From: Sandor Yu -Date: Fri, 19 Jun 2020 16:25:51 +0800 -Subject: [PATCH 32/49] LF-1516: drm: cdns-mhdp: fix error check variable name - for clk_pxl_link - -fix error check variable name for clk_pxl_link. -Report by Coverity ID:6652947 - -Signed-off-by: Sandor Yu -Reviewed-by: Fancy Fang ---- - drivers/gpu/drm/imx/mhdp/cdns-mhdp-imx8qm.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imx8qm.c b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imx8qm.c -index a3ba3da4b05d..2ee4e8748b77 100644 ---- a/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imx8qm.c -+++ b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imx8qm.c -@@ -167,7 +167,7 @@ int imx8qm_clocks_init(struct imx_mhdp_device *imx_mhdp) - } - - clks->clk_pxl_link = devm_clk_get(dev, "clk_pxl_link"); -- if (IS_ERR(clks->clk_pxl_mux)) { -+ if (IS_ERR(clks->clk_pxl_link)) { - dev_warn(dev, "failed to get pxl link clk\n"); - return PTR_ERR(clks->clk_pxl_link); - } --- -2.29.2 - diff --git a/projects/NXP/devices/iMX8/patches/linux/0033-MLK-24601-drm-imx-mhdp-DP-PHY-support-1-2-lanes-mode.patch b/projects/NXP/devices/iMX8/patches/linux/0033-MLK-24601-drm-imx-mhdp-DP-PHY-support-1-2-lanes-mode.patch deleted file mode 100644 index f3076760c9..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0033-MLK-24601-drm-imx-mhdp-DP-PHY-support-1-2-lanes-mode.patch +++ /dev/null @@ -1,58 +0,0 @@ -From c789945d09e4c77eb30af1a8db1425cefab52080 Mon Sep 17 00:00:00 2001 -From: Sandor Yu -Date: Fri, 28 Aug 2020 10:09:12 +0800 -Subject: [PATCH 33/49] MLK-24601: drm: imx: mhdp: DP PHY support 1/2 lanes - mode - -All four lanes should be configurated for 1/2/4 lanes modes in driver. -The DP FW will power down unused PHY lanes after negotiation. - -Signed-off-by: Sandor Yu -Reviewed-by: Robby Cai ---- - drivers/gpu/drm/imx/mhdp/cdns-mhdp-dp-phy.c | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - -diff --git a/drivers/gpu/drm/imx/mhdp/cdns-mhdp-dp-phy.c b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-dp-phy.c -index 5c75e7d40cc0..3d17840b0941 100644 ---- a/drivers/gpu/drm/imx/mhdp/cdns-mhdp-dp-phy.c -+++ b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-dp-phy.c -@@ -137,7 +137,7 @@ static void dp_aux_cfg(struct cdns_mhdp_device *mhdp) - static void dp_phy_pma_cmn_cfg_24mhz(struct cdns_mhdp_device *mhdp) - { - int k; -- u32 num_lanes = mhdp->dp.num_lanes; -+ u32 num_lanes = 4; - u16 val; - - val = cdns_phy_reg_read(mhdp, PHY_PMA_CMN_CTRL1); -@@ -157,7 +157,7 @@ static void dp_phy_pma_cmn_cfg_24mhz(struct cdns_mhdp_device *mhdp) - /* Valid for 24 MHz only */ - static void dp_phy_pma_cmn_pll0_24mhz(struct cdns_mhdp_device *mhdp) - { -- u32 num_lanes = mhdp->dp.num_lanes; -+ u32 num_lanes = 4; - u32 link_rate = mhdp->dp.rate; - u16 val; - int index, i, k; -@@ -228,7 +228,7 @@ static void dp_phy_pma_cmn_pll0_24mhz(struct cdns_mhdp_device *mhdp) - /* PMA common configuration for 27MHz */ - static void dp_phy_pma_cmn_cfg_27mhz(struct cdns_mhdp_device *mhdp) - { -- u32 num_lanes = mhdp->dp.num_lanes; -+ u32 num_lanes = 4; - u16 val; - int k; - -@@ -279,7 +279,7 @@ static void dp_phy_pma_cmn_cfg_27mhz(struct cdns_mhdp_device *mhdp) - - static void dp_phy_pma_cmn_pll0_27mhz(struct cdns_mhdp_device *mhdp) - { -- u32 num_lanes = mhdp->dp.num_lanes; -+ u32 num_lanes = 4; - u32 link_rate = mhdp->dp.rate; - u16 val; - int index, i, k; --- -2.29.2 - diff --git a/projects/NXP/devices/iMX8/patches/linux/0034-MLK-24519-2-gpu-imx-Increase-maximum-single-pipe-wid.patch b/projects/NXP/devices/iMX8/patches/linux/0034-MLK-24519-2-gpu-imx-Increase-maximum-single-pipe-wid.patch deleted file mode 100644 index 799824c90b..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0034-MLK-24519-2-gpu-imx-Increase-maximum-single-pipe-wid.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 7772a57acd0e05353caead7eb7d064e36bcb92e6 Mon Sep 17 00:00:00 2001 -From: Sandor Yu -Date: Sun, 20 Sep 2020 19:32:28 +0800 -Subject: [PATCH 34/49] MLK-24519-2 gpu: imx: Increase maximum single pipe - width to 2560 - -This patch increase the DPU single pipe maximum from 1920 to 2560 for HDMI/DP. - -Signed-off-by: Oliver F. Brown -Reviewed-by: Liu Ying ---- - drivers/gpu/drm/imx/mhdp/cdns-mhdp-imx8qm.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imx8qm.c b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imx8qm.c -index 2ee4e8748b77..cda4d245bab8 100644 ---- a/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imx8qm.c -+++ b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imx8qm.c -@@ -22,7 +22,7 @@ - #define PLL_800MHZ (800000000) - - #define HDP_DUAL_MODE_MIN_PCLK_RATE 300000 /* KHz */ --#define HDP_SINGLE_MODE_MAX_WIDTH 1920 -+#define HDP_SINGLE_MODE_MAX_WIDTH 2560 - - #define CSR_PIXEL_LINK_MUX_CTL 0x00 - #define CSR_PIXEL_LINK_MUX_VCP_OFFSET 5 --- -2.29.2 - diff --git a/projects/NXP/devices/iMX8/patches/linux/0035-MLK-24072-drm-imx8-correct-mhdp-files-copyright.patch b/projects/NXP/devices/iMX8/patches/linux/0035-MLK-24072-drm-imx8-correct-mhdp-files-copyright.patch deleted file mode 100644 index 987690f888..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0035-MLK-24072-drm-imx8-correct-mhdp-files-copyright.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 60077991d60b1ba96e52d5a6568ae65ae7143ee2 Mon Sep 17 00:00:00 2001 -From: Sandor Yu -Date: Wed, 20 May 2020 10:56:53 +0800 -Subject: [PATCH 35/49] MLK-24072: drm: imx8: correct mhdp files copyright - -Correct mhdp files copyright. - -Signed-off-by: Sandor Yu -Reviewed-by: Robby Cai ---- - drivers/gpu/drm/imx/mhdp/cdns-mhdp-imx8qm.c | 2 +- - drivers/gpu/drm/imx/mhdp/cdns-mhdp-imxdrv.c | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) - -diff --git a/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imx8qm.c b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imx8qm.c -index cda4d245bab8..38f9defa42f8 100644 ---- a/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imx8qm.c -+++ b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imx8qm.c -@@ -1,5 +1,5 @@ - /* -- * copyright (c) 2019 nxp semiconductor, inc. -+ * Copyright (c) 2019 NXP semiconductor, inc. - * - * 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 -diff --git a/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imxdrv.c b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imxdrv.c -index 3acbdf575ee2..cc429fe48abd 100644 ---- a/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imxdrv.c -+++ b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imxdrv.c -@@ -1,5 +1,5 @@ - /* -- * copyright (c) 2019 nxp semiconductor, inc. -+ * Copyright (c) 2019 NXP semiconductor, inc. - * - * 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 --- -2.29.2 - diff --git a/projects/NXP/devices/iMX8/patches/linux/0036-LF-2744-drm-cdns-reset-force_mode_set-flag-in-atomic.patch b/projects/NXP/devices/iMX8/patches/linux/0036-LF-2744-drm-cdns-reset-force_mode_set-flag-in-atomic.patch deleted file mode 100644 index 8586df89c8..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0036-LF-2744-drm-cdns-reset-force_mode_set-flag-in-atomic.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 93502b984119af556f8a204bf80a62bc1c21fbfd Mon Sep 17 00:00:00 2001 -From: Sandor Yu -Date: Tue, 17 Nov 2020 15:47:36 +0800 -Subject: [PATCH 36/49] LF-2744: drm: cdns: reset force_mode_set flag in - atomic_check - -Reset force_mode_set flag in atomic_check function -to avoid set mode_changed flag multi times when cable plugin. - -Signed-off-by: Sandor Yu -Reviewed-by: Robby Cai ---- - drivers/gpu/drm/imx/mhdp/cdns-mhdp-imxdrv.c | 7 +++++-- - 1 file changed, 5 insertions(+), 2 deletions(-) - -diff --git a/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imxdrv.c b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imxdrv.c -index cc429fe48abd..9fa0df74ad7c 100644 ---- a/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imxdrv.c -+++ b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imxdrv.c -@@ -1,5 +1,5 @@ - /* -- * Copyright (c) 2019 NXP semiconductor, inc. -+ * Copyright (c) 2019-2020 NXP semiconductor, inc. - * - * 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 -@@ -44,8 +44,11 @@ static int cdns_mhdp_imx_encoder_atomic_check(struct drm_encoder *encoder, - if (mhdp->plat_data->video_format != 0) - imx_crtc_state->bus_format = mhdp->plat_data->video_format; - -- if (mhdp->force_mode_set) -+ if (mhdp->force_mode_set) { - crtc_state->mode_changed = true; -+ /* reset force mode set flag */ -+ mhdp->force_mode_set = false; -+ } - - return 0; - } --- -2.29.2 - diff --git a/projects/NXP/devices/iMX8/patches/linux/0037-MLK-25199-1-drm-mhdp-Add-hdmi-phy-reset-poweroff-fun.patch b/projects/NXP/devices/iMX8/patches/linux/0037-MLK-25199-1-drm-mhdp-Add-hdmi-phy-reset-poweroff-fun.patch deleted file mode 100644 index e70e44eb2e..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0037-MLK-25199-1-drm-mhdp-Add-hdmi-phy-reset-poweroff-fun.patch +++ /dev/null @@ -1,161 +0,0 @@ -From 38f1f4ecd038628f4ce7a47114455123e5db3367 Mon Sep 17 00:00:00 2001 -From: Sandor Yu -Date: Wed, 30 Dec 2020 16:02:52 +0800 -Subject: [PATCH 37/49] MLK-25199-1: drm: mhdp: Add hdmi phy reset/poweroff - function - -Add hdmi phy reset and power off function. - -Signed-off-by: Sandor Yu -Reviewed-by: Robby Cai ---- - drivers/gpu/drm/imx/mhdp/cdns-mhdp-hdmi-phy.c | 28 ++++++++++++++++++- - drivers/gpu/drm/imx/mhdp/cdns-mhdp-imx.h | 3 +- - drivers/gpu/drm/imx/mhdp/cdns-mhdp-imx8qm.c | 4 +-- - drivers/gpu/drm/imx/mhdp/cdns-mhdp-imxdrv.c | 2 ++ - drivers/gpu/drm/imx/mhdp/cdns-mhdp-phy.h | 3 +- - 5 files changed, 35 insertions(+), 5 deletions(-) - -diff --git a/drivers/gpu/drm/imx/mhdp/cdns-mhdp-hdmi-phy.c b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-hdmi-phy.c -index 120300e6a2df..212f3f4f1e26 100644 ---- a/drivers/gpu/drm/imx/mhdp/cdns-mhdp-hdmi-phy.c -+++ b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-hdmi-phy.c -@@ -1,7 +1,7 @@ - /* - * Cadence High-Definition Multimedia Interface (HDMI) driver - * -- * Copyright (C) 2019 NXP Semiconductor, Inc. -+ * Copyright (C) 2019-2021 NXP Semiconductor, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -21,6 +21,7 @@ - - #include - #include "cdns-mhdp-phy.h" -+#include "cdns-mhdp-imx.h" - - /* HDMI TX clock control settings */ - struct hdmi_ctrl { -@@ -746,6 +747,7 @@ int cdns_hdmi_phy_set_imx8qm(struct cdns_mhdp_device *mhdp) - DRM_ERROR("NO HDMI FW running\n"); - return -ENXIO; - } -+ imx8qm_phy_reset(0); - - /* Configure PHY */ - mhdp->hdmi.char_rate = hdmi_phy_cfg_ss28fdsoi(mhdp, mode); -@@ -753,6 +755,7 @@ int cdns_hdmi_phy_set_imx8qm(struct cdns_mhdp_device *mhdp) - DRM_ERROR("failed to set phy pclock\n"); - return -EINVAL; - } -+ imx8qm_phy_reset(1); - - ret = hdmi_phy_power_up(mhdp); - if (ret < 0) -@@ -762,3 +765,26 @@ int cdns_hdmi_phy_set_imx8qm(struct cdns_mhdp_device *mhdp) - - return true; - } -+ -+int cdns_hdmi_phy_shutdown(struct cdns_mhdp_device *mhdp) -+{ -+ int timeout; -+ u32 reg_val; -+ -+ reg_val = cdns_phy_reg_read(mhdp, PHY_HDP_MODE_CTRL); -+ reg_val &= 0xfff0; -+ /* PHY_DP_MODE_CTL set to A3 power state*/ -+ cdns_phy_reg_write(mhdp, PHY_HDP_MODE_CTRL, reg_val | 0x8); -+ -+ /* PHY_DP_MODE_CTL */ -+ timeout = 0; -+ do { -+ reg_val = cdns_phy_reg_read(mhdp, PHY_HDP_MODE_CTRL); -+ DRM_INFO("Reg val is 0x%04x\n", reg_val); -+ timeout++; -+ msleep(100); -+ } while (!(reg_val & (0x8 << 4)) && (timeout < 10)); /* Wait for A3 acknowledge */ -+ -+ DRM_INFO("hdmi phy shutdown complete\n"); -+ return 0; -+} -diff --git a/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imx.h b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imx.h -index fc3247dada2d..a12005ae4c53 100644 ---- a/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imx.h -+++ b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imx.h -@@ -1,7 +1,7 @@ - /* - * Cadence High-Definition Multimedia Interface (HDMI) driver - * -- * Copyright (C) 2019 NXP Semiconductor, Inc. -+ * Copyright (C) 2019-2021 NXP Semiconductor, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -72,4 +72,5 @@ int cdns_mhdp_suspend_imx8qm(struct cdns_mhdp_device *mhdp); - int cdns_mhdp_power_on_imx8qm(struct cdns_mhdp_device *mhdp); - int cdns_mhdp_power_on_ls1028a(struct cdns_mhdp_device *mhdp); - void cdns_mhdp_pclk_rate_ls1028a(struct cdns_mhdp_device *mhdp); -+void imx8qm_phy_reset(u8 reset); - #endif /* CDNS_MHDP_IMX_H_ */ -diff --git a/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imx8qm.c b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imx8qm.c -index 38f9defa42f8..46c0500da4c3 100644 ---- a/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imx8qm.c -+++ b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imx8qm.c -@@ -1,5 +1,5 @@ - /* -- * Copyright (c) 2019 NXP semiconductor, inc. -+ * Copyright (c) 2019-2021 NXP semiconductor, inc. - * - * 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 -@@ -102,7 +102,7 @@ static void imx8qm_pixel_link_sync_disable(u32 dual_mode) - imx_sc_misc_set_control(handle, IMX_SC_R_DC_0, IMX_SC_C_SYNC_CTRL0, 0); - } - --static void imx8qm_phy_reset(u8 reset) -+void imx8qm_phy_reset(u8 reset) - { - struct imx_sc_ipc *handle; - -diff --git a/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imxdrv.c b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imxdrv.c -index 9fa0df74ad7c..4c4ce9d3c847 100644 ---- a/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imxdrv.c -+++ b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imxdrv.c -@@ -22,6 +22,7 @@ static void cdns_mhdp_imx_encoder_disable(struct drm_encoder *encoder) - struct drm_bridge *bridge = drm_bridge_chain_get_first_bridge(encoder); - struct cdns_mhdp_device *mhdp = bridge->driver_private; - -+ cdns_hdmi_phy_shutdown(mhdp); - cdns_mhdp_plat_call(mhdp, plat_init); - } - -@@ -184,6 +185,7 @@ static int cdns_mhdp_imx_bind(struct device *dev, struct device *master, - - imx_mhdp->mhdp.plat_data = plat_data; - imx_mhdp->mhdp.dev = dev; -+ imx_mhdp->mhdp.drm_dev = drm; - imx_mhdp->mhdp.bus_type = plat_data->bus_type; - ret = plat_data->bind(pdev, encoder, &imx_mhdp->mhdp); - /* -diff --git a/drivers/gpu/drm/imx/mhdp/cdns-mhdp-phy.h b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-phy.h -index 5682b9fbc90f..9035f1f71eee 100644 ---- a/drivers/gpu/drm/imx/mhdp/cdns-mhdp-phy.h -+++ b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-phy.h -@@ -1,5 +1,5 @@ - /* -- * Copyright (C) 2019 NXP Semiconductor, Inc. -+ * Copyright (C) 2019-2021 NXP Semiconductor, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -152,4 +152,5 @@ bool cdns_hdmi_phy_video_valid_imx8mq(struct cdns_mhdp_device *hdp); - bool cdns_hdmi_phy_video_valid_imx8qm(struct cdns_mhdp_device *hdp); - int cdns_hdmi_phy_set_imx8mq(struct cdns_mhdp_device *hdp); - int cdns_hdmi_phy_set_imx8qm(struct cdns_mhdp_device *hdp); -+int cdns_hdmi_phy_shutdown(struct cdns_mhdp_device *mhdp); - #endif /* _CDNS_MHDP_PHY_H */ --- -2.29.2 - diff --git a/projects/NXP/devices/iMX8/patches/linux/0038-MLK-25199-2-drm-mhdp-Fix-typo-for-hdmi-phy-configura.patch b/projects/NXP/devices/iMX8/patches/linux/0038-MLK-25199-2-drm-mhdp-Fix-typo-for-hdmi-phy-configura.patch deleted file mode 100644 index 9fc25f46f8..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0038-MLK-25199-2-drm-mhdp-Fix-typo-for-hdmi-phy-configura.patch +++ /dev/null @@ -1,38 +0,0 @@ -From d77cbee9949eda85baba634bdf6c6c2afe0b64e4 Mon Sep 17 00:00:00 2001 -From: Sandor Yu -Date: Thu, 31 Dec 2020 10:13:55 +0800 -Subject: [PATCH 38/49] MLK-25199-2: drm: mhdp: Fix typo for hdmi phy - configuration table - -Fix typo for imx8qm hdmi phy configuration table. - -Signed-off-by: Sandor Yu -Reviewed-by: Robby Cai ---- - drivers/gpu/drm/imx/mhdp/cdns-mhdp-hdmi-phy.c | 10 +++++----- - 1 file changed, 5 insertions(+), 5 deletions(-) - -diff --git a/drivers/gpu/drm/imx/mhdp/cdns-mhdp-hdmi-phy.c b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-hdmi-phy.c -index 212f3f4f1e26..f96b200885df 100644 ---- a/drivers/gpu/drm/imx/mhdp/cdns-mhdp-hdmi-phy.c -+++ b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-hdmi-phy.c -@@ -95,11 +95,11 @@ static const struct hdmi_ctrl imx8qm_ctrl_table[] = { - { 85000, 170000, 1000, 850000, 1700000, 0x11, 0x00, 0x07, 340, 0x146, 0x00A, 0, 0, 0, 1700000, 3400000, 0, 1, 1, 2, 2, 0x01, 85000, 170000}, - {170000, 340000, 1000, 1700000, 3400000, 0x22, 0x01, 0x07, 340, 0x146, 0x00A, 0, 0, 0, 1700000, 3400000, 0, 1, 1, 2, 1, 0x00, 170000, 340000}, - {340000, 600000, 1000, 3400000, 6000000, 0x3C, 0x03, 0x06, 600, 0x24A, 0x00A, 0, 0, 0, 3400000, 6000000, 1, 1, 1, 2, 1, 0x00, 340000, 600000}, --{ 25000, 34000, 1205, 312500, 425000, 0x04, 0x01, 0x01, 400, 0x182, 0x00A, 0, 0, 0, 2500000, 3400000, 0, 2, 2, 2, 4, 0x03, 31250, 42500}, --{ 34000, 68000, 1205, 425000, 850000, 0x06, 0x02, 0x01, 300, 0x11E, 0x00A, 0, 0, 0, 1700000, 3400000, 0, 1, 1, 2, 4, 0x02, 42500, 85000}, --{ 68000, 136000, 1205, 850000, 1700000, 0x0D, 0x02, 0x02, 325, 0x137, 0x00A, 0, 0, 0, 1700000, 3400000, 0, 1, 1, 2, 2, 0x01, 85000, 170000}, --{136000, 272000, 1205, 1700000, 3400000, 0x1A, 0x02, 0x04, 325, 0x137, 0x00A, 0, 0, 0, 1700000, 3400000, 0, 1, 1, 2, 1, 0x00, 170000, 340000}, --{272000, 480000, 1205, 3400000, 6000000, 0x30, 0x03, 0x05, 600, 0x24A, 0x00A, 0, 0, 0, 3400000, 6000000, 1, 1, 1, 2, 1, 0x00, 340000, 600000}, -+{ 25000, 34000, 1250, 312500, 425000, 0x04, 0x01, 0x01, 400, 0x182, 0x00A, 0, 0, 0, 2500000, 3400000, 0, 2, 2, 2, 4, 0x03, 31250, 42500}, -+{ 34000, 68000, 1250, 425000, 850000, 0x06, 0x02, 0x01, 300, 0x11E, 0x00A, 0, 0, 0, 1700000, 3400000, 0, 1, 1, 2, 4, 0x02, 42500, 85000}, -+{ 68000, 136000, 1250, 850000, 1700000, 0x0D, 0x02, 0x02, 325, 0x137, 0x00A, 0, 0, 0, 1700000, 3400000, 0, 1, 1, 2, 2, 0x01, 85000, 170000}, -+{136000, 272000, 1250, 1700000, 3400000, 0x1A, 0x02, 0x04, 325, 0x137, 0x00A, 0, 0, 0, 1700000, 3400000, 0, 1, 1, 2, 1, 0x00, 170000, 340000}, -+{272000, 480000, 1250, 3400000, 6000000, 0x30, 0x03, 0x05, 600, 0x24A, 0x00A, 0, 0, 0, 3400000, 6000000, 1, 1, 1, 2, 1, 0x00, 340000, 600000}, - { 25000, 28000, 1500, 375000, 420000, 0x03, 0x01, 0x01, 360, 0x15A, 0x00A, 0, 0, 0, 3000000, 3360000, 0, 2, 2, 2, 4, 0x03, 37500, 42000}, - { 28000, 56000, 1500, 420000, 840000, 0x06, 0x02, 0x01, 360, 0x15A, 0x00A, 0, 0, 0, 1680000, 3360000, 0, 1, 1, 2, 4, 0x02, 42000, 84000}, - { 56000, 113000, 1500, 840000, 1695000, 0x0B, 0x00, 0x05, 330, 0x13C, 0x00A, 0, 0, 0, 1680000, 3390000, 0, 1, 1, 2, 2, 0x01, 84000, 169500}, --- -2.29.2 - diff --git a/projects/NXP/devices/iMX8/patches/linux/0040-drm-imx-dcss-use-the-external-27MHz-phy-clock.patch b/projects/NXP/devices/iMX8/patches/linux/0040-drm-imx-dcss-use-the-external-27MHz-phy-clock.patch deleted file mode 100644 index 2bd14ddf27..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0040-drm-imx-dcss-use-the-external-27MHz-phy-clock.patch +++ /dev/null @@ -1,108 +0,0 @@ -From c2af9b24bfa69ffb12e72153f89ed3bb3245fafb Mon Sep 17 00:00:00 2001 -From: Laurentiu Palcu -Date: Fri, 22 Nov 2019 10:00:56 +0200 -Subject: [PATCH 40/49] drm/imx/dcss: use the external 27MHz phy clock - -The 27MHz external oscillator offers a high precision low jitter clock and -is suitable for high pixel clocks modes(ie 4K@60). - -Signed-off-by: Laurentiu Palcu ---- - drivers/gpu/drm/imx/dcss/dcss-dev.c | 25 +++++++++++++++++++------ - drivers/gpu/drm/imx/dcss/dcss-dtg.c | 11 +++++++++++ - 2 files changed, 30 insertions(+), 6 deletions(-) - -diff --git a/drivers/gpu/drm/imx/dcss/dcss-dev.c b/drivers/gpu/drm/imx/dcss/dcss-dev.c -index c849533ca83e..1977f6b058f8 100644 ---- a/drivers/gpu/drm/imx/dcss/dcss-dev.c -+++ b/drivers/gpu/drm/imx/dcss/dcss-dev.c -@@ -17,6 +17,11 @@ - - static void dcss_clocks_enable(struct dcss_dev *dcss) - { -+ if (dcss->hdmi_output) { -+ clk_prepare_enable(dcss->pll_phy_ref_clk); -+ clk_prepare_enable(dcss->pll_src_clk); -+ } -+ - clk_prepare_enable(dcss->axi_clk); - clk_prepare_enable(dcss->apb_clk); - clk_prepare_enable(dcss->rtrm_clk); -@@ -31,6 +36,11 @@ static void dcss_clocks_disable(struct dcss_dev *dcss) - clk_disable_unprepare(dcss->rtrm_clk); - clk_disable_unprepare(dcss->apb_clk); - clk_disable_unprepare(dcss->axi_clk); -+ -+ if (dcss->hdmi_output) { -+ clk_disable_unprepare(dcss->pll_src_clk); -+ clk_disable_unprepare(dcss->pll_phy_ref_clk); -+ } - } - - static void dcss_disable_dtg_and_ss_cb(void *data) -@@ -133,17 +143,20 @@ static int dcss_clks_init(struct dcss_dev *dcss) - struct { - const char *id; - struct clk **clk; -+ bool required; - } clks[] = { -- {"apb", &dcss->apb_clk}, -- {"axi", &dcss->axi_clk}, -- {"pix", &dcss->pix_clk}, -- {"rtrm", &dcss->rtrm_clk}, -- {"dtrc", &dcss->dtrc_clk}, -+ {"apb", &dcss->apb_clk, true}, -+ {"axi", &dcss->axi_clk, true}, -+ {"pix", &dcss->pix_clk, true}, -+ {"rtrm", &dcss->rtrm_clk, true}, -+ {"dtrc", &dcss->dtrc_clk, true}, -+ {"pll_src", &dcss->pll_src_clk, dcss->hdmi_output}, -+ {"pll_phy_ref", &dcss->pll_phy_ref_clk, dcss->hdmi_output}, - }; - - for (i = 0; i < ARRAY_SIZE(clks); i++) { - *clks[i].clk = devm_clk_get(dcss->dev, clks[i].id); -- if (IS_ERR(*clks[i].clk)) { -+ if (IS_ERR(*clks[i].clk) && clks[i].required) { - dev_err(dcss->dev, "failed to get %s clock\n", - clks[i].id); - return PTR_ERR(*clks[i].clk); -diff --git a/drivers/gpu/drm/imx/dcss/dcss-dtg.c b/drivers/gpu/drm/imx/dcss/dcss-dtg.c -index 30de00540f63..b70785d69ad9 100644 ---- a/drivers/gpu/drm/imx/dcss/dcss-dtg.c -+++ b/drivers/gpu/drm/imx/dcss/dcss-dtg.c -@@ -83,6 +83,7 @@ struct dcss_dtg { - u32 ctx_id; - - bool in_use; -+ bool hdmi_output; - - u32 dis_ulc_x; - u32 dis_ulc_y; -@@ -159,6 +160,7 @@ int dcss_dtg_init(struct dcss_dev *dcss, unsigned long dtg_base) - dcss->dtg = dtg; - dtg->dev = dcss->dev; - dtg->ctxld = dcss->ctxld; -+ dtg->hdmi_output = dcss->hdmi_output; - - dtg->base_reg = ioremap(dtg_base, SZ_4K); - if (!dtg->base_reg) { -@@ -221,6 +223,15 @@ void dcss_dtg_sync_set(struct dcss_dtg *dtg, struct videomode *vm) - vm->vactive - 1; - - clk_disable_unprepare(dcss->pix_clk); -+ if (dcss->hdmi_output) { -+ int err; -+ -+ clk_disable_unprepare(dcss->pll_src_clk); -+ err = clk_set_parent(dcss->pll_src_clk, dcss->pll_phy_ref_clk); -+ if (err < 0) -+ dev_warn(dcss->dev, "clk_set_parent() returned %d", err); -+ clk_prepare_enable(dcss->pll_src_clk); -+ } - clk_set_rate(dcss->pix_clk, vm->pixelclock); - clk_prepare_enable(dcss->pix_clk); - --- -2.29.2 - diff --git a/projects/NXP/devices/iMX8/patches/linux/0041-drm-imx-dcss-add-component-framework-functionality.patch b/projects/NXP/devices/iMX8/patches/linux/0041-drm-imx-dcss-add-component-framework-functionality.patch deleted file mode 100644 index 5709ab1a84..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0041-drm-imx-dcss-add-component-framework-functionality.patch +++ /dev/null @@ -1,228 +0,0 @@ -From ec59d2988d1ac50acea0fdaa63513f216ddf016d Mon Sep 17 00:00:00 2001 -From: Laurentiu Palcu -Date: Thu, 9 Jul 2020 19:47:31 +0300 -Subject: [PATCH 41/49] drm/imx/dcss: add component framework functionality - -Component framework is needed by HDP driver. - -Signed-off-by: Laurentiu Palcu ---- - drivers/gpu/drm/imx/dcss/dcss-drv.c | 89 ++++++++++++++++++++++------- - drivers/gpu/drm/imx/dcss/dcss-kms.c | 23 +++++--- - drivers/gpu/drm/imx/dcss/dcss-kms.h | 4 +- - 3 files changed, 85 insertions(+), 31 deletions(-) - -diff --git a/drivers/gpu/drm/imx/dcss/dcss-drv.c b/drivers/gpu/drm/imx/dcss/dcss-drv.c -index 8dc2f85c514b..09d0ac28e28a 100644 ---- a/drivers/gpu/drm/imx/dcss/dcss-drv.c -+++ b/drivers/gpu/drm/imx/dcss/dcss-drv.c -@@ -8,6 +8,7 @@ - #include - #include - #include -+#include - #include - - #include "dcss-dev.h" -@@ -16,6 +17,8 @@ - struct dcss_drv { - struct dcss_dev *dcss; - struct dcss_kms_dev *kms; -+ -+ bool is_componentized; - }; - - struct dcss_dev *dcss_drv_dev_to_dcss(struct device *dev) -@@ -32,30 +35,18 @@ struct drm_device *dcss_drv_dev_to_drm(struct device *dev) - return mdrv ? &mdrv->kms->base : NULL; - } - --static int dcss_drv_platform_probe(struct platform_device *pdev) -+static int dcss_drv_init(struct device *dev, bool componentized) - { -- struct device *dev = &pdev->dev; -- struct device_node *remote; - struct dcss_drv *mdrv; - int err = 0; -- bool hdmi_output = true; -- -- if (!dev->of_node) -- return -ENODEV; -- -- remote = of_graph_get_remote_node(dev->of_node, 0, 0); -- if (!remote) -- return -ENODEV; -- -- hdmi_output = !of_device_is_compatible(remote, "fsl,imx8mq-nwl-dsi"); -- -- of_node_put(remote); - - mdrv = devm_kzalloc(dev, sizeof(*mdrv), GFP_KERNEL); - if (!mdrv) - return -ENOMEM; - -- mdrv->dcss = dcss_dev_create(dev, hdmi_output); -+ mdrv->is_componentized = componentized; -+ -+ mdrv->dcss = dcss_dev_create(dev, componentized); - if (IS_ERR(mdrv->dcss)) - return PTR_ERR(mdrv->dcss); - -@@ -61,7 +52,7 @@ static int dcss_drv_platform_probe(struct platform_device *pdev) - - dev_set_drvdata(dev, mdrv); - -- mdrv->kms = dcss_kms_attach(mdrv->dcss); -+ mdrv->kms = dcss_kms_attach(mdrv->dcss, componentized); - if (IS_ERR(mdrv->kms)) { - err = PTR_ERR(mdrv->kms); - dev_err_probe(dev, err, "Failed to initialize KMS\n"); -@@ -76,12 +67,66 @@ static int dcss_drv_platform_probe(struct platform_device *pdev) - return err; - } - --static void dcss_drv_platform_remove(struct platform_device *pdev) -+static void dcss_drv_deinit(struct device *dev, bool componentized) - { -- struct dcss_drv *mdrv = dev_get_drvdata(&pdev->dev); -+ struct dcss_drv *mdrv = dev_get_drvdata(dev); - -- dcss_kms_detach(mdrv->kms); -+ dcss_kms_detach(mdrv->kms, componentized); - dcss_dev_destroy(mdrv->dcss); -+} -+ -+static int dcss_drv_bind(struct device *dev) -+{ -+ return dcss_drv_init(dev, true); -+} -+ -+static void dcss_drv_unbind(struct device *dev) -+{ -+ return dcss_drv_deinit(dev, true); -+} -+ -+static const struct component_master_ops dcss_master_ops = { -+ .bind = dcss_drv_bind, -+ .unbind = dcss_drv_unbind, -+}; -+ -+static int compare_of(struct device *dev, void *data) -+{ -+ return dev->of_node == data; -+} -+ -+static int dcss_drv_platform_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct component_match *match = NULL; -+ struct device_node *remote; -+ -+ if (!dev->of_node) -+ return -ENODEV; -+ -+ remote = of_graph_get_remote_node(dev->of_node, 0, 0); -+ if (!remote) -+ return -ENODEV; -+ -+ if (of_device_is_compatible(remote, "fsl,imx8mq-nwl-dsi")) { -+ of_node_put(remote); -+ return dcss_drv_init(dev, false); -+ } -+ -+ drm_of_component_match_add(dev, &match, compare_of, remote); -+ of_node_put(remote); -+ -+ return component_master_add_with_match(dev, &dcss_master_ops, match); -+} -+ -+static void dcss_drv_platform_remove(struct platform_device *pdev) -+{ -+ struct dcss_drv *mdrv = dev_get_drvdata(&pdev->dev); -+ -+ if (mdrv->is_componentized) -+ component_master_del(&pdev->dev, &dcss_master_ops); -+ else -+ dcss_drv_deinit(&pdev->dev, false); - } - - static void dcss_drv_platform_shutdown(struct platform_device *pdev) -diff --git a/drivers/gpu/drm/imx/dcss/dcss-kms.c b/drivers/gpu/drm/imx/dcss/dcss-kms.c -index 135a62366ab8..cafb09df6c75 100644 ---- a/drivers/gpu/drm/imx/dcss/dcss-kms.c -+++ b/drivers/gpu/drm/imx/dcss/dcss-kms.c -@@ -13,6 +13,7 @@ - #include - #include - #include -+#include - - #include "dcss-dev.h" - #include "dcss-kms.h" -@@ -123,7 +124,7 @@ static int dcss_kms_bridge_connector_init(struct dcss_kms_dev *kms) - return 0; - } - --struct dcss_kms_dev *dcss_kms_attach(struct dcss_dev *dcss) -+struct dcss_kms_dev *dcss_kms_attach(struct dcss_dev *dcss, bool componentized) - { - struct dcss_kms_dev *kms; - struct drm_device *drm; -@@ -148,13 +149,16 @@ struct dcss_kms_dev *dcss_kms_attach(struct dcss_dev *dcss) - - goto cleanup_mode_config; - -- ret = dcss_kms_bridge_connector_init(kms); -+ ret = dcss_crtc_init(crtc, drm); - if (ret) - goto cleanup_mode_config; - -- ret = dcss_crtc_init(crtc, drm); -+ if (componentized) -+ ret = component_bind_all(dcss->dev, kms); -+ else -+ ret = dcss_kms_bridge_connector_init(kms); - if (ret) -- goto cleanup_mode_config; -+ goto cleanup_crtc; - - drm_mode_config_reset(drm); - -@@ -182,9 +188,10 @@ struct dcss_kms_dev *dcss_kms_attach(struct dcss_dev *dcss) - return ERR_PTR(ret); - } - --void dcss_kms_detach(struct dcss_kms_dev *kms) -+void dcss_kms_detach(struct dcss_kms_dev *kms, bool componentized) - { - struct drm_device *drm = &kms->base; -+ struct dcss_dev *dcss = drm->dev_private; - - drm_dev_unregister(drm); - drm_bridge_connector_disable_hpd(kms->connector); -@@ -194,5 +201,7 @@ void dcss_kms_detach(struct dcss_kms_dev *kms) - drm->irq_enabled = false; - drm_mode_config_cleanup(drm); - dcss_crtc_deinit(&kms->crtc, drm); -+ if (componentized) -+ component_unbind_all(dcss->dev, drm); - drm->dev_private = NULL; - } -diff --git a/drivers/gpu/drm/imx/dcss/dcss-kms.h b/drivers/gpu/drm/imx/dcss/dcss-kms.h -index dfe5dd99eea3..e98d9c587a43 100644 ---- a/drivers/gpu/drm/imx/dcss/dcss-kms.h -+++ b/drivers/gpu/drm/imx/dcss/dcss-kms.h -@@ -32,8 +32,8 @@ struct dcss_kms_dev { - struct drm_connector *connector; - }; - --struct dcss_kms_dev *dcss_kms_attach(struct dcss_dev *dcss); --void dcss_kms_detach(struct dcss_kms_dev *kms); -+struct dcss_kms_dev *dcss_kms_attach(struct dcss_dev *dcss, bool componentized); -+void dcss_kms_detach(struct dcss_kms_dev *kms, bool componentized); - void dcss_kms_shutdown(struct dcss_kms_dev *kms); - int dcss_crtc_init(struct dcss_crtc *crtc, struct drm_device *drm); - void dcss_crtc_deinit(struct dcss_crtc *crtc, struct drm_device *drm); --- -2.29.2 - diff --git a/projects/NXP/devices/iMX8/patches/linux/0043-arm64-dts-imx8mq-add-DCSS-node.patch b/projects/NXP/devices/iMX8/patches/linux/0043-arm64-dts-imx8mq-add-DCSS-node.patch deleted file mode 100644 index 889d2bfe7a..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0043-arm64-dts-imx8mq-add-DCSS-node.patch +++ /dev/null @@ -1,49 +0,0 @@ -From bd9c83ea41380f584fdd8f2781112b530c84ebba Mon Sep 17 00:00:00 2001 -From: Laurentiu Palcu -Date: Thu, 9 Jul 2020 19:47:33 +0300 -Subject: [PATCH 43/49] arm64: dts: imx8mq: add DCSS node - -This patch adds the node for iMX8MQ Display Controller Subsystem. - -Signed-off-by: Laurentiu Palcu ---- - arch/arm64/boot/dts/freescale/imx8mq.dtsi | 23 +++++++++++++++++++++++ - 1 file changed, 23 insertions(+) - -diff --git a/arch/arm64/boot/dts/freescale/imx8mq.dtsi b/arch/arm64/boot/dts/freescale/imx8mq.dtsi -index 5e0e7d0f1bc4..5a617f9ed8b5 100644 ---- a/arch/arm64/boot/dts/freescale/imx8mq.dtsi -+++ b/arch/arm64/boot/dts/freescale/imx8mq.dtsi -@@ -1103,6 +1103,29 @@ bus@32c00000 { /* AIPS4 */ - #size-cells = <1>; - ranges = <0x32c00000 0x32c00000 0x400000>; - -+ dcss: display-controller@32e00000 { -+ compatible = "nxp,imx8mq-dcss"; -+ reg = <0x32e00000 0x2d000>, <0x32e2f000 0x1000>; -+ interrupts = <6>, <8>, <9>; -+ interrupt-names = "ctxld", "ctxld_kick", "vblank"; -+ interrupt-parent = <&irqsteer>; -+ clocks = <&clk IMX8MQ_CLK_DISP_APB_ROOT>, -+ <&clk IMX8MQ_CLK_DISP_AXI_ROOT>, -+ <&clk IMX8MQ_CLK_DISP_RTRM_ROOT>, -+ <&clk IMX8MQ_VIDEO2_PLL_OUT>, -+ <&clk IMX8MQ_CLK_DISP_DTRC>; -+ clock-names = "apb", "axi", "rtrm", "pix", "dtrc"; -+ assigned-clocks = <&clk IMX8MQ_CLK_DISP_AXI>, -+ <&clk IMX8MQ_CLK_DISP_RTRM>, -+ <&clk IMX8MQ_VIDEO2_PLL1_REF_SEL>; -+ assigned-clock-parents = <&clk IMX8MQ_SYS1_PLL_800M>, -+ <&clk IMX8MQ_SYS1_PLL_800M>, -+ <&clk IMX8MQ_CLK_27M>; -+ assigned-clock-rates = <800000000>, -+ <400000000>; -+ status = "disabled"; -+ }; -+ - irqsteer: interrupt-controller@32e2d000 { - compatible = "fsl,imx8m-irqsteer", "fsl,imx-irqsteer"; - reg = <0x32e2d000 0x1000>; --- -2.29.2 - diff --git a/projects/NXP/devices/iMX8/patches/linux/0044-arm64-dts-imx8mq-add-DCSS-external-oscillator-suppor.patch b/projects/NXP/devices/iMX8/patches/linux/0044-arm64-dts-imx8mq-add-DCSS-external-oscillator-suppor.patch deleted file mode 100644 index af0fe275a3..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0044-arm64-dts-imx8mq-add-DCSS-external-oscillator-suppor.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 8e5a885158f430de3ea36b1439dd8c0058ce95df Mon Sep 17 00:00:00 2001 -From: Laurentiu Palcu -Date: Fri, 22 Nov 2019 10:12:50 +0200 -Subject: [PATCH 44/49] arm64: dts: imx8mq: add DCSS external oscillator - support - -The external oscillator, which is high precision, will be used when DCSS output -goes to HDMI. - -Signed-off-by: Laurentiu Palcu ---- - arch/arm64/boot/dts/freescale/imx8mq.dtsi | 7 +++++-- - 1 file changed, 5 insertions(+), 2 deletions(-) - -diff --git a/arch/arm64/boot/dts/freescale/imx8mq.dtsi b/arch/arm64/boot/dts/freescale/imx8mq.dtsi -index 5a617f9ed8b5..b75252a65c44 100644 ---- a/arch/arm64/boot/dts/freescale/imx8mq.dtsi -+++ b/arch/arm64/boot/dts/freescale/imx8mq.dtsi -@@ -1113,8 +1113,11 @@ dcss: display-controller@32e00000 { - <&clk IMX8MQ_CLK_DISP_AXI_ROOT>, - <&clk IMX8MQ_CLK_DISP_RTRM_ROOT>, - <&clk IMX8MQ_VIDEO2_PLL_OUT>, -- <&clk IMX8MQ_CLK_DISP_DTRC>; -- clock-names = "apb", "axi", "rtrm", "pix", "dtrc"; -+ <&clk IMX8MQ_CLK_DISP_DTRC>, -+ <&clk IMX8MQ_VIDEO2_PLL1_REF_SEL>, -+ <&clk IMX8MQ_CLK_PHY_27MHZ>; -+ clock-names = "apb", "axi", "rtrm", "pix", "dtrc", "pll_src", -+ "pll_phy_ref"; - assigned-clocks = <&clk IMX8MQ_CLK_DISP_AXI>, - <&clk IMX8MQ_CLK_DISP_RTRM>, - <&clk IMX8MQ_VIDEO2_PLL1_REF_SEL>; --- -2.29.2 - diff --git a/projects/NXP/devices/iMX8/patches/linux/0045-arm64-dts-fsl-imx8mq-add-HDP-bridge-node.patch b/projects/NXP/devices/iMX8/patches/linux/0045-arm64-dts-fsl-imx8mq-add-HDP-bridge-node.patch deleted file mode 100644 index 7eab52d86c..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0045-arm64-dts-fsl-imx8mq-add-HDP-bridge-node.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 0327e9fc14269069711cd2d45d60130b318532fe Mon Sep 17 00:00:00 2001 -From: Lucas Stach -Date: Tue, 13 Feb 2018 12:30:58 +0100 -Subject: [PATCH 45/49] arm64: dts: fsl: imx8mq: add HDP bridge node - -Signed-off-by: Lucas Stach ---- - arch/arm64/boot/dts/freescale/imx8mq.dtsi | 10 ++++++++++ - 1 file changed, 10 insertions(+) - -diff --git a/arch/arm64/boot/dts/freescale/imx8mq.dtsi b/arch/arm64/boot/dts/freescale/imx8mq.dtsi -index b75252a65c44..aad21d6f1da7 100644 ---- a/arch/arm64/boot/dts/freescale/imx8mq.dtsi -+++ b/arch/arm64/boot/dts/freescale/imx8mq.dtsi -@@ -1103,6 +1103,16 @@ bus@32c00000 { /* AIPS4 */ - #size-cells = <1>; - ranges = <0x32c00000 0x32c00000 0x400000>; - -+ hdmi: hdmi@32c00000 { -+ reg = <0x32c00000 0x33800>, /* HDP registers */ -+ <0x32e40000 0x40000>, /* HDP SEC register */ -+ <0x32e2f000 0x10>; /* RESET register */ -+ interrupts = , -+ ; -+ interrupt-names = "plug_in", "plug_out"; -+ status = "disabled"; -+ }; -+ - dcss: display-controller@32e00000 { - compatible = "nxp,imx8mq-dcss"; - reg = <0x32e00000 0x2d000>, <0x32e2f000 0x1000>; --- -2.29.2 - diff --git a/projects/NXP/devices/iMX8/patches/linux/0046-arm64-dts-fsl-imx8mq-evk-enable-DCSS-and-HDMI.patch b/projects/NXP/devices/iMX8/patches/linux/0046-arm64-dts-fsl-imx8mq-evk-enable-DCSS-and-HDMI.patch deleted file mode 100644 index 48d5c6da67..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0046-arm64-dts-fsl-imx8mq-evk-enable-DCSS-and-HDMI.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 96ab278661207096c013ad1b39ed36f5f9a35ffd Mon Sep 17 00:00:00 2001 -From: Lucas Stach -Date: Tue, 13 Feb 2018 12:47:09 +0100 -Subject: [PATCH 46/49] arm64: dts: fsl: imx8mq-evk: enable DCSS and HDMI - -Signed-off-by: Lucas Stach ---- - arch/arm64/boot/dts/freescale/imx8mq-evk.dts | 22 ++++++++++++++++++++ - 1 file changed, 22 insertions(+) - -diff --git a/arch/arm64/boot/dts/freescale/imx8mq-evk.dts b/arch/arm64/boot/dts/freescale/imx8mq-evk.dts -index 2418cca00bc5..71eeda6de3d7 100644 ---- a/arch/arm64/boot/dts/freescale/imx8mq-evk.dts -+++ b/arch/arm64/boot/dts/freescale/imx8mq-evk.dts -@@ -132,6 +132,16 @@ opp-800M { - }; - }; - -+&dcss { -+ status = "okay"; -+ -+ port { -+ dcss_out: endpoint { -+ remote-endpoint = <&hdmi_in>; -+ }; -+ }; -+}; -+ - &dphy { - status = "okay"; - }; -@@ -168,6 +178,18 @@ wl-reg-on-hog { - }; - }; - -+&hdmi { -+ compatible = "cdn,imx8mq-hdmi"; -+ lane-mapping = <0xe4>; -+ status = "okay"; -+ -+ port { -+ hdmi_in: endpoint { -+ remote-endpoint = <&dcss_out>; -+ }; -+ }; -+}; -+ - &i2c1 { - clock-frequency = <100000>; - pinctrl-names = "default"; --- -2.29.2 - diff --git a/projects/NXP/devices/iMX8/patches/linux/0047-arm64-dts-fsl-imx8mq-pico-pi-enable-DCSS-and-HDMI.patch b/projects/NXP/devices/iMX8/patches/linux/0047-arm64-dts-fsl-imx8mq-pico-pi-enable-DCSS-and-HDMI.patch deleted file mode 100644 index d9a5d06075..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0047-arm64-dts-fsl-imx8mq-pico-pi-enable-DCSS-and-HDMI.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 5a139d07d03076be7972db4b022558dffcfd685b Mon Sep 17 00:00:00 2001 -From: Lukas Rusak -Date: Tue, 9 Mar 2021 10:47:27 -0800 -Subject: [PATCH 47/49] arm64: dts: fsl: imx8mq-pico-pi: enable DCSS and HDMI - ---- - .../boot/dts/freescale/imx8mq-pico-pi.dts | 22 +++++++++++++++++++ - 1 file changed, 22 insertions(+) - -diff --git a/arch/arm64/boot/dts/freescale/imx8mq-pico-pi.dts b/arch/arm64/boot/dts/freescale/imx8mq-pico-pi.dts -index 89cbec5c41b2..03734145c50e 100644 ---- a/arch/arm64/boot/dts/freescale/imx8mq-pico-pi.dts -+++ b/arch/arm64/boot/dts/freescale/imx8mq-pico-pi.dts -@@ -37,6 +37,16 @@ reg_usb_otg_vbus: regulator-usb-otg-vbus { - }; - }; - -+&dcss { -+ status = "okay"; -+ -+ port { -+ dcss_out: endpoint { -+ remote-endpoint = <&hdmi_in>; -+ }; -+ }; -+}; -+ - &fec1 { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_fec1 &pinctrl_enet_3v3>; -@@ -56,6 +66,18 @@ ethphy0: ethernet-phy@1 { - }; - }; - -+&hdmi { -+ compatible = "cdn,imx8mq-hdmi"; -+ lane-mapping = <0xe4>; -+ status = "okay"; -+ -+ port { -+ hdmi_in: endpoint { -+ remote-endpoint = <&dcss_out>; -+ }; -+ }; -+}; -+ - &i2c1 { - clock-frequency = <100000>; - pinctrl-names = "default"; --- -2.29.2 - diff --git a/projects/NXP/devices/iMX8/patches/linux/0048-drm-imx-mhdp-don-t-depend-on-DRM_IMX.patch b/projects/NXP/devices/iMX8/patches/linux/0048-drm-imx-mhdp-don-t-depend-on-DRM_IMX.patch deleted file mode 100644 index c49bd36ee2..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0048-drm-imx-mhdp-don-t-depend-on-DRM_IMX.patch +++ /dev/null @@ -1,23 +0,0 @@ -From f94717816b9a39869219ede859fe74af3f2ecd19 Mon Sep 17 00:00:00 2001 -From: Lukas Rusak -Date: Wed, 24 Mar 2021 14:27:43 -0700 -Subject: [PATCH 48/49] drm: imx: mhdp: don't depend on DRM_IMX - ---- - drivers/gpu/drm/imx/mhdp/Kconfig | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/drivers/gpu/drm/imx/mhdp/Kconfig b/drivers/gpu/drm/imx/mhdp/Kconfig -index 86950badb947..cf7dfacdd434 100644 ---- a/drivers/gpu/drm/imx/mhdp/Kconfig -+++ b/drivers/gpu/drm/imx/mhdp/Kconfig -@@ -6,6 +6,5 @@ config DRM_IMX_CDNS_MHDP - select DRM_CDNS_DP - select DRM_CDNS_HDMI - select DRM_CDNS_AUDIO -- depends on DRM_IMX - help - Choose this if you want to use HDMI on i.MX8. --- -2.29.2 - diff --git a/projects/NXP/devices/iMX8/patches/linux/0049-drm-cadence-shutup-cec-logging.patch b/projects/NXP/devices/iMX8/patches/linux/0049-drm-cadence-shutup-cec-logging.patch deleted file mode 100644 index 5589e19370..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0049-drm-cadence-shutup-cec-logging.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 3111faf58971c2c517457e62f84d138a3d62464e Mon Sep 17 00:00:00 2001 -From: Lukas Rusak -Date: Wed, 24 Mar 2021 15:14:57 -0700 -Subject: [PATCH 49/49] drm: cadence: shutup cec logging - ---- - drivers/gpu/drm/bridge/cadence/cdns-mhdp-cec.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-cec.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-cec.c -index 25cf9e91e64f..e91de13eae58 100644 ---- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-cec.c -+++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-cec.c -@@ -171,8 +171,8 @@ static u32 mhdp_cec_write_message(struct cdns_mhdp_cec *cec, struct cec_msg *msg - return -EINVAL; - } - -- for (i = 0; i < msg->len; ++i) -- printk("msg[%d]=0x%x\n",i, msg->msg[i]); -+ // for (i = 0; i < msg->len; ++i) -+ // printk("msg[%d]=0x%x\n",i, msg->msg[i]); - - /* Write Message to register */ - for (i = 0; i < msg->len; ++i) { --- -2.29.2 - diff --git a/projects/NXP/devices/iMX8/patches/linux/0050-drm-display-drm-hdmi-helper-h.patch b/projects/NXP/devices/iMX8/patches/linux/0050-drm-display-drm-hdmi-helper-h.patch deleted file mode 100644 index 9d4a322234..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0050-drm-display-drm-hdmi-helper-h.patch +++ /dev/null @@ -1,21 +0,0 @@ ---- a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c 2022-06-28 15:48:27.254022595 +0000 -+++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c 2022-06-28 15:46:14.919939083 +0000 -@@ -14,6 +14,8 @@ - #include - #include - #include -+#include -+#include - #include - #include - #include ---- a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-hdcp.c 2022-06-28 15:53:59.618466556 +0000 -+++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-hdcp.c 2022-06-28 15:56:01.987635836 +0000 -@@ -11,6 +11,7 @@ - */ - #include - #include -+#include - #include - #include - diff --git a/projects/NXP/devices/iMX8/patches/linux/0060-mhdp-dp-hdmi-add-missing-include-patch-for-6-3.patch b/projects/NXP/devices/iMX8/patches/linux/0060-mhdp-dp-hdmi-add-missing-include-patch-for-6-3.patch deleted file mode 100644 index 081fc3affa..0000000000 --- a/projects/NXP/devices/iMX8/patches/linux/0060-mhdp-dp-hdmi-add-missing-include-patch-for-6-3.patch +++ /dev/null @@ -1,10 +0,0 @@ ---- a/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imxdrv.c 2023-04-24 10:04:54.095068512 +0000 -+++ b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imxdrv.c 2023-04-25 13:35:44.405261313 +0000 -@@ -12,6 +12,7 @@ - #include - #include - #include -+#include - - #include - diff --git a/scripts/uboot_helper b/scripts/uboot_helper index cd9a94b768..adb2a9147c 100755 --- a/scripts/uboot_helper +++ b/scripts/uboot_helper @@ -258,6 +258,10 @@ devices = \ 'dtb' : 'imx8mq-evk.dtb', 'config' : 'imx8mq_evk_defconfig' }, + 'phanbell' : { + 'dtb' : 'imx8mq-phanbell.dtb', + 'config' : 'imx8mq_phanbell_defconfig' + }, 'pico-mq' : { 'dtb' : 'imx8mq-pico-pi.dtb', 'config' : 'pico-imx8mq_defconfig'