diff --git a/config/Config-images.in b/config/Config-images.in index 66b1d3e4b..6bad2340d 100644 --- a/config/Config-images.in +++ b/config/Config-images.in @@ -321,15 +321,14 @@ menu "Target Images" depends on USES_BOOT_PART default 8 if TARGET_apm821xx_sata default 128 if TARGET_armsr - default 64 if TARGET_bcm27xx + default 64 if TARGET_bcm27xx || TARGET_x86 || TARGET_loongarch64 default 32 if TARGET_rockchip default 16 config TARGET_ROOTFS_PARTSIZE int "Root filesystem partition size (in MiB)" depends on USES_ROOTFS_PART || TARGET_ROOTFS_EXT4FS - default 232 if TARGET_loongarch64 - default 448 if TARGET_mediatek || TARGET_x86 + default 448 if TARGET_mediatek || TARGET_x86 || TARGET_loongarch64 default 160 help Select the root filesystem partition size. diff --git a/include/trusted-firmware-a.mk b/include/trusted-firmware-a.mk index 15bbb1d69..d86fb1aa1 100644 --- a/include/trusted-firmware-a.mk +++ b/include/trusted-firmware-a.mk @@ -81,7 +81,6 @@ define Build/Compile/Trusted-Firmware-A $(if $(DTC),DTC="$(DTC)") \ PLAT=$(PLAT) \ BUILD_STRING="OpenWrt v$(PKG_VERSION)-$(PKG_RELEASE) ($(VARIANT))" \ - $(if $(CONFIG_BINUTILS_VERSION_2_37)$(CONFIG_BINUTILS_VERSION_2_38),,LDFLAGS="-no-warn-rwx-segments") \ $(TFA_MAKE_FLAGS) endef diff --git a/package/boot/arm-trusted-firmware-mediatek/Makefile b/package/boot/arm-trusted-firmware-mediatek/Makefile index 798070a59..daf68e3b7 100644 --- a/package/boot/arm-trusted-firmware-mediatek/Makefile +++ b/package/boot/arm-trusted-firmware-mediatek/Makefile @@ -9,13 +9,13 @@ include $(TOPDIR)/rules.mk PKG_NAME:=arm-trusted-firmware-mediatek -PKG_RELEASE:=2 +PKG_RELEASE:=1 PKG_SOURCE_PROTO:=git PKG_SOURCE_URL=https://github.com/mtk-openwrt/arm-trusted-firmware.git -PKG_SOURCE_DATE:=2024-01-17 -PKG_SOURCE_VERSION:=bacca82a8cac369470df052a9d801a0ceb9b74ca -PKG_MIRROR_HASH:=d035c1b63a9bd71d752c90540361b66d290e7cf42dcca73259d0950af3569c79 +PKG_SOURCE_DATE:=2025-07-11 +PKG_SOURCE_VERSION:=78a0dfd927bb00ce973a1f8eb4079df0f755887a +PKG_MIRROR_HASH:=5604a9419f788f53448c48761dc50d3dc4bef3b3dbbc08a32cf2def253588171 PKG_MAINTAINER:=Daniel Golle @@ -33,6 +33,7 @@ define Trusted-Firmware-A/Default BOARD_QFN:= DRAM_USE_COMB:= USE_UBI:= + SPIM_CTRL:= endef define Trusted-Firmware-A/mt7622-nor-1ddr @@ -285,6 +286,59 @@ define Trusted-Firmware-A/mt7986-spim-nand-ddr3 DDR_TYPE:=ddr3 endef +define Trusted-Firmware-A/mt7986-spim-nand-ubi-ddr3 + NAME:=MediaTek MT7986 (SPI-NAND via SPIM using UBI, DDR3) + BOOT_DEVICE:=spim-nand + BUILD_SUBTARGET:=filogic + PLAT:=mt7986 + DDR_TYPE:=ddr3 + USE_UBI:=1 +endef + +define Trusted-Firmware-A/mt7987-emmc-comb + NAME:=MediaTek MT7987 (eMMC) + BOOT_DEVICE:=emmc + BUILD_SUBTARGET:=filogic + PLAT:=mt7987 + DRAM_USE_COMB:=1 +endef + +define Trusted-Firmware-A/mt7987-nor-comb + NAME:=MediaTek MT7987 (NOR) + BOOT_DEVICE:=nor + BUILD_SUBTARGET:=filogic + PLAT:=mt7987 + DRAM_USE_COMB:=1 +endef + +define Trusted-Firmware-A/mt7987-sdmmc-comb + NAME:=MediaTek MT7987 (SD card) + BOOT_DEVICE:=sdmmc + BUILD_SUBTARGET:=filogic + PLAT:=mt7987 + DRAM_USE_COMB:=1 +endef + +define Trusted-Firmware-A/mt7987-spim-nand0-ubi-comb + NAME:=MediaTek MT7987 (SPI-NAND via SPIM, UBI) + BOOT_DEVICE:=spim-nand + BUILD_SUBTARGET:=filogic + PLAT:=mt7987 + DRAM_USE_COMB:=1 + USE_UBI:=1 + SPIM_CTRL:=0 +endef + +define Trusted-Firmware-A/mt7987-spim-nand2-ubi-comb + NAME:=MediaTek MT7987 (SPI-NAND via SPIM, UBI) + BOOT_DEVICE:=spim-nand + BUILD_SUBTARGET:=filogic + PLAT:=mt7987 + DRAM_USE_COMB:=1 + USE_UBI:=1 + SPIM_CTRL:=2 +endef + define Trusted-Firmware-A/mt7988-nor-ddr3 NAME:=MediaTek MT7988 (SPI-NOR, DDR3) BOOT_DEVICE:=nor @@ -423,6 +477,15 @@ define Trusted-Firmware-A/mt7988-spim-nand-ubi-comb USE_UBI:=1 endef +define Trusted-Firmware-A/mt7988-spim-nand-ubi-ddr4 + NAME:=MediaTek MT7988 (SPI-NAND via SPIM, DDR4) + BOOT_DEVICE:=spim-nand + BUILD_SUBTARGET:=filogic + PLAT:=mt7988 + DDR_TYPE:=ddr4 + USE_UBI:=1 +endef + TFA_TARGETS:= \ mt7622-nor-1ddr \ mt7622-nor-2ddr \ @@ -448,6 +511,7 @@ TFA_TARGETS:= \ mt7986-sdmmc-ddr3 \ mt7986-snand-ddr3 \ mt7986-spim-nand-ddr3 \ + mt7986-spim-nand-ubi-ddr3 \ mt7986-emmc-ddr4 \ mt7986-nor-ddr4 \ mt7986-sdmmc-ddr4 \ @@ -455,6 +519,11 @@ TFA_TARGETS:= \ mt7986-spim-nand-ddr4 \ mt7986-spim-nand-ubi-ddr4 \ mt7986-spim-nand-4k-ddr4 \ + mt7987-emmc-comb \ + mt7987-nor-comb \ + mt7987-sdmmc-comb \ + mt7987-spim-nand0-ubi-comb \ + mt7987-spim-nand2-ubi-comb \ mt7988-emmc-ddr3 \ mt7988-nor-ddr3 \ mt7988-sdmmc-ddr3 \ @@ -471,7 +540,8 @@ TFA_TARGETS:= \ mt7988-snand-comb \ mt7988-snand-ubi-comb \ mt7988-spim-nand-comb \ - mt7988-spim-nand-ubi-comb + mt7988-spim-nand-ubi-comb \ + mt7988-spim-nand-ubi-ddr4 TFA_MAKE_FLAGS += \ BOOT_DEVICE=$(BOOT_DEVICE) \ @@ -484,6 +554,8 @@ TFA_MAKE_FLAGS += \ $(if $(DRAM_USE_COMB),DRAM_USE_COMB=1) \ $(if $(USE_UBI),UBI=1 $(if $(findstring mt7622,$(PLAT)),OVERRIDE_UBI_START_ADDR=0x80000)) \ $(if $(USE_UBI),UBI=1 $(if $(findstring mt7981,$(PLAT)),OVERRIDE_UBI_START_ADDR=0x100000)) \ + $(if $(USE_UBI),UBI=1 $(if $(findstring mt7986,$(PLAT)),OVERRIDE_UBI_START_ADDR=0x200000)) \ + $(if $(SPIM_CTRL),SPIM_CTRL=$(SPIM_CTRL)) \ all define Package/trusted-firmware-a/install diff --git a/package/boot/arm-trusted-firmware-mediatek/patches/0004-mediatek-snfi-add-FudanMicro-manufacturer.patch b/package/boot/arm-trusted-firmware-mediatek/patches/0004-mediatek-snfi-add-FudanMicro-manufacturer.patch new file mode 100644 index 000000000..7900cfe44 --- /dev/null +++ b/package/boot/arm-trusted-firmware-mediatek/patches/0004-mediatek-snfi-add-FudanMicro-manufacturer.patch @@ -0,0 +1,41 @@ +From fd057aba83aea8458986e11c81dbb75a69468b84 Mon Sep 17 00:00:00 2001 +From: Mikhail Zhilkin +Date: Wed, 13 Aug 2025 22:46:54 +0300 +Subject: arm-trusted-firmware-mediatek: add FudanMicro manufacturer + +Add FudanMicro manufacturer. + +Signed-off-by: Mikhail Zhilkin +--- + +--- a/plat/mediatek/apsoc_common/drivers/spi_nand/mtk_spi_nand.c ++++ b/plat/mediatek/apsoc_common/drivers/spi_nand/mtk_spi_nand.c +@@ -21,6 +21,7 @@ + #define SPI_NAND_MAX_ID_LEN 4U + #define DELAY_US_400MS 400000U + #define ETRON_ID 0xD5U ++#define FUDAN_ID 0xA1U + #define GIGADEVICE_ID 0xC8U + #define MACRONIX_ID 0xC2U + #define MICRON_ID 0x2CU +@@ -146,7 +147,8 @@ static int spi_nand_quad_enable(uint8_t + if (manufacturer_id != MACRONIX_ID && + manufacturer_id != GIGADEVICE_ID && + manufacturer_id != ETRON_ID && +- manufacturer_id != FORESEE_ID) { ++ manufacturer_id != FORESEE_ID && ++ manufacturer_id != FUDAN_ID) { + return 0; + } + +@@ -543,6 +545,10 @@ static int spi_nand_check_pp(struct para + INFO("PP COPY %d CRC read: 0x%x, compute: 0x%x\n", + i, crc, crc_compute); + ++ // FUDAN integrity CRC (bytes 254-255) is reversed ++ if (crc != crc_compute) ++ crc = htobe16(pp->integrity_crc); ++ + if (crc != crc_compute) { + ret = -EBADMSG; + continue; diff --git a/package/boot/arm-trusted-firmware-mediatek/patches/0005-mt7987-make-SPI-controller-configurable.patch b/package/boot/arm-trusted-firmware-mediatek/patches/0005-mt7987-make-SPI-controller-configurable.patch new file mode 100644 index 000000000..41017844b --- /dev/null +++ b/package/boot/arm-trusted-firmware-mediatek/patches/0005-mt7987-make-SPI-controller-configurable.patch @@ -0,0 +1,128 @@ +From e2e43103c00b5f7ccedbdbdece0f622cb420b4a5 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Fri, 3 Oct 2025 12:53:10 +0100 +Subject: [PATCH] mt7987: make SPI controller configurable + +Allow selecting the SPI controller used for SPIM-NAND or SPI-NOR boot +devices (either SPI0 or SPI2). + +Signed-off-by: Daniel Golle +--- + plat/mediatek/apsoc_common/Config.in | 1 + + plat/mediatek/mt7987/Config.in | 29 +++++++++++++++++++++ + plat/mediatek/mt7987/bl2/bl2.mk | 12 +++++++++ + plat/mediatek/mt7987/bl2/bl2_dev_spi_nand.c | 10 ++++++- + plat/mediatek/mt7987/platform.mk | 4 +-- + 5 files changed, 53 insertions(+), 3 deletions(-) + create mode 100644 plat/mediatek/mt7987/Config.in + +--- a/plat/mediatek/apsoc_common/Config.in ++++ b/plat/mediatek/apsoc_common/Config.in +@@ -783,6 +783,7 @@ config ENABLE_BL31_RUNTIME_LOG + default 1 + depends on _ENABLE_BL31_RUNTIME_LOG + ++source "plat/mediatek/mt7987/Config.in" + source "plat/mediatek/mt7988/Config.in" + + endmenu # Platform configurations +--- /dev/null ++++ b/plat/mediatek/mt7987/Config.in +@@ -0,0 +1,29 @@ ++# SPDX-License-Identifier: BSD-3-Clause ++# ++# Copyright (c) 2025 Daniel Golle ++# ++# MT7987 platform-specific configurations ++# ++ ++if _PLAT_MT7987 ++ ++choice ++ prompt "SPI controller" ++ depends on (_BOOT_DEVICE_SPIM_NAND || _BOOT_DEVICE_SPI_NOR) ++ default _SPIM_CTRL_0 if _BOOT_DEVICE_SPIM_NAND ++ default _SPIM_CTRL_2 if _BOOT_DEVICE_SPI_NOR ++ ++ config _SPIM_CTRL_0 ++ bool "0" ++ ++ config _SPIM_CTRL_2 ++ bool "2" ++ ++endchoice ++ ++config SPIM_CTRL ++ int ++ default 0 if _SPIM_CTRL_0 ++ default 2 if _SPIM_CTRL_2 ++ ++endif # _PLAT_MT7987 +--- a/plat/mediatek/mt7987/bl2/bl2.mk ++++ b/plat/mediatek/mt7987/bl2/bl2.mk +@@ -91,7 +91,11 @@ endif # END OF BOOT_DEVICE = ram + ifeq ($(BOOT_DEVICE),nor) + $(eval $(call BL2_BOOT_NOR)) + BL2_SOURCES += $(MTK_PLAT_SOC)/bl2/bl2_dev_spi_nor.c ++ifeq ($(SPIM_CTRL),0) ++DTS_NAME := mt7987-spi0 ++else + DTS_NAME := mt7987-spi2 ++endif + endif # END OF BOOTDEVICE = nor + + ifeq ($(BOOT_DEVICE),emmc) +@@ -112,10 +116,18 @@ ifeq ($(BOOT_DEVICE),spim-nand) + $(eval $(call BL2_BOOT_SPI_NAND,0,0)) + BL2_SOURCES += $(MTK_PLAT_SOC)/bl2/bl2_dev_spi_nand.c + NAND_TYPE ?= spim:2k+64 ++ifeq ($(SPIM_CTRL),2) ++DTS_NAME := mt7987-spi2 ++else + DTS_NAME := mt7987-spi0 ++endif + $(eval $(call BL2_BOOT_NAND_TYPE_CHECK,$(NAND_TYPE),spim:2k+64 spim:2k+128 spim:4k+256)) + endif # END OF BOOTDEVICE = spim-nand + ++ifneq ($(SPIM_CTRL),) ++BL2_CPPFLAGS += -DSPIM_CTRL=$(SPIM_CTRL) ++endif ++ + ifeq ($(BROM_HEADER_TYPE),) + $(error BOOT_DEVICE has invalid value. Please re-check.) + endif +--- a/plat/mediatek/mt7987/bl2/bl2_dev_spi_nand.c ++++ b/plat/mediatek/mt7987/bl2/bl2_dev_spi_nand.c +@@ -12,10 +12,18 @@ + + #define MTK_QSPI_SRC_CLK CB_MPLL_D2 + ++#if SPIM_CTRL == 0 ++#define SELECTED_SPIM SPIM0 ++#elif SPIM_CTRL == 2 ++#define SELECTED_SPIM SPIM2 ++#else ++#error "Invalid SPI controller selection" ++#endif ++ + uint32_t mtk_plat_get_qspi_src_clk(void) + { + /* config GPIO pinmux to spi mode */ +- mtk_spi_gpio_init(SPIM0); ++ mtk_spi_gpio_init(SELECTED_SPIM); + + /* select 208M clk */ + mtk_spi_source_clock_select(MTK_QSPI_SRC_CLK); +--- a/plat/mediatek/mt7987/platform.mk ++++ b/plat/mediatek/mt7987/platform.mk +@@ -56,8 +56,8 @@ include make_helpers/dep.mk + + $(call GEN_DEP_RULES,bl2,emicfg bl2_boot_ram bl2_boot_nand_nmbm bl2_dev_mmc bl2_plat_init bl2_plat_setup mt7987_gpio dtb) + $(call MAKE_DEP,bl2,emicfg,DDR4_4BG_MODE DRAM_DEBUG_LOG DDR3_FREQ_2133 DDR3_FREQ_1866 DDR4_FREQ_3200 DDR4_FREQ_2666) +-$(call MAKE_DEP,bl2,bl2_plat_init,BL2_COMPRESS) +-$(call MAKE_DEP,bl2,bl2_plat_setup,BOOT_DEVICE TRUSTED_BOARD_BOOT BL32_TZRAM_BASE BL32_TZRAM_SIZE BL32_LOAD_OFFSET) ++$(call MAKE_DEP,bl2,bl2_plat_init,BL2_COMPRESS SPIM_CTRL) ++$(call MAKE_DEP,bl2,bl2_plat_setup,BOOT_DEVICE TRUSTED_BOARD_BOOT BL32_TZRAM_BASE BL32_TZRAM_SIZE BL32_LOAD_OFFSET SPIM_CTRL) + $(call MAKE_DEP,bl2,bl2_dev_mmc,BOOT_DEVICE) + $(call MAKE_DEP,bl2,bl2_boot_ram,RAM_BOOT_DEBUGGER_HOOK RAM_BOOT_UART_DL) + $(call MAKE_DEP,bl2,bl2_boot_nand_nmbm,NMBM_MAX_RATIO NMBM_MAX_RESERVED_BLOCKS NMBM_DEFAULT_LOG_LEVEL) diff --git a/package/boot/arm-trusted-firmware-mediatek/patches/0006-hack-mt7987-mmc-use-4-bit-bus-width-for-eMMC.patch b/package/boot/arm-trusted-firmware-mediatek/patches/0006-hack-mt7987-mmc-use-4-bit-bus-width-for-eMMC.patch new file mode 100644 index 000000000..0f64a7e14 --- /dev/null +++ b/package/boot/arm-trusted-firmware-mediatek/patches/0006-hack-mt7987-mmc-use-4-bit-bus-width-for-eMMC.patch @@ -0,0 +1,24 @@ +From 0a09912eb336bee788443b919ea5b99b195f5a91 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Sat, 4 Oct 2025 22:13:49 +0100 +Subject: [PATCH] hack: mt7987: mmc: use 4-bit bus-width for eMMC + +The BananaPi R4 Lite has broken DAT5 signal of the MMC bus, which +results in 8-bit buswidth not working well for the eMMC. +Reduce to 4-bit buswidth fixes it (and makes all other boards with +eMMC a tiny bit slower to boot, but it's in the milliseconds). +--- + plat/mediatek/mt7987/bl2/bl2_dev_mmc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/plat/mediatek/mt7987/bl2/bl2_dev_mmc.c ++++ b/plat/mediatek/mt7987/bl2/bl2_dev_mmc.c +@@ -74,7 +74,7 @@ static const struct mt7987_msdc_conf { + { + .base = MSDC0_BASE, + .top_base = MSDC0_TOP_BASE, +- .bus_width = MMC_BUS_WIDTH_8, ++ .bus_width = MMC_BUS_WIDTH_4, + .type = MMC_IS_EMMC, + .src_clk = 200000000, + .dev_comp = &mt7987_msdc_compat, diff --git a/package/boot/arm-trusted-firmware-mediatek/patches/0007-hack-mt7987-bl2-move-FIP-offset-to-0x100000.patch b/package/boot/arm-trusted-firmware-mediatek/patches/0007-hack-mt7987-bl2-move-FIP-offset-to-0x100000.patch new file mode 100644 index 000000000..fcb60b41a --- /dev/null +++ b/package/boot/arm-trusted-firmware-mediatek/patches/0007-hack-mt7987-bl2-move-FIP-offset-to-0x100000.patch @@ -0,0 +1,27 @@ +From 6725bb3c2aa9330f37a591e1e539badf67021b47 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Sat, 4 Oct 2025 23:59:54 +0100 +Subject: [PATCH] hack: mt7987: bl2: move FIP offset to 0x100000 + +There is no use in allocating more than 2MB to the factory partition. +After all, even for WiFi 7 tri-band devices the calibration data is +still in the kilobytes range. +Move FIP offset to 0x100000 to not waste so much space on small NOR +flash. + +Signed-off-by: Daniel Golle +--- + plat/mediatek/mt7987/bl2/bl2_dev_spi_nor.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/plat/mediatek/mt7987/bl2/bl2_dev_spi_nor.c ++++ b/plat/mediatek/mt7987/bl2/bl2_dev_spi_nor.c +@@ -7,7 +7,7 @@ + #include + #include + +-#define FIP_BASE 0x250000 ++#define FIP_BASE 0x100000 + #define FIP_SIZE 0x80000 + + #define MTK_QSPI_SRC_CLK CB_MPLL_D2 diff --git a/package/boot/arm-trusted-firmware-mvebu/Makefile b/package/boot/arm-trusted-firmware-mvebu/Makefile index e66b9d40b..d8f0714f6 100644 --- a/package/boot/arm-trusted-firmware-mvebu/Makefile +++ b/package/boot/arm-trusted-firmware-mvebu/Makefile @@ -108,6 +108,7 @@ TFA_TARGETS:= \ udpu TFA_MAKE_FLAGS += \ + $(if $(CONFIG_BINUTILS_VERSION_2_37)$(CONFIG_BINUTILS_VERSION_2_38),,LDFLAGS="-no-warn-rwx-segments") \ CROSS_CM3=$(STAGING_DIR_IMAGE)/$(LINARO_NAME)-$(LINARO_RELEASE).$(LINARO_VERSION)/bin/arm-linux-gnueabi- \ BL33=$(STAGING_DIR_IMAGE)/$(UBOOT)-u-boot.bin \ MV_DDR_PATH=$(STAGING_DIR_IMAGE)/$(MV_DDR_NAME) \ diff --git a/package/boot/arm-trusted-firmware-sunxi/Makefile b/package/boot/arm-trusted-firmware-sunxi/Makefile index 4b007f8b0..4903c98cd 100644 --- a/package/boot/arm-trusted-firmware-sunxi/Makefile +++ b/package/boot/arm-trusted-firmware-sunxi/Makefile @@ -46,6 +46,9 @@ TFA_TARGETS:= \ sunxi-h6 \ sunxi-h616 +TFA_MAKE_FLAGS+= \ + $(if $(CONFIG_BINUTILS_VERSION_2_37)$(CONFIG_BINUTILS_VERSION_2_38),,LDFLAGS="-no-warn-rwx-segments") + define Package/trusted-firmware-a/install $(INSTALL_DIR) $(STAGING_DIR_IMAGE) $(INSTALL_DATA) $(PKG_BUILD_DIR)/build/$(PLAT)/release/bl31.bin $(STAGING_DIR_IMAGE)/bl31_$(BUILD_VARIANT).bin diff --git a/package/firmware/ipq-wifi/Makefile b/package/firmware/ipq-wifi/Makefile index cfc874904..cd043c08c 100644 --- a/package/firmware/ipq-wifi/Makefile +++ b/package/firmware/ipq-wifi/Makefile @@ -6,9 +6,11 @@ PKG_RELEASE:=1 PKG_SOURCE_PROTO:=git PKG_SOURCE_URL=$(PROJECT_GIT)/project/firmware/qca-wireless.git -PKG_SOURCE_DATE:=2025-06-13 -PKG_SOURCE_VERSION:=4810aacf3b1c5de99923b9a424a1f0e6341c6bca -PKG_MIRROR_HASH:=2e2fdf0578e39eb0be36cfd8e11de920c3e8446469dafee0ebbc580f272193a8 +PKG_SOURCE_DATE:=2025-10-22 +PKG_SOURCE_VERSION:=ec6831a43ff066c9873e7c41fd6f68354bb67b4a +PKG_MIRROR_HASH:=a9fbf572eb8c6dc2f40f167139d7ecdae8dbc86d29e519209ac482a76bcb0fe2 + +PKG_FLAGS:=nonshared include $(INCLUDE_DIR)/package.mk @@ -37,15 +39,24 @@ ALLWIFIBOARDS:= \ edimax_cax1800 \ glinet_gl-ax1800 \ glinet_gl-axt1800 \ - jdcloud_ax1800pro \ + glinet_gl-b3000 \ jdcloud_re-cs-02 \ + jdcloud_re-ss-01 \ + linksys_homewrk \ + linksys_mr5500 \ linksys_mr7350 \ + linksys_mr7500 \ + linksys_mx2000 \ linksys_mx4200 \ linksys_mx5300 \ + linksys_mx5500 \ + linksys_mx8500 \ netgear_lbr20 \ netgear_rax120v2 \ netgear_wax214 \ netgear_wax218 \ + netgear_wax610 \ + netgear_wax610y \ netgear_wax620 \ netgear_wax630 \ prpl_haze \ @@ -58,6 +69,7 @@ ALLWIFIBOARDS:= \ xiaomi_ax6000 \ xiaomi_ax9000 \ xiaomi_rm1800 \ + yuncore_ax830 \ yuncore_ax880 \ yuncore_fap650 \ zbtlink_zbt-z800ax \ @@ -72,7 +84,7 @@ define Package/ipq-wifi-default SUBMENU:=ath10k Board-Specific Overrides SECTION:=firmware CATEGORY:=Firmware - DEPENDS:=@(TARGET_ipq40xx||TARGET_ipq806x||TARGET_qualcommax) + DEPENDS:=@(TARGET_ipq40xx||TARGET_ipq806x||TARGET_qualcommax||TARGET_qualcommbe) TITLE:=Custom Board endef @@ -86,6 +98,11 @@ define ipq-wifi-install-ath11-one-to $(INSTALL_DATA) $(1) $(2)/lib/firmware/ath11k/$(3)/board-2.bin endef +define ipq-wifi-install-ath12-one-to + $(INSTALL_DIR) $(2)/lib/firmware/ath12k/$(3)/ + $(INSTALL_DATA) $(1) $(2)/lib/firmware/ath12k/$(3)/board-2.bin +endef + define ipq-wifi-install-one $(if $(filter $(suffix $(1)),.QCA4019 .qca4019),\ $(call ipq-wifi-install-one-to,$(1),$(2),QCA4019/hw1.0),\ @@ -107,8 +124,10 @@ define ipq-wifi-install-one $(call ipq-wifi-install-ath11-one-to,$(1),$(2),QCN6122/hw1.0),\ $(if $(filter $(suffix $(1)),.QCN9074 .qcn9074),\ $(call ipq-wifi-install-ath11-one-to,$(1),$(2),QCN9074/hw1.0),\ + $(if $(filter $(suffix $(1)),.QCN9274 .qcn9274),\ + $(call ipq-wifi-install-ath12-one-to,$(1),$(2),QCN9274/hw2.0),\ $(error Unrecognized board-file suffix '$(suffix $(1))' for '$(1)')\ - )))))))))) + ))))))))))) endef # Blank line required at end of above define due to foreach context @@ -155,15 +174,24 @@ $(eval $(call generate-ipq-wifi-package,edgecore_eap102,Edgecore EAP102)) $(eval $(call generate-ipq-wifi-package,edimax_cax1800,Edimax CAX1800)) $(eval $(call generate-ipq-wifi-package,glinet_gl-ax1800,GL.iNet GL-AX1800)) $(eval $(call generate-ipq-wifi-package,glinet_gl-axt1800,GL.iNet GL-AXT1800)) -$(eval $(call generate-ipq-wifi-package,jdcloud_ax1800pro,JDCloud AX1800 Pro)) +$(eval $(call generate-ipq-wifi-package,glinet_gl-b3000,GL.iNet GL-B3000)) $(eval $(call generate-ipq-wifi-package,jdcloud_re-cs-02,JDCloud RE-CS-02)) +$(eval $(call generate-ipq-wifi-package,jdcloud_re-ss-01,JDCloud RE-SS-01)) +$(eval $(call generate-ipq-wifi-package,linksys_homewrk,Linksys HomeWRK)) +$(eval $(call generate-ipq-wifi-package,linksys_mr5500,Linksys MR5500)) $(eval $(call generate-ipq-wifi-package,linksys_mr7350,Linksys MR7350)) +$(eval $(call generate-ipq-wifi-package,linksys_mr7500,Linksys MR7500)) +$(eval $(call generate-ipq-wifi-package,linksys_mx2000,Linksys MX2000)) $(eval $(call generate-ipq-wifi-package,linksys_mx4200,Linksys MX4200)) $(eval $(call generate-ipq-wifi-package,linksys_mx5300,Linksys MX5300)) +$(eval $(call generate-ipq-wifi-package,linksys_mx5500,Linksys MX5500)) +$(eval $(call generate-ipq-wifi-package,linksys_mx8500,Linksys MX8500)) $(eval $(call generate-ipq-wifi-package,netgear_lbr20,Netgear LBR20)) $(eval $(call generate-ipq-wifi-package,netgear_rax120v2,Netgear RAX120v2)) $(eval $(call generate-ipq-wifi-package,netgear_wax214,Netgear WAX214)) $(eval $(call generate-ipq-wifi-package,netgear_wax218,Netgear WAX218)) +$(eval $(call generate-ipq-wifi-package,netgear_wax610,Netgear WAX610)) +$(eval $(call generate-ipq-wifi-package,netgear_wax610y,Netgear WAX610Y)) $(eval $(call generate-ipq-wifi-package,netgear_wax620,Netgear WAX620)) $(eval $(call generate-ipq-wifi-package,netgear_wax630,Netgear WAX630)) $(eval $(call generate-ipq-wifi-package,qihoo_360v6,Qihoo 360V6)) @@ -176,6 +204,7 @@ $(eval $(call generate-ipq-wifi-package,xiaomi_ax3600,Xiaomi AX3600)) $(eval $(call generate-ipq-wifi-package,xiaomi_ax6000,Xiaomi AX6000)) $(eval $(call generate-ipq-wifi-package,xiaomi_ax9000,Xiaomi AX9000)) $(eval $(call generate-ipq-wifi-package,xiaomi_rm1800,Xiaomi RM1800)) +$(eval $(call generate-ipq-wifi-package,yuncore_ax830,Yuncore AX830)) $(eval $(call generate-ipq-wifi-package,yuncore_ax880,Yuncore AX880)) $(eval $(call generate-ipq-wifi-package,yuncore_fap650,Yuncore FAP650)) $(eval $(call generate-ipq-wifi-package,zbtlink_zbt-z800ax,Zbtlink ZBT-Z800AX)) diff --git a/package/firmware/ipq-wifi/src/board-jdcloud_ax1800pro.ipq6018 b/package/firmware/ipq-wifi/src/board-jdcloud_ax1800pro.ipq6018 deleted file mode 100644 index 3a05fe8f1..000000000 Binary files a/package/firmware/ipq-wifi/src/board-jdcloud_ax1800pro.ipq6018 and /dev/null differ diff --git a/package/firmware/ipq-wifi/src/board-jdcloud_re-cs-02.ipq6018 b/package/firmware/ipq-wifi/src/board-jdcloud_re-cs-02.ipq6018 deleted file mode 100644 index 6b39583c5..000000000 Binary files a/package/firmware/ipq-wifi/src/board-jdcloud_re-cs-02.ipq6018 and /dev/null differ diff --git a/package/kernel/linux/modules/video.mk b/package/kernel/linux/modules/video.mk index ab9a1a7e6..6c061ff41 100644 --- a/package/kernel/linux/modules/video.mk +++ b/package/kernel/linux/modules/video.mk @@ -481,15 +481,14 @@ define KernelPackage/drm-amdgpu DEPENDS:=@TARGET_x86 @DISPLAY_SUPPORT +kmod-backlight +kmod-drm-ttm \ +kmod-drm-ttm-helper +kmod-drm-kms-helper +kmod-i2c-algo-bit +amdgpu-firmware \ +kmod-drm-display-helper +kmod-drm-buddy +kmod-acpi-video \ - +(LINUX_6_6||LINUX_6_12):kmod-drm-exec +(LINUX_6_6||LINUX_6_12):kmod-drm-suballoc-helper + +(LINUX_6_6||LINUX_6_12):kmod-drm-exec +(LINUX_6_6||LINUX_6_12):kmod-drm-suballoc-helper +kmod-drm-sched KCONFIG:=CONFIG_DRM_AMDGPU \ CONFIG_DRM_AMDGPU_SI=y \ CONFIG_DRM_AMDGPU_CIK=y \ CONFIG_DRM_AMD_DC=y \ CONFIG_DEBUG_KERNEL_DC=n FILES:=$(LINUX_DIR)/drivers/gpu/drm/amd/amdgpu/amdgpu.ko \ - $(LINUX_DIR)/drivers/gpu/drm/amd/amdxcp/amdxcp.ko@ge6.5 \ - $(LINUX_DIR)/drivers/gpu/drm/scheduler/gpu-sched.ko + $(LINUX_DIR)/drivers/gpu/drm/amd/amdxcp/amdxcp.ko@ge6.5 AUTOLOAD:=$(call AutoProbe,amdgpu) endef @@ -754,6 +753,31 @@ endef $(eval $(call KernelPackage,drm-nouveau)) + +define KernelPackage/drm-xe + SUBMENU:=$(VIDEO_MENU) + TITLE:=Intel Xe GPU drm support + DEPENDS:=@TARGET_x86 +kmod-drm-buddy +kmod-drm-ttm +kmod-drm-kms-helper +kmod-drm-i915 +i915-firmware \ + +kmod-drm-display-helper +kmod-acpi-video \ + +kmod-drm-exec +kmod-drm-suballoc-helper +kmod-drm-sched @LINUX_6_12 + KCONFIG:= \ + CONFIG_DRM_GPUVM \ + CONFIG_DRM_SCHED \ + CONFIG_DRM_XE + FILES:= \ + $(LINUX_DIR)/drivers/gpu/drm/drm_gpuvm.ko \ + $(LINUX_DIR)/drivers/gpu/drm/xe/xe.ko + AUTOLOAD:=$(call AutoProbe,gpu-sched drm_gpuvm xe) +endef + +define KernelPackage/drm-xe/description + The drm/xe driver supports some future GFX cards with rendering, display, + compute and media. Support for currently available platforms like TGL, ADL, + DG2, etc is provided to prototype the driver. +endef + +$(eval $(call KernelPackage,drm-xe)) + # # Video Capture # diff --git a/package/lean/autocore/Makefile b/package/lean/autocore/Makefile index 9bf0ced2b..e3f654945 100644 --- a/package/lean/autocore/Makefile +++ b/package/lean/autocore/Makefile @@ -22,6 +22,13 @@ define Package/autocore-arm VARIANT:=arm endef +define Package/autocore-loongarch64 + TITLE:=Loongarch64 auto core loadbalance script. + MAINTAINER:=LEAN + DEPENDS:=@loongarch64 +bc +ethtool +pciutils + VARIANT:=loongarch64 +endef + define Package/autocore-x86 TITLE:=x86/x64 auto core loadbalance script. MAINTAINER:=Lean @@ -33,6 +40,10 @@ define Package/autocore-arm/description A luci autoconfig hotplug script. endef +define Package/autocore-loongarch64/description + A luci autoconfig hotplug script. +endef + define Package/autocore-x86/description A usb autoconfig hotplug script. endef @@ -57,6 +68,19 @@ endif $(CP) ./files/luci-mod-status-autocore.json $(1)/usr/share/rpcd/acl.d/ endef +define Package/autocore-loongarch64/install + $(INSTALL_DIR) $(1)/etc + $(INSTALL_DIR) $(1)/etc/uci-defaults + $(INSTALL_DIR) $(1)/etc/init.d + $(INSTALL_BIN) ./files/loongarch64/autocore $(1)/etc/init.d/autocore + $(INSTALL_BIN) ./files/60-autocore-reload-rpcd $(1)/etc/uci-defaults/ + $(INSTALL_DIR) $(1)/sbin + $(INSTALL_BIN) ./files/loongarch64/sbin/cpuinfo $(1)/sbin/cpuinfo + $(INSTALL_BIN) ./files/loongarch64/sbin/tempinfo $(1)/sbin/tempinfo + $(INSTALL_DIR) $(1)/usr/share/rpcd/acl.d + $(CP) ./files/luci-mod-status-autocore.json $(1)/usr/share/rpcd/acl.d/ +endef + define Package/autocore-x86/install $(INSTALL_DIR) $(1)/etc/init.d $(INSTALL_BIN) ./files/x86/autocore $(1)/etc/init.d/autocore @@ -71,4 +95,5 @@ define Package/autocore-x86/install endef $(eval $(call BuildPackage,autocore-arm)) +$(eval $(call BuildPackage,autocore-loongarch64)) $(eval $(call BuildPackage,autocore-x86)) diff --git a/package/lean/autocore/files/loongarch64/autocore b/package/lean/autocore/files/loongarch64/autocore new file mode 100755 index 000000000..158f1cec9 --- /dev/null +++ b/package/lean/autocore/files/loongarch64/autocore @@ -0,0 +1,20 @@ +#!/bin/sh /etc/rc.common +# Copyright (C) 2025 lean + +START=99 + +start() +{ + a=$(cat /proc/cpuinfo | grep 'Model Name' | cut -f2 -d: | head -n 1) + b=$(echo -n ' : ') + c=$(cat /proc/cpuinfo | grep 'core' | sort -u | wc -l) + d=$(echo -n 'C') + e=$(cat /proc/cpuinfo | grep 'global_id' | sort -u | wc -l) + f=$(echo -n 'T ') + g=$(cat /proc/cpuinfo | grep 'CPU Family' | cut -f2 -d: | head -n 1) + + h=${g}' - '${a}${b}${c}${d}${e}${f} + + mkdir -p /tmp/sysinfo + echo $h > /tmp/sysinfo/model +} diff --git a/package/lean/autocore/files/loongarch64/sbin/cpuinfo b/package/lean/autocore/files/loongarch64/sbin/cpuinfo new file mode 100755 index 000000000..18ae8e39f --- /dev/null +++ b/package/lean/autocore/files/loongarch64/sbin/cpuinfo @@ -0,0 +1,5 @@ +#!/bin/sh + +MHz=`grep 'MHz' /proc/cpuinfo | cut -c13- |sed -n '1p'` + +echo "$MHz MHz" diff --git a/package/lean/autocore/files/loongarch64/sbin/ethinfo b/package/lean/autocore/files/loongarch64/sbin/ethinfo new file mode 100644 index 000000000..3472e6812 --- /dev/null +++ b/package/lean/autocore/files/loongarch64/sbin/ethinfo @@ -0,0 +1,45 @@ +#!/usr/bin/lua +-- Copyright (C) 2022 ImmortalWrt.org + +local util = require "luci.util" +local jsonc = require "luci.jsonc" + +local eth_info = {} +local ifname, stat + +for ifname, stat in pairs(util.ubus("network.device", "status")) do + while true do + if (ifname:match("^(br-.+)$")) == ifname then + break + else + local status, speed, duplex + + if(stat.speed ~= nil) then + status = stat.carrier and 1 or 0 + + if stat.speed:sub(1, 1) == "-" then + speed = " - " + else + speed = stat.speed:sub(1, -2) .. "Mb/s" + end + + if stat.carrier and stat.speed:sub(-1) == "F" then + duplex = 1 + else + duplex = 0 + end + + eth_info[#eth_info+1] = { name = ifname, status = status, + speed = speed, duplex = duplex } + end + break + end + end +end + +table.sort(eth_info, + function(a, b) + return a.name < b.name + end) + +print(jsonc.stringify(eth_info)) diff --git a/package/lean/autocore/files/loongarch64/sbin/tempinfo b/package/lean/autocore/files/loongarch64/sbin/tempinfo new file mode 100755 index 000000000..ee6e9ec22 --- /dev/null +++ b/package/lean/autocore/files/loongarch64/sbin/tempinfo @@ -0,0 +1,5 @@ +#!/bin/sh + +TEMP=`awk '{printf("%.1f°C", $0 / 1000)}' "/sys/class/thermal/thermal_zone0/temp" 2>"/dev/null"` + +echo "$TEMP " diff --git a/package/network/services/uhttpd/Makefile b/package/network/services/uhttpd/Makefile index 55ca3f681..1fd48adda 100644 --- a/package/network/services/uhttpd/Makefile +++ b/package/network/services/uhttpd/Makefile @@ -12,9 +12,9 @@ PKG_RELEASE:=1 PKG_SOURCE_PROTO:=git PKG_SOURCE_URL=$(PROJECT_GIT)/project/uhttpd.git -PKG_SOURCE_DATE:=2022-10-31 -PKG_SOURCE_VERSION:=23977554d9694d025eada50a5547e99ee1be7838 -PKG_MIRROR_HASH:=e546fd57d0d0be6a51e2aeb5797febe8c89d2bba61b26c930ecb0616d5f6ace9 +PKG_SOURCE_DATE:=2025-10-03 +PKG_SOURCE_VERSION:=ebb92e6b339b88bbc6b76501b6603c52d4887ba1 +PKG_MIRROR_HASH:=331155667553e4ee02cc027558af62e480fd4c863bda3e2a6ec327f38b933323 PKG_MAINTAINER:=Felix Fietkau PKG_LICENSE:=ISC diff --git a/package/system/fstools/Makefile b/package/system/fstools/Makefile index d1249a643..cd3209f44 100644 --- a/package/system/fstools/Makefile +++ b/package/system/fstools/Makefile @@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=fstools -PKG_RELEASE:=1 +PKG_RELEASE:=2 PKG_SOURCE_PROTO:=git PKG_SOURCE_URL=$(PROJECT_GIT)/project/fstools.git diff --git a/package/system/fstools/patches/0300-change-default-f2fs-overlay-size.patch b/package/system/fstools/patches/0300-change-default-f2fs-overlay-size.patch new file mode 100644 index 000000000..1e6e6e83e --- /dev/null +++ b/package/system/fstools/patches/0300-change-default-f2fs-overlay-size.patch @@ -0,0 +1,11 @@ +--- a/libfstools/common.h ++++ b/libfstools/common.h +@@ -19,7 +19,7 @@ + #include "libfstools.h" + #include "volume.h" + +-#define F2FS_MINSIZE (100ULL * 1024ULL * 1024ULL) ++#define F2FS_MINSIZE (1024ULL * 1024ULL * 1024ULL) + + int read_uint_from_file(char *dirname, char *filename, unsigned int *i); + char *read_string_from_file(const char *dirname, const char *filename, char *buf, size_t bufsz); diff --git a/target/linux/amlogic/mesongx/config-6.1 b/target/linux/amlogic/mesongx/config-6.1 index 710913988..f0511c913 100644 --- a/target/linux/amlogic/mesongx/config-6.1 +++ b/target/linux/amlogic/mesongx/config-6.1 @@ -60,7 +60,9 @@ CONFIG_BINFMT_MISC=y CONFIG_BLK_DEV_BSGLIB=y CONFIG_BLK_DEV_BSG_COMMON=y CONFIG_BLK_DEV_INTEGRITY=y +CONFIG_BLK_DEV_INTEGRITY_T10=y CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_SD=y CONFIG_BLK_MQ_PCI=y CONFIG_BLK_MQ_VIRTIO=y CONFIG_BLK_PM=y @@ -532,6 +534,13 @@ CONFIG_SCHED_INFO=y CONFIG_SCHED_MC=y CONFIG_SCHED_SMT=y CONFIG_SCHED_THERMAL_PRESSURE=y +CONFIG_SCSI=y +CONFIG_SCSI_COMMON=y +# CONFIG_SCSI_LOWLEVEL is not set +# CONFIG_SCSI_PROC_FS is not set +CONFIG_SCSI_SAS_ATTRS=y +CONFIG_SCSI_SAS_HOST_SMP=y +CONFIG_SCSI_SAS_LIBSAS=y CONFIG_SECURITY=y # CONFIG_SECURITY_NETWORK is not set CONFIG_SERIAL_8250_FSL=y diff --git a/target/linux/amlogic/patches-6.1/201-fix-i2ca-and-i2cb-miossing-pins.patch b/target/linux/amlogic/patches-6.1/201-fix-i2ca-and-i2cb-missing-pins.patch similarity index 100% rename from target/linux/amlogic/patches-6.1/201-fix-i2ca-and-i2cb-miossing-pins.patch rename to target/linux/amlogic/patches-6.1/201-fix-i2ca-and-i2cb-missing-pins.patch diff --git a/target/linux/bcm27xx/patches-6.12/950-0018-arm64-setup-Fix-build-warning.patch b/target/linux/bcm27xx/patches-6.12/950-0018-arm64-setup-Fix-build-warning.patch index 0867cda6d..cca6e7606 100644 --- a/target/linux/bcm27xx/patches-6.12/950-0018-arm64-setup-Fix-build-warning.patch +++ b/target/linux/bcm27xx/patches-6.12/950-0018-arm64-setup-Fix-build-warning.patch @@ -13,7 +13,7 @@ Signed-off-by: Maxime Ripard @@ -214,9 +214,9 @@ static void __init request_standard_reso size_t res_size; - kernel_code.start = __pa_symbol(_stext); + kernel_code.start = __pa_symbol(_text); - kernel_code.end = __pa_symbol(__init_begin - 1); + kernel_code.end = __pa_symbol(__init_begin) - 1; kernel_data.start = __pa_symbol(_sdata); diff --git a/target/linux/bcm27xx/patches-6.12/950-0073-ASoC-Add-support-for-all-the-downstream-rpi-sound-ca.patch b/target/linux/bcm27xx/patches-6.12/950-0073-ASoC-Add-support-for-all-the-downstream-rpi-sound-ca.patch index 59105068c..c6ce4dd6d 100644 --- a/target/linux/bcm27xx/patches-6.12/950-0073-ASoC-Add-support-for-all-the-downstream-rpi-sound-ca.patch +++ b/target/linux/bcm27xx/patches-6.12/950-0073-ASoC-Add-support-for-all-the-downstream-rpi-sound-ca.patch @@ -18608,7 +18608,7 @@ Signed-off-by: j-schambacher } --- a/sound/usb/card.c +++ b/sound/usb/card.c -@@ -869,8 +869,14 @@ static int usb_audio_probe(struct usb_in +@@ -875,8 +875,14 @@ static int usb_audio_probe(struct usb_in if (ignore_ctl_error) chip->quirk_flags |= QUIRK_FLAG_IGNORE_CTL_ERROR; @@ -18626,7 +18626,7 @@ Signed-off-by: j-schambacher * For devices with more than one control interface, we assume the --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c -@@ -2360,6 +2360,8 @@ static const struct usb_audio_quirk_flag +@@ -2378,6 +2378,8 @@ static const struct usb_audio_quirk_flag QUIRK_FLAG_ALIGN_TRANSFER), DEVICE_FLG(0x534d, 0x2109, /* MacroSilicon MS2109 */ QUIRK_FLAG_ALIGN_TRANSFER), diff --git a/target/linux/bcm27xx/patches-6.12/950-0094-net-lan78xx-Disable-TCP-Segmentation-Offload-TSO.patch b/target/linux/bcm27xx/patches-6.12/950-0094-net-lan78xx-Disable-TCP-Segmentation-Offload-TSO.patch index 0d6a293ff..9d9b3dcb5 100644 --- a/target/linux/bcm27xx/patches-6.12/950-0094-net-lan78xx-Disable-TCP-Segmentation-Offload-TSO.patch +++ b/target/linux/bcm27xx/patches-6.12/950-0094-net-lan78xx-Disable-TCP-Segmentation-Offload-TSO.patch @@ -37,7 +37,7 @@ Signed-off-by: Dave Stevenson static int lan78xx_read_reg(struct lan78xx_net *dev, u32 index, u32 *data) { u32 *buf; -@@ -3444,8 +3453,14 @@ static int lan78xx_bind(struct lan78xx_n +@@ -3464,8 +3473,14 @@ static int lan78xx_bind(struct lan78xx_n if (DEFAULT_RX_CSUM_ENABLE) dev->net->features |= NETIF_F_RXCSUM; diff --git a/target/linux/bcm27xx/patches-6.12/950-0096-lan78xx-Debounce-link-events-to-minimize-poll-storm.patch b/target/linux/bcm27xx/patches-6.12/950-0096-lan78xx-Debounce-link-events-to-minimize-poll-storm.patch index 9eb0f8733..79881ca14 100644 --- a/target/linux/bcm27xx/patches-6.12/950-0096-lan78xx-Debounce-link-events-to-minimize-poll-storm.patch +++ b/target/linux/bcm27xx/patches-6.12/950-0096-lan78xx-Debounce-link-events-to-minimize-poll-storm.patch @@ -28,7 +28,7 @@ See: https://github.com/raspberrypi/linux/issues/2447 static int lan78xx_read_reg(struct lan78xx_net *dev, u32 index, u32 *data) { u32 *buf; -@@ -4428,7 +4433,13 @@ static int lan78xx_probe(struct usb_inte +@@ -4448,7 +4453,13 @@ static int lan78xx_probe(struct usb_inte if (ret < 0) goto out4; diff --git a/target/linux/bcm27xx/patches-6.12/950-0098-Patching-lan78xx-for-SOF_TIMESTAMPING_TX_SOFTWARE-su.patch b/target/linux/bcm27xx/patches-6.12/950-0098-Patching-lan78xx-for-SOF_TIMESTAMPING_TX_SOFTWARE-su.patch index d430674c2..de734ca0c 100644 --- a/target/linux/bcm27xx/patches-6.12/950-0098-Patching-lan78xx-for-SOF_TIMESTAMPING_TX_SOFTWARE-su.patch +++ b/target/linux/bcm27xx/patches-6.12/950-0098-Patching-lan78xx-for-SOF_TIMESTAMPING_TX_SOFTWARE-su.patch @@ -16,4 +16,4 @@ Subject: [PATCH] Patching lan78xx for SOF_TIMESTAMPING_TX_SOFTWARE support + .get_ts_info = ethtool_op_get_ts_info, }; - static void lan78xx_init_mac_address(struct lan78xx_net *dev) + static int lan78xx_init_mac_address(struct lan78xx_net *dev) diff --git a/target/linux/bcm27xx/patches-6.12/950-0099-lan78xx-Enable-LEDs-and-auto-negotiation.patch b/target/linux/bcm27xx/patches-6.12/950-0099-lan78xx-Enable-LEDs-and-auto-negotiation.patch index c55ffd049..4137adb1f 100644 --- a/target/linux/bcm27xx/patches-6.12/950-0099-lan78xx-Enable-LEDs-and-auto-negotiation.patch +++ b/target/linux/bcm27xx/patches-6.12/950-0099-lan78xx-Enable-LEDs-and-auto-negotiation.patch @@ -14,7 +14,7 @@ Signed-off-by: Phil Elwell --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c -@@ -2897,6 +2897,11 @@ static int lan78xx_reset(struct lan78xx_ +@@ -2915,6 +2915,11 @@ static int lan78xx_reset(struct lan78xx_ int ret; u32 buf; u8 sig; @@ -26,7 +26,7 @@ Signed-off-by: Phil Elwell ret = lan78xx_read_reg(dev, HW_CFG, &buf); if (ret < 0) -@@ -2963,6 +2968,10 @@ static int lan78xx_reset(struct lan78xx_ +@@ -2983,6 +2988,10 @@ static int lan78xx_reset(struct lan78xx_ buf |= HW_CFG_CLK125_EN_; buf |= HW_CFG_REFCLK25_EN_; @@ -37,7 +37,7 @@ Signed-off-by: Phil Elwell ret = lan78xx_write_reg(dev, HW_CFG, buf); if (ret < 0) return ret; -@@ -3065,6 +3074,9 @@ static int lan78xx_reset(struct lan78xx_ +@@ -3085,6 +3094,9 @@ static int lan78xx_reset(struct lan78xx_ buf |= MAC_CR_AUTO_DUPLEX_ | MAC_CR_AUTO_SPEED_; } } diff --git a/target/linux/bcm27xx/patches-6.12/950-0125-xhci-implement-xhci_fixup_endpoint-for-interval-adju.patch b/target/linux/bcm27xx/patches-6.12/950-0125-xhci-implement-xhci_fixup_endpoint-for-interval-adju.patch index 1860bf173..0491be436 100644 --- a/target/linux/bcm27xx/patches-6.12/950-0125-xhci-implement-xhci_fixup_endpoint-for-interval-adju.patch +++ b/target/linux/bcm27xx/patches-6.12/950-0125-xhci-implement-xhci_fixup_endpoint-for-interval-adju.patch @@ -14,7 +14,7 @@ Signed-off-by: Jonathan Bell --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c -@@ -1519,6 +1519,109 @@ static int xhci_check_ep0_maxpacket(stru +@@ -1515,6 +1515,109 @@ static int xhci_check_ep0_maxpacket(stru } /* @@ -124,7 +124,7 @@ Signed-off-by: Jonathan Bell * non-error returns are a promise to giveback() the urb later * we drop ownership so next owner (or urb unlink) can get it */ -@@ -5390,6 +5493,7 @@ static const struct hc_driver xhci_hc_dr +@@ -5386,6 +5489,7 @@ static const struct hc_driver xhci_hc_dr .endpoint_reset = xhci_endpoint_reset, .check_bandwidth = xhci_check_bandwidth, .reset_bandwidth = xhci_reset_bandwidth, diff --git a/target/linux/bcm27xx/patches-6.12/950-0127-usb-xhci-drop-and-add-the-endpoint-context-in-xhci_f.patch b/target/linux/bcm27xx/patches-6.12/950-0127-usb-xhci-drop-and-add-the-endpoint-context-in-xhci_f.patch index 1ac575a2c..e2f7caeaf 100644 --- a/target/linux/bcm27xx/patches-6.12/950-0127-usb-xhci-drop-and-add-the-endpoint-context-in-xhci_f.patch +++ b/target/linux/bcm27xx/patches-6.12/950-0127-usb-xhci-drop-and-add-the-endpoint-context-in-xhci_f.patch @@ -19,7 +19,7 @@ Signed-off-by: Jonathan Bell --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c -@@ -1608,7 +1608,7 @@ static void xhci_fixup_endpoint(struct u +@@ -1604,7 +1604,7 @@ static void xhci_fixup_endpoint(struct u return; } ctrl_ctx->add_flags = xhci_get_endpoint_flag_from_index(ep_index); diff --git a/target/linux/bcm27xx/patches-6.12/950-0322-Bluetooth-hci_sync-Add-fallback-bd-address-prop.patch b/target/linux/bcm27xx/patches-6.12/950-0322-Bluetooth-hci_sync-Add-fallback-bd-address-prop.patch index d5a21169b..81e8d31c1 100644 --- a/target/linux/bcm27xx/patches-6.12/950-0322-Bluetooth-hci_sync-Add-fallback-bd-address-prop.patch +++ b/target/linux/bcm27xx/patches-6.12/950-0322-Bluetooth-hci_sync-Add-fallback-bd-address-prop.patch @@ -20,7 +20,7 @@ Signed-off-by: Phil Elwell --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c -@@ -4921,6 +4921,7 @@ static const struct { +@@ -4930,6 +4930,7 @@ static const struct { */ static int hci_dev_setup_sync(struct hci_dev *hdev) { @@ -28,7 +28,7 @@ Signed-off-by: Phil Elwell int ret = 0; bool invalid_bdaddr; size_t i; -@@ -4949,7 +4950,8 @@ static int hci_dev_setup_sync(struct hci +@@ -4958,7 +4959,8 @@ static int hci_dev_setup_sync(struct hci test_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks); if (!ret) { if (test_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks) && diff --git a/target/linux/bcm27xx/patches-6.12/950-0331-serial-sc16is7xx-Read-modem-line-state-at-startup.patch b/target/linux/bcm27xx/patches-6.12/950-0331-serial-sc16is7xx-Read-modem-line-state-at-startup.patch index 57945f6e8..686aba0ec 100644 --- a/target/linux/bcm27xx/patches-6.12/950-0331-serial-sc16is7xx-Read-modem-line-state-at-startup.patch +++ b/target/linux/bcm27xx/patches-6.12/950-0331-serial-sc16is7xx-Read-modem-line-state-at-startup.patch @@ -16,7 +16,7 @@ Signed-off-by: Phil Elwell --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c -@@ -1206,6 +1206,9 @@ static int sc16is7xx_startup(struct uart +@@ -1196,6 +1196,9 @@ static int sc16is7xx_startup(struct uart SC16IS7XX_IER_MSI_BIT; sc16is7xx_port_write(port, SC16IS7XX_IER_REG, val); diff --git a/target/linux/bcm27xx/patches-6.12/950-0333-xhci-quirks-add-link-TRB-quirk-for-VL805.patch b/target/linux/bcm27xx/patches-6.12/950-0333-xhci-quirks-add-link-TRB-quirk-for-VL805.patch index f28330893..fad1aafc0 100644 --- a/target/linux/bcm27xx/patches-6.12/950-0333-xhci-quirks-add-link-TRB-quirk-for-VL805.patch +++ b/target/linux/bcm27xx/patches-6.12/950-0333-xhci-quirks-add-link-TRB-quirk-for-VL805.patch @@ -53,7 +53,7 @@ Signed-off-by: Jonathan Bell if (addr == 0) { --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h -@@ -1628,6 +1628,9 @@ struct xhci_hcd { +@@ -1631,6 +1631,9 @@ struct xhci_hcd { #define XHCI_ETRON_HOST BIT_ULL(49) #define XHCI_LIMIT_ENDPOINT_INTERVAL_9 BIT_ULL(50) diff --git a/target/linux/bcm27xx/patches-6.12/950-0334-usb-xhci-add-VLI_SS_BULK_OUT_BUG-quirk.patch b/target/linux/bcm27xx/patches-6.12/950-0334-usb-xhci-add-VLI_SS_BULK_OUT_BUG-quirk.patch index 4e1c1bd76..56708d6bc 100644 --- a/target/linux/bcm27xx/patches-6.12/950-0334-usb-xhci-add-VLI_SS_BULK_OUT_BUG-quirk.patch +++ b/target/linux/bcm27xx/patches-6.12/950-0334-usb-xhci-add-VLI_SS_BULK_OUT_BUG-quirk.patch @@ -34,7 +34,7 @@ Signed-off-by: Jonathan Bell --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c -@@ -1397,6 +1397,7 @@ int xhci_endpoint_init(struct xhci_hcd * +@@ -1387,6 +1387,7 @@ int xhci_endpoint_init(struct xhci_hcd * unsigned int ep_index; struct xhci_ep_ctx *ep_ctx; struct xhci_ring *ep_ring; @@ -42,7 +42,7 @@ Signed-off-by: Jonathan Bell unsigned int max_packet; enum xhci_ring_type ring_type; u32 max_esit_payload; -@@ -1406,6 +1407,8 @@ int xhci_endpoint_init(struct xhci_hcd * +@@ -1396,6 +1397,8 @@ int xhci_endpoint_init(struct xhci_hcd * unsigned int mult; unsigned int avg_trb_len; unsigned int err_count = 0; @@ -51,7 +51,7 @@ Signed-off-by: Jonathan Bell ep_index = xhci_get_endpoint_index(&ep->desc); ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index); -@@ -1441,9 +1444,35 @@ int xhci_endpoint_init(struct xhci_hcd * +@@ -1431,9 +1434,35 @@ int xhci_endpoint_init(struct xhci_hcd * mult = xhci_get_endpoint_mult(udev, ep); max_packet = usb_endpoint_maxp(&ep->desc); @@ -100,7 +100,7 @@ Signed-off-by: Jonathan Bell if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA && --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h -@@ -1630,6 +1630,7 @@ struct xhci_hcd { +@@ -1633,6 +1633,7 @@ struct xhci_hcd { /* Downstream VLI fixes */ #define XHCI_AVOID_DQ_ON_LINK BIT_ULL(56) diff --git a/target/linux/bcm27xx/patches-6.12/950-0335-usb-xhci-add-XHCI_VLI_HUB_TT_QUIRK.patch b/target/linux/bcm27xx/patches-6.12/950-0335-usb-xhci-add-XHCI_VLI_HUB_TT_QUIRK.patch index c1731fb1d..9abbcd0ba 100644 --- a/target/linux/bcm27xx/patches-6.12/950-0335-usb-xhci-add-XHCI_VLI_HUB_TT_QUIRK.patch +++ b/target/linux/bcm27xx/patches-6.12/950-0335-usb-xhci-add-XHCI_VLI_HUB_TT_QUIRK.patch @@ -75,7 +75,7 @@ Signed-off-by: Jonathan Bell if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA && --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c -@@ -3664,6 +3664,48 @@ static int xhci_align_td(struct xhci_hcd +@@ -3661,6 +3661,48 @@ static int xhci_align_td(struct xhci_hcd return 1; } @@ -124,7 +124,7 @@ Signed-off-by: Jonathan Bell /* This is very similar to what ehci-q.c qtd_fill() does */ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb, int slot_id, unsigned int ep_index) -@@ -3818,6 +3860,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd * +@@ -3815,6 +3857,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd * } check_trb_math(urb, enqd_len); @@ -133,7 +133,7 @@ Signed-off-by: Jonathan Bell giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id, start_cycle, start_trb); return 0; -@@ -3966,6 +4010,8 @@ int xhci_queue_ctrl_tx(struct xhci_hcd * +@@ -3963,6 +4007,8 @@ int xhci_queue_ctrl_tx(struct xhci_hcd * /* Event on completion */ field | TRB_IOC | TRB_TYPE(TRB_STATUS) | ep_ring->cycle_state); @@ -144,7 +144,7 @@ Signed-off-by: Jonathan Bell return 0; --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h -@@ -1631,6 +1631,7 @@ struct xhci_hcd { +@@ -1634,6 +1634,7 @@ struct xhci_hcd { /* Downstream VLI fixes */ #define XHCI_AVOID_DQ_ON_LINK BIT_ULL(56) #define XHCI_VLI_SS_BULK_OUT_BUG BIT_ULL(57) diff --git a/target/linux/bcm27xx/patches-6.12/950-0401-xhci-Use-more-event-ring-segment-table-entries.patch b/target/linux/bcm27xx/patches-6.12/950-0401-xhci-Use-more-event-ring-segment-table-entries.patch index 6baba3b44..f74985e43 100644 --- a/target/linux/bcm27xx/patches-6.12/950-0401-xhci-Use-more-event-ring-segment-table-entries.patch +++ b/target/linux/bcm27xx/patches-6.12/950-0401-xhci-Use-more-event-ring-segment-table-entries.patch @@ -21,7 +21,7 @@ Signed-off-by: Jonathan Bell --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h -@@ -1395,7 +1395,7 @@ struct urb_priv { +@@ -1398,7 +1398,7 @@ struct urb_priv { }; /* Number of Event Ring segments to allocate, when amount is not specified. (spec allows 32k) */ diff --git a/target/linux/bcm27xx/patches-6.12/950-0476-lan78xx-Read-initial-EEE-status-from-DT.patch b/target/linux/bcm27xx/patches-6.12/950-0476-lan78xx-Read-initial-EEE-status-from-DT.patch index 945e0a5b1..1c2ec17d5 100644 --- a/target/linux/bcm27xx/patches-6.12/950-0476-lan78xx-Read-initial-EEE-status-from-DT.patch +++ b/target/linux/bcm27xx/patches-6.12/950-0476-lan78xx-Read-initial-EEE-status-from-DT.patch @@ -15,7 +15,7 @@ Signed-off-by: Phil Elwell --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c -@@ -2422,7 +2422,26 @@ static int lan78xx_phy_init(struct lan78 +@@ -2440,7 +2440,26 @@ static int lan78xx_phy_init(struct lan78 mii_adv_to_linkmode_adv_t(fc, mii_adv); linkmode_or(phydev->advertising, fc, phydev->advertising); diff --git a/target/linux/bcm27xx/patches-6.12/950-0502-Bluetooth-hci_sync-Fix-crash-on-NULL-parent.patch b/target/linux/bcm27xx/patches-6.12/950-0502-Bluetooth-hci_sync-Fix-crash-on-NULL-parent.patch index 2b1d52359..cb98eb72f 100644 --- a/target/linux/bcm27xx/patches-6.12/950-0502-Bluetooth-hci_sync-Fix-crash-on-NULL-parent.patch +++ b/target/linux/bcm27xx/patches-6.12/950-0502-Bluetooth-hci_sync-Fix-crash-on-NULL-parent.patch @@ -15,7 +15,7 @@ Signed-off-by: Phil Elwell --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c -@@ -4921,7 +4921,8 @@ static const struct { +@@ -4930,7 +4930,8 @@ static const struct { */ static int hci_dev_setup_sync(struct hci_dev *hdev) { diff --git a/target/linux/bcm27xx/patches-6.12/950-0534-drivers-usb-xhci-set-HID-bit-in-streaming-endpoint-c.patch b/target/linux/bcm27xx/patches-6.12/950-0534-drivers-usb-xhci-set-HID-bit-in-streaming-endpoint-c.patch index 9a052443c..9d0a6e205 100644 --- a/target/linux/bcm27xx/patches-6.12/950-0534-drivers-usb-xhci-set-HID-bit-in-streaming-endpoint-c.patch +++ b/target/linux/bcm27xx/patches-6.12/950-0534-drivers-usb-xhci-set-HID-bit-in-streaming-endpoint-c.patch @@ -28,7 +28,7 @@ Signed-off-by: Jonathan Bell --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c -@@ -715,6 +715,14 @@ void xhci_setup_streams_ep_input_ctx(str +@@ -705,6 +705,14 @@ void xhci_setup_streams_ep_input_ctx(str ep_ctx->ep_info &= cpu_to_le32(~EP_MAXPSTREAMS_MASK); ep_ctx->ep_info |= cpu_to_le32(EP_MAXPSTREAMS(max_primary_streams) | EP_HAS_LSA); diff --git a/target/linux/bcm27xx/patches-6.12/950-0685-nvme-pci-Disable-Host-Memory-Buffer-usage.patch b/target/linux/bcm27xx/patches-6.12/950-0685-nvme-pci-Disable-Host-Memory-Buffer-usage.patch index 5ae8f6c96..a299c6c57 100644 --- a/target/linux/bcm27xx/patches-6.12/950-0685-nvme-pci-Disable-Host-Memory-Buffer-usage.patch +++ b/target/linux/bcm27xx/patches-6.12/950-0685-nvme-pci-Disable-Host-Memory-Buffer-usage.patch @@ -18,7 +18,7 @@ Signed-off-by: Phil Elwell --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c -@@ -2103,6 +2103,7 @@ static void nvme_free_host_mem(struct nv +@@ -2106,6 +2106,7 @@ static void nvme_free_host_mem(struct nv dev->nr_host_mem_descs = 0; } @@ -26,7 +26,7 @@ Signed-off-by: Phil Elwell static int __nvme_alloc_host_mem(struct nvme_dev *dev, u64 preferred, u32 chunk_size) { -@@ -2171,9 +2172,11 @@ out: +@@ -2174,9 +2175,11 @@ out: dev->host_mem_descs = NULL; return -ENOMEM; } @@ -38,7 +38,7 @@ Signed-off-by: Phil Elwell u64 min_chunk = min_t(u64, preferred, PAGE_SIZE * MAX_ORDER_NR_PAGES); u64 hmminds = max_t(u32, dev->ctrl.hmminds * 4096, PAGE_SIZE * 2); u64 chunk_size; -@@ -2186,6 +2189,7 @@ static int nvme_alloc_host_mem(struct nv +@@ -2189,6 +2192,7 @@ static int nvme_alloc_host_mem(struct nv nvme_free_host_mem(dev); } } diff --git a/target/linux/bcm27xx/patches-6.12/950-0692-cgroup-Add-cgroup_enable-option.patch b/target/linux/bcm27xx/patches-6.12/950-0692-cgroup-Add-cgroup_enable-option.patch index 9ea92a5f3..d44e050e0 100644 --- a/target/linux/bcm27xx/patches-6.12/950-0692-cgroup-Add-cgroup_enable-option.patch +++ b/target/linux/bcm27xx/patches-6.12/950-0692-cgroup-Add-cgroup_enable-option.patch @@ -17,7 +17,7 @@ Signed-off-by: Phil Elwell --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c -@@ -6887,6 +6887,39 @@ static int __init cgroup_disable(char *s +@@ -6916,6 +6916,39 @@ static int __init cgroup_disable(char *s } __setup("cgroup_disable=", cgroup_disable); diff --git a/target/linux/bcm27xx/patches-6.12/950-0702-serial-sc16is7xx-announce-support-for-SER_RS485_RTS_.patch b/target/linux/bcm27xx/patches-6.12/950-0702-serial-sc16is7xx-announce-support-for-SER_RS485_RTS_.patch index 5de1b1c4a..7a8b37a00 100644 --- a/target/linux/bcm27xx/patches-6.12/950-0702-serial-sc16is7xx-announce-support-for-SER_RS485_RTS_.patch +++ b/target/linux/bcm27xx/patches-6.12/950-0702-serial-sc16is7xx-announce-support-for-SER_RS485_RTS_.patch @@ -31,7 +31,7 @@ Signed-off-by: Greg Kroah-Hartman --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c -@@ -1478,7 +1478,7 @@ static int sc16is7xx_setup_mctrl_ports(s +@@ -1468,7 +1468,7 @@ static int sc16is7xx_setup_mctrl_ports(s } static const struct serial_rs485 sc16is7xx_rs485_supported = { diff --git a/target/linux/bcm27xx/patches-6.12/950-0830-media-mc-add-debugfs-node-to-keep-track-of-requests.patch b/target/linux/bcm27xx/patches-6.12/950-0830-media-mc-add-debugfs-node-to-keep-track-of-requests.patch index 0e31e290e..7ad80a032 100644 --- a/target/linux/bcm27xx/patches-6.12/950-0830-media-mc-add-debugfs-node-to-keep-track-of-requests.patch +++ b/target/linux/bcm27xx/patches-6.12/950-0830-media-mc-add-debugfs-node-to-keep-track-of-requests.patch @@ -88,7 +88,7 @@ Signed-off-by: Hans Verkuil /* Called when the last user of the media device exits. */ static void media_devnode_release(struct device *cd) { -@@ -236,6 +239,7 @@ int __must_check media_devnode_register( +@@ -231,6 +234,7 @@ int __must_check media_devnode_register( if (devnode->parent) devnode->dev.parent = devnode->parent; dev_set_name(&devnode->dev, "media%d", devnode->minor); @@ -96,7 +96,7 @@ Signed-off-by: Hans Verkuil device_initialize(&devnode->dev); /* Part 2: Initialize the character device */ -@@ -313,6 +317,7 @@ static int __init media_devnode_init(voi +@@ -309,6 +313,7 @@ static int __init media_devnode_init(voi static void __exit media_devnode_exit(void) { diff --git a/target/linux/bcm27xx/patches-6.12/950-0950-usb-xhci-default-to-Intel-scheme-for-calculating-U1-.patch b/target/linux/bcm27xx/patches-6.12/950-0950-usb-xhci-default-to-Intel-scheme-for-calculating-U1-.patch index 06b91a6ce..33f8ca71a 100644 --- a/target/linux/bcm27xx/patches-6.12/950-0950-usb-xhci-default-to-Intel-scheme-for-calculating-U1-.patch +++ b/target/linux/bcm27xx/patches-6.12/950-0950-usb-xhci-default-to-Intel-scheme-for-calculating-U1-.patch @@ -39,8 +39,8 @@ Signed-off-by: Jonathan Bell + static bool td_on_ring(struct xhci_td *td, struct xhci_ring *ring) { - struct xhci_segment *seg = ring->first_seg; -@@ -4795,7 +4799,7 @@ static u16 xhci_calculate_u1_timeout(str + struct xhci_segment *seg; +@@ -4791,7 +4795,7 @@ static u16 xhci_calculate_u1_timeout(str } } @@ -49,7 +49,7 @@ Signed-off-by: Jonathan Bell timeout_ns = xhci_calculate_intel_u1_timeout(udev, desc); else timeout_ns = udev->u1_params.sel; -@@ -4859,7 +4863,7 @@ static u16 xhci_calculate_u2_timeout(str +@@ -4855,7 +4859,7 @@ static u16 xhci_calculate_u2_timeout(str } } diff --git a/target/linux/generic/backport-6.12/203-v6.15-drivers-base-component-add-function-to-query-the-bound.patch b/target/linux/generic/backport-6.12/203-v6.15-drivers-base-component-add-function-to-query-the-bound.patch new file mode 100644 index 000000000..201bd229a --- /dev/null +++ b/target/linux/generic/backport-6.12/203-v6.15-drivers-base-component-add-function-to-query-the-bound.patch @@ -0,0 +1,69 @@ +From a6ba2dad0aa4f623ab0def8b6e6888ac00639055 Mon Sep 17 00:00:00 2001 +From: Heiko Stuebner +Date: Fri, 21 Feb 2025 00:41:40 +0100 +Subject: [PATCH] drivers: base: component: add function to query the bound + status + +The component helpers already expose the bound status in debugfs, but at +times it might be necessary to also check that state in the kernel and +act differently depending on the result. + +For example the shutdown handler of a drm-driver might need to stop +a whole output pipeline if the drm device is up and running, but may +run into problems if that drm-device has never been set up before, +for example because the binding deferred. + +So add a little helper that returns the bound status for a componet +device. + +Acked-by: Greg Kroah-Hartman +Signed-off-by: Heiko Stuebner +Link: https://patchwork.freedesktop.org/patch/msgid/20250220234141.2788785-2-heiko@sntech.de +--- + drivers/base/component.c | 14 ++++++++++++++ + include/linux/component.h | 4 +++- + 2 files changed, 17 insertions(+), 1 deletion(-) + +--- a/drivers/base/component.c ++++ b/drivers/base/component.c +@@ -569,6 +569,20 @@ void component_master_del(struct device + } + EXPORT_SYMBOL_GPL(component_master_del); + ++bool component_master_is_bound(struct device *parent, ++ const struct component_master_ops *ops) ++{ ++ struct aggregate_device *adev; ++ ++ guard(mutex)(&component_mutex); ++ adev = __aggregate_find(parent, ops); ++ if (!adev) ++ return 0; ++ ++ return adev->bound; ++} ++EXPORT_SYMBOL_GPL(component_master_is_bound); ++ + static void component_unbind(struct component *component, + struct aggregate_device *adev, void *data) + { +--- a/include/linux/component.h ++++ b/include/linux/component.h +@@ -3,7 +3,7 @@ + #define COMPONENT_H + + #include +- ++#include + + struct device; + +@@ -90,6 +90,8 @@ int component_compare_dev_name(struct de + + void component_master_del(struct device *, + const struct component_master_ops *); ++bool component_master_is_bound(struct device *parent, ++ const struct component_master_ops *ops); + + struct component_match; + diff --git a/target/linux/generic/hack-5.10/983-add-bcm-fullconenat-to-nft.patch b/target/linux/generic/hack-5.10/983-add-bcm-fullconenat-to-nft.patch new file mode 100644 index 000000000..bb1cd62a3 --- /dev/null +++ b/target/linux/generic/hack-5.10/983-add-bcm-fullconenat-to-nft.patch @@ -0,0 +1,65 @@ +--- a/include/uapi/linux/netfilter/nf_tables.h ++++ b/include/uapi/linux/netfilter/nf_tables.h +@@ -1477,12 +1477,14 @@ enum nft_tproxy_attributes { + * @NFTA_MASQ_FLAGS: NAT flags (see NF_NAT_RANGE_* in linux/netfilter/nf_nat.h) (NLA_U32) + * @NFTA_MASQ_REG_PROTO_MIN: source register of proto range start (NLA_U32: nft_registers) + * @NFTA_MASQ_REG_PROTO_MAX: source register of proto range end (NLA_U32: nft_registers) ++ * @NFTA_MASQ_REG_FULLCONE: fullcone NAT (NLA_U8) + */ + enum nft_masq_attributes { + NFTA_MASQ_UNSPEC, + NFTA_MASQ_FLAGS, + NFTA_MASQ_REG_PROTO_MIN, + NFTA_MASQ_REG_PROTO_MAX, ++ NFTA_MASQ_REG_FULLCONE, + __NFTA_MASQ_MAX + }; + #define NFTA_MASQ_MAX (__NFTA_MASQ_MAX - 1) +--- a/net/netfilter/nft_masq.c ++++ b/net/netfilter/nft_masq.c +@@ -17,6 +17,7 @@ struct nft_masq { + u32 flags; + u8 sreg_proto_min; + u8 sreg_proto_max; ++ bool fullcone; + }; + + static const struct nla_policy nft_masq_policy[NFTA_MASQ_MAX + 1] = { +@@ -24,6 +25,7 @@ static const struct nla_policy nft_masq_ + NLA_POLICY_MASK(NLA_BE32, NF_NAT_RANGE_MASK), + [NFTA_MASQ_REG_PROTO_MIN] = { .type = NLA_U32 }, + [NFTA_MASQ_REG_PROTO_MAX] = { .type = NLA_U32 }, ++ [NFTA_MASQ_REG_FULLCONE] = { .type = NLA_U8 }, + }; + + static int nft_masq_validate(const struct nft_ctx *ctx, +@@ -51,6 +53,9 @@ static int nft_masq_init(const struct nf + if (tb[NFTA_MASQ_FLAGS]) + priv->flags = ntohl(nla_get_be32(tb[NFTA_MASQ_FLAGS])); + ++ if (tb[NFTA_MASQ_REG_FULLCONE]) ++ priv->fullcone = nla_get_u8(tb[NFTA_MASQ_REG_FULLCONE]); ++ + if (tb[NFTA_MASQ_REG_PROTO_MIN]) { + err = nft_parse_register_load(tb[NFTA_MASQ_REG_PROTO_MIN], + &priv->sreg_proto_min, plen); +@@ -80,6 +85,9 @@ static int nft_masq_dump(struct sk_buff + nla_put_be32(skb, NFTA_MASQ_FLAGS, htonl(priv->flags))) + goto nla_put_failure; + ++ if (priv->fullcone && nla_put_u8(skb, NFTA_MASQ_REG_FULLCONE, 1)) ++ goto nla_put_failure; ++ + if (priv->sreg_proto_min) { + if (nft_dump_register(skb, NFTA_MASQ_REG_PROTO_MIN, + priv->sreg_proto_min) || +@@ -112,6 +120,9 @@ static void nft_masq_eval(const struct n + { + switch (nft_pf(pkt)) { + case NFPROTO_IPV4: ++ if (priv->fullcone) { ++ range.min_addr.ip = 1; ++ } + return nft_masq_ipv4_eval(expr, regs, pkt); + case NFPROTO_IPV6: + return nft_masq_ipv6_eval(expr, regs, pkt); diff --git a/target/linux/generic/hack-5.15/983-add-bcm-fullconenat-to-nft.patch b/target/linux/generic/hack-5.15/983-add-bcm-fullconenat-to-nft.patch new file mode 100644 index 000000000..bb1cd62a3 --- /dev/null +++ b/target/linux/generic/hack-5.15/983-add-bcm-fullconenat-to-nft.patch @@ -0,0 +1,65 @@ +--- a/include/uapi/linux/netfilter/nf_tables.h ++++ b/include/uapi/linux/netfilter/nf_tables.h +@@ -1477,12 +1477,14 @@ enum nft_tproxy_attributes { + * @NFTA_MASQ_FLAGS: NAT flags (see NF_NAT_RANGE_* in linux/netfilter/nf_nat.h) (NLA_U32) + * @NFTA_MASQ_REG_PROTO_MIN: source register of proto range start (NLA_U32: nft_registers) + * @NFTA_MASQ_REG_PROTO_MAX: source register of proto range end (NLA_U32: nft_registers) ++ * @NFTA_MASQ_REG_FULLCONE: fullcone NAT (NLA_U8) + */ + enum nft_masq_attributes { + NFTA_MASQ_UNSPEC, + NFTA_MASQ_FLAGS, + NFTA_MASQ_REG_PROTO_MIN, + NFTA_MASQ_REG_PROTO_MAX, ++ NFTA_MASQ_REG_FULLCONE, + __NFTA_MASQ_MAX + }; + #define NFTA_MASQ_MAX (__NFTA_MASQ_MAX - 1) +--- a/net/netfilter/nft_masq.c ++++ b/net/netfilter/nft_masq.c +@@ -17,6 +17,7 @@ struct nft_masq { + u32 flags; + u8 sreg_proto_min; + u8 sreg_proto_max; ++ bool fullcone; + }; + + static const struct nla_policy nft_masq_policy[NFTA_MASQ_MAX + 1] = { +@@ -24,6 +25,7 @@ static const struct nla_policy nft_masq_ + NLA_POLICY_MASK(NLA_BE32, NF_NAT_RANGE_MASK), + [NFTA_MASQ_REG_PROTO_MIN] = { .type = NLA_U32 }, + [NFTA_MASQ_REG_PROTO_MAX] = { .type = NLA_U32 }, ++ [NFTA_MASQ_REG_FULLCONE] = { .type = NLA_U8 }, + }; + + static int nft_masq_validate(const struct nft_ctx *ctx, +@@ -51,6 +53,9 @@ static int nft_masq_init(const struct nf + if (tb[NFTA_MASQ_FLAGS]) + priv->flags = ntohl(nla_get_be32(tb[NFTA_MASQ_FLAGS])); + ++ if (tb[NFTA_MASQ_REG_FULLCONE]) ++ priv->fullcone = nla_get_u8(tb[NFTA_MASQ_REG_FULLCONE]); ++ + if (tb[NFTA_MASQ_REG_PROTO_MIN]) { + err = nft_parse_register_load(tb[NFTA_MASQ_REG_PROTO_MIN], + &priv->sreg_proto_min, plen); +@@ -80,6 +85,9 @@ static int nft_masq_dump(struct sk_buff + nla_put_be32(skb, NFTA_MASQ_FLAGS, htonl(priv->flags))) + goto nla_put_failure; + ++ if (priv->fullcone && nla_put_u8(skb, NFTA_MASQ_REG_FULLCONE, 1)) ++ goto nla_put_failure; ++ + if (priv->sreg_proto_min) { + if (nft_dump_register(skb, NFTA_MASQ_REG_PROTO_MIN, + priv->sreg_proto_min) || +@@ -112,6 +120,9 @@ static void nft_masq_eval(const struct n + { + switch (nft_pf(pkt)) { + case NFPROTO_IPV4: ++ if (priv->fullcone) { ++ range.min_addr.ip = 1; ++ } + return nft_masq_ipv4_eval(expr, regs, pkt); + case NFPROTO_IPV6: + return nft_masq_ipv6_eval(expr, regs, pkt); diff --git a/target/linux/generic/hack-5.4/983-add-bcm-fullconenat-to-nft.patch b/target/linux/generic/hack-5.4/983-add-bcm-fullconenat-to-nft.patch new file mode 100644 index 000000000..bb1cd62a3 --- /dev/null +++ b/target/linux/generic/hack-5.4/983-add-bcm-fullconenat-to-nft.patch @@ -0,0 +1,65 @@ +--- a/include/uapi/linux/netfilter/nf_tables.h ++++ b/include/uapi/linux/netfilter/nf_tables.h +@@ -1477,12 +1477,14 @@ enum nft_tproxy_attributes { + * @NFTA_MASQ_FLAGS: NAT flags (see NF_NAT_RANGE_* in linux/netfilter/nf_nat.h) (NLA_U32) + * @NFTA_MASQ_REG_PROTO_MIN: source register of proto range start (NLA_U32: nft_registers) + * @NFTA_MASQ_REG_PROTO_MAX: source register of proto range end (NLA_U32: nft_registers) ++ * @NFTA_MASQ_REG_FULLCONE: fullcone NAT (NLA_U8) + */ + enum nft_masq_attributes { + NFTA_MASQ_UNSPEC, + NFTA_MASQ_FLAGS, + NFTA_MASQ_REG_PROTO_MIN, + NFTA_MASQ_REG_PROTO_MAX, ++ NFTA_MASQ_REG_FULLCONE, + __NFTA_MASQ_MAX + }; + #define NFTA_MASQ_MAX (__NFTA_MASQ_MAX - 1) +--- a/net/netfilter/nft_masq.c ++++ b/net/netfilter/nft_masq.c +@@ -17,6 +17,7 @@ struct nft_masq { + u32 flags; + u8 sreg_proto_min; + u8 sreg_proto_max; ++ bool fullcone; + }; + + static const struct nla_policy nft_masq_policy[NFTA_MASQ_MAX + 1] = { +@@ -24,6 +25,7 @@ static const struct nla_policy nft_masq_ + NLA_POLICY_MASK(NLA_BE32, NF_NAT_RANGE_MASK), + [NFTA_MASQ_REG_PROTO_MIN] = { .type = NLA_U32 }, + [NFTA_MASQ_REG_PROTO_MAX] = { .type = NLA_U32 }, ++ [NFTA_MASQ_REG_FULLCONE] = { .type = NLA_U8 }, + }; + + static int nft_masq_validate(const struct nft_ctx *ctx, +@@ -51,6 +53,9 @@ static int nft_masq_init(const struct nf + if (tb[NFTA_MASQ_FLAGS]) + priv->flags = ntohl(nla_get_be32(tb[NFTA_MASQ_FLAGS])); + ++ if (tb[NFTA_MASQ_REG_FULLCONE]) ++ priv->fullcone = nla_get_u8(tb[NFTA_MASQ_REG_FULLCONE]); ++ + if (tb[NFTA_MASQ_REG_PROTO_MIN]) { + err = nft_parse_register_load(tb[NFTA_MASQ_REG_PROTO_MIN], + &priv->sreg_proto_min, plen); +@@ -80,6 +85,9 @@ static int nft_masq_dump(struct sk_buff + nla_put_be32(skb, NFTA_MASQ_FLAGS, htonl(priv->flags))) + goto nla_put_failure; + ++ if (priv->fullcone && nla_put_u8(skb, NFTA_MASQ_REG_FULLCONE, 1)) ++ goto nla_put_failure; ++ + if (priv->sreg_proto_min) { + if (nft_dump_register(skb, NFTA_MASQ_REG_PROTO_MIN, + priv->sreg_proto_min) || +@@ -112,6 +120,9 @@ static void nft_masq_eval(const struct n + { + switch (nft_pf(pkt)) { + case NFPROTO_IPV4: ++ if (priv->fullcone) { ++ range.min_addr.ip = 1; ++ } + return nft_masq_ipv4_eval(expr, regs, pkt); + case NFPROTO_IPV6: + return nft_masq_ipv6_eval(expr, regs, pkt); diff --git a/target/linux/generic/hack-6.1/983-add-bcm-fullconenat-to-nft.patch b/target/linux/generic/hack-6.1/983-add-bcm-fullconenat-to-nft.patch new file mode 100644 index 000000000..bb1cd62a3 --- /dev/null +++ b/target/linux/generic/hack-6.1/983-add-bcm-fullconenat-to-nft.patch @@ -0,0 +1,65 @@ +--- a/include/uapi/linux/netfilter/nf_tables.h ++++ b/include/uapi/linux/netfilter/nf_tables.h +@@ -1477,12 +1477,14 @@ enum nft_tproxy_attributes { + * @NFTA_MASQ_FLAGS: NAT flags (see NF_NAT_RANGE_* in linux/netfilter/nf_nat.h) (NLA_U32) + * @NFTA_MASQ_REG_PROTO_MIN: source register of proto range start (NLA_U32: nft_registers) + * @NFTA_MASQ_REG_PROTO_MAX: source register of proto range end (NLA_U32: nft_registers) ++ * @NFTA_MASQ_REG_FULLCONE: fullcone NAT (NLA_U8) + */ + enum nft_masq_attributes { + NFTA_MASQ_UNSPEC, + NFTA_MASQ_FLAGS, + NFTA_MASQ_REG_PROTO_MIN, + NFTA_MASQ_REG_PROTO_MAX, ++ NFTA_MASQ_REG_FULLCONE, + __NFTA_MASQ_MAX + }; + #define NFTA_MASQ_MAX (__NFTA_MASQ_MAX - 1) +--- a/net/netfilter/nft_masq.c ++++ b/net/netfilter/nft_masq.c +@@ -17,6 +17,7 @@ struct nft_masq { + u32 flags; + u8 sreg_proto_min; + u8 sreg_proto_max; ++ bool fullcone; + }; + + static const struct nla_policy nft_masq_policy[NFTA_MASQ_MAX + 1] = { +@@ -24,6 +25,7 @@ static const struct nla_policy nft_masq_ + NLA_POLICY_MASK(NLA_BE32, NF_NAT_RANGE_MASK), + [NFTA_MASQ_REG_PROTO_MIN] = { .type = NLA_U32 }, + [NFTA_MASQ_REG_PROTO_MAX] = { .type = NLA_U32 }, ++ [NFTA_MASQ_REG_FULLCONE] = { .type = NLA_U8 }, + }; + + static int nft_masq_validate(const struct nft_ctx *ctx, +@@ -51,6 +53,9 @@ static int nft_masq_init(const struct nf + if (tb[NFTA_MASQ_FLAGS]) + priv->flags = ntohl(nla_get_be32(tb[NFTA_MASQ_FLAGS])); + ++ if (tb[NFTA_MASQ_REG_FULLCONE]) ++ priv->fullcone = nla_get_u8(tb[NFTA_MASQ_REG_FULLCONE]); ++ + if (tb[NFTA_MASQ_REG_PROTO_MIN]) { + err = nft_parse_register_load(tb[NFTA_MASQ_REG_PROTO_MIN], + &priv->sreg_proto_min, plen); +@@ -80,6 +85,9 @@ static int nft_masq_dump(struct sk_buff + nla_put_be32(skb, NFTA_MASQ_FLAGS, htonl(priv->flags))) + goto nla_put_failure; + ++ if (priv->fullcone && nla_put_u8(skb, NFTA_MASQ_REG_FULLCONE, 1)) ++ goto nla_put_failure; ++ + if (priv->sreg_proto_min) { + if (nft_dump_register(skb, NFTA_MASQ_REG_PROTO_MIN, + priv->sreg_proto_min) || +@@ -112,6 +120,9 @@ static void nft_masq_eval(const struct n + { + switch (nft_pf(pkt)) { + case NFPROTO_IPV4: ++ if (priv->fullcone) { ++ range.min_addr.ip = 1; ++ } + return nft_masq_ipv4_eval(expr, regs, pkt); + case NFPROTO_IPV6: + return nft_masq_ipv6_eval(expr, regs, pkt); diff --git a/target/linux/generic/hack-6.12/983-add-bcm-fullconenat-to-nft.patch b/target/linux/generic/hack-6.12/983-add-bcm-fullconenat-to-nft.patch new file mode 100644 index 000000000..ec868e19f --- /dev/null +++ b/target/linux/generic/hack-6.12/983-add-bcm-fullconenat-to-nft.patch @@ -0,0 +1,65 @@ +--- a/include/uapi/linux/netfilter/nf_tables.h ++++ b/include/uapi/linux/netfilter/nf_tables.h +@@ -1477,12 +1477,14 @@ enum nft_tproxy_attributes { + * @NFTA_MASQ_FLAGS: NAT flags (see NF_NAT_RANGE_* in linux/netfilter/nf_nat.h) (NLA_U32) + * @NFTA_MASQ_REG_PROTO_MIN: source register of proto range start (NLA_U32: nft_registers) + * @NFTA_MASQ_REG_PROTO_MAX: source register of proto range end (NLA_U32: nft_registers) ++ * @NFTA_MASQ_REG_FULLCONE: fullcone NAT (NLA_U8) + */ + enum nft_masq_attributes { + NFTA_MASQ_UNSPEC, + NFTA_MASQ_FLAGS, + NFTA_MASQ_REG_PROTO_MIN, + NFTA_MASQ_REG_PROTO_MAX, ++ NFTA_MASQ_REG_FULLCONE, + __NFTA_MASQ_MAX + }; + #define NFTA_MASQ_MAX (__NFTA_MASQ_MAX - 1) +--- a/net/netfilter/nft_masq.c ++++ b/net/netfilter/nft_masq.c +@@ -17,6 +17,7 @@ struct nft_masq { + u32 flags; + u8 sreg_proto_min; + u8 sreg_proto_max; ++ bool fullcone; + }; + + static const struct nla_policy nft_masq_policy[NFTA_MASQ_MAX + 1] = { +@@ -24,6 +25,7 @@ static const struct nla_policy nft_masq_ + NLA_POLICY_MASK(NLA_BE32, NF_NAT_RANGE_MASK), + [NFTA_MASQ_REG_PROTO_MIN] = { .type = NLA_U32 }, + [NFTA_MASQ_REG_PROTO_MAX] = { .type = NLA_U32 }, ++ [NFTA_MASQ_REG_FULLCONE] = { .type = NLA_U8 }, + }; + + static int nft_masq_validate(const struct nft_ctx *ctx, +@@ -51,6 +53,9 @@ static int nft_masq_init(const struct nf + if (tb[NFTA_MASQ_FLAGS]) + priv->flags = ntohl(nla_get_be32(tb[NFTA_MASQ_FLAGS])); + ++ if (tb[NFTA_MASQ_REG_FULLCONE]) ++ priv->fullcone = nla_get_u8(tb[NFTA_MASQ_REG_FULLCONE]); ++ + if (tb[NFTA_MASQ_REG_PROTO_MIN]) { + err = nft_parse_register_load(tb[NFTA_MASQ_REG_PROTO_MIN], + &priv->sreg_proto_min, plen); +@@ -80,6 +85,9 @@ static int nft_masq_dump(struct sk_buff + nla_put_be32(skb, NFTA_MASQ_FLAGS, htonl(priv->flags))) + goto nla_put_failure; + ++ if (priv->fullcone && nla_put_u8(skb, NFTA_MASQ_REG_FULLCONE, 1)) ++ goto nla_put_failure; ++ + if (priv->sreg_proto_min) { + if (nft_dump_register(skb, NFTA_MASQ_REG_PROTO_MIN, + priv->sreg_proto_min) || +@@ -112,6 +120,9 @@ static void nft_masq_eval(const struct n + + switch (nft_pf(pkt)) { + case NFPROTO_IPV4: ++ if (priv->fullcone) { ++ range.min_addr.ip = 1; ++ } + regs->verdict.code = nf_nat_masquerade_ipv4(pkt->skb, + nft_hook(pkt), + &range, diff --git a/target/linux/generic/hack-6.6/983-add-bcm-fullconenat-to-nft.patch b/target/linux/generic/hack-6.6/983-add-bcm-fullconenat-to-nft.patch new file mode 100644 index 000000000..ec868e19f --- /dev/null +++ b/target/linux/generic/hack-6.6/983-add-bcm-fullconenat-to-nft.patch @@ -0,0 +1,65 @@ +--- a/include/uapi/linux/netfilter/nf_tables.h ++++ b/include/uapi/linux/netfilter/nf_tables.h +@@ -1477,12 +1477,14 @@ enum nft_tproxy_attributes { + * @NFTA_MASQ_FLAGS: NAT flags (see NF_NAT_RANGE_* in linux/netfilter/nf_nat.h) (NLA_U32) + * @NFTA_MASQ_REG_PROTO_MIN: source register of proto range start (NLA_U32: nft_registers) + * @NFTA_MASQ_REG_PROTO_MAX: source register of proto range end (NLA_U32: nft_registers) ++ * @NFTA_MASQ_REG_FULLCONE: fullcone NAT (NLA_U8) + */ + enum nft_masq_attributes { + NFTA_MASQ_UNSPEC, + NFTA_MASQ_FLAGS, + NFTA_MASQ_REG_PROTO_MIN, + NFTA_MASQ_REG_PROTO_MAX, ++ NFTA_MASQ_REG_FULLCONE, + __NFTA_MASQ_MAX + }; + #define NFTA_MASQ_MAX (__NFTA_MASQ_MAX - 1) +--- a/net/netfilter/nft_masq.c ++++ b/net/netfilter/nft_masq.c +@@ -17,6 +17,7 @@ struct nft_masq { + u32 flags; + u8 sreg_proto_min; + u8 sreg_proto_max; ++ bool fullcone; + }; + + static const struct nla_policy nft_masq_policy[NFTA_MASQ_MAX + 1] = { +@@ -24,6 +25,7 @@ static const struct nla_policy nft_masq_ + NLA_POLICY_MASK(NLA_BE32, NF_NAT_RANGE_MASK), + [NFTA_MASQ_REG_PROTO_MIN] = { .type = NLA_U32 }, + [NFTA_MASQ_REG_PROTO_MAX] = { .type = NLA_U32 }, ++ [NFTA_MASQ_REG_FULLCONE] = { .type = NLA_U8 }, + }; + + static int nft_masq_validate(const struct nft_ctx *ctx, +@@ -51,6 +53,9 @@ static int nft_masq_init(const struct nf + if (tb[NFTA_MASQ_FLAGS]) + priv->flags = ntohl(nla_get_be32(tb[NFTA_MASQ_FLAGS])); + ++ if (tb[NFTA_MASQ_REG_FULLCONE]) ++ priv->fullcone = nla_get_u8(tb[NFTA_MASQ_REG_FULLCONE]); ++ + if (tb[NFTA_MASQ_REG_PROTO_MIN]) { + err = nft_parse_register_load(tb[NFTA_MASQ_REG_PROTO_MIN], + &priv->sreg_proto_min, plen); +@@ -80,6 +85,9 @@ static int nft_masq_dump(struct sk_buff + nla_put_be32(skb, NFTA_MASQ_FLAGS, htonl(priv->flags))) + goto nla_put_failure; + ++ if (priv->fullcone && nla_put_u8(skb, NFTA_MASQ_REG_FULLCONE, 1)) ++ goto nla_put_failure; ++ + if (priv->sreg_proto_min) { + if (nft_dump_register(skb, NFTA_MASQ_REG_PROTO_MIN, + priv->sreg_proto_min) || +@@ -112,6 +120,9 @@ static void nft_masq_eval(const struct n + + switch (nft_pf(pkt)) { + case NFPROTO_IPV4: ++ if (priv->fullcone) { ++ range.min_addr.ip = 1; ++ } + regs->verdict.code = nf_nat_masquerade_ipv4(pkt->skb, + nft_hook(pkt), + &range, diff --git a/target/linux/generic/pending-6.12/737-net-ethernet-mtk_eth_soc-add-paths-and-SerDes-modes-.patch b/target/linux/generic/pending-6.12/737-net-ethernet-mtk_eth_soc-add-paths-and-SerDes-modes-.patch index b03b72b33..9440c23e6 100644 --- a/target/linux/generic/pending-6.12/737-net-ethernet-mtk_eth_soc-add-paths-and-SerDes-modes-.patch +++ b/target/linux/generic/pending-6.12/737-net-ethernet-mtk_eth_soc-add-paths-and-SerDes-modes-.patch @@ -544,7 +544,7 @@ Signed-off-by: Daniel Golle + } + + if (mtk_is_netsys_v3_or_greater(eth) && (mac->sgmii_pcs || mac->usxgmii_pcs)) { -+ mac->pextp = devm_of_phy_get(eth->dev, mac->of_node, NULL); ++ mac->pextp = devm_of_phy_optional_get(eth->dev, mac->of_node, NULL); + if (IS_ERR(mac->pextp)) { + if (PTR_ERR(mac->pextp) != -EPROBE_DEFER) + dev_err(eth->dev, "cannot get PHY, error %ld\n", diff --git a/target/linux/loongarch64/Makefile b/target/linux/loongarch64/Makefile index c128c6177..ad38868e1 100644 --- a/target/linux/loongarch64/Makefile +++ b/target/linux/loongarch64/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk ARCH:=loongarch64 BOARD:=loongarch64 BOARDNAME:=Loongson LoongArch -FEATURES:=audio display ext4 pcie boot-part rootfs-part rtc usb targz +FEATURES:=squashfs audio display ext4 pcie boot-part rootfs-part rtc usb targz SUBTARGETS:=generic KERNEL_PATCHVER:=6.12 @@ -18,6 +18,7 @@ KERNELNAME:=vmlinuz.efi dtbs include $(INCLUDE_DIR)/target.mk DEFAULT_PACKAGES += \ - partx-utils blkid e2fsprogs grub2-efi-loongarch64 kmod-yt6801 + partx-utils blkid e2fsprogs grub2-efi-loongarch64 kmod-yt6801 \ + kmod-fs-ext4 kmod-fs-f2fs losetup mkf2fs f2fsck e2fsprogs autocore-loongarch64 $(eval $(call BuildTarget)) diff --git a/target/linux/mediatek/dts/mt7981b-huasifei-ws3006.dts b/target/linux/mediatek/dts/mt7981b-huasifei-ws3006.dts index 7a8bb18ec..2cbfc5522 100644 --- a/target/linux/mediatek/dts/mt7981b-huasifei-ws3006.dts +++ b/target/linux/mediatek/dts/mt7981b-huasifei-ws3006.dts @@ -98,8 +98,8 @@ gmac1: mac@1 { compatible = "mediatek,eth-mac"; reg = <1>; - phy-handle = <&phy0>; - phy-mode = "2500base-x"; + phy-mode = "gmii"; + phy-handle = <&int_gbe_phy>; nvmem-cells = <&macaddr_factory_4 2>; nvmem-cell-names = "mac-address"; @@ -117,20 +117,13 @@ interrupts = <38 IRQ_TYPE_LEVEL_HIGH>; }; - phy0: ethernet-phy@0 { - compatible = "ethernet-phy-id03a2.9461"; - reg = <0>; - phy-mode = "gmii"; - nvmem-cells = <&phy_calibration>; - nvmem-cell-names = "phy-cal-data"; - }; - - phy6: ethernet-phy@6 { + phy1: ethernet-phy@1 { compatible = "ethernet-phy-ieee802.3-c45"; - reg = <6>; + reg = <1>; reset-assert-us = <100000>; reset-deassert-us = <100000>; - reset-gpios = <&pio 3 GPIO_ACTIVE_LOW>; + reset-gpios = <&pio 14 GPIO_ACTIVE_LOW>; + realtek,led-link-select = <0x0 0xa7 0xa7>; }; }; @@ -247,7 +240,7 @@ port@5 { reg = <5>; label = "wan"; - phy-handle = <&phy6>; + phy-handle = <&phy1>; phy-mode = "2500base-x"; }; diff --git a/target/linux/mediatek/filogic/base-files/etc/board.d/01_leds b/target/linux/mediatek/filogic/base-files/etc/board.d/01_leds index 1a74d6a3e..25ada3ad8 100644 --- a/target/linux/mediatek/filogic/base-files/etc/board.d/01_leds +++ b/target/linux/mediatek/filogic/base-files/etc/board.d/01_leds @@ -22,13 +22,6 @@ bananapi,bpi-r4-poe) ucidef_set_led_netdev "lan2" "lan2" "mt7530-0:02:green:lan" "lan2" "link tx rx" ucidef_set_led_netdev "lan3" "lan3" "mt7530-0:03:green:lan" "lan3" "link tx rx" ;; -hf,m7986r1*) - ucidef_set_led_netdev "led-1" "LAN1" "led-1" "lan1" - ucidef_set_led_netdev "led-2" "LAN2" "led-2" "lan2" - ucidef_set_led_netdev "led-3" "LAN3" "led-3" "lan3" - ucidef_set_led_netdev "led-4" "LAN4" "led-4" "lan4" - ucidef_set_led_netdev "led-5" "WWAN" "led-5" "usb0" - ;; glinet,gl-x3000|\ glinet,gl-xe3000) ucidef_set_led_default "power" "POWER" "green:power" "1" @@ -40,6 +33,18 @@ glinet,gl-xe3000) ucidef_set_led_netdev "wlan2g" "WLAN2G" "green:wifi2g" "phy0-ap0" ucidef_set_led_netdev "wlan5g" "WLAN5G" "green:wifi5g" "phy1-ap0" ;; +hf,m7986r1*) + ucidef_set_led_netdev "led-1" "LAN1" "led-1" "lan1" + ucidef_set_led_netdev "led-2" "LAN2" "led-2" "lan2" + ucidef_set_led_netdev "led-3" "LAN3" "led-3" "lan3" + ucidef_set_led_netdev "led-4" "LAN4" "led-4" "lan4" + ucidef_set_led_netdev "led-5" "WWAN" "led-5" "usb0" + ;; +huasifei,ws3006) + ucidef_set_led_netdev "lan3" "LAN3" "green:gbe" "eth1" + ucidef_set_led_netdev "wan" "WAN" "green:wan" "wan" + ucidef_set_led_netdev "wlan" "WLAN" "green:wlan" "wlan1" + ;; imou,lc-hx3001|\ nokia,ea0326gmp) ucidef_set_led_netdev "lan" "LAN" "green:lan" "br-lan" diff --git a/target/linux/mediatek/patches-6.12/740-net-pcs-mtk_lynxi-add-mt7987-support.patch b/target/linux/mediatek/patches-6.12/740-net-pcs-mtk_lynxi-add-mt7987-support.patch new file mode 100644 index 000000000..d4d09b64f --- /dev/null +++ b/target/linux/mediatek/patches-6.12/740-net-pcs-mtk_lynxi-add-mt7987-support.patch @@ -0,0 +1,36 @@ +From 6e9ec5ade644eeb136c6b827d72fac80bf2c3817 Mon Sep 17 00:00:00 2001 +From: Bo-Cun Chen +Date: Fri, 9 May 2025 13:22:14 +0800 +Subject: [PATCH] net: pcs: mtk_lynxi add mt7987 support + +Signed-off-by: Bo-Cun Chen +--- + drivers/net/pcs/pcs-mtk-lynxi.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +--- a/drivers/net/pcs/pcs-mtk-lynxi.c ++++ b/drivers/net/pcs/pcs-mtk-lynxi.c +@@ -413,9 +413,12 @@ static int mtk_pcs_lynxi_probe(struct pl + if (of_property_read_bool(np->parent, "mediatek,pnswap")) + flags |= MTK_SGMII_FLAG_PN_SWAP; + +- mpcs->rstc = of_reset_control_get_shared(np->parent, NULL); +- if (IS_ERR(mpcs->rstc)) +- return PTR_ERR(mpcs->rstc); ++ if (of_parse_phandle(np->parent, "resets", 0)) { ++ mpcs->rstc = of_reset_control_get_shared(np->parent, NULL); ++ if (IS_ERR(mpcs->rstc)) ++ return PTR_ERR(mpcs->rstc); ++ } else ++ mpcs->rstc = NULL; + + reset_control_deassert(mpcs->rstc); + mpcs->sgmii_sel = devm_clk_get_enabled(dev, "sgmii_sel"); +@@ -462,6 +465,7 @@ static void mtk_pcs_lynxi_remove(struct + } + + static const struct of_device_id mtk_pcs_lynxi_of_match[] = { ++ { .compatible = "mediatek,mt7987-sgmii", .data = (void *)MTK_NETSYS_V3_AMA_RGC3 }, + { .compatible = "mediatek,mt7988-sgmii", .data = (void *)MTK_NETSYS_V3_AMA_RGC3 }, + { /* sentinel */ }, + }; diff --git a/target/linux/mediatek/patches-6.12/741-net-pcs-mtk-lynxi-add-phya-tx-rx-clock-path.patch b/target/linux/mediatek/patches-6.12/741-net-pcs-mtk-lynxi-add-phya-tx-rx-clock-path.patch new file mode 100644 index 000000000..eef6e361a --- /dev/null +++ b/target/linux/mediatek/patches-6.12/741-net-pcs-mtk-lynxi-add-phya-tx-rx-clock-path.patch @@ -0,0 +1,89 @@ +From be193994deca7cc3ca6ddedc6efd06182b032f21 Mon Sep 17 00:00:00 2001 +From: Bo-Cun Chen +Date: Tue, 6 May 2025 12:53:37 +0800 +Subject: [PATCH] net: pcs: mtk-lynxi: add phya tx rx clock path + +In NETSYSv3.1, the SGMII hardware introduces a new clock path from PHYA. +Consequently, users can switch the SGMII PCS to this new clock source +for better performance on the MT7987. + +Signed-off-by: Bo-Cun Chen +--- +--- a/drivers/net/pcs/pcs-mtk-lynxi.c ++++ b/drivers/net/pcs/pcs-mtk-lynxi.c +@@ -25,6 +25,7 @@ + #define SGMSYS_PCS_CONTROL_1 0x0 + #define SGMII_BMCR GENMASK(15, 0) + #define SGMII_BMSR GENMASK(31, 16) ++#define SGMII_REF_CK_SEL BIT(24) + + #define SGMSYS_PCS_DEVICE_ID 0x4 + #define SGMII_LYNXI_DEV_ID 0x4d544950 +@@ -52,6 +53,8 @@ + #define SGMII_SPEED_1000 FIELD_PREP(SGMII_SPEED_MASK, 2) + #define SGMII_DUPLEX_HALF BIT(4) + #define SGMII_REMOTE_FAULT_DIS BIT(8) ++#define SGMII_TRXBUF_THR_MASK GENMASK(31, 16) ++#define SGMII_TRXBUF_THR(x) FIELD_PREP(SGMII_TRXBUF_THR_MASK, (x)) + + /* Register to reset SGMII design */ + #define SGMSYS_RESERVED_0 0x34 +@@ -166,7 +169,7 @@ static int mtk_pcs_lynxi_config(struct p + { + struct mtk_pcs_lynxi *mpcs = pcs_to_mtk_pcs_lynxi(pcs); + bool mode_changed = false, changed; +- unsigned int rgc3, sgm_mode, bmcr = 0; ++ unsigned int rgc3, sgm_mode, bmcr = 0, trxbuf_thr = 0x3112; + int advertise, link_timer; + + advertise = phylink_mii_c22_pcs_encode_advertisement(interface, +@@ -193,6 +196,12 @@ static int mtk_pcs_lynxi_config(struct p + bmcr = BMCR_ANENABLE; + } + ++ /* Configure SGMII PCS clock source */ ++ if (mpcs->flags & MTK_SGMII_FLAG_PHYA_TRX_CK) { ++ bmcr |= SGMII_REF_CK_SEL; ++ trxbuf_thr = 0x2111; ++ } ++ + if (mpcs->interface != interface) { + link_timer = phylink_get_link_timer_ns(interface); + if (link_timer < 0) +@@ -235,12 +244,14 @@ static int mtk_pcs_lynxi_config(struct p + + /* Update the sgmsys mode register */ + regmap_update_bits(mpcs->regmap, SGMSYS_SGMII_MODE, ++ SGMII_TRXBUF_THR_MASK | + SGMII_REMOTE_FAULT_DIS | SGMII_SPEED_DUPLEX_AN | +- SGMII_IF_MODE_SGMII, sgm_mode); ++ SGMII_IF_MODE_SGMII, ++ SGMII_TRXBUF_THR(trxbuf_thr) | sgm_mode); + + /* Update the BMCR */ + regmap_update_bits(mpcs->regmap, SGMSYS_PCS_CONTROL_1, +- BMCR_ANENABLE, bmcr); ++ SGMII_REF_CK_SEL | BMCR_ANENABLE, bmcr); + + /* Release PHYA power down state + * Only removing bit SGMII_PHYA_PWD isn't enough. +@@ -413,6 +424,9 @@ static int mtk_pcs_lynxi_probe(struct pl + if (of_property_read_bool(np->parent, "mediatek,pnswap")) + flags |= MTK_SGMII_FLAG_PN_SWAP; + ++ if (of_property_read_bool(np->parent, "mediatek,phya_trx_ck")) ++ flags |= MTK_SGMII_FLAG_PHYA_TRX_CK; ++ + if (of_parse_phandle(np->parent, "resets", 0)) { + mpcs->rstc = of_reset_control_get_shared(np->parent, NULL); + if (IS_ERR(mpcs->rstc)) +--- a/include/linux/pcs/pcs-mtk-lynxi.h ++++ b/include/linux/pcs/pcs-mtk-lynxi.h +@@ -6,6 +6,7 @@ + #include + + #define MTK_SGMII_FLAG_PN_SWAP BIT(0) ++#define MTK_SGMII_FLAG_PHYA_TRX_CK BIT(2) + struct phylink_pcs *mtk_pcs_lynxi_create(struct device *dev, + struct regmap *regmap, + u32 ana_rgc3, u32 flags); diff --git a/target/linux/mediatek/patches-6.12/750-net-ethernet-mtk_eth_soc-add-mt7987-support.patch b/target/linux/mediatek/patches-6.12/750-net-ethernet-mtk_eth_soc-add-mt7987-support.patch new file mode 100644 index 000000000..238e7a76b --- /dev/null +++ b/target/linux/mediatek/patches-6.12/750-net-ethernet-mtk_eth_soc-add-mt7987-support.patch @@ -0,0 +1,325 @@ +From 56973433cbea9f91f5f7eddebbc361ffc2bd6156 Mon Sep 17 00:00:00 2001 +From: Bo-Cun Chen +Date: Mon, 26 May 2025 13:20:42 +0800 +Subject: [PATCH] net: ethernet: mtk_eth_soc: add mt7987 support + +Without this patch, users are unable to bring up ETH driver on the +mt7987. + +Signed-off-by: Bo-Cun Chen +--- + drivers/net/ethernet/mediatek/mtk_eth_path.c | 9 +- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 138 ++++++++++++++++--- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 70 ++++++++-- + 3 files changed, 179 insertions(+), 38 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_path.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_path.c +@@ -106,13 +106,14 @@ static int set_mux_gmac2_gmac0_to_gephy( + return 0; + } + +-static int set_mux_u3_gmac2_to_qphy(struct mtk_eth *eth, u64 path) ++static int set_mux_u3_gmac23_to_qphy(struct mtk_eth *eth, u64 path) + { + unsigned int val = 0, mask = 0, reg = 0; + bool updated = true; + + switch (path) { + case MTK_ETH_PATH_GMAC2_SGMII: ++ case MTK_ETH_PATH_GMAC3_SGMII: + if (MTK_HAS_CAPS(eth->soc->caps, MTK_U3_COPHY_V2)) { + reg = USB_PHY_SWITCH_REG; + val = SGMII_QPHY_SEL; +@@ -281,9 +282,9 @@ static const struct mtk_eth_muxc mtk_eth + .cap_bit = MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY, + .set_path = set_mux_gmac2_gmac0_to_gephy, + }, { +- .name = "mux_u3_gmac2_to_qphy", +- .cap_bit = MTK_ETH_MUX_U3_GMAC2_TO_QPHY, +- .set_path = set_mux_u3_gmac2_to_qphy, ++ .name = "mux_u3_gmac23_to_qphy", ++ .cap_bit = MTK_ETH_MUX_U3_GMAC23_TO_QPHY, ++ .set_path = set_mux_u3_gmac23_to_qphy, + }, { + .name = "mux_gmac2_to_2p5gphy", + .cap_bit = MTK_ETH_MUX_GMAC2_TO_2P5GPHY, +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -817,10 +817,16 @@ static void mtk_set_queue_speed(struct m + return; + + val = MTK_QTX_SCH_MIN_RATE_EN | +- /* minimum: 10 Mbps */ +- FIELD_PREP(MTK_QTX_SCH_MIN_RATE_MAN, 1) | +- FIELD_PREP(MTK_QTX_SCH_MIN_RATE_EXP, 4) | + MTK_QTX_SCH_LEAKY_BUCKET_SIZE; ++ /* minimum: 10 Mbps */ ++ if (mtk_is_netsys_v3_or_greater(eth) && ++ (eth->soc->caps != MT7988_CAPS)) { ++ val |= FIELD_PREP(MTK_QTX_SCH_MIN_RATE_MAN_V3, 1) | ++ FIELD_PREP(MTK_QTX_SCH_MIN_RATE_EXP_V3, 4); ++ } else { ++ val |= FIELD_PREP(MTK_QTX_SCH_MIN_RATE_MAN, 1) | ++ FIELD_PREP(MTK_QTX_SCH_MIN_RATE_EXP, 4); ++ } + if (mtk_is_netsys_v1(eth)) + val |= MTK_QTX_SCH_LEAKY_BUCKET_EN; + +@@ -847,6 +853,30 @@ static void mtk_set_queue_speed(struct m + default: + break; + } ++ } else if (mtk_is_netsys_v3_or_greater(eth) && ++ (eth->soc->caps != MT7988_CAPS)) { ++ switch (speed) { ++ case SPEED_10: ++ val |= MTK_QTX_SCH_MAX_RATE_EN_V3 | ++ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_MAN_V3, 1) | ++ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_EXP_V3, 4) | ++ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_WEIGHT_V3, 1); ++ break; ++ case SPEED_100: ++ val |= MTK_QTX_SCH_MAX_RATE_EN_V3 | ++ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_MAN_V3, 1) | ++ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_EXP_V3, 5) | ++ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_WEIGHT_V3, 1); ++ break; ++ case SPEED_1000: ++ val |= MTK_QTX_SCH_MAX_RATE_EN_V3 | ++ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_MAN_V3, 1) | ++ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_EXP_V3, 6) | ++ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_WEIGHT_V3, 10); ++ break; ++ default: ++ break; ++ } + } else { + switch (speed) { + case SPEED_10: +@@ -935,7 +965,7 @@ static void mtk_xgdm_mac_link_up(struct + return; + + /* Eliminate the interference(before link-up) caused by PHY noise */ +- mtk_m32(mac->hw, XMAC_LOGIC_RST, 0, MTK_XMAC_LOGIC_RST(mac->id)); ++ mtk_m32(mac->hw, XMAC_LOGIC_RST, 0, MTK_XMAC_LOGIC_RST(mac->hw, mac->id)); + mdelay(20); + mtk_m32(mac->hw, XMAC_GLB_CNTCLR, XMAC_GLB_CNTCLR, MTK_XMAC_CNT_CTRL(mac->id)); + +@@ -2901,10 +2931,16 @@ static int mtk_tx_alloc(struct mtk_eth * + mtk_w32(eth, val, soc->reg_map->qdma.qtx_cfg + ofs); + + val = MTK_QTX_SCH_MIN_RATE_EN | +- /* minimum: 10 Mbps */ +- FIELD_PREP(MTK_QTX_SCH_MIN_RATE_MAN, 1) | +- FIELD_PREP(MTK_QTX_SCH_MIN_RATE_EXP, 4) | + MTK_QTX_SCH_LEAKY_BUCKET_SIZE; ++ /* minimum: 10 Mbps */ ++ if (mtk_is_netsys_v3_or_greater(eth) && ++ (eth->soc->caps != MT7988_CAPS)) { ++ val |= FIELD_PREP(MTK_QTX_SCH_MIN_RATE_MAN_V3, 1) | ++ FIELD_PREP(MTK_QTX_SCH_MIN_RATE_EXP_V3, 4); ++ } else { ++ val |= FIELD_PREP(MTK_QTX_SCH_MIN_RATE_MAN, 1) | ++ FIELD_PREP(MTK_QTX_SCH_MIN_RATE_EXP, 4); ++ } + if (mtk_is_netsys_v1(eth)) + val |= MTK_QTX_SCH_LEAKY_BUCKET_EN; + mtk_w32(eth, val, soc->reg_map->qdma.qtx_sch + ofs); +@@ -5873,6 +5909,36 @@ static const struct mtk_soc_data mt7986_ + }, + }; + ++static const struct mtk_soc_data mt7987_data = { ++ .reg_map = &mt7988_reg_map, ++ .ana_rgc3 = 0x128, ++ .caps = MT7987_CAPS, ++ .hw_features = MTK_HW_FEATURES, ++ .required_clks = MT7987_CLKS_BITMAP, ++ .required_pctl = false, ++ .version = 3, ++ .offload_version = 2, ++ .ppe_num = 2, ++ .hash_offset = 4, ++ .has_accounting = true, ++ .foe_entry_size = MTK_FOE_ENTRY_V3_SIZE, ++ .tx = { ++ DESC_SIZE(struct mtk_tx_dma_v2), ++ .dma_max_len = MTK_TX_DMA_BUF_LEN_V2, ++ .dma_len_offset = 8, ++ .dma_size = MTK_DMA_SIZE(2K), ++ .fq_dma_size = MTK_DMA_SIZE(4K), ++ }, ++ .rx = { ++ DESC_SIZE(struct mtk_rx_dma_v2), ++ .irq_done_mask = MTK_RX_DONE_INT_V2, ++ .dma_l4_valid = RX_DMA_L4_VALID_V2, ++ .dma_max_len = MTK_TX_DMA_BUF_LEN_V2, ++ .dma_len_offset = 8, ++ .dma_size = MTK_DMA_SIZE(2K), ++ }, ++}; ++ + static const struct mtk_soc_data mt7988_data = { + .reg_map = &mt7988_reg_map, + .ana_rgc3 = 0x128, +@@ -5934,6 +6000,7 @@ const struct of_device_id of_mtk_match[] + { .compatible = "mediatek,mt7629-eth", .data = &mt7629_data }, + { .compatible = "mediatek,mt7981-eth", .data = &mt7981_data }, + { .compatible = "mediatek,mt7986-eth", .data = &mt7986_data }, ++ { .compatible = "mediatek,mt7987-eth", .data = &mt7987_data }, + { .compatible = "mediatek,mt7988-eth", .data = &mt7988_data }, + { .compatible = "ralink,rt5350-eth", .data = &rt5350_data }, + {}, +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -262,6 +262,13 @@ + #define MTK_QTX_SCH_MAX_RATE_MAN GENMASK(10, 4) + #define MTK_QTX_SCH_MAX_RATE_EXP GENMASK(3, 0) + ++#define MTK_QTX_SCH_MAX_RATE_EN_V3 BIT(26) ++#define MTK_QTX_SCH_MIN_RATE_MAN_V3 GENMASK(25, 19) ++#define MTK_QTX_SCH_MIN_RATE_EXP_V3 GENMASK(18, 16) ++#define MTK_QTX_SCH_MAX_RATE_WEIGHT_V3 GENMASK(15, 10) ++#define MTK_QTX_SCH_MAX_RATE_MAN_V3 GENMASK(9, 3) ++#define MTK_QTX_SCH_MAX_RATE_EXP_V3 GENMASK(2, 0) ++ + /* QDMA TX Scheduler Rate Control Register */ + #define MTK_QDMA_TX_SCH_MAX_WFQ BIT(15) + +@@ -536,9 +543,23 @@ + #define XMAC_MCR_FORCE_RX_FC BIT(4) + + /* XFI Mac logic reset registers */ +-#define MTK_XMAC_LOGIC_RST(x) (MTK_XMAC_BASE(x) + 0x10) ++#define MTK_XMAC_LOGIC_RST(eth, x) (MTK_XMAC_BASE(x) + \ ++ (MTK_HAS_CAPS((eth)->soc->caps, MTK_XGMAC_V2) ? \ ++ 0x820 : 0x10)) + #define XMAC_LOGIC_RST BIT(0) + ++/* XFI Mac status force registers */ ++#define MTK_XMAC_STS(x) (MTK_XMAC_MCR(x) + 0x14) ++ ++/* XFI Mac status force registers */ ++#define MTK_XMAC_STS_FRC(x) (MTK_XMAC_MCR(x) + 0x18) ++#define XMAC_FORCE_RX_FC_MODE BIT(13) ++#define XMAC_FORCE_TX_FC_MODE BIT(12) ++#define XMAC_FORCE_LINK_MODE BIT(8) ++#define XMAC_FORCE_RX_FC BIT(5) ++#define XMAC_FORCE_TX_FC BIT(4) ++#define XMAC_FORCE_LINK BIT(0) ++ + /* XFI Mac count global control */ + #define MTK_XMAC_CNT_CTRL(x) (MTK_XMAC_BASE(x) + 0x100) + #define XMAC_GLB_CNTCLR BIT(0) +@@ -834,6 +855,17 @@ enum mtk_clks_map { + BIT_ULL(MTK_CLK_SGMII2_RX_250M) | \ + BIT_ULL(MTK_CLK_SGMII2_CDR_REF) | \ + BIT_ULL(MTK_CLK_SGMII2_CDR_FB)) ++#define MT7987_CLKS_BITMAP (BIT_ULL(MTK_CLK_FE) | BIT_ULL(MTK_CLK_GP1) | \ ++ BIT_ULL(MTK_CLK_GP2) | BIT_ULL(MTK_CLK_GP3) | \ ++ BIT_ULL(MTK_CLK_TOP_ETH_GMII_SEL) | \ ++ BIT_ULL(MTK_CLK_TOP_ETH_REFCK_50M_SEL) | \ ++ BIT_ULL(MTK_CLK_TOP_ETH_SYS_200M_SEL) | \ ++ BIT_ULL(MTK_CLK_TOP_ETH_SYS_SEL) | \ ++ BIT_ULL(MTK_CLK_TOP_ETH_XGMII_SEL) | \ ++ BIT_ULL(MTK_CLK_TOP_ETH_MII_SEL) | \ ++ BIT_ULL(MTK_CLK_TOP_NETSYS_SEL) | \ ++ BIT_ULL(MTK_CLK_TOP_NETSYS_500M_SEL) | \ ++ BIT_ULL(MTK_CLK_TOP_NETSYS_PAO_2X_SEL)) + #define MT7988_CLKS_BITMAP (BIT_ULL(MTK_CLK_FE) | BIT_ULL(MTK_CLK_ESW) | \ + BIT_ULL(MTK_CLK_GP1) | BIT_ULL(MTK_CLK_GP2) | \ + BIT_ULL(MTK_CLK_GP3) | BIT_ULL(MTK_CLK_XGP1) | \ +@@ -990,12 +1022,14 @@ enum mkt_eth_capabilities { + MTK_RSTCTRL_PPE2_BIT, + MTK_U3_COPHY_V2_BIT, + MTK_SRAM_BIT, ++ MTK_XGMAC_BIT, ++ MTK_XGMAC_V2_BIT, + MTK_36BIT_DMA_BIT, + + /* MUX BITS*/ + MTK_ETH_MUX_GDM1_TO_GMAC1_ESW_BIT, + MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY_BIT, +- MTK_ETH_MUX_U3_GMAC2_TO_QPHY_BIT, ++ MTK_ETH_MUX_U3_GMAC23_TO_QPHY_BIT, + MTK_ETH_MUX_GMAC2_TO_2P5GPHY_BIT, + MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII_BIT, + MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII_BIT, +@@ -1037,14 +1071,16 @@ enum mkt_eth_capabilities { + #define MTK_RSTCTRL_PPE2 BIT_ULL(MTK_RSTCTRL_PPE2_BIT) + #define MTK_U3_COPHY_V2 BIT_ULL(MTK_U3_COPHY_V2_BIT) + #define MTK_SRAM BIT_ULL(MTK_SRAM_BIT) ++#define MTK_XGMAC BIT_ULL(MTK_XGMAC_BIT) ++#define MTK_XGMAC_V2 BIT_ULL(MTK_XGMAC_V2_BIT) + #define MTK_36BIT_DMA BIT_ULL(MTK_36BIT_DMA_BIT) + + #define MTK_ETH_MUX_GDM1_TO_GMAC1_ESW \ + BIT_ULL(MTK_ETH_MUX_GDM1_TO_GMAC1_ESW_BIT) + #define MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY \ + BIT_ULL(MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY_BIT) +-#define MTK_ETH_MUX_U3_GMAC2_TO_QPHY \ +- BIT_ULL(MTK_ETH_MUX_U3_GMAC2_TO_QPHY_BIT) ++#define MTK_ETH_MUX_U3_GMAC23_TO_QPHY \ ++ BIT_ULL(MTK_ETH_MUX_U3_GMAC23_TO_QPHY_BIT) + #define MTK_ETH_MUX_GMAC2_TO_2P5GPHY \ + BIT_ULL(MTK_ETH_MUX_GMAC2_TO_2P5GPHY_BIT) + #define MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII \ +@@ -1076,12 +1112,13 @@ enum mkt_eth_capabilities { + #define MTK_GMAC2_RGMII (MTK_ETH_PATH_GMAC2_RGMII | MTK_RGMII) + #define MTK_GMAC2_SGMII (MTK_ETH_PATH_GMAC2_SGMII | MTK_SGMII) + #define MTK_GMAC2_GEPHY (MTK_ETH_PATH_GMAC2_GEPHY | MTK_GEPHY) +-#define MTK_GMAC2_2P5GPHY (MTK_ETH_PATH_GMAC2_2P5GPHY | MTK_2P5GPHY) ++#define MTK_GMAC2_2P5GPHY (MTK_ETH_PATH_GMAC2_2P5GPHY | MTK_2P5GPHY | MTK_XGMAC) ++#define MTK_GMAC2_2P5GPHY_V2 (MTK_ETH_PATH_GMAC2_2P5GPHY | MTK_2P5GPHY | MTK_XGMAC_V2) + #define MTK_GMAC3_SGMII (MTK_ETH_PATH_GMAC3_SGMII | MTK_SGMII) + #define MTK_GDM1_ESW (MTK_ETH_PATH_GDM1_ESW | MTK_ESW) +-#define MTK_GMAC1_USXGMII (MTK_ETH_PATH_GMAC1_USXGMII | MTK_USXGMII) +-#define MTK_GMAC2_USXGMII (MTK_ETH_PATH_GMAC2_USXGMII | MTK_USXGMII) +-#define MTK_GMAC3_USXGMII (MTK_ETH_PATH_GMAC3_USXGMII | MTK_USXGMII) ++#define MTK_GMAC1_USXGMII (MTK_ETH_PATH_GMAC1_USXGMII | MTK_USXGMII | MTK_XGMAC) ++#define MTK_GMAC2_USXGMII (MTK_ETH_PATH_GMAC2_USXGMII | MTK_USXGMII | MTK_XGMAC) ++#define MTK_GMAC3_USXGMII (MTK_ETH_PATH_GMAC3_USXGMII | MTK_USXGMII | MTK_XGMAC) + + /* MUXes present on SoCs */ + /* 0: GDM1 -> GMAC1, 1: GDM1 -> ESW */ +@@ -1091,9 +1128,9 @@ enum mkt_eth_capabilities { + #define MTK_MUX_GMAC2_GMAC0_TO_GEPHY \ + (MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY | MTK_MUX | MTK_INFRA) + +-/* 0: U3 -> QPHY, 1: GMAC2 -> QPHY */ +-#define MTK_MUX_U3_GMAC2_TO_QPHY \ +- (MTK_ETH_MUX_U3_GMAC2_TO_QPHY | MTK_MUX | MTK_INFRA) ++/* 0: U3 -> QPHY, 1: GMACx -> QPHY where x is 2 or 3 */ ++#define MTK_MUX_U3_GMAC23_TO_QPHY \ ++ (MTK_ETH_MUX_U3_GMAC23_TO_QPHY | MTK_MUX | MTK_INFRA) + + /* 2: GMAC1 -> SGMII, 3: GMAC2 -> SGMII */ + #define MTK_MUX_GMAC1_GMAC2_TO_SGMII_RGMII \ +@@ -1133,18 +1170,24 @@ enum mkt_eth_capabilities { + #define MT7629_CAPS (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | MTK_GMAC2_GEPHY | \ + MTK_GDM1_ESW | MTK_MUX_GDM1_TO_GMAC1_ESW | \ + MTK_MUX_GMAC2_GMAC0_TO_GEPHY | \ +- MTK_MUX_U3_GMAC2_TO_QPHY | \ ++ MTK_MUX_U3_GMAC23_TO_QPHY | \ + MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA) + + #define MT7981_CAPS (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | MTK_GMAC2_GEPHY | \ + MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA | \ +- MTK_MUX_U3_GMAC2_TO_QPHY | MTK_U3_COPHY_V2 | \ ++ MTK_MUX_U3_GMAC23_TO_QPHY | MTK_U3_COPHY_V2 | \ + MTK_RSTCTRL_PPE1 | MTK_SRAM) + + #define MT7986_CAPS (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | \ + MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA | \ + MTK_RSTCTRL_PPE1 | MTK_SRAM) + ++#define MT7987_CAPS (MTK_36BIT_DMA | MTK_GMAC1_SGMII | \ ++ MTK_GMAC2_2P5GPHY_V2 | MTK_GMAC2_SGMII | MTK_GMAC3_SGMII | \ ++ MTK_MUX_GMAC123_TO_GEPHY_SGMII | MTK_MUX_GMAC2_TO_2P5GPHY | \ ++ MTK_MUX_U3_GMAC23_TO_QPHY | MTK_U3_COPHY_V2 | \ ++ MTK_QDMA | MTK_RSTCTRL_PPE1) ++ + #define MT7988_CAPS (MTK_36BIT_DMA | MTK_GDM1_ESW | MTK_GMAC1_SGMII | \ + MTK_GMAC2_2P5GPHY | MTK_GMAC2_SGMII | MTK_GMAC2_USXGMII | \ + MTK_GMAC3_SGMII | MTK_GMAC3_USXGMII | \ diff --git a/target/linux/mediatek/patches-6.12/751-net-ethernet-mtk_eth_soc-revise-hardware-configuration-for-mt7987.patch b/target/linux/mediatek/patches-6.12/751-net-ethernet-mtk_eth_soc-revise-hardware-configuration-for-mt7987.patch new file mode 100644 index 000000000..56dd3257c --- /dev/null +++ b/target/linux/mediatek/patches-6.12/751-net-ethernet-mtk_eth_soc-revise-hardware-configuration-for-mt7987.patch @@ -0,0 +1,79 @@ +From 5ef0b04d30efff8f171e30bfbe876c00e3b9036a Mon Sep 17 00:00:00 2001 +From: Bo-Cun Chen +Date: Fri, 9 May 2025 09:49:04 +0800 +Subject: [PATCH] net: ethernet: mtk_eth_soc: revise hardware configuration for + mt7987 + +Change hardware configuration for the MT7987. + - Enable PSE drop mechanism when the WDMA Rx ring full + - Enable PSE no-drop mechanism for packets from the WDMA Tx + +Signed-off-by: Bo-Cun Chen +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 49 +++++++++++++-------- + 1 file changed, 31 insertions(+), 18 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -4445,27 +4445,40 @@ static int mtk_hw_init(struct mtk_eth *e + mtk_w32(eth, PSE_DUMMY_WORK_GDM(1) | PSE_DUMMY_WORK_GDM(2) | + PSE_DUMMY_WORK_GDM(3) | DUMMY_PAGE_THR, PSE_DUMY_REQ); + +- /* PSE free buffer drop threshold */ +- mtk_w32(eth, 0x00600009, PSE_IQ_REV(8)); +- +- /* PSE should not drop port8, port9 and port13 packets from +- * WDMA Tx +- */ +- mtk_w32(eth, 0x00002300, PSE_DROP_CFG); +- +- /* PSE should drop packets to port8, port9 and port13 on WDMA Rx +- * ring full +- */ +- mtk_w32(eth, 0x00002300, PSE_PPE_DROP(0)); +- mtk_w32(eth, 0x00002300, PSE_PPE_DROP(1)); +- mtk_w32(eth, 0x00002300, PSE_PPE_DROP(2)); +- +- /* GDM and CDM Threshold */ +- mtk_w32(eth, 0x08000707, MTK_CDMW0_THRES); +- mtk_w32(eth, 0x00000077, MTK_CDMW1_THRES); +- +- /* Disable GDM1 RX CRC stripping */ +- mtk_m32(eth, MTK_GDMA_STRP_CRC, 0, MTK_GDMA_FWD_CFG(0)); ++ if (eth->soc->caps == MT7988_CAPS) { ++ /* PSE free buffer drop threshold */ ++ mtk_w32(eth, 0x00600009, PSE_IQ_REV(8)); ++ ++ /* PSE should not drop port8, port9 and port13 packets ++ * from WDMA Tx ++ */ ++ mtk_w32(eth, 0x00002300, PSE_DROP_CFG); ++ ++ /* PSE should drop packets to port8, port9 and port13 ++ * on WDMA Rx ring full ++ */ ++ mtk_w32(eth, 0x00002300, PSE_PPE_DROP(0)); ++ mtk_w32(eth, 0x00002300, PSE_PPE_DROP(1)); ++ mtk_w32(eth, 0x00002300, PSE_PPE_DROP(2)); ++ ++ /* GDM and CDM Threshold */ ++ mtk_w32(eth, 0x08000707, MTK_CDMW0_THRES); ++ mtk_w32(eth, 0x00000077, MTK_CDMW1_THRES); ++ } else if (eth->soc->caps == MT7987_CAPS) { ++ /* PSE should not drop port8 packets from WDMA Tx */ ++ mtk_w32(eth, 0x00000100, PSE_DROP_CFG); ++ ++ /* PSE should drop packets to port8 on WDMA Rx ring ++ * full ++ */ ++ mtk_w32(eth, 0x00000100, PSE_PPE_DROP(0)); ++ mtk_w32(eth, 0x00000100, PSE_PPE_DROP(1)); ++ } ++ ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_ESW)) { ++ /* Disable GDM1 RX CRC stripping */ ++ mtk_m32(eth, MTK_GDMA_STRP_CRC, 0, MTK_GDMA_FWD_CFG(0)); ++ } + + /* PSE GDM3 MIB counter has incorrect hw default values, + * so the driver ought to read clear the values beforehand diff --git a/target/linux/mediatek/patches-6.12/752-net-phy-mediatek-i2p5g-add-support-for-mt7987.patch b/target/linux/mediatek/patches-6.12/752-net-phy-mediatek-i2p5g-add-support-for-mt7987.patch new file mode 100644 index 000000000..de720a357 --- /dev/null +++ b/target/linux/mediatek/patches-6.12/752-net-phy-mediatek-i2p5g-add-support-for-mt7987.patch @@ -0,0 +1,397 @@ +--- a/drivers/net/phy/mediatek/mtk-2p5ge.c ++++ b/drivers/net/phy/mediatek/mtk-2p5ge.c +@@ -12,13 +12,77 @@ + + #include "mtk.h" + ++#define MTK_2P5GPHY_ID_MT7987 (0x00339c91) + #define MTK_2P5GPHY_ID_MT7988 (0x00339c11) + ++#define MT7987_2P5GE_PMB_FW "mediatek/mt7987/i2p5ge-phy-pmb.bin" ++#define MT7987_2P5GE_PMB_FW_SIZE (0x18000) ++#define MT7987_2P5GE_DSPBITTB \ ++ "mediatek/mt7987/i2p5ge-phy-DSPBitTb.bin" ++#define MT7987_2P5GE_DSPBITTB_SIZE (0x7000) ++ + #define MT7988_2P5GE_PMB_FW "mediatek/mt7988/i2p5ge-phy-pmb.bin" + #define MT7988_2P5GE_PMB_FW_SIZE (0x20000) ++ ++#define MTK_2P5GPHY_PMD_REG_BASE (0x0f010000) ++#define MTK_2P5GPHY_PMD_REG_LEN (0x210) ++#define DO_NOT_RESET (0x28) ++#define DO_NOT_RESET_XBZ BIT(0) ++#define DO_NOT_RESET_PMA BIT(3) ++#define DO_NOT_RESET_RX BIT(5) ++#define FNPLL_PWR_CTRL1 (0x208) ++#define RG_SPEED_MASK GENMASK(3, 0) ++#define RG_SPEED_2500 BIT(3) ++#define RG_SPEED_100 BIT(0) ++#define FNPLL_PWR_CTRL_STATUS (0x20c) ++#define RG_STABLE_MASK GENMASK(3, 0) ++#define RG_SPEED_2500_STABLE BIT(3) ++#define RG_SPEED_100_STABLE BIT(0) ++ ++#define MTK_2P5GPHY_XBZ_PCS_REG_BASE (0x0f030000) ++#define MTK_2P5GPHY_XBZ_PCS_REG_LEN (0x844) ++#define PHY_CTRL_CONFIG (0x200) ++#define PMU_WP (0x800) ++#define WRITE_PROTECT_KEY (0xCAFEF00D) ++#define PMU_PMA_AUTO_CFG (0x820) ++#define POWER_ON_AUTO_MODE BIT(16) ++#define PMU_AUTO_MODE_EN BIT(0) ++#define PMU_PMA_STATUS (0x840) ++#define CLK_IS_DISABLED BIT(3) ++ ++#define MTK_2P5GPHY_XBZ_PMA_RX_BASE (0x0f080000) ++#define MTK_2P5GPHY_XBZ_PMA_RX_LEN (0x5228) ++#define SMEM_WDAT0 (0x5000) ++#define SMEM_WDAT1 (0x5004) ++#define SMEM_WDAT2 (0x5008) ++#define SMEM_WDAT3 (0x500c) ++#define SMEM_CTRL (0x5024) ++#define SMEM_HW_RDATA_ZERO BIT(24) ++#define SMEM_ADDR_REF_ADDR (0x502c) ++#define CM_CTRL_P01 (0x5100) ++#define CM_CTRL_P23 (0x5124) ++#define DM_CTRL_P01 (0x5200) ++#define DM_CTRL_P23 (0x5224) ++ ++#define MTK_2P5GPHY_CHIP_SCU_BASE (0x0f0cf800) ++#define MTK_2P5GPHY_CHIP_SCU_LEN (0x12c) ++#define SYS_SW_RESET (0x128) ++#define RESET_RST_CNT BIT(0) ++ ++#define MTK_2P5GPHY_MCU_CSR_BASE (0x0f0f0000) ++#define MTK_2P5GPHY_MCU_CSR_LEN (0x20) + #define MD32_EN_CFG (0x18) + #define MD32_EN BIT(0) + ++#define MTK_2P5GPHY_PMB_FW_BASE (0x0f100000) ++//#define MTK_2P5GPHY_PMB_FW_LEN MT7988_2P5GE_PMB_FW_SIZE ++ ++#define MTK_2P5GPHY_APB_BASE (0x11c30000) ++#define MTK_2P5GPHY_APB_LEN (0x9c) ++#define SW_RESET (0x94) ++#define MD32_RESTART_EN_CLEAR BIT(9) ++ ++ + #define BASE100T_STATUS_EXTEND (0x10) + #define BASE1000T_STATUS_EXTEND (0x11) + #define EXTEND_CTRL_AND_STATUS (0x16) +@@ -31,6 +95,14 @@ + #define MTK_PHY_LPI_PCS_DSP_CTRL (0x121) + #define MTK_PHY_LPI_SIG_EN_LO_THRESH100_MASK GENMASK(12, 8) + ++#define MTK_PHY_LINK_STATUS_RELATED (0x147) ++#define MTK_PHY_BYPASS_LINK_STATUS_OK BIT(4) ++#define MTK_PHY_FORCE_LINK_STATUS_HCD BIT(3) ++ ++#define MTK_PHY_AN_FORCE_SPEED_REG (0x313) ++#define MTK_PHY_MASTER_FORCE_SPEED_SEL_EN BIT(7) ++#define MTK_PHY_MASTER_FORCE_SPEED_SEL_MASK GENMASK(6, 0) ++ + #define MTK_PHY_HOST_CMD1 0x800e + #define MTK_PHY_HOST_CMD2 0x800f + /* Registers on Token Ring debug nodes */ +@@ -48,7 +120,249 @@ enum { + PHY_AUX_SPD_2500, + }; + +-static int mt798x_2p5ge_phy_load_fw(struct phy_device *phydev) ++static int mt7987_2p5ge_phy_load_fw(struct phy_device *phydev) ++{ ++ struct mtk_i2p5ge_phy_priv *priv = phydev->priv; ++ struct device *dev = &phydev->mdio.dev; ++ void __iomem *xbz_pcs_reg_base; ++ void __iomem *xbz_pma_rx_base; ++ void __iomem *chip_scu_base; ++ void __iomem *pmd_reg_base; ++ void __iomem *mcu_csr_base; ++ const struct firmware *fw; ++ void __iomem *apb_base; ++ void __iomem *pmb_addr; ++ int ret, i; ++ u32 reg; ++ ++ if (priv->fw_loaded) ++ return 0; ++ ++ apb_base = ioremap(MTK_2P5GPHY_APB_BASE, ++ MTK_2P5GPHY_APB_LEN); ++ if (!apb_base) ++ return -ENOMEM; ++ ++ pmd_reg_base = ioremap(MTK_2P5GPHY_PMD_REG_BASE, ++ MTK_2P5GPHY_PMD_REG_LEN); ++ if (!pmd_reg_base) { ++ ret = -ENOMEM; ++ goto free_apb; ++ } ++ ++ xbz_pcs_reg_base = ioremap(MTK_2P5GPHY_XBZ_PCS_REG_BASE, ++ MTK_2P5GPHY_XBZ_PCS_REG_LEN); ++ if (!xbz_pcs_reg_base) { ++ ret = -ENOMEM; ++ goto free_pmd; ++ } ++ ++ xbz_pma_rx_base = ioremap(MTK_2P5GPHY_XBZ_PMA_RX_BASE, ++ MTK_2P5GPHY_XBZ_PMA_RX_LEN); ++ if (!xbz_pma_rx_base) { ++ ret = -ENOMEM; ++ goto free_pcs; ++ } ++ ++ chip_scu_base = ioremap(MTK_2P5GPHY_CHIP_SCU_BASE, ++ MTK_2P5GPHY_CHIP_SCU_LEN); ++ if (!chip_scu_base) { ++ ret = -ENOMEM; ++ goto free_pma; ++ } ++ ++ mcu_csr_base = ioremap(MTK_2P5GPHY_MCU_CSR_BASE, ++ MTK_2P5GPHY_MCU_CSR_LEN); ++ if (!mcu_csr_base) { ++ ret = -ENOMEM; ++ goto free_chip_scu; ++ } ++ ++ pmb_addr = ioremap(MTK_2P5GPHY_PMB_FW_BASE, MT7987_2P5GE_PMB_FW_SIZE); ++ if (!pmb_addr) { ++ return -ENOMEM; ++ goto free_mcu_csr; ++ } ++ ++ ret = request_firmware(&fw, MT7987_2P5GE_PMB_FW, dev); ++ if (ret) { ++ dev_err(dev, "failed to load firmware: %s, ret: %d\n", ++ MT7987_2P5GE_PMB_FW, ret); ++ goto free_pmb_addr; ++ } ++ ++ if (fw->size != MT7987_2P5GE_PMB_FW_SIZE) { ++ dev_err(dev, "PMb firmware size 0x%zx != 0x%x\n", ++ fw->size, MT7987_2P5GE_PMB_FW_SIZE); ++ ret = -EINVAL; ++ goto release_fw; ++ } ++ ++ /* Force 2.5Gphy back to AN state */ ++ phy_set_bits(phydev, MII_BMCR, BMCR_RESET); ++ usleep_range(5000, 6000); ++ phy_set_bits(phydev, MII_BMCR, BMCR_PDOWN); ++ ++ reg = readw(apb_base + SW_RESET); ++ writew(reg & ~MD32_RESTART_EN_CLEAR, apb_base + SW_RESET); ++ writew(reg | MD32_RESTART_EN_CLEAR, apb_base + SW_RESET); ++ writew(reg & ~MD32_RESTART_EN_CLEAR, apb_base + SW_RESET); ++ ++ reg = readw(mcu_csr_base + MD32_EN_CFG); ++ writew(reg & ~MD32_EN, mcu_csr_base + MD32_EN_CFG); ++ ++ for (i = 0; i < MT7987_2P5GE_PMB_FW_SIZE - 1; i += 4) ++ writel(*((uint32_t *)(fw->data + i)), pmb_addr + i); ++ dev_info(dev, "Firmware date code: %x/%x/%x, version: %x.%x\n", ++ be16_to_cpu(*((__be16 *)(fw->data + ++ MT7987_2P5GE_PMB_FW_SIZE - 8))), ++ *(fw->data + MT7987_2P5GE_PMB_FW_SIZE - 6), ++ *(fw->data + MT7987_2P5GE_PMB_FW_SIZE - 5), ++ *(fw->data + MT7987_2P5GE_PMB_FW_SIZE - 2), ++ *(fw->data + MT7987_2P5GE_PMB_FW_SIZE - 1)); ++ release_firmware(fw); ++ ++ /* Enable 100Mbps module clock. */ ++ writel(FIELD_PREP(RG_SPEED_MASK, RG_SPEED_100), ++ pmd_reg_base + FNPLL_PWR_CTRL1); ++ ++ /* Check if 100Mbps module clock is ready. */ ++ ret = readl_poll_timeout(pmd_reg_base + FNPLL_PWR_CTRL_STATUS, reg, ++ reg & RG_SPEED_100_STABLE, 1, 10000); ++ if (ret) ++ dev_err(dev, "Fail to enable 100Mbps module clock: %d\n", ret); ++ ++ /* Enable 2.5Gbps module clock. */ ++ writel(FIELD_PREP(RG_SPEED_MASK, RG_SPEED_2500), ++ pmd_reg_base + FNPLL_PWR_CTRL1); ++ ++ /* Check if 2.5Gbps module clock is ready. */ ++ ret = readl_poll_timeout(pmd_reg_base + FNPLL_PWR_CTRL_STATUS, reg, ++ reg & RG_SPEED_2500_STABLE, 1, 10000); ++ ++ if (ret) ++ dev_err(dev, "Fail to enable 2.5Gbps module clock: %d\n", ret); ++ ++ /* Disable AN */ ++ phy_clear_bits(phydev, MII_BMCR, BMCR_ANENABLE); ++ ++ /* Force to run at 2.5G speed */ ++ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_AN_FORCE_SPEED_REG, ++ MTK_PHY_MASTER_FORCE_SPEED_SEL_MASK, ++ MTK_PHY_MASTER_FORCE_SPEED_SEL_EN | ++ FIELD_PREP(MTK_PHY_MASTER_FORCE_SPEED_SEL_MASK, 0x1b)); ++ ++ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LINK_STATUS_RELATED, ++ MTK_PHY_BYPASS_LINK_STATUS_OK | ++ MTK_PHY_FORCE_LINK_STATUS_HCD); ++ ++ /* Set xbz, pma and rx as "do not reset" in order to input DSP code. */ ++ reg = readl(pmd_reg_base + DO_NOT_RESET); ++ reg |= DO_NOT_RESET_XBZ | DO_NOT_RESET_PMA | DO_NOT_RESET_RX; ++ writel(reg, pmd_reg_base + DO_NOT_RESET); ++ ++ reg = readl(chip_scu_base + SYS_SW_RESET); ++ writel(reg & ~RESET_RST_CNT, chip_scu_base + SYS_SW_RESET); ++ ++ writel(WRITE_PROTECT_KEY, xbz_pcs_reg_base + PMU_WP); ++ ++ reg = readl(xbz_pcs_reg_base + PMU_PMA_AUTO_CFG); ++ reg |= PMU_AUTO_MODE_EN | POWER_ON_AUTO_MODE; ++ writel(reg, xbz_pcs_reg_base + PMU_PMA_AUTO_CFG); ++ ++ /* Check if clock in auto mode is disabled. */ ++ ret = readl_poll_timeout(xbz_pcs_reg_base + PMU_PMA_STATUS, reg, ++ (reg & CLK_IS_DISABLED) == 0x0, 1, 100000); ++ if (ret) ++ dev_err(dev, "Clock isn't disabled in auto mode: %d\n", ret); ++ ++ reg = readl(xbz_pma_rx_base + SMEM_CTRL); ++ writel(reg | SMEM_HW_RDATA_ZERO, xbz_pma_rx_base + SMEM_CTRL); ++ ++ reg = readl(xbz_pcs_reg_base + PHY_CTRL_CONFIG); ++ writel(reg | BIT(16), xbz_pcs_reg_base + PHY_CTRL_CONFIG); ++ ++ /* Initialize data memory */ ++ reg = readl(xbz_pma_rx_base + DM_CTRL_P01); ++ writel(reg | BIT(28), xbz_pma_rx_base + DM_CTRL_P01); ++ reg = readl(xbz_pma_rx_base + DM_CTRL_P23); ++ writel(reg | BIT(28), xbz_pma_rx_base + DM_CTRL_P23); ++ ++ /* Initialize coefficient memory */ ++ reg = readl(xbz_pma_rx_base + CM_CTRL_P01); ++ writel(reg | BIT(28), xbz_pma_rx_base + CM_CTRL_P01); ++ reg = readl(xbz_pma_rx_base + CM_CTRL_P23); ++ writel(reg | BIT(28), xbz_pma_rx_base + CM_CTRL_P23); ++ ++ /* Initilize PM offset */ ++ writel(0, xbz_pma_rx_base + SMEM_ADDR_REF_ADDR); ++ ++ ret = request_firmware(&fw, MT7987_2P5GE_DSPBITTB, dev); ++ if (ret) { ++ dev_err(dev, "failed to load firmware: %s, ret: %d\n", ++ MT7987_2P5GE_DSPBITTB, ret); ++ goto free_pmb_addr; ++ } ++ if (fw->size != MT7987_2P5GE_DSPBITTB_SIZE) { ++ dev_err(dev, "DSPBITTB size 0x%zx != 0x%x\n", ++ fw->size, MT7987_2P5GE_DSPBITTB_SIZE); ++ ret = -EINVAL; ++ goto release_fw; ++ } ++ ++ for (i = 0; i < fw->size - 1; i += 16) { ++ writel(*((uint32_t *)(fw->data + i)), ++ xbz_pma_rx_base + SMEM_WDAT0); ++ writel(*((uint32_t *)(fw->data + i + 0x4)), ++ xbz_pma_rx_base + SMEM_WDAT1); ++ writel(*((uint32_t *)(fw->data + i + 0x8)), ++ xbz_pma_rx_base + SMEM_WDAT2); ++ writel(*((uint32_t *)(fw->data + i + 0xc)), ++ xbz_pma_rx_base + SMEM_WDAT3); ++ } ++ ++ reg = readl(xbz_pma_rx_base + DM_CTRL_P01); ++ writel(reg & ~BIT(28), xbz_pma_rx_base + DM_CTRL_P01); ++ ++ reg = readl(xbz_pma_rx_base + DM_CTRL_P23); ++ writel(reg & ~BIT(28), xbz_pma_rx_base + DM_CTRL_P23); ++ ++ reg = readl(xbz_pma_rx_base + CM_CTRL_P01); ++ writel(reg & ~BIT(28), xbz_pma_rx_base + CM_CTRL_P01); ++ ++ reg = readl(xbz_pma_rx_base + CM_CTRL_P23); ++ writel(reg & ~BIT(28), xbz_pma_rx_base + CM_CTRL_P23); ++ ++ reg = readw(mcu_csr_base + MD32_EN_CFG); ++ writew(reg | MD32_EN, mcu_csr_base + MD32_EN_CFG); ++ phy_set_bits(phydev, MII_BMCR, BMCR_RESET); ++ /* We need a delay here to stabilize initialization of MCU */ ++ usleep_range(7000, 8000); ++ dev_info(dev, "Firmware loading/trigger ok.\n"); ++ ++ priv->fw_loaded = true; ++ ++release_fw: ++ release_firmware(fw); ++free_pmb_addr: ++ iounmap(pmb_addr); ++free_mcu_csr: ++ iounmap(mcu_csr_base); ++free_chip_scu: ++ iounmap(chip_scu_base); ++free_pma: ++ iounmap(xbz_pma_rx_base); ++free_pcs: ++ iounmap(xbz_pcs_reg_base); ++free_pmd: ++ iounmap(pmd_reg_base); ++free_apb: ++ iounmap(apb_base); ++ ++ return ret; ++} ++ ++static int mt7988_2p5ge_phy_load_fw(struct phy_device *phydev) + { + struct mtk_i2p5ge_phy_priv *priv = phydev->priv; + void __iomem *mcu_csr_base, *pmb_addr; +@@ -135,7 +449,20 @@ static int mt798x_2p5ge_phy_config_init( + if (phydev->interface != PHY_INTERFACE_MODE_INTERNAL) + return -ENODEV; + +- ret = mt798x_2p5ge_phy_load_fw(phydev); ++ switch (phydev->drv->phy_id) { ++ case MTK_2P5GPHY_ID_MT7987: ++ ret = mt7987_2p5ge_phy_load_fw(phydev); ++ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED0_ON_CTRL, ++ MTK_PHY_LED_ON_POLARITY); ++ break; ++ case MTK_2P5GPHY_ID_MT7988: ++ ret = mt7988_2p5ge_phy_load_fw(phydev); ++ phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED0_ON_CTRL, ++ MTK_PHY_LED_ON_POLARITY); ++ break; ++ default: ++ return -EINVAL; ++ } + if (ret < 0) + return ret; + +@@ -293,6 +620,7 @@ static int mt798x_2p5ge_phy_probe(struct + return -ENOMEM; + + switch (phydev->drv->phy_id) { ++ case MTK_2P5GPHY_ID_MT7987: + case MTK_2P5GPHY_ID_MT7988: + /* The original hardware only sets MDIO_DEVS_PMAPMD */ + phydev->c45_ids.mmds_present |= MDIO_DEVS_PCS | +@@ -312,6 +640,20 @@ static int mt798x_2p5ge_phy_probe(struct + + static struct phy_driver mtk_2p5gephy_driver[] = { + { ++ PHY_ID_MATCH_MODEL(MTK_2P5GPHY_ID_MT7987), ++ .name = "MediaTek MT7987 2.5GbE PHY", ++ .probe = mt798x_2p5ge_phy_probe, ++ .config_init = mt798x_2p5ge_phy_config_init, ++ .config_aneg = mt798x_2p5ge_phy_config_aneg, ++ .get_features = mt798x_2p5ge_phy_get_features, ++ .read_status = mt798x_2p5ge_phy_read_status, ++ .get_rate_matching = mt798x_2p5ge_phy_get_rate_matching, ++ .suspend = genphy_suspend, ++ .resume = genphy_resume, ++ .read_page = mtk_phy_read_page, ++ .write_page = mtk_phy_write_page, ++ }, ++ { + PHY_ID_MATCH_MODEL(MTK_2P5GPHY_ID_MT7988), + .name = "MediaTek MT7988 2.5GbE PHY", + .probe = mt798x_2p5ge_phy_probe, diff --git a/target/linux/mediatek/patches-6.12/830-thermal-drivers-mediatek-lvts_thermal-Add-irq_enable-support.patch b/target/linux/mediatek/patches-6.12/830-thermal-drivers-mediatek-lvts_thermal-Add-irq_enable-support.patch new file mode 100644 index 000000000..ff1fd3e01 --- /dev/null +++ b/target/linux/mediatek/patches-6.12/830-thermal-drivers-mediatek-lvts_thermal-Add-irq_enable-support.patch @@ -0,0 +1,148 @@ +From: Chad Monroe +Date: Mon, 01 Sep 2025 06:42:10 -0700 +Subject: [PATCH] thermal/drivers/mediatek/lvts_thermal: Add irq_enable + support. + +Allow interrupt support to be disabled as some SoCs don't support it. + +Signed-off-by: Chad Monroe +--- + drivers/thermal/mediatek/lvts_thermal.c | 33 ++++++++++++++++------ + 1 file changed, 25 insertions(+), 8 deletions(-) + +--- a/drivers/thermal/mediatek/lvts_thermal.c ++++ b/drivers/thermal/mediatek/lvts_thermal.c +@@ -127,6 +127,7 @@ struct lvts_data { + const struct lvts_ctrl_data *lvts_ctrl; + const u32 *conn_cmd; + const u32 *init_cmd; ++ bool irq_enable; + int num_lvts_ctrl; + int num_conn_cmd; + int num_init_cmd; +@@ -408,6 +409,10 @@ static int lvts_set_trips(struct thermal + lvts_ctrl->high_thresh = high; + lvts_ctrl->low_thresh = low; + } ++ ++ if (!lvts_data->irq_enable) ++ return 0; ++ + lvts_update_irq_mask(lvts_ctrl); + + if (!should_update_thresh) +@@ -921,6 +926,8 @@ static void lvts_write_config(struct lvt + + static int lvts_irq_init(struct lvts_ctrl *lvts_ctrl) + { ++ const struct lvts_data *lvts_data = lvts_ctrl->lvts_data; ++ + /* + * LVTS_PROTCTL : Thermal Protection Sensor Selection + * +@@ -954,7 +961,8 @@ static int lvts_irq_init(struct lvts_ctr + * The LVTS_MONINT register layout is the same as the LVTS_MONINTSTS + * register, except we set the bits to enable the interrupt. + */ +- writel(0, LVTS_MONINT(lvts_ctrl->base)); ++ if (lvts_data->irq_enable) ++ writel(0, LVTS_MONINT(lvts_ctrl->base)); + + return 0; + } +@@ -1338,9 +1346,11 @@ static int lvts_probe(struct platform_de + if (IS_ERR(lvts_td->reset)) + return dev_err_probe(dev, PTR_ERR(lvts_td->reset), "Failed to get reset control\n"); + +- irq = platform_get_irq(pdev, 0); +- if (irq < 0) +- return irq; ++ if (lvts_data->irq_enable) { ++ irq = platform_get_irq(pdev, 0); ++ if (irq < 0) ++ return irq; ++ } + + golden_temp_offset = lvts_data->temp_offset; + +@@ -1352,10 +1362,12 @@ static int lvts_probe(struct platform_de + * At this point the LVTS is initialized and enabled. We can + * safely enable the interrupt. + */ +- ret = devm_request_threaded_irq(dev, irq, NULL, lvts_irq_handler, +- IRQF_ONESHOT, dev_name(dev), lvts_td); +- if (ret) +- return dev_err_probe(dev, ret, "Failed to request interrupt\n"); ++ if (lvts_data->irq_enable) { ++ ret = devm_request_threaded_irq(dev, irq, NULL, lvts_irq_handler, ++ IRQF_ONESHOT, dev_name(dev), lvts_td); ++ if (ret) ++ return dev_err_probe(dev, ret, "Failed to request interrupt\n"); ++ } + + platform_set_drvdata(pdev, lvts_td); + +@@ -1754,6 +1766,7 @@ static const struct lvts_ctrl_data mt819 + }; + + static const struct lvts_data mt7988_lvts_ap_data = { ++ .irq_enable = true, + .lvts_ctrl = mt7988_lvts_ap_data_ctrl, + .conn_cmd = mt7988_conn_cmds, + .init_cmd = mt7988_init_cmds, +@@ -1766,6 +1779,7 @@ static const struct lvts_data mt7988_lvt + }; + + static const struct lvts_data mt8186_lvts_data = { ++ .irq_enable = true, + .lvts_ctrl = mt8186_lvts_data_ctrl, + .conn_cmd = default_conn_cmds, + .init_cmd = default_init_cmds, +@@ -1779,6 +1793,7 @@ static const struct lvts_data mt8186_lvt + }; + + static const struct lvts_data mt8188_lvts_mcu_data = { ++ .irq_enable = true, + .lvts_ctrl = mt8188_lvts_mcu_data_ctrl, + .conn_cmd = default_conn_cmds, + .init_cmd = default_init_cmds, +@@ -1792,6 +1807,7 @@ static const struct lvts_data mt8188_lvt + }; + + static const struct lvts_data mt8188_lvts_ap_data = { ++ .irq_enable = true, + .lvts_ctrl = mt8188_lvts_ap_data_ctrl, + .conn_cmd = default_conn_cmds, + .init_cmd = default_init_cmds, +@@ -1805,6 +1821,7 @@ static const struct lvts_data mt8188_lvt + }; + + static const struct lvts_data mt8192_lvts_mcu_data = { ++ .irq_enable = true, + .lvts_ctrl = mt8192_lvts_mcu_data_ctrl, + .conn_cmd = default_conn_cmds, + .init_cmd = default_init_cmds, +@@ -1818,6 +1835,7 @@ static const struct lvts_data mt8192_lvt + }; + + static const struct lvts_data mt8192_lvts_ap_data = { ++ .irq_enable = true, + .lvts_ctrl = mt8192_lvts_ap_data_ctrl, + .conn_cmd = default_conn_cmds, + .init_cmd = default_init_cmds, +@@ -1831,6 +1849,7 @@ static const struct lvts_data mt8192_lvt + }; + + static const struct lvts_data mt8195_lvts_mcu_data = { ++ .irq_enable = true, + .lvts_ctrl = mt8195_lvts_mcu_data_ctrl, + .conn_cmd = default_conn_cmds, + .init_cmd = default_init_cmds, +@@ -1844,6 +1863,7 @@ static const struct lvts_data mt8195_lvt + }; + + static const struct lvts_data mt8195_lvts_ap_data = { ++ .irq_enable = true, + .lvts_ctrl = mt8195_lvts_ap_data_ctrl, + .conn_cmd = default_conn_cmds, + .init_cmd = default_init_cmds, diff --git a/target/linux/mediatek/patches-6.12/831-thermal-drivers-mediatek-lvts_thermal-Add-MT7987-support.patch b/target/linux/mediatek/patches-6.12/831-thermal-drivers-mediatek-lvts_thermal-Add-MT7987-support.patch new file mode 100644 index 000000000..7cd4affae --- /dev/null +++ b/target/linux/mediatek/patches-6.12/831-thermal-drivers-mediatek-lvts_thermal-Add-MT7987-support.patch @@ -0,0 +1,106 @@ +From: Chad Monroe +Date: Mon, 01 Sep 2025 06:44:04 -0700 +Subject: [PATCH] thermal/drivers/mediatek/lvts_thermal: Add MT7987 support + +Add support for Mediatek MT7987 LVTS. Based patch[1] from vendor SDK. + +1: https://git01.mediatek.com/plugins/gitiles/openwrt/feeds/mtk-openwrt-feeds/+/742007e189ffcc95783924cea1150f574b6eb71e + +Signed-off-by: Chad Monroe +--- + drivers/thermal/mediatek/lvts_thermal.c | 36 ++++++++++ + include/dt-bindings/thermal/mediatek,lvts-thermal.h | 3 + 2 files changed, 39 insertions(+) + +--- a/drivers/thermal/mediatek/lvts_thermal.c ++++ b/drivers/thermal/mediatek/lvts_thermal.c +@@ -87,6 +87,8 @@ + #define LVTS_COEFF_B_MT8195 250460 + #define LVTS_COEFF_A_MT7988 -204650 + #define LVTS_COEFF_B_MT7988 204650 ++#define LVTS_COEFF_A_MT7987 -204650 ++#define LVTS_COEFF_B_MT7987 204650 + + #define LVTS_MSR_IMMEDIATE_MODE 0 + #define LVTS_MSR_FILTERED_MODE 1 +@@ -1385,6 +1387,19 @@ static void lvts_remove(struct platform_ + lvts_ctrl_set_enable(&lvts_td->lvts_ctrl[i], false); + } + ++static const struct lvts_ctrl_data mt7987_lvts_ap_data_ctrl[] = { ++ { ++ .lvts_sensor = { ++ { .dt_id = MT7987_CPU, ++ .cal_offsets = { 0x04, 0x05, 0x06 } }, ++ { .dt_id = MT7987_ETH2P5G, ++ .cal_offsets = { 0x08, 0x09, 0x0a } }, ++ }, ++ VALID_SENSOR_MAP(1, 1, 0, 0), ++ .offset = 0x0, ++ }, ++}; ++ + static const struct lvts_ctrl_data mt7988_lvts_ap_data_ctrl[] = { + { + .lvts_sensor = { +@@ -1455,6 +1470,7 @@ static int lvts_resume(struct device *de + } + + static const u32 default_conn_cmds[] = { 0xC103FFFF, 0xC502FF55 }; ++static const u32 mt7987_conn_cmds[] = { 0xC103FFFF, 0xC502FC55 }; + static const u32 mt7988_conn_cmds[] = { 0xC103FFFF, 0xC502FC55 }; + + /* +@@ -1467,6 +1483,12 @@ static const u32 default_init_cmds[] = { + 0xC10300FC, 0xC103009D, 0xC10300F1, 0xC10300E1 + }; + ++static const u32 mt7987_init_cmds[] = { ++ 0xC1030300, 0xC1030420, 0xC1030500, 0xC10307A6, 0xC10308C7, ++ 0xC103098D, 0xC1030C7C, 0xC1030AA8, 0xC10308CE, 0xC10308C7, ++ 0xC1030B04, 0xC1030E01, 0xC10306B8 ++}; ++ + static const u32 mt7988_init_cmds[] = { + 0xC1030300, 0xC1030420, 0xC1030500, 0xC10307A6, 0xC1030CFC, + 0xC1030A8C, 0xC103098D, 0xC10308F1, 0xC1030B04, 0xC1030E01, +@@ -1765,6 +1787,19 @@ static const struct lvts_ctrl_data mt819 + } + }; + ++static const struct lvts_data mt7987_lvts_ap_data = { ++ .irq_enable = false, ++ .lvts_ctrl = mt7987_lvts_ap_data_ctrl, ++ .conn_cmd = mt7987_conn_cmds, ++ .init_cmd = mt7987_init_cmds, ++ .num_lvts_ctrl = ARRAY_SIZE(mt7987_lvts_ap_data_ctrl), ++ .num_conn_cmd = ARRAY_SIZE(mt7987_conn_cmds), ++ .num_init_cmd = ARRAY_SIZE(mt7987_init_cmds), ++ .temp_factor = LVTS_COEFF_A_MT7987, ++ .temp_offset = LVTS_COEFF_B_MT7987, ++ .gt_calib_bit_offset = 24, ++}; ++ + static const struct lvts_data mt7988_lvts_ap_data = { + .irq_enable = true, + .lvts_ctrl = mt7988_lvts_ap_data_ctrl, +@@ -1877,6 +1912,7 @@ static const struct lvts_data mt8195_lvt + }; + + static const struct of_device_id lvts_of_match[] = { ++ { .compatible = "mediatek,mt7987-lvts-ap", .data = &mt7987_lvts_ap_data }, + { .compatible = "mediatek,mt7988-lvts-ap", .data = &mt7988_lvts_ap_data }, + { .compatible = "mediatek,mt8186-lvts", .data = &mt8186_lvts_data }, + { .compatible = "mediatek,mt8188-lvts-mcu", .data = &mt8188_lvts_mcu_data }, +--- a/include/dt-bindings/thermal/mediatek,lvts-thermal.h ++++ b/include/dt-bindings/thermal/mediatek,lvts-thermal.h +@@ -7,6 +7,9 @@ + #ifndef __MEDIATEK_LVTS_DT_H + #define __MEDIATEK_LVTS_DT_H + ++#define MT7987_CPU 0 ++#define MT7987_ETH2P5G 1 ++ + #define MT7988_CPU_0 0 + #define MT7988_CPU_1 1 + #define MT7988_ETH2P5G_0 2 diff --git a/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq6000-re-ss-01.dts b/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq6000-re-ss-01.dts index c09f77e65..b53ae071b 100644 --- a/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq6000-re-ss-01.dts +++ b/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq6000-re-ss-01.dts @@ -212,6 +212,7 @@ &wifi { status = "okay"; - qcom,ath11k-calibration-variant = "JDC-AX1800-Pro"; + + qcom,ath11k-calibration-variant = "JDC-RE-SS-01"; qcom,ath11k-fw-memory-mode = <1>; }; diff --git a/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq6010-re-cs-02.dts b/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq6010-re-cs-02.dts index 436f8127e..0e7f2750b 100644 --- a/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq6010-re-cs-02.dts +++ b/target/linux/qualcommax/files/arch/arm64/boot/dts/qcom/ipq6010-re-cs-02.dts @@ -143,15 +143,17 @@ perst-gpio = <&tlmm 53 GPIO_ACTIVE_LOW>; status = "okay"; - bridge@0,0 { - reg = <0x00000000 0 0 0 0>; + pcie@0 { + reg = <0x0 0x0 0x0 0x0 0x0>; + bus-range = <0x01 0xff>; #address-cells = <3>; #size-cells = <2>; ranges; - wifi@1,0 { + wifi@0,0 { compatible = "pci17cb,1104"; reg = <0x00010000 0 0 0 0>; + qcom,ath11k-calibration-variant = "JDC-RE-CS-02"; }; }; }; @@ -288,5 +290,6 @@ &wifi { status = "okay"; - qcom,ath11k-calibration-variant = "JDC-AX6600"; + + qcom,ath11k-calibration-variant = "JDC-RE-CS-02"; }; diff --git a/target/linux/qualcommax/image/ipq60xx.mk b/target/linux/qualcommax/image/ipq60xx.mk index 1228c1900..f63640814 100644 --- a/target/linux/qualcommax/image/ipq60xx.mk +++ b/target/linux/qualcommax/image/ipq60xx.mk @@ -52,7 +52,7 @@ define Device/jdcloud_re-cs-02 BLOCKSIZE := 64k KERNEL_SIZE := 6144k DEVICE_DTS_CONFIG := config@cp03-c3 - DEVICE_PACKAGES := ipq-wifi-jdcloud_re-cs-02 kmod-ath11k-pci ath11k-firmware-qcn9074 + DEVICE_PACKAGES := ath11k-firmware-qcn9074 ipq-wifi-jdcloud_re-cs-02 kmod-ath11k-pci endef TARGET_DEVICES += jdcloud_re-cs-02 @@ -78,7 +78,7 @@ define Device/jdcloud_re-ss-01 BLOCKSIZE := 64k KERNEL_SIZE := 6144k DEVICE_DTS_CONFIG := config@cp03-c2 - DEVICE_PACKAGES := ipq-wifi-jdcloud_ax1800pro + DEVICE_PACKAGES := ipq-wifi-jdcloud_re-ss-01 endef TARGET_DEVICES += jdcloud_re-ss-01 diff --git a/target/linux/rockchip/armv8/config-6.12 b/target/linux/rockchip/armv8/config-6.12 index b2055e1a4..3b4b33bb0 100644 --- a/target/linux/rockchip/armv8/config-6.12 +++ b/target/linux/rockchip/armv8/config-6.12 @@ -404,6 +404,7 @@ CONFIG_MFD_CORE=y CONFIG_MFD_RK8XX=y CONFIG_MFD_RK8XX_I2C=y CONFIG_MFD_RK8XX_SPI=y +CONFIG_MFD_ROCKCHIP_MFPWM=y CONFIG_MFD_SYSCON=y CONFIG_MIGRATION=y CONFIG_MMC=y @@ -587,6 +588,7 @@ CONFIG_ROCKCHIP_MBOX=y CONFIG_ROCKCHIP_MFPWM=y CONFIG_ROCKCHIP_PHY=y CONFIG_ROCKCHIP_PM_DOMAINS=y +CONFIG_ROCKCHIP_PWM_CAPTURE=y CONFIG_ROCKCHIP_THERMAL=y CONFIG_ROCKCHIP_TIMER=y CONFIG_RODATA_FULL_DEFAULT_ENABLED=y diff --git a/target/linux/rockchip/patches-6.12/040-01-v6.13-phy-phy-rockchip-samsung-hdptx-Don-t-request.patch b/target/linux/rockchip/patches-6.12/040-01-v6.13-phy-phy-rockchip-samsung-hdptx-Don-t-request.patch new file mode 100644 index 000000000..d93801193 --- /dev/null +++ b/target/linux/rockchip/patches-6.12/040-01-v6.13-phy-phy-rockchip-samsung-hdptx-Don-t-request.patch @@ -0,0 +1,71 @@ +From f2dbca169790ea1e436ffdd9ef37d7c3a4401c46 Mon Sep 17 00:00:00 2001 +From: Andy Yan +Date: Fri, 20 Sep 2024 17:36:28 +0800 +Subject: [PATCH] phy: phy-rockchip-samsung-hdptx: Don't request + RST_PHY/RST_ROPLL/RST_LCPLL + +RST_PHY/RST_ROPLL/RST_LCPLL are used for debug only on rk3588, +and they are not exported on rk3576, no need to request it in +driver. + +Signed-off-by: Andy Yan +Link: https://lore.kernel.org/r/20240920093629.7410-1-andyshrk@163.com +Signed-off-by: Vinod Koul +--- + .../phy/rockchip/phy-rockchip-samsung-hdptx.c | 17 +---------------- + 1 file changed, 1 insertion(+), 16 deletions(-) + +--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c ++++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c +@@ -257,13 +257,10 @@ struct ropll_config { + }; + + enum rk_hdptx_reset { +- RST_PHY = 0, +- RST_APB, ++ RST_APB = 0, + RST_INIT, + RST_CMN, + RST_LANE, +- RST_ROPLL, +- RST_LCPLL, + RST_MAX + }; + +@@ -679,11 +676,6 @@ static void rk_hdptx_phy_disable(struct + { + u32 val; + +- /* reset phy and apb, or phy locked flag may keep 1 */ +- reset_control_assert(hdptx->rsts[RST_PHY].rstc); +- usleep_range(20, 30); +- reset_control_deassert(hdptx->rsts[RST_PHY].rstc); +- + reset_control_assert(hdptx->rsts[RST_APB].rstc); + usleep_range(20, 30); + reset_control_deassert(hdptx->rsts[RST_APB].rstc); +@@ -804,10 +796,6 @@ static int rk_hdptx_ropll_tmds_cmn_confi + + rk_hdptx_pre_power_up(hdptx); + +- reset_control_assert(hdptx->rsts[RST_ROPLL].rstc); +- usleep_range(20, 30); +- reset_control_deassert(hdptx->rsts[RST_ROPLL].rstc); +- + rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_common_cmn_init_seq); + rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_tmds_cmn_init_seq); + +@@ -1130,13 +1118,10 @@ static int rk_hdptx_phy_probe(struct pla + return dev_err_probe(dev, PTR_ERR(hdptx->regmap), + "Failed to init regmap\n"); + +- hdptx->rsts[RST_PHY].id = "phy"; + hdptx->rsts[RST_APB].id = "apb"; + hdptx->rsts[RST_INIT].id = "init"; + hdptx->rsts[RST_CMN].id = "cmn"; + hdptx->rsts[RST_LANE].id = "lane"; +- hdptx->rsts[RST_ROPLL].id = "ropll"; +- hdptx->rsts[RST_LCPLL].id = "lcpll"; + + ret = devm_reset_control_bulk_get_exclusive(dev, RST_MAX, hdptx->rsts); + if (ret) diff --git a/target/linux/rockchip/patches-6.12/040-02-v6.15-phy-phy-rockchip-samsung-hdptx-annotate-regmap.patch b/target/linux/rockchip/patches-6.12/040-02-v6.15-phy-phy-rockchip-samsung-hdptx-annotate-regmap.patch new file mode 100644 index 000000000..3af5f85f3 --- /dev/null +++ b/target/linux/rockchip/patches-6.12/040-02-v6.15-phy-phy-rockchip-samsung-hdptx-annotate-regmap.patch @@ -0,0 +1,42 @@ +From c8f7d65cac565cacf0420acf8b54c855dd7b4484 Mon Sep 17 00:00:00 2001 +From: Heiko Stuebner +Date: Fri, 6 Dec 2024 11:34:00 +0100 +Subject: [PATCH] phy: phy-rockchip-samsung-hdptx: annotate regmap + register-callback + +The variant of the driver in the vendor-tree contained those handy +comments in the regmap register callback. Having the different ranges +describe what they are looks helpful. + +Signed-off-by: Heiko Stuebner +Reviewed-by: Cristian Ciocaltea +Reviewed-by: Sebastian Reichel +Link: https://lore.kernel.org/r/20241206103401.1780416-2-heiko@sntech.de +Signed-off-by: Vinod Koul +--- + drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c ++++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c +@@ -574,13 +574,13 @@ static const struct reg_sequence rk_hdtp + static bool rk_hdptx_phy_is_rw_reg(struct device *dev, unsigned int reg) + { + switch (reg) { +- case 0x0000 ... 0x029c: +- case 0x0400 ... 0x04a4: +- case 0x0800 ... 0x08a4: +- case 0x0c00 ... 0x0cb4: +- case 0x1000 ... 0x10b4: +- case 0x1400 ... 0x14b4: +- case 0x1800 ... 0x18b4: ++ case 0x0000 ... 0x029c: /* CMN Register */ ++ case 0x0400 ... 0x04a4: /* Sideband Register */ ++ case 0x0800 ... 0x08a4: /* Lane Top Register */ ++ case 0x0c00 ... 0x0cb4: /* Lane 0 Register */ ++ case 0x1000 ... 0x10b4: /* Lane 1 Register */ ++ case 0x1400 ... 0x14b4: /* Lane 2 Register */ ++ case 0x1800 ... 0x18b4: /* Lane 3 Register */ + return true; + } + diff --git a/target/linux/rockchip/patches-6.12/040-03-v6.15-phy-phy-rockchip-samsung-hdptx-Supplement-some-register.patch b/target/linux/rockchip/patches-6.12/040-03-v6.15-phy-phy-rockchip-samsung-hdptx-Supplement-some-register.patch new file mode 100644 index 000000000..7ba10067f --- /dev/null +++ b/target/linux/rockchip/patches-6.12/040-03-v6.15-phy-phy-rockchip-samsung-hdptx-Supplement-some-register.patch @@ -0,0 +1,37 @@ +From f706024107204cb0b640bac35ea47e7b91b8c71f Mon Sep 17 00:00:00 2001 +From: Damon Ding +Date: Wed, 5 Feb 2025 18:51:55 +0800 +Subject: [PATCH] phy: phy-rockchip-samsung-hdptx: Supplement some register + names with their full version + +Complete the register names of CMN_REG(0081) and CMN_REG(0087) to their +full version, and it can help to better match the datasheet. + +Signed-off-by: Damon Ding +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20250205105157.580060-3-damon.ding@rock-chips.com +Signed-off-by: Vinod Koul +--- + drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c ++++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c +@@ -82,14 +82,14 @@ + #define ROPLL_SSC_EN BIT(0) + /* CMN_REG(0081) */ + #define OVRD_PLL_CD_CLK_EN BIT(8) +-#define PLL_CD_HSCLK_EAST_EN BIT(0) ++#define ANA_PLL_CD_HSCLK_EAST_EN BIT(0) + /* CMN_REG(0086) */ + #define PLL_PCG_POSTDIV_SEL_MASK GENMASK(7, 4) + #define PLL_PCG_CLK_SEL_MASK GENMASK(3, 1) + #define PLL_PCG_CLK_EN BIT(0) + /* CMN_REG(0087) */ +-#define PLL_FRL_MODE_EN BIT(3) +-#define PLL_TX_HS_CLK_EN BIT(2) ++#define ANA_PLL_FRL_MODE_EN BIT(3) ++#define ANA_PLL_TX_HS_CLK_EN BIT(2) + /* CMN_REG(0089) */ + #define LCPLL_ALONE_MODE BIT(1) + /* CMN_REG(0097) */ diff --git a/target/linux/rockchip/patches-6.12/040-04-v6.15-phy-phy-rockchip-samsung-hdptx-Add-the-_MASK-suffix-to.patch b/target/linux/rockchip/patches-6.12/040-04-v6.15-phy-phy-rockchip-samsung-hdptx-Add-the-_MASK-suffix-to.patch new file mode 100644 index 000000000..9cc71f824 --- /dev/null +++ b/target/linux/rockchip/patches-6.12/040-04-v6.15-phy-phy-rockchip-samsung-hdptx-Add-the-_MASK-suffix-to.patch @@ -0,0 +1,170 @@ +From 2dc8224e3758c5d6387786ea1d74d2d510149b1a Mon Sep 17 00:00:00 2001 +From: Damon Ding +Date: Wed, 5 Feb 2025 18:51:56 +0800 +Subject: [PATCH] phy: phy-rockchip-samsung-hdptx: Add the '_MASK' suffix to + all registers + +Adding the '_MASK' suffix to all registers in order to ensures consistency +in the naming convention for register macros throughout the file. + +Signed-off-by: Damon Ding +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20250205105157.580060-4-damon.ding@rock-chips.com +Signed-off-by: Vinod Koul +--- + .../phy/rockchip/phy-rockchip-samsung-hdptx.c | 88 +++++++++---------- + 1 file changed, 44 insertions(+), 44 deletions(-) + +--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c ++++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c +@@ -50,60 +50,60 @@ + #define LCPLL_PI_EN_MASK BIT(5) + #define LCPLL_100M_CLK_EN_MASK BIT(0) + /* CMN_REG(0025) */ +-#define LCPLL_PMS_IQDIV_RSTN BIT(4) ++#define LCPLL_PMS_IQDIV_RSTN_MASK BIT(4) + /* CMN_REG(0028) */ +-#define LCPLL_SDC_FRAC_EN BIT(2) +-#define LCPLL_SDC_FRAC_RSTN BIT(0) ++#define LCPLL_SDC_FRAC_EN_MASK BIT(2) ++#define LCPLL_SDC_FRAC_RSTN_MASK BIT(0) + /* CMN_REG(002d) */ + #define LCPLL_SDC_N_MASK GENMASK(3, 1) + /* CMN_REG(002e) */ + #define LCPLL_SDC_NUMBERATOR_MASK GENMASK(5, 0) + /* CMN_REG(002f) */ + #define LCPLL_SDC_DENOMINATOR_MASK GENMASK(7, 2) +-#define LCPLL_SDC_NDIV_RSTN BIT(0) ++#define LCPLL_SDC_NDIV_RSTN_MASK BIT(0) + /* CMN_REG(003d) */ +-#define ROPLL_LCVCO_EN BIT(4) ++#define ROPLL_LCVCO_EN_MASK BIT(4) + /* CMN_REG(004e) */ +-#define ROPLL_PI_EN BIT(5) ++#define ROPLL_PI_EN_MASK BIT(5) + /* CMN_REG(005c) */ +-#define ROPLL_PMS_IQDIV_RSTN BIT(5) ++#define ROPLL_PMS_IQDIV_RSTN_MASK BIT(5) + /* CMN_REG(005e) */ + #define ROPLL_SDM_EN_MASK BIT(6) +-#define ROPLL_SDM_FRAC_EN_RBR BIT(3) +-#define ROPLL_SDM_FRAC_EN_HBR BIT(2) +-#define ROPLL_SDM_FRAC_EN_HBR2 BIT(1) +-#define ROPLL_SDM_FRAC_EN_HBR3 BIT(0) ++#define ROPLL_SDC_FRAC_EN_RBR_MASK BIT(3) ++#define ROPLL_SDC_FRAC_EN_HBR_MASK BIT(2) ++#define ROPLL_SDC_FRAC_EN_HBR2_MASK BIT(1) ++#define ROPLL_SDM_FRAC_EN_HBR3_MASK BIT(0) + /* CMN_REG(0064) */ + #define ROPLL_SDM_NUM_SIGN_RBR_MASK BIT(3) + /* CMN_REG(0069) */ + #define ROPLL_SDC_N_RBR_MASK GENMASK(2, 0) + /* CMN_REG(0074) */ +-#define ROPLL_SDC_NDIV_RSTN BIT(2) +-#define ROPLL_SSC_EN BIT(0) ++#define ROPLL_SDC_NDIV_RSTN_MASK BIT(2) ++#define ROPLL_SSC_EN_MASK BIT(0) + /* CMN_REG(0081) */ +-#define OVRD_PLL_CD_CLK_EN BIT(8) +-#define ANA_PLL_CD_HSCLK_EAST_EN BIT(0) ++#define OVRD_PLL_CD_CLK_EN_MASK BIT(8) ++#define ANA_PLL_CD_HSCLK_EAST_EN_MASK BIT(0) + /* CMN_REG(0086) */ + #define PLL_PCG_POSTDIV_SEL_MASK GENMASK(7, 4) + #define PLL_PCG_CLK_SEL_MASK GENMASK(3, 1) +-#define PLL_PCG_CLK_EN BIT(0) ++#define PLL_PCG_CLK_EN_MASK BIT(0) + /* CMN_REG(0087) */ +-#define ANA_PLL_FRL_MODE_EN BIT(3) +-#define ANA_PLL_TX_HS_CLK_EN BIT(2) ++#define ANA_PLL_FRL_MODE_EN_MASK BIT(3) ++#define ANA_PLL_TX_HS_CLK_EN_MASK BIT(2) + /* CMN_REG(0089) */ +-#define LCPLL_ALONE_MODE BIT(1) ++#define LCPLL_ALONE_MODE_MASK BIT(1) + /* CMN_REG(0097) */ +-#define DIG_CLK_SEL BIT(1) ++#define DIG_CLK_SEL_MASK BIT(1) + #define LCPLL_REF BIT(1) + #define ROPLL_REF 0 + /* CMN_REG(0099) */ +-#define CMN_ROPLL_ALONE_MODE BIT(2) ++#define CMN_ROPLL_ALONE_MODE_MASK BIT(2) + #define ROPLL_ALONE_MODE BIT(2) + /* CMN_REG(009a) */ +-#define HS_SPEED_SEL BIT(0) ++#define HS_SPEED_SEL_MASK BIT(0) + #define DIV_10_CLOCK BIT(0) + /* CMN_REG(009b) */ +-#define IS_SPEED_SEL BIT(4) ++#define LS_SPEED_SEL_MASK BIT(4) + #define LINK_SYMBOL_CLOCK BIT(4) + #define LINK_SYMBOL_CLOCK1_2 0 + +@@ -161,36 +161,36 @@ + #define SB_READY_MASK BIT(4) + + /* LNTOP_REG(0200) */ +-#define PROTOCOL_SEL BIT(2) ++#define PROTOCOL_SEL_MASK BIT(2) + #define HDMI_MODE BIT(2) + #define HDMI_TMDS_FRL_SEL BIT(1) + /* LNTOP_REG(0206) */ +-#define DATA_BUS_SEL BIT(0) ++#define DATA_BUS_WIDTH_SEL_MASK BIT(0) + #define DATA_BUS_36_40 BIT(0) + /* LNTOP_REG(0207) */ +-#define LANE_EN 0xf ++#define LANE_EN_MASK 0xf + #define ALL_LANE_EN 0xf + + /* LANE_REG(0312) */ +-#define LN0_TX_SER_RATE_SEL_RBR BIT(5) +-#define LN0_TX_SER_RATE_SEL_HBR BIT(4) +-#define LN0_TX_SER_RATE_SEL_HBR2 BIT(3) +-#define LN0_TX_SER_RATE_SEL_HBR3 BIT(2) ++#define LN0_TX_SER_RATE_SEL_RBR_MASK BIT(5) ++#define LN0_TX_SER_RATE_SEL_HBR_MASK BIT(4) ++#define LN0_TX_SER_RATE_SEL_HBR2_MASK BIT(3) ++#define LN0_TX_SER_RATE_SEL_HBR3_MASK BIT(2) + /* LANE_REG(0412) */ +-#define LN1_TX_SER_RATE_SEL_RBR BIT(5) +-#define LN1_TX_SER_RATE_SEL_HBR BIT(4) +-#define LN1_TX_SER_RATE_SEL_HBR2 BIT(3) +-#define LN1_TX_SER_RATE_SEL_HBR3 BIT(2) ++#define LN1_TX_SER_RATE_SEL_RBR_MASK BIT(5) ++#define LN1_TX_SER_RATE_SEL_HBR_MASK BIT(4) ++#define LN1_TX_SER_RATE_SEL_HBR2_MASK BIT(3) ++#define LN1_TX_SER_RATE_SEL_HBR3_MASK BIT(2) + /* LANE_REG(0512) */ +-#define LN2_TX_SER_RATE_SEL_RBR BIT(5) +-#define LN2_TX_SER_RATE_SEL_HBR BIT(4) +-#define LN2_TX_SER_RATE_SEL_HBR2 BIT(3) +-#define LN2_TX_SER_RATE_SEL_HBR3 BIT(2) ++#define LN2_TX_SER_RATE_SEL_RBR_MASK BIT(5) ++#define LN2_TX_SER_RATE_SEL_HBR_MASK BIT(4) ++#define LN2_TX_SER_RATE_SEL_HBR2_MASK BIT(3) ++#define LN2_TX_SER_RATE_SEL_HBR3_MASK BIT(2) + /* LANE_REG(0612) */ +-#define LN3_TX_SER_RATE_SEL_RBR BIT(5) +-#define LN3_TX_SER_RATE_SEL_HBR BIT(4) +-#define LN3_TX_SER_RATE_SEL_HBR2 BIT(3) +-#define LN3_TX_SER_RATE_SEL_HBR3 BIT(2) ++#define LN3_TX_SER_RATE_SEL_RBR_MASK BIT(5) ++#define LN3_TX_SER_RATE_SEL_HBR_MASK BIT(4) ++#define LN3_TX_SER_RATE_SEL_HBR2_MASK BIT(3) ++#define LN3_TX_SER_RATE_SEL_HBR3_MASK BIT(2) + + #define HDMI14_MAX_RATE 340000000 + #define HDMI20_MAX_RATE 600000000 +@@ -825,8 +825,8 @@ static int rk_hdptx_ropll_tmds_cmn_confi + regmap_update_bits(hdptx->regmap, CMN_REG(0086), PLL_PCG_POSTDIV_SEL_MASK, + FIELD_PREP(PLL_PCG_POSTDIV_SEL_MASK, cfg->pms_sdiv)); + +- regmap_update_bits(hdptx->regmap, CMN_REG(0086), PLL_PCG_CLK_EN, +- PLL_PCG_CLK_EN); ++ regmap_update_bits(hdptx->regmap, CMN_REG(0086), PLL_PCG_CLK_EN_MASK, ++ FIELD_PREP(PLL_PCG_CLK_EN_MASK, 0x1)); + + ret = rk_hdptx_post_enable_pll(hdptx); + if (!ret) diff --git a/target/linux/rockchip/patches-6.12/040-05-v6.15-phy-phy-rockchip-samsung-hdptx-Add-eDP-mode-support-for.patch b/target/linux/rockchip/patches-6.12/040-05-v6.15-phy-phy-rockchip-samsung-hdptx-Add-eDP-mode-support-for.patch new file mode 100644 index 000000000..26d2fc266 --- /dev/null +++ b/target/linux/rockchip/patches-6.12/040-05-v6.15-phy-phy-rockchip-samsung-hdptx-Add-eDP-mode-support-for.patch @@ -0,0 +1,1114 @@ +From 8f831f272b4c89aa13b45bd010c2c18ad97a3f1b Mon Sep 17 00:00:00 2001 +From: Damon Ding +Date: Wed, 5 Feb 2025 18:51:57 +0800 +Subject: [PATCH] phy: phy-rockchip-samsung-hdptx: Add eDP mode support for + RK3588 + +The PHY is based on a Samsung IP block that supports HDMI 2.1, and eDP +1.4b. RK3588 integrates the Analogix eDP 1.3 TX controller IP and the +HDMI/eDP TX Combo PHY to support eDP display. + +Add basic support for RBR/HBR/HBR2 link rates, and the voltage swing and +pre-emphasis configurations of each link rate are set according to the +eDP 1.3 requirements. + +Signed-off-by: Damon Ding +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20250205105157.580060-5-damon.ding@rock-chips.com +Signed-off-by: Vinod Koul +--- + .../phy/rockchip/phy-rockchip-samsung-hdptx.c | 879 +++++++++++++++++- + 1 file changed, 869 insertions(+), 10 deletions(-) + +--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c ++++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c +@@ -25,6 +25,7 @@ + #define HDPTX_I_PLL_EN BIT(7) + #define HDPTX_I_BIAS_EN BIT(6) + #define HDPTX_I_BGR_EN BIT(5) ++#define HDPTX_MODE_SEL BIT(0) + #define GRF_HDPTX_STATUS 0x80 + #define HDPTX_O_PLL_LOCK_DONE BIT(3) + #define HDPTX_O_PHY_CLK_RDY BIT(2) +@@ -44,6 +45,7 @@ + #define LANE_REG(n) HDTPX_REG(n, 0300, 062d) + + /* CMN_REG(0008) */ ++#define OVRD_LCPLL_EN_MASK BIT(7) + #define LCPLL_EN_MASK BIT(6) + #define LCPLL_LCVCO_MODE_EN_MASK BIT(4) + /* CMN_REG(001e) */ +@@ -61,28 +63,88 @@ + /* CMN_REG(002f) */ + #define LCPLL_SDC_DENOMINATOR_MASK GENMASK(7, 2) + #define LCPLL_SDC_NDIV_RSTN_MASK BIT(0) ++/* CMN_REG(003c) */ ++#define ANA_LCPLL_RESERVED7_MASK BIT(7) + /* CMN_REG(003d) */ ++#define OVRD_ROPLL_EN_MASK BIT(7) ++#define ROPLL_EN_MASK BIT(6) + #define ROPLL_LCVCO_EN_MASK BIT(4) ++/* CMN_REG(0046) */ ++#define ROPLL_ANA_CPP_CTRL_COARSE_MASK GENMASK(7, 4) ++#define ROPLL_ANA_CPP_CTRL_FINE_MASK GENMASK(3, 0) ++/* CMN_REG(0047) */ ++#define ROPLL_ANA_LPF_C_SEL_COARSE_MASK GENMASK(5, 3) ++#define ROPLL_ANA_LPF_C_SEL_FINE_MASK GENMASK(2, 0) + /* CMN_REG(004e) */ + #define ROPLL_PI_EN_MASK BIT(5) ++/* CMN_REG(0051) */ ++#define ROPLL_PMS_MDIV_MASK GENMASK(7, 0) ++/* CMN_REG(0055) */ ++#define ROPLL_PMS_MDIV_AFC_MASK GENMASK(7, 0) ++/* CMN_REG(0059) */ ++#define ANA_ROPLL_PMS_PDIV_MASK GENMASK(7, 4) ++#define ANA_ROPLL_PMS_REFDIV_MASK GENMASK(3, 0) ++/* CMN_REG(005a) */ ++#define ROPLL_PMS_SDIV_RBR_MASK GENMASK(7, 4) ++#define ROPLL_PMS_SDIV_HBR_MASK GENMASK(3, 0) ++/* CMN_REG(005b) */ ++#define ROPLL_PMS_SDIV_HBR2_MASK GENMASK(7, 4) + /* CMN_REG(005c) */ + #define ROPLL_PMS_IQDIV_RSTN_MASK BIT(5) + /* CMN_REG(005e) */ + #define ROPLL_SDM_EN_MASK BIT(6) ++#define OVRD_ROPLL_SDM_RSTN_MASK BIT(5) ++#define ROPLL_SDM_RSTN_MASK BIT(4) + #define ROPLL_SDC_FRAC_EN_RBR_MASK BIT(3) + #define ROPLL_SDC_FRAC_EN_HBR_MASK BIT(2) + #define ROPLL_SDC_FRAC_EN_HBR2_MASK BIT(1) + #define ROPLL_SDM_FRAC_EN_HBR3_MASK BIT(0) ++/* CMN_REG(005f) */ ++#define OVRD_ROPLL_SDC_RSTN_MASK BIT(5) ++#define ROPLL_SDC_RSTN_MASK BIT(4) ++/* CMN_REG(0060) */ ++#define ROPLL_SDM_DENOMINATOR_MASK GENMASK(7, 0) + /* CMN_REG(0064) */ + #define ROPLL_SDM_NUM_SIGN_RBR_MASK BIT(3) ++#define ROPLL_SDM_NUM_SIGN_HBR_MASK BIT(2) ++#define ROPLL_SDM_NUM_SIGN_HBR2_MASK BIT(1) ++/* CMN_REG(0065) */ ++#define ROPLL_SDM_NUM_MASK GENMASK(7, 0) + /* CMN_REG(0069) */ + #define ROPLL_SDC_N_RBR_MASK GENMASK(2, 0) ++/* CMN_REG(006a) */ ++#define ROPLL_SDC_N_HBR_MASK GENMASK(5, 3) ++#define ROPLL_SDC_N_HBR2_MASK GENMASK(2, 0) ++/* CMN_REG(006b) */ ++#define ROPLL_SDC_N_HBR3_MASK GENMASK(3, 1) ++/* CMN_REG(006c) */ ++#define ROPLL_SDC_NUM_MASK GENMASK(5, 0) ++/* cmn_reg0070 */ ++#define ROPLL_SDC_DENO_MASK GENMASK(5, 0) + /* CMN_REG(0074) */ ++#define OVRD_ROPLL_SDC_NDIV_RSTN_MASK BIT(3) + #define ROPLL_SDC_NDIV_RSTN_MASK BIT(2) ++#define OVRD_ROPLL_SSC_EN_MASK BIT(1) + #define ROPLL_SSC_EN_MASK BIT(0) ++/* CMN_REG(0075) */ ++#define ANA_ROPLL_SSC_FM_DEVIATION_MASK GENMASK(5, 0) ++/* CMN_REG(0076) */ ++#define ANA_ROPLL_SSC_FM_FREQ_MASK GENMASK(6, 2) ++/* CMN_REG(0077) */ ++#define ANA_ROPLL_SSC_CLK_DIV_SEL_MASK GENMASK(6, 3) + /* CMN_REG(0081) */ + #define OVRD_PLL_CD_CLK_EN_MASK BIT(8) ++#define ANA_PLL_CD_TX_SER_RATE_SEL_MASK BIT(3) ++#define ANA_PLL_CD_HSCLK_WEST_EN_MASK BIT(1) + #define ANA_PLL_CD_HSCLK_EAST_EN_MASK BIT(0) ++/* CMN_REG(0082) */ ++#define ANA_PLL_CD_VREG_GAIN_CTRL_MASK GENMASK(3, 0) ++/* CMN_REG(0083) */ ++#define ANA_PLL_CD_VREG_ICTRL_MASK GENMASK(6, 5) ++/* CMN_REG(0084) */ ++#define PLL_LCRO_CLK_SEL_MASK BIT(5) ++/* CMN_REG(0085) */ ++#define ANA_PLL_SYNC_LOSS_DET_MODE_MASK GENMASK(1, 0) + /* CMN_REG(0086) */ + #define PLL_PCG_POSTDIV_SEL_MASK GENMASK(7, 4) + #define PLL_PCG_CLK_SEL_MASK GENMASK(3, 1) +@@ -92,11 +154,14 @@ + #define ANA_PLL_TX_HS_CLK_EN_MASK BIT(2) + /* CMN_REG(0089) */ + #define LCPLL_ALONE_MODE_MASK BIT(1) ++/* CMN_REG(0095) */ ++#define DP_TX_LINK_BW_MASK GENMASK(1, 0) + /* CMN_REG(0097) */ + #define DIG_CLK_SEL_MASK BIT(1) + #define LCPLL_REF BIT(1) + #define ROPLL_REF 0 + /* CMN_REG(0099) */ ++#define SSC_EN_MASK GENMASK(7, 6) + #define CMN_ROPLL_ALONE_MODE_MASK BIT(2) + #define ROPLL_ALONE_MODE BIT(2) + /* CMN_REG(009a) */ +@@ -118,6 +183,8 @@ + /* SB_REG(0104) */ + #define OVRD_SB_EN_MASK BIT(5) + #define SB_EN_MASK BIT(4) ++#define OVRD_SB_AUX_EN_MASK BIT(1) ++#define SB_AUX_EN_MASK BIT(0) + /* SB_REG(0105) */ + #define OVRD_SB_EARC_CMDC_EN_MASK BIT(6) + #define SB_EARC_CMDC_EN_MASK BIT(5) +@@ -126,6 +193,8 @@ + #define ANA_SB_TX_LLVL_PROG_MASK GENMASK(6, 4) + /* SB_REG(0109) */ + #define ANA_SB_DMRX_AFC_DIV_RATIO_MASK GENMASK(2, 0) ++/* SB_REG(010d) */ ++#define ANA_SB_DMRX_LPBK_DATA_MASK BIT(4) + /* SB_REG(010f) */ + #define OVRD_SB_VREG_EN_MASK BIT(7) + #define SB_VREG_EN_MASK BIT(6) +@@ -133,6 +202,7 @@ + #define SB_VREG_LPF_BYPASS_MASK BIT(4) + #define ANA_SB_VREG_GAIN_CTRL_MASK GENMASK(3, 0) + /* SB_REG(0110) */ ++#define ANA_SB_VREG_OUT_SEL_MASK BIT(1) + #define ANA_SB_VREG_REF_SEL_MASK BIT(0) + /* SB_REG(0113) */ + #define SB_RX_RCAL_OPT_CODE_MASK GENMASK(5, 4) +@@ -147,13 +217,24 @@ + #define AFC_RSTN_DELAY_TIME_MASK GENMASK(6, 4) + /* SB_REG(0117) */ + #define FAST_PULSE_TIME_MASK GENMASK(3, 0) ++/* SB_REG(0118) */ ++#define SB_TG_EARC_DMRX_RECVRD_CLK_CNT_MASK GENMASK(7, 0) ++/* SB_REG(011a) */ ++#define SB_TG_CNT_RUN_NO_7_0_MASK GENMASK(7, 0) + /* SB_REG(011b) */ + #define SB_EARC_SIG_DET_BYPASS_MASK BIT(4) + #define SB_AFC_TOL_MASK GENMASK(3, 0) ++/* SB_REG(011c) */ ++#define SB_AFC_STB_NUM_MASK GENMASK(3, 0) ++/* SB_REG(011d) */ ++#define SB_TG_OSC_CNT_MIN_MASK GENMASK(7, 0) ++/* SB_REG(011e) */ ++#define SB_TG_OSC_CNT_MAX_MASK GENMASK(7, 0) + /* SB_REG(011f) */ + #define SB_PWM_AFC_CTRL_MASK GENMASK(7, 2) + #define SB_RCAL_RSTN_MASK BIT(1) + /* SB_REG(0120) */ ++#define SB_AUX_EN_IN_MASK BIT(7) + #define SB_EARC_EN_MASK BIT(1) + #define SB_EARC_AFC_EN_MASK BIT(2) + /* SB_REG(0123) */ +@@ -165,27 +246,74 @@ + #define HDMI_MODE BIT(2) + #define HDMI_TMDS_FRL_SEL BIT(1) + /* LNTOP_REG(0206) */ ++#define DATA_BUS_WIDTH_MASK GENMASK(2, 1) + #define DATA_BUS_WIDTH_SEL_MASK BIT(0) + #define DATA_BUS_36_40 BIT(0) + /* LNTOP_REG(0207) */ + #define LANE_EN_MASK 0xf + #define ALL_LANE_EN 0xf + ++/* LANE_REG(0301) */ ++#define OVRD_LN_TX_DRV_EI_EN_MASK BIT(7) ++#define LN_TX_DRV_EI_EN_MASK BIT(6) ++/* LANE_REG(0303) */ ++#define OVRD_LN_TX_DRV_LVL_CTRL_MASK BIT(5) ++#define LN_TX_DRV_LVL_CTRL_MASK GENMASK(4, 0) ++/* LANE_REG(0304) */ ++#define OVRD_LN_TX_DRV_POST_LVL_CTRL_MASK BIT(4) ++#define LN_TX_DRV_POST_LVL_CTRL_MASK GENMASK(3, 0) ++/* LANE_REG(0305) */ ++#define OVRD_LN_TX_DRV_PRE_LVL_CTRL_MASK BIT(6) ++#define LN_TX_DRV_PRE_LVL_CTRL_MASK GENMASK(5, 2) ++/* LANE_REG(0306) */ ++#define LN_ANA_TX_DRV_IDRV_IDN_CTRL_MASK GENMASK(7, 5) ++#define LN_ANA_TX_DRV_IDRV_IUP_CTRL_MASK GENMASK(4, 2) ++#define LN_ANA_TX_DRV_ACCDRV_EN_MASK BIT(0) ++/* LANE_REG(0307) */ ++#define LN_ANA_TX_DRV_ACCDRV_POL_SEL_MASK BIT(6) ++#define LN_ANA_TX_DRV_ACCDRV_CTRL_MASK GENMASK(5, 3) ++/* LANE_REG(030a) */ ++#define LN_ANA_TX_JEQ_EN_MASK BIT(4) ++#define LN_TX_JEQ_EVEN_CTRL_RBR_MASK GENMASK(3, 0) ++/* LANE_REG(030b) */ ++#define LN_TX_JEQ_EVEN_CTRL_HBR_MASK GENMASK(7, 4) ++#define LN_TX_JEQ_EVEN_CTRL_HBR2_MASK GENMASK(3, 0) ++/* LANE_REG(030c) */ ++#define LN_TX_JEQ_ODD_CTRL_RBR_MASK GENMASK(3, 0) ++/* LANE_REG(030d) */ ++#define LN_TX_JEQ_ODD_CTRL_HBR_MASK GENMASK(7, 4) ++#define LN_TX_JEQ_ODD_CTRL_HBR2_MASK GENMASK(3, 0) ++/* LANE_REG(0310) */ ++#define LN_ANA_TX_SYNC_LOSS_DET_MODE_MASK GENMASK(1, 0) ++/* LANE_REG(0311) */ ++#define LN_TX_SER_40BIT_EN_RBR_MASK BIT(3) ++#define LN_TX_SER_40BIT_EN_HBR_MASK BIT(2) ++#define LN_TX_SER_40BIT_EN_HBR2_MASK BIT(1) + /* LANE_REG(0312) */ + #define LN0_TX_SER_RATE_SEL_RBR_MASK BIT(5) + #define LN0_TX_SER_RATE_SEL_HBR_MASK BIT(4) + #define LN0_TX_SER_RATE_SEL_HBR2_MASK BIT(3) + #define LN0_TX_SER_RATE_SEL_HBR3_MASK BIT(2) ++/* LANE_REG(0316) */ ++#define LN_ANA_TX_SER_VREG_GAIN_CTRL_MASK GENMASK(3, 0) ++/* LANE_REG(031B) */ ++#define LN_ANA_TX_RESERVED_MASK GENMASK(7, 0) ++/* LANE_REG(031e) */ ++#define LN_POLARITY_INV_MASK BIT(2) ++#define LN_LANE_MODE_MASK BIT(1) ++ + /* LANE_REG(0412) */ + #define LN1_TX_SER_RATE_SEL_RBR_MASK BIT(5) + #define LN1_TX_SER_RATE_SEL_HBR_MASK BIT(4) + #define LN1_TX_SER_RATE_SEL_HBR2_MASK BIT(3) + #define LN1_TX_SER_RATE_SEL_HBR3_MASK BIT(2) ++ + /* LANE_REG(0512) */ + #define LN2_TX_SER_RATE_SEL_RBR_MASK BIT(5) + #define LN2_TX_SER_RATE_SEL_HBR_MASK BIT(4) + #define LN2_TX_SER_RATE_SEL_HBR2_MASK BIT(3) + #define LN2_TX_SER_RATE_SEL_HBR3_MASK BIT(2) ++ + /* LANE_REG(0612) */ + #define LN3_TX_SER_RATE_SEL_RBR_MASK BIT(5) + #define LN3_TX_SER_RATE_SEL_HBR_MASK BIT(4) +@@ -195,6 +323,12 @@ + #define HDMI14_MAX_RATE 340000000 + #define HDMI20_MAX_RATE 600000000 + ++enum dp_link_rate { ++ DP_BW_RBR, ++ DP_BW_HBR, ++ DP_BW_HBR2, ++}; ++ + struct lcpll_config { + u32 bit_rate; + u8 lcvco_mode_en; +@@ -256,6 +390,19 @@ struct ropll_config { + u8 cd_tx_ser_rate_sel; + }; + ++struct tx_drv_ctrl { ++ u8 tx_drv_lvl_ctrl; ++ u8 tx_drv_post_lvl_ctrl; ++ u8 ana_tx_drv_idrv_idn_ctrl; ++ u8 ana_tx_drv_idrv_iup_ctrl; ++ u8 ana_tx_drv_accdrv_en; ++ u8 ana_tx_drv_accdrv_ctrl; ++ u8 tx_drv_pre_lvl_ctrl; ++ u8 ana_tx_jeq_en; ++ u8 tx_jeq_even_ctrl; ++ u8 tx_jeq_odd_ctrl; ++}; ++ + enum rk_hdptx_reset { + RST_APB = 0, + RST_INIT, +@@ -291,6 +438,10 @@ struct rk_hdptx_phy { + unsigned long rate; + + atomic_t usage_count; ++ ++ /* used for dp mode */ ++ unsigned int link_rate; ++ unsigned int lanes; + }; + + static const struct ropll_config ropll_tmds_cfg[] = { +@@ -571,6 +722,90 @@ static const struct reg_sequence rk_hdtp + REG_SEQ0(LANE_REG(0606), 0x1c), + }; + ++static struct tx_drv_ctrl tx_drv_ctrl_rbr[4][4] = { ++ /* voltage swing 0, pre-emphasis 0->3 */ ++ { ++ { 0x2, 0x0, 0x4, 0x6, 0x0, 0x4, 0x1, 0x1, 0x7, 0x7 }, ++ { 0x4, 0x3, 0x4, 0x6, 0x0, 0x4, 0x0, 0x1, 0x7, 0x7 }, ++ { 0x7, 0x6, 0x4, 0x6, 0x0, 0x4, 0x0, 0x1, 0x7, 0x7 }, ++ { 0xd, 0xc, 0x7, 0x7, 0x1, 0x7, 0x0, 0x1, 0x7, 0x7 }, ++ }, ++ ++ /* voltage swing 1, pre-emphasis 0->2 */ ++ { ++ { 0x4, 0x0, 0x4, 0x6, 0x0, 0x4, 0x1, 0x1, 0x7, 0x7 }, ++ { 0x9, 0x5, 0x4, 0x6, 0x0, 0x4, 0x0, 0x1, 0x7, 0x7 }, ++ { 0xc, 0x8, 0x7, 0x7, 0x1, 0x7, 0x0, 0x1, 0x7, 0x7 }, ++ }, ++ ++ /* voltage swing 2, pre-emphasis 0->1 */ ++ { ++ { 0x8, 0x0, 0x4, 0x6, 0x0, 0x4, 0x1, 0x1, 0x7, 0x7 }, ++ { 0xc, 0x5, 0x7, 0x7, 0x1, 0x7, 0x0, 0x1, 0x7, 0x7 }, ++ }, ++ ++ /* voltage swing 3, pre-emphasis 0 */ ++ { ++ { 0xb, 0x0, 0x7, 0x7, 0x1, 0x4, 0x1, 0x1, 0x7, 0x7 }, ++ } ++}; ++ ++static struct tx_drv_ctrl tx_drv_ctrl_hbr[4][4] = { ++ /* voltage swing 0, pre-emphasis 0->3 */ ++ { ++ { 0x2, 0x0, 0x4, 0x6, 0x0, 0x4, 0x1, 0x1, 0x7, 0x7 }, ++ { 0x5, 0x4, 0x4, 0x6, 0x0, 0x4, 0x0, 0x1, 0x7, 0x7 }, ++ { 0x9, 0x8, 0x4, 0x6, 0x0, 0x4, 0x0, 0x1, 0x7, 0x7 }, ++ { 0xd, 0xc, 0x7, 0x7, 0x1, 0x7, 0x0, 0x1, 0x7, 0x7 }, ++ }, ++ ++ /* voltage swing 1, pre-emphasis 0->2 */ ++ { ++ { 0x6, 0x1, 0x4, 0x6, 0x0, 0x4, 0x1, 0x1, 0x7, 0x7 }, ++ { 0xa, 0x6, 0x4, 0x6, 0x0, 0x4, 0x0, 0x1, 0x7, 0x7 }, ++ { 0xc, 0x8, 0x7, 0x7, 0x1, 0x7, 0x0, 0x1, 0x7, 0x7 }, ++ }, ++ ++ /* voltage swing 2, pre-emphasis 0->1 */ ++ { ++ { 0x9, 0x1, 0x4, 0x6, 0x0, 0x4, 0x1, 0x1, 0x7, 0x7 }, ++ { 0xd, 0x6, 0x7, 0x7, 0x1, 0x7, 0x0, 0x1, 0x7, 0x7 }, ++ }, ++ ++ /* voltage swing 3, pre-emphasis 0 */ ++ { ++ { 0xc, 0x1, 0x7, 0x7, 0x1, 0x4, 0x1, 0x1, 0x7, 0x7 }, ++ } ++}; ++ ++static struct tx_drv_ctrl tx_drv_ctrl_hbr2[4][4] = { ++ /* voltage swing 0, pre-emphasis 0->3 */ ++ { ++ { 0x2, 0x1, 0x4, 0x6, 0x0, 0x4, 0x0, 0x1, 0x7, 0x7 }, ++ { 0x5, 0x4, 0x4, 0x6, 0x0, 0x4, 0x0, 0x1, 0x7, 0x7 }, ++ { 0x9, 0x8, 0x4, 0x6, 0x1, 0x4, 0x0, 0x1, 0x7, 0x7 }, ++ { 0xd, 0xc, 0x7, 0x7, 0x1, 0x7, 0x0, 0x1, 0x7, 0x7 }, ++ }, ++ ++ /* voltage swing 1, pre-emphasis 0->2 */ ++ { ++ { 0x6, 0x1, 0x4, 0x6, 0x0, 0x4, 0x1, 0x1, 0x7, 0x7 }, ++ { 0xb, 0x7, 0x4, 0x6, 0x0, 0x4, 0x0, 0x1, 0x7, 0x7 }, ++ { 0xd, 0x9, 0x7, 0x7, 0x1, 0x7, 0x0, 0x1, 0x7, 0x7 }, ++ }, ++ ++ /* voltage swing 2, pre-emphasis 0->1 */ ++ { ++ { 0x8, 0x1, 0x4, 0x6, 0x0, 0x4, 0x1, 0x1, 0x7, 0x7 }, ++ { 0xc, 0x6, 0x7, 0x7, 0x1, 0x7, 0x0, 0x1, 0x7, 0x7 }, ++ }, ++ ++ /* voltage swing 3, pre-emphasis 0 */ ++ { ++ { 0xb, 0x0, 0x7, 0x7, 0x1, 0x4, 0x1, 0x1, 0x7, 0x7 }, ++ } ++}; ++ + static bool rk_hdptx_phy_is_rw_reg(struct device *dev, unsigned int reg) + { + switch (reg) { +@@ -859,9 +1094,45 @@ static int rk_hdptx_ropll_tmds_mode_conf + return rk_hdptx_post_enable_lane(hdptx); + } + ++static void rk_hdptx_dp_reset(struct rk_hdptx_phy *hdptx) ++{ ++ reset_control_assert(hdptx->rsts[RST_LANE].rstc); ++ reset_control_assert(hdptx->rsts[RST_CMN].rstc); ++ reset_control_assert(hdptx->rsts[RST_INIT].rstc); ++ ++ reset_control_assert(hdptx->rsts[RST_APB].rstc); ++ udelay(10); ++ reset_control_deassert(hdptx->rsts[RST_APB].rstc); ++ ++ regmap_update_bits(hdptx->regmap, LANE_REG(0301), ++ OVRD_LN_TX_DRV_EI_EN_MASK | LN_TX_DRV_EI_EN_MASK, ++ FIELD_PREP(OVRD_LN_TX_DRV_EI_EN_MASK, 1) | ++ FIELD_PREP(LN_TX_DRV_EI_EN_MASK, 0)); ++ regmap_update_bits(hdptx->regmap, LANE_REG(0401), ++ OVRD_LN_TX_DRV_EI_EN_MASK | LN_TX_DRV_EI_EN_MASK, ++ FIELD_PREP(OVRD_LN_TX_DRV_EI_EN_MASK, 1) | ++ FIELD_PREP(LN_TX_DRV_EI_EN_MASK, 0)); ++ regmap_update_bits(hdptx->regmap, LANE_REG(0501), ++ OVRD_LN_TX_DRV_EI_EN_MASK | LN_TX_DRV_EI_EN_MASK, ++ FIELD_PREP(OVRD_LN_TX_DRV_EI_EN_MASK, 1) | ++ FIELD_PREP(LN_TX_DRV_EI_EN_MASK, 0)); ++ regmap_update_bits(hdptx->regmap, LANE_REG(0601), ++ OVRD_LN_TX_DRV_EI_EN_MASK | LN_TX_DRV_EI_EN_MASK, ++ FIELD_PREP(OVRD_LN_TX_DRV_EI_EN_MASK, 1) | ++ FIELD_PREP(LN_TX_DRV_EI_EN_MASK, 0)); ++ ++ regmap_write(hdptx->grf, GRF_HDPTX_CON0, ++ HDPTX_I_PLL_EN << 16 | FIELD_PREP(HDPTX_I_PLL_EN, 0x0)); ++ regmap_write(hdptx->grf, GRF_HDPTX_CON0, ++ HDPTX_I_BIAS_EN << 16 | FIELD_PREP(HDPTX_I_BIAS_EN, 0x0)); ++ regmap_write(hdptx->grf, GRF_HDPTX_CON0, ++ HDPTX_I_BGR_EN << 16 | FIELD_PREP(HDPTX_I_BGR_EN, 0x0)); ++} ++ + static int rk_hdptx_phy_consumer_get(struct rk_hdptx_phy *hdptx, + unsigned int rate) + { ++ enum phy_mode mode = phy_get_mode(hdptx->phy); + u32 status; + int ret; + +@@ -875,10 +1146,14 @@ static int rk_hdptx_phy_consumer_get(str + if (status & HDPTX_O_PLL_LOCK_DONE) + dev_warn(hdptx->dev, "PLL locked by unknown consumer!\n"); + +- if (rate) { +- ret = rk_hdptx_ropll_tmds_cmn_config(hdptx, rate); +- if (ret) +- goto dec_usage; ++ if (mode == PHY_MODE_DP) { ++ rk_hdptx_dp_reset(hdptx); ++ } else { ++ if (rate) { ++ ret = rk_hdptx_ropll_tmds_cmn_config(hdptx, rate); ++ if (ret) ++ goto dec_usage; ++ } + } + + return 0; +@@ -890,6 +1165,7 @@ dec_usage: + + static int rk_hdptx_phy_consumer_put(struct rk_hdptx_phy *hdptx, bool force) + { ++ enum phy_mode mode = phy_get_mode(hdptx->phy); + u32 status; + int ret; + +@@ -903,8 +1179,12 @@ static int rk_hdptx_phy_consumer_put(str + } else { + ret = regmap_read(hdptx->grf, GRF_HDPTX_STATUS, &status); + if (!ret) { +- if (status & HDPTX_O_PLL_LOCK_DONE) +- rk_hdptx_phy_disable(hdptx); ++ if (status & HDPTX_O_PLL_LOCK_DONE) { ++ if (mode == PHY_MODE_DP) ++ rk_hdptx_dp_reset(hdptx); ++ else ++ rk_hdptx_phy_disable(hdptx); ++ } + return 0; + } else if (force) { + return 0; +@@ -915,11 +1195,262 @@ static int rk_hdptx_phy_consumer_put(str + return ret; + } + ++static void rk_hdptx_dp_pll_init(struct rk_hdptx_phy *hdptx) ++{ ++ regmap_update_bits(hdptx->regmap, CMN_REG(003c), ANA_LCPLL_RESERVED7_MASK, ++ FIELD_PREP(ANA_LCPLL_RESERVED7_MASK, 0x1)); ++ ++ regmap_update_bits(hdptx->regmap, CMN_REG(0046), ++ ROPLL_ANA_CPP_CTRL_COARSE_MASK | ROPLL_ANA_CPP_CTRL_FINE_MASK, ++ FIELD_PREP(ROPLL_ANA_CPP_CTRL_COARSE_MASK, 0xe) | ++ FIELD_PREP(ROPLL_ANA_CPP_CTRL_FINE_MASK, 0xe)); ++ regmap_update_bits(hdptx->regmap, CMN_REG(0047), ++ ROPLL_ANA_LPF_C_SEL_COARSE_MASK | ++ ROPLL_ANA_LPF_C_SEL_FINE_MASK, ++ FIELD_PREP(ROPLL_ANA_LPF_C_SEL_COARSE_MASK, 0x4) | ++ FIELD_PREP(ROPLL_ANA_LPF_C_SEL_FINE_MASK, 0x4)); ++ ++ regmap_write(hdptx->regmap, CMN_REG(0051), FIELD_PREP(ROPLL_PMS_MDIV_MASK, 0x87)); ++ regmap_write(hdptx->regmap, CMN_REG(0052), FIELD_PREP(ROPLL_PMS_MDIV_MASK, 0x71)); ++ regmap_write(hdptx->regmap, CMN_REG(0053), FIELD_PREP(ROPLL_PMS_MDIV_MASK, 0x71)); ++ ++ regmap_write(hdptx->regmap, CMN_REG(0055), ++ FIELD_PREP(ROPLL_PMS_MDIV_AFC_MASK, 0x87)); ++ regmap_write(hdptx->regmap, CMN_REG(0056), ++ FIELD_PREP(ROPLL_PMS_MDIV_AFC_MASK, 0x71)); ++ regmap_write(hdptx->regmap, CMN_REG(0057), ++ FIELD_PREP(ROPLL_PMS_MDIV_AFC_MASK, 0x71)); ++ ++ regmap_write(hdptx->regmap, CMN_REG(0059), ++ FIELD_PREP(ANA_ROPLL_PMS_PDIV_MASK, 0x1) | ++ FIELD_PREP(ANA_ROPLL_PMS_REFDIV_MASK, 0x1)); ++ regmap_write(hdptx->regmap, CMN_REG(005a), ++ FIELD_PREP(ROPLL_PMS_SDIV_RBR_MASK, 0x3) | ++ FIELD_PREP(ROPLL_PMS_SDIV_HBR_MASK, 0x1)); ++ regmap_update_bits(hdptx->regmap, CMN_REG(005b), ROPLL_PMS_SDIV_HBR2_MASK, ++ FIELD_PREP(ROPLL_PMS_SDIV_HBR2_MASK, 0x0)); ++ ++ regmap_update_bits(hdptx->regmap, CMN_REG(005e), ROPLL_SDM_EN_MASK, ++ FIELD_PREP(ROPLL_SDM_EN_MASK, 0x1)); ++ regmap_update_bits(hdptx->regmap, CMN_REG(005e), ++ OVRD_ROPLL_SDM_RSTN_MASK | ROPLL_SDM_RSTN_MASK, ++ FIELD_PREP(OVRD_ROPLL_SDM_RSTN_MASK, 0x1) | ++ FIELD_PREP(ROPLL_SDM_RSTN_MASK, 0x1)); ++ regmap_update_bits(hdptx->regmap, CMN_REG(005e), ROPLL_SDC_FRAC_EN_RBR_MASK, ++ FIELD_PREP(ROPLL_SDC_FRAC_EN_RBR_MASK, 0x1)); ++ regmap_update_bits(hdptx->regmap, CMN_REG(005e), ROPLL_SDC_FRAC_EN_HBR_MASK, ++ FIELD_PREP(ROPLL_SDC_FRAC_EN_HBR_MASK, 0x1)); ++ regmap_update_bits(hdptx->regmap, CMN_REG(005e), ROPLL_SDC_FRAC_EN_HBR2_MASK, ++ FIELD_PREP(ROPLL_SDC_FRAC_EN_HBR2_MASK, 0x1)); ++ ++ regmap_update_bits(hdptx->regmap, CMN_REG(005f), ++ OVRD_ROPLL_SDC_RSTN_MASK | ROPLL_SDC_RSTN_MASK, ++ FIELD_PREP(OVRD_ROPLL_SDC_RSTN_MASK, 0x1) | ++ FIELD_PREP(ROPLL_SDC_RSTN_MASK, 0x1)); ++ regmap_write(hdptx->regmap, CMN_REG(0060), ++ FIELD_PREP(ROPLL_SDM_DENOMINATOR_MASK, 0x21)); ++ regmap_write(hdptx->regmap, CMN_REG(0061), ++ FIELD_PREP(ROPLL_SDM_DENOMINATOR_MASK, 0x27)); ++ regmap_write(hdptx->regmap, CMN_REG(0062), ++ FIELD_PREP(ROPLL_SDM_DENOMINATOR_MASK, 0x27)); ++ ++ regmap_update_bits(hdptx->regmap, CMN_REG(0064), ++ ROPLL_SDM_NUM_SIGN_RBR_MASK | ++ ROPLL_SDM_NUM_SIGN_HBR_MASK | ++ ROPLL_SDM_NUM_SIGN_HBR2_MASK, ++ FIELD_PREP(ROPLL_SDM_NUM_SIGN_RBR_MASK, 0x0) | ++ FIELD_PREP(ROPLL_SDM_NUM_SIGN_HBR_MASK, 0x1) | ++ FIELD_PREP(ROPLL_SDM_NUM_SIGN_HBR2_MASK, 0x1)); ++ regmap_write(hdptx->regmap, CMN_REG(0065), ++ FIELD_PREP(ROPLL_SDM_NUM_MASK, 0x0)); ++ regmap_write(hdptx->regmap, CMN_REG(0066), ++ FIELD_PREP(ROPLL_SDM_NUM_MASK, 0xd)); ++ regmap_write(hdptx->regmap, CMN_REG(0067), ++ FIELD_PREP(ROPLL_SDM_NUM_MASK, 0xd)); ++ ++ regmap_update_bits(hdptx->regmap, CMN_REG(0069), ROPLL_SDC_N_RBR_MASK, ++ FIELD_PREP(ROPLL_SDC_N_RBR_MASK, 0x2)); ++ ++ regmap_update_bits(hdptx->regmap, CMN_REG(006a), ++ ROPLL_SDC_N_HBR_MASK | ROPLL_SDC_N_HBR2_MASK, ++ FIELD_PREP(ROPLL_SDC_N_HBR_MASK, 0x1) | ++ FIELD_PREP(ROPLL_SDC_N_HBR2_MASK, 0x1)); ++ ++ regmap_write(hdptx->regmap, CMN_REG(006c), ++ FIELD_PREP(ROPLL_SDC_NUM_MASK, 0x3)); ++ regmap_write(hdptx->regmap, CMN_REG(006d), ++ FIELD_PREP(ROPLL_SDC_NUM_MASK, 0x7)); ++ regmap_write(hdptx->regmap, CMN_REG(006e), ++ FIELD_PREP(ROPLL_SDC_NUM_MASK, 0x7)); ++ ++ regmap_write(hdptx->regmap, CMN_REG(0070), ++ FIELD_PREP(ROPLL_SDC_DENO_MASK, 0x8)); ++ regmap_write(hdptx->regmap, CMN_REG(0071), ++ FIELD_PREP(ROPLL_SDC_DENO_MASK, 0x18)); ++ regmap_write(hdptx->regmap, CMN_REG(0072), ++ FIELD_PREP(ROPLL_SDC_DENO_MASK, 0x18)); ++ ++ regmap_update_bits(hdptx->regmap, CMN_REG(0074), ++ OVRD_ROPLL_SDC_NDIV_RSTN_MASK | ROPLL_SDC_NDIV_RSTN_MASK, ++ FIELD_PREP(OVRD_ROPLL_SDC_NDIV_RSTN_MASK, 0x1) | ++ FIELD_PREP(ROPLL_SDC_NDIV_RSTN_MASK, 0x1)); ++ ++ regmap_update_bits(hdptx->regmap, CMN_REG(0077), ANA_ROPLL_SSC_CLK_DIV_SEL_MASK, ++ FIELD_PREP(ANA_ROPLL_SSC_CLK_DIV_SEL_MASK, 0x1)); ++ ++ regmap_update_bits(hdptx->regmap, CMN_REG(0081), ANA_PLL_CD_TX_SER_RATE_SEL_MASK, ++ FIELD_PREP(ANA_PLL_CD_TX_SER_RATE_SEL_MASK, 0x0)); ++ regmap_update_bits(hdptx->regmap, CMN_REG(0081), ++ ANA_PLL_CD_HSCLK_EAST_EN_MASK | ANA_PLL_CD_HSCLK_WEST_EN_MASK, ++ FIELD_PREP(ANA_PLL_CD_HSCLK_EAST_EN_MASK, 0x1) | ++ FIELD_PREP(ANA_PLL_CD_HSCLK_WEST_EN_MASK, 0x0)); ++ ++ regmap_update_bits(hdptx->regmap, CMN_REG(0082), ANA_PLL_CD_VREG_GAIN_CTRL_MASK, ++ FIELD_PREP(ANA_PLL_CD_VREG_GAIN_CTRL_MASK, 0x4)); ++ regmap_update_bits(hdptx->regmap, CMN_REG(0083), ANA_PLL_CD_VREG_ICTRL_MASK, ++ FIELD_PREP(ANA_PLL_CD_VREG_ICTRL_MASK, 0x1)); ++ regmap_update_bits(hdptx->regmap, CMN_REG(0084), PLL_LCRO_CLK_SEL_MASK, ++ FIELD_PREP(PLL_LCRO_CLK_SEL_MASK, 0x1)); ++ regmap_update_bits(hdptx->regmap, CMN_REG(0085), ANA_PLL_SYNC_LOSS_DET_MODE_MASK, ++ FIELD_PREP(ANA_PLL_SYNC_LOSS_DET_MODE_MASK, 0x3)); ++ ++ regmap_update_bits(hdptx->regmap, CMN_REG(0087), ANA_PLL_TX_HS_CLK_EN_MASK, ++ FIELD_PREP(ANA_PLL_TX_HS_CLK_EN_MASK, 0x1)); ++ ++ regmap_update_bits(hdptx->regmap, CMN_REG(0097), DIG_CLK_SEL_MASK, ++ FIELD_PREP(DIG_CLK_SEL_MASK, 0x1)); ++ ++ regmap_update_bits(hdptx->regmap, CMN_REG(0099), CMN_ROPLL_ALONE_MODE_MASK, ++ FIELD_PREP(CMN_ROPLL_ALONE_MODE_MASK, 0x1)); ++ regmap_update_bits(hdptx->regmap, CMN_REG(009a), HS_SPEED_SEL_MASK, ++ FIELD_PREP(HS_SPEED_SEL_MASK, 0x1)); ++ regmap_update_bits(hdptx->regmap, CMN_REG(009b), LS_SPEED_SEL_MASK, ++ FIELD_PREP(LS_SPEED_SEL_MASK, 0x1)); ++} ++ ++static int rk_hdptx_dp_aux_init(struct rk_hdptx_phy *hdptx) ++{ ++ u32 status; ++ int ret; ++ ++ regmap_update_bits(hdptx->regmap, SB_REG(0102), ANA_SB_RXTERM_OFFSP_MASK, ++ FIELD_PREP(ANA_SB_RXTERM_OFFSP_MASK, 0x3)); ++ regmap_update_bits(hdptx->regmap, SB_REG(0103), ANA_SB_RXTERM_OFFSN_MASK, ++ FIELD_PREP(ANA_SB_RXTERM_OFFSN_MASK, 0x3)); ++ regmap_update_bits(hdptx->regmap, SB_REG(0104), SB_AUX_EN_MASK, ++ FIELD_PREP(SB_AUX_EN_MASK, 0x1)); ++ regmap_update_bits(hdptx->regmap, SB_REG(0105), ANA_SB_TX_HLVL_PROG_MASK, ++ FIELD_PREP(ANA_SB_TX_HLVL_PROG_MASK, 0x7)); ++ regmap_update_bits(hdptx->regmap, SB_REG(0106), ANA_SB_TX_LLVL_PROG_MASK, ++ FIELD_PREP(ANA_SB_TX_LLVL_PROG_MASK, 0x7)); ++ ++ regmap_update_bits(hdptx->regmap, SB_REG(010d), ANA_SB_DMRX_LPBK_DATA_MASK, ++ FIELD_PREP(ANA_SB_DMRX_LPBK_DATA_MASK, 0x1)); ++ ++ regmap_update_bits(hdptx->regmap, SB_REG(010f), ANA_SB_VREG_GAIN_CTRL_MASK, ++ FIELD_PREP(ANA_SB_VREG_GAIN_CTRL_MASK, 0x0)); ++ regmap_update_bits(hdptx->regmap, SB_REG(0110), ++ ANA_SB_VREG_OUT_SEL_MASK | ANA_SB_VREG_REF_SEL_MASK, ++ FIELD_PREP(ANA_SB_VREG_OUT_SEL_MASK, 0x1) | ++ FIELD_PREP(ANA_SB_VREG_REF_SEL_MASK, 0x1)); ++ ++ regmap_update_bits(hdptx->regmap, SB_REG(0113), ++ SB_RX_RCAL_OPT_CODE_MASK | SB_RX_RTERM_CTRL_MASK, ++ FIELD_PREP(SB_RX_RCAL_OPT_CODE_MASK, 0x1) | ++ FIELD_PREP(SB_RX_RTERM_CTRL_MASK, 0x3)); ++ regmap_update_bits(hdptx->regmap, SB_REG(0114), ++ SB_TG_SB_EN_DELAY_TIME_MASK | SB_TG_RXTERM_EN_DELAY_TIME_MASK, ++ FIELD_PREP(SB_TG_SB_EN_DELAY_TIME_MASK, 0x2) | ++ FIELD_PREP(SB_TG_RXTERM_EN_DELAY_TIME_MASK, 0x2)); ++ regmap_update_bits(hdptx->regmap, SB_REG(0115), ++ SB_READY_DELAY_TIME_MASK | SB_TG_OSC_EN_DELAY_TIME_MASK, ++ FIELD_PREP(SB_READY_DELAY_TIME_MASK, 0x2) | ++ FIELD_PREP(SB_TG_OSC_EN_DELAY_TIME_MASK, 0x2)); ++ regmap_update_bits(hdptx->regmap, SB_REG(0116), ++ AFC_RSTN_DELAY_TIME_MASK, ++ FIELD_PREP(AFC_RSTN_DELAY_TIME_MASK, 0x2)); ++ regmap_update_bits(hdptx->regmap, SB_REG(0117), ++ FAST_PULSE_TIME_MASK, ++ FIELD_PREP(FAST_PULSE_TIME_MASK, 0x4)); ++ regmap_update_bits(hdptx->regmap, SB_REG(0118), ++ SB_TG_EARC_DMRX_RECVRD_CLK_CNT_MASK, ++ FIELD_PREP(SB_TG_EARC_DMRX_RECVRD_CLK_CNT_MASK, 0xa)); ++ ++ regmap_update_bits(hdptx->regmap, SB_REG(011a), SB_TG_CNT_RUN_NO_7_0_MASK, ++ FIELD_PREP(SB_TG_CNT_RUN_NO_7_0_MASK, 0x3)); ++ regmap_update_bits(hdptx->regmap, SB_REG(011b), ++ SB_EARC_SIG_DET_BYPASS_MASK | SB_AFC_TOL_MASK, ++ FIELD_PREP(SB_EARC_SIG_DET_BYPASS_MASK, 0x1) | ++ FIELD_PREP(SB_AFC_TOL_MASK, 0x3)); ++ regmap_update_bits(hdptx->regmap, SB_REG(011c), SB_AFC_STB_NUM_MASK, ++ FIELD_PREP(SB_AFC_STB_NUM_MASK, 0x4)); ++ regmap_update_bits(hdptx->regmap, SB_REG(011d), SB_TG_OSC_CNT_MIN_MASK, ++ FIELD_PREP(SB_TG_OSC_CNT_MIN_MASK, 0x67)); ++ regmap_update_bits(hdptx->regmap, SB_REG(011e), SB_TG_OSC_CNT_MAX_MASK, ++ FIELD_PREP(SB_TG_OSC_CNT_MAX_MASK, 0x6a)); ++ regmap_update_bits(hdptx->regmap, SB_REG(011f), SB_PWM_AFC_CTRL_MASK, ++ FIELD_PREP(SB_PWM_AFC_CTRL_MASK, 0x5)); ++ regmap_update_bits(hdptx->regmap, SB_REG(011f), SB_RCAL_RSTN_MASK, ++ FIELD_PREP(SB_RCAL_RSTN_MASK, 0x1)); ++ regmap_update_bits(hdptx->regmap, SB_REG(0120), SB_AUX_EN_IN_MASK, ++ FIELD_PREP(SB_AUX_EN_IN_MASK, 0x1)); ++ ++ regmap_update_bits(hdptx->regmap, SB_REG(0102), OVRD_SB_RXTERM_EN_MASK, ++ FIELD_PREP(OVRD_SB_RXTERM_EN_MASK, 0x1)); ++ regmap_update_bits(hdptx->regmap, SB_REG(0103), OVRD_SB_RX_RESCAL_DONE_MASK, ++ FIELD_PREP(OVRD_SB_RX_RESCAL_DONE_MASK, 0x1)); ++ regmap_update_bits(hdptx->regmap, SB_REG(0104), OVRD_SB_EN_MASK, ++ FIELD_PREP(OVRD_SB_EN_MASK, 0x1)); ++ regmap_update_bits(hdptx->regmap, SB_REG(0104), OVRD_SB_AUX_EN_MASK, ++ FIELD_PREP(OVRD_SB_AUX_EN_MASK, 0x1)); ++ ++ regmap_update_bits(hdptx->regmap, SB_REG(010f), OVRD_SB_VREG_EN_MASK, ++ FIELD_PREP(OVRD_SB_VREG_EN_MASK, 0x1)); ++ ++ regmap_write(hdptx->grf, GRF_HDPTX_CON0, ++ HDPTX_I_BGR_EN << 16 | FIELD_PREP(HDPTX_I_BGR_EN, 0x1)); ++ regmap_write(hdptx->grf, GRF_HDPTX_CON0, ++ HDPTX_I_BIAS_EN << 16 | FIELD_PREP(HDPTX_I_BIAS_EN, 0x1)); ++ usleep_range(20, 25); ++ ++ reset_control_deassert(hdptx->rsts[RST_INIT].rstc); ++ usleep_range(20, 25); ++ reset_control_deassert(hdptx->rsts[RST_CMN].rstc); ++ usleep_range(20, 25); ++ ++ regmap_update_bits(hdptx->regmap, SB_REG(0103), OVRD_SB_RX_RESCAL_DONE_MASK, ++ FIELD_PREP(OVRD_SB_RX_RESCAL_DONE_MASK, 0x1)); ++ usleep_range(100, 110); ++ regmap_update_bits(hdptx->regmap, SB_REG(0104), SB_EN_MASK, ++ FIELD_PREP(SB_EN_MASK, 0x1)); ++ usleep_range(100, 110); ++ regmap_update_bits(hdptx->regmap, SB_REG(0102), SB_RXTERM_EN_MASK, ++ FIELD_PREP(SB_RXTERM_EN_MASK, 0x1)); ++ usleep_range(20, 25); ++ regmap_update_bits(hdptx->regmap, SB_REG(010f), SB_VREG_EN_MASK, ++ FIELD_PREP(SB_VREG_EN_MASK, 0x1)); ++ usleep_range(20, 25); ++ regmap_update_bits(hdptx->regmap, SB_REG(0104), SB_AUX_EN_MASK, ++ FIELD_PREP(SB_AUX_EN_MASK, 0x1)); ++ usleep_range(100, 110); ++ ++ ret = regmap_read_poll_timeout(hdptx->grf, GRF_HDPTX_STATUS, ++ status, FIELD_GET(HDPTX_O_SB_RDY, status), ++ 50, 1000); ++ if (ret) { ++ dev_err(hdptx->dev, "Failed to get phy sb ready: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ + static int rk_hdptx_phy_power_on(struct phy *phy) + { + struct rk_hdptx_phy *hdptx = phy_get_drvdata(phy); + int bus_width = phy_get_bus_width(hdptx->phy); +- int ret; ++ enum phy_mode mode = phy_get_mode(phy); ++ int ret, lane; + + /* + * FIXME: Temporary workaround to pass pixel_clk_rate +@@ -935,9 +1466,37 @@ static int rk_hdptx_phy_power_on(struct + if (ret) + return ret; + +- ret = rk_hdptx_ropll_tmds_mode_config(hdptx, rate); +- if (ret) +- rk_hdptx_phy_consumer_put(hdptx, true); ++ if (mode == PHY_MODE_DP) { ++ regmap_write(hdptx->grf, GRF_HDPTX_CON0, ++ HDPTX_MODE_SEL << 16 | FIELD_PREP(HDPTX_MODE_SEL, 0x1)); ++ ++ for (lane = 0; lane < 4; lane++) { ++ regmap_update_bits(hdptx->regmap, LANE_REG(031e) + 0x400 * lane, ++ LN_POLARITY_INV_MASK | LN_LANE_MODE_MASK, ++ FIELD_PREP(LN_POLARITY_INV_MASK, 0) | ++ FIELD_PREP(LN_LANE_MODE_MASK, 1)); ++ } ++ ++ regmap_update_bits(hdptx->regmap, LNTOP_REG(0200), PROTOCOL_SEL_MASK, ++ FIELD_PREP(PROTOCOL_SEL_MASK, 0x0)); ++ regmap_update_bits(hdptx->regmap, LNTOP_REG(0206), DATA_BUS_WIDTH_MASK, ++ FIELD_PREP(DATA_BUS_WIDTH_MASK, 0x1)); ++ regmap_update_bits(hdptx->regmap, LNTOP_REG(0206), DATA_BUS_WIDTH_SEL_MASK, ++ FIELD_PREP(DATA_BUS_WIDTH_SEL_MASK, 0x0)); ++ ++ rk_hdptx_dp_pll_init(hdptx); ++ ++ ret = rk_hdptx_dp_aux_init(hdptx); ++ if (ret) ++ rk_hdptx_phy_consumer_put(hdptx, true); ++ } else { ++ regmap_write(hdptx->grf, GRF_HDPTX_CON0, ++ HDPTX_MODE_SEL << 16 | FIELD_PREP(HDPTX_MODE_SEL, 0x0)); ++ ++ ret = rk_hdptx_ropll_tmds_mode_config(hdptx, rate); ++ if (ret) ++ rk_hdptx_phy_consumer_put(hdptx, true); ++ } + + return ret; + } +@@ -949,9 +1508,308 @@ static int rk_hdptx_phy_power_off(struct + return rk_hdptx_phy_consumer_put(hdptx, false); + } + ++static int rk_hdptx_phy_verify_config(struct rk_hdptx_phy *hdptx, ++ struct phy_configure_opts_dp *dp) ++{ ++ int i; ++ ++ if (dp->set_rate) { ++ switch (dp->link_rate) { ++ case 1620: ++ case 2700: ++ case 5400: ++ break; ++ default: ++ return -EINVAL; ++ } ++ } ++ ++ if (dp->set_lanes) { ++ switch (dp->lanes) { ++ case 1: ++ case 2: ++ case 4: ++ break; ++ default: ++ return -EINVAL; ++ } ++ } ++ ++ if (dp->set_voltages) { ++ for (i = 0; i < hdptx->lanes; i++) { ++ if (dp->voltage[i] > 3 || dp->pre[i] > 3) ++ return -EINVAL; ++ ++ if (dp->voltage[i] + dp->pre[i] > 3) ++ return -EINVAL; ++ } ++ } ++ ++ return 0; ++} ++ ++static int rk_hdptx_phy_set_rate(struct rk_hdptx_phy *hdptx, ++ struct phy_configure_opts_dp *dp) ++{ ++ u32 bw, status; ++ int ret; ++ ++ regmap_write(hdptx->grf, GRF_HDPTX_CON0, ++ HDPTX_I_PLL_EN << 16 | FIELD_PREP(HDPTX_I_PLL_EN, 0x0)); ++ ++ switch (dp->link_rate) { ++ case 1620: ++ bw = DP_BW_RBR; ++ break; ++ case 2700: ++ bw = DP_BW_HBR; ++ break; ++ case 5400: ++ bw = DP_BW_HBR2; ++ break; ++ default: ++ return -EINVAL; ++ } ++ hdptx->link_rate = dp->link_rate; ++ ++ regmap_update_bits(hdptx->regmap, CMN_REG(0008), OVRD_LCPLL_EN_MASK | LCPLL_EN_MASK, ++ FIELD_PREP(OVRD_LCPLL_EN_MASK, 0x1) | ++ FIELD_PREP(LCPLL_EN_MASK, 0x0)); ++ ++ regmap_update_bits(hdptx->regmap, CMN_REG(003d), OVRD_ROPLL_EN_MASK | ROPLL_EN_MASK, ++ FIELD_PREP(OVRD_ROPLL_EN_MASK, 0x1) | ++ FIELD_PREP(ROPLL_EN_MASK, 0x1)); ++ ++ if (dp->ssc) { ++ regmap_update_bits(hdptx->regmap, CMN_REG(0074), ++ OVRD_ROPLL_SSC_EN_MASK | ROPLL_SSC_EN_MASK, ++ FIELD_PREP(OVRD_ROPLL_SSC_EN_MASK, 0x1) | ++ FIELD_PREP(ROPLL_SSC_EN_MASK, 0x1)); ++ regmap_write(hdptx->regmap, CMN_REG(0075), ++ FIELD_PREP(ANA_ROPLL_SSC_FM_DEVIATION_MASK, 0xc)); ++ regmap_update_bits(hdptx->regmap, CMN_REG(0076), ++ ANA_ROPLL_SSC_FM_FREQ_MASK, ++ FIELD_PREP(ANA_ROPLL_SSC_FM_FREQ_MASK, 0x1f)); ++ ++ regmap_update_bits(hdptx->regmap, CMN_REG(0099), SSC_EN_MASK, ++ FIELD_PREP(SSC_EN_MASK, 0x2)); ++ } else { ++ regmap_update_bits(hdptx->regmap, CMN_REG(0074), ++ OVRD_ROPLL_SSC_EN_MASK | ROPLL_SSC_EN_MASK, ++ FIELD_PREP(OVRD_ROPLL_SSC_EN_MASK, 0x1) | ++ FIELD_PREP(ROPLL_SSC_EN_MASK, 0x0)); ++ regmap_write(hdptx->regmap, CMN_REG(0075), ++ FIELD_PREP(ANA_ROPLL_SSC_FM_DEVIATION_MASK, 0x20)); ++ regmap_update_bits(hdptx->regmap, CMN_REG(0076), ++ ANA_ROPLL_SSC_FM_FREQ_MASK, ++ FIELD_PREP(ANA_ROPLL_SSC_FM_FREQ_MASK, 0xc)); ++ ++ regmap_update_bits(hdptx->regmap, CMN_REG(0099), SSC_EN_MASK, ++ FIELD_PREP(SSC_EN_MASK, 0x0)); ++ } ++ ++ regmap_update_bits(hdptx->regmap, CMN_REG(0095), DP_TX_LINK_BW_MASK, ++ FIELD_PREP(DP_TX_LINK_BW_MASK, bw)); ++ ++ regmap_write(hdptx->grf, GRF_HDPTX_CON0, ++ HDPTX_I_PLL_EN << 16 | FIELD_PREP(HDPTX_I_PLL_EN, 0x1)); ++ ++ ret = regmap_read_poll_timeout(hdptx->grf, GRF_HDPTX_STATUS, ++ status, FIELD_GET(HDPTX_O_PLL_LOCK_DONE, status), ++ 50, 1000); ++ if (ret) { ++ dev_err(hdptx->dev, "Failed to get phy pll lock: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int rk_hdptx_phy_set_lanes(struct rk_hdptx_phy *hdptx, ++ struct phy_configure_opts_dp *dp) ++{ ++ hdptx->lanes = dp->lanes; ++ ++ regmap_update_bits(hdptx->regmap, LNTOP_REG(0207), LANE_EN_MASK, ++ FIELD_PREP(LANE_EN_MASK, GENMASK(hdptx->lanes - 1, 0))); ++ ++ return 0; ++} ++ ++static void rk_hdptx_phy_set_voltage(struct rk_hdptx_phy *hdptx, ++ struct phy_configure_opts_dp *dp, ++ u8 lane) ++{ ++ const struct tx_drv_ctrl *ctrl; ++ u32 offset = lane * 0x400; ++ ++ switch (hdptx->link_rate) { ++ case 1620: ++ ctrl = &tx_drv_ctrl_rbr[dp->voltage[lane]][dp->pre[lane]]; ++ regmap_update_bits(hdptx->regmap, LANE_REG(030a) + offset, ++ LN_TX_JEQ_EVEN_CTRL_RBR_MASK, ++ FIELD_PREP(LN_TX_JEQ_EVEN_CTRL_RBR_MASK, ++ ctrl->tx_jeq_even_ctrl)); ++ regmap_update_bits(hdptx->regmap, LANE_REG(030c) + offset, ++ LN_TX_JEQ_ODD_CTRL_RBR_MASK, ++ FIELD_PREP(LN_TX_JEQ_ODD_CTRL_RBR_MASK, ++ ctrl->tx_jeq_odd_ctrl)); ++ regmap_update_bits(hdptx->regmap, LANE_REG(0311) + offset, ++ LN_TX_SER_40BIT_EN_RBR_MASK, ++ FIELD_PREP(LN_TX_SER_40BIT_EN_RBR_MASK, 0x1)); ++ break; ++ case 2700: ++ ctrl = &tx_drv_ctrl_hbr[dp->voltage[lane]][dp->pre[lane]]; ++ regmap_update_bits(hdptx->regmap, LANE_REG(030b) + offset, ++ LN_TX_JEQ_EVEN_CTRL_HBR_MASK, ++ FIELD_PREP(LN_TX_JEQ_EVEN_CTRL_HBR_MASK, ++ ctrl->tx_jeq_even_ctrl)); ++ regmap_update_bits(hdptx->regmap, LANE_REG(030d) + offset, ++ LN_TX_JEQ_ODD_CTRL_HBR_MASK, ++ FIELD_PREP(LN_TX_JEQ_ODD_CTRL_HBR_MASK, ++ ctrl->tx_jeq_odd_ctrl)); ++ regmap_update_bits(hdptx->regmap, LANE_REG(0311) + offset, ++ LN_TX_SER_40BIT_EN_HBR_MASK, ++ FIELD_PREP(LN_TX_SER_40BIT_EN_HBR_MASK, 0x1)); ++ break; ++ case 5400: ++ default: ++ ctrl = &tx_drv_ctrl_hbr2[dp->voltage[lane]][dp->pre[lane]]; ++ regmap_update_bits(hdptx->regmap, LANE_REG(030b) + offset, ++ LN_TX_JEQ_EVEN_CTRL_HBR2_MASK, ++ FIELD_PREP(LN_TX_JEQ_EVEN_CTRL_HBR2_MASK, ++ ctrl->tx_jeq_even_ctrl)); ++ regmap_update_bits(hdptx->regmap, LANE_REG(030d) + offset, ++ LN_TX_JEQ_ODD_CTRL_HBR2_MASK, ++ FIELD_PREP(LN_TX_JEQ_ODD_CTRL_HBR2_MASK, ++ ctrl->tx_jeq_odd_ctrl)); ++ regmap_update_bits(hdptx->regmap, LANE_REG(0311) + offset, ++ LN_TX_SER_40BIT_EN_HBR2_MASK, ++ FIELD_PREP(LN_TX_SER_40BIT_EN_HBR2_MASK, 0x1)); ++ break; ++ } ++ ++ regmap_update_bits(hdptx->regmap, LANE_REG(0303) + offset, ++ OVRD_LN_TX_DRV_LVL_CTRL_MASK | LN_TX_DRV_LVL_CTRL_MASK, ++ FIELD_PREP(OVRD_LN_TX_DRV_LVL_CTRL_MASK, 0x1) | ++ FIELD_PREP(LN_TX_DRV_LVL_CTRL_MASK, ++ ctrl->tx_drv_lvl_ctrl)); ++ regmap_update_bits(hdptx->regmap, LANE_REG(0304) + offset, ++ OVRD_LN_TX_DRV_POST_LVL_CTRL_MASK | ++ LN_TX_DRV_POST_LVL_CTRL_MASK, ++ FIELD_PREP(OVRD_LN_TX_DRV_POST_LVL_CTRL_MASK, 0x1) | ++ FIELD_PREP(LN_TX_DRV_POST_LVL_CTRL_MASK, ++ ctrl->tx_drv_post_lvl_ctrl)); ++ regmap_update_bits(hdptx->regmap, LANE_REG(0305) + offset, ++ OVRD_LN_TX_DRV_PRE_LVL_CTRL_MASK | ++ LN_TX_DRV_PRE_LVL_CTRL_MASK, ++ FIELD_PREP(OVRD_LN_TX_DRV_PRE_LVL_CTRL_MASK, 0x1) | ++ FIELD_PREP(LN_TX_DRV_PRE_LVL_CTRL_MASK, ++ ctrl->tx_drv_pre_lvl_ctrl)); ++ regmap_update_bits(hdptx->regmap, LANE_REG(0306) + offset, ++ LN_ANA_TX_DRV_IDRV_IDN_CTRL_MASK | ++ LN_ANA_TX_DRV_IDRV_IUP_CTRL_MASK | ++ LN_ANA_TX_DRV_ACCDRV_EN_MASK, ++ FIELD_PREP(LN_ANA_TX_DRV_IDRV_IDN_CTRL_MASK, ++ ctrl->ana_tx_drv_idrv_idn_ctrl) | ++ FIELD_PREP(LN_ANA_TX_DRV_IDRV_IUP_CTRL_MASK, ++ ctrl->ana_tx_drv_idrv_iup_ctrl) | ++ FIELD_PREP(LN_ANA_TX_DRV_ACCDRV_EN_MASK, ++ ctrl->ana_tx_drv_accdrv_en)); ++ regmap_update_bits(hdptx->regmap, LANE_REG(0307) + offset, ++ LN_ANA_TX_DRV_ACCDRV_POL_SEL_MASK | ++ LN_ANA_TX_DRV_ACCDRV_CTRL_MASK, ++ FIELD_PREP(LN_ANA_TX_DRV_ACCDRV_POL_SEL_MASK, 0x1) | ++ FIELD_PREP(LN_ANA_TX_DRV_ACCDRV_CTRL_MASK, ++ ctrl->ana_tx_drv_accdrv_ctrl)); ++ ++ regmap_update_bits(hdptx->regmap, LANE_REG(030a) + offset, ++ LN_ANA_TX_JEQ_EN_MASK, ++ FIELD_PREP(LN_ANA_TX_JEQ_EN_MASK, ctrl->ana_tx_jeq_en)); ++ ++ regmap_update_bits(hdptx->regmap, LANE_REG(0310) + offset, ++ LN_ANA_TX_SYNC_LOSS_DET_MODE_MASK, ++ FIELD_PREP(LN_ANA_TX_SYNC_LOSS_DET_MODE_MASK, 0x3)); ++ ++ regmap_update_bits(hdptx->regmap, LANE_REG(0316) + offset, ++ LN_ANA_TX_SER_VREG_GAIN_CTRL_MASK, ++ FIELD_PREP(LN_ANA_TX_SER_VREG_GAIN_CTRL_MASK, 0x2)); ++ ++ regmap_update_bits(hdptx->regmap, LANE_REG(031b) + offset, ++ LN_ANA_TX_RESERVED_MASK, ++ FIELD_PREP(LN_ANA_TX_RESERVED_MASK, 0x1)); ++} ++ ++static int rk_hdptx_phy_set_voltages(struct rk_hdptx_phy *hdptx, ++ struct phy_configure_opts_dp *dp) ++{ ++ u8 lane; ++ u32 status; ++ int ret; ++ ++ for (lane = 0; lane < hdptx->lanes; lane++) ++ rk_hdptx_phy_set_voltage(hdptx, dp, lane); ++ ++ reset_control_deassert(hdptx->rsts[RST_LANE].rstc); ++ ++ ret = regmap_read_poll_timeout(hdptx->grf, GRF_HDPTX_STATUS, ++ status, FIELD_GET(HDPTX_O_PHY_RDY, status), ++ 50, 5000); ++ if (ret) { ++ dev_err(hdptx->dev, "Failed to get phy ready: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int rk_hdptx_phy_configure(struct phy *phy, union phy_configure_opts *opts) ++{ ++ struct rk_hdptx_phy *hdptx = phy_get_drvdata(phy); ++ enum phy_mode mode = phy_get_mode(phy); ++ int ret; ++ ++ if (mode != PHY_MODE_DP) ++ return 0; ++ ++ ret = rk_hdptx_phy_verify_config(hdptx, &opts->dp); ++ if (ret) { ++ dev_err(hdptx->dev, "invalid params for phy configure\n"); ++ return ret; ++ } ++ ++ if (opts->dp.set_rate) { ++ ret = rk_hdptx_phy_set_rate(hdptx, &opts->dp); ++ if (ret) { ++ dev_err(hdptx->dev, "failed to set rate: %d\n", ret); ++ return ret; ++ } ++ } ++ ++ if (opts->dp.set_lanes) { ++ ret = rk_hdptx_phy_set_lanes(hdptx, &opts->dp); ++ if (ret) { ++ dev_err(hdptx->dev, "failed to set lanes: %d\n", ret); ++ return ret; ++ } ++ } ++ ++ if (opts->dp.set_voltages) { ++ ret = rk_hdptx_phy_set_voltages(hdptx, &opts->dp); ++ if (ret) { ++ dev_err(hdptx->dev, "failed to set voltages: %d\n", ++ ret); ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ + static const struct phy_ops rk_hdptx_phy_ops = { + .power_on = rk_hdptx_phy_power_on, + .power_off = rk_hdptx_phy_power_off, ++ .configure = rk_hdptx_phy_configure, + .owner = THIS_MODULE, + }; + +@@ -1193,5 +2051,6 @@ module_platform_driver(rk_hdptx_phy_driv + + MODULE_AUTHOR("Algea Cao "); + MODULE_AUTHOR("Cristian Ciocaltea "); ++MODULE_AUTHOR("Damon Ding "); + MODULE_DESCRIPTION("Samsung HDMI/eDP Transmitter Combo PHY Driver"); + MODULE_LICENSE("GPL"); diff --git a/target/linux/rockchip/patches-6.12/040-06-v6.15-phy-phy-rockchip-samsung-hdptx-Add-support-for-RK3576.patch b/target/linux/rockchip/patches-6.12/040-06-v6.15-phy-phy-rockchip-samsung-hdptx-Add-support-for-RK3576.patch new file mode 100644 index 000000000..f8590c0cb --- /dev/null +++ b/target/linux/rockchip/patches-6.12/040-06-v6.15-phy-phy-rockchip-samsung-hdptx-Add-support-for-RK3576.patch @@ -0,0 +1,49 @@ +From 4a8463ae8d871ccd491d48a371a6789eb7378243 Mon Sep 17 00:00:00 2001 +From: Nicolas Frattaroli +Date: Thu, 6 Mar 2025 20:29:23 +0100 +Subject: [PATCH] phy: phy-rockchip-samsung-hdptx: Add support for RK3576 + +Despite the compatible already being listed in the bindings, the PHY +driver never gained explicit support for it. This is especially a +problem because the explicitly listed PHY addresses need to be specified +for each SoC. + +To solve this, add the compatible, and a PHY config, with the address +gleaned from rk3576.dtsi. + +Signed-off-by: Nicolas Frattaroli +Reviewed-by: Cristian Ciocaltea +Reviewed-by: Heiko Stuebner +Link: https://lore.kernel.org/r/20250306-rk3576-hdptx-phy-v1-1-288cc4b0611a@collabora.com +Signed-off-by: Vinod Koul +--- + drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c ++++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c +@@ -2022,6 +2022,13 @@ static const struct dev_pm_ops rk_hdptx_ + rk_hdptx_phy_runtime_resume, NULL) + }; + ++static const struct rk_hdptx_phy_cfg rk3576_hdptx_phy_cfgs = { ++ .num_phys = 1, ++ .phy_ids = { ++ 0x2b000000, ++ }, ++}; ++ + static const struct rk_hdptx_phy_cfg rk3588_hdptx_phy_cfgs = { + .num_phys = 2, + .phy_ids = { +@@ -2032,6 +2039,10 @@ static const struct rk_hdptx_phy_cfg rk3 + + static const struct of_device_id rk_hdptx_phy_of_match[] = { + { ++ .compatible = "rockchip,rk3576-hdptx-phy", ++ .data = &rk3576_hdptx_phy_cfgs ++ }, ++ { + .compatible = "rockchip,rk3588-hdptx-phy", + .data = &rk3588_hdptx_phy_cfgs + }, diff --git a/target/linux/rockchip/patches-6.12/040-07-v6.16-phy-Add-HDMI-configuration-options.patch b/target/linux/rockchip/patches-6.12/040-07-v6.16-phy-Add-HDMI-configuration-options.patch new file mode 100644 index 000000000..47ce0c13d --- /dev/null +++ b/target/linux/rockchip/patches-6.12/040-07-v6.16-phy-Add-HDMI-configuration-options.patch @@ -0,0 +1,83 @@ +From 10ed34d6eaaf86e301a8f2dd190d26dfbc9799bd Mon Sep 17 00:00:00 2001 +From: Sandor Yu +Date: Tue, 18 Mar 2025 14:35:35 +0200 +Subject: [PATCH] phy: Add HDMI configuration options + +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 +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Maxime Ripard +Acked-by: Vinod Koul +Link: https://lore.kernel.org/r/d1cff6c03ec3732d2244022029245ab2d954d997.1734340233.git.Sandor.yu@nxp.com +Signed-off-by: Cristian Ciocaltea +Link: https://lore.kernel.org/r/20250318-phy-sam-hdptx-bpc-v6-1-8cb1678e7663@collabora.com +Signed-off-by: Vinod Koul +--- + include/linux/phy/phy-hdmi.h | 19 +++++++++++++++++++ + include/linux/phy/phy.h | 7 ++++++- + 2 files changed, 25 insertions(+), 1 deletion(-) + create mode 100644 include/linux/phy/phy-hdmi.h + +--- /dev/null ++++ b/include/linux/phy/phy-hdmi.h +@@ -0,0 +1,19 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright 2022,2024 NXP ++ */ ++ ++#ifndef __PHY_HDMI_H_ ++#define __PHY_HDMI_H_ ++ ++/** ++ * 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_ */ +--- 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; + }; + + /** diff --git a/target/linux/rockchip/patches-6.12/040-08-v6.16-phy-hdmi-Add-color-depth-configuration.patch b/target/linux/rockchip/patches-6.12/040-08-v6.16-phy-hdmi-Add-color-depth-configuration.patch new file mode 100644 index 000000000..cc00c6c03 --- /dev/null +++ b/target/linux/rockchip/patches-6.12/040-08-v6.16-phy-hdmi-Add-color-depth-configuration.patch @@ -0,0 +1,33 @@ +From 3bb9286f4ece6acbc1fbaa9f192a82645d30efbf Mon Sep 17 00:00:00 2001 +From: Cristian Ciocaltea +Date: Tue, 18 Mar 2025 14:35:36 +0200 +Subject: [PATCH] phy: hdmi: Add color depth configuration + +Extend the HDMI configuration options to allow managing bits per color +channel. This is required by some PHY drivers such as +rockchip-samsung-hdptx. + +Reviewed-by: Dmitry Baryshkov +Signed-off-by: Cristian Ciocaltea +Link: https://lore.kernel.org/r/20250318-phy-sam-hdptx-bpc-v6-2-8cb1678e7663@collabora.com +Signed-off-by: Vinod Koul +--- + include/linux/phy/phy-hdmi.h | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/include/linux/phy/phy-hdmi.h ++++ b/include/linux/phy/phy-hdmi.h +@@ -9,11 +9,13 @@ + /** + * struct phy_configure_opts_hdmi - HDMI configuration set + * @tmds_char_rate: HDMI TMDS Character Rate in Hertz. ++ * @bpc: Bits per color channel. + * + * This structure is used to represent the configuration state of a HDMI phy. + */ + struct phy_configure_opts_hdmi { + unsigned long long tmds_char_rate; ++ unsigned int bpc; + }; + + #endif /* __PHY_HDMI_H_ */ diff --git a/target/linux/rockchip/patches-6.12/040-09-v6.16-phy-rockchip-samsung-hdptx-Drop-unused-struct-lcpll_confi.patch b/target/linux/rockchip/patches-6.12/040-09-v6.16-phy-rockchip-samsung-hdptx-Drop-unused-struct-lcpll_confi.patch new file mode 100644 index 000000000..8d6da312f --- /dev/null +++ b/target/linux/rockchip/patches-6.12/040-09-v6.16-phy-rockchip-samsung-hdptx-Drop-unused-struct-lcpll_confi.patch @@ -0,0 +1,56 @@ +From 6218c3fd6702a5bc4ab323fed25714cde127684c Mon Sep 17 00:00:00 2001 +From: Cristian Ciocaltea +Date: Tue, 18 Mar 2025 14:35:39 +0200 +Subject: [PATCH] phy: rockchip: samsung-hdptx: Drop unused struct lcpll_config + +This is just a leftover from downstream support for HDMI 2.1. +Remove the unused struct for now. + +Reviewed-by: Dmitry Baryshkov +Signed-off-by: Cristian Ciocaltea +Link: https://lore.kernel.org/r/20250318-phy-sam-hdptx-bpc-v6-5-8cb1678e7663@collabora.com +Signed-off-by: Vinod Koul +--- + .../phy/rockchip/phy-rockchip-samsung-hdptx.c | 31 ------------------- + 1 file changed, 31 deletions(-) + +--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c ++++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c +@@ -329,37 +329,6 @@ enum dp_link_rate { + DP_BW_HBR2, + }; + +-struct lcpll_config { +- u32 bit_rate; +- u8 lcvco_mode_en; +- u8 pi_en; +- u8 clk_en_100m; +- u8 pms_mdiv; +- u8 pms_mdiv_afc; +- u8 pms_pdiv; +- u8 pms_refdiv; +- u8 pms_sdiv; +- u8 pi_cdiv_rstn; +- u8 pi_cdiv_sel; +- u8 sdm_en; +- u8 sdm_rstn; +- u8 sdc_frac_en; +- u8 sdc_rstn; +- u8 sdm_deno; +- u8 sdm_num_sign; +- u8 sdm_num; +- u8 sdc_n; +- u8 sdc_n2; +- u8 sdc_num; +- u8 sdc_deno; +- u8 sdc_ndiv_rstn; +- u8 ssc_en; +- u8 ssc_fm_dev; +- u8 ssc_fm_freq; +- u8 ssc_clk_div_sel; +- u8 cd_tx_ser_rate_sel; +-}; +- + struct ropll_config { + u32 bit_rate; + u8 pms_mdiv; diff --git a/target/linux/rockchip/patches-6.12/040-10-v6.16-phy-rockchip-samsung-hdptx-Drop-unused-phy_cfg-driver-dat.patch b/target/linux/rockchip/patches-6.12/040-10-v6.16-phy-rockchip-samsung-hdptx-Drop-unused-phy_cfg-driver-dat.patch new file mode 100644 index 000000000..bbb38090a --- /dev/null +++ b/target/linux/rockchip/patches-6.12/040-10-v6.16-phy-rockchip-samsung-hdptx-Drop-unused-phy_cfg-driver-dat.patch @@ -0,0 +1,26 @@ +From bcd61d182618c6a77d0841fcdc3333e125725360 Mon Sep 17 00:00:00 2001 +From: Cristian Ciocaltea +Date: Tue, 18 Mar 2025 14:35:40 +0200 +Subject: [PATCH] phy: rockchip: samsung-hdptx: Drop unused phy_cfg driver data + +There is no usage of phy_cfg in the upstream driver data, nor in the +downstream one, hence remove it. + +Reviewed-by: Dmitry Baryshkov +Signed-off-by: Cristian Ciocaltea +Link: https://lore.kernel.org/r/20250318-phy-sam-hdptx-bpc-v6-6-8cb1678e7663@collabora.com +Signed-off-by: Vinod Koul +--- + drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 1 - + 1 file changed, 1 deletion(-) + +--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c ++++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c +@@ -397,7 +397,6 @@ struct rk_hdptx_phy { + int phy_id; + + struct phy *phy; +- struct phy_config *phy_cfg; + struct clk_bulk_data *clks; + int nr_clks; + struct reset_control_bulk_data rsts[RST_MAX]; diff --git a/target/linux/rockchip/patches-6.12/040-11-v6.16-phy-rockchip-samsung-hdptx-Drop-superfluous-cfgs-driver.patch b/target/linux/rockchip/patches-6.12/040-11-v6.16-phy-rockchip-samsung-hdptx-Drop-superfluous-cfgs-driver.patch new file mode 100644 index 000000000..ac86e83be --- /dev/null +++ b/target/linux/rockchip/patches-6.12/040-11-v6.16-phy-rockchip-samsung-hdptx-Drop-superfluous-cfgs-driver.patch @@ -0,0 +1,61 @@ +From bacf2fe750dab6bc7ed50556aaadd3ab107fc643 Mon Sep 17 00:00:00 2001 +From: Cristian Ciocaltea +Date: Tue, 18 Mar 2025 14:35:41 +0200 +Subject: [PATCH] phy: rockchip: samsung-hdptx: Drop superfluous cfgs driver + data + +The ->cfgs member has been introduced via commit f08d1c085638 ("phy: +phy-rockchip-samsung-hdptx: Don't use dt aliases to determine phy-id"), +but it is only used during probe() in order to setup ->phy_id. + +Use a probe() local variable to store device match data and remove the +now unnecessary member from struct rk_hdptx_phy. + +Reviewed-by: Dmitry Baryshkov +Signed-off-by: Cristian Ciocaltea +Link: https://lore.kernel.org/r/20250318-phy-sam-hdptx-bpc-v6-7-8cb1678e7663@collabora.com +Signed-off-by: Vinod Koul +--- + drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 12 +++++------- + 1 file changed, 5 insertions(+), 7 deletions(-) + +--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c ++++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c +@@ -392,10 +392,7 @@ struct rk_hdptx_phy { + struct regmap *regmap; + struct regmap *grf; + +- /* PHY const config */ +- const struct rk_hdptx_phy_cfg *cfgs; + int phy_id; +- + struct phy *phy; + struct clk_bulk_data *clks; + int nr_clks; +@@ -1896,6 +1893,7 @@ static int rk_hdptx_phy_runtime_resume(s + + static int rk_hdptx_phy_probe(struct platform_device *pdev) + { ++ const struct rk_hdptx_phy_cfg *cfgs; + struct phy_provider *phy_provider; + struct device *dev = &pdev->dev; + struct rk_hdptx_phy *hdptx; +@@ -1914,14 +1912,14 @@ static int rk_hdptx_phy_probe(struct pla + return dev_err_probe(dev, PTR_ERR(regs), + "Failed to ioremap resource\n"); + +- hdptx->cfgs = device_get_match_data(dev); +- if (!hdptx->cfgs) ++ cfgs = device_get_match_data(dev); ++ if (!cfgs) + return dev_err_probe(dev, -EINVAL, "missing match data\n"); + + /* find the phy-id from the io address */ + hdptx->phy_id = -ENODEV; +- for (id = 0; id < hdptx->cfgs->num_phys; id++) { +- if (res->start == hdptx->cfgs->phy_ids[id]) { ++ for (id = 0; id < cfgs->num_phys; id++) { ++ if (res->start == cfgs->phy_ids[id]) { + hdptx->phy_id = id; + break; + } diff --git a/target/linux/rockchip/patches-6.12/040-12-v6.16-phy-rockchip-samsung-hdptx-Avoid-Hz-hHz-unit-conversion.patch b/target/linux/rockchip/patches-6.12/040-12-v6.16-phy-rockchip-samsung-hdptx-Avoid-Hz-hHz-unit-conversion.patch new file mode 100644 index 000000000..9d90a332f --- /dev/null +++ b/target/linux/rockchip/patches-6.12/040-12-v6.16-phy-rockchip-samsung-hdptx-Avoid-Hz-hHz-unit-conversion.patch @@ -0,0 +1,240 @@ +From 0edf9d2bb9b4ba7566dfdc7605883e04575129d9 Mon Sep 17 00:00:00 2001 +From: Cristian Ciocaltea +Date: Tue, 18 Mar 2025 14:35:42 +0200 +Subject: [PATCH] phy: rockchip: samsung-hdptx: Avoid Hz<->hHz unit conversion + overhead + +The ropll_tmds_cfg table used to identify the configuration params for +the supported rates expects the search key, i.e. bit_rate member of +struct ropll_config, to be provided in hHz rather than Hz (1 hHz = 100 +Hz). This requires multiple conversions between these units being +performed at runtime. + +Improve implementation clarity and efficiency by consistently using the +Hz unit throughout driver's internal data structures and functions. +Also rename the rather misleading struct member. + +Signed-off-by: Cristian Ciocaltea +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20250318-phy-sam-hdptx-bpc-v6-8-8cb1678e7663@collabora.com +Signed-off-by: Vinod Koul +--- + .../phy/rockchip/phy-rockchip-samsung-hdptx.c | 79 +++++++++---------- + 1 file changed, 39 insertions(+), 40 deletions(-) + +--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c ++++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c +@@ -330,7 +330,7 @@ enum dp_link_rate { + }; + + struct ropll_config { +- u32 bit_rate; ++ unsigned long long rate; + u8 pms_mdiv; + u8 pms_mdiv_afc; + u8 pms_pdiv; +@@ -410,47 +410,47 @@ struct rk_hdptx_phy { + }; + + static const struct ropll_config ropll_tmds_cfg[] = { +- { 5940000, 124, 124, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0, ++ { 594000000ULL, 124, 124, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0, + 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, +- { 3712500, 155, 155, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0, ++ { 371250000ULL, 155, 155, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0, + 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, +- { 2970000, 124, 124, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0, ++ { 297000000ULL, 124, 124, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0, + 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, +- { 1620000, 135, 135, 1, 1, 3, 1, 1, 0, 1, 1, 1, 1, 4, 0, 3, 5, 5, 0x10, ++ { 162000000ULL, 135, 135, 1, 1, 3, 1, 1, 0, 1, 1, 1, 1, 4, 0, 3, 5, 5, 0x10, + 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, +- { 1856250, 155, 155, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0, ++ { 185625000ULL, 155, 155, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0, + 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, +- { 1540000, 193, 193, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 193, 1, 32, 2, 1, ++ { 154000000ULL, 193, 193, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 193, 1, 32, 2, 1, + 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, +- { 1485000, 0x7b, 0x7b, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 4, 0, 3, 5, 5, ++ { 148500000ULL, 0x7b, 0x7b, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 4, 0, 3, 5, 5, + 0x10, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, +- { 1462500, 122, 122, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 244, 1, 16, 2, 1, 1, ++ { 146250000ULL, 122, 122, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 244, 1, 16, 2, 1, 1, + 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, +- { 1190000, 149, 149, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 149, 1, 16, 2, 1, 1, ++ { 119000000ULL, 149, 149, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 149, 1, 16, 2, 1, 1, + 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, +- { 1065000, 89, 89, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 89, 1, 16, 1, 0, 1, ++ { 106500000ULL, 89, 89, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 89, 1, 16, 1, 0, 1, + 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, +- { 1080000, 135, 135, 1, 1, 5, 1, 1, 0, 1, 0, 1, 1, 0x9, 0, 0x05, 0, ++ { 108000000ULL, 135, 135, 1, 1, 5, 1, 1, 0, 1, 0, 1, 1, 0x9, 0, 0x05, 0, + 0x14, 0x18, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, +- { 855000, 214, 214, 1, 1, 11, 1, 1, 1, 1, 1, 1, 1, 214, 1, 16, 2, 1, ++ { 85500000ULL, 214, 214, 1, 1, 11, 1, 1, 1, 1, 1, 1, 1, 214, 1, 16, 2, 1, + 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, +- { 835000, 105, 105, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 42, 1, 16, 1, 0, ++ { 83500000ULL, 105, 105, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 42, 1, 16, 1, 0, + 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, +- { 928125, 155, 155, 1, 1, 7, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0, ++ { 92812500ULL, 155, 155, 1, 1, 7, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0, + 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, +- { 742500, 124, 124, 1, 1, 7, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0, ++ { 74250000ULL, 124, 124, 1, 1, 7, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0, + 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, +- { 650000, 162, 162, 1, 1, 11, 1, 1, 1, 1, 1, 1, 1, 54, 0, 16, 4, 1, ++ { 65000000ULL, 162, 162, 1, 1, 11, 1, 1, 1, 1, 1, 1, 1, 54, 0, 16, 4, 1, + 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, +- { 502500, 84, 84, 1, 1, 7, 1, 1, 1, 1, 1, 1, 1, 11, 1, 4, 5, ++ { 50250000ULL, 84, 84, 1, 1, 7, 1, 1, 1, 1, 1, 1, 1, 11, 1, 4, 5, + 4, 11, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, +- { 337500, 0x70, 0x70, 1, 1, 0xf, 1, 1, 1, 1, 1, 1, 1, 0x2, 0, 0x01, 5, ++ { 33750000ULL, 0x70, 0x70, 1, 1, 0xf, 1, 1, 1, 1, 1, 1, 1, 0x2, 0, 0x01, 5, + 1, 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, +- { 400000, 100, 100, 1, 1, 11, 1, 1, 0, 1, 0, 1, 1, 0x9, 0, 0x05, 0, ++ { 40000000ULL, 100, 100, 1, 1, 11, 1, 1, 0, 1, 0, 1, 1, 0x9, 0, 0x05, 0, + 0x14, 0x18, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, +- { 270000, 0x5a, 0x5a, 1, 1, 0xf, 1, 1, 0, 1, 0, 1, 1, 0x9, 0, 0x05, 0, ++ { 27000000ULL, 0x5a, 0x5a, 1, 1, 0xf, 1, 1, 0, 1, 0, 1, 1, 0x9, 0, 0x05, 0, + 0x14, 0x18, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, +- { 251750, 84, 84, 1, 1, 0xf, 1, 1, 1, 1, 1, 1, 1, 168, 1, 16, 4, 1, 1, ++ { 25175000ULL, 84, 84, 1, 1, 0xf, 1, 1, 1, 1, 1, 1, 1, 168, 1, 16, 4, 1, 1, + 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, + }; + +@@ -896,10 +896,10 @@ static void rk_hdptx_phy_disable(struct + regmap_write(hdptx->grf, GRF_HDPTX_CON0, val); + } + +-static bool rk_hdptx_phy_clk_pll_calc(unsigned int data_rate, ++static bool rk_hdptx_phy_clk_pll_calc(unsigned long long rate, + struct ropll_config *cfg) + { +- const unsigned int fout = data_rate / 2, fref = 24000; ++ const unsigned int fout = div_u64(rate, 200), fref = 24000; + unsigned long k = 0, lc, k_sub, lc_sub; + unsigned int fvco, sdc; + u32 mdiv, sdiv, n = 8; +@@ -969,14 +969,14 @@ static bool rk_hdptx_phy_clk_pll_calc(un + } + + static int rk_hdptx_ropll_tmds_cmn_config(struct rk_hdptx_phy *hdptx, +- unsigned int rate) ++ unsigned long long rate) + { + const struct ropll_config *cfg = NULL; + struct ropll_config rc = {0}; + int ret, i; + + for (i = 0; i < ARRAY_SIZE(ropll_tmds_cfg); i++) +- if (rate == ropll_tmds_cfg[i].bit_rate) { ++ if (rate == ropll_tmds_cfg[i].rate) { + cfg = &ropll_tmds_cfg[i]; + break; + } +@@ -990,8 +990,8 @@ static int rk_hdptx_ropll_tmds_cmn_confi + } + } + +- dev_dbg(hdptx->dev, "mdiv=%u, sdiv=%u, sdm_en=%u, k_sign=%u, k=%u, lc=%u\n", +- cfg->pms_mdiv, cfg->pms_sdiv + 1, cfg->sdm_en, ++ dev_dbg(hdptx->dev, "%s rate=%llu mdiv=%u sdiv=%u sdm_en=%u k_sign=%u k=%u lc=%u\n", ++ __func__, rate, cfg->pms_mdiv, cfg->pms_sdiv + 1, cfg->sdm_en, + cfg->sdm_num_sign, cfg->sdm_num, cfg->sdm_deno); + + rk_hdptx_pre_power_up(hdptx); +@@ -1030,19 +1030,19 @@ static int rk_hdptx_ropll_tmds_cmn_confi + + ret = rk_hdptx_post_enable_pll(hdptx); + if (!ret) +- hdptx->rate = rate * 100; ++ hdptx->rate = rate; + + return ret; + } + + static int rk_hdptx_ropll_tmds_mode_config(struct rk_hdptx_phy *hdptx, +- unsigned int rate) ++ unsigned long long rate) + { + rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_common_sb_init_seq); + + regmap_write(hdptx->regmap, LNTOP_REG(0200), 0x06); + +- if (rate > HDMI14_MAX_RATE / 100) { ++ if (rate > HDMI14_MAX_RATE) { + /* For 1/40 bitrate clk */ + rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_tmds_lntop_highbr_seq); + } else { +@@ -1095,7 +1095,7 @@ static void rk_hdptx_dp_reset(struct rk_ + } + + static int rk_hdptx_phy_consumer_get(struct rk_hdptx_phy *hdptx, +- unsigned int rate) ++ unsigned long long rate) + { + enum phy_mode mode = phy_get_mode(hdptx->phy); + u32 status; +@@ -1413,8 +1413,8 @@ static int rk_hdptx_dp_aux_init(struct r + static int rk_hdptx_phy_power_on(struct phy *phy) + { + struct rk_hdptx_phy *hdptx = phy_get_drvdata(phy); +- int bus_width = phy_get_bus_width(hdptx->phy); + enum phy_mode mode = phy_get_mode(phy); ++ unsigned long long rate; + int ret, lane; + + /* +@@ -1422,10 +1422,10 @@ static int rk_hdptx_phy_power_on(struct + * from the HDMI bridge driver until phy_configure_opts_hdmi + * becomes available in the PHY API. + */ +- unsigned int rate = bus_width & 0xfffffff; ++ rate = phy_get_bus_width(hdptx->phy) & 0xfffffff; ++ rate *= 100; + +- dev_dbg(hdptx->dev, "%s bus_width=%x rate=%u\n", +- __func__, bus_width, rate); ++ dev_dbg(hdptx->dev, "%s rate=%llu\n", __func__, rate); + + ret = rk_hdptx_phy_consumer_get(hdptx, rate); + if (ret) +@@ -1787,7 +1787,7 @@ static int rk_hdptx_phy_clk_prepare(stru + { + struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw); + +- return rk_hdptx_phy_consumer_get(hdptx, hdptx->rate / 100); ++ return rk_hdptx_phy_consumer_get(hdptx, hdptx->rate); + } + + static void rk_hdptx_phy_clk_unprepare(struct clk_hw *hw) +@@ -1808,18 +1808,17 @@ static unsigned long rk_hdptx_phy_clk_re + static long rk_hdptx_phy_clk_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) + { +- u32 bit_rate = rate / 100; + int i; + + if (rate > HDMI20_MAX_RATE) + return rate; + + for (i = 0; i < ARRAY_SIZE(ropll_tmds_cfg); i++) +- if (bit_rate == ropll_tmds_cfg[i].bit_rate) ++ if (rate == ropll_tmds_cfg[i].rate) + break; + + if (i == ARRAY_SIZE(ropll_tmds_cfg) && +- !rk_hdptx_phy_clk_pll_calc(bit_rate, NULL)) ++ !rk_hdptx_phy_clk_pll_calc(rate, NULL)) + return -EINVAL; + + return rate; +@@ -1830,7 +1829,7 @@ static int rk_hdptx_phy_clk_set_rate(str + { + struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw); + +- return rk_hdptx_ropll_tmds_cmn_config(hdptx, rate / 100); ++ return rk_hdptx_ropll_tmds_cmn_config(hdptx, rate); + } + + static const struct clk_ops hdptx_phy_clk_ops = { diff --git a/target/linux/rockchip/patches-6.12/040-13-v6.16-phy-rockchip-samsung-hdptx-Setup-TMDS-char-rate-via.patch b/target/linux/rockchip/patches-6.12/040-13-v6.16-phy-rockchip-samsung-hdptx-Setup-TMDS-char-rate-via.patch new file mode 100644 index 000000000..2b22600e8 --- /dev/null +++ b/target/linux/rockchip/patches-6.12/040-13-v6.16-phy-rockchip-samsung-hdptx-Setup-TMDS-char-rate-via.patch @@ -0,0 +1,131 @@ +From c871a311edf0ebb1b934946a84a6c532cac0c035 Mon Sep 17 00:00:00 2001 +From: Cristian Ciocaltea +Date: Tue, 18 Mar 2025 14:35:43 +0200 +Subject: [PATCH] phy: rockchip: samsung-hdptx: Setup TMDS char rate via + phy_configure_opts_hdmi + +The current workaround to setup the TMDS character rate relies on the +unconventional usage of phy_set_bus_width(). + +Make use of the recently introduced HDMI PHY configuration API to +properly handle the setup. The workaround will be dropped as soon as +the switch has been completed on both ends. + +Rename rk_hdptx_phy_verify_config() to rk_hdptx_phy_verify_dp_config() +and introduce the rk_hdptx_phy_verify_hdmi_config() helper to check the +HDMI parameters during phy_configure(). + +Signed-off-by: Cristian Ciocaltea +Link: https://lore.kernel.org/r/20250318-phy-sam-hdptx-bpc-v6-9-8cb1678e7663@collabora.com +Signed-off-by: Vinod Koul +--- + .../phy/rockchip/phy-rockchip-samsung-hdptx.c | 64 ++++++++++++++----- + 1 file changed, 47 insertions(+), 17 deletions(-) + +--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c ++++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c +@@ -394,6 +394,7 @@ struct rk_hdptx_phy { + + int phy_id; + struct phy *phy; ++ struct phy_configure_opts_hdmi hdmi_cfg; + struct clk_bulk_data *clks; + int nr_clks; + struct reset_control_bulk_data rsts[RST_MAX]; +@@ -1414,20 +1415,24 @@ static int rk_hdptx_phy_power_on(struct + { + struct rk_hdptx_phy *hdptx = phy_get_drvdata(phy); + enum phy_mode mode = phy_get_mode(phy); +- unsigned long long rate; + int ret, lane; + +- /* +- * FIXME: Temporary workaround to pass pixel_clk_rate +- * from the HDMI bridge driver until phy_configure_opts_hdmi +- * becomes available in the PHY API. +- */ +- rate = phy_get_bus_width(hdptx->phy) & 0xfffffff; +- rate *= 100; ++ if (mode != PHY_MODE_DP) { ++ if (!hdptx->hdmi_cfg.tmds_char_rate) { ++ /* ++ * FIXME: Temporary workaround to setup TMDS char rate ++ * from the RK DW HDMI QP bridge driver. ++ * Will be removed as soon the switch to the HDMI PHY ++ * configuration API has been completed on both ends. ++ */ ++ hdptx->hdmi_cfg.tmds_char_rate = phy_get_bus_width(hdptx->phy) & 0xfffffff; ++ hdptx->hdmi_cfg.tmds_char_rate *= 100; ++ } + +- dev_dbg(hdptx->dev, "%s rate=%llu\n", __func__, rate); ++ dev_dbg(hdptx->dev, "%s rate=%llu\n", __func__, hdptx->hdmi_cfg.tmds_char_rate); ++ } + +- ret = rk_hdptx_phy_consumer_get(hdptx, rate); ++ ret = rk_hdptx_phy_consumer_get(hdptx, hdptx->hdmi_cfg.tmds_char_rate); + if (ret) + return ret; + +@@ -1458,7 +1463,7 @@ static int rk_hdptx_phy_power_on(struct + regmap_write(hdptx->grf, GRF_HDPTX_CON0, + HDPTX_MODE_SEL << 16 | FIELD_PREP(HDPTX_MODE_SEL, 0x0)); + +- ret = rk_hdptx_ropll_tmds_mode_config(hdptx, rate); ++ ret = rk_hdptx_ropll_tmds_mode_config(hdptx, hdptx->hdmi_cfg.tmds_char_rate); + if (ret) + rk_hdptx_phy_consumer_put(hdptx, true); + } +@@ -1473,8 +1478,27 @@ static int rk_hdptx_phy_power_off(struct + return rk_hdptx_phy_consumer_put(hdptx, false); + } + +-static int rk_hdptx_phy_verify_config(struct rk_hdptx_phy *hdptx, +- struct phy_configure_opts_dp *dp) ++static int rk_hdptx_phy_verify_hdmi_config(struct rk_hdptx_phy *hdptx, ++ struct phy_configure_opts_hdmi *hdmi) ++{ ++ int i; ++ ++ if (!hdmi->tmds_char_rate || hdmi->tmds_char_rate > HDMI20_MAX_RATE) ++ return -EINVAL; ++ ++ for (i = 0; i < ARRAY_SIZE(ropll_tmds_cfg); i++) ++ if (hdmi->tmds_char_rate == ropll_tmds_cfg[i].rate) ++ break; ++ ++ if (i == ARRAY_SIZE(ropll_tmds_cfg) && ++ !rk_hdptx_phy_clk_pll_calc(hdmi->tmds_char_rate, NULL)) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static int rk_hdptx_phy_verify_dp_config(struct rk_hdptx_phy *hdptx, ++ struct phy_configure_opts_dp *dp) + { + int i; + +@@ -1734,12 +1758,18 @@ static int rk_hdptx_phy_configure(struct + enum phy_mode mode = phy_get_mode(phy); + int ret; + +- if (mode != PHY_MODE_DP) +- return 0; ++ if (mode != PHY_MODE_DP) { ++ ret = rk_hdptx_phy_verify_hdmi_config(hdptx, &opts->hdmi); ++ if (ret) ++ dev_err(hdptx->dev, "invalid hdmi params for phy configure\n"); ++ else ++ hdptx->hdmi_cfg = opts->hdmi; ++ return ret; ++ } + +- ret = rk_hdptx_phy_verify_config(hdptx, &opts->dp); ++ ret = rk_hdptx_phy_verify_dp_config(hdptx, &opts->dp); + if (ret) { +- dev_err(hdptx->dev, "invalid params for phy configure\n"); ++ dev_err(hdptx->dev, "invalid dp params for phy configure\n"); + return ret; + } + diff --git a/target/linux/rockchip/patches-6.12/040-14-v6.16-phy-rockchip-samsung-hdptx-Provide-config-params.patch b/target/linux/rockchip/patches-6.12/040-14-v6.16-phy-rockchip-samsung-hdptx-Provide-config-params.patch new file mode 100644 index 000000000..22eb311ca --- /dev/null +++ b/target/linux/rockchip/patches-6.12/040-14-v6.16-phy-rockchip-samsung-hdptx-Provide-config-params.patch @@ -0,0 +1,42 @@ +From 2392050a2cb94ff3397949e109e4b9f0285ee085 Mon Sep 17 00:00:00 2001 +From: Cristian Ciocaltea +Date: Tue, 18 Mar 2025 14:35:44 +0200 +Subject: [PATCH] phy: rockchip: samsung-hdptx: Provide config params + validation support + +Implement the phy_ops.validate() callback to allow checking the PHY +configuration parameters without actually applying them. + +Reviewed-by: Dmitry Baryshkov +Signed-off-by: Cristian Ciocaltea +Link: https://lore.kernel.org/r/20250318-phy-sam-hdptx-bpc-v6-10-8cb1678e7663@collabora.com +Signed-off-by: Vinod Koul +--- + drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c ++++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c +@@ -1801,10 +1801,22 @@ static int rk_hdptx_phy_configure(struct + return 0; + } + ++static int rk_hdptx_phy_validate(struct phy *phy, enum phy_mode mode, ++ int submode, union phy_configure_opts *opts) ++{ ++ struct rk_hdptx_phy *hdptx = phy_get_drvdata(phy); ++ ++ if (mode != PHY_MODE_DP) ++ return rk_hdptx_phy_verify_hdmi_config(hdptx, &opts->hdmi); ++ ++ return rk_hdptx_phy_verify_dp_config(hdptx, &opts->dp); ++} ++ + static const struct phy_ops rk_hdptx_phy_ops = { + .power_on = rk_hdptx_phy_power_on, + .power_off = rk_hdptx_phy_power_off, + .configure = rk_hdptx_phy_configure, ++ .validate = rk_hdptx_phy_validate, + .owner = THIS_MODULE, + }; + diff --git a/target/linux/rockchip/patches-6.12/040-15-v6.16-phy-rockchip-samsung-hdptx-Restrict-altering-TMDS-char.patch b/target/linux/rockchip/patches-6.12/040-15-v6.16-phy-rockchip-samsung-hdptx-Restrict-altering-TMDS-char.patch new file mode 100644 index 000000000..ef64539ac --- /dev/null +++ b/target/linux/rockchip/patches-6.12/040-15-v6.16-phy-rockchip-samsung-hdptx-Restrict-altering-TMDS-char.patch @@ -0,0 +1,129 @@ +From 6efbd0f46dd8ae1d2b91b41d98c2800c60ab1f5e Mon Sep 17 00:00:00 2001 +From: Cristian Ciocaltea +Date: Tue, 18 Mar 2025 14:35:45 +0200 +Subject: [PATCH] phy: rockchip: samsung-hdptx: Restrict altering TMDS char + rate via CCF + +Although, in theory, the clock provider functionality could be enabled +as a standalone driver feature, in practice it is unlikely that it would +be ever needed separately from the common PHY related features, i.e. +making use of the PHY PLL as an alternative and more accurate clock +source for display modes handling. Which means the PLL will be always +programmed according to the TMDS char rate set via the HDMI PHY +configuration API. + +Currently it's possible to freely adjust the rate via the clock API as +well, that is through clk_set_rate(). Making the clock read-only is not +feasible since we need to ensure any rate update done via the PHY +configuration API has been actually programmed into the hardware before +CCF accesses it. This would be normally done during phy_ops.power_on() +or clk_ops.prepare() callbacks, but it might happen that the former gets +fired too late and the latter only once, hence we need to keep handle it +via clk_ops.set_rate() as a fallback approach. + +Prevent changing the TMDS character rate via CCF by letting +rk_hdptx_phy_clk_round_rate() always return the value set via +phy_configure(). To avoid breaking existing users, i.e. RK DW HDMI QP +bridge driver, until the switch to the HDMI PHY config based approach is +completed, introduce a temporary exception to the rule, toggled via the +new ->restrict_rate_change flag, which indicates whether phy_configure() +has been called or not. + +Additionally, revert any unlikely rate change that might have occurred +between the calls to ->round_rate() and ->set_rate(). + +Signed-off-by: Cristian Ciocaltea +Link: https://lore.kernel.org/r/20250318-phy-sam-hdptx-bpc-v6-11-8cb1678e7663@collabora.com +Signed-off-by: Vinod Koul +--- + .../phy/rockchip/phy-rockchip-samsung-hdptx.c | 52 ++++++++++++++----- + 1 file changed, 40 insertions(+), 12 deletions(-) + +--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c ++++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c +@@ -402,6 +402,7 @@ struct rk_hdptx_phy { + /* clk provider */ + struct clk_hw hw; + unsigned long rate; ++ bool restrict_rate_change; + + atomic_t usage_count; + +@@ -1760,10 +1761,12 @@ static int rk_hdptx_phy_configure(struct + + if (mode != PHY_MODE_DP) { + ret = rk_hdptx_phy_verify_hdmi_config(hdptx, &opts->hdmi); +- if (ret) ++ if (ret) { + dev_err(hdptx->dev, "invalid hdmi params for phy configure\n"); +- else ++ } else { + hdptx->hdmi_cfg = opts->hdmi; ++ hdptx->restrict_rate_change = true; ++ } + return ret; + } + +@@ -1850,20 +1853,31 @@ static unsigned long rk_hdptx_phy_clk_re + static long rk_hdptx_phy_clk_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) + { +- int i; ++ struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw); + +- if (rate > HDMI20_MAX_RATE) +- return rate; ++ /* ++ * FIXME: Temporarily allow altering TMDS char rate via CCF. ++ * To be dropped as soon as the RK DW HDMI QP bridge driver ++ * switches to make use of phy_configure(). ++ */ ++ if (!hdptx->restrict_rate_change && rate != hdptx->hdmi_cfg.tmds_char_rate) { ++ struct phy_configure_opts_hdmi hdmi = { ++ .tmds_char_rate = rate, ++ }; ++ int ret = rk_hdptx_phy_verify_hdmi_config(hdptx, &hdmi); + +- for (i = 0; i < ARRAY_SIZE(ropll_tmds_cfg); i++) +- if (rate == ropll_tmds_cfg[i].rate) +- break; ++ if (ret) ++ return ret; + +- if (i == ARRAY_SIZE(ropll_tmds_cfg) && +- !rk_hdptx_phy_clk_pll_calc(rate, NULL)) +- return -EINVAL; ++ hdptx->hdmi_cfg = hdmi; ++ } + +- return rate; ++ /* ++ * The TMDS char rate shall be adjusted via phy_configure() only, ++ * hence ensure rk_hdptx_phy_clk_set_rate() won't be invoked with ++ * a different rate argument. ++ */ ++ return hdptx->hdmi_cfg.tmds_char_rate; + } + + static int rk_hdptx_phy_clk_set_rate(struct clk_hw *hw, unsigned long rate, +@@ -1871,6 +1885,20 @@ static int rk_hdptx_phy_clk_set_rate(str + { + struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw); + ++ /* Revert any unlikely TMDS char rate change since round_rate() */ ++ if (hdptx->hdmi_cfg.tmds_char_rate != rate) { ++ dev_warn(hdptx->dev, "Reverting unexpected rate change from %lu to %llu\n", ++ rate, hdptx->hdmi_cfg.tmds_char_rate); ++ hdptx->hdmi_cfg.tmds_char_rate = rate; ++ } ++ ++ /* ++ * The TMDS char rate would be normally programmed in HW during ++ * phy_ops.power_on() or clk_ops.prepare() callbacks, but it might ++ * happen that the former gets fired too late, i.e. after this call, ++ * while the latter being executed only once, i.e. when clock remains ++ * in the prepared state during rate changes. ++ */ + return rk_hdptx_ropll_tmds_cmn_config(hdptx, rate); + } + diff --git a/target/linux/rockchip/patches-6.12/040-16-v6.16-phy-rockchip-samsung-hdptx-Rename-ambiguous.patch b/target/linux/rockchip/patches-6.12/040-16-v6.16-phy-rockchip-samsung-hdptx-Rename-ambiguous.patch new file mode 100644 index 000000000..df71625d1 --- /dev/null +++ b/target/linux/rockchip/patches-6.12/040-16-v6.16-phy-rockchip-samsung-hdptx-Rename-ambiguous.patch @@ -0,0 +1,58 @@ +From 37f335dbfd028c008d0a7940ca5a270d1e2f6b81 Mon Sep 17 00:00:00 2001 +From: Cristian Ciocaltea +Date: Tue, 18 Mar 2025 14:35:46 +0200 +Subject: [PATCH] phy: rockchip: samsung-hdptx: Rename ambiguous + rk_hdptx_phy->rate + +The main purpose of the ->rate member of struct rk_hdptx_phy is to +implement rk_hdptx_phy_clk_recalc_rate() by providing the actual rate +programmed in hardware. Hence the current naming is too generic and +rather ambiguous. + +Improve clarity by renaming ->rate to ->hw_rate. + +Signed-off-by: Cristian Ciocaltea +Link: https://lore.kernel.org/r/20250318-phy-sam-hdptx-bpc-v6-12-8cb1678e7663@collabora.com +Signed-off-by: Vinod Koul +--- + drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c ++++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c +@@ -401,7 +401,7 @@ struct rk_hdptx_phy { + + /* clk provider */ + struct clk_hw hw; +- unsigned long rate; ++ unsigned long hw_rate; + bool restrict_rate_change; + + atomic_t usage_count; +@@ -1032,7 +1032,7 @@ static int rk_hdptx_ropll_tmds_cmn_confi + + ret = rk_hdptx_post_enable_pll(hdptx); + if (!ret) +- hdptx->rate = rate; ++ hdptx->hw_rate = rate; + + return ret; + } +@@ -1832,7 +1832,7 @@ static int rk_hdptx_phy_clk_prepare(stru + { + struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw); + +- return rk_hdptx_phy_consumer_get(hdptx, hdptx->rate); ++ return rk_hdptx_phy_consumer_get(hdptx, hdptx->hw_rate); + } + + static void rk_hdptx_phy_clk_unprepare(struct clk_hw *hw) +@@ -1847,7 +1847,7 @@ static unsigned long rk_hdptx_phy_clk_re + { + struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw); + +- return hdptx->rate; ++ return hdptx->hw_rate; + } + + static long rk_hdptx_phy_clk_round_rate(struct clk_hw *hw, unsigned long rate, diff --git a/target/linux/rockchip/patches-6.12/040-17-v6.16-phy-rockchip-samsung-hdptx-Optimize-internal-rate-handlin.patch b/target/linux/rockchip/patches-6.12/040-17-v6.16-phy-rockchip-samsung-hdptx-Optimize-internal-rate-handlin.patch new file mode 100644 index 000000000..d737f228a --- /dev/null +++ b/target/linux/rockchip/patches-6.12/040-17-v6.16-phy-rockchip-samsung-hdptx-Optimize-internal-rate-handlin.patch @@ -0,0 +1,147 @@ +From 45b14bdcf4acfd483d9890396197c35c23821124 Mon Sep 17 00:00:00 2001 +From: Cristian Ciocaltea +Date: Tue, 18 Mar 2025 14:35:47 +0200 +Subject: [PATCH] phy: rockchip: samsung-hdptx: Optimize internal rate handling + +Drop the rate parameter from a bunch of internal helpers and, instead, +make better use of the newly introduced ->hdmi_cfg.tmds_char_rate driver +data. + +Signed-off-by: Cristian Ciocaltea +Acked-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20250318-phy-sam-hdptx-bpc-v6-13-8cb1678e7663@collabora.com +Signed-off-by: Vinod Koul +--- + .../phy/rockchip/phy-rockchip-samsung-hdptx.c | 47 +++++++++---------- + 1 file changed, 23 insertions(+), 24 deletions(-) + +--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c ++++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c +@@ -970,31 +970,34 @@ static bool rk_hdptx_phy_clk_pll_calc(un + return true; + } + +-static int rk_hdptx_ropll_tmds_cmn_config(struct rk_hdptx_phy *hdptx, +- unsigned long long rate) ++static int rk_hdptx_ropll_tmds_cmn_config(struct rk_hdptx_phy *hdptx) + { + const struct ropll_config *cfg = NULL; + struct ropll_config rc = {0}; + int ret, i; + ++ if (!hdptx->hdmi_cfg.tmds_char_rate) ++ return 0; ++ + for (i = 0; i < ARRAY_SIZE(ropll_tmds_cfg); i++) +- if (rate == ropll_tmds_cfg[i].rate) { ++ if (hdptx->hdmi_cfg.tmds_char_rate == ropll_tmds_cfg[i].rate) { + cfg = &ropll_tmds_cfg[i]; + break; + } + + if (!cfg) { +- if (rk_hdptx_phy_clk_pll_calc(rate, &rc)) { +- cfg = &rc; +- } else { +- dev_err(hdptx->dev, "%s cannot find pll cfg\n", __func__); ++ if (!rk_hdptx_phy_clk_pll_calc(hdptx->hdmi_cfg.tmds_char_rate, &rc)) { ++ dev_err(hdptx->dev, "%s cannot find pll cfg for rate=%llu\n", ++ __func__, hdptx->hdmi_cfg.tmds_char_rate); + return -EINVAL; + } ++ ++ cfg = &rc; + } + + dev_dbg(hdptx->dev, "%s rate=%llu mdiv=%u sdiv=%u sdm_en=%u k_sign=%u k=%u lc=%u\n", +- __func__, rate, cfg->pms_mdiv, cfg->pms_sdiv + 1, cfg->sdm_en, +- cfg->sdm_num_sign, cfg->sdm_num, cfg->sdm_deno); ++ __func__, hdptx->hdmi_cfg.tmds_char_rate, cfg->pms_mdiv, cfg->pms_sdiv + 1, ++ cfg->sdm_en, cfg->sdm_num_sign, cfg->sdm_num, cfg->sdm_deno); + + rk_hdptx_pre_power_up(hdptx); + +@@ -1032,19 +1035,18 @@ static int rk_hdptx_ropll_tmds_cmn_confi + + ret = rk_hdptx_post_enable_pll(hdptx); + if (!ret) +- hdptx->hw_rate = rate; ++ hdptx->hw_rate = hdptx->hdmi_cfg.tmds_char_rate; + + return ret; + } + +-static int rk_hdptx_ropll_tmds_mode_config(struct rk_hdptx_phy *hdptx, +- unsigned long long rate) ++static int rk_hdptx_ropll_tmds_mode_config(struct rk_hdptx_phy *hdptx) + { + rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_common_sb_init_seq); + + regmap_write(hdptx->regmap, LNTOP_REG(0200), 0x06); + +- if (rate > HDMI14_MAX_RATE) { ++ if (hdptx->hdmi_cfg.tmds_char_rate > HDMI14_MAX_RATE) { + /* For 1/40 bitrate clk */ + rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_tmds_lntop_highbr_seq); + } else { +@@ -1096,8 +1098,7 @@ static void rk_hdptx_dp_reset(struct rk_ + HDPTX_I_BGR_EN << 16 | FIELD_PREP(HDPTX_I_BGR_EN, 0x0)); + } + +-static int rk_hdptx_phy_consumer_get(struct rk_hdptx_phy *hdptx, +- unsigned long long rate) ++static int rk_hdptx_phy_consumer_get(struct rk_hdptx_phy *hdptx) + { + enum phy_mode mode = phy_get_mode(hdptx->phy); + u32 status; +@@ -1116,11 +1117,9 @@ static int rk_hdptx_phy_consumer_get(str + if (mode == PHY_MODE_DP) { + rk_hdptx_dp_reset(hdptx); + } else { +- if (rate) { +- ret = rk_hdptx_ropll_tmds_cmn_config(hdptx, rate); +- if (ret) +- goto dec_usage; +- } ++ ret = rk_hdptx_ropll_tmds_cmn_config(hdptx); ++ if (ret) ++ goto dec_usage; + } + + return 0; +@@ -1433,7 +1432,7 @@ static int rk_hdptx_phy_power_on(struct + dev_dbg(hdptx->dev, "%s rate=%llu\n", __func__, hdptx->hdmi_cfg.tmds_char_rate); + } + +- ret = rk_hdptx_phy_consumer_get(hdptx, hdptx->hdmi_cfg.tmds_char_rate); ++ ret = rk_hdptx_phy_consumer_get(hdptx); + if (ret) + return ret; + +@@ -1464,7 +1463,7 @@ static int rk_hdptx_phy_power_on(struct + regmap_write(hdptx->grf, GRF_HDPTX_CON0, + HDPTX_MODE_SEL << 16 | FIELD_PREP(HDPTX_MODE_SEL, 0x0)); + +- ret = rk_hdptx_ropll_tmds_mode_config(hdptx, hdptx->hdmi_cfg.tmds_char_rate); ++ ret = rk_hdptx_ropll_tmds_mode_config(hdptx); + if (ret) + rk_hdptx_phy_consumer_put(hdptx, true); + } +@@ -1832,7 +1831,7 @@ static int rk_hdptx_phy_clk_prepare(stru + { + struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw); + +- return rk_hdptx_phy_consumer_get(hdptx, hdptx->hw_rate); ++ return rk_hdptx_phy_consumer_get(hdptx); + } + + static void rk_hdptx_phy_clk_unprepare(struct clk_hw *hw) +@@ -1899,7 +1898,7 @@ static int rk_hdptx_phy_clk_set_rate(str + * while the latter being executed only once, i.e. when clock remains + * in the prepared state during rate changes. + */ +- return rk_hdptx_ropll_tmds_cmn_config(hdptx, rate); ++ return rk_hdptx_ropll_tmds_cmn_config(hdptx); + } + + static const struct clk_ops hdptx_phy_clk_ops = { diff --git a/target/linux/rockchip/patches-6.12/040-18-v6.16-phy-rockchip-samsung-hdptx-Add-high-color-depth-managemen.patch b/target/linux/rockchip/patches-6.12/040-18-v6.16-phy-rockchip-samsung-hdptx-Add-high-color-depth-managemen.patch new file mode 100644 index 000000000..568419bba --- /dev/null +++ b/target/linux/rockchip/patches-6.12/040-18-v6.16-phy-rockchip-samsung-hdptx-Add-high-color-depth-managemen.patch @@ -0,0 +1,76 @@ +From 9d0ec51d7c227c3ae837e22832eaed219e25f126 Mon Sep 17 00:00:00 2001 +From: Cristian Ciocaltea +Date: Tue, 18 Mar 2025 14:35:48 +0200 +Subject: [PATCH] phy: rockchip: samsung-hdptx: Add high color depth management + +Add support for 8-bit, 10-bit, 12-bit and 16-bit color depth setup. + +Reviewed-by: Dmitry Baryshkov +Signed-off-by: Cristian Ciocaltea +Reviewed-by: Dmitry Baryshkov +Link: https://lore.kernel.org/r/20250318-phy-sam-hdptx-bpc-v6-14-8cb1678e7663@collabora.com +Signed-off-by: Vinod Koul +--- + .../phy/rockchip/phy-rockchip-samsung-hdptx.c | 23 ++++++++++++++++++- + 1 file changed, 22 insertions(+), 1 deletion(-) + +--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c ++++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c +@@ -1030,6 +1030,9 @@ static int rk_hdptx_ropll_tmds_cmn_confi + regmap_update_bits(hdptx->regmap, CMN_REG(0086), PLL_PCG_POSTDIV_SEL_MASK, + FIELD_PREP(PLL_PCG_POSTDIV_SEL_MASK, cfg->pms_sdiv)); + ++ regmap_update_bits(hdptx->regmap, CMN_REG(0086), PLL_PCG_CLK_SEL_MASK, ++ FIELD_PREP(PLL_PCG_CLK_SEL_MASK, (hdptx->hdmi_cfg.bpc - 8) >> 1)); ++ + regmap_update_bits(hdptx->regmap, CMN_REG(0086), PLL_PCG_CLK_EN_MASK, + FIELD_PREP(PLL_PCG_CLK_EN_MASK, 0x1)); + +@@ -1429,7 +1432,8 @@ static int rk_hdptx_phy_power_on(struct + hdptx->hdmi_cfg.tmds_char_rate *= 100; + } + +- dev_dbg(hdptx->dev, "%s rate=%llu\n", __func__, hdptx->hdmi_cfg.tmds_char_rate); ++ dev_dbg(hdptx->dev, "%s rate=%llu bpc=%u\n", __func__, ++ hdptx->hdmi_cfg.tmds_char_rate, hdptx->hdmi_cfg.bpc); + } + + ret = rk_hdptx_phy_consumer_get(hdptx); +@@ -1494,6 +1498,19 @@ static int rk_hdptx_phy_verify_hdmi_conf + !rk_hdptx_phy_clk_pll_calc(hdmi->tmds_char_rate, NULL)) + return -EINVAL; + ++ if (!hdmi->bpc) ++ hdmi->bpc = 8; ++ ++ switch (hdmi->bpc) { ++ case 8: ++ case 10: ++ case 12: ++ case 16: ++ break; ++ default: ++ return -EINVAL; ++ }; ++ + return 0; + } + +@@ -1766,6 +1783,9 @@ static int rk_hdptx_phy_configure(struct + hdptx->hdmi_cfg = opts->hdmi; + hdptx->restrict_rate_change = true; + } ++ ++ dev_dbg(hdptx->dev, "%s rate=%llu bpc=%u\n", __func__, ++ hdptx->hdmi_cfg.tmds_char_rate, hdptx->hdmi_cfg.bpc); + return ret; + } + +@@ -1974,6 +1994,7 @@ static int rk_hdptx_phy_probe(struct pla + return -ENOMEM; + + hdptx->dev = dev; ++ hdptx->hdmi_cfg.bpc = 8; + + regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (IS_ERR(regs)) diff --git a/target/linux/rockchip/patches-6.12/040-55-v6.16-dt-bindings-display-rockchip-analogix-dp-Add-support-for.patch b/target/linux/rockchip/patches-6.12/040-55-v6.16-dt-bindings-display-rockchip-analogix-dp-Add-support-for.patch new file mode 100644 index 000000000..096680e89 --- /dev/null +++ b/target/linux/rockchip/patches-6.12/040-55-v6.16-dt-bindings-display-rockchip-analogix-dp-Add-support-for.patch @@ -0,0 +1,68 @@ +From f855146263b14abadd8d5bd0e280e54fbab3bd18 Mon Sep 17 00:00:00 2001 +From: Damon Ding +Date: Mon, 10 Mar 2025 18:41:10 +0800 +Subject: [PATCH] dt-bindings: display: rockchip: analogix-dp: Add support for + RK3588 + +Compared with RK3288/RK3399, the HBR2 link rate support is the main +improvement of RK3588 eDP TX controller, and there are also two +independent eDP display interfaces on RK3588 Soc. + +The newly added 'apb' reset is to ensure the APB bus of eDP controller +works well on the RK3588 SoC. + +Reviewed-by: Rob Herring (Arm) +Signed-off-by: Damon Ding +Link: https://lore.kernel.org/r/20250310104114.2608063-10-damon.ding@rock-chips.com +Signed-off-by: Dmitry Baryshkov +--- + .../rockchip/rockchip,analogix-dp.yaml | 22 +++++++++++++++++-- + 1 file changed, 20 insertions(+), 2 deletions(-) + +--- a/Documentation/devicetree/bindings/display/rockchip/rockchip,analogix-dp.yaml ++++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,analogix-dp.yaml +@@ -15,6 +15,7 @@ properties: + enum: + - rockchip,rk3288-dp + - rockchip,rk3399-edp ++ - rockchip,rk3588-edp + + clocks: + minItems: 2 +@@ -31,10 +32,14 @@ properties: + maxItems: 1 + + resets: +- maxItems: 1 ++ minItems: 1 ++ maxItems: 2 + + reset-names: +- const: dp ++ minItems: 1 ++ items: ++ - const: dp ++ - const: apb + + rockchip,grf: + $ref: /schemas/types.yaml#/definitions/phandle +@@ -52,6 +57,19 @@ required: + allOf: + - $ref: /schemas/display/bridge/analogix,dp.yaml# + ++ - if: ++ properties: ++ compatible: ++ contains: ++ enum: ++ - rockchip,rk3588-edp ++ then: ++ properties: ++ resets: ++ minItems: 2 ++ reset-names: ++ minItems: 2 ++ + unevaluatedProperties: false + + examples: diff --git a/target/linux/rockchip/patches-6.12/041-01-v6.13-drm-rockchip-dw_hdmi-Filter-modes-based-on-hdmiphy_clk.patch b/target/linux/rockchip/patches-6.12/041-01-v6.13-drm-rockchip-dw_hdmi-Filter-modes-based-on-hdmiphy_clk.patch new file mode 100644 index 000000000..f1c24eceb --- /dev/null +++ b/target/linux/rockchip/patches-6.12/041-01-v6.13-drm-rockchip-dw_hdmi-Filter-modes-based-on-hdmiphy_clk.patch @@ -0,0 +1,92 @@ +From 3303a206ae7474b2f8a5d17d8df9de08bac16ca5 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sun, 8 Sep 2024 14:54:58 +0000 +Subject: [PATCH] drm/rockchip: dw_hdmi: Filter modes based on hdmiphy_clk + +RK3228 and RK3328 clock rate is being validated against a mpll config +table intended for a Synopsys phy, and not the used inno-hdmi-phy. + +Instead get a reference to the hdmiphy clk and validate rates against +it to enable use of HDMI2.0 modes, e.g. 4K@60Hz, on RK3228 and RK3328. + +For Synopsis phy the max_tmds_clock validation is sufficient. + +Signed-off-by: Jonas Karlman +Tested-by: Diederik de Haas # Rock64 +Signed-off-by: Heiko Stuebner +Link: https://patchwork.freedesktop.org/patch/msgid/20240908145511.3331451-2-jonas@kwiboo.se +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 35 ++++++++++----------- + 1 file changed, 17 insertions(+), 18 deletions(-) + +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -76,6 +76,7 @@ struct rockchip_hdmi { + struct rockchip_encoder encoder; + const struct rockchip_hdmi_chip_data *chip_data; + const struct dw_hdmi_plat_data *plat_data; ++ struct clk *hdmiphy_clk; + struct clk *ref_clk; + struct clk *grf_clk; + struct dw_hdmi *hdmi; +@@ -251,10 +252,7 @@ dw_hdmi_rockchip_mode_valid(struct dw_hd + const struct drm_display_mode *mode) + { + struct rockchip_hdmi *hdmi = data; +- const struct dw_hdmi_mpll_config *mpll_cfg = rockchip_mpll_cfg; + int pclk = mode->clock * 1000; +- bool exact_match = hdmi->plat_data->phy_force_vendor; +- int i; + + if (hdmi->chip_data->max_tmds_clock && + mode->clock > hdmi->chip_data->max_tmds_clock) +@@ -263,26 +261,18 @@ dw_hdmi_rockchip_mode_valid(struct dw_hd + if (hdmi->ref_clk) { + int rpclk = clk_round_rate(hdmi->ref_clk, pclk); + +- if (abs(rpclk - pclk) > pclk / 1000) ++ if (rpclk < 0 || abs(rpclk - pclk) > pclk / 1000) + return MODE_NOCLOCK; + } + +- for (i = 0; mpll_cfg[i].mpixelclock != (~0UL); i++) { +- /* +- * For vendor specific phys force an exact match of the pixelclock +- * to preserve the original behaviour of the driver. +- */ +- if (exact_match && pclk == mpll_cfg[i].mpixelclock) +- return MODE_OK; +- /* +- * The Synopsys phy can work with pixelclocks up to the value given +- * in the corresponding mpll_cfg entry. +- */ +- if (!exact_match && pclk <= mpll_cfg[i].mpixelclock) +- return MODE_OK; ++ if (hdmi->hdmiphy_clk) { ++ int rpclk = clk_round_rate(hdmi->hdmiphy_clk, pclk); ++ ++ if (rpclk < 0 || abs(rpclk - pclk) > pclk / 1000) ++ return MODE_NOCLOCK; + } + +- return MODE_BAD; ++ return MODE_OK; + } + + static void dw_hdmi_rockchip_encoder_disable(struct drm_encoder *encoder) +@@ -607,6 +597,15 @@ static int dw_hdmi_rockchip_bind(struct + return ret; + } + ++ if (hdmi->phy) { ++ struct of_phandle_args clkspec; ++ ++ clkspec.np = hdmi->phy->dev.of_node; ++ hdmi->hdmiphy_clk = of_clk_get_from_provider(&clkspec); ++ if (IS_ERR(hdmi->hdmiphy_clk)) ++ hdmi->hdmiphy_clk = NULL; ++ } ++ + if (hdmi->chip_data == &rk3568_chip_data) { + regmap_write(hdmi->regmap, RK3568_GRF_VO_CON1, + HIWORD_UPDATE(RK3568_HDMI_SDAIN_MSK | diff --git a/target/linux/rockchip/patches-6.12/041-02-v6.13-drm-rockchip-dw_hdmi-Adjust-cklvl-txlvl-for-RF-EMI.patch b/target/linux/rockchip/patches-6.12/041-02-v6.13-drm-rockchip-dw_hdmi-Adjust-cklvl-txlvl-for-RF-EMI.patch new file mode 100644 index 000000000..8eed371cc --- /dev/null +++ b/target/linux/rockchip/patches-6.12/041-02-v6.13-drm-rockchip-dw_hdmi-Adjust-cklvl-txlvl-for-RF-EMI.patch @@ -0,0 +1,53 @@ +From 6e94e2871eb706a17692acf7ef85ecf2789f6433 Mon Sep 17 00:00:00 2001 +From: Yakir Yang +Date: Sun, 8 Sep 2024 14:54:59 +0000 +Subject: [PATCH] drm/rockchip: dw_hdmi: Adjust cklvl & txlvl for RF/EMI + +Dut to the high HDMI signal voltage driver, Mickey have meet +a serious RF/EMI problem, so we decided to reduce HDMI signal +voltage to a proper value. + +The default params for phy is cklvl = 20 & txlvl = 13 (RF/EMI failed) + ck: lvl = 13, term=100, vlo = 2.71, vhi=3.14, vswing = 0.43 + tx: lvl = 20, term=100, vlo = 2.81, vhi=3.16, vswing = 0.35 + +1. We decided to reduce voltage value to lower, but VSwing still +keep high, RF/EMI have been improved but still failed. + ck: lvl = 6, term=100, vlo = 2.61, vhi=3.11, vswing = 0.50 + tx: lvl = 6, term=100, vlo = 2.61, vhi=3.11, vswing = 0.50 + +2. We try to keep voltage value and vswing both lower, then RF/EMI +test all passed ;) + ck: lvl = 11, term= 66, vlo = 2.68, vhi=3.09, vswing = 0.40 + tx: lvl = 11, term= 66, vlo = 2.68, vhi=3.09, vswing = 0.40 +When we back to run HDMI different test and single-end test, we see +different test passed, but signle-end test failed. The oscilloscope +show that simgle-end clock's VL value is 1.78v (which remind LowLimit +should not lower then 2.6v). + +3. That's to say there are some different between PHY document and +measure value. And according to experiment 2 results, we need to +higher clock voltage and lower data voltage, then we can keep RF/EMI +satisfied and single-end & differen test passed. + ck: lvl = 9, term=100, vlo = 2.65, vhi=3.12, vswing = 0.47 + tx: lvl = 16, term=100, vlo = 2.75, vhi=3.15, vswing = 0.39 + +Signed-off-by: Yakir Yang +Signed-off-by: Jonas Karlman +Signed-off-by: Heiko Stuebner +Link: https://patchwork.freedesktop.org/patch/msgid/20240908145511.3331451-3-jonas@kwiboo.se +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -202,7 +202,7 @@ static const struct dw_hdmi_curr_ctrl ro + static const struct dw_hdmi_phy_config rockchip_phy_config[] = { + /*pixelclk symbol term vlev*/ + { 74250000, 0x8009, 0x0004, 0x0272}, +- { 148500000, 0x802b, 0x0004, 0x028d}, ++ { 165000000, 0x802b, 0x0004, 0x0209}, + { 297000000, 0x8039, 0x0005, 0x028d}, + { ~0UL, 0x0000, 0x0000, 0x0000} + }; diff --git a/target/linux/rockchip/patches-6.12/041-03-v6.13-drm-rockchip-dw_hdmi-Add-phy_config-for-594Mhz-pixel-cloc.patch b/target/linux/rockchip/patches-6.12/041-03-v6.13-drm-rockchip-dw_hdmi-Add-phy_config-for-594Mhz-pixel-cloc.patch new file mode 100644 index 000000000..5929c58c6 --- /dev/null +++ b/target/linux/rockchip/patches-6.12/041-03-v6.13-drm-rockchip-dw_hdmi-Add-phy_config-for-594Mhz-pixel-cloc.patch @@ -0,0 +1,25 @@ +From b60c86d305f46483d3ed0743e9ec97a76addcabc Mon Sep 17 00:00:00 2001 +From: Nickey Yang +Date: Sun, 8 Sep 2024 14:55:00 +0000 +Subject: [PATCH] drm/rockchip: dw_hdmi: Add phy_config for 594Mhz pixel clock + +Add phy_config for 594Mhz pixel clock used for HDMI2.0 display modes. + +Signed-off-by: Nickey Yang +Signed-off-by: Jonas Karlman +Signed-off-by: Heiko Stuebner +Link: https://patchwork.freedesktop.org/patch/msgid/20240908145511.3331451-4-jonas@kwiboo.se +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -204,6 +204,7 @@ static const struct dw_hdmi_phy_config r + { 74250000, 0x8009, 0x0004, 0x0272}, + { 165000000, 0x802b, 0x0004, 0x0209}, + { 297000000, 0x8039, 0x0005, 0x028d}, ++ { 594000000, 0x8039, 0x0000, 0x019d}, + { ~0UL, 0x0000, 0x0000, 0x0000} + }; + diff --git a/target/linux/rockchip/patches-6.12/041-04-v6.13-drm-rockchip-dw_hdmi-Set-cur_ctr-to-0-always.patch b/target/linux/rockchip/patches-6.12/041-04-v6.13-drm-rockchip-dw_hdmi-Set-cur_ctr-to-0-always.patch new file mode 100644 index 000000000..a7e60e111 --- /dev/null +++ b/target/linux/rockchip/patches-6.12/041-04-v6.13-drm-rockchip-dw_hdmi-Set-cur_ctr-to-0-always.patch @@ -0,0 +1,46 @@ +From 7d324630f3515bd6e11cadeb1d748bd74ecc9664 Mon Sep 17 00:00:00 2001 +From: Douglas Anderson +Date: Sun, 8 Sep 2024 14:55:01 +0000 +Subject: [PATCH] drm/rockchip: dw_hdmi: Set cur_ctr to 0 always + +Jitter was improved by lowering the MPLL bandwidth to account for high +frequency noise in the rk3288 PLL. In each case MPLL bandwidth was +lowered only enough to get us a comfortable margin. We believe that +lowering the bandwidth like this is safe given sufficient testing. + +Signed-off-by: Douglas Anderson +Signed-off-by: Yakir Yang +Signed-off-by: Jonas Karlman +Signed-off-by: Heiko Stuebner +Link: https://patchwork.freedesktop.org/patch/msgid/20240908145511.3331451-5-jonas@kwiboo.se +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 16 +--------------- + 1 file changed, 1 insertion(+), 15 deletions(-) + +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -179,23 +179,9 @@ static const struct dw_hdmi_mpll_config + static const struct dw_hdmi_curr_ctrl rockchip_cur_ctr[] = { + /* pixelclk bpp8 bpp10 bpp12 */ + { +- 40000000, { 0x0018, 0x0018, 0x0018 }, +- }, { +- 65000000, { 0x0028, 0x0028, 0x0028 }, +- }, { +- 66000000, { 0x0038, 0x0038, 0x0038 }, +- }, { +- 74250000, { 0x0028, 0x0038, 0x0038 }, +- }, { +- 83500000, { 0x0028, 0x0038, 0x0038 }, +- }, { +- 146250000, { 0x0038, 0x0038, 0x0038 }, +- }, { +- 148500000, { 0x0000, 0x0038, 0x0038 }, +- }, { + 600000000, { 0x0000, 0x0000, 0x0000 }, + }, { +- ~0UL, { 0x0000, 0x0000, 0x0000}, ++ ~0UL, { 0x0000, 0x0000, 0x0000 }, + } + }; + diff --git a/target/linux/rockchip/patches-6.12/041-05-v6.13-drm-rockchip-dw_hdmi-Use-auto-generated-tables.patch b/target/linux/rockchip/patches-6.12/041-05-v6.13-drm-rockchip-dw_hdmi-Use-auto-generated-tables.patch new file mode 100644 index 000000000..fd5ed90d2 --- /dev/null +++ b/target/linux/rockchip/patches-6.12/041-05-v6.13-drm-rockchip-dw_hdmi-Use-auto-generated-tables.patch @@ -0,0 +1,173 @@ +From 7595c7ef17ffe70d0f4fdda01f87f105a12de66b Mon Sep 17 00:00:00 2001 +From: Douglas Anderson +Date: Sun, 8 Sep 2024 14:55:02 +0000 +Subject: [PATCH] drm/rockchip: dw_hdmi: Use auto-generated tables + +The previous tables for mpll_cfg and curr_ctrl were created using the +20-pages of example settings provided by the PHY vendor. Those +example settings weren't particularly dense, so there were places +where we were guessing what the settings would be for 10-bit and +12-bit (not that we use those anyway). It was also always a lot of +extra work every time we wanted to add a new clock rate since we had +to cross-reference several tables. + +In I've gone through the work to figure +out how to generate this table automatically. Let's now use the +automatically generated table and then we'll never need to look at it +again. + +We only support 8-bit mode right now and only support a small number +of clock rates and I've verified that the only 8-bit rate that was +affected was 148.5. That mode appears to have been wrong in the old +table. + +Signed-off-by: Douglas Anderson +Signed-off-by: Yakir Yang +Signed-off-by: Jonas Karlman +Signed-off-by: Heiko Stuebner +Link: https://patchwork.freedesktop.org/patch/msgid/20240908145511.3331451-6-jonas@kwiboo.se +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 104 ++++++++++---------- + 1 file changed, 53 insertions(+), 51 deletions(-) + +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -92,74 +92,70 @@ static struct rockchip_hdmi *to_rockchip + + static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = { + { +- 27000000, { +- { 0x00b3, 0x0000}, +- { 0x2153, 0x0000}, +- { 0x40f3, 0x0000} ++ 30666000, { ++ { 0x00b3, 0x0000 }, ++ { 0x2153, 0x0000 }, ++ { 0x40f3, 0x0000 }, + }, + }, { +- 36000000, { +- { 0x00b3, 0x0000}, +- { 0x2153, 0x0000}, +- { 0x40f3, 0x0000} ++ 36800000, { ++ { 0x00b3, 0x0000 }, ++ { 0x2153, 0x0000 }, ++ { 0x40a2, 0x0001 }, + }, + }, { +- 40000000, { +- { 0x00b3, 0x0000}, +- { 0x2153, 0x0000}, +- { 0x40f3, 0x0000} ++ 46000000, { ++ { 0x00b3, 0x0000 }, ++ { 0x2142, 0x0001 }, ++ { 0x40a2, 0x0001 }, + }, + }, { +- 54000000, { +- { 0x0072, 0x0001}, +- { 0x2142, 0x0001}, +- { 0x40a2, 0x0001}, ++ 61333000, { ++ { 0x0072, 0x0001 }, ++ { 0x2142, 0x0001 }, ++ { 0x40a2, 0x0001 }, + }, + }, { +- 65000000, { +- { 0x0072, 0x0001}, +- { 0x2142, 0x0001}, +- { 0x40a2, 0x0001}, ++ 73600000, { ++ { 0x0072, 0x0001 }, ++ { 0x2142, 0x0001 }, ++ { 0x4061, 0x0002 }, + }, + }, { +- 66000000, { +- { 0x013e, 0x0003}, +- { 0x217e, 0x0002}, +- { 0x4061, 0x0002} ++ 92000000, { ++ { 0x0072, 0x0001 }, ++ { 0x2145, 0x0002 }, ++ { 0x4061, 0x0002 }, + }, + }, { +- 74250000, { +- { 0x0072, 0x0001}, +- { 0x2145, 0x0002}, +- { 0x4061, 0x0002} ++ 122666000, { ++ { 0x0051, 0x0002 }, ++ { 0x2145, 0x0002 }, ++ { 0x4061, 0x0002 }, + }, + }, { +- 83500000, { +- { 0x0072, 0x0001}, ++ 147200000, { ++ { 0x0051, 0x0002 }, ++ { 0x2145, 0x0002 }, ++ { 0x4064, 0x0003 }, + }, + }, { +- 108000000, { +- { 0x0051, 0x0002}, +- { 0x2145, 0x0002}, +- { 0x4061, 0x0002} ++ 184000000, { ++ { 0x0051, 0x0002 }, ++ { 0x214c, 0x0003 }, ++ { 0x4064, 0x0003 }, + }, + }, { +- 106500000, { +- { 0x0051, 0x0002}, +- { 0x2145, 0x0002}, +- { 0x4061, 0x0002} +- }, +- }, { +- 146250000, { +- { 0x0051, 0x0002}, +- { 0x2145, 0x0002}, +- { 0x4061, 0x0002} ++ 226666000, { ++ { 0x0040, 0x0003 }, ++ { 0x214c, 0x0003 }, ++ { 0x4064, 0x0003 }, + }, + }, { +- 148500000, { +- { 0x0051, 0x0003}, +- { 0x214c, 0x0003}, +- { 0x4064, 0x0003} ++ 272000000, { ++ { 0x0040, 0x0003 }, ++ { 0x214c, 0x0003 }, ++ { 0x5a64, 0x0003 }, + }, + }, { + 340000000, { +@@ -168,10 +164,16 @@ static const struct dw_hdmi_mpll_config + { 0x5a64, 0x0003 }, + }, + }, { ++ 600000000, { ++ { 0x1a40, 0x0003 }, ++ { 0x3b4c, 0x0003 }, ++ { 0x5a64, 0x0003 }, ++ }, ++ }, { + ~0UL, { +- { 0x00a0, 0x000a }, +- { 0x2001, 0x000f }, +- { 0x4002, 0x000f }, ++ { 0x0000, 0x0000 }, ++ { 0x0000, 0x0000 }, ++ { 0x0000, 0x0000 }, + }, + } + }; diff --git a/target/linux/rockchip/patches-6.12/041-06-v6.13-drm-rockchip-dw_hdmi-Enable-4K-60Hz-mode-on-RK3399-and.patch b/target/linux/rockchip/patches-6.12/041-06-v6.13-drm-rockchip-dw_hdmi-Enable-4K-60Hz-mode-on-RK3399-and.patch new file mode 100644 index 000000000..f3398ec66 --- /dev/null +++ b/target/linux/rockchip/patches-6.12/041-06-v6.13-drm-rockchip-dw_hdmi-Enable-4K-60Hz-mode-on-RK3399-and.patch @@ -0,0 +1,37 @@ +From 28f0ae48e7fdbd6cdcf3972c8d8686a529ae1ede Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sun, 8 Sep 2024 14:55:03 +0000 +Subject: [PATCH] drm/rockchip: dw_hdmi: Enable 4K@60Hz mode on RK3399 and + RK356x + +Use a maximum TMDS clock rate limit of 594MHz to enable use of HDMI2.0 +modes, e.g. 4K@60Hz, on RK3399 and RK3568. + +Signed-off-by: Jonas Karlman +Tested-by: Diederik de Haas # Quartz64 Model B +Signed-off-by: Heiko Stuebner +Link: https://patchwork.freedesktop.org/patch/msgid/20240908145511.3331451-7-jonas@kwiboo.se +--- + drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +@@ -481,7 +481,7 @@ static struct rockchip_hdmi_chip_data rk + .lcdsel_grf_reg = RK3399_GRF_SOC_CON20, + .lcdsel_big = HIWORD_UPDATE(0, RK3399_HDMI_LCDC_SEL), + .lcdsel_lit = HIWORD_UPDATE(RK3399_HDMI_LCDC_SEL, RK3399_HDMI_LCDC_SEL), +- .max_tmds_clock = 340000, ++ .max_tmds_clock = 594000, + }; + + static const struct dw_hdmi_plat_data rk3399_hdmi_drv_data = { +@@ -495,7 +495,7 @@ static const struct dw_hdmi_plat_data rk + + static struct rockchip_hdmi_chip_data rk3568_chip_data = { + .lcdsel_grf_reg = -1, +- .max_tmds_clock = 340000, ++ .max_tmds_clock = 594000, + }; + + static const struct dw_hdmi_plat_data rk3568_hdmi_drv_data = { diff --git a/target/linux/rockchip/patches-6.12/041-07-v6.13-drm-rockchip-Load-crtc-devices-in-preferred-order.patch b/target/linux/rockchip/patches-6.12/041-07-v6.13-drm-rockchip-Load-crtc-devices-in-preferred-order.patch new file mode 100644 index 000000000..3eae81af5 --- /dev/null +++ b/target/linux/rockchip/patches-6.12/041-07-v6.13-drm-rockchip-Load-crtc-devices-in-preferred-order.patch @@ -0,0 +1,59 @@ +From 0c4558a1bc2df9b6e6fb311de9cab192b0943426 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sun, 8 Sep 2024 14:55:04 +0000 +Subject: [PATCH] drm/rockchip: Load crtc devices in preferred order + +On RK3399 the VOPL is loaded before VOPB and get registered as crtc-0. +However, on RK3288 and PX30 VOPB is gets registered as crtc-0 instead of +VOPL. + +With VOPL registered as crtc-0 the kernel kms client is not able to +enable 4K display modes for console use on RK3399. + +Load VOPB before VOPL to help kernel kms client make use of 4K display +modes for console use on RK3399. + +Signed-off-by: Jonas Karlman +Signed-off-by: Heiko Stuebner +Link: https://patchwork.freedesktop.org/patch/msgid/20240908145511.3331451-8-jonas@kwiboo.se +--- + drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 23 +++++++++++++++++++++ + 1 file changed, 23 insertions(+) + +--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +@@ -358,11 +358,34 @@ static void rockchip_drm_match_remove(st + device_link_del(link); + } + ++/* list of preferred vop devices */ ++static const char *const rockchip_drm_match_preferred[] = { ++ "rockchip,rk3399-vop-big", ++ NULL, ++}; ++ + static struct component_match *rockchip_drm_match_add(struct device *dev) + { + struct component_match *match = NULL; ++ struct device_node *port; + int i; + ++ /* add preferred vop device match before adding driver device matches */ ++ for (i = 0; ; i++) { ++ port = of_parse_phandle(dev->of_node, "ports", i); ++ if (!port) ++ break; ++ ++ if (of_device_is_available(port->parent) && ++ of_device_compatible_match(port->parent, ++ rockchip_drm_match_preferred)) ++ drm_of_component_match_add(dev, &match, ++ component_compare_of, ++ port->parent); ++ ++ of_node_put(port); ++ } ++ + for (i = 0; i < num_rockchip_sub_drivers; i++) { + struct platform_driver *drv = rockchip_sub_drivers[i]; + struct device *p = NULL, *d; diff --git a/target/linux/rockchip/patches-6.12/041-08-v6.13-drm-rockchip-Run-DRM-default-client-setup.patch b/target/linux/rockchip/patches-6.12/041-08-v6.13-drm-rockchip-Run-DRM-default-client-setup.patch new file mode 100644 index 000000000..1a0cba19f --- /dev/null +++ b/target/linux/rockchip/patches-6.12/041-08-v6.13-drm-rockchip-Run-DRM-default-client-setup.patch @@ -0,0 +1,63 @@ +From 905df8f19e1a7042ddeae1e39d0920b60dfe8c0d Mon Sep 17 00:00:00 2001 +From: Thomas Zimmermann +Date: Tue, 24 Sep 2024 09:12:35 +0200 +Subject: [PATCH] drm/rockchip: Run DRM default client setup +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Call drm_client_setup() to run the kernel's default client setup +for DRM. Set fbdev_probe in struct drm_driver, so that the client +setup can start the common fbdev client. + +v5: +- select DRM_CLIENT_SELECTION + +Signed-off-by: Thomas Zimmermann +Cc: Sandy Huang +Cc: "Heiko St¡§1bner" +Cc: Andy Yan +Acked-by: Heiko Stuebner +Link: https://patchwork.freedesktop.org/patch/msgid/20240924071734.98201-38-tzimmermann@suse.de +--- + drivers/gpu/drm/rockchip/Kconfig | 1 + + drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 4 +++- + 2 files changed, 4 insertions(+), 1 deletion(-) + +--- a/drivers/gpu/drm/rockchip/Kconfig ++++ b/drivers/gpu/drm/rockchip/Kconfig +@@ -2,6 +2,7 @@ + config DRM_ROCKCHIP + tristate "DRM Support for Rockchip" + depends on DRM && ROCKCHIP_IOMMU ++ select DRM_CLIENT_SELECTION + select DRM_GEM_DMA_HELPER + select DRM_KMS_HELPER + select DRM_PANEL +--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +@@ -17,6 +17,7 @@ + #include + + #include ++#include + #include + #include + #include +@@ -195,7 +196,7 @@ static int rockchip_drm_bind(struct devi + if (ret) + goto err_kms_helper_poll_fini; + +- drm_fbdev_dma_setup(drm_dev, 0); ++ drm_client_setup(drm_dev, NULL); + + return 0; + err_kms_helper_poll_fini: +@@ -230,6 +231,7 @@ static const struct drm_driver rockchip_ + .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC, + .dumb_create = rockchip_gem_dumb_create, + .gem_prime_import_sg_table = rockchip_gem_prime_import_sg_table, ++ DRM_FBDEV_DMA_DRIVER_OPS, + .fops = &rockchip_drm_driver_fops, + .name = DRIVER_NAME, + .desc = DRIVER_DESC, diff --git a/target/linux/rockchip/patches-6.12/041-09-v6.13-drm-bridge-synopsys-Add-DW-HDMI-QP-TX-Controller-support.patch b/target/linux/rockchip/patches-6.12/041-09-v6.13-drm-bridge-synopsys-Add-DW-HDMI-QP-TX-Controller-support.patch new file mode 100644 index 000000000..0a7d24f90 --- /dev/null +++ b/target/linux/rockchip/patches-6.12/041-09-v6.13-drm-bridge-synopsys-Add-DW-HDMI-QP-TX-Controller-support.patch @@ -0,0 +1,1592 @@ +From 5bd0d8e687bf04fdd3d4a733a6bb17e25d4a1de2 Mon Sep 17 00:00:00 2001 +From: Cristian Ciocaltea +Date: Wed, 16 Oct 2024 23:06:51 +0300 +Subject: [PATCH] drm/bridge: synopsys: Add DW HDMI QP TX Controller support + library + +The Synopsys DesignWare HDMI 2.1 Quad-Pixel (QP) TX Controller IP +supports the following features, among others: + +* Fixed Rate Link (FRL) +* Display Stream Compression (DSC) +* 4K@120Hz and 8K@60Hz video modes +* Variable Refresh Rate (VRR) including Quick Media Switching (QMS), aka + Cinema VRR +* Fast Vactive (FVA), aka Quick Frame Transport (QFT) +* SCDC I2C DDC access +* TMDS Scrambler enabling 2160p@60Hz with RGB/YCbCr4:4:4 +* YCbCr4:2:0 enabling 2160p@60Hz at lower HDMI link speeds +* Multi-stream audio +* Enhanced Audio Return Channel (EARC) + +Add library containing common helpers to enable basic support, i.e. RGB +output up to 4K@30Hz, without audio, CEC or any HDMI 2.1 specific +features. + +Co-developed-by: Algea Cao +Signed-off-by: Algea Cao +Tested-by: Heiko Stuebner +Reviewed-by: Maxime Ripard +Signed-off-by: Cristian Ciocaltea +Acked-by: Maxime Ripard +Link: https://patchwork.freedesktop.org/patch/msgid/20241016-b4-rk3588-bridge-upstream-v10-1-87ef92a6d14e@collabora.com +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/bridge/synopsys/Kconfig | 8 + + drivers/gpu/drm/bridge/synopsys/Makefile | 2 + + drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 647 ++++++++++++++ + drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.h | 834 +++++++++++++++++++ + include/drm/bridge/dw_hdmi_qp.h | 32 + + 5 files changed, 1523 insertions(+) + create mode 100644 drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c + create mode 100644 drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.h + create mode 100644 include/drm/bridge/dw_hdmi_qp.h + +--- a/drivers/gpu/drm/bridge/synopsys/Kconfig ++++ b/drivers/gpu/drm/bridge/synopsys/Kconfig +@@ -46,6 +46,14 @@ config DRM_DW_HDMI_CEC + Support the CE interface which is part of the Synopsys + Designware HDMI block. + ++config DRM_DW_HDMI_QP ++ tristate ++ select DRM_DISPLAY_HDMI_HELPER ++ select DRM_DISPLAY_HDMI_STATE_HELPER ++ select DRM_DISPLAY_HELPER ++ select DRM_KMS_HELPER ++ select REGMAP_MMIO ++ + config DRM_DW_MIPI_DSI + tristate + select DRM_KMS_HELPER +--- a/drivers/gpu/drm/bridge/synopsys/Makefile ++++ b/drivers/gpu/drm/bridge/synopsys/Makefile +@@ -5,4 +5,6 @@ obj-$(CONFIG_DRM_DW_HDMI_GP_AUDIO) += dw + obj-$(CONFIG_DRM_DW_HDMI_I2S_AUDIO) += dw-hdmi-i2s-audio.o + obj-$(CONFIG_DRM_DW_HDMI_CEC) += dw-hdmi-cec.o + ++obj-$(CONFIG_DRM_DW_HDMI_QP) += dw-hdmi-qp.o ++ + obj-$(CONFIG_DRM_DW_MIPI_DSI) += dw-mipi-dsi.o +--- /dev/null ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c +@@ -0,0 +1,647 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2021-2022 Rockchip Electronics Co., Ltd. ++ * Copyright (c) 2024 Collabora Ltd. ++ * ++ * Author: Algea Cao ++ * Author: Cristian Ciocaltea ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "dw-hdmi-qp.h" ++ ++#define DDC_CI_ADDR 0x37 ++#define DDC_SEGMENT_ADDR 0x30 ++ ++#define HDMI14_MAX_TMDSCLK 340000000 ++ ++#define SCRAMB_POLL_DELAY_MS 3000 ++ ++struct dw_hdmi_qp_i2c { ++ struct i2c_adapter adap; ++ ++ struct mutex lock; /* used to serialize data transfers */ ++ struct completion cmp; ++ u8 stat; ++ ++ u8 slave_reg; ++ bool is_regaddr; ++ bool is_segment; ++}; ++ ++struct dw_hdmi_qp { ++ struct drm_bridge bridge; ++ ++ struct device *dev; ++ struct dw_hdmi_qp_i2c *i2c; ++ ++ struct { ++ const struct dw_hdmi_qp_phy_ops *ops; ++ void *data; ++ } phy; ++ ++ struct regmap *regm; ++}; ++ ++static void dw_hdmi_qp_write(struct dw_hdmi_qp *hdmi, unsigned int val, ++ int offset) ++{ ++ regmap_write(hdmi->regm, offset, val); ++} ++ ++static unsigned int dw_hdmi_qp_read(struct dw_hdmi_qp *hdmi, int offset) ++{ ++ unsigned int val = 0; ++ ++ regmap_read(hdmi->regm, offset, &val); ++ ++ return val; ++} ++ ++static void dw_hdmi_qp_mod(struct dw_hdmi_qp *hdmi, unsigned int data, ++ unsigned int mask, unsigned int reg) ++{ ++ regmap_update_bits(hdmi->regm, reg, mask, data); ++} ++ ++static int dw_hdmi_qp_i2c_read(struct dw_hdmi_qp *hdmi, ++ unsigned char *buf, unsigned int length) ++{ ++ struct dw_hdmi_qp_i2c *i2c = hdmi->i2c; ++ int stat; ++ ++ if (!i2c->is_regaddr) { ++ dev_dbg(hdmi->dev, "set read register address to 0\n"); ++ i2c->slave_reg = 0x00; ++ i2c->is_regaddr = true; ++ } ++ ++ while (length--) { ++ reinit_completion(&i2c->cmp); ++ ++ dw_hdmi_qp_mod(hdmi, i2c->slave_reg++ << 12, I2CM_ADDR, ++ I2CM_INTERFACE_CONTROL0); ++ ++ if (i2c->is_segment) ++ dw_hdmi_qp_mod(hdmi, I2CM_EXT_READ, I2CM_WR_MASK, ++ I2CM_INTERFACE_CONTROL0); ++ else ++ dw_hdmi_qp_mod(hdmi, I2CM_FM_READ, I2CM_WR_MASK, ++ I2CM_INTERFACE_CONTROL0); ++ ++ stat = wait_for_completion_timeout(&i2c->cmp, HZ / 10); ++ if (!stat) { ++ dev_err(hdmi->dev, "i2c read timed out\n"); ++ dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0); ++ return -EAGAIN; ++ } ++ ++ /* Check for error condition on the bus */ ++ if (i2c->stat & I2CM_NACK_RCVD_IRQ) { ++ dev_err(hdmi->dev, "i2c read error\n"); ++ dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0); ++ return -EIO; ++ } ++ ++ *buf++ = dw_hdmi_qp_read(hdmi, I2CM_INTERFACE_RDDATA_0_3) & 0xff; ++ dw_hdmi_qp_mod(hdmi, 0, I2CM_WR_MASK, I2CM_INTERFACE_CONTROL0); ++ } ++ ++ i2c->is_segment = false; ++ ++ return 0; ++} ++ ++static int dw_hdmi_qp_i2c_write(struct dw_hdmi_qp *hdmi, ++ unsigned char *buf, unsigned int length) ++{ ++ struct dw_hdmi_qp_i2c *i2c = hdmi->i2c; ++ int stat; ++ ++ if (!i2c->is_regaddr) { ++ /* Use the first write byte as register address */ ++ i2c->slave_reg = buf[0]; ++ length--; ++ buf++; ++ i2c->is_regaddr = true; ++ } ++ ++ while (length--) { ++ reinit_completion(&i2c->cmp); ++ ++ dw_hdmi_qp_write(hdmi, *buf++, I2CM_INTERFACE_WRDATA_0_3); ++ dw_hdmi_qp_mod(hdmi, i2c->slave_reg++ << 12, I2CM_ADDR, ++ I2CM_INTERFACE_CONTROL0); ++ dw_hdmi_qp_mod(hdmi, I2CM_FM_WRITE, I2CM_WR_MASK, ++ I2CM_INTERFACE_CONTROL0); ++ ++ stat = wait_for_completion_timeout(&i2c->cmp, HZ / 10); ++ if (!stat) { ++ dev_err(hdmi->dev, "i2c write time out!\n"); ++ dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0); ++ return -EAGAIN; ++ } ++ ++ /* Check for error condition on the bus */ ++ if (i2c->stat & I2CM_NACK_RCVD_IRQ) { ++ dev_err(hdmi->dev, "i2c write nack!\n"); ++ dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0); ++ return -EIO; ++ } ++ ++ dw_hdmi_qp_mod(hdmi, 0, I2CM_WR_MASK, I2CM_INTERFACE_CONTROL0); ++ } ++ ++ return 0; ++} ++ ++static int dw_hdmi_qp_i2c_xfer(struct i2c_adapter *adap, ++ struct i2c_msg *msgs, int num) ++{ ++ struct dw_hdmi_qp *hdmi = i2c_get_adapdata(adap); ++ struct dw_hdmi_qp_i2c *i2c = hdmi->i2c; ++ u8 addr = msgs[0].addr; ++ int i, ret = 0; ++ ++ if (addr == DDC_CI_ADDR) ++ /* ++ * The internal I2C controller does not support the multi-byte ++ * read and write operations needed for DDC/CI. ++ * FIXME: Blacklist the DDC/CI address until we filter out ++ * unsupported I2C operations. ++ */ ++ return -EOPNOTSUPP; ++ ++ for (i = 0; i < num; i++) { ++ if (msgs[i].len == 0) { ++ dev_err(hdmi->dev, ++ "unsupported transfer %d/%d, no data\n", ++ i + 1, num); ++ return -EOPNOTSUPP; ++ } ++ } ++ ++ guard(mutex)(&i2c->lock); ++ ++ /* Unmute DONE and ERROR interrupts */ ++ dw_hdmi_qp_mod(hdmi, I2CM_NACK_RCVD_MASK_N | I2CM_OP_DONE_MASK_N, ++ I2CM_NACK_RCVD_MASK_N | I2CM_OP_DONE_MASK_N, ++ MAINUNIT_1_INT_MASK_N); ++ ++ /* Set slave device address taken from the first I2C message */ ++ if (addr == DDC_SEGMENT_ADDR && msgs[0].len == 1) ++ addr = DDC_ADDR; ++ ++ dw_hdmi_qp_mod(hdmi, addr << 5, I2CM_SLVADDR, I2CM_INTERFACE_CONTROL0); ++ ++ /* Set slave device register address on transfer */ ++ i2c->is_regaddr = false; ++ ++ /* Set segment pointer for I2C extended read mode operation */ ++ i2c->is_segment = false; ++ ++ for (i = 0; i < num; i++) { ++ if (msgs[i].addr == DDC_SEGMENT_ADDR && msgs[i].len == 1) { ++ i2c->is_segment = true; ++ dw_hdmi_qp_mod(hdmi, DDC_SEGMENT_ADDR, I2CM_SEG_ADDR, ++ I2CM_INTERFACE_CONTROL1); ++ dw_hdmi_qp_mod(hdmi, *msgs[i].buf << 7, I2CM_SEG_PTR, ++ I2CM_INTERFACE_CONTROL1); ++ } else { ++ if (msgs[i].flags & I2C_M_RD) ++ ret = dw_hdmi_qp_i2c_read(hdmi, msgs[i].buf, ++ msgs[i].len); ++ else ++ ret = dw_hdmi_qp_i2c_write(hdmi, msgs[i].buf, ++ msgs[i].len); ++ } ++ if (ret < 0) ++ break; ++ } ++ ++ if (!ret) ++ ret = num; ++ ++ /* Mute DONE and ERROR interrupts */ ++ dw_hdmi_qp_mod(hdmi, 0, I2CM_OP_DONE_MASK_N | I2CM_NACK_RCVD_MASK_N, ++ MAINUNIT_1_INT_MASK_N); ++ ++ return ret; ++} ++ ++static u32 dw_hdmi_qp_i2c_func(struct i2c_adapter *adapter) ++{ ++ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; ++} ++ ++static const struct i2c_algorithm dw_hdmi_qp_algorithm = { ++ .master_xfer = dw_hdmi_qp_i2c_xfer, ++ .functionality = dw_hdmi_qp_i2c_func, ++}; ++ ++static struct i2c_adapter *dw_hdmi_qp_i2c_adapter(struct dw_hdmi_qp *hdmi) ++{ ++ struct dw_hdmi_qp_i2c *i2c; ++ struct i2c_adapter *adap; ++ int ret; ++ ++ i2c = devm_kzalloc(hdmi->dev, sizeof(*i2c), GFP_KERNEL); ++ if (!i2c) ++ return ERR_PTR(-ENOMEM); ++ ++ mutex_init(&i2c->lock); ++ init_completion(&i2c->cmp); ++ ++ adap = &i2c->adap; ++ adap->owner = THIS_MODULE; ++ adap->dev.parent = hdmi->dev; ++ adap->algo = &dw_hdmi_qp_algorithm; ++ strscpy(adap->name, "DesignWare HDMI QP", sizeof(adap->name)); ++ ++ i2c_set_adapdata(adap, hdmi); ++ ++ ret = devm_i2c_add_adapter(hdmi->dev, adap); ++ if (ret) { ++ dev_warn(hdmi->dev, "cannot add %s I2C adapter\n", adap->name); ++ devm_kfree(hdmi->dev, i2c); ++ return ERR_PTR(ret); ++ } ++ ++ hdmi->i2c = i2c; ++ dev_info(hdmi->dev, "registered %s I2C bus driver\n", adap->name); ++ ++ return adap; ++} ++ ++static int dw_hdmi_qp_config_avi_infoframe(struct dw_hdmi_qp *hdmi, ++ const u8 *buffer, size_t len) ++{ ++ u32 val, i, j; ++ ++ if (len != HDMI_INFOFRAME_SIZE(AVI)) { ++ dev_err(hdmi->dev, "failed to configure avi infoframe\n"); ++ return -EINVAL; ++ } ++ ++ /* ++ * DW HDMI QP IP uses a different byte format from standard AVI info ++ * frames, though generally the bits are in the correct bytes. ++ */ ++ val = buffer[1] << 8 | buffer[2] << 16; ++ dw_hdmi_qp_write(hdmi, val, PKT_AVI_CONTENTS0); ++ ++ for (i = 0; i < 4; i++) { ++ for (j = 0; j < 4; j++) { ++ if (i * 4 + j >= 14) ++ break; ++ if (!j) ++ val = buffer[i * 4 + j + 3]; ++ val |= buffer[i * 4 + j + 3] << (8 * j); ++ } ++ ++ dw_hdmi_qp_write(hdmi, val, PKT_AVI_CONTENTS1 + i * 4); ++ } ++ ++ dw_hdmi_qp_mod(hdmi, 0, PKTSCHED_AVI_FIELDRATE, PKTSCHED_PKT_CONFIG1); ++ ++ dw_hdmi_qp_mod(hdmi, PKTSCHED_AVI_TX_EN | PKTSCHED_GCP_TX_EN, ++ PKTSCHED_AVI_TX_EN | PKTSCHED_GCP_TX_EN, PKTSCHED_PKT_EN); ++ ++ return 0; ++} ++ ++static int dw_hdmi_qp_config_drm_infoframe(struct dw_hdmi_qp *hdmi, ++ const u8 *buffer, size_t len) ++{ ++ u32 val, i; ++ ++ if (len != HDMI_INFOFRAME_SIZE(DRM)) { ++ dev_err(hdmi->dev, "failed to configure drm infoframe\n"); ++ return -EINVAL; ++ } ++ ++ dw_hdmi_qp_mod(hdmi, 0, PKTSCHED_DRMI_TX_EN, PKTSCHED_PKT_EN); ++ ++ val = buffer[1] << 8 | buffer[2] << 16; ++ dw_hdmi_qp_write(hdmi, val, PKT_DRMI_CONTENTS0); ++ ++ for (i = 0; i <= buffer[2]; i++) { ++ if (i % 4 == 0) ++ val = buffer[3 + i]; ++ val |= buffer[3 + i] << ((i % 4) * 8); ++ ++ if ((i % 4 == 3) || i == buffer[2]) ++ dw_hdmi_qp_write(hdmi, val, ++ PKT_DRMI_CONTENTS1 + ((i / 4) * 4)); ++ } ++ ++ dw_hdmi_qp_mod(hdmi, 0, PKTSCHED_DRMI_FIELDRATE, PKTSCHED_PKT_CONFIG1); ++ dw_hdmi_qp_mod(hdmi, PKTSCHED_DRMI_TX_EN, PKTSCHED_DRMI_TX_EN, ++ PKTSCHED_PKT_EN); ++ ++ return 0; ++} ++ ++static int dw_hdmi_qp_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) ++{ ++ struct dw_hdmi_qp *hdmi = bridge->driver_private; ++ int ret; ++ ++ ret = drm_atomic_helper_connector_hdmi_check(conn_state->connector, ++ conn_state->state); ++ if (ret) ++ dev_dbg(hdmi->dev, "%s failed: %d\n", __func__, ret); ++ ++ return ret; ++} ++ ++static void dw_hdmi_qp_bridge_atomic_enable(struct drm_bridge *bridge, ++ struct drm_bridge_state *old_state) ++{ ++ struct dw_hdmi_qp *hdmi = bridge->driver_private; ++ struct drm_atomic_state *state = old_state->base.state; ++ struct drm_connector_state *conn_state; ++ struct drm_connector *connector; ++ unsigned int op_mode; ++ ++ connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder); ++ if (WARN_ON(!connector)) ++ return; ++ ++ conn_state = drm_atomic_get_new_connector_state(state, connector); ++ if (WARN_ON(!conn_state)) ++ return; ++ ++ if (connector->display_info.is_hdmi) { ++ dev_dbg(hdmi->dev, "%s mode=HDMI rate=%llu\n", ++ __func__, conn_state->hdmi.tmds_char_rate); ++ op_mode = 0; ++ } else { ++ dev_dbg(hdmi->dev, "%s mode=DVI\n", __func__); ++ op_mode = OPMODE_DVI; ++ } ++ ++ hdmi->phy.ops->init(hdmi, hdmi->phy.data); ++ ++ dw_hdmi_qp_mod(hdmi, HDCP2_BYPASS, HDCP2_BYPASS, HDCP2LOGIC_CONFIG0); ++ dw_hdmi_qp_mod(hdmi, op_mode, OPMODE_DVI, LINK_CONFIG0); ++ ++ drm_atomic_helper_connector_hdmi_update_infoframes(connector, state); ++} ++ ++static void dw_hdmi_qp_bridge_atomic_disable(struct drm_bridge *bridge, ++ struct drm_bridge_state *old_state) ++{ ++ struct dw_hdmi_qp *hdmi = bridge->driver_private; ++ ++ hdmi->phy.ops->disable(hdmi, hdmi->phy.data); ++} ++ ++static enum drm_connector_status ++dw_hdmi_qp_bridge_detect(struct drm_bridge *bridge) ++{ ++ struct dw_hdmi_qp *hdmi = bridge->driver_private; ++ ++ return hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data); ++} ++ ++static const struct drm_edid * ++dw_hdmi_qp_bridge_edid_read(struct drm_bridge *bridge, ++ struct drm_connector *connector) ++{ ++ struct dw_hdmi_qp *hdmi = bridge->driver_private; ++ const struct drm_edid *drm_edid; ++ ++ drm_edid = drm_edid_read_ddc(connector, bridge->ddc); ++ if (!drm_edid) ++ dev_dbg(hdmi->dev, "failed to get edid\n"); ++ ++ return drm_edid; ++} ++ ++static enum drm_mode_status ++dw_hdmi_qp_bridge_mode_valid(struct drm_bridge *bridge, ++ const struct drm_display_info *info, ++ const struct drm_display_mode *mode) ++{ ++ struct dw_hdmi_qp *hdmi = bridge->driver_private; ++ unsigned long long rate; ++ ++ rate = drm_hdmi_compute_mode_clock(mode, 8, HDMI_COLORSPACE_RGB); ++ if (rate > HDMI14_MAX_TMDSCLK) { ++ dev_dbg(hdmi->dev, "Unsupported mode clock: %d\n", mode->clock); ++ return MODE_CLOCK_HIGH; ++ } ++ ++ return MODE_OK; ++} ++ ++static int dw_hdmi_qp_bridge_clear_infoframe(struct drm_bridge *bridge, ++ enum hdmi_infoframe_type type) ++{ ++ struct dw_hdmi_qp *hdmi = bridge->driver_private; ++ ++ switch (type) { ++ case HDMI_INFOFRAME_TYPE_AVI: ++ dw_hdmi_qp_mod(hdmi, 0, PKTSCHED_AVI_TX_EN | PKTSCHED_GCP_TX_EN, ++ PKTSCHED_PKT_EN); ++ break; ++ ++ case HDMI_INFOFRAME_TYPE_DRM: ++ dw_hdmi_qp_mod(hdmi, 0, PKTSCHED_DRMI_TX_EN, PKTSCHED_PKT_EN); ++ break; ++ ++ default: ++ dev_dbg(hdmi->dev, "Unsupported infoframe type %x\n", type); ++ } ++ ++ return 0; ++} ++ ++static int dw_hdmi_qp_bridge_write_infoframe(struct drm_bridge *bridge, ++ enum hdmi_infoframe_type type, ++ const u8 *buffer, size_t len) ++{ ++ struct dw_hdmi_qp *hdmi = bridge->driver_private; ++ ++ dw_hdmi_qp_bridge_clear_infoframe(bridge, type); ++ ++ switch (type) { ++ case HDMI_INFOFRAME_TYPE_AVI: ++ return dw_hdmi_qp_config_avi_infoframe(hdmi, buffer, len); ++ ++ case HDMI_INFOFRAME_TYPE_DRM: ++ return dw_hdmi_qp_config_drm_infoframe(hdmi, buffer, len); ++ ++ default: ++ dev_dbg(hdmi->dev, "Unsupported infoframe type %x\n", type); ++ return 0; ++ } ++} ++ ++static const struct drm_bridge_funcs dw_hdmi_qp_bridge_funcs = { ++ .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, ++ .atomic_check = dw_hdmi_qp_bridge_atomic_check, ++ .atomic_enable = dw_hdmi_qp_bridge_atomic_enable, ++ .atomic_disable = dw_hdmi_qp_bridge_atomic_disable, ++ .detect = dw_hdmi_qp_bridge_detect, ++ .edid_read = dw_hdmi_qp_bridge_edid_read, ++ .mode_valid = dw_hdmi_qp_bridge_mode_valid, ++ .hdmi_clear_infoframe = dw_hdmi_qp_bridge_clear_infoframe, ++ .hdmi_write_infoframe = dw_hdmi_qp_bridge_write_infoframe, ++}; ++ ++static irqreturn_t dw_hdmi_qp_main_hardirq(int irq, void *dev_id) ++{ ++ struct dw_hdmi_qp *hdmi = dev_id; ++ struct dw_hdmi_qp_i2c *i2c = hdmi->i2c; ++ u32 stat; ++ ++ stat = dw_hdmi_qp_read(hdmi, MAINUNIT_1_INT_STATUS); ++ ++ i2c->stat = stat & (I2CM_OP_DONE_IRQ | I2CM_READ_REQUEST_IRQ | ++ I2CM_NACK_RCVD_IRQ); ++ ++ if (i2c->stat) { ++ dw_hdmi_qp_write(hdmi, i2c->stat, MAINUNIT_1_INT_CLEAR); ++ complete(&i2c->cmp); ++ } ++ ++ if (stat) ++ return IRQ_HANDLED; ++ ++ return IRQ_NONE; ++} ++ ++static const struct regmap_config dw_hdmi_qp_regmap_config = { ++ .reg_bits = 32, ++ .val_bits = 32, ++ .reg_stride = 4, ++ .max_register = EARCRX_1_INT_FORCE, ++}; ++ ++static void dw_hdmi_qp_init_hw(struct dw_hdmi_qp *hdmi) ++{ ++ dw_hdmi_qp_write(hdmi, 0, MAINUNIT_0_INT_MASK_N); ++ dw_hdmi_qp_write(hdmi, 0, MAINUNIT_1_INT_MASK_N); ++ dw_hdmi_qp_write(hdmi, 428571429, TIMER_BASE_CONFIG0); ++ ++ /* Software reset */ ++ dw_hdmi_qp_write(hdmi, 0x01, I2CM_CONTROL0); ++ ++ dw_hdmi_qp_write(hdmi, 0x085c085c, I2CM_FM_SCL_CONFIG0); ++ ++ dw_hdmi_qp_mod(hdmi, 0, I2CM_FM_EN, I2CM_INTERFACE_CONTROL0); ++ ++ /* Clear DONE and ERROR interrupts */ ++ dw_hdmi_qp_write(hdmi, I2CM_OP_DONE_CLEAR | I2CM_NACK_RCVD_CLEAR, ++ MAINUNIT_1_INT_CLEAR); ++ ++ if (hdmi->phy.ops->setup_hpd) ++ hdmi->phy.ops->setup_hpd(hdmi, hdmi->phy.data); ++} ++ ++struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev, ++ struct drm_encoder *encoder, ++ const struct dw_hdmi_qp_plat_data *plat_data) ++{ ++ struct device *dev = &pdev->dev; ++ struct dw_hdmi_qp *hdmi; ++ void __iomem *regs; ++ int ret; ++ ++ if (!plat_data->phy_ops || !plat_data->phy_ops->init || ++ !plat_data->phy_ops->disable || !plat_data->phy_ops->read_hpd) { ++ dev_err(dev, "Missing platform PHY ops\n"); ++ return ERR_PTR(-ENODEV); ++ } ++ ++ hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL); ++ if (!hdmi) ++ return ERR_PTR(-ENOMEM); ++ ++ hdmi->dev = dev; ++ ++ regs = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(regs)) ++ return ERR_CAST(regs); ++ ++ hdmi->regm = devm_regmap_init_mmio(dev, regs, &dw_hdmi_qp_regmap_config); ++ if (IS_ERR(hdmi->regm)) { ++ dev_err(dev, "Failed to configure regmap\n"); ++ return ERR_CAST(hdmi->regm); ++ } ++ ++ hdmi->phy.ops = plat_data->phy_ops; ++ hdmi->phy.data = plat_data->phy_data; ++ ++ dw_hdmi_qp_init_hw(hdmi); ++ ++ ret = devm_request_threaded_irq(dev, plat_data->main_irq, ++ dw_hdmi_qp_main_hardirq, NULL, ++ IRQF_SHARED, dev_name(dev), hdmi); ++ if (ret) ++ return ERR_PTR(ret); ++ ++ hdmi->bridge.driver_private = hdmi; ++ hdmi->bridge.funcs = &dw_hdmi_qp_bridge_funcs; ++ hdmi->bridge.ops = DRM_BRIDGE_OP_DETECT | ++ DRM_BRIDGE_OP_EDID | ++ DRM_BRIDGE_OP_HDMI | ++ DRM_BRIDGE_OP_HPD; ++ hdmi->bridge.of_node = pdev->dev.of_node; ++ hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA; ++ hdmi->bridge.vendor = "Synopsys"; ++ hdmi->bridge.product = "DW HDMI QP TX"; ++ ++ hdmi->bridge.ddc = dw_hdmi_qp_i2c_adapter(hdmi); ++ if (IS_ERR(hdmi->bridge.ddc)) ++ return ERR_CAST(hdmi->bridge.ddc); ++ ++ ret = devm_drm_bridge_add(dev, &hdmi->bridge); ++ if (ret) ++ return ERR_PTR(ret); ++ ++ ret = drm_bridge_attach(encoder, &hdmi->bridge, NULL, ++ DRM_BRIDGE_ATTACH_NO_CONNECTOR); ++ if (ret) ++ return ERR_PTR(ret); ++ ++ return hdmi; ++} ++EXPORT_SYMBOL_GPL(dw_hdmi_qp_bind); ++ ++void dw_hdmi_qp_resume(struct device *dev, struct dw_hdmi_qp *hdmi) ++{ ++ dw_hdmi_qp_init_hw(hdmi); ++} ++EXPORT_SYMBOL_GPL(dw_hdmi_qp_resume); ++ ++MODULE_AUTHOR("Algea Cao "); ++MODULE_AUTHOR("Cristian Ciocaltea "); ++MODULE_DESCRIPTION("DW HDMI QP transmitter library"); ++MODULE_LICENSE("GPL"); +--- /dev/null ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.h +@@ -0,0 +1,834 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) Rockchip Electronics Co.Ltd ++ * Author: ++ * Algea Cao ++ */ ++#ifndef __DW_HDMI_QP_H__ ++#define __DW_HDMI_QP_H__ ++ ++#include ++ ++/* Main Unit Registers */ ++#define CORE_ID 0x0 ++#define VER_NUMBER 0x4 ++#define VER_TYPE 0x8 ++#define CONFIG_REG 0xc ++#define CONFIG_CEC BIT(28) ++#define CONFIG_AUD_UD BIT(23) ++#define CORE_TIMESTAMP_HHMM 0x14 ++#define CORE_TIMESTAMP_MMDD 0x18 ++#define CORE_TIMESTAMP_YYYY 0x1c ++/* Reset Manager Registers */ ++#define GLOBAL_SWRESET_REQUEST 0x40 ++#define EARCRX_CMDC_SWINIT_P BIT(27) ++#define AVP_DATAPATH_PACKET_AUDIO_SWINIT_P BIT(10) ++#define GLOBAL_SWDISABLE 0x44 ++#define CEC_SWDISABLE BIT(17) ++#define AVP_DATAPATH_PACKET_AUDIO_SWDISABLE BIT(10) ++#define AVP_DATAPATH_VIDEO_SWDISABLE BIT(6) ++#define RESET_MANAGER_CONFIG0 0x48 ++#define RESET_MANAGER_STATUS0 0x50 ++#define RESET_MANAGER_STATUS1 0x54 ++#define RESET_MANAGER_STATUS2 0x58 ++/* Timer Base Registers */ ++#define TIMER_BASE_CONFIG0 0x80 ++#define TIMER_BASE_STATUS0 0x84 ++/* CMU Registers */ ++#define CMU_CONFIG0 0xa0 ++#define CMU_CONFIG1 0xa4 ++#define CMU_CONFIG2 0xa8 ++#define CMU_CONFIG3 0xac ++#define CMU_STATUS 0xb0 ++#define DISPLAY_CLK_MONITOR 0x3f ++#define DISPLAY_CLK_LOCKED 0X15 ++#define EARC_BPCLK_OFF BIT(9) ++#define AUDCLK_OFF BIT(7) ++#define LINKQPCLK_OFF BIT(5) ++#define VIDQPCLK_OFF BIT(3) ++#define IPI_CLK_OFF BIT(1) ++#define CMU_IPI_CLK_FREQ 0xb4 ++#define CMU_VIDQPCLK_FREQ 0xb8 ++#define CMU_LINKQPCLK_FREQ 0xbc ++#define CMU_AUDQPCLK_FREQ 0xc0 ++#define CMU_EARC_BPCLK_FREQ 0xc4 ++/* I2CM Registers */ ++#define I2CM_SM_SCL_CONFIG0 0xe0 ++#define I2CM_FM_SCL_CONFIG0 0xe4 ++#define I2CM_CONFIG0 0xe8 ++#define I2CM_CONTROL0 0xec ++#define I2CM_STATUS0 0xf0 ++#define I2CM_INTERFACE_CONTROL0 0xf4 ++#define I2CM_ADDR 0xff000 ++#define I2CM_SLVADDR 0xfe0 ++#define I2CM_WR_MASK 0x1e ++#define I2CM_EXT_READ BIT(4) ++#define I2CM_SHORT_READ BIT(3) ++#define I2CM_FM_READ BIT(2) ++#define I2CM_FM_WRITE BIT(1) ++#define I2CM_FM_EN BIT(0) ++#define I2CM_INTERFACE_CONTROL1 0xf8 ++#define I2CM_SEG_PTR 0x7f80 ++#define I2CM_SEG_ADDR 0x7f ++#define I2CM_INTERFACE_WRDATA_0_3 0xfc ++#define I2CM_INTERFACE_WRDATA_4_7 0x100 ++#define I2CM_INTERFACE_WRDATA_8_11 0x104 ++#define I2CM_INTERFACE_WRDATA_12_15 0x108 ++#define I2CM_INTERFACE_RDDATA_0_3 0x10c ++#define I2CM_INTERFACE_RDDATA_4_7 0x110 ++#define I2CM_INTERFACE_RDDATA_8_11 0x114 ++#define I2CM_INTERFACE_RDDATA_12_15 0x118 ++/* SCDC Registers */ ++#define SCDC_CONFIG0 0x140 ++#define SCDC_I2C_FM_EN BIT(12) ++#define SCDC_UPD_FLAGS_AUTO_CLR BIT(6) ++#define SCDC_UPD_FLAGS_POLL_EN BIT(4) ++#define SCDC_CONTROL0 0x148 ++#define SCDC_STATUS0 0x150 ++#define STATUS_UPDATE BIT(0) ++#define FRL_START BIT(4) ++#define FLT_UPDATE BIT(5) ++/* FLT Registers */ ++#define FLT_CONFIG0 0x160 ++#define FLT_CONFIG1 0x164 ++#define FLT_CONFIG2 0x168 ++#define FLT_CONTROL0 0x170 ++/* Main Unit 2 Registers */ ++#define MAINUNIT_STATUS0 0x180 ++/* Video Interface Registers */ ++#define VIDEO_INTERFACE_CONFIG0 0x800 ++#define VIDEO_INTERFACE_CONFIG1 0x804 ++#define VIDEO_INTERFACE_CONFIG2 0x808 ++#define VIDEO_INTERFACE_CONTROL0 0x80c ++#define VIDEO_INTERFACE_STATUS0 0x814 ++/* Video Packing Registers */ ++#define VIDEO_PACKING_CONFIG0 0x81c ++/* Audio Interface Registers */ ++#define AUDIO_INTERFACE_CONFIG0 0x820 ++#define AUD_IF_SEL_MSK 0x3 ++#define AUD_IF_SPDIF 0x2 ++#define AUD_IF_I2S 0x1 ++#define AUD_IF_PAI 0x0 ++#define AUD_FIFO_INIT_ON_OVF_MSK BIT(2) ++#define AUD_FIFO_INIT_ON_OVF_EN BIT(2) ++#define I2S_LINES_EN_MSK GENMASK(7, 4) ++#define I2S_LINES_EN(x) BIT((x) + 4) ++#define I2S_BPCUV_RCV_MSK BIT(12) ++#define I2S_BPCUV_RCV_EN BIT(12) ++#define I2S_BPCUV_RCV_DIS 0 ++#define SPDIF_LINES_EN GENMASK(19, 16) ++#define AUD_FORMAT_MSK GENMASK(26, 24) ++#define AUD_3DOBA (0x7 << 24) ++#define AUD_3DASP (0x6 << 24) ++#define AUD_MSOBA (0x5 << 24) ++#define AUD_MSASP (0x4 << 24) ++#define AUD_HBR (0x3 << 24) ++#define AUD_DST (0x2 << 24) ++#define AUD_OBA (0x1 << 24) ++#define AUD_ASP (0x0 << 24) ++#define AUDIO_INTERFACE_CONFIG1 0x824 ++#define AUDIO_INTERFACE_CONTROL0 0x82c ++#define AUDIO_FIFO_CLR_P BIT(0) ++#define AUDIO_INTERFACE_STATUS0 0x834 ++/* Frame Composer Registers */ ++#define FRAME_COMPOSER_CONFIG0 0x840 ++#define FRAME_COMPOSER_CONFIG1 0x844 ++#define FRAME_COMPOSER_CONFIG2 0x848 ++#define FRAME_COMPOSER_CONFIG3 0x84c ++#define FRAME_COMPOSER_CONFIG4 0x850 ++#define FRAME_COMPOSER_CONFIG5 0x854 ++#define FRAME_COMPOSER_CONFIG6 0x858 ++#define FRAME_COMPOSER_CONFIG7 0x85c ++#define FRAME_COMPOSER_CONFIG8 0x860 ++#define FRAME_COMPOSER_CONFIG9 0x864 ++#define FRAME_COMPOSER_CONTROL0 0x86c ++/* Video Monitor Registers */ ++#define VIDEO_MONITOR_CONFIG0 0x880 ++#define VIDEO_MONITOR_STATUS0 0x884 ++#define VIDEO_MONITOR_STATUS1 0x888 ++#define VIDEO_MONITOR_STATUS2 0x88c ++#define VIDEO_MONITOR_STATUS3 0x890 ++#define VIDEO_MONITOR_STATUS4 0x894 ++#define VIDEO_MONITOR_STATUS5 0x898 ++#define VIDEO_MONITOR_STATUS6 0x89c ++/* HDCP2 Logic Registers */ ++#define HDCP2LOGIC_CONFIG0 0x8e0 ++#define HDCP2_BYPASS BIT(0) ++#define HDCP2LOGIC_ESM_GPIO_IN 0x8e4 ++#define HDCP2LOGIC_ESM_GPIO_OUT 0x8e8 ++/* HDCP14 Registers */ ++#define HDCP14_CONFIG0 0x900 ++#define HDCP14_CONFIG1 0x904 ++#define HDCP14_CONFIG2 0x908 ++#define HDCP14_CONFIG3 0x90c ++#define HDCP14_KEY_SEED 0x914 ++#define HDCP14_KEY_H 0x918 ++#define HDCP14_KEY_L 0x91c ++#define HDCP14_KEY_STATUS 0x920 ++#define HDCP14_AKSV_H 0x924 ++#define HDCP14_AKSV_L 0x928 ++#define HDCP14_AN_H 0x92c ++#define HDCP14_AN_L 0x930 ++#define HDCP14_STATUS0 0x934 ++#define HDCP14_STATUS1 0x938 ++/* Scrambler Registers */ ++#define SCRAMB_CONFIG0 0x960 ++/* Video Configuration Registers */ ++#define LINK_CONFIG0 0x968 ++#define OPMODE_FRL_4LANES BIT(8) ++#define OPMODE_DVI BIT(4) ++#define OPMODE_FRL BIT(0) ++/* TMDS FIFO Registers */ ++#define TMDS_FIFO_CONFIG0 0x970 ++#define TMDS_FIFO_CONTROL0 0x974 ++/* FRL RSFEC Registers */ ++#define FRL_RSFEC_CONFIG0 0xa20 ++#define FRL_RSFEC_STATUS0 0xa30 ++/* FRL Packetizer Registers */ ++#define FRL_PKTZ_CONFIG0 0xa40 ++#define FRL_PKTZ_CONTROL0 0xa44 ++#define FRL_PKTZ_CONTROL1 0xa50 ++#define FRL_PKTZ_STATUS1 0xa54 ++/* Packet Scheduler Registers */ ++#define PKTSCHED_CONFIG0 0xa80 ++#define PKTSCHED_PRQUEUE0_CONFIG0 0xa84 ++#define PKTSCHED_PRQUEUE1_CONFIG0 0xa88 ++#define PKTSCHED_PRQUEUE2_CONFIG0 0xa8c ++#define PKTSCHED_PRQUEUE2_CONFIG1 0xa90 ++#define PKTSCHED_PRQUEUE2_CONFIG2 0xa94 ++#define PKTSCHED_PKT_CONFIG0 0xa98 ++#define PKTSCHED_PKT_CONFIG1 0xa9c ++#define PKTSCHED_DRMI_FIELDRATE BIT(13) ++#define PKTSCHED_AVI_FIELDRATE BIT(12) ++#define PKTSCHED_PKT_CONFIG2 0xaa0 ++#define PKTSCHED_PKT_CONFIG3 0xaa4 ++#define PKTSCHED_PKT_EN 0xaa8 ++#define PKTSCHED_DRMI_TX_EN BIT(17) ++#define PKTSCHED_AUDI_TX_EN BIT(15) ++#define PKTSCHED_AVI_TX_EN BIT(13) ++#define PKTSCHED_EMP_CVTEM_TX_EN BIT(10) ++#define PKTSCHED_AMD_TX_EN BIT(8) ++#define PKTSCHED_GCP_TX_EN BIT(3) ++#define PKTSCHED_AUDS_TX_EN BIT(2) ++#define PKTSCHED_ACR_TX_EN BIT(1) ++#define PKTSCHED_NULL_TX_EN BIT(0) ++#define PKTSCHED_PKT_CONTROL0 0xaac ++#define PKTSCHED_PKT_SEND 0xab0 ++#define PKTSCHED_PKT_STATUS0 0xab4 ++#define PKTSCHED_PKT_STATUS1 0xab8 ++#define PKT_NULL_CONTENTS0 0xb00 ++#define PKT_NULL_CONTENTS1 0xb04 ++#define PKT_NULL_CONTENTS2 0xb08 ++#define PKT_NULL_CONTENTS3 0xb0c ++#define PKT_NULL_CONTENTS4 0xb10 ++#define PKT_NULL_CONTENTS5 0xb14 ++#define PKT_NULL_CONTENTS6 0xb18 ++#define PKT_NULL_CONTENTS7 0xb1c ++#define PKT_ACP_CONTENTS0 0xb20 ++#define PKT_ACP_CONTENTS1 0xb24 ++#define PKT_ACP_CONTENTS2 0xb28 ++#define PKT_ACP_CONTENTS3 0xb2c ++#define PKT_ACP_CONTENTS4 0xb30 ++#define PKT_ACP_CONTENTS5 0xb34 ++#define PKT_ACP_CONTENTS6 0xb38 ++#define PKT_ACP_CONTENTS7 0xb3c ++#define PKT_ISRC1_CONTENTS0 0xb40 ++#define PKT_ISRC1_CONTENTS1 0xb44 ++#define PKT_ISRC1_CONTENTS2 0xb48 ++#define PKT_ISRC1_CONTENTS3 0xb4c ++#define PKT_ISRC1_CONTENTS4 0xb50 ++#define PKT_ISRC1_CONTENTS5 0xb54 ++#define PKT_ISRC1_CONTENTS6 0xb58 ++#define PKT_ISRC1_CONTENTS7 0xb5c ++#define PKT_ISRC2_CONTENTS0 0xb60 ++#define PKT_ISRC2_CONTENTS1 0xb64 ++#define PKT_ISRC2_CONTENTS2 0xb68 ++#define PKT_ISRC2_CONTENTS3 0xb6c ++#define PKT_ISRC2_CONTENTS4 0xb70 ++#define PKT_ISRC2_CONTENTS5 0xb74 ++#define PKT_ISRC2_CONTENTS6 0xb78 ++#define PKT_ISRC2_CONTENTS7 0xb7c ++#define PKT_GMD_CONTENTS0 0xb80 ++#define PKT_GMD_CONTENTS1 0xb84 ++#define PKT_GMD_CONTENTS2 0xb88 ++#define PKT_GMD_CONTENTS3 0xb8c ++#define PKT_GMD_CONTENTS4 0xb90 ++#define PKT_GMD_CONTENTS5 0xb94 ++#define PKT_GMD_CONTENTS6 0xb98 ++#define PKT_GMD_CONTENTS7 0xb9c ++#define PKT_AMD_CONTENTS0 0xba0 ++#define PKT_AMD_CONTENTS1 0xba4 ++#define PKT_AMD_CONTENTS2 0xba8 ++#define PKT_AMD_CONTENTS3 0xbac ++#define PKT_AMD_CONTENTS4 0xbb0 ++#define PKT_AMD_CONTENTS5 0xbb4 ++#define PKT_AMD_CONTENTS6 0xbb8 ++#define PKT_AMD_CONTENTS7 0xbbc ++#define PKT_VSI_CONTENTS0 0xbc0 ++#define PKT_VSI_CONTENTS1 0xbc4 ++#define PKT_VSI_CONTENTS2 0xbc8 ++#define PKT_VSI_CONTENTS3 0xbcc ++#define PKT_VSI_CONTENTS4 0xbd0 ++#define PKT_VSI_CONTENTS5 0xbd4 ++#define PKT_VSI_CONTENTS6 0xbd8 ++#define PKT_VSI_CONTENTS7 0xbdc ++#define PKT_AVI_CONTENTS0 0xbe0 ++#define HDMI_FC_AVICONF0_ACTIVE_FMT_INFO_PRESENT BIT(4) ++#define HDMI_FC_AVICONF0_BAR_DATA_VERT_BAR 0x04 ++#define HDMI_FC_AVICONF0_BAR_DATA_HORIZ_BAR 0x08 ++#define HDMI_FC_AVICONF2_IT_CONTENT_VALID 0x80 ++#define PKT_AVI_CONTENTS1 0xbe4 ++#define PKT_AVI_CONTENTS2 0xbe8 ++#define PKT_AVI_CONTENTS3 0xbec ++#define PKT_AVI_CONTENTS4 0xbf0 ++#define PKT_AVI_CONTENTS5 0xbf4 ++#define PKT_AVI_CONTENTS6 0xbf8 ++#define PKT_AVI_CONTENTS7 0xbfc ++#define PKT_SPDI_CONTENTS0 0xc00 ++#define PKT_SPDI_CONTENTS1 0xc04 ++#define PKT_SPDI_CONTENTS2 0xc08 ++#define PKT_SPDI_CONTENTS3 0xc0c ++#define PKT_SPDI_CONTENTS4 0xc10 ++#define PKT_SPDI_CONTENTS5 0xc14 ++#define PKT_SPDI_CONTENTS6 0xc18 ++#define PKT_SPDI_CONTENTS7 0xc1c ++#define PKT_AUDI_CONTENTS0 0xc20 ++#define PKT_AUDI_CONTENTS1 0xc24 ++#define PKT_AUDI_CONTENTS2 0xc28 ++#define PKT_AUDI_CONTENTS3 0xc2c ++#define PKT_AUDI_CONTENTS4 0xc30 ++#define PKT_AUDI_CONTENTS5 0xc34 ++#define PKT_AUDI_CONTENTS6 0xc38 ++#define PKT_AUDI_CONTENTS7 0xc3c ++#define PKT_NVI_CONTENTS0 0xc40 ++#define PKT_NVI_CONTENTS1 0xc44 ++#define PKT_NVI_CONTENTS2 0xc48 ++#define PKT_NVI_CONTENTS3 0xc4c ++#define PKT_NVI_CONTENTS4 0xc50 ++#define PKT_NVI_CONTENTS5 0xc54 ++#define PKT_NVI_CONTENTS6 0xc58 ++#define PKT_NVI_CONTENTS7 0xc5c ++#define PKT_DRMI_CONTENTS0 0xc60 ++#define PKT_DRMI_CONTENTS1 0xc64 ++#define PKT_DRMI_CONTENTS2 0xc68 ++#define PKT_DRMI_CONTENTS3 0xc6c ++#define PKT_DRMI_CONTENTS4 0xc70 ++#define PKT_DRMI_CONTENTS5 0xc74 ++#define PKT_DRMI_CONTENTS6 0xc78 ++#define PKT_DRMI_CONTENTS7 0xc7c ++#define PKT_GHDMI1_CONTENTS0 0xc80 ++#define PKT_GHDMI1_CONTENTS1 0xc84 ++#define PKT_GHDMI1_CONTENTS2 0xc88 ++#define PKT_GHDMI1_CONTENTS3 0xc8c ++#define PKT_GHDMI1_CONTENTS4 0xc90 ++#define PKT_GHDMI1_CONTENTS5 0xc94 ++#define PKT_GHDMI1_CONTENTS6 0xc98 ++#define PKT_GHDMI1_CONTENTS7 0xc9c ++#define PKT_GHDMI2_CONTENTS0 0xca0 ++#define PKT_GHDMI2_CONTENTS1 0xca4 ++#define PKT_GHDMI2_CONTENTS2 0xca8 ++#define PKT_GHDMI2_CONTENTS3 0xcac ++#define PKT_GHDMI2_CONTENTS4 0xcb0 ++#define PKT_GHDMI2_CONTENTS5 0xcb4 ++#define PKT_GHDMI2_CONTENTS6 0xcb8 ++#define PKT_GHDMI2_CONTENTS7 0xcbc ++/* EMP Packetizer Registers */ ++#define PKT_EMP_CONFIG0 0xce0 ++#define PKT_EMP_CONTROL0 0xcec ++#define PKT_EMP_CONTROL1 0xcf0 ++#define PKT_EMP_CONTROL2 0xcf4 ++#define PKT_EMP_VTEM_CONTENTS0 0xd00 ++#define PKT_EMP_VTEM_CONTENTS1 0xd04 ++#define PKT_EMP_VTEM_CONTENTS2 0xd08 ++#define PKT_EMP_VTEM_CONTENTS3 0xd0c ++#define PKT_EMP_VTEM_CONTENTS4 0xd10 ++#define PKT_EMP_VTEM_CONTENTS5 0xd14 ++#define PKT_EMP_VTEM_CONTENTS6 0xd18 ++#define PKT_EMP_VTEM_CONTENTS7 0xd1c ++#define PKT0_EMP_CVTEM_CONTENTS0 0xd20 ++#define PKT0_EMP_CVTEM_CONTENTS1 0xd24 ++#define PKT0_EMP_CVTEM_CONTENTS2 0xd28 ++#define PKT0_EMP_CVTEM_CONTENTS3 0xd2c ++#define PKT0_EMP_CVTEM_CONTENTS4 0xd30 ++#define PKT0_EMP_CVTEM_CONTENTS5 0xd34 ++#define PKT0_EMP_CVTEM_CONTENTS6 0xd38 ++#define PKT0_EMP_CVTEM_CONTENTS7 0xd3c ++#define PKT1_EMP_CVTEM_CONTENTS0 0xd40 ++#define PKT1_EMP_CVTEM_CONTENTS1 0xd44 ++#define PKT1_EMP_CVTEM_CONTENTS2 0xd48 ++#define PKT1_EMP_CVTEM_CONTENTS3 0xd4c ++#define PKT1_EMP_CVTEM_CONTENTS4 0xd50 ++#define PKT1_EMP_CVTEM_CONTENTS5 0xd54 ++#define PKT1_EMP_CVTEM_CONTENTS6 0xd58 ++#define PKT1_EMP_CVTEM_CONTENTS7 0xd5c ++#define PKT2_EMP_CVTEM_CONTENTS0 0xd60 ++#define PKT2_EMP_CVTEM_CONTENTS1 0xd64 ++#define PKT2_EMP_CVTEM_CONTENTS2 0xd68 ++#define PKT2_EMP_CVTEM_CONTENTS3 0xd6c ++#define PKT2_EMP_CVTEM_CONTENTS4 0xd70 ++#define PKT2_EMP_CVTEM_CONTENTS5 0xd74 ++#define PKT2_EMP_CVTEM_CONTENTS6 0xd78 ++#define PKT2_EMP_CVTEM_CONTENTS7 0xd7c ++#define PKT3_EMP_CVTEM_CONTENTS0 0xd80 ++#define PKT3_EMP_CVTEM_CONTENTS1 0xd84 ++#define PKT3_EMP_CVTEM_CONTENTS2 0xd88 ++#define PKT3_EMP_CVTEM_CONTENTS3 0xd8c ++#define PKT3_EMP_CVTEM_CONTENTS4 0xd90 ++#define PKT3_EMP_CVTEM_CONTENTS5 0xd94 ++#define PKT3_EMP_CVTEM_CONTENTS6 0xd98 ++#define PKT3_EMP_CVTEM_CONTENTS7 0xd9c ++#define PKT4_EMP_CVTEM_CONTENTS0 0xda0 ++#define PKT4_EMP_CVTEM_CONTENTS1 0xda4 ++#define PKT4_EMP_CVTEM_CONTENTS2 0xda8 ++#define PKT4_EMP_CVTEM_CONTENTS3 0xdac ++#define PKT4_EMP_CVTEM_CONTENTS4 0xdb0 ++#define PKT4_EMP_CVTEM_CONTENTS5 0xdb4 ++#define PKT4_EMP_CVTEM_CONTENTS6 0xdb8 ++#define PKT4_EMP_CVTEM_CONTENTS7 0xdbc ++#define PKT5_EMP_CVTEM_CONTENTS0 0xdc0 ++#define PKT5_EMP_CVTEM_CONTENTS1 0xdc4 ++#define PKT5_EMP_CVTEM_CONTENTS2 0xdc8 ++#define PKT5_EMP_CVTEM_CONTENTS3 0xdcc ++#define PKT5_EMP_CVTEM_CONTENTS4 0xdd0 ++#define PKT5_EMP_CVTEM_CONTENTS5 0xdd4 ++#define PKT5_EMP_CVTEM_CONTENTS6 0xdd8 ++#define PKT5_EMP_CVTEM_CONTENTS7 0xddc ++/* Audio Packetizer Registers */ ++#define AUDPKT_CONTROL0 0xe20 ++#define AUDPKT_PBIT_FORCE_EN_MASK BIT(12) ++#define AUDPKT_PBIT_FORCE_EN BIT(12) ++#define AUDPKT_CHSTATUS_OVR_EN_MASK BIT(0) ++#define AUDPKT_CHSTATUS_OVR_EN BIT(0) ++#define AUDPKT_CONTROL1 0xe24 ++#define AUDPKT_ACR_CONTROL0 0xe40 ++#define AUDPKT_ACR_N_VALUE 0xfffff ++#define AUDPKT_ACR_CONTROL1 0xe44 ++#define AUDPKT_ACR_CTS_OVR_VAL_MSK GENMASK(23, 4) ++#define AUDPKT_ACR_CTS_OVR_VAL(x) ((x) << 4) ++#define AUDPKT_ACR_CTS_OVR_EN_MSK BIT(1) ++#define AUDPKT_ACR_CTS_OVR_EN BIT(1) ++#define AUDPKT_ACR_STATUS0 0xe4c ++#define AUDPKT_CHSTATUS_OVR0 0xe60 ++#define AUDPKT_CHSTATUS_OVR1 0xe64 ++/* IEC60958 Byte 3: Sampleing frenuency Bits 24 to 27 */ ++#define AUDPKT_CHSTATUS_SR_MASK GENMASK(3, 0) ++#define AUDPKT_CHSTATUS_SR_22050 0x4 ++#define AUDPKT_CHSTATUS_SR_24000 0x6 ++#define AUDPKT_CHSTATUS_SR_32000 0x3 ++#define AUDPKT_CHSTATUS_SR_44100 0x0 ++#define AUDPKT_CHSTATUS_SR_48000 0x2 ++#define AUDPKT_CHSTATUS_SR_88200 0x8 ++#define AUDPKT_CHSTATUS_SR_96000 0xa ++#define AUDPKT_CHSTATUS_SR_176400 0xc ++#define AUDPKT_CHSTATUS_SR_192000 0xe ++#define AUDPKT_CHSTATUS_SR_768000 0x9 ++#define AUDPKT_CHSTATUS_SR_NOT_INDICATED 0x1 ++/* IEC60958 Byte 4: Original Sampleing frenuency Bits 36 to 39 */ ++#define AUDPKT_CHSTATUS_0SR_MASK GENMASK(15, 12) ++#define AUDPKT_CHSTATUS_OSR_8000 0x6 ++#define AUDPKT_CHSTATUS_OSR_11025 0xa ++#define AUDPKT_CHSTATUS_OSR_12000 0x2 ++#define AUDPKT_CHSTATUS_OSR_16000 0x8 ++#define AUDPKT_CHSTATUS_OSR_22050 0xb ++#define AUDPKT_CHSTATUS_OSR_24000 0x9 ++#define AUDPKT_CHSTATUS_OSR_32000 0xc ++#define AUDPKT_CHSTATUS_OSR_44100 0xf ++#define AUDPKT_CHSTATUS_OSR_48000 0xd ++#define AUDPKT_CHSTATUS_OSR_88200 0x7 ++#define AUDPKT_CHSTATUS_OSR_96000 0x5 ++#define AUDPKT_CHSTATUS_OSR_176400 0x3 ++#define AUDPKT_CHSTATUS_OSR_192000 0x1 ++#define AUDPKT_CHSTATUS_OSR_NOT_INDICATED 0x0 ++#define AUDPKT_CHSTATUS_OVR2 0xe68 ++#define AUDPKT_CHSTATUS_OVR3 0xe6c ++#define AUDPKT_CHSTATUS_OVR4 0xe70 ++#define AUDPKT_CHSTATUS_OVR5 0xe74 ++#define AUDPKT_CHSTATUS_OVR6 0xe78 ++#define AUDPKT_CHSTATUS_OVR7 0xe7c ++#define AUDPKT_CHSTATUS_OVR8 0xe80 ++#define AUDPKT_CHSTATUS_OVR9 0xe84 ++#define AUDPKT_CHSTATUS_OVR10 0xe88 ++#define AUDPKT_CHSTATUS_OVR11 0xe8c ++#define AUDPKT_CHSTATUS_OVR12 0xe90 ++#define AUDPKT_CHSTATUS_OVR13 0xe94 ++#define AUDPKT_CHSTATUS_OVR14 0xe98 ++#define AUDPKT_USRDATA_OVR_MSG_GENERIC0 0xea0 ++#define AUDPKT_USRDATA_OVR_MSG_GENERIC1 0xea4 ++#define AUDPKT_USRDATA_OVR_MSG_GENERIC2 0xea8 ++#define AUDPKT_USRDATA_OVR_MSG_GENERIC3 0xeac ++#define AUDPKT_USRDATA_OVR_MSG_GENERIC4 0xeb0 ++#define AUDPKT_USRDATA_OVR_MSG_GENERIC5 0xeb4 ++#define AUDPKT_USRDATA_OVR_MSG_GENERIC6 0xeb8 ++#define AUDPKT_USRDATA_OVR_MSG_GENERIC7 0xebc ++#define AUDPKT_USRDATA_OVR_MSG_GENERIC8 0xec0 ++#define AUDPKT_USRDATA_OVR_MSG_GENERIC9 0xec4 ++#define AUDPKT_USRDATA_OVR_MSG_GENERIC10 0xec8 ++#define AUDPKT_USRDATA_OVR_MSG_GENERIC11 0xecc ++#define AUDPKT_USRDATA_OVR_MSG_GENERIC12 0xed0 ++#define AUDPKT_USRDATA_OVR_MSG_GENERIC13 0xed4 ++#define AUDPKT_USRDATA_OVR_MSG_GENERIC14 0xed8 ++#define AUDPKT_USRDATA_OVR_MSG_GENERIC15 0xedc ++#define AUDPKT_USRDATA_OVR_MSG_GENERIC16 0xee0 ++#define AUDPKT_USRDATA_OVR_MSG_GENERIC17 0xee4 ++#define AUDPKT_USRDATA_OVR_MSG_GENERIC18 0xee8 ++#define AUDPKT_USRDATA_OVR_MSG_GENERIC19 0xeec ++#define AUDPKT_USRDATA_OVR_MSG_GENERIC20 0xef0 ++#define AUDPKT_USRDATA_OVR_MSG_GENERIC21 0xef4 ++#define AUDPKT_USRDATA_OVR_MSG_GENERIC22 0xef8 ++#define AUDPKT_USRDATA_OVR_MSG_GENERIC23 0xefc ++#define AUDPKT_USRDATA_OVR_MSG_GENERIC24 0xf00 ++#define AUDPKT_USRDATA_OVR_MSG_GENERIC25 0xf04 ++#define AUDPKT_USRDATA_OVR_MSG_GENERIC26 0xf08 ++#define AUDPKT_USRDATA_OVR_MSG_GENERIC27 0xf0c ++#define AUDPKT_USRDATA_OVR_MSG_GENERIC28 0xf10 ++#define AUDPKT_USRDATA_OVR_MSG_GENERIC29 0xf14 ++#define AUDPKT_USRDATA_OVR_MSG_GENERIC30 0xf18 ++#define AUDPKT_USRDATA_OVR_MSG_GENERIC31 0xf1c ++#define AUDPKT_USRDATA_OVR_MSG_GENERIC32 0xf20 ++#define AUDPKT_VBIT_OVR0 0xf24 ++/* CEC Registers */ ++#define CEC_TX_CONTROL 0x1000 ++#define CEC_STATUS 0x1004 ++#define CEC_CONFIG 0x1008 ++#define CEC_ADDR 0x100c ++#define CEC_TX_COUNT 0x1020 ++#define CEC_TX_DATA3_0 0x1024 ++#define CEC_TX_DATA7_4 0x1028 ++#define CEC_TX_DATA11_8 0x102c ++#define CEC_TX_DATA15_12 0x1030 ++#define CEC_RX_COUNT_STATUS 0x1040 ++#define CEC_RX_DATA3_0 0x1044 ++#define CEC_RX_DATA7_4 0x1048 ++#define CEC_RX_DATA11_8 0x104c ++#define CEC_RX_DATA15_12 0x1050 ++#define CEC_LOCK_CONTROL 0x1054 ++#define CEC_RXQUAL_BITTIME_CONFIG 0x1060 ++#define CEC_RX_BITTIME_CONFIG 0x1064 ++#define CEC_TX_BITTIME_CONFIG 0x1068 ++/* eARC RX CMDC Registers */ ++#define EARCRX_CMDC_CONFIG0 0x1800 ++#define EARCRX_XACTREAD_STOP_CFG BIT(26) ++#define EARCRX_XACTREAD_RETRY_CFG BIT(25) ++#define EARCRX_CMDC_DSCVR_EARCVALID0_TO_DISC1 BIT(24) ++#define EARCRX_CMDC_XACT_RESTART_EN BIT(18) ++#define EARCRX_CMDC_CONFIG1 0x1804 ++#define EARCRX_CMDC_CONTROL 0x1808 ++#define EARCRX_CMDC_HEARTBEAT_LOSS_EN BIT(4) ++#define EARCRX_CMDC_DISCOVERY_EN BIT(3) ++#define EARCRX_CONNECTOR_HPD BIT(1) ++#define EARCRX_CMDC_WHITELIST0_CONFIG 0x180c ++#define EARCRX_CMDC_WHITELIST1_CONFIG 0x1810 ++#define EARCRX_CMDC_WHITELIST2_CONFIG 0x1814 ++#define EARCRX_CMDC_WHITELIST3_CONFIG 0x1818 ++#define EARCRX_CMDC_STATUS 0x181c ++#define EARCRX_CMDC_XACT_INFO 0x1820 ++#define EARCRX_CMDC_XACT_ACTION 0x1824 ++#define EARCRX_CMDC_HEARTBEAT_RXSTAT_SE 0x1828 ++#define EARCRX_CMDC_HEARTBEAT_STATUS 0x182c ++#define EARCRX_CMDC_XACT_WR0 0x1840 ++#define EARCRX_CMDC_XACT_WR1 0x1844 ++#define EARCRX_CMDC_XACT_WR2 0x1848 ++#define EARCRX_CMDC_XACT_WR3 0x184c ++#define EARCRX_CMDC_XACT_WR4 0x1850 ++#define EARCRX_CMDC_XACT_WR5 0x1854 ++#define EARCRX_CMDC_XACT_WR6 0x1858 ++#define EARCRX_CMDC_XACT_WR7 0x185c ++#define EARCRX_CMDC_XACT_WR8 0x1860 ++#define EARCRX_CMDC_XACT_WR9 0x1864 ++#define EARCRX_CMDC_XACT_WR10 0x1868 ++#define EARCRX_CMDC_XACT_WR11 0x186c ++#define EARCRX_CMDC_XACT_WR12 0x1870 ++#define EARCRX_CMDC_XACT_WR13 0x1874 ++#define EARCRX_CMDC_XACT_WR14 0x1878 ++#define EARCRX_CMDC_XACT_WR15 0x187c ++#define EARCRX_CMDC_XACT_WR16 0x1880 ++#define EARCRX_CMDC_XACT_WR17 0x1884 ++#define EARCRX_CMDC_XACT_WR18 0x1888 ++#define EARCRX_CMDC_XACT_WR19 0x188c ++#define EARCRX_CMDC_XACT_WR20 0x1890 ++#define EARCRX_CMDC_XACT_WR21 0x1894 ++#define EARCRX_CMDC_XACT_WR22 0x1898 ++#define EARCRX_CMDC_XACT_WR23 0x189c ++#define EARCRX_CMDC_XACT_WR24 0x18a0 ++#define EARCRX_CMDC_XACT_WR25 0x18a4 ++#define EARCRX_CMDC_XACT_WR26 0x18a8 ++#define EARCRX_CMDC_XACT_WR27 0x18ac ++#define EARCRX_CMDC_XACT_WR28 0x18b0 ++#define EARCRX_CMDC_XACT_WR29 0x18b4 ++#define EARCRX_CMDC_XACT_WR30 0x18b8 ++#define EARCRX_CMDC_XACT_WR31 0x18bc ++#define EARCRX_CMDC_XACT_WR32 0x18c0 ++#define EARCRX_CMDC_XACT_WR33 0x18c4 ++#define EARCRX_CMDC_XACT_WR34 0x18c8 ++#define EARCRX_CMDC_XACT_WR35 0x18cc ++#define EARCRX_CMDC_XACT_WR36 0x18d0 ++#define EARCRX_CMDC_XACT_WR37 0x18d4 ++#define EARCRX_CMDC_XACT_WR38 0x18d8 ++#define EARCRX_CMDC_XACT_WR39 0x18dc ++#define EARCRX_CMDC_XACT_WR40 0x18e0 ++#define EARCRX_CMDC_XACT_WR41 0x18e4 ++#define EARCRX_CMDC_XACT_WR42 0x18e8 ++#define EARCRX_CMDC_XACT_WR43 0x18ec ++#define EARCRX_CMDC_XACT_WR44 0x18f0 ++#define EARCRX_CMDC_XACT_WR45 0x18f4 ++#define EARCRX_CMDC_XACT_WR46 0x18f8 ++#define EARCRX_CMDC_XACT_WR47 0x18fc ++#define EARCRX_CMDC_XACT_WR48 0x1900 ++#define EARCRX_CMDC_XACT_WR49 0x1904 ++#define EARCRX_CMDC_XACT_WR50 0x1908 ++#define EARCRX_CMDC_XACT_WR51 0x190c ++#define EARCRX_CMDC_XACT_WR52 0x1910 ++#define EARCRX_CMDC_XACT_WR53 0x1914 ++#define EARCRX_CMDC_XACT_WR54 0x1918 ++#define EARCRX_CMDC_XACT_WR55 0x191c ++#define EARCRX_CMDC_XACT_WR56 0x1920 ++#define EARCRX_CMDC_XACT_WR57 0x1924 ++#define EARCRX_CMDC_XACT_WR58 0x1928 ++#define EARCRX_CMDC_XACT_WR59 0x192c ++#define EARCRX_CMDC_XACT_WR60 0x1930 ++#define EARCRX_CMDC_XACT_WR61 0x1934 ++#define EARCRX_CMDC_XACT_WR62 0x1938 ++#define EARCRX_CMDC_XACT_WR63 0x193c ++#define EARCRX_CMDC_XACT_WR64 0x1940 ++#define EARCRX_CMDC_XACT_RD0 0x1960 ++#define EARCRX_CMDC_XACT_RD1 0x1964 ++#define EARCRX_CMDC_XACT_RD2 0x1968 ++#define EARCRX_CMDC_XACT_RD3 0x196c ++#define EARCRX_CMDC_XACT_RD4 0x1970 ++#define EARCRX_CMDC_XACT_RD5 0x1974 ++#define EARCRX_CMDC_XACT_RD6 0x1978 ++#define EARCRX_CMDC_XACT_RD7 0x197c ++#define EARCRX_CMDC_XACT_RD8 0x1980 ++#define EARCRX_CMDC_XACT_RD9 0x1984 ++#define EARCRX_CMDC_XACT_RD10 0x1988 ++#define EARCRX_CMDC_XACT_RD11 0x198c ++#define EARCRX_CMDC_XACT_RD12 0x1990 ++#define EARCRX_CMDC_XACT_RD13 0x1994 ++#define EARCRX_CMDC_XACT_RD14 0x1998 ++#define EARCRX_CMDC_XACT_RD15 0x199c ++#define EARCRX_CMDC_XACT_RD16 0x19a0 ++#define EARCRX_CMDC_XACT_RD17 0x19a4 ++#define EARCRX_CMDC_XACT_RD18 0x19a8 ++#define EARCRX_CMDC_XACT_RD19 0x19ac ++#define EARCRX_CMDC_XACT_RD20 0x19b0 ++#define EARCRX_CMDC_XACT_RD21 0x19b4 ++#define EARCRX_CMDC_XACT_RD22 0x19b8 ++#define EARCRX_CMDC_XACT_RD23 0x19bc ++#define EARCRX_CMDC_XACT_RD24 0x19c0 ++#define EARCRX_CMDC_XACT_RD25 0x19c4 ++#define EARCRX_CMDC_XACT_RD26 0x19c8 ++#define EARCRX_CMDC_XACT_RD27 0x19cc ++#define EARCRX_CMDC_XACT_RD28 0x19d0 ++#define EARCRX_CMDC_XACT_RD29 0x19d4 ++#define EARCRX_CMDC_XACT_RD30 0x19d8 ++#define EARCRX_CMDC_XACT_RD31 0x19dc ++#define EARCRX_CMDC_XACT_RD32 0x19e0 ++#define EARCRX_CMDC_XACT_RD33 0x19e4 ++#define EARCRX_CMDC_XACT_RD34 0x19e8 ++#define EARCRX_CMDC_XACT_RD35 0x19ec ++#define EARCRX_CMDC_XACT_RD36 0x19f0 ++#define EARCRX_CMDC_XACT_RD37 0x19f4 ++#define EARCRX_CMDC_XACT_RD38 0x19f8 ++#define EARCRX_CMDC_XACT_RD39 0x19fc ++#define EARCRX_CMDC_XACT_RD40 0x1a00 ++#define EARCRX_CMDC_XACT_RD41 0x1a04 ++#define EARCRX_CMDC_XACT_RD42 0x1a08 ++#define EARCRX_CMDC_XACT_RD43 0x1a0c ++#define EARCRX_CMDC_XACT_RD44 0x1a10 ++#define EARCRX_CMDC_XACT_RD45 0x1a14 ++#define EARCRX_CMDC_XACT_RD46 0x1a18 ++#define EARCRX_CMDC_XACT_RD47 0x1a1c ++#define EARCRX_CMDC_XACT_RD48 0x1a20 ++#define EARCRX_CMDC_XACT_RD49 0x1a24 ++#define EARCRX_CMDC_XACT_RD50 0x1a28 ++#define EARCRX_CMDC_XACT_RD51 0x1a2c ++#define EARCRX_CMDC_XACT_RD52 0x1a30 ++#define EARCRX_CMDC_XACT_RD53 0x1a34 ++#define EARCRX_CMDC_XACT_RD54 0x1a38 ++#define EARCRX_CMDC_XACT_RD55 0x1a3c ++#define EARCRX_CMDC_XACT_RD56 0x1a40 ++#define EARCRX_CMDC_XACT_RD57 0x1a44 ++#define EARCRX_CMDC_XACT_RD58 0x1a48 ++#define EARCRX_CMDC_XACT_RD59 0x1a4c ++#define EARCRX_CMDC_XACT_RD60 0x1a50 ++#define EARCRX_CMDC_XACT_RD61 0x1a54 ++#define EARCRX_CMDC_XACT_RD62 0x1a58 ++#define EARCRX_CMDC_XACT_RD63 0x1a5c ++#define EARCRX_CMDC_XACT_RD64 0x1a60 ++#define EARCRX_CMDC_SYNC_CONFIG 0x1b00 ++/* eARC RX DMAC Registers */ ++#define EARCRX_DMAC_PHY_CONTROL 0x1c00 ++#define EARCRX_DMAC_CONFIG 0x1c08 ++#define EARCRX_DMAC_CONTROL0 0x1c0c ++#define EARCRX_DMAC_AUDIO_EN BIT(1) ++#define EARCRX_DMAC_EN BIT(0) ++#define EARCRX_DMAC_CONTROL1 0x1c10 ++#define EARCRX_DMAC_STATUS 0x1c14 ++#define EARCRX_DMAC_CHSTATUS0 0x1c18 ++#define EARCRX_DMAC_CHSTATUS1 0x1c1c ++#define EARCRX_DMAC_CHSTATUS2 0x1c20 ++#define EARCRX_DMAC_CHSTATUS3 0x1c24 ++#define EARCRX_DMAC_CHSTATUS4 0x1c28 ++#define EARCRX_DMAC_CHSTATUS5 0x1c2c ++#define EARCRX_DMAC_USRDATA_MSG_HDMI_AC0 0x1c30 ++#define EARCRX_DMAC_USRDATA_MSG_HDMI_AC1 0x1c34 ++#define EARCRX_DMAC_USRDATA_MSG_HDMI_AC2 0x1c38 ++#define EARCRX_DMAC_USRDATA_MSG_HDMI_AC3 0x1c3c ++#define EARCRX_DMAC_USRDATA_MSG_HDMI_AC4 0x1c40 ++#define EARCRX_DMAC_USRDATA_MSG_HDMI_AC5 0x1c44 ++#define EARCRX_DMAC_USRDATA_MSG_HDMI_AC6 0x1c48 ++#define EARCRX_DMAC_USRDATA_MSG_HDMI_AC7 0x1c4c ++#define EARCRX_DMAC_USRDATA_MSG_HDMI_AC8 0x1c50 ++#define EARCRX_DMAC_USRDATA_MSG_HDMI_AC9 0x1c54 ++#define EARCRX_DMAC_USRDATA_MSG_HDMI_AC10 0x1c58 ++#define EARCRX_DMAC_USRDATA_MSG_HDMI_AC11 0x1c5c ++#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC1_PKT0 0x1c60 ++#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC1_PKT1 0x1c64 ++#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC1_PKT2 0x1c68 ++#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC1_PKT3 0x1c6c ++#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC1_PKT4 0x1c70 ++#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC1_PKT5 0x1c74 ++#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC1_PKT6 0x1c78 ++#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC1_PKT7 0x1c7c ++#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC1_PKT8 0x1c80 ++#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC1_PKT9 0x1c84 ++#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC1_PKT10 0x1c88 ++#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC1_PKT11 0x1c8c ++#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC2_PKT0 0x1c90 ++#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC2_PKT1 0x1c94 ++#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC2_PKT2 0x1c98 ++#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC2_PKT3 0x1c9c ++#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC2_PKT4 0x1ca0 ++#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC2_PKT5 0x1ca4 ++#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC2_PKT6 0x1ca8 ++#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC2_PKT7 0x1cac ++#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC2_PKT8 0x1cb0 ++#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC2_PKT9 0x1cb4 ++#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC2_PKT10 0x1cb8 ++#define EARCRX_DMAC_USRDATA_MSG_HDMI_ISRC2_PKT11 0x1cbc ++#define EARCRX_DMAC_USRDATA_MSG_GENERIC0 0x1cc0 ++#define EARCRX_DMAC_USRDATA_MSG_GENERIC1 0x1cc4 ++#define EARCRX_DMAC_USRDATA_MSG_GENERIC2 0x1cc8 ++#define EARCRX_DMAC_USRDATA_MSG_GENERIC3 0x1ccc ++#define EARCRX_DMAC_USRDATA_MSG_GENERIC4 0x1cd0 ++#define EARCRX_DMAC_USRDATA_MSG_GENERIC5 0x1cd4 ++#define EARCRX_DMAC_USRDATA_MSG_GENERIC6 0x1cd8 ++#define EARCRX_DMAC_USRDATA_MSG_GENERIC7 0x1cdc ++#define EARCRX_DMAC_USRDATA_MSG_GENERIC8 0x1ce0 ++#define EARCRX_DMAC_USRDATA_MSG_GENERIC9 0x1ce4 ++#define EARCRX_DMAC_USRDATA_MSG_GENERIC10 0x1ce8 ++#define EARCRX_DMAC_USRDATA_MSG_GENERIC11 0x1cec ++#define EARCRX_DMAC_USRDATA_MSG_GENERIC12 0x1cf0 ++#define EARCRX_DMAC_USRDATA_MSG_GENERIC13 0x1cf4 ++#define EARCRX_DMAC_USRDATA_MSG_GENERIC14 0x1cf8 ++#define EARCRX_DMAC_USRDATA_MSG_GENERIC15 0x1cfc ++#define EARCRX_DMAC_USRDATA_MSG_GENERIC16 0x1d00 ++#define EARCRX_DMAC_USRDATA_MSG_GENERIC17 0x1d04 ++#define EARCRX_DMAC_USRDATA_MSG_GENERIC18 0x1d08 ++#define EARCRX_DMAC_USRDATA_MSG_GENERIC19 0x1d0c ++#define EARCRX_DMAC_USRDATA_MSG_GENERIC20 0x1d10 ++#define EARCRX_DMAC_USRDATA_MSG_GENERIC21 0x1d14 ++#define EARCRX_DMAC_USRDATA_MSG_GENERIC22 0x1d18 ++#define EARCRX_DMAC_USRDATA_MSG_GENERIC23 0x1d1c ++#define EARCRX_DMAC_USRDATA_MSG_GENERIC24 0x1d20 ++#define EARCRX_DMAC_USRDATA_MSG_GENERIC25 0x1d24 ++#define EARCRX_DMAC_USRDATA_MSG_GENERIC26 0x1d28 ++#define EARCRX_DMAC_USRDATA_MSG_GENERIC27 0x1d2c ++#define EARCRX_DMAC_USRDATA_MSG_GENERIC28 0x1d30 ++#define EARCRX_DMAC_USRDATA_MSG_GENERIC29 0x1d34 ++#define EARCRX_DMAC_USRDATA_MSG_GENERIC30 0x1d38 ++#define EARCRX_DMAC_USRDATA_MSG_GENERIC31 0x1d3c ++#define EARCRX_DMAC_USRDATA_MSG_GENERIC32 0x1d40 ++#define EARCRX_DMAC_CHSTATUS_STREAMER0 0x1d44 ++#define EARCRX_DMAC_CHSTATUS_STREAMER1 0x1d48 ++#define EARCRX_DMAC_CHSTATUS_STREAMER2 0x1d4c ++#define EARCRX_DMAC_CHSTATUS_STREAMER3 0x1d50 ++#define EARCRX_DMAC_CHSTATUS_STREAMER4 0x1d54 ++#define EARCRX_DMAC_CHSTATUS_STREAMER5 0x1d58 ++#define EARCRX_DMAC_CHSTATUS_STREAMER6 0x1d5c ++#define EARCRX_DMAC_CHSTATUS_STREAMER7 0x1d60 ++#define EARCRX_DMAC_CHSTATUS_STREAMER8 0x1d64 ++#define EARCRX_DMAC_CHSTATUS_STREAMER9 0x1d68 ++#define EARCRX_DMAC_CHSTATUS_STREAMER10 0x1d6c ++#define EARCRX_DMAC_CHSTATUS_STREAMER11 0x1d70 ++#define EARCRX_DMAC_CHSTATUS_STREAMER12 0x1d74 ++#define EARCRX_DMAC_CHSTATUS_STREAMER13 0x1d78 ++#define EARCRX_DMAC_CHSTATUS_STREAMER14 0x1d7c ++#define EARCRX_DMAC_USRDATA_STREAMER0 0x1d80 ++/* Main Unit Interrupt Registers */ ++#define MAIN_INTVEC_INDEX 0x3000 ++#define MAINUNIT_0_INT_STATUS 0x3010 ++#define MAINUNIT_0_INT_MASK_N 0x3014 ++#define MAINUNIT_0_INT_CLEAR 0x3018 ++#define MAINUNIT_0_INT_FORCE 0x301c ++#define MAINUNIT_1_INT_STATUS 0x3020 ++#define FLT_EXIT_TO_LTSL_IRQ BIT(22) ++#define FLT_EXIT_TO_LTS4_IRQ BIT(21) ++#define FLT_EXIT_TO_LTSP_IRQ BIT(20) ++#define SCDC_NACK_RCVD_IRQ BIT(12) ++#define SCDC_RR_REPLY_STOP_IRQ BIT(11) ++#define SCDC_UPD_FLAGS_CLR_IRQ BIT(10) ++#define SCDC_UPD_FLAGS_CHG_IRQ BIT(9) ++#define SCDC_UPD_FLAGS_RD_IRQ BIT(8) ++#define I2CM_NACK_RCVD_IRQ BIT(2) ++#define I2CM_READ_REQUEST_IRQ BIT(1) ++#define I2CM_OP_DONE_IRQ BIT(0) ++#define MAINUNIT_1_INT_MASK_N 0x3024 ++#define I2CM_NACK_RCVD_MASK_N BIT(2) ++#define I2CM_READ_REQUEST_MASK_N BIT(1) ++#define I2CM_OP_DONE_MASK_N BIT(0) ++#define MAINUNIT_1_INT_CLEAR 0x3028 ++#define I2CM_NACK_RCVD_CLEAR BIT(2) ++#define I2CM_READ_REQUEST_CLEAR BIT(1) ++#define I2CM_OP_DONE_CLEAR BIT(0) ++#define MAINUNIT_1_INT_FORCE 0x302c ++/* AVPUNIT Interrupt Registers */ ++#define AVP_INTVEC_INDEX 0x3800 ++#define AVP_0_INT_STATUS 0x3810 ++#define AVP_0_INT_MASK_N 0x3814 ++#define AVP_0_INT_CLEAR 0x3818 ++#define AVP_0_INT_FORCE 0x381c ++#define AVP_1_INT_STATUS 0x3820 ++#define AVP_1_INT_MASK_N 0x3824 ++#define HDCP14_AUTH_CHG_MASK_N BIT(6) ++#define AVP_1_INT_CLEAR 0x3828 ++#define AVP_1_INT_FORCE 0x382c ++#define AVP_2_INT_STATUS 0x3830 ++#define AVP_2_INT_MASK_N 0x3834 ++#define AVP_2_INT_CLEAR 0x3838 ++#define AVP_2_INT_FORCE 0x383c ++#define AVP_3_INT_STATUS 0x3840 ++#define AVP_3_INT_MASK_N 0x3844 ++#define AVP_3_INT_CLEAR 0x3848 ++#define AVP_3_INT_FORCE 0x384c ++#define AVP_4_INT_STATUS 0x3850 ++#define AVP_4_INT_MASK_N 0x3854 ++#define AVP_4_INT_CLEAR 0x3858 ++#define AVP_4_INT_FORCE 0x385c ++#define AVP_5_INT_STATUS 0x3860 ++#define AVP_5_INT_MASK_N 0x3864 ++#define AVP_5_INT_CLEAR 0x3868 ++#define AVP_5_INT_FORCE 0x386c ++#define AVP_6_INT_STATUS 0x3870 ++#define AVP_6_INT_MASK_N 0x3874 ++#define AVP_6_INT_CLEAR 0x3878 ++#define AVP_6_INT_FORCE 0x387c ++/* CEC Interrupt Registers */ ++#define CEC_INT_STATUS 0x4000 ++#define CEC_INT_MASK_N 0x4004 ++#define CEC_INT_CLEAR 0x4008 ++#define CEC_INT_FORCE 0x400c ++/* eARC RX Interrupt Registers */ ++#define EARCRX_INTVEC_INDEX 0x4800 ++#define EARCRX_0_INT_STATUS 0x4810 ++#define EARCRX_CMDC_DISCOVERY_TIMEOUT_IRQ BIT(9) ++#define EARCRX_CMDC_DISCOVERY_DONE_IRQ BIT(8) ++#define EARCRX_0_INT_MASK_N 0x4814 ++#define EARCRX_0_INT_CLEAR 0x4818 ++#define EARCRX_0_INT_FORCE 0x481c ++#define EARCRX_1_INT_STATUS 0x4820 ++#define EARCRX_1_INT_MASK_N 0x4824 ++#define EARCRX_1_INT_CLEAR 0x4828 ++#define EARCRX_1_INT_FORCE 0x482c ++ ++#endif /* __DW_HDMI_QP_H__ */ +--- /dev/null ++++ b/include/drm/bridge/dw_hdmi_qp.h +@@ -0,0 +1,32 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright (c) 2021-2022 Rockchip Electronics Co., Ltd. ++ * Copyright (c) 2024 Collabora Ltd. ++ */ ++ ++#ifndef __DW_HDMI_QP__ ++#define __DW_HDMI_QP__ ++ ++struct device; ++struct drm_encoder; ++struct dw_hdmi_qp; ++struct platform_device; ++ ++struct dw_hdmi_qp_phy_ops { ++ int (*init)(struct dw_hdmi_qp *hdmi, void *data); ++ void (*disable)(struct dw_hdmi_qp *hdmi, void *data); ++ enum drm_connector_status (*read_hpd)(struct dw_hdmi_qp *hdmi, void *data); ++ void (*setup_hpd)(struct dw_hdmi_qp *hdmi, void *data); ++}; ++ ++struct dw_hdmi_qp_plat_data { ++ const struct dw_hdmi_qp_phy_ops *phy_ops; ++ void *phy_data; ++ int main_irq; ++}; ++ ++struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev, ++ struct drm_encoder *encoder, ++ const struct dw_hdmi_qp_plat_data *plat_data); ++void dw_hdmi_qp_resume(struct device *dev, struct dw_hdmi_qp *hdmi); ++#endif /* __DW_HDMI_QP__ */ diff --git a/target/linux/rockchip/patches-6.12/041-10-v6.13-drm-rockchip-Add-basic-RK3588-HDMI-output-support.patch b/target/linux/rockchip/patches-6.12/041-10-v6.13-drm-rockchip-Add-basic-RK3588-HDMI-output-support.patch new file mode 100644 index 000000000..6ea142c42 --- /dev/null +++ b/target/linux/rockchip/patches-6.12/041-10-v6.13-drm-rockchip-Add-basic-RK3588-HDMI-output-support.patch @@ -0,0 +1,511 @@ +From 128a9bf8ace290d86d2805c06f3b0e4cfab75de0 Mon Sep 17 00:00:00 2001 +From: Cristian Ciocaltea +Date: Wed, 16 Oct 2024 23:06:53 +0300 +Subject: [PATCH] drm/rockchip: Add basic RK3588 HDMI output support + +The RK3588 SoC family integrates the newer Synopsys DesignWare HDMI 2.1 +Quad-Pixel (QP) TX controller IP and a HDMI/eDP TX Combo PHY based on a +Samsung IP block. + +Add just the basic support for now, i.e. RGB output up to 4K@60Hz, +without audio, CEC or any of the HDMI 2.1 specific features. + +Co-developed-by: Algea Cao +Signed-off-by: Algea Cao +Tested-by: Heiko Stuebner +Reviewed-by: Maxime Ripard +Signed-off-by: Cristian Ciocaltea +Link: https://patchwork.freedesktop.org/patch/msgid/20241016-b4-rk3588-bridge-upstream-v10-3-87ef92a6d14e@collabora.com +Signed-off-by: Maxime Ripard +--- + drivers/gpu/drm/rockchip/Kconfig | 9 + + drivers/gpu/drm/rockchip/Makefile | 1 + + .../gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 424 ++++++++++++++++++ + drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 2 + + drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 1 + + 5 files changed, 437 insertions(+) + create mode 100644 drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c + +--- a/drivers/gpu/drm/rockchip/Kconfig ++++ b/drivers/gpu/drm/rockchip/Kconfig +@@ -9,6 +9,7 @@ config DRM_ROCKCHIP + select VIDEOMODE_HELPERS + select DRM_ANALOGIX_DP if ROCKCHIP_ANALOGIX_DP + select DRM_DW_HDMI if ROCKCHIP_DW_HDMI ++ select DRM_DW_HDMI_QP if ROCKCHIP_DW_HDMI_QP + select DRM_DW_MIPI_DSI if ROCKCHIP_DW_MIPI_DSI + select GENERIC_PHY if ROCKCHIP_DW_MIPI_DSI + select GENERIC_PHY_MIPI_DPHY if ROCKCHIP_DW_MIPI_DSI +@@ -64,6 +65,14 @@ config ROCKCHIP_DW_HDMI + enable HDMI on RK3288 or RK3399 based SoC, you should select + this option. + ++config ROCKCHIP_DW_HDMI_QP ++ bool "Rockchip specific extensions for Synopsys DW HDMI QP" ++ select DRM_BRIDGE_CONNECTOR ++ help ++ This selects support for Rockchip SoC specific extensions ++ for the Synopsys DesignWare HDMI QP driver. If you want to ++ enable HDMI on RK3588 based SoC, you should select this option. ++ + config ROCKCHIP_DW_MIPI_DSI + bool "Rockchip specific extensions for Synopsys DW MIPI DSI" + select GENERIC_PHY_MIPI_DPHY +--- a/drivers/gpu/drm/rockchip/Makefile ++++ b/drivers/gpu/drm/rockchip/Makefile +@@ -11,6 +11,7 @@ rockchipdrm-$(CONFIG_ROCKCHIP_VOP) += ro + 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_DW_HDMI) += dw_hdmi-rockchip.o ++rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI_QP) += dw_hdmi_qp-rockchip.o + rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi-rockchip.o + rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o + rockchipdrm-$(CONFIG_ROCKCHIP_LVDS) += rockchip_lvds.o +--- /dev/null ++++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c +@@ -0,0 +1,424 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (c) 2021-2022 Rockchip Electronics Co., Ltd. ++ * Copyright (c) 2024 Collabora Ltd. ++ * ++ * Author: Algea Cao ++ * Author: Cristian Ciocaltea ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "rockchip_drm_drv.h" ++ ++#define RK3588_GRF_SOC_CON2 0x0308 ++#define RK3588_HDMI0_HPD_INT_MSK BIT(13) ++#define RK3588_HDMI0_HPD_INT_CLR BIT(12) ++#define RK3588_GRF_SOC_CON7 0x031c ++#define RK3588_SET_HPD_PATH_MASK GENMASK(13, 12) ++#define RK3588_GRF_SOC_STATUS1 0x0384 ++#define RK3588_HDMI0_LEVEL_INT BIT(16) ++#define RK3588_GRF_VO1_CON3 0x000c ++#define RK3588_SCLIN_MASK BIT(9) ++#define RK3588_SDAIN_MASK BIT(10) ++#define RK3588_MODE_MASK BIT(11) ++#define RK3588_I2S_SEL_MASK BIT(13) ++#define RK3588_GRF_VO1_CON9 0x0024 ++#define RK3588_HDMI0_GRANT_SEL BIT(10) ++ ++#define HIWORD_UPDATE(val, mask) ((val) | (mask) << 16) ++#define HOTPLUG_DEBOUNCE_MS 150 ++ ++struct rockchip_hdmi_qp { ++ struct device *dev; ++ struct regmap *regmap; ++ struct regmap *vo_regmap; ++ struct rockchip_encoder encoder; ++ struct clk *ref_clk; ++ struct dw_hdmi_qp *hdmi; ++ struct phy *phy; ++ struct gpio_desc *enable_gpio; ++ struct delayed_work hpd_work; ++}; ++ ++static struct rockchip_hdmi_qp *to_rockchip_hdmi_qp(struct drm_encoder *encoder) ++{ ++ struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder); ++ ++ return container_of(rkencoder, struct rockchip_hdmi_qp, encoder); ++} ++ ++static void dw_hdmi_qp_rockchip_encoder_enable(struct drm_encoder *encoder) ++{ ++ struct rockchip_hdmi_qp *hdmi = to_rockchip_hdmi_qp(encoder); ++ struct drm_crtc *crtc = encoder->crtc; ++ unsigned long long rate; ++ ++ /* Unconditionally switch to TMDS as FRL is not yet supported */ ++ gpiod_set_value(hdmi->enable_gpio, 1); ++ ++ if (crtc && crtc->state) { ++ rate = drm_hdmi_compute_mode_clock(&crtc->state->adjusted_mode, ++ 8, HDMI_COLORSPACE_RGB); ++ clk_set_rate(hdmi->ref_clk, rate); ++ /* ++ * FIXME: Temporary workaround to pass pixel clock rate ++ * to the PHY driver until phy_configure_opts_hdmi ++ * becomes available in the PHY API. See also the related ++ * comment in rk_hdptx_phy_power_on() from ++ * drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c ++ */ ++ phy_set_bus_width(hdmi->phy, rate / 100); ++ } ++} ++ ++static int ++dw_hdmi_qp_rockchip_encoder_atomic_check(struct drm_encoder *encoder, ++ struct drm_crtc_state *crtc_state, ++ struct drm_connector_state *conn_state) ++{ ++ struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state); ++ ++ s->output_mode = ROCKCHIP_OUT_MODE_AAAA; ++ s->output_type = DRM_MODE_CONNECTOR_HDMIA; ++ ++ return 0; ++} ++ ++static const struct ++drm_encoder_helper_funcs dw_hdmi_qp_rockchip_encoder_helper_funcs = { ++ .enable = dw_hdmi_qp_rockchip_encoder_enable, ++ .atomic_check = dw_hdmi_qp_rockchip_encoder_atomic_check, ++}; ++ ++static int dw_hdmi_qp_rk3588_phy_init(struct dw_hdmi_qp *dw_hdmi, void *data) ++{ ++ struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data; ++ ++ return phy_power_on(hdmi->phy); ++} ++ ++static void dw_hdmi_qp_rk3588_phy_disable(struct dw_hdmi_qp *dw_hdmi, ++ void *data) ++{ ++ struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data; ++ ++ phy_power_off(hdmi->phy); ++} ++ ++static enum drm_connector_status ++dw_hdmi_qp_rk3588_read_hpd(struct dw_hdmi_qp *dw_hdmi, void *data) ++{ ++ struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data; ++ u32 val; ++ ++ regmap_read(hdmi->regmap, RK3588_GRF_SOC_STATUS1, &val); ++ ++ return val & RK3588_HDMI0_LEVEL_INT ? ++ connector_status_connected : connector_status_disconnected; ++} ++ ++static void dw_hdmi_qp_rk3588_setup_hpd(struct dw_hdmi_qp *dw_hdmi, void *data) ++{ ++ struct rockchip_hdmi_qp *hdmi = (struct rockchip_hdmi_qp *)data; ++ ++ regmap_write(hdmi->regmap, ++ RK3588_GRF_SOC_CON2, ++ HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_CLR, ++ RK3588_HDMI0_HPD_INT_CLR | ++ RK3588_HDMI0_HPD_INT_MSK)); ++} ++ ++static const struct dw_hdmi_qp_phy_ops rk3588_hdmi_phy_ops = { ++ .init = dw_hdmi_qp_rk3588_phy_init, ++ .disable = dw_hdmi_qp_rk3588_phy_disable, ++ .read_hpd = dw_hdmi_qp_rk3588_read_hpd, ++ .setup_hpd = dw_hdmi_qp_rk3588_setup_hpd, ++}; ++ ++static void dw_hdmi_qp_rk3588_hpd_work(struct work_struct *work) ++{ ++ struct rockchip_hdmi_qp *hdmi = container_of(work, ++ struct rockchip_hdmi_qp, ++ hpd_work.work); ++ struct drm_device *drm = hdmi->encoder.encoder.dev; ++ bool changed; ++ ++ if (drm) { ++ changed = drm_helper_hpd_irq_event(drm); ++ if (changed) ++ drm_dbg(hdmi, "connector status changed\n"); ++ } ++} ++ ++static irqreturn_t dw_hdmi_qp_rk3588_hardirq(int irq, void *dev_id) ++{ ++ struct rockchip_hdmi_qp *hdmi = dev_id; ++ u32 intr_stat, val; ++ ++ regmap_read(hdmi->regmap, RK3588_GRF_SOC_STATUS1, &intr_stat); ++ ++ if (intr_stat) { ++ val = HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_MSK, ++ RK3588_HDMI0_HPD_INT_MSK); ++ regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val); ++ return IRQ_WAKE_THREAD; ++ } ++ ++ return IRQ_NONE; ++} ++ ++static irqreturn_t dw_hdmi_qp_rk3588_irq(int irq, void *dev_id) ++{ ++ struct rockchip_hdmi_qp *hdmi = dev_id; ++ u32 intr_stat, val; ++ ++ regmap_read(hdmi->regmap, RK3588_GRF_SOC_STATUS1, &intr_stat); ++ if (!intr_stat) ++ return IRQ_NONE; ++ ++ val = HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_CLR, ++ RK3588_HDMI0_HPD_INT_CLR); ++ regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val); ++ ++ mod_delayed_work(system_wq, &hdmi->hpd_work, ++ msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS)); ++ ++ val |= HIWORD_UPDATE(0, RK3588_HDMI0_HPD_INT_MSK); ++ regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val); ++ ++ return IRQ_HANDLED; ++} ++ ++static const struct of_device_id dw_hdmi_qp_rockchip_dt_ids[] = { ++ { .compatible = "rockchip,rk3588-dw-hdmi-qp", ++ .data = &rk3588_hdmi_phy_ops }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, dw_hdmi_qp_rockchip_dt_ids); ++ ++static int dw_hdmi_qp_rockchip_bind(struct device *dev, struct device *master, ++ void *data) ++{ ++ static const char * const clk_names[] = { ++ "pclk", "earc", "aud", "hdp", "hclk_vo1", ++ "ref" /* keep "ref" last */ ++ }; ++ struct platform_device *pdev = to_platform_device(dev); ++ struct dw_hdmi_qp_plat_data plat_data; ++ struct drm_device *drm = data; ++ struct drm_connector *connector; ++ struct drm_encoder *encoder; ++ struct rockchip_hdmi_qp *hdmi; ++ struct clk *clk; ++ int ret, irq, i; ++ u32 val; ++ ++ if (!pdev->dev.of_node) ++ return -ENODEV; ++ ++ hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL); ++ if (!hdmi) ++ return -ENOMEM; ++ ++ plat_data.phy_ops = of_device_get_match_data(dev); ++ if (!plat_data.phy_ops) ++ return -ENODEV; ++ ++ plat_data.phy_data = hdmi; ++ hdmi->dev = &pdev->dev; ++ ++ encoder = &hdmi->encoder.encoder; ++ encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node); ++ ++ rockchip_drm_encoder_set_crtc_endpoint_id(&hdmi->encoder, ++ dev->of_node, 0, 0); ++ /* ++ * 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; ++ ++ hdmi->regmap = syscon_regmap_lookup_by_phandle(dev->of_node, ++ "rockchip,grf"); ++ if (IS_ERR(hdmi->regmap)) { ++ drm_err(hdmi, "Unable to get rockchip,grf\n"); ++ return PTR_ERR(hdmi->regmap); ++ } ++ ++ hdmi->vo_regmap = syscon_regmap_lookup_by_phandle(dev->of_node, ++ "rockchip,vo-grf"); ++ if (IS_ERR(hdmi->vo_regmap)) { ++ drm_err(hdmi, "Unable to get rockchip,vo-grf\n"); ++ return PTR_ERR(hdmi->vo_regmap); ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(clk_names); i++) { ++ clk = devm_clk_get_enabled(hdmi->dev, clk_names[i]); ++ ++ if (IS_ERR(clk)) { ++ ret = PTR_ERR(clk); ++ if (ret != -EPROBE_DEFER) ++ drm_err(hdmi, "Failed to get %s clock: %d\n", ++ clk_names[i], ret); ++ return ret; ++ } ++ } ++ hdmi->ref_clk = clk; ++ ++ hdmi->enable_gpio = devm_gpiod_get_optional(hdmi->dev, "enable", ++ GPIOD_OUT_HIGH); ++ if (IS_ERR(hdmi->enable_gpio)) { ++ ret = PTR_ERR(hdmi->enable_gpio); ++ drm_err(hdmi, "Failed to request enable GPIO: %d\n", ret); ++ return ret; ++ } ++ ++ hdmi->phy = devm_of_phy_get_by_index(dev, dev->of_node, 0); ++ if (IS_ERR(hdmi->phy)) { ++ ret = PTR_ERR(hdmi->phy); ++ if (ret != -EPROBE_DEFER) ++ drm_err(hdmi, "failed to get phy: %d\n", ret); ++ return ret; ++ } ++ ++ val = HIWORD_UPDATE(RK3588_SCLIN_MASK, RK3588_SCLIN_MASK) | ++ HIWORD_UPDATE(RK3588_SDAIN_MASK, RK3588_SDAIN_MASK) | ++ HIWORD_UPDATE(RK3588_MODE_MASK, RK3588_MODE_MASK) | ++ HIWORD_UPDATE(RK3588_I2S_SEL_MASK, RK3588_I2S_SEL_MASK); ++ regmap_write(hdmi->vo_regmap, RK3588_GRF_VO1_CON3, val); ++ ++ val = HIWORD_UPDATE(RK3588_SET_HPD_PATH_MASK, ++ RK3588_SET_HPD_PATH_MASK); ++ regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON7, val); ++ ++ val = HIWORD_UPDATE(RK3588_HDMI0_GRANT_SEL, ++ RK3588_HDMI0_GRANT_SEL); ++ regmap_write(hdmi->vo_regmap, RK3588_GRF_VO1_CON9, val); ++ ++ val = HIWORD_UPDATE(RK3588_HDMI0_HPD_INT_MSK, RK3588_HDMI0_HPD_INT_MSK); ++ regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON2, val); ++ ++ INIT_DELAYED_WORK(&hdmi->hpd_work, dw_hdmi_qp_rk3588_hpd_work); ++ ++ plat_data.main_irq = platform_get_irq_byname(pdev, "main"); ++ if (plat_data.main_irq < 0) ++ return plat_data.main_irq; ++ ++ irq = platform_get_irq_byname(pdev, "hpd"); ++ if (irq < 0) ++ return irq; ++ ++ ret = devm_request_threaded_irq(hdmi->dev, irq, ++ dw_hdmi_qp_rk3588_hardirq, ++ dw_hdmi_qp_rk3588_irq, ++ IRQF_SHARED, "dw-hdmi-qp-hpd", ++ hdmi); ++ if (ret) ++ return ret; ++ ++ drm_encoder_helper_add(encoder, &dw_hdmi_qp_rockchip_encoder_helper_funcs); ++ drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS); ++ ++ platform_set_drvdata(pdev, hdmi); ++ ++ hdmi->hdmi = dw_hdmi_qp_bind(pdev, encoder, &plat_data); ++ if (IS_ERR(hdmi->hdmi)) { ++ ret = PTR_ERR(hdmi->hdmi); ++ drm_encoder_cleanup(encoder); ++ return ret; ++ } ++ ++ connector = drm_bridge_connector_init(drm, encoder); ++ if (IS_ERR(connector)) { ++ ret = PTR_ERR(connector); ++ drm_err(hdmi, "failed to init bridge connector: %d\n", ret); ++ return ret; ++ } ++ ++ return drm_connector_attach_encoder(connector, encoder); ++} ++ ++static void dw_hdmi_qp_rockchip_unbind(struct device *dev, ++ struct device *master, ++ void *data) ++{ ++ struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev); ++ ++ cancel_delayed_work_sync(&hdmi->hpd_work); ++ ++ drm_encoder_cleanup(&hdmi->encoder.encoder); ++} ++ ++static const struct component_ops dw_hdmi_qp_rockchip_ops = { ++ .bind = dw_hdmi_qp_rockchip_bind, ++ .unbind = dw_hdmi_qp_rockchip_unbind, ++}; ++ ++static int dw_hdmi_qp_rockchip_probe(struct platform_device *pdev) ++{ ++ return component_add(&pdev->dev, &dw_hdmi_qp_rockchip_ops); ++} ++ ++static void dw_hdmi_qp_rockchip_remove(struct platform_device *pdev) ++{ ++ component_del(&pdev->dev, &dw_hdmi_qp_rockchip_ops); ++} ++ ++static int __maybe_unused dw_hdmi_qp_rockchip_resume(struct device *dev) ++{ ++ struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev); ++ u32 val; ++ ++ val = HIWORD_UPDATE(RK3588_SCLIN_MASK, RK3588_SCLIN_MASK) | ++ HIWORD_UPDATE(RK3588_SDAIN_MASK, RK3588_SDAIN_MASK) | ++ HIWORD_UPDATE(RK3588_MODE_MASK, RK3588_MODE_MASK) | ++ HIWORD_UPDATE(RK3588_I2S_SEL_MASK, RK3588_I2S_SEL_MASK); ++ regmap_write(hdmi->vo_regmap, RK3588_GRF_VO1_CON3, val); ++ ++ val = HIWORD_UPDATE(RK3588_SET_HPD_PATH_MASK, ++ RK3588_SET_HPD_PATH_MASK); ++ regmap_write(hdmi->regmap, RK3588_GRF_SOC_CON7, val); ++ ++ val = HIWORD_UPDATE(RK3588_HDMI0_GRANT_SEL, ++ RK3588_HDMI0_GRANT_SEL); ++ regmap_write(hdmi->vo_regmap, RK3588_GRF_VO1_CON9, val); ++ ++ dw_hdmi_qp_resume(dev, hdmi->hdmi); ++ ++ if (hdmi->encoder.encoder.dev) ++ drm_helper_hpd_irq_event(hdmi->encoder.encoder.dev); ++ ++ return 0; ++} ++ ++static const struct dev_pm_ops dw_hdmi_qp_rockchip_pm = { ++ SET_SYSTEM_SLEEP_PM_OPS(NULL, dw_hdmi_qp_rockchip_resume) ++}; ++ ++struct platform_driver dw_hdmi_qp_rockchip_pltfm_driver = { ++ .probe = dw_hdmi_qp_rockchip_probe, ++ .remove = dw_hdmi_qp_rockchip_remove, ++ .driver = { ++ .name = "dwhdmiqp-rockchip", ++ .pm = &dw_hdmi_qp_rockchip_pm, ++ .of_match_table = dw_hdmi_qp_rockchip_dt_ids, ++ }, ++}; +--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +@@ -532,6 +532,8 @@ static int __init rockchip_drm_init(void + ADD_ROCKCHIP_SUB_DRIVER(cdn_dp_driver, CONFIG_ROCKCHIP_CDN_DP); + ADD_ROCKCHIP_SUB_DRIVER(dw_hdmi_rockchip_pltfm_driver, + CONFIG_ROCKCHIP_DW_HDMI); ++ ADD_ROCKCHIP_SUB_DRIVER(dw_hdmi_qp_rockchip_pltfm_driver, ++ CONFIG_ROCKCHIP_DW_HDMI_QP); + ADD_ROCKCHIP_SUB_DRIVER(dw_mipi_dsi_rockchip_driver, + CONFIG_ROCKCHIP_DW_MIPI_DSI); + ADD_ROCKCHIP_SUB_DRIVER(inno_hdmi_driver, CONFIG_ROCKCHIP_INNO_HDMI); +--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +@@ -88,6 +88,7 @@ int rockchip_drm_encoder_set_crtc_endpoi + int rockchip_drm_endpoint_is_subdriver(struct device_node *ep); + extern struct platform_driver cdn_dp_driver; + extern struct platform_driver dw_hdmi_rockchip_pltfm_driver; ++extern struct platform_driver dw_hdmi_qp_rockchip_pltfm_driver; + extern struct platform_driver dw_mipi_dsi_rockchip_driver; + extern struct platform_driver inno_hdmi_driver; + extern struct platform_driver rockchip_dp_driver; diff --git a/target/linux/rockchip/patches-6.12/041-11-v6.14-rockchip-drm-vop2-add-support-for-gamma-LUT.patch b/target/linux/rockchip/patches-6.12/041-11-v6.14-rockchip-drm-vop2-add-support-for-gamma-LUT.patch new file mode 100644 index 000000000..270f693fa --- /dev/null +++ b/target/linux/rockchip/patches-6.12/041-11-v6.14-rockchip-drm-vop2-add-support-for-gamma-LUT.patch @@ -0,0 +1,334 @@ +From 4f537776340dab2b680a4d8554567f6884240d0b Mon Sep 17 00:00:00 2001 +From: Piotr Zalewski +Date: Fri, 1 Nov 2024 19:01:17 +0000 +Subject: [PATCH] rockchip/drm: vop2: add support for gamma LUT + +Add support for gamma LUT in VOP2 driver. The implementation was inspired +by one found in VOP1 driver. Blue and red channels in gamma LUT register +write were swapped with respect to how gamma LUT values are written in +VOP1. Gamma LUT port selection was added before the write of new gamma LUT +table. + +If the current SoC is rk356x, check if no other CRTC has gamma LUT enabled +in atomic_check (only one video port can use gamma LUT at a time) and +disable gamma LUT before the LUT table write. + +If the current SoC isn't rk356x, "seamless" gamma lut update is performed +similarly to how it was done in the case of RK3399 in VOP1[1]. In seamless +update gamma LUT disable before the write isn't necessary, check if no +other CRTC has gamma LUT enabled is also not necessary, different register +is being used to select gamma LUT port[2] and after setting DSP_LUT_EN bit, +GAMMA_UPDATE_EN bit is set[3]. + +Gamma size is set and drm color management is enabled for each video port's +CRTC except ones which have no associated device. + +Patch was tested on RK3566 (Pinetab2). When using userspace tools +which set eg. constant color temperature no issues were noticed. When +using userspace tools which adjust eg. color temperature the slight screen +flicker is visible probably because of gamma LUT disable needed in the +case of RK356x before gamma LUT write. + +Compare behaviour of eg.: +``` +gammastep -O 3000 +``` + +To eg.: +``` +gammastep -l 53:23 -t 6000:3000 +``` + +In latter case color temperature is slowly adjusted at the beginning which +causes screen to slighly flicker. Then it adjusts every few seconds which +also causes slight screen flicker. + +[1] https://lists.infradead.org/pipermail/linux-rockchip/2021-October/028132.html +[2] https://lore.kernel.org/linux-rockchip/48249708-8c05-40d2-a5d8-23de960c5a77@rock-chips.com/ +[3] https://github.com/radxa/kernel/blob/linux-6.1-stan-rkr1/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c#L3437 + +Helped-by: Daniel Stone +Helped-by: Dragan Simic +Helped-by: Diederik de Haas +Helped-by: Andy Yan +Signed-off-by: Piotr Zalewski +Reviewed-by: Andy Yan +Signed-off-by: Heiko Stuebner +Link: https://patchwork.freedesktop.org/patch/msgid/20241101185545.559090-3-pZ010001011111@proton.me +--- + drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 186 +++++++++++++++++++ + drivers/gpu/drm/rockchip/rockchip_drm_vop2.h | 5 + + 2 files changed, 191 insertions(+) + +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +@@ -281,6 +281,15 @@ static u32 vop2_readl(struct vop2 *vop2, + return val; + } + ++static u32 vop2_vp_read(struct vop2_video_port *vp, u32 offset) ++{ ++ u32 val; ++ ++ regmap_read(vp->vop2->map, vp->data->offset + offset, &val); ++ ++ return val; ++} ++ + static void vop2_win_write(const struct vop2_win *win, unsigned int reg, u32 v) + { + regmap_field_write(win->reg[reg], v); +@@ -1020,6 +1029,67 @@ static void vop2_disable(struct vop2 *vo + clk_disable_unprepare(vop2->hclk); + } + ++static bool vop2_vp_dsp_lut_is_enabled(struct vop2_video_port *vp) ++{ ++ u32 dsp_ctrl = vop2_vp_read(vp, RK3568_VP_DSP_CTRL); ++ ++ return dsp_ctrl & RK3568_VP_DSP_CTRL__DSP_LUT_EN; ++} ++ ++static void vop2_vp_dsp_lut_disable(struct vop2_video_port *vp) ++{ ++ u32 dsp_ctrl = vop2_vp_read(vp, RK3568_VP_DSP_CTRL); ++ ++ dsp_ctrl &= ~RK3568_VP_DSP_CTRL__DSP_LUT_EN; ++ vop2_vp_write(vp, RK3568_VP_DSP_CTRL, dsp_ctrl); ++} ++ ++static bool vop2_vp_dsp_lut_poll_disabled(struct vop2_video_port *vp) ++{ ++ u32 dsp_ctrl; ++ int ret = readx_poll_timeout(vop2_vp_dsp_lut_is_enabled, vp, dsp_ctrl, ++ !dsp_ctrl, 5, 30 * 1000); ++ if (ret) { ++ drm_err(vp->vop2->drm, "display LUT RAM enable timeout!\n"); ++ return false; ++ } ++ ++ return true; ++} ++ ++static void vop2_vp_dsp_lut_enable(struct vop2_video_port *vp) ++{ ++ u32 dsp_ctrl = vop2_vp_read(vp, RK3568_VP_DSP_CTRL); ++ ++ dsp_ctrl |= RK3568_VP_DSP_CTRL__DSP_LUT_EN; ++ vop2_vp_write(vp, RK3568_VP_DSP_CTRL, dsp_ctrl); ++} ++ ++static void vop2_vp_dsp_lut_update_enable(struct vop2_video_port *vp) ++{ ++ u32 dsp_ctrl = vop2_vp_read(vp, RK3568_VP_DSP_CTRL); ++ ++ dsp_ctrl |= RK3588_VP_DSP_CTRL__GAMMA_UPDATE_EN; ++ vop2_vp_write(vp, RK3568_VP_DSP_CTRL, dsp_ctrl); ++} ++ ++static inline bool vop2_supports_seamless_gamma_lut_update(struct vop2 *vop2) ++{ ++ return (vop2->data->soc_id != 3566 && vop2->data->soc_id != 3568); ++} ++ ++static bool vop2_gamma_lut_in_use(struct vop2 *vop2, struct vop2_video_port *vp) ++{ ++ const int nr_vps = vop2->data->nr_vps; ++ int gamma_en_vp_id; ++ ++ for (gamma_en_vp_id = 0; gamma_en_vp_id < nr_vps; gamma_en_vp_id++) ++ if (vop2_vp_dsp_lut_is_enabled(&vop2->vps[gamma_en_vp_id])) ++ break; ++ ++ return gamma_en_vp_id != nr_vps && gamma_en_vp_id != vp->id; ++} ++ + static void vop2_crtc_atomic_disable(struct drm_crtc *crtc, + struct drm_atomic_state *state) + { +@@ -1511,6 +1581,77 @@ static bool vop2_crtc_mode_fixup(struct + return true; + } + ++static void vop2_crtc_write_gamma_lut(struct vop2 *vop2, struct drm_crtc *crtc) ++{ ++ const struct vop2_video_port *vp = to_vop2_video_port(crtc); ++ const struct vop2_video_port_data *vp_data = &vop2->data->vp[vp->id]; ++ struct drm_color_lut *lut = crtc->state->gamma_lut->data; ++ unsigned int i, bpc = ilog2(vp_data->gamma_lut_len); ++ u32 word; ++ ++ for (i = 0; i < crtc->gamma_size; i++) { ++ word = (drm_color_lut_extract(lut[i].blue, bpc) << (2 * bpc)) | ++ (drm_color_lut_extract(lut[i].green, bpc) << bpc) | ++ drm_color_lut_extract(lut[i].red, bpc); ++ ++ writel(word, vop2->lut_regs + i * 4); ++ } ++} ++ ++static void vop2_crtc_atomic_set_gamma_seamless(struct vop2 *vop2, ++ struct vop2_video_port *vp, ++ struct drm_crtc *crtc) ++{ ++ vop2_writel(vop2, RK3568_LUT_PORT_SEL, ++ FIELD_PREP(RK3588_LUT_PORT_SEL__GAMMA_AHB_WRITE_SEL, vp->id)); ++ vop2_vp_dsp_lut_enable(vp); ++ vop2_crtc_write_gamma_lut(vop2, crtc); ++ vop2_vp_dsp_lut_update_enable(vp); ++} ++ ++static void vop2_crtc_atomic_set_gamma_rk356x(struct vop2 *vop2, ++ struct vop2_video_port *vp, ++ struct drm_crtc *crtc) ++{ ++ vop2_vp_dsp_lut_disable(vp); ++ vop2_cfg_done(vp); ++ if (!vop2_vp_dsp_lut_poll_disabled(vp)) ++ return; ++ ++ vop2_writel(vop2, RK3568_LUT_PORT_SEL, vp->id); ++ vop2_crtc_write_gamma_lut(vop2, crtc); ++ vop2_vp_dsp_lut_enable(vp); ++} ++ ++static void vop2_crtc_atomic_try_set_gamma(struct vop2 *vop2, ++ struct vop2_video_port *vp, ++ struct drm_crtc *crtc, ++ struct drm_crtc_state *crtc_state) ++{ ++ if (!vop2->lut_regs || !crtc_state->color_mgmt_changed) ++ return; ++ ++ if (!crtc_state->gamma_lut) { ++ vop2_vp_dsp_lut_disable(vp); ++ return; ++ } ++ ++ if (vop2_supports_seamless_gamma_lut_update(vop2)) ++ vop2_crtc_atomic_set_gamma_seamless(vop2, vp, crtc); ++ else ++ vop2_crtc_atomic_set_gamma_rk356x(vop2, vp, crtc); ++} ++ ++static inline void vop2_crtc_atomic_try_set_gamma_locked(struct vop2 *vop2, ++ struct vop2_video_port *vp, ++ struct drm_crtc *crtc, ++ struct drm_crtc_state *crtc_state) ++{ ++ vop2_lock(vop2); ++ vop2_crtc_atomic_try_set_gamma(vop2, vp, crtc, crtc_state); ++ vop2_unlock(vop2); ++} ++ + static void vop2_dither_setup(struct drm_crtc *crtc, u32 *dsp_ctrl) + { + struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state); +@@ -2107,11 +2248,40 @@ static void vop2_crtc_atomic_enable(stru + + vop2_vp_write(vp, RK3568_VP_DSP_CTRL, dsp_ctrl); + ++ vop2_crtc_atomic_try_set_gamma(vop2, vp, crtc, crtc_state); ++ + drm_crtc_vblank_on(crtc); + + vop2_unlock(vop2); + } + ++static int vop2_crtc_atomic_check_gamma(struct vop2_video_port *vp, ++ struct drm_crtc *crtc, ++ struct drm_atomic_state *state, ++ struct drm_crtc_state *crtc_state) ++{ ++ struct vop2 *vop2 = vp->vop2; ++ unsigned int len; ++ ++ if (!vp->vop2->lut_regs || !crtc_state->color_mgmt_changed || ++ !crtc_state->gamma_lut) ++ return 0; ++ ++ len = drm_color_lut_size(crtc_state->gamma_lut); ++ if (len != crtc->gamma_size) { ++ drm_dbg(vop2->drm, "Invalid LUT size; got %d, expected %d\n", ++ len, crtc->gamma_size); ++ return -EINVAL; ++ } ++ ++ if (!vop2_supports_seamless_gamma_lut_update(vop2) && vop2_gamma_lut_in_use(vop2, vp)) { ++ drm_info(vop2->drm, "Gamma LUT can be enabled for only one CRTC at a time\n"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ + static int vop2_crtc_atomic_check(struct drm_crtc *crtc, + struct drm_atomic_state *state) + { +@@ -2119,6 +2289,11 @@ static int vop2_crtc_atomic_check(struct + struct drm_plane *plane; + int nplanes = 0; + struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); ++ int ret; ++ ++ ret = vop2_crtc_atomic_check_gamma(vp, crtc, state, crtc_state); ++ if (ret) ++ return ret; + + drm_atomic_crtc_state_for_each_plane(plane, crtc_state) + nplanes++; +@@ -2582,7 +2757,13 @@ static void vop2_crtc_atomic_begin(struc + static void vop2_crtc_atomic_flush(struct drm_crtc *crtc, + struct drm_atomic_state *state) + { ++ struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); + struct vop2_video_port *vp = to_vop2_video_port(crtc); ++ struct vop2 *vop2 = vp->vop2; ++ ++ /* In case of modeset, gamma lut update already happened in atomic enable */ ++ if (!drm_atomic_crtc_needs_modeset(crtc_state)) ++ vop2_crtc_atomic_try_set_gamma_locked(vop2, vp, crtc, crtc_state); + + vop2_post_config(crtc); + +@@ -2885,7 +3066,12 @@ static int vop2_create_crtcs(struct vop2 + } + + drm_crtc_helper_add(&vp->crtc, &vop2_crtc_helper_funcs); ++ if (vop2->lut_regs) { ++ const struct vop2_video_port_data *vp_data = &vop2_data->vp[vp->id]; + ++ drm_mode_crtc_set_gamma_size(&vp->crtc, vp_data->gamma_lut_len); ++ drm_crtc_enable_color_mgmt(&vp->crtc, 0, false, vp_data->gamma_lut_len); ++ } + init_completion(&vp->dsp_hold_completion); + } + +--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h ++++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h +@@ -404,6 +404,7 @@ enum dst_factor_mode { + #define RK3568_REG_CFG_DONE__GLB_CFG_DONE_EN BIT(15) + + #define RK3568_VP_DSP_CTRL__STANDBY BIT(31) ++#define RK3568_VP_DSP_CTRL__DSP_LUT_EN BIT(28) + #define RK3568_VP_DSP_CTRL__DITHER_DOWN_MODE BIT(20) + #define RK3568_VP_DSP_CTRL__DITHER_DOWN_SEL GENMASK(19, 18) + #define RK3568_VP_DSP_CTRL__DITHER_DOWN_EN BIT(17) +@@ -418,6 +419,8 @@ enum dst_factor_mode { + #define RK3568_VP_DSP_CTRL__CORE_DCLK_DIV BIT(4) + #define RK3568_VP_DSP_CTRL__OUT_MODE GENMASK(3, 0) + ++#define RK3588_VP_DSP_CTRL__GAMMA_UPDATE_EN BIT(22) ++ + #define RK3588_VP_CLK_CTRL__DCLK_OUT_DIV GENMASK(3, 2) + #define RK3588_VP_CLK_CTRL__DCLK_CORE_DIV GENMASK(1, 0) + +@@ -470,6 +473,8 @@ enum dst_factor_mode { + #define RK3588_DSP_IF_POL__DP1_PIN_POL GENMASK(14, 12) + #define RK3588_DSP_IF_POL__DP0_PIN_POL GENMASK(10, 8) + ++#define RK3588_LUT_PORT_SEL__GAMMA_AHB_WRITE_SEL GENMASK(13, 12) ++ + #define RK3568_VP0_MIPI_CTRL__DCLK_DIV2_PHASE_LOCK BIT(5) + #define RK3568_VP0_MIPI_CTRL__DCLK_DIV2 BIT(4) + diff --git a/target/linux/rockchip/patches-6.12/041-12-v6.14-drm-rockchip-analogix_dp-allow-to-work-without-panel.patch b/target/linux/rockchip/patches-6.12/041-12-v6.14-drm-rockchip-analogix_dp-allow-to-work-without-panel.patch new file mode 100644 index 000000000..81ba60625 --- /dev/null +++ b/target/linux/rockchip/patches-6.12/041-12-v6.14-drm-rockchip-analogix_dp-allow-to-work-without-panel.patch @@ -0,0 +1,28 @@ +From 86caee745e4506528801d9542db54e7b4c4d834b Mon Sep 17 00:00:00 2001 +From: Lucas Stach +Date: Fri, 21 Jun 2024 22:17:55 +0200 +Subject: [PATCH] drm/rockchip: analogix_dp: allow to work without panel + +When the DP output is routed to a external connector there is no +need for a fixed panel, as the panel may be detected via EDID on +the AUX channel. Allow to continue probing if no panel reference +is present. + +Signed-off-by: Lucas Stach +Signed-off-by: Heiko Stuebner +Link: https://patchwork.freedesktop.org/patch/msgid/20240621201755.500271-1-l.stach@pengutronix.de +--- + drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c ++++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +@@ -386,7 +386,7 @@ static int rockchip_dp_probe(struct plat + return -ENODEV; + + ret = drm_of_find_panel_or_bridge(dev->of_node, 1, 0, &panel, NULL); +- if (ret < 0) ++ if (ret < 0 && ret != -ENODEV) + return ret; + + dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL); diff --git a/target/linux/rockchip/patches-6.12/041-13-v6.14-drm-rockchip-avoid-64-bit-division.patch b/target/linux/rockchip/patches-6.12/041-13-v6.14-drm-rockchip-avoid-64-bit-division.patch new file mode 100644 index 000000000..cdb64e617 --- /dev/null +++ b/target/linux/rockchip/patches-6.12/041-13-v6.14-drm-rockchip-avoid-64-bit-division.patch @@ -0,0 +1,32 @@ +From 4b64b4a81fcd51f570c046cf904aef19ec756d45 Mon Sep 17 00:00:00 2001 +From: Arnd Bergmann +Date: Fri, 18 Oct 2024 15:10:10 +0000 +Subject: [PATCH] drm/rockchip: avoid 64-bit division + +Dividing a 64-bit integer prevents building this for 32-bit targets: + +ERROR: modpost: "__aeabi_uldivmod" [drivers/gpu/drm/rockchip/rockchipdrm.ko] undefined! + +As this function is not performance criticial, just Use the div_u64() helper. + +Fixes: 128a9bf8ace2 ("drm/rockchip: Add basic RK3588 HDMI output support") +Signed-off-by: Arnd Bergmann +Reviewed-by: Dmitry Baryshkov +Reviewed-by: Nathan Chancellor +Link: https://lore.kernel.org/r/20241018151016.3496613-1-arnd@kernel.org +Signed-off-by: Liviu Dudau +--- + drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c ++++ b/drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c +@@ -82,7 +82,7 @@ static void dw_hdmi_qp_rockchip_encoder_ + * comment in rk_hdptx_phy_power_on() from + * drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c + */ +- phy_set_bus_width(hdmi->phy, rate / 100); ++ phy_set_bus_width(hdmi->phy, div_u64(rate, 100)); + } + } + diff --git a/target/linux/rockchip/patches-6.12/041-14-v6.14-drm-bridge-synopsys-Add-MIPI-DSI2-host-controller-bridge.patch b/target/linux/rockchip/patches-6.12/041-14-v6.14-drm-bridge-synopsys-Add-MIPI-DSI2-host-controller-bridge.patch new file mode 100644 index 000000000..6a8ef79e9 --- /dev/null +++ b/target/linux/rockchip/patches-6.12/041-14-v6.14-drm-bridge-synopsys-Add-MIPI-DSI2-host-controller-bridge.patch @@ -0,0 +1,1179 @@ +From 0d6d86253fef1e6b1e38a54db14bcbea9d0d9ca4 Mon Sep 17 00:00:00 2001 +From: Heiko Stuebner +Date: Tue, 10 Dec 2024 00:10:19 +0100 +Subject: [PATCH] drm/bridge/synopsys: Add MIPI DSI2 host controller bridge + +Add a Synopsys Designware MIPI DSI host DRM bridge driver for their +DSI2 host controller, based on the Rockchip version from the driver +rockchip/dw-mipi-dsi2.c in their vendor-kernel with phy & bridge APIs. + +While the driver is heavily modelled after the previous IP, the register +set of this DSI2 controller is completely different and there are also +additional properties like the variable-width phy interface. + +Tested-by: Daniel Semkowicz +Tested-by: Dmitry Yashin +Reviewed-by: Neil Armstrong +Signed-off-by: Heiko Stuebner +Reviewed-by: Andy Yan +Signed-off-by: Heiko Stuebner +Link: https://patchwork.freedesktop.org/patch/msgid/20241209231021.2180582-2-heiko@sntech.de +--- + drivers/gpu/drm/bridge/synopsys/Kconfig | 6 + + drivers/gpu/drm/bridge/synopsys/Makefile | 1 + + .../gpu/drm/bridge/synopsys/dw-mipi-dsi2.c | 1030 +++++++++++++++++ + include/drm/bridge/dw_mipi_dsi2.h | 95 ++ + 4 files changed, 1132 insertions(+) + create mode 100644 drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi2.c + create mode 100644 include/drm/bridge/dw_mipi_dsi2.h + +--- a/drivers/gpu/drm/bridge/synopsys/Kconfig ++++ b/drivers/gpu/drm/bridge/synopsys/Kconfig +@@ -59,3 +59,9 @@ config DRM_DW_MIPI_DSI + select DRM_KMS_HELPER + select DRM_MIPI_DSI + select DRM_PANEL_BRIDGE ++ ++config DRM_DW_MIPI_DSI2 ++ tristate ++ select DRM_KMS_HELPER ++ select DRM_MIPI_DSI ++ select DRM_PANEL_BRIDGE +--- a/drivers/gpu/drm/bridge/synopsys/Makefile ++++ b/drivers/gpu/drm/bridge/synopsys/Makefile +@@ -8,3 +8,4 @@ obj-$(CONFIG_DRM_DW_HDMI_CEC) += dw-hdmi + obj-$(CONFIG_DRM_DW_HDMI_QP) += dw-hdmi-qp.o + + obj-$(CONFIG_DRM_DW_MIPI_DSI) += dw-mipi-dsi.o ++obj-$(CONFIG_DRM_DW_MIPI_DSI2) += dw-mipi-dsi2.o +--- /dev/null ++++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi2.c +@@ -0,0 +1,1030 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright (c) 2024, Fuzhou Rockchip Electronics Co., Ltd ++ * ++ * Modified by Heiko Stuebner ++ * This generic Synopsys DesignWare MIPI DSI2 host driver is based on the ++ * Rockchip version from rockchip/dw-mipi-dsi2.c converted to use bridge APIs. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include