From bbd72c2711620a6044823f4eecfb6886ee51d6d8 Mon Sep 17 00:00:00 2001 From: Rudraksha Gupta Date: Sat, 25 Jul 2026 03:25:39 -0700 Subject: [PATCH] linux-pine64-pinephonepro: update to v7.1 The reason why we have patches instead of a separate repo are because of the following reasons: 1. We don't want to make a repo to which users contribute to. While people haven't tried to commit to my repository yet, this is yet another incentive for people to upstream into Linux kernel mainline. Most of the functionality is here. We just need to upstream it. 2. I assume that all the patches here aren't needed. This calls for a scream test. People who find functionalality missing will open an issue. It becomes trivial to add/remove patches from the `source=...` var rather than repackaging the entire kernel. The next commit aims to remove a lot of patches and see if there are people who rely on said functionality. If not, there is no requirement to upstream it. Signed-off-by: Rudraksha Gupta Part-of: --- ...-pinephone-pro-Keep-modem-regulators.patch | 33 + .../linux-pine64-pinephonepro/APKBUILD | 204 +- .../BTF-seg-fault.patch | 161 + .../config-pine64-pinephonepro.aarch64 | 189 +- ...40-Fix-output-mixer-input-channel-li.patch | 93 + ...40-Fix-hpout-restore-when-lout-is-en.patch | 32 + ...40-Add-input-mixer-input-volume-cont.patch | 48 + ...40-Allow-to-control-single-ended-dif.patch | 32 + ...640-Keep-the-codec-enabled-when-idle.patch | 28 + ...t5640-Add-support-for-power-supplies.patch | 54 + .../0007-media-imx258-Add-i2c-supply.patch | 27 + .../0008-media-imx258-Add-reset-gpio.patch | 69 + ...58-Drop-interface-speed-to-1224-mbps.patch | 78 + ...dia-imx258-Add-debug-register-access.patch | 81 + ...x-doubling-of-playback-speed-after-s.patch | 46 + ...Abort-suspend-on-soft-disconnect-fai.patch | 89 + ...-rockchip-Add-support-for-RV1106-SoC.patch | 175 ++ ...-support-for-power-monitoring-driver.patch | 149 + ...-support-for-RTC-present-in-RV1106-S.patch | 868 ++++++ ...rmal-rockchip-Add-support-for-RK3506.patch | 177 ++ ...igadevice-Add-support-for-gd25lq128e.patch | 33 + ...port-SCLK_CIF_OUT_SRC-to-device-tree.patch | 41 + ...399-Don-t-allow-to-reparent-dclk_vop.patch | 35 + ...-support-for-USB_BC_ENABLED-and-USB_.patch | 45 + ...-rk8xx-Enable-rk808-clkout2-function.patch | 44 + ...18_battery-Add-battery-charger-drive.patch | 2598 +++++++++++++++++ ...18_battery-Add-code-docs-for-the-HW-.patch | 281 ++ ...-tcpm-unregister-existing-source-cap.patch | 41 + ...es-displayport-Respect-DP_CAP_RECEPT.patch | 105 + ...nregister-altmodes-before-registerin.patch | 54 + ...ix-PD-devices-capabilities-registrat.patch | 97 + ...2-Slightly-increase-wait-time-for-BC.patch | 35 + ...2-Set-the-current-before-enabling-pu.patch | 52 + ...2-Retry-reading-of-CC-pins-status-if.patch | 77 + ...2-Update-VBUS-state-even-if-VBUS-int.patch | 44 + ...-typec-fusb302-Add-OF-extcon-support.patch | 45 + ...pec-fusb302-Fix-register-definitions.patch | 50 + ...2-Clear-interrupts-before-we-start-t.patch | 42 + ...2-Turn-off-VBUS-and-VCONN-on-shutdow.patch | 59 + ...o-usb2-Add-support-for-RV1106-RV1103.patch | 209 ++ ...hip-inno-usb2-Add-support-for-RK3506.patch | 156 + ...o-usb2-Add-PHY-tuning-for-rk3566-rk3.patch | 99 + ...-cdn-dp-Disable-CDN-DP-on-disconnect.patch | 28 + ...o-usb2-Decrease-delay-between-port-i.patch | 41 + ...o-usb2-More-robust-charger-detection.patch | 115 + ...-the-power-state-of-usb3_generic_phy.patch | 73 + ...-disable-SUSPHY-when-entering-a-role.patch | 47 + ...able-connection-state-separately-fro.patch | 143 + ...ycle-USB3-PHY-on-role-connection-cha.patch | 311 ++ ...r-the-role-even-when-no-cable-is-con.patch | 69 + ...o-usb2-Set-up-charger-detection-mode.patch | 189 ++ ...re-register-the-gadget-on-cable-even.patch | 106 + ...ec-Support-a-Type-C-orientation-swit.patch | 150 + ...chip-typec-Support-a-Type-C-mode-mux.patch | 225 ++ ...chip-typec-Publish-the-DP-lane-count.patch | 106 + ...-dp-Support-ports-driven-by-a-Type-C.patch | 169 ++ ...o-usb2-Learn-the-host-role-from-phy_.patch | 141 + ...-the-UDC-core-when-there-is-no-cable.patch | 102 + ...o-usb2-Do-not-run-charger-detection-.patch | 114 + ...he-PHY-mode-before-starting-the-host.patch | 73 + ...connect-the-gadget-while-no-cable-is.patch | 60 + ...o-usb2-Power-the-PHY-up-before-the-h.patch | 61 + ...dwc3-Require-MPS-aligned-OUT-buffers.patch | 44 + ...yport-Update-the-mux-before-signalli.patch | 106 + ...-rockchip-rk3399-Disable-debug-nodes.patch | 36 + ...ckchip-rk3399-Add-reboot-mode-driver.patch | 36 + ...ip-rk3399-Power-cycle-the-USB3-PHY-o.patch | 43 + ...ts-rockchip-rk3399-Add-dmc_opp_table.patch | 63 + ...-dts-rockchip-rk3399-s-Add-DMC-table.patch | 63 + ...kchip-rk3399-Number-the-CDN-DP-ports.patch | 54 + ...ip-rk3399-pinephone-pro-Add-Type-C-p.patch | 302 ++ ...ip-rk3399-pinephone-pro-Add-internal.patch | 71 + ...ip-rk3399-pinephone-pro-Add-battery-.patch | 178 ++ ...ip-rk3399-pinephone-pro-Add-sound-su.patch | 194 ++ ...ip-rk3399-pinephone-pro-Add-modem-su.patch | 151 + ...ip-rk3399-pinephone-pro-Change-modem.patch | 28 + ...ip-rk3399-pinephone-pro-Add-light-pr.patch | 30 + ...ip-rk3399-pinephone-pro-Add-I2C-supp.patch | 30 + ...ip-rk3399-pinephone-pro-Add-magnetom.patch | 36 + ...ip-rk3399-pinephone-pro-Add-mount-ma.patch | 38 + ...ip-rk3399-pinephone-pro-Enable-POGO-.patch | 49 + ...ip-rk3399-pinephone-pro-Add-pinephon.patch | 187 ++ ...ip-rk3399-pinephone-pro-Switch-LED-b.patch | 42 + ...ip-rk3399-pinephone-pro-Pre-configur.patch | 111 + ...ip-rk3399-pinephone-pro-Improve-SPI-.patch | 37 + ...ip-rk3399-pinephone-pro-Assign-power.patch | 30 + ...ip-rk3399-pinephone-pro-Add-camera-f.patch | 75 + ...ip-rk3399-pinephone-pro-Disable-inte.patch | 36 + 88 files changed, 11185 insertions(+), 83 deletions(-) create mode 100644 device/community/linux-pine64-pinephonepro/0001-arm64-dts-rk3399-pinephone-pro-Keep-modem-regulators.patch create mode 100644 device/community/linux-pine64-pinephonepro/BTF-seg-fault.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0001-ASoC-codecs-rt5640-Fix-output-mixer-input-channel-li.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0002-ASoC-codecs-rt5640-Fix-hpout-restore-when-lout-is-en.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0003-ASoC-codecs-rt5640-Add-input-mixer-input-volume-cont.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0004-ASoC-codecs-rt5640-Allow-to-control-single-ended-dif.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0005-ASoC-codecs-rt5640-Keep-the-codec-enabled-when-idle.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0006-ASoC-codecs-rt5640-Add-support-for-power-supplies.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0007-media-imx258-Add-i2c-supply.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0008-media-imx258-Add-reset-gpio.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0009-media-imx258-Drop-interface-speed-to-1224-mbps.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0010-DEBUG-media-imx258-Add-debug-register-access.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0011-ASoC-rockchip-Fix-doubling-of-playback-speed-after-s.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0012-Revert-usb-dwc3-Abort-suspend-on-soft-disconnect-fai.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0013-thermal-rockchip-Add-support-for-RV1106-SoC.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0014-soc-rockchip-Add-support-for-power-monitoring-driver.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0015-rtc-rockchip-Add-support-for-RTC-present-in-RV1106-S.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0016-thermal-rockchip-Add-support-for-RK3506.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0017-mtd-spi-nor-gigadevice-Add-support-for-gd25lq128e.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0018-clk-rk3399-Export-SCLK_CIF_OUT_SRC-to-device-tree.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0019-clk-rockchip-rk3399-Don-t-allow-to-reparent-dclk_vop.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0020-power-supply-Add-support-for-USB_BC_ENABLED-and-USB_.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0021-mfd-rk8xx-Enable-rk808-clkout2-function.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0022-power-supply-rk818_battery-Add-battery-charger-drive.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0023-power-supply-rk818_battery-Add-code-docs-for-the-HW-.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0024-Revert-usb-typec-tcpm-unregister-existing-source-cap.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0025-usb-typec-altmodes-displayport-Respect-DP_CAP_RECEPT.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0026-usb-typec-tcpm-Unregister-altmodes-before-registerin.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0027-usb-typec-tcpm-Fix-PD-devices-capabilities-registrat.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0028-usb-typec-fusb302-Slightly-increase-wait-time-for-BC.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0029-usb-typec-fusb302-Set-the-current-before-enabling-pu.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0030-usb-typec-fusb302-Retry-reading-of-CC-pins-status-if.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0031-usb-typec-fusb302-Update-VBUS-state-even-if-VBUS-int.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0032-usb-typec-fusb302-Add-OF-extcon-support.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0033-usb-typec-fusb302-Fix-register-definitions.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0034-usb-typec-fusb302-Clear-interrupts-before-we-start-t.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0035-usb-typec-fusb302-Turn-off-VBUS-and-VCONN-on-shutdow.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0036-phy-rockchip-inno-usb2-Add-support-for-RV1106-RV1103.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0037-phy-rockchip-inno-usb2-Add-support-for-RK3506.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0038-phy-rockchip-inno-usb2-Add-PHY-tuning-for-rk3566-rk3.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0039-drm-rockchip-cdn-dp-Disable-CDN-DP-on-disconnect.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0040-phy-rockchip-inno-usb2-Decrease-delay-between-port-i.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0041-phy-rockchip-inno-usb2-More-robust-charger-detection.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0042-usb-dwc3-Track-the-power-state-of-usb3_generic_phy.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0043-usb-dwc3-Always-disable-SUSPHY-when-entering-a-role.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0044-usb-dwc3-Track-cable-connection-state-separately-fro.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0045-usb-dwc3-Power-cycle-USB3-PHY-on-role-connection-cha.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0046-usb-dwc3-Register-the-role-even-when-no-cable-is-con.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0047-phy-rockchip-inno-usb2-Set-up-charger-detection-mode.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0048-usb-dwc3-Do-not-re-register-the-gadget-on-cable-even.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0049-phy-rockchip-typec-Support-a-Type-C-orientation-swit.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0050-phy-rockchip-typec-Support-a-Type-C-mode-mux.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0051-phy-rockchip-typec-Publish-the-DP-lane-count.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0052-drm-rockchip-cdn-dp-Support-ports-driven-by-a-Type-C.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0053-phy-rockchip-inno-usb2-Learn-the-host-role-from-phy_.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0054-usb-dwc3-Tell-the-UDC-core-when-there-is-no-cable.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0055-phy-rockchip-inno-usb2-Do-not-run-charger-detection-.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0056-usb-dwc3-Set-the-PHY-mode-before-starting-the-host.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0057-usb-dwc3-Do-not-connect-the-gadget-while-no-cable-is.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0058-phy-rockchip-inno-usb2-Power-the-PHY-up-before-the-h.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0059-usb-dwc3-Require-MPS-aligned-OUT-buffers.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0060-usb-typec-displayport-Update-the-mux-before-signalli.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0061-arm64-dts-rockchip-rk3399-Disable-debug-nodes.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0062-arm64-dts-rockchip-rk3399-Add-reboot-mode-driver.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0063-arm64-dts-rockchip-rk3399-Power-cycle-the-USB3-PHY-o.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0064-arm64-dts-rockchip-rk3399-Add-dmc_opp_table.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0065-arm64-dts-rockchip-rk3399-s-Add-DMC-table.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0066-arm64-dts-rockchip-rk3399-Number-the-CDN-DP-ports.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0067-arm64-dts-rockchip-rk3399-pinephone-pro-Add-Type-C-p.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0068-arm64-dts-rockchip-rk3399-pinephone-pro-Add-internal.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0069-arm64-dts-rockchip-rk3399-pinephone-pro-Add-battery-.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0070-arm64-dts-rockchip-rk3399-pinephone-pro-Add-sound-su.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0071-arm64-dts-rockchip-rk3399-pinephone-pro-Add-modem-su.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0072-arm64-dts-rockchip-rk3399-pinephone-pro-Change-modem.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0073-arm64-dts-rockchip-rk3399-pinephone-pro-Add-light-pr.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0074-arm64-dts-rockchip-rk3399-pinephone-pro-Add-I2C-supp.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0075-arm64-dts-rockchip-rk3399-pinephone-pro-Add-magnetom.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0076-arm64-dts-rockchip-rk3399-pinephone-pro-Add-mount-ma.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0077-arm64-dts-rockchip-rk3399-pinephone-pro-Enable-POGO-.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0078-arm64-dts-rockchip-rk3399-pinephone-pro-Add-pinephon.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0079-arm64-dts-rockchip-rk3399-pinephone-pro-Switch-LED-b.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0080-arm64-dts-rockchip-rk3399-pinephone-pro-Pre-configur.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0081-arm64-dts-rockchip-rk3399-pinephone-pro-Improve-SPI-.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0082-arm64-dts-rockchip-rk3399-pinephone-pro-Assign-power.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0083-arm64-dts-rockchip-rk3399-pinephone-pro-Add-camera-f.patch create mode 100644 device/community/linux-pine64-pinephonepro/megi_patches/0084-arm64-dts-rockchip-rk3399-pinephone-pro-Disable-inte.patch diff --git a/device/community/linux-pine64-pinephonepro/0001-arm64-dts-rk3399-pinephone-pro-Keep-modem-regulators.patch b/device/community/linux-pine64-pinephonepro/0001-arm64-dts-rk3399-pinephone-pro-Keep-modem-regulators.patch new file mode 100644 index 000000000..7e4801921 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/0001-arm64-dts-rk3399-pinephone-pro-Keep-modem-regulators.patch @@ -0,0 +1,33 @@ +From: Dummy +Subject: [PATCH] arm64: dts: rk3399-pinephone-pro: Keep modem regulators + always-on + +The vcc_4g and vcc_4g_5v regulators power the EG25 modem. Mark them +always-on so the modem is powered at boot when using eg25-manager. +--- + arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts +index 7a3fa599f541..9afef750bb9b 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts +@@ -430,6 +430,7 @@ vcc_4g_5v: regulator-vcc-4g-5v { + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc5v0_sys>; ++ regulator-always-on; + }; + + vcc_4g: regulator-vcc-4g { +@@ -442,6 +443,7 @@ vcc_4g: regulator-vcc-4g { + regulator-min-microvolt = <3800000>; + regulator-max-microvolt = <3800000>; + vin-supply = <&vcc_sys>; ++ regulator-always-on; + }; + + vcc1v8_codec: regulator-vcc1v8-codec { +-- +2.39.5 + diff --git a/device/community/linux-pine64-pinephonepro/APKBUILD b/device/community/linux-pine64-pinephonepro/APKBUILD index 9fe772a4a..3ec50ea31 100644 --- a/device/community/linux-pine64-pinephonepro/APKBUILD +++ b/device/community/linux-pine64-pinephonepro/APKBUILD @@ -1,10 +1,8 @@ maintainer="Rudraksha Gupta " pkgname=linux-pine64-pinephonepro -pkgver=7.0 -_pkgver=7.0 -_tagdate=20251104-2007 -pkgrel=3 -pkgdesc="Mainline kernel for the pinephone pro" +pkgver=7.1 +pkgrel=0 +pkgdesc="Mainline kernel for the Pinephone Pro" arch="aarch64" _flavor="${pkgname#linux-}" url="https://kernel.org" @@ -45,10 +43,16 @@ esac # Currently, the megi kernel is the most up-to-date pinephone pro kernel. As postmarketOS doesn't want to use the Megi kernel directly, we can strip the Megi kernel down to it's essentials by doing the following: # -# git reset --hard v7.0 -# git merge megi/fusb302-7.0 megi/imx258-7.0 megi/rk818-7.0 megi/rt5640-7.0 megi/rk3399-typec-7.0 megi/typec-extcon-7.0 megi/tcpm-7.0 megi/arasan-7.0 megi/ppp-7.0 -# git cherry-pick ebc624f4 # `arm64: dts: rockchip: rk3399-s: Add DMC table ` -# git rebase v7.0 +# git clone https://codeberg.org/megi/linux.git --branch orange-pi-7.1 +# git switch -c ppp-7.1 +# git reset --hard 8cd9520d35a6c38db6567e97dd93b1f11f185dc6 # v7.1 +# +# cherry pick and make sure to fix/skip conflicts... +# +# git cherry-pick $(git log --reverse --format='%H%x09%s' HEAD..orange-pi-7.1 | awk -F'\t' '{n=split($2,a,":"); s=a[n-1]; gsub(/^ +| +$/,"",s); if(s ~/^(arasan|cdn-dp|displayport|dwc3|fusb302|gigadevice|imx258|phy-rockchip-inno-usb2|rk3399|rk3399-pinephone-pro|rk3399-s|rk818|rk818-battery|rk818-charger|rockchip|rockchip-inno-usb2|rt5640|supply|tcpm|typec-extcon|rk8xx|rk818_battery|rockchip-typec)$/) print $1}') +# +# keep modem always on... +# # git am --ignore-whitespace <<'PATCH' # From: Dummy # Subject: [PATCH] arm64: dts: rk3399-pinephone-pro: Keep modem regulators always-on @@ -85,10 +89,96 @@ esac # Source _config="config-$_flavor.$CARCH" source=" - https://codeberg.org/LogicalErzor/linux/archive/ppp-megi-7.0-stripped-modem-fix.tar.gz + ppp-v7.1.tar.gz::https://github.com/torvalds/linux/archive/refs/tags/v7.1.tar.gz config-$_flavor.aarch64 + megi_patches/0001-ASoC-codecs-rt5640-Fix-output-mixer-input-channel-li.patch + megi_patches/0002-ASoC-codecs-rt5640-Fix-hpout-restore-when-lout-is-en.patch + megi_patches/0003-ASoC-codecs-rt5640-Add-input-mixer-input-volume-cont.patch + megi_patches/0004-ASoC-codecs-rt5640-Allow-to-control-single-ended-dif.patch + megi_patches/0005-ASoC-codecs-rt5640-Keep-the-codec-enabled-when-idle.patch + megi_patches/0006-ASoC-codecs-rt5640-Add-support-for-power-supplies.patch + megi_patches/0007-media-imx258-Add-i2c-supply.patch + megi_patches/0008-media-imx258-Add-reset-gpio.patch + megi_patches/0009-media-imx258-Drop-interface-speed-to-1224-mbps.patch + megi_patches/0010-DEBUG-media-imx258-Add-debug-register-access.patch + megi_patches/0011-ASoC-rockchip-Fix-doubling-of-playback-speed-after-s.patch + megi_patches/0012-Revert-usb-dwc3-Abort-suspend-on-soft-disconnect-fai.patch + megi_patches/0013-thermal-rockchip-Add-support-for-RV1106-SoC.patch + megi_patches/0014-soc-rockchip-Add-support-for-power-monitoring-driver.patch + megi_patches/0015-rtc-rockchip-Add-support-for-RTC-present-in-RV1106-S.patch + megi_patches/0016-thermal-rockchip-Add-support-for-RK3506.patch + megi_patches/0017-mtd-spi-nor-gigadevice-Add-support-for-gd25lq128e.patch + megi_patches/0018-clk-rk3399-Export-SCLK_CIF_OUT_SRC-to-device-tree.patch + megi_patches/0019-clk-rockchip-rk3399-Don-t-allow-to-reparent-dclk_vop.patch + megi_patches/0020-power-supply-Add-support-for-USB_BC_ENABLED-and-USB_.patch + megi_patches/0021-mfd-rk8xx-Enable-rk808-clkout2-function.patch + megi_patches/0022-power-supply-rk818_battery-Add-battery-charger-drive.patch + megi_patches/0023-power-supply-rk818_battery-Add-code-docs-for-the-HW-.patch + megi_patches/0024-Revert-usb-typec-tcpm-unregister-existing-source-cap.patch + megi_patches/0025-usb-typec-altmodes-displayport-Respect-DP_CAP_RECEPT.patch + megi_patches/0026-usb-typec-tcpm-Unregister-altmodes-before-registerin.patch + megi_patches/0027-usb-typec-tcpm-Fix-PD-devices-capabilities-registrat.patch + megi_patches/0028-usb-typec-fusb302-Slightly-increase-wait-time-for-BC.patch + megi_patches/0029-usb-typec-fusb302-Set-the-current-before-enabling-pu.patch + megi_patches/0030-usb-typec-fusb302-Retry-reading-of-CC-pins-status-if.patch + megi_patches/0031-usb-typec-fusb302-Update-VBUS-state-even-if-VBUS-int.patch + megi_patches/0032-usb-typec-fusb302-Add-OF-extcon-support.patch + megi_patches/0033-usb-typec-fusb302-Fix-register-definitions.patch + megi_patches/0034-usb-typec-fusb302-Clear-interrupts-before-we-start-t.patch + megi_patches/0035-usb-typec-fusb302-Turn-off-VBUS-and-VCONN-on-shutdow.patch + megi_patches/0036-phy-rockchip-inno-usb2-Add-support-for-RV1106-RV1103.patch + megi_patches/0037-phy-rockchip-inno-usb2-Add-support-for-RK3506.patch + megi_patches/0038-phy-rockchip-inno-usb2-Add-PHY-tuning-for-rk3566-rk3.patch + megi_patches/0039-drm-rockchip-cdn-dp-Disable-CDN-DP-on-disconnect.patch + megi_patches/0040-phy-rockchip-inno-usb2-Decrease-delay-between-port-i.patch + megi_patches/0041-phy-rockchip-inno-usb2-More-robust-charger-detection.patch + megi_patches/0042-usb-dwc3-Track-the-power-state-of-usb3_generic_phy.patch + megi_patches/0043-usb-dwc3-Always-disable-SUSPHY-when-entering-a-role.patch + megi_patches/0044-usb-dwc3-Track-cable-connection-state-separately-fro.patch + megi_patches/0045-usb-dwc3-Power-cycle-USB3-PHY-on-role-connection-cha.patch + megi_patches/0046-usb-dwc3-Register-the-role-even-when-no-cable-is-con.patch + megi_patches/0047-phy-rockchip-inno-usb2-Set-up-charger-detection-mode.patch + megi_patches/0048-usb-dwc3-Do-not-re-register-the-gadget-on-cable-even.patch + megi_patches/0049-phy-rockchip-typec-Support-a-Type-C-orientation-swit.patch + megi_patches/0050-phy-rockchip-typec-Support-a-Type-C-mode-mux.patch + megi_patches/0051-phy-rockchip-typec-Publish-the-DP-lane-count.patch + megi_patches/0052-drm-rockchip-cdn-dp-Support-ports-driven-by-a-Type-C.patch + megi_patches/0053-phy-rockchip-inno-usb2-Learn-the-host-role-from-phy_.patch + megi_patches/0054-usb-dwc3-Tell-the-UDC-core-when-there-is-no-cable.patch + megi_patches/0055-phy-rockchip-inno-usb2-Do-not-run-charger-detection-.patch + megi_patches/0056-usb-dwc3-Set-the-PHY-mode-before-starting-the-host.patch + megi_patches/0057-usb-dwc3-Do-not-connect-the-gadget-while-no-cable-is.patch + megi_patches/0058-phy-rockchip-inno-usb2-Power-the-PHY-up-before-the-h.patch + megi_patches/0059-usb-dwc3-Require-MPS-aligned-OUT-buffers.patch + megi_patches/0060-usb-typec-displayport-Update-the-mux-before-signalli.patch + megi_patches/0061-arm64-dts-rockchip-rk3399-Disable-debug-nodes.patch + megi_patches/0062-arm64-dts-rockchip-rk3399-Add-reboot-mode-driver.patch + megi_patches/0063-arm64-dts-rockchip-rk3399-Power-cycle-the-USB3-PHY-o.patch + megi_patches/0064-arm64-dts-rockchip-rk3399-Add-dmc_opp_table.patch + megi_patches/0065-arm64-dts-rockchip-rk3399-s-Add-DMC-table.patch + megi_patches/0066-arm64-dts-rockchip-rk3399-Number-the-CDN-DP-ports.patch + megi_patches/0067-arm64-dts-rockchip-rk3399-pinephone-pro-Add-Type-C-p.patch + megi_patches/0068-arm64-dts-rockchip-rk3399-pinephone-pro-Add-internal.patch + megi_patches/0069-arm64-dts-rockchip-rk3399-pinephone-pro-Add-battery-.patch + megi_patches/0070-arm64-dts-rockchip-rk3399-pinephone-pro-Add-sound-su.patch + megi_patches/0071-arm64-dts-rockchip-rk3399-pinephone-pro-Add-modem-su.patch + megi_patches/0072-arm64-dts-rockchip-rk3399-pinephone-pro-Change-modem.patch + megi_patches/0073-arm64-dts-rockchip-rk3399-pinephone-pro-Add-light-pr.patch + megi_patches/0074-arm64-dts-rockchip-rk3399-pinephone-pro-Add-I2C-supp.patch + megi_patches/0075-arm64-dts-rockchip-rk3399-pinephone-pro-Add-magnetom.patch + megi_patches/0076-arm64-dts-rockchip-rk3399-pinephone-pro-Add-mount-ma.patch + megi_patches/0077-arm64-dts-rockchip-rk3399-pinephone-pro-Enable-POGO-.patch + megi_patches/0078-arm64-dts-rockchip-rk3399-pinephone-pro-Add-pinephon.patch + megi_patches/0079-arm64-dts-rockchip-rk3399-pinephone-pro-Switch-LED-b.patch + megi_patches/0080-arm64-dts-rockchip-rk3399-pinephone-pro-Pre-configur.patch + megi_patches/0081-arm64-dts-rockchip-rk3399-pinephone-pro-Improve-SPI-.patch + megi_patches/0082-arm64-dts-rockchip-rk3399-pinephone-pro-Assign-power.patch + megi_patches/0083-arm64-dts-rockchip-rk3399-pinephone-pro-Add-camera-f.patch + megi_patches/0084-arm64-dts-rockchip-rk3399-pinephone-pro-Disable-inte.patch + 0001-arm64-dts-rk3399-pinephone-pro-Keep-modem-regulators.patch + BTF-seg-fault.patch " -builddir="$srcdir/linux" +builddir="$srcdir/linux-$pkgver" prepare() { default_prepare @@ -111,7 +201,7 @@ package() { INSTALL_MOD_STRIP=1 \ INSTALL_PATH="$pkgdir"/boot \ INSTALL_DTBS_PATH="$pkgdir"/boot/dtbs-$_flavor - rm -f "$pkgdir"/lib/modules/*/build "$pkgdir"/lib/modules/*/source + rm -f "$pkgdir"/usr/lib/modules/*/build "$pkgdir"/usr/lib/modules/*/source install -D "$builddir"/include/config/kernel.release \ "$pkgdir"/usr/share/kernel/$_flavor/kernel.release @@ -119,6 +209,92 @@ package() { sha512sums=" -8a2e76553f0635d5891ae5e11219506da73893d78ce1cccf3421c0bbaf87c6caf48d927f5be7c8e2a8119e05cb9035e7b3c15bea786ff2eaeafd693b9219a428 ppp-megi-7.0-stripped-modem-fix.tar.gz -510a18c5ef416be1eab1c93d9b62b4c3530fb666e8166d5ab3fd94998773f9d405aac4deec3be03390195ad0f1a1c5efadf19b19356332f49a6c426e95106733 config-pine64-pinephonepro.aarch64 +10c0cfd70a7a5731963cb4c7538396f6ed637d7db532a1c04b00628af47f4b81ffb3d92200e64ba1ce04047e4b2e39e6845c4067762e85ad9df13f2740c10397 ppp-v7.1.tar.gz +f489be70242738c722dd588b9cadc94dbab329a76fed396473318f94abcc9d724ed54cd06f5d101e9b95e5a9098e46a5c8c95ddeb6d30f3b87f822b83080ac43 config-pine64-pinephonepro.aarch64 +cafe0f07dab850059475c8f84df0b859d65bedda455517a5996f75d4e5f28c7fe66ac5a2b2e4ee6b46ed173819b899cc37ac08d1106bf635beab018ad636ee1e 0001-ASoC-codecs-rt5640-Fix-output-mixer-input-channel-li.patch +5db306c6728666c3e64ca28a3cc330d7452c87c9119aa8cd57a4549cee7aee1c1137dedece8c50bb58d1040bd861d7722c6341112b24699919fb5a3bd816afdb 0002-ASoC-codecs-rt5640-Fix-hpout-restore-when-lout-is-en.patch +a734d758f0e84fbd7dd3c8e7daa24ca8778af2d25e8d1df3c7e27978f616428fa57e507dede65f59dab6ce23597380b69d83fde35b549b3c0d8b55a38f58a57b 0003-ASoC-codecs-rt5640-Add-input-mixer-input-volume-cont.patch +b7b94b6b2f144932009fa94ad0e5505b5749cea446221ef94e51490117b9a747080a876d7a004a0b0829fba1e3ecbb714f867a3725e40cf51fb90ff49a7c0da9 0004-ASoC-codecs-rt5640-Allow-to-control-single-ended-dif.patch +5c8e63d2e3fe0b4805f74ad0da75159495dd82592e701160d07c4729f00e9c9de7d23dee6250fb62fbbba05c3a0ca42f6495e2f1e51fd1d330f62394003ac222 0005-ASoC-codecs-rt5640-Keep-the-codec-enabled-when-idle.patch +89c5ecda11e85c795aaf5e718b7c636ed149ca17ca71068cc329abd598edb568584db3b559f9cc4074c8eef4e4e9f749181726e416747ca9b853e6bdd30b4dd1 0006-ASoC-codecs-rt5640-Add-support-for-power-supplies.patch +0a865555b611922507021b262d5ba6f7991ddc0354a440543aa18c2ddc9c47a6807905fd0fcd23e33dfa1f93a337f016114230c472c9ee5f4d56fa45866e828f 0007-media-imx258-Add-i2c-supply.patch +a9feac6a2eaf059699584dab91665a3bcf4afce09dba8c69739c77a1fc3639d01de1dc8fd68d3593afeeac8413a1c1e37d6bf59f272e9f8e504fa67b26d07f76 0008-media-imx258-Add-reset-gpio.patch +50983f8bf418b0b602aa4fedaba273316d13eebff0c4a03f8f680851797a1f28fcf2da0ca98d1fa61cb0e3eb30a36a23b936262f426bfa38a4f43ad64116e307 0009-media-imx258-Drop-interface-speed-to-1224-mbps.patch +a7c6cde4aa77e5df3e464f7eef00859d1ea71f4874f1d447cb78dbc722691380f60aabfef39ce1e740448593a5017b50cb38d01b68ea7c279c808f5043acfce6 0010-DEBUG-media-imx258-Add-debug-register-access.patch +001b8f0c086b24acc5b53f0ce13a10d754903314b21f8fc22c45b5bd6ea719c09c2c2b51a839710e1d2fcff70f7dceeac7ac44a24fd42acb8c99cb1bb3c2023c 0011-ASoC-rockchip-Fix-doubling-of-playback-speed-after-s.patch +f0b43b03a918c66f96d6d2987762eefdd4c5a11f4252a0b977532a17a0d7a24498b10511a059dcb07f7e572cb3864599a31c1fc3ca7505727cf1e08b64a9d614 0012-Revert-usb-dwc3-Abort-suspend-on-soft-disconnect-fai.patch +1bf5e2cef1ecf4d470b6ef0159fce095eee239f4c296c6bbbc14edf510fb9a20b0048ac537876c91e2cc4c0318572c2eaa727ac5ddacf3dbddea2bf0202043e0 0013-thermal-rockchip-Add-support-for-RV1106-SoC.patch +7b0e3cb86ebe501fcf82433c2cc046720f311cdeb423d3191fb472f54501e99eafecaf5da338698453e0feb6c00ed29257ecf1a5765290911d47d77467875f43 0014-soc-rockchip-Add-support-for-power-monitoring-driver.patch +67c5119ae325a9e328e5d9e92690f575d2cfd5c46304c65a4c7966330800fadd7a314fe57ba76c29970ed9afbfebbdf676e95b1a7f3a8b4328ba2dba87d7f2e3 0015-rtc-rockchip-Add-support-for-RTC-present-in-RV1106-S.patch +a9a8aa2da2f503d86681e4b61606db6bfac4622030f05ea081f4d75b05edfcf4794a3a7575de4c1c9a5025aa3f25be6fa348418f97d06c0bed88843fc2aca9c5 0016-thermal-rockchip-Add-support-for-RK3506.patch +96a56ce7aa57c8e1e04892dcf12c043143f6e0dc0affddeb4c565865358d8b51d84fb2e25ef58c9a07a684a8e43058f64dc206c1371b3b07d0e115444885469f 0017-mtd-spi-nor-gigadevice-Add-support-for-gd25lq128e.patch +c7dfed2e10fc2902647134ce09351c2567d04be3d190ecacd09f08130587311553d12831d1b0652b41eb949f0172308efaa65cda0ea0b53aeff92c007b805619 0018-clk-rk3399-Export-SCLK_CIF_OUT_SRC-to-device-tree.patch +1639b72d3552817018fb2811388d30c0c5f958ef0e14dd395962db0394bc8cdd8369d70ca494668cbad0a36e61df60cf508686ac06794639038dbc0d15382477 0019-clk-rockchip-rk3399-Don-t-allow-to-reparent-dclk_vop.patch +247a291979eafbccdfe85c99a569235f7fff860f037e2d47fd76312bb20277c0f0fa3e523be969f977657b602a88b846f2ddc058c243b64828bcca0315fe7386 0020-power-supply-Add-support-for-USB_BC_ENABLED-and-USB_.patch +888dbcd2af60be116391e9464b0915a2468fcb2661803f2df54e9df9b1d38c718eabaf704c0d9c6cbf96f73b115ed14bac0d2bbbb87617cf10181b357a2c719e 0021-mfd-rk8xx-Enable-rk808-clkout2-function.patch +73e2cadbfacb5c8e9547ca410efb6c11a9c87dc8239fd7096f2373d56a7697f19114c08811b8a01b1de5e199cbd20f9a78cc5c4e0db6830b79842a8eede9d079 0022-power-supply-rk818_battery-Add-battery-charger-drive.patch +6d7027d970a389213ef8a233c564df25e854f8635db2dbf4c14f7d29de51ad6d3d9ee61523513be71b382c2ee1d730bd32160b1809ed0dcbfec2c7b24c6547ad 0023-power-supply-rk818_battery-Add-code-docs-for-the-HW-.patch +b443aaa45d2bcb98b2b6c43577722fb718198f06baf126e2c1ea2d636a8874787a972c45d0bf83bdceb783920280a7cfeeb7e8d18b2b2634f685e974cc362e97 0024-Revert-usb-typec-tcpm-unregister-existing-source-cap.patch +db34fb8ee7c4ba3baba480ccbe7df866fe7f5277a80739f7eeeadde80c1a4fa103df4f5995ba9660de725ece6aabeaefc302db39d50b6fa8c7fe3fdb212c6e26 0025-usb-typec-altmodes-displayport-Respect-DP_CAP_RECEPT.patch +98229ad878e1158c887c63c1cfe72b7ca7084bf6b42f092005ba1e327307c20e7c77246cb9258ad2f0813722a91e6023f45553230bff7d248c1923c1452a94c4 0026-usb-typec-tcpm-Unregister-altmodes-before-registerin.patch +89edc9f8935f6905e37e18a554787cf5262624f4c5b9e4dfaa984022bdfb1e0293e95bf731f27ca7640f352167676924b720d9a6a09bded813c07fd152878f63 0027-usb-typec-tcpm-Fix-PD-devices-capabilities-registrat.patch +196080cfeee98682195153f0918edbd08b302e5bad5afc9860747b0b6b90159a133813e0b6940ffabf9a88be36088a680f647cd5b611083c9139ea123989783f 0028-usb-typec-fusb302-Slightly-increase-wait-time-for-BC.patch +dc4d378cd114949ad51f47a8da7deb9cda63a75432f6f386086d41fa0ebe126657da270af89df84495c1777be7e5041274a780877b2ce6ca387e35aaaca7a46d 0029-usb-typec-fusb302-Set-the-current-before-enabling-pu.patch +67049fa20660f5924cf06001ac9e55363f337e4cda084f79b828a9863627893c5a3f4d5cc809d613f60d792540eee579097b652bf49dfee8c9840892485beaad 0030-usb-typec-fusb302-Retry-reading-of-CC-pins-status-if.patch +3bf2d0ac9c737eb761461ab5eb5597c05ef8b368a69b9b0c48ae2b68e58da2d432cd9060fea80c2541b7f453c6fc93657ef94aa073a893b48a7407632d46820d 0031-usb-typec-fusb302-Update-VBUS-state-even-if-VBUS-int.patch +d9b11a9acbbb64668332e202c786457f370c7f9d2bdedf6144b434d992d067ada00ab027067da0a597277c726ccb7ae68d49580848a95ea88775f0a6837586f7 0032-usb-typec-fusb302-Add-OF-extcon-support.patch +4946338c55952347050ac2c3cb814ce778b8c9933a1974ed093daf82e8234b0a2d8ccb808c9beb29451d41c80a6cc03917a9d1a2a72a374a47374d20d3ca460f 0033-usb-typec-fusb302-Fix-register-definitions.patch +f72b87321bb0ff45e58e729587d6edf97604f1cbf3b5c82e9b26289096f752b0725e800a22525ab662f378eca2637463e3ceb7e213b86f6f5293705dd509d119 0034-usb-typec-fusb302-Clear-interrupts-before-we-start-t.patch +4ae24e87a3b514a8fbb41cf47d5d00292bc399ed8fd1299ef4dc4990c31143c5c6d3fbc6c6480089c492b3988f743a86b30420c91a1d551968a3758ea9538b03 0035-usb-typec-fusb302-Turn-off-VBUS-and-VCONN-on-shutdow.patch +065427abc79c435762e25a40cc13b35a14feeca318f767d0384970cf57e7c785c796923bd891746edd0497079941313b0b7839c7988f63e243c8166a0c8f3579 0036-phy-rockchip-inno-usb2-Add-support-for-RV1106-RV1103.patch +9115fe459431dac6558d60f9e6ebab1fef726413c8a3bdb88b21e402f2b1ccd0c485ce65aa9feaca948b2ef88bff6ea38973c761bac0f7dccb7b019938c37ae5 0037-phy-rockchip-inno-usb2-Add-support-for-RK3506.patch +2abd784fd1a6abe3ca5da3919f7a9b7617379d06340cc9549dbf3dee2dcf095fb5aa3735d08e93f4363247667ba14d9f6c96e414afa965b65e12fd00af08bd48 0038-phy-rockchip-inno-usb2-Add-PHY-tuning-for-rk3566-rk3.patch +60656a8bdf90e92661d5d2b69aad78489955e5a82edbee67b385a3285bbb59d59c615e47ad83f993ed3c5b4ee6f39958e5199492d41cf652e333473d27136855 0039-drm-rockchip-cdn-dp-Disable-CDN-DP-on-disconnect.patch +a941594dd09c6468c6b89ba56f8ba127aedc15228904667f521cfbf9d25dafac8dc8e8ecddea3c86af2a1305d2fb40035f85bf3b559a5574bad3e0362649f290 0040-phy-rockchip-inno-usb2-Decrease-delay-between-port-i.patch +b0093aec9b85ef54400585c23b9a1cc2b31598c847cb998ae03f277eaa81a0cdf8c979ac7b8d581b4dff7bd70c601d812eb6ef7bff543fbc00f5ba9436cea748 0041-phy-rockchip-inno-usb2-More-robust-charger-detection.patch +32e6b984e14996387c232ac0ac708d7eaf75d1fc6de3ec5df53a110368be270177cd02253523c66163f6d0c227b0b6a18d171411d76c2757bbe4dd13facb8920 0042-usb-dwc3-Track-the-power-state-of-usb3_generic_phy.patch +7b4ce3f693b3d1731693c79fdf114de0c67b5a74406b3b46b1bd133babb6e5a20c3e2466feb33239dfc9dd08f9db68fc018c8a80a1115dfd2fd8812b7da017fa 0043-usb-dwc3-Always-disable-SUSPHY-when-entering-a-role.patch +302dad47110479739cb5348c938ad9c9c3b41d0ce46c45ee49211cf71578ca2342edaea664b52d3855fd5a7e8ae7fd850d80bd080a43423c349254e47ff79b11 0044-usb-dwc3-Track-cable-connection-state-separately-fro.patch +e08557f8efe8f730d358f247771d32d3001ea3337db950f3a785b632be8098044933276f2b1a5b376270b88bb21345c056ccb818b74e59b93fb291d062edc85c 0045-usb-dwc3-Power-cycle-USB3-PHY-on-role-connection-cha.patch +107bdb8b4d289306b8f4be1f7088a44a239e8e66cc286d9108f14281d7bb64a5defb54909ec9a356b7bf60aa83152e5c9ac9c5aa8f872a69cf201a5b9c8cff69 0046-usb-dwc3-Register-the-role-even-when-no-cable-is-con.patch +46a8452081223bdf5864c86f50e070a796b7d495b77ad861804e862d2659df29f9c17130bc9ff438b5c9a8cb8df4c3c55191eecb339c5691ad6d9c341c1d6293 0047-phy-rockchip-inno-usb2-Set-up-charger-detection-mode.patch +ec262e3094fe7edac553d8b29662182ca9b617bba266c1e959b04fea1c358dc26be123cb0e5e286e08aac5210f8ba26172230bc9508b8685a293d0349276dc6a 0048-usb-dwc3-Do-not-re-register-the-gadget-on-cable-even.patch +3561f087e06bb61eb1f3c10250120bf747e879aa7aebe039f148d20a8960c9b545f90a882960bc91a4eda593092dcf36de34e81074ed2ccbadb37a9cc2c04731 0049-phy-rockchip-typec-Support-a-Type-C-orientation-swit.patch +cf24ee439036f001d66a6c9c8662f8cafcb0e3b068269782de00b8a1fb14a58b39b66a17078bc0d9c22c8e76093633aeae553c3c05aec803e08b96a40134a3f6 0050-phy-rockchip-typec-Support-a-Type-C-mode-mux.patch +5d659877cb2fd5f099eac102ef2f6da7975215bfbf52b8790999cb11a8be06f37c7c87d26e6fa1c38d6c803e6988913bfb91b41948585fca1d3513d2471d0c77 0051-phy-rockchip-typec-Publish-the-DP-lane-count.patch +76d1b5efc343564f7dde1dbcb8f46a564879395aa12b3b6aa21aaf1ea018ee14c5c2a0dea6cb13d5609a716b623bf008aa11e29021363a57dc33fdf762f6fd43 0052-drm-rockchip-cdn-dp-Support-ports-driven-by-a-Type-C.patch +b6f71b575b69b5a44892bfd51253fff8e422d701d95e1b4cf318b1263ed3227a7e861f181458f37af933e26d3756e985646e2b9f9cec654ce0ac419f822d8a04 0053-phy-rockchip-inno-usb2-Learn-the-host-role-from-phy_.patch +cfedc21450d5ac15411f0703179f312dcf1a7d179d8983a269b69e06b2c07d1292abbb9a741caf7e18d091bac47d87bd0be5382a1b0077136ee67e4fa8e25b0e 0054-usb-dwc3-Tell-the-UDC-core-when-there-is-no-cable.patch +c79dc3ff0ad97514df04bb295f1a33d022c3200b02c21162a2cd9c1da453c935be3d49486904741968dfffda18ff7c273b783eac3ccab875ca99964c07b4eacc 0055-phy-rockchip-inno-usb2-Do-not-run-charger-detection-.patch +56f43f4f6448506d7ddce07b5cb0bcfa8a82fd799da17c7be0c9cec0d7194035455b9850a9637ad1226f80fa01b6a6834c33e3bc50da855e5121160eda806a44 0056-usb-dwc3-Set-the-PHY-mode-before-starting-the-host.patch +86a7b1e9f59e1532c985d3a4a1edd196e4ab47b3047627306e9e7fe122bf3f7fa6a2049f9467d30a221c3d65277600e91d71e9fa295c388117b379456adc2970 0057-usb-dwc3-Do-not-connect-the-gadget-while-no-cable-is.patch +9e5ad8a5f08e6419f6bd25162fe4e542b2cc33890ef761e35fac4fb324f10d5df96fe0f5be3458ee636dd57f05f90ced31d01c084a3580beed7c1c71573f7b23 0058-phy-rockchip-inno-usb2-Power-the-PHY-up-before-the-h.patch +2c6d05ddb458189aedb70f8ba6036fadc942f1b2634003c2f2325625a8a1a4afa933c927d893b4fdac406b593cbeb321320be6f835ca7cb0268448738f850ffc 0059-usb-dwc3-Require-MPS-aligned-OUT-buffers.patch +d40ca07d6379fedd78858097c4e57fea2a52a24254be0a534874c641d1e9ed5e1ee96755420fd45bea1ec538b0340f326712230d5fb1377a07521c8c6c93debf 0060-usb-typec-displayport-Update-the-mux-before-signalli.patch +36a5a4ca60c45161e7913edde968d87884d6c552d6f0bc119a9b6ff3c0d0d3e750410df4cd891c0233f56c3a5b80ef7a7aadb34ec4936dce1f399301fa993001 0061-arm64-dts-rockchip-rk3399-Disable-debug-nodes.patch +15998054b6521020e4895c2024ce2ad9db3650220ee0d3eb693fa44c72086520eefa592c824b015d514b593ca7ded1d3c5b6e1f7146b1133598cae13b4994c62 0062-arm64-dts-rockchip-rk3399-Add-reboot-mode-driver.patch +60904d0dd44dd3740991dcdfb752d7d78470a9814414d407e7ca2de0d4061716deb1c70e08ae1937684e05f5ef6ba4fe57fbcdea69374053906ee3753d11fc63 0063-arm64-dts-rockchip-rk3399-Power-cycle-the-USB3-PHY-o.patch +dff55b92a62499fe5c46d68debeac92213038058b8fd19652b4ae7cc5980205bdb560e568cba4c8109ae298fceeb79c7815f0f405501c8fbccdb759d828bd5f5 0064-arm64-dts-rockchip-rk3399-Add-dmc_opp_table.patch +9f8b94efc2d5c0a6602122731e70a29f8439d2b4861211da189cdb845f707530bd7c73956ad85c94aeb94ec8b62918f8f6b17687b84470087580b3a15c4a5a55 0065-arm64-dts-rockchip-rk3399-s-Add-DMC-table.patch +9ea12b3c4ccc408cb07116da003186ac2060cece7c4847f55489c6fd0cae6035a2555eebf0bbbb54d674d44fc5db0e1bbe1a2ded48dc5ec2a6a3df4c2e2ca185 0066-arm64-dts-rockchip-rk3399-Number-the-CDN-DP-ports.patch +1ecce40405e69b9fec96d1535622ca71ccb5fc76753b459c9e321c7903178623ddc31f5527ca1949b071d47ce1f73dbce74dea8059bc1b683d253f83d9130c80 0067-arm64-dts-rockchip-rk3399-pinephone-pro-Add-Type-C-p.patch +2f1dcbe2f0538cdc4c01aa2992afc1f26d1599e1505780b286c1e645a81be5ed1f44288bf5024c2e3178e2f438f38b7220c76f1fce842548cdcec37728d18b9f 0068-arm64-dts-rockchip-rk3399-pinephone-pro-Add-internal.patch +479cfb8e65ccd95d656ff0fe212aa31cfdd7f3e298d612da27063dcff7e62324210b627e7ab210a273142d3f15384b5f2cadfb1983f3864145355421f99f0957 0069-arm64-dts-rockchip-rk3399-pinephone-pro-Add-battery-.patch +bdf826beedcfe769acd7475f7a30c3adc8225fa103dd1e37c5a31d750fea3044b077f4903986c0ee3d3102e79948f4375bed7a674498e4c21b34b3ba44e54ba1 0070-arm64-dts-rockchip-rk3399-pinephone-pro-Add-sound-su.patch +443688c9b00de95b9bd23fbc08741ef488c849211151f7f8bae136149e0f0aa562d2353875120333e2e7f3e187abfd0bebdc1b2b006d725d33d638e0e20496f6 0071-arm64-dts-rockchip-rk3399-pinephone-pro-Add-modem-su.patch +eb66518e6876badf3ef3bc766328ff621031194dc067ecea5a0ed629702c08cd5f964d3c25c2a1aae9fc5b13615f212c7150ea0c2afe33b0427a1554a6bd4029 0072-arm64-dts-rockchip-rk3399-pinephone-pro-Change-modem.patch +70f83b6210e991b546c70c594e8d6f28ebc557c301acf1ef9f0d1df625dd709f3744ae1738865626ae7ca5b6ce9682bfbc052766bb6989d67b261abd6606ce85 0073-arm64-dts-rockchip-rk3399-pinephone-pro-Add-light-pr.patch +077deb29bf5182a0f1689bc7e6da41f553cc7a2c8a2ef96a2b111f9d5e9e2ba8f26d3228af20f79d15f45c0a69aa8f60733a422fad1895700a299a8aad7d1e51 0074-arm64-dts-rockchip-rk3399-pinephone-pro-Add-I2C-supp.patch +fbb3e8fa505f8a97d512834dd75b849cad5aed4d357dbbe2904d9b435bb8f19c3863ef7417c4ef4afeefc224bd4ad6eab74f4bc00ac66b69aaccb001c29fba71 0075-arm64-dts-rockchip-rk3399-pinephone-pro-Add-magnetom.patch +2d79639df7928f464217e71e4219a40fa082e36bb410b3d1fa12bb1ab6246199c4976fba84fa32e621939c0c37b08929d2be7380756aec40b8bcaff91298e81d 0076-arm64-dts-rockchip-rk3399-pinephone-pro-Add-mount-ma.patch +e1e1fc09232f21c69b8a2613d3da6063d669f8f97a340954702e7227214f1a6c4adc866420618cd365753767a0da93e52ac40c3575e5beac9dc778c93895b622 0077-arm64-dts-rockchip-rk3399-pinephone-pro-Enable-POGO-.patch +ac1e93b71deb4cf8a070c3380061b46e1e1cea094346d02d5f8ed326d3f0e5316ca4ebdae7677ceea3d4456a580542f0075d29df50d1a37d8817392e59e5d380 0078-arm64-dts-rockchip-rk3399-pinephone-pro-Add-pinephon.patch +8a160ffa6e95afbf58608f030c3ca3a7d7de298f7a20ce8e298eba54576a7f99ffff6389e36a4dc5d8bb1110e112c72e0718e4d8e88fe4049019119ba0c1a8fa 0079-arm64-dts-rockchip-rk3399-pinephone-pro-Switch-LED-b.patch +5308f80bd8fdaa3d76f26bd278f2d027689b5e75a8d0e6a00e13b6c056bdd1b30875105e2afbe4daa47f282ab3312df3747e74368601f745b394f2f5874d018a 0080-arm64-dts-rockchip-rk3399-pinephone-pro-Pre-configur.patch +9f61f0602d232c583ec1e447037e8f69eb89fae674e8e1cf65a187d224bc3eeb5da7ce209045c2a48508d9202b355a3ad001ed9ed365b0afdf5cf7e6b98822d3 0081-arm64-dts-rockchip-rk3399-pinephone-pro-Improve-SPI-.patch +04c6e3f63e897d044945cf05f7a15c3d99ec0889f3518691738e84ffa115532b70215695e9e7c1b6b6c3483b872ed676cefd9cebdcf18f0e83db3d5207045813 0082-arm64-dts-rockchip-rk3399-pinephone-pro-Assign-power.patch +2baa9dc87a0f7d9f60e0f0429c83943dab6edc25e963fe70d5bf322e713217ce8285691ebbc7b6f73fd3d48a0fd36c8053f819af904753898b27cf12e8e1df54 0083-arm64-dts-rockchip-rk3399-pinephone-pro-Add-camera-f.patch +e820d9169b6854832d1a29d0c1925732155afe08e72aa865a6804ee67359137cdcbd967acee41913ef36ff1acae02346c4a5f8b07337ab4f9d56ae45b75b56f3 0084-arm64-dts-rockchip-rk3399-pinephone-pro-Disable-inte.patch +79ac34ea9e3f4e74809c5f30bc90c511a3bf02ed9c00475db2adb0b009c5609b00f14dedccafb0f9f2dea136332df8416b78920807df100faa2ce937484871d3 0001-arm64-dts-rk3399-pinephone-pro-Keep-modem-regulators.patch +e2555390d48cbbdc32a7d3f0c27599ff88f2fe3e786d1d0086caaa5b092cc3edcb6e95e2fb07034edb3793f6dc954da0662c723202eb7e2c4956c99b50919b12 BTF-seg-fault.patch " diff --git a/device/community/linux-pine64-pinephonepro/BTF-seg-fault.patch b/device/community/linux-pine64-pinephonepro/BTF-seg-fault.patch new file mode 100644 index 000000000..1fc18c672 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/BTF-seg-fault.patch @@ -0,0 +1,161 @@ +From b23705e6afb6ac4ae6d220dcb35975698667dd76 Mon Sep 17 00:00:00 2001 +From: Carlos Llamas +Date: Sat, 23 May 2026 16:27:21 +0000 +Subject: [PATCH] libbpf: Fix UAF in strset__add_str() + +strset_add_str_mem() might reallocate the strset data buffer in order to +accommodate the provided string 's'. However, if 's' points to a string +already present in the buffer, it becomes dangling after the realloc. +This leads to a use-after-free when attempting to memcpy() the string +into the new buffer. + +One scenario that triggers this problematic path is when resolve_btfids +attempts to patch kfunc prototypes using existing BTF parameter names: + + | resolve_btfids: function bpf_list_push_back_impl already exists in BTF + | Segmentation fault (core dumped) + +Compiling resolve_btfids with fsanitize=address generates a detailed +report of the UAF: + + | ================================================================= + | ERROR: AddressSanitizer: heap-use-after-free on address 0x7f4c4a500bd4 + | ==1507892==ERROR: AddressSanitizer: heap-use-after-free on address 0x7f4c4a500bd4 at pc 0x55d25155a2a8 bp 0x7ffcef879060 sp 0x7ffcef878818 + | READ of size 5 at 0x7f4c4a500bd4 thread T0 + | #0 0x55d25155a2a7 in memcpy (tools/bpf/resolve_btfids/resolve_btfids+0xcf2a7) + | #1 0x55d2515d708e in strset__add_str tools/lib/bpf/strset.c:162:2 + | #2 0x55d2515c730b in btf__add_str tools/lib/bpf/btf.c:2109:8 + | #3 0x55d2515c9020 in btf__add_func_param tools/lib/bpf/btf.c:3108:14 + | #4 0x55d25159f0b5 in process_kfunc_with_implicit_args tools/bpf/resolve_btfids/main.c:1196:9 + | #5 0x55d25159e004 in btf2btf tools/bpf/resolve_btfids/main.c:1229:9 + | #6 0x55d25159cee7 in main tools/bpf/resolve_btfids/main.c:1535:6 + | #7 0x7f4c78e29f76 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16 + | #8 0x7f4c78e2a026 in __libc_start_main csu/../csu/libc-start.c:360:3 + | #9 0x55d2514bb860 in _start (tools/bpf/resolve_btfids/resolve_btfids+0x30860) + | + | 0x7f4c4a500bd4 is located 13268 bytes inside of 2829000-byte region [0x7f4c4a4fd800,0x7f4c4a7b02c8) + | freed by thread T0 here: + | #0 0x55d25155b700 in realloc (tools/bpf/resolve_btfids/resolve_btfids+0xd0700) + | #1 0x55d2515c426c in libbpf_reallocarray tools/lib/bpf/./libbpf_internal.h:220:9 + | #2 0x55d2515c426c in libbpf_add_mem tools/lib/bpf/btf.c:224:13 + | + | previously allocated by thread T0 here: + | #0 0x55d25155b2e3 in malloc (tools/bpf/resolve_btfids/resolve_btfids+0xd02e3) + | #1 0x55d2515d6e7d in strset__new tools/lib/bpf/strset.c:58:20 + +While resolve_btfids could be refactored to avoid this call path, let's +instead fix this issue at the source in strset__add_str() and avoid +similar scenarios. + +Let's check if set->strs_data was reallocated and whether 's' points to +an internal string within the old strset buffer. In such case, 's' is +reconstructed to point to the new buffer. + +While already here, also fix strset__find_str() which suffers from the +same problem by factoring out the common operations into a new helper +function strset_str_append(). + +Fixes: 90d76d3ececc ("libbpf: Extract internal set-of-strings datastructure APIs") +Suggested-by: Andrii Nakryiko +Suggested-by: Mykyta Yatsenko +Signed-off-by: Carlos Llamas +Signed-off-by: Andrii Nakryiko +Link: https://lore.kernel.org/bpf/20260523162722.2718940-1-cmllamas@google.com +--- + tools/lib/bpf/strset.c | 62 ++++++++++++++++++++++++++++-------------- + 1 file changed, 41 insertions(+), 21 deletions(-) + +diff --git a/tools/lib/bpf/strset.c b/tools/lib/bpf/strset.c +index 2464bcbd04e037..ace73c6b3d62b4 100644 +--- a/tools/lib/bpf/strset.c ++++ b/tools/lib/bpf/strset.c +@@ -107,6 +107,41 @@ static void *strset_add_str_mem(struct strset *set, size_t add_sz) + set->strs_data_len, set->strs_data_max_len, add_sz); + } + ++static long strset_str_append(struct strset *set, const char *s) ++{ ++ uintptr_t old_data = (uintptr_t)set->strs_data; ++ size_t old_data_len = set->strs_data_len; ++ uintptr_t old_s = (uintptr_t)s; ++ long len = strlen(s) + 1; ++ void *p; ++ ++ /* ++ * Hashmap keys are always offsets within set->strs_data, so to even ++ * look up some string from the "outside", we need to first append it ++ * at the end, so that it can be addressed with an offset. Luckily, ++ * until set->strs_data_len is incremented, that string is just a piece ++ * of garbage for the rest of the code, so no harm, no foul. On the ++ * other hand, if the string is unique, it's already appended and ++ * ready to be used, only a simple set->strs_data_len increment away. ++ */ ++ p = strset_add_str_mem(set, len); ++ if (!p) ++ return -ENOMEM; ++ ++ /* ++ * The set->strs_data might have reallocated and if 's' pointed ++ * to an internal string within the old buffer, then it became ++ * dangling and needs to be reconstructed before the copy. ++ */ ++ if (old_data && old_data != (uintptr_t)set->strs_data && ++ old_s >= old_data && old_s < old_data + old_data_len) ++ s = set->strs_data + (old_s - old_data); ++ ++ memcpy(p, s, len); ++ ++ return len; ++} ++ + /* Find string offset that corresponds to a given string *s*. + * Returns: + * - >0 offset into string data, if string is found; +@@ -116,16 +151,12 @@ static void *strset_add_str_mem(struct strset *set, size_t add_sz) + int strset__find_str(struct strset *set, const char *s) + { + long old_off, new_off, len; +- void *p; + +- /* see strset__add_str() for why we do this */ +- len = strlen(s) + 1; +- p = strset_add_str_mem(set, len); +- if (!p) +- return -ENOMEM; ++ len = strset_str_append(set, s); ++ if (len < 0) ++ return len; + + new_off = set->strs_data_len; +- memcpy(p, s, len); + + if (hashmap__find(set->strs_hash, new_off, &old_off)) + return old_off; +@@ -142,24 +173,13 @@ int strset__find_str(struct strset *set, const char *s) + int strset__add_str(struct strset *set, const char *s) + { + long old_off, new_off, len; +- void *p; + int err; + +- /* Hashmap keys are always offsets within set->strs_data, so to even +- * look up some string from the "outside", we need to first append it +- * at the end, so that it can be addressed with an offset. Luckily, +- * until set->strs_data_len is incremented, that string is just a piece +- * of garbage for the rest of the code, so no harm, no foul. On the +- * other hand, if the string is unique, it's already appended and +- * ready to be used, only a simple set->strs_data_len increment away. +- */ +- len = strlen(s) + 1; +- p = strset_add_str_mem(set, len); +- if (!p) +- return -ENOMEM; ++ len = strset_str_append(set, s); ++ if (len < 0) ++ return len; + + new_off = set->strs_data_len; +- memcpy(p, s, len); + + /* Now attempt to add the string, but only if the string with the same + * contents doesn't exist already (HASHMAP_ADD strategy). If such diff --git a/device/community/linux-pine64-pinephonepro/config-pine64-pinephonepro.aarch64 b/device/community/linux-pine64-pinephonepro/config-pine64-pinephonepro.aarch64 index 3480231e2..99778186d 100644 --- a/device/community/linux-pine64-pinephonepro/config-pine64-pinephonepro.aarch64 +++ b/device/community/linux-pine64-pinephonepro/config-pine64-pinephonepro.aarch64 @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/arm64 7.0.0 Kernel Configuration +# Linux/arm64 7.1.0 Kernel Configuration # CONFIG_CC_VERSION_TEXT="Alpine clang version 22.1.8" CONFIG_GCC_VERSION=0 @@ -13,6 +13,7 @@ CONFIG_LD_IS_LLD=y CONFIG_LLD_VERSION=220108 CONFIG_RUSTC_VERSION=0 CONFIG_RUSTC_LLVM_VERSION=0 +CONFIG_RUSTC_LLVM_MAJOR_VERSION=0 CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y CONFIG_CC_HAS_ASM_GOTO_TIED_OUTPUT=y CONFIG_TOOLS_SUPPORT_RELR=y @@ -186,6 +187,7 @@ CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH=y CONFIG_CC_HAS_INT128=y CONFIG_CC_IMPLICIT_FALLTHROUGH="-Wimplicit-fallthrough" +CONFIG_CC_MS_EXTENSIONS="-fms-extensions" CONFIG_GCC10_NO_ARRAY_BOUNDS=y CONFIG_GCC_NO_STRINGOP_OVERFLOW=y CONFIG_ARCH_SUPPORTS_INT128=y @@ -224,6 +226,7 @@ CONFIG_SOCK_CGROUP_DATA=y CONFIG_NAMESPACES=y CONFIG_UTS_NS=y CONFIG_TIME_NS=y +CONFIG_TIME_NS_VDSO=y CONFIG_IPC_NS=y CONFIG_USER_NS=y CONFIG_PID_NS=y @@ -312,6 +315,7 @@ CONFIG_VMCORE_INFO=y # end of General setup CONFIG_ARM64=y +CONFIG_RUSTC_SUPPORTS_ARM64=y CONFIG_CLANG_SUPPORTS_DYNAMIC_FTRACE_WITH_ARGS=y CONFIG_64BIT=y CONFIG_MMU=y @@ -360,14 +364,7 @@ CONFIG_BUILTIN_RETURN_ADDRESS_STRIPS_PAC=y # CONFIG_ARCH_KEEMBAY is not set # CONFIG_ARCH_MEDIATEK is not set # CONFIG_ARCH_MESON is not set - -# -# Microchip SoC support -# -# CONFIG_ARCH_LAN969X is not set -# CONFIG_ARCH_SPARX5 is not set -# end of Microchip SoC support - +# CONFIG_ARCH_MICROCHIP is not set # CONFIG_ARCH_MMP is not set # CONFIG_ARCH_MVEBU is not set # CONFIG_ARCH_NXP is not set @@ -437,6 +434,7 @@ CONFIG_ARM64_WORKAROUND_SPECULATIVE_UNPRIV_LOAD=y CONFIG_ARM64_ERRATUM_3117295=y CONFIG_ARM64_ERRATUM_3194386=y CONFIG_ARM64_ERRATUM_4311569=y +CONFIG_ARM64_ERRATUM_4193714=y # CONFIG_CAVIUM_ERRATUM_22375 is not set # CONFIG_CAVIUM_ERRATUM_23144 is not set # CONFIG_CAVIUM_ERRATUM_23154 is not set @@ -567,6 +565,14 @@ CONFIG_ARCH_PKEY_BITS=3 CONFIG_ARM64_GCS=y # end of ARMv9.4 architectural features +CONFIG_AS_HAS_LSUI=y + +# +# ARMv9.6 architectural features +# +CONFIG_ARM64_LSUI=y +# end of ARMv9.6 architectural features + CONFIG_ARM64_SVE=y CONFIG_ARM64_SME=y # CONFIG_ARM64_PSEUDO_NMI is not set @@ -721,8 +727,8 @@ CONFIG_KVM_GENERIC_HARDWARE_ENABLING=y CONFIG_KVM_GUEST_MEMFD=y CONFIG_VIRTUALIZATION=y CONFIG_KVM=y -# CONFIG_NVHE_EL2_DEBUG is not set # CONFIG_PTDUMP_STAGE2_DEBUGFS is not set +# CONFIG_NVHE_EL2_DEBUG is not set CONFIG_HAVE_LIVEPATCH=y # CONFIG_LIVEPATCH is not set CONFIG_CPU_MITIGATIONS=y @@ -767,6 +773,7 @@ CONFIG_ARCH_WANTS_NO_INSTR=y CONFIG_HAVE_ASM_MODVERSIONS=y CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y CONFIG_HAVE_RSEQ=y +CONFIG_HAVE_RUST=y CONFIG_HAVE_FUNCTION_ARG_ACCESS_API=y CONFIG_HAVE_HW_BREAKPOINT=y CONFIG_HAVE_PERF_REGS=y @@ -801,6 +808,7 @@ CONFIG_ARCH_SUPPORTS_CFI=y CONFIG_CFI=y CONFIG_CFI_ICALL_NORMALIZE_INTEGERS=y CONFIG_HAVE_CFI_ICALL_NORMALIZE_INTEGERS=y +CONFIG_HAVE_CFI_ICALL_NORMALIZE_INTEGERS_RUSTC=y # CONFIG_CFI_PERMISSIVE is not set CONFIG_HAVE_CONTEXT_TRACKING_USER=y CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y @@ -873,9 +881,11 @@ CONFIG_HAVE_GCC_PLUGINS=y CONFIG_FUNCTION_ALIGNMENT_4B=y CONFIG_FUNCTION_ALIGNMENT=4 CONFIG_CC_HAS_SANE_FUNCTION_ALIGNMENT=y +CONFIG_HAVE_ARCH_GET_SECUREBOOT=y # end of General architecture-dependent options CONFIG_RT_MUTEXES=y +CONFIG_MODULE_SIG_FORMAT=y CONFIG_MODULES=y # CONFIG_MODULE_DEBUG is not set CONFIG_MODULE_FORCE_LOAD=y @@ -883,7 +893,16 @@ CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y # CONFIG_MODULE_UNLOAD_TAINT_TRACKING is not set # CONFIG_MODULE_SRCVERSION_ALL is not set -# CONFIG_MODULE_SIG is not set +CONFIG_MODULE_SIG=y +# CONFIG_MODULE_SIG_FORCE is not set +CONFIG_MODULE_SIG_ALL=y +# CONFIG_MODULE_SIG_SHA256 is not set +# CONFIG_MODULE_SIG_SHA384 is not set +CONFIG_MODULE_SIG_SHA512=y +# CONFIG_MODULE_SIG_SHA3_256 is not set +# CONFIG_MODULE_SIG_SHA3_384 is not set +# CONFIG_MODULE_SIG_SHA3_512 is not set +CONFIG_MODULE_SIG_HASH="sha512" CONFIG_MODULE_COMPRESS=y # CONFIG_MODULE_COMPRESS_GZIP is not set # CONFIG_MODULE_COMPRESS_XZ is not set @@ -1038,7 +1057,6 @@ CONFIG_ARCH_KEEP_MEMBLOCK=y CONFIG_NUMA_KEEP_MEMINFO=y CONFIG_MEMORY_ISOLATION=y CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y -CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y CONFIG_MEMORY_HOTPLUG=y CONFIG_MHP_DEFAULT_ONLINE_TYPE_OFFLINE=y # CONFIG_MHP_DEFAULT_ONLINE_TYPE_ONLINE_AUTO is not set @@ -1053,6 +1071,7 @@ CONFIG_SPLIT_PMD_PTLOCKS=y CONFIG_COMPACTION=y CONFIG_COMPACT_UNEVICTABLE_DEFAULT=1 # CONFIG_PAGE_REPORTING is not set +CONFIG_NUMA_MIGRATION=y CONFIG_MIGRATION=y CONFIG_ARCH_ENABLE_HUGEPAGE_MIGRATION=y CONFIG_ARCH_ENABLE_THP_MIGRATION=y @@ -1309,7 +1328,6 @@ CONFIG_NF_CONNTRACK_PROCFS=y # CONFIG_NF_CONNTRACK_TIMESTAMP is not set # CONFIG_NF_CONNTRACK_LABELS is not set CONFIG_NF_CT_PROTO_SCTP=y -CONFIG_NF_CT_PROTO_UDPLITE=y # CONFIG_NF_CONNTRACK_AMANDA is not set # CONFIG_NF_CONNTRACK_FTP is not set # CONFIG_NF_CONNTRACK_H323 is not set @@ -1734,7 +1752,6 @@ CONFIG_NET_DROP_MONITOR=m # end of Network testing # end of Networking options -# CONFIG_HAMRADIO is not set # CONFIG_CAN is not set CONFIG_BT=m CONFIG_BT_BREDR=y @@ -1828,7 +1845,6 @@ CONFIG_RFKILL_LEDS=y CONFIG_RFKILL_INPUT=y CONFIG_RFKILL_GPIO=m # CONFIG_NET_9P is not set -# CONFIG_CAIF is not set # CONFIG_CEPH_LIB is not set # CONFIG_NFC is not set CONFIG_PSAMPLE=m @@ -1864,6 +1880,7 @@ CONFIG_UEVENT_HELPER_PATH="" CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y # CONFIG_DEVTMPFS_SAFE is not set +CONFIG_DRIVER_DEFERRED_PROBE_TIMEOUT=10 CONFIG_STANDALONE=y CONFIG_PREVENT_FIRMWARE_BUILD=y @@ -1911,8 +1928,6 @@ CONFIG_GENERIC_ARCH_NUMA=y CONFIG_ARM_CCI=y CONFIG_ARM_CCI400_COMMON=y # CONFIG_ARM_INTEGRATOR_LM is not set -# CONFIG_BT1_APB is not set -# CONFIG_BT1_AXI is not set # CONFIG_MOXTET is not set # CONFIG_HISILICON_LPC is not set # CONFIG_IMX_WEIM is not set @@ -2060,6 +2075,7 @@ CONFIG_MTD_BLOCK=y # CONFIG_MTD_OOPS is not set # CONFIG_MTD_SWAP is not set CONFIG_MTD_PARTITIONED_MASTER=y +# CONFIG_MTD_VIRT_CONCAT is not set # # RAM/ROM/Flash chip drivers @@ -2425,7 +2441,6 @@ CONFIG_NET_VENDOR_FREESCALE=y # CONFIG_FSL_PQ_MDIO is not set # CONFIG_FSL_XGMAC_MDIO is not set # CONFIG_GIANFAR is not set -# CONFIG_FSL_DPAA2_SWITCH is not set # CONFIG_FSL_ENETC_IERB is not set # CONFIG_NXP_NETC_BLK_CTRL is not set # CONFIG_NET_VENDOR_FUNGIBLE is not set @@ -2473,7 +2488,6 @@ CONFIG_NET_VENDOR_VERTEXCOM=y # CONFIG_NET_VENDOR_WANGXUN is not set # CONFIG_NET_VENDOR_WIZNET is not set # CONFIG_NET_VENDOR_XILINX is not set -CONFIG_MDIO_BUS=y CONFIG_PHYLINK=m CONFIG_PHYLIB=y CONFIG_SWPHY=y @@ -2561,6 +2575,7 @@ CONFIG_OF_MDIO=y # CONFIG_MDIO_MSCC_MIIM is not set # CONFIG_MDIO_MOXART is not set # CONFIG_MDIO_OCTEON is not set +# CONFIG_MDIO_PIC64HPSC is not set # CONFIG_MDIO_IPQ4019 is not set # CONFIG_MDIO_IPQ8064 is not set # CONFIG_MDIO_REALTEK_RTL9300 is not set @@ -2682,7 +2697,6 @@ CONFIG_MAC80211_HWSIM=m # CONFIG_NETDEVSIM is not set CONFIG_NET_FAILOVER=m -# CONFIG_ISDN is not set # # Input device support @@ -2722,6 +2736,7 @@ CONFIG_KEYBOARD_GPIO=y CONFIG_KEYBOARD_GPIO_POLLED=m # CONFIG_KEYBOARD_TCA8418 is not set CONFIG_KEYBOARD_MATRIX=m +# CONFIG_KEYBOARD_CHARLIEPLEX is not set # CONFIG_KEYBOARD_LM8323 is not set # CONFIG_KEYBOARD_LM8333 is not set # CONFIG_KEYBOARD_LPC32XX is not set @@ -3040,6 +3055,7 @@ CONFIG_SERIAL_AMBA_PL011_CONSOLE=y # CONFIG_SERIAL_HS_LPC32XX is not set CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_PIC32 is not set # CONFIG_SERIAL_MSM is not set # CONFIG_SERIAL_VT8500 is not set # CONFIG_SERIAL_OMAP is not set @@ -3068,8 +3084,6 @@ CONFIG_SERIAL_CORE_CONSOLE=y # CONFIG_SERIAL_LITEUART is not set # CONFIG_SERIAL_SUNPLUS is not set # CONFIG_SERIAL_NUVOTON_MA35D1 is not set -# CONFIG_SERIAL_ESP32 is not set -# CONFIG_SERIAL_ESP32_ACM is not set # end of Serial drivers CONFIG_SERIAL_MCTRL_GPIO=y @@ -3289,6 +3303,7 @@ CONFIG_SPI_MEM=y # CONFIG_SPI_AMLOGIC_SPISG is not set # CONFIG_SPI_APPLE is not set # CONFIG_SPI_AR934X is not set +# CONFIG_SPI_ATCSPI200 is not set # CONFIG_SPI_ATH79 is not set # CONFIG_SPI_ARMADA_3700 is not set # CONFIG_SPI_ASPEED_SMC is not set @@ -3475,6 +3490,7 @@ CONFIG_GENERIC_PINCONF=y # CONFIG_PINCTRL_MCP23S08 is not set # CONFIG_PINCTRL_MICROCHIP_SGPIO is not set # CONFIG_PINCTRL_OCELOT is not set +# CONFIG_PINCTRL_PIC32 is not set # CONFIG_PINCTRL_PISTACHIO is not set # CONFIG_PINCTRL_RK805 is not set CONFIG_PINCTRL_ROCKCHIP=y @@ -3721,6 +3737,7 @@ CONFIG_GPIO_GENERIC=y # CONFIG_GPIO_BCM_XGS_IPROC is not set # CONFIG_GPIO_BLZP1600 is not set # CONFIG_GPIO_BRCMSTB is not set +# CONFIG_GPIO_BY_PINCTRL is not set # CONFIG_GPIO_CADENCE is not set # CONFIG_GPIO_CLPS711X is not set # CONFIG_GPIO_DAVINCI is not set @@ -3870,6 +3887,7 @@ CONFIG_REBOOT_MODE=m CONFIG_SYSCON_REBOOT_MODE=m # CONFIG_POWER_RESET_SC27XX is not set CONFIG_NVMEM_REBOOT_MODE=m +# CONFIG_POWER_RESET_QEMU_VIRT_CTRL is not set # CONFIG_POWER_SEQUENCING is not set CONFIG_POWER_SUPPLY=y # CONFIG_POWER_SUPPLY_DEBUG is not set @@ -3886,6 +3904,7 @@ CONFIG_IP5XXX_POWER=y # CONFIG_BATTERY_DS2782 is not set # CONFIG_BATTERY_LEGO_EV3 is not set # CONFIG_BATTERY_SAMSUNG_SDI is not set +# CONFIG_BATTERY_S2MU005 is not set # CONFIG_BATTERY_SBS is not set # CONFIG_CHARGER_SBS is not set # CONFIG_MANAGER_SBS is not set @@ -3966,7 +3985,6 @@ CONFIG_SENSORS_ARM_SCPI=m # CONFIG_SENSORS_ASPEED is not set # CONFIG_SENSORS_ASPEED_G6 is not set # CONFIG_SENSORS_ATXP1 is not set -# CONFIG_SENSORS_BT1_PVT is not set # CONFIG_SENSORS_CHIPCAP2 is not set # CONFIG_SENSORS_CORSAIR_CPRO is not set # CONFIG_SENSORS_CORSAIR_PSU is not set @@ -4027,6 +4045,7 @@ CONFIG_SENSORS_JC42=m # CONFIG_SENSORS_MAX31790 is not set # CONFIG_SENSORS_MC34VR500 is not set # CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_MCP9982 is not set # CONFIG_SENSORS_TC654 is not set # CONFIG_SENSORS_TPS23861 is not set # CONFIG_SENSORS_MR75203 is not set @@ -4986,6 +5005,7 @@ CONFIG_VIDEO_IMX258=m # CONFIG_VIDEO_OV2659 is not set # CONFIG_VIDEO_OV2680 is not set # CONFIG_VIDEO_OV2685 is not set +# CONFIG_VIDEO_OV2732 is not set # CONFIG_VIDEO_OV2735 is not set # CONFIG_VIDEO_OV2740 is not set # CONFIG_VIDEO_OV4689 is not set @@ -5019,6 +5039,7 @@ CONFIG_VIDEO_OV8858=m # CONFIG_VIDEO_S5K5BAF is not set # CONFIG_VIDEO_S5K6A3 is not set # CONFIG_VIDEO_S5KJN1 is not set +# CONFIG_VIDEO_T4KA3 is not set # CONFIG_VIDEO_VD55G1 is not set # CONFIG_VIDEO_VD56G3 is not set # CONFIG_VIDEO_VGXY61 is not set @@ -5188,6 +5209,7 @@ CONFIG_DRM=y CONFIG_DRM_MIPI_DSI=y CONFIG_DRM_KMS_HELPER=y # CONFIG_DRM_PANIC is not set +# CONFIG_DRM_RAS is not set # CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS is not set # CONFIG_DRM_DEBUG_MODESET_LOCK is not set CONFIG_DRM_CLIENT=y @@ -5235,6 +5257,7 @@ CONFIG_DRM_SCHED=y # CONFIG_DRM_ATMEL_HLCDC is not set CONFIG_DRM_BRIDGE=y CONFIG_DRM_PANEL_BRIDGE=y +CONFIG_DRM_AUX_HPD_BRIDGE=y # # Display Interface Bridges @@ -5252,6 +5275,7 @@ CONFIG_DRM_INNO_HDMI=y # CONFIG_DRM_LONTIUM_LT9211 is not set # CONFIG_DRM_LONTIUM_LT9611 is not set # CONFIG_DRM_LONTIUM_LT9611UXC is not set +# CONFIG_DRM_LONTIUM_LT8713SX is not set # CONFIG_DRM_ITE_IT66121 is not set # CONFIG_DRM_LVDS_CODEC is not set # CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW is not set @@ -5266,6 +5290,7 @@ CONFIG_DRM_INNO_HDMI=y CONFIG_DRM_SIMPLE_BRIDGE=y # CONFIG_DRM_SOLOMON_SSD2825 is not set # CONFIG_DRM_THINE_THC63LVD1024 is not set +# CONFIG_DRM_THEAD_TH1520_DW_HDMI is not set # CONFIG_DRM_TOSHIBA_TC358762 is not set # CONFIG_DRM_TOSHIBA_TC358764 is not set # CONFIG_DRM_TOSHIBA_TC358767 is not set @@ -5345,12 +5370,14 @@ CONFIG_DRM_PANEL=y # CONFIG_DRM_PANEL_HIMAX_HX83102 is not set # CONFIG_DRM_PANEL_HIMAX_HX83112A is not set # CONFIG_DRM_PANEL_HIMAX_HX83112B is not set +# CONFIG_DRM_PANEL_HIMAX_HX83121A is not set CONFIG_DRM_PANEL_HIMAX_HX8394=y # CONFIG_DRM_PANEL_HYDIS_HV101HD1 is not set # CONFIG_DRM_PANEL_ILITEK_IL9322 is not set # CONFIG_DRM_PANEL_ILITEK_ILI9341 is not set # CONFIG_DRM_PANEL_ILITEK_ILI9805 is not set -# CONFIG_DRM_PANEL_ILITEK_ILI9806E is not set +# CONFIG_DRM_PANEL_ILITEK_ILI9806E_DSI is not set +# CONFIG_DRM_PANEL_ILITEK_ILI9806E_SPI is not set # CONFIG_DRM_PANEL_ILITEK_ILI9881C is not set # CONFIG_DRM_PANEL_ILITEK_ILI9882T is not set # CONFIG_DRM_PANEL_INNOLUX_EJ030NA is not set @@ -5368,8 +5395,10 @@ CONFIG_DRM_PANEL_HIMAX_HX8394=y # CONFIG_DRM_PANEL_LG_LD070WX3 is not set # CONFIG_DRM_PANEL_LG_LG4573 is not set # CONFIG_DRM_PANEL_LG_SW43408 is not set +# CONFIG_DRM_PANEL_LXD_M9189A is not set # CONFIG_DRM_PANEL_MAGNACHIP_D53E6EA8966 is not set # CONFIG_DRM_PANEL_MANTIX_MLAF057WE51 is not set +# CONFIG_DRM_PANEL_MOTOROLA_MOT is not set # CONFIG_DRM_PANEL_NEC_NL8048HL11 is not set # CONFIG_DRM_PANEL_NEWVISION_NV3051D is not set # CONFIG_DRM_PANEL_NEWVISION_NV3052C is not set @@ -5379,6 +5408,7 @@ CONFIG_DRM_PANEL_HIMAX_HX8394=y # CONFIG_DRM_PANEL_NOVATEK_NT36523 is not set # CONFIG_DRM_PANEL_NOVATEK_NT36672A is not set # CONFIG_DRM_PANEL_NOVATEK_NT36672E is not set +# CONFIG_DRM_PANEL_NOVATEK_NT37700F is not set # CONFIG_DRM_PANEL_NOVATEK_NT37801 is not set # CONFIG_DRM_PANEL_NOVATEK_NT39016 is not set # CONFIG_DRM_PANEL_OLIMEX_LCD_OLINUXINO is not set @@ -5414,6 +5444,7 @@ CONFIG_DRM_PANEL_HIMAX_HX8394=y # CONFIG_DRM_PANEL_SAMSUNG_S6E63M0 is not set # CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0 is not set # CONFIG_DRM_PANEL_SAMSUNG_S6E8AA5X01_AMS561RA01 is not set +# CONFIG_DRM_PANEL_SAMSUNG_S6E8FC0 is not set # CONFIG_DRM_PANEL_SAMSUNG_SOFEF00 is not set # CONFIG_DRM_PANEL_SEIKO_43WVF1G is not set # CONFIG_DRM_PANEL_SHARP_LQ079L1SX01 is not set @@ -5508,6 +5539,7 @@ CONFIG_DRM_SIMPLEDRM=y CONFIG_DRM_UDL=m # CONFIG_DRM_V3D is not set # CONFIG_DRM_VC4 is not set +# CONFIG_DRM_VERISILICON_DC is not set CONFIG_DRM_VGEM=m # CONFIG_DRM_VKMS is not set CONFIG_DRM_PANEL_ORIENTATION_QUIRKS=y @@ -6174,6 +6206,7 @@ CONFIG_SND_SOC_SPDIF=m # CONFIG_SND_SOC_TSCS454 is not set # CONFIG_SND_SOC_UDA1334 is not set # CONFIG_SND_SOC_UDA1342 is not set +# CONFIG_SND_SOC_UDA1380 is not set # CONFIG_SND_SOC_WM8510 is not set # CONFIG_SND_SOC_WM8523 is not set # CONFIG_SND_SOC_WM8524 is not set @@ -6303,6 +6336,8 @@ CONFIG_HID_KENSINGTON=m CONFIG_HID_LCPOWER=m CONFIG_HID_LED=m # CONFIG_HID_LENOVO is not set +# CONFIG_HID_LENOVO_GO is not set +# CONFIG_HID_LENOVO_GO_S is not set CONFIG_HID_LETSKETCH=m CONFIG_HID_LOGITECH=m CONFIG_HID_LOGITECH_DJ=m @@ -6381,6 +6416,7 @@ CONFIG_HID_SENSOR_CUSTOM_SENSOR=m CONFIG_HID_ALPS=m # CONFIG_HID_MCP2200 is not set CONFIG_HID_MCP2221=m +# CONFIG_HID_HUAWEI is not set # end of Special HID drivers # @@ -6554,6 +6590,7 @@ CONFIG_USB_DWC3_OF_SIMPLE=y CONFIG_USB_DWC3_ST=y CONFIG_USB_DWC3_QCOM=y CONFIG_USB_DWC3_IMX8MP=y +CONFIG_USB_DWC3_IMX=y CONFIG_USB_DWC3_XILINX=y CONFIG_USB_DWC3_AM62=y CONFIG_USB_DWC3_OCTEON=y @@ -6784,7 +6821,6 @@ CONFIG_TYPEC_UCSI=y # CONFIG_TYPEC_HD3SS3220 is not set # CONFIG_TYPEC_STUSB160X is not set # CONFIG_TYPEC_WUSB3801 is not set -CONFIG_TYPEC_EXTCON=y # # USB Type-C Multiplexer/DeMultiplexer Switch support @@ -6844,6 +6880,7 @@ CONFIG_MMC_SDHCI_OF_ARASAN=y # CONFIG_MMC_SDHCI_PXAV2 is not set # CONFIG_MMC_SDHCI_SPEAR is not set # CONFIG_MMC_SDHCI_BCM_KONA is not set +# CONFIG_MMC_SDHCI_BST is not set # CONFIG_MMC_SDHCI_F_SDH30 is not set # CONFIG_MMC_SDHCI_MILBEAUT is not set # CONFIG_MMC_SDHCI_IPROC is not set @@ -6878,6 +6915,7 @@ CONFIG_MMC_CQHCI=y # CONFIG_MMC_HSQ is not set # CONFIG_MMC_BCM2835 is not set # CONFIG_MMC_MTK is not set +# CONFIG_MMC_SDHCI_MICROCHIP_PIC32 is not set # CONFIG_MMC_SDHCI_BRCMSTB is not set # CONFIG_MMC_SDHCI_XENON is not set # CONFIG_MMC_SDHCI_OMAP is not set @@ -7070,6 +7108,7 @@ CONFIG_RTC_INTF_DEV=y # CONFIG_RTC_DRV_NVIDIA_VRS10 is not set # CONFIG_RTC_DRV_NCT3018Y is not set CONFIG_RTC_DRV_RK808=y +# CONFIG_RTC_DRV_ROCKCHIP is not set # CONFIG_RTC_DRV_RS5C372 is not set # CONFIG_RTC_DRV_ISL1208 is not set # CONFIG_RTC_DRV_ISL12022 is not set @@ -7189,6 +7228,7 @@ CONFIG_RTC_DRV_CADENCE=m # CONFIG_RTC_DRV_MT6397 is not set # CONFIG_RTC_DRV_MT7622 is not set # CONFIG_RTC_DRV_XGENE is not set +CONFIG_RTC_DRV_PIC32=y # CONFIG_RTC_DRV_R7301 is not set # CONFIG_RTC_DRV_STM32 is not set # CONFIG_RTC_DRV_RTD119X is not set @@ -7231,8 +7271,6 @@ CONFIG_DMA_OF=y # CONFIG_IMG_MDC_DMA is not set # CONFIG_INTEL_IDMA64 is not set # CONFIG_K3_DMA is not set -# CONFIG_LOONGSON1_APB_DMA is not set -# CONFIG_LOONGSON2_APB_DMA is not set # CONFIG_MCF_EDMA is not set # CONFIG_MILBEAUT_HDMAC is not set # CONFIG_MILBEAUT_XDMAC is not set @@ -7271,6 +7309,9 @@ CONFIG_PL330_DMA=m # CONFIG_TI_EDMA is not set # CONFIG_DMA_OMAP is not set # CONFIG_INTEL_LDMA is not set +# CONFIG_LOONGSON1_APB_DMA is not set +# CONFIG_LOONGSON2_APB_DMA is not set +# CONFIG_LOONGSON2_APB_CMC_DMA is not set # CONFIG_STM32_DMA is not set # CONFIG_STM32_MDMA is not set # CONFIG_STM32_DMA3 is not set @@ -7287,7 +7328,6 @@ CONFIG_ASYNC_TX_DMA=y CONFIG_SYNC_FILE=y # CONFIG_SW_SYNC is not set CONFIG_UDMABUF=y -CONFIG_DMABUF_MOVE_NOTIFY=y # CONFIG_DMABUF_DEBUG is not set # CONFIG_DMABUF_SELFTESTS is not set CONFIG_DMABUF_HEAPS=y @@ -7303,7 +7343,6 @@ CONFIG_IRQ_BYPASS_MANAGER=y CONFIG_VIRT_DRIVERS=y CONFIG_VMGENID=y # CONFIG_EFI_SECRET is not set -# CONFIG_ARM_PKVM_GUEST is not set # CONFIG_ARM_CCA_GUEST is not set CONFIG_VIRTIO_ANCHOR=y CONFIG_VIRTIO=m @@ -7363,11 +7402,6 @@ CONFIG_STAGING=y CONFIG_STAGING_MEDIA=y # CONFIG_VIDEO_MAX96712 is not set # CONFIG_VIDEO_MESON_VDEC is not set - -# -# StarFive media platform drivers -# -# CONFIG_VIDEO_STARFIVE_CAMSS is not set # CONFIG_VIDEO_SUNXI is not set # CONFIG_STAGING_MEDIA_DEPRECATED is not set # CONFIG_FB_TFT is not set @@ -7444,7 +7478,6 @@ CONFIG_COMMON_CLK_PWM=y # CONFIG_CLK_ACTIONS is not set # CONFIG_COMMON_CLK_ASPEED is not set # CONFIG_COMMON_CLK_AST2700 is not set -# CONFIG_CLK_BAIKAL_T1 is not set # CONFIG_CLK_BCM2711_DVP is not set # CONFIG_CLK_BCM2835 is not set # CONFIG_CLK_BCM_63XX is not set @@ -7457,6 +7490,7 @@ CONFIG_COMMON_CLK_PWM=y # CONFIG_CLK_BCM_NS2 is not set # CONFIG_CLK_BCM_SR is not set # CONFIG_CLK_RASPBERRYPI is not set +# CONFIG_COMMON_CLK_EIC7700 is not set # CONFIG_COMMON_CLK_HI3516CV300 is not set # CONFIG_COMMON_CLK_HI3519 is not set # CONFIG_COMMON_CLK_HI3559A is not set @@ -7554,6 +7588,7 @@ CONFIG_MCHP_CLK_MPFS=y # CONFIG_CLK_RENESAS is not set CONFIG_COMMON_CLK_ROCKCHIP=y # CONFIG_CLK_PX30 is not set +CONFIG_CLK_RV1103B=y CONFIG_CLK_RV110X=y CONFIG_CLK_RV1126=y CONFIG_CLK_RV1126B=y @@ -7594,6 +7629,7 @@ CONFIG_CLK_RK3588=y # CONFIG_CLK_STARFIVE_JH7110_SYS is not set # CONFIG_CLK_SUNXI is not set # CONFIG_SUNXI_CCU is not set +# CONFIG_TENSTORRENT_ATLANTIS_PRCM is not set # CONFIG_CLK_THEAD_TH1520_AP is not set # CONFIG_COMMON_CLK_STM32MP is not set # CONFIG_COMMON_CLK_TI_ADPLL is not set @@ -7609,7 +7645,6 @@ CONFIG_HWSPINLOCK=y # CONFIG_HWSPINLOCK_SPRD is not set # CONFIG_HWSPINLOCK_STM32 is not set # CONFIG_HWSPINLOCK_SUN6I is not set -# CONFIG_HSEM_U8500 is not set # # Clock Source drivers @@ -7752,6 +7787,7 @@ CONFIG_ARM_SMMU_V3=y # CONFIG_TEGRA241_CMDQV is not set # CONFIG_QCOM_IOMMU is not set # CONFIG_IOMMUFD is not set +# CONFIG_RISCV_IOMMU is not set # CONFIG_OMAP_IOMMU is not set CONFIG_ROCKCHIP_IOMMU=y # CONFIG_SUN50I_IOMMU is not set @@ -7893,6 +7929,7 @@ CONFIG_ROCKCHIP_IOMMU=y # CONFIG_SOC_RENESAS is not set CONFIG_ROCKCHIP_GRF=y CONFIG_ROCKCHIP_IODOMAIN=y +# CONFIG_ROCKCHIP_NPOR_POWERGOOD is not set # CONFIG_SOC_SAMSUNG is not set # @@ -7969,6 +8006,7 @@ CONFIG_ARM_SCPI_POWER_DOMAIN=m # # Qualcomm PM Domains # +# CONFIG_QCOM_CPR is not set # end of Qualcomm PM Domains CONFIG_ROCKCHIP_PM_DOMAINS=y @@ -8027,7 +8065,6 @@ CONFIG_MEMORY=y # CONFIG_ATMEL_EBI is not set # CONFIG_BRCMSTB_DPFE is not set # CONFIG_BRCMSTB_MEMC is not set -# CONFIG_BT1_L2_CTL is not set # CONFIG_TI_AEMIF is not set # CONFIG_TI_EMIF is not set # CONFIG_OMAP_GPMC is not set @@ -8199,6 +8236,7 @@ CONFIG_HID_SENSOR_ACCEL_3D=m # CONFIG_QCOM_SPMI_IADC is not set # CONFIG_QCOM_SPMI_VADC is not set # CONFIG_QCOM_SPMI_ADC5 is not set +# CONFIG_QCOM_SPMI_ADC5_GEN3 is not set # CONFIG_RCAR_GYRO_ADC is not set # CONFIG_ROHM_BD79112 is not set # CONFIG_ROHM_BD79124 is not set @@ -8697,6 +8735,7 @@ CONFIG_HID_SENSOR_CUSTOM_INTEL_HINGE=m # CONFIG_SRF08 is not set # CONFIG_VCNL3020 is not set # CONFIG_VL53L0X_I2C is not set +# CONFIG_VL53L1X_I2C is not set # CONFIG_AW96103 is not set # end of Proximity and distance sensors @@ -8810,6 +8849,7 @@ CONFIG_IRQ_MSI_LIB=y # CONFIG_BCM7120_L2_IRQ is not set # CONFIG_BRCMSTB_L2_IRQ is not set # CONFIG_LAN966X_OIC is not set +CONFIG_PIC32_EVIC=y # CONFIG_JCORE_AIC is not set # CONFIG_RENESAS_INTC_IRQPIN is not set # CONFIG_RENESAS_IRQC is not set @@ -8869,9 +8909,11 @@ CONFIG_RESET_POLARFIRE_SOC=y # CONFIG_RESET_RZV2H_USB2PHY is not set CONFIG_RESET_SCMI=y # CONFIG_RESET_SIMPLE is not set +# CONFIG_RESET_SKY1 is not set # CONFIG_RESET_SOCFPGA is not set # CONFIG_RESET_SUNPLUS is not set # CONFIG_RESET_SUNXI is not set +# CONFIG_RESET_TENSTORRENT_ATLANTIS is not set # CONFIG_RESET_TH1520 is not set # CONFIG_RESET_TI_SCI is not set # CONFIG_RESET_TI_SYSCON is not set @@ -8901,16 +8943,15 @@ CONFIG_RESET_SCMI=y # CONFIG_GENERIC_PHY=y CONFIG_GENERIC_PHY_MIPI_DPHY=y +# CONFIG_PHY_AIROHA_PCIE is not set +# CONFIG_PHY_CAN_TRANSCEIVER is not set # CONFIG_PHY_GOOGLE_USB is not set +# CONFIG_USB_LGM_PHY is not set # CONFIG_PHY_LPC18XX_USB_OTG is not set +# CONFIG_PHY_NXP_PTN3222 is not set # CONFIG_PHY_PISTACHIO_USB is not set # CONFIG_PHY_SNPS_EUSB2 is not set # CONFIG_PHY_XGENE is not set -# CONFIG_USB_LGM_PHY is not set -# CONFIG_PHY_CAN_TRANSCEIVER is not set -# CONFIG_PHY_AIROHA_PCIE is not set -# CONFIG_PHY_NXP_PTN3222 is not set -# CONFIG_PHY_SPACEMIT_K1_PCIE is not set # CONFIG_PHY_SUN4I_USB is not set # CONFIG_PHY_SUN6I_MIPI_DPHY is not set # CONFIG_PHY_SUN9I_USB is not set @@ -8947,6 +8988,8 @@ CONFIG_GENERIC_PHY_MIPI_DPHY=y # CONFIG_PHY_CADENCE_DPHY_RX is not set # CONFIG_PHY_CADENCE_SIERRA is not set # CONFIG_PHY_CADENCE_SALVO is not set +# CONFIG_PHY_CANAAN_USB is not set +# CONFIG_PHY_EIC7700_SATA is not set # CONFIG_PHY_FSL_IMX8MQ_USB is not set # CONFIG_PHY_MIXEL_LVDS_PHY is not set # CONFIG_PHY_MIXEL_MIPI_DPHY is not set @@ -8961,6 +9004,10 @@ CONFIG_GENERIC_PHY_MIPI_DPHY=y # CONFIG_PHY_HISTB_COMBPHY is not set # CONFIG_PHY_HISI_INNO_USB2 is not set # CONFIG_PHY_INGENIC_USB is not set +# CONFIG_PHY_INTEL_KEEMBAY_EMMC is not set +# CONFIG_PHY_INTEL_KEEMBAY_USB is not set +# CONFIG_PHY_INTEL_LGM_COMBO is not set +# CONFIG_PHY_INTEL_LGM_EMMC is not set # CONFIG_PHY_LANTIQ_VRX200_PCIE is not set # CONFIG_PHY_LANTIQ_RCU_USB2 is not set # CONFIG_ARMADA375_USBCLUSTER_PHY is not set @@ -9040,6 +9087,7 @@ CONFIG_PHY_ROCKCHIP_USB=y # CONFIG_PHY_UNIPHIER_PCIE is not set # CONFIG_PHY_UNIPHIER_AHCI is not set # CONFIG_PHY_SOPHGO_CV1800_USB2 is not set +# CONFIG_PHY_SPACEMIT_K1_PCIE is not set # CONFIG_PHY_SPACEMIT_K1_USB2 is not set # CONFIG_PHY_ST_SPEAR1310_MIPHY is not set # CONFIG_PHY_ST_SPEAR1340_MIPHY is not set @@ -9060,10 +9108,6 @@ CONFIG_PHY_ROCKCHIP_USB=y # CONFIG_OMAP_USB2 is not set # CONFIG_TI_PIPE3 is not set # CONFIG_PHY_TUSB1210 is not set -# CONFIG_PHY_INTEL_KEEMBAY_EMMC is not set -# CONFIG_PHY_INTEL_KEEMBAY_USB is not set -# CONFIG_PHY_INTEL_LGM_COMBO is not set -# CONFIG_PHY_INTEL_LGM_EMMC is not set # CONFIG_PHY_XILINX_ZYNQMP is not set # end of PHY Subsystem @@ -9168,6 +9212,7 @@ CONFIG_NVMEM_LAYOUTS=y # CONFIG_FSI is not set # CONFIG_TEE is not set CONFIG_MULTIPLEXER=y +# CONFIG_MUX_CORE is not set # # Multiplexer drivers @@ -9309,8 +9354,8 @@ CONFIG_FAT_DEFAULT_IOCHARSET="ascii" CONFIG_FAT_DEFAULT_UTF8=y CONFIG_EXFAT_FS=m CONFIG_EXFAT_DEFAULT_IOCHARSET="utf8" -# CONFIG_NTFS3_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS3_FS is not set # end of DOS/FAT/EXFAT/NT Filesystems # @@ -9432,7 +9477,6 @@ CONFIG_NFSD_SCSILAYOUT=y CONFIG_NFSD_V4_2_INTER_SSC=y # CONFIG_NFSD_V4_SECURITY_LABEL is not set # CONFIG_NFSD_LEGACY_CLIENT_TRACKING is not set -# CONFIG_NFSD_V4_DELEG_TIMESTAMPS is not set # CONFIG_NFSD_V4_POSIX_ACLS is not set CONFIG_GRACE_PERIOD=m CONFIG_LOCKD=m @@ -9552,13 +9596,17 @@ CONFIG_SECURITY_PATH=y # CONFIG_SECURITY_LOADPIN is not set CONFIG_SECURITY_YAMA=y # CONFIG_SECURITY_SAFESETID is not set -# CONFIG_SECURITY_LOCKDOWN_LSM is not set +CONFIG_SECURITY_LOCKDOWN_LSM=y +CONFIG_SECURITY_LOCKDOWN_LSM_EARLY=y +CONFIG_LOCK_DOWN_KERNEL_FORCE_NONE=y +# CONFIG_LOCK_DOWN_KERNEL_FORCE_INTEGRITY is not set +# CONFIG_LOCK_DOWN_KERNEL_FORCE_CONFIDENTIALITY is not set # CONFIG_SECURITY_LANDLOCK is not set # CONFIG_SECURITY_IPE is not set # CONFIG_INTEGRITY is not set # CONFIG_IMA_SECURE_AND_OR_TRUSTED_BOOT is not set CONFIG_DEFAULT_SECURITY_DAC=y -CONFIG_LSM="lockdown,yama,loadpin,safesetid,integrity,apparmor,selinux,smack,tomoyo" +CONFIG_LSM="landlock,lockdown,yama,loadpin,safesetid,selinux,smack,tomoyo,ipe,bpf" # # Kernel hardening options @@ -9602,7 +9650,6 @@ CONFIG_RANDSTRUCT_NONE=y # end of Kernel hardening options # end of Security options -CONFIG_XOR_BLOCKS=y CONFIG_ASYNC_CORE=m CONFIG_ASYNC_MEMCPY=m CONFIG_ASYNC_XOR=m @@ -9625,7 +9672,6 @@ CONFIG_CRYPTO_HASH=y CONFIG_CRYPTO_HASH2=y CONFIG_CRYPTO_RNG=y CONFIG_CRYPTO_RNG2=y -CONFIG_CRYPTO_RNG_DEFAULT=y CONFIG_CRYPTO_AKCIPHER2=y CONFIG_CRYPTO_AKCIPHER=y CONFIG_CRYPTO_KPP2=y @@ -9639,7 +9685,7 @@ CONFIG_CRYPTO_NULL=y CONFIG_CRYPTO_PCRYPT=m # CONFIG_CRYPTO_CRYPTD is not set CONFIG_CRYPTO_AUTHENC=y -# CONFIG_CRYPTO_KRB5ENC is not set +CONFIG_CRYPTO_KRB5ENC=y # CONFIG_CRYPTO_BENCHMARK is not set CONFIG_CRYPTO_ENGINE=m # end of Crypto core or helper @@ -9664,7 +9710,7 @@ CONFIG_CRYPTO_AES=y # CONFIG_CRYPTO_ARIA is not set CONFIG_CRYPTO_BLOWFISH=m CONFIG_CRYPTO_BLOWFISH_COMMON=m -CONFIG_CRYPTO_CAMELLIA=m +CONFIG_CRYPTO_CAMELLIA=y CONFIG_CRYPTO_CAST_COMMON=m CONFIG_CRYPTO_CAST5=m CONFIG_CRYPTO_CAST6=m @@ -9710,18 +9756,16 @@ CONFIG_CRYPTO_ESSIV=y # Hashes, digests, and MACs # CONFIG_CRYPTO_BLAKE2B=y -CONFIG_CRYPTO_CMAC=m -CONFIG_CRYPTO_GHASH=y +CONFIG_CRYPTO_CMAC=y CONFIG_CRYPTO_HMAC=y CONFIG_CRYPTO_MD4=m CONFIG_CRYPTO_MD5=y -# CONFIG_CRYPTO_MICHAEL_MIC is not set CONFIG_CRYPTO_RMD160=m CONFIG_CRYPTO_SHA1=y CONFIG_CRYPTO_SHA256=y CONFIG_CRYPTO_SHA512=y CONFIG_CRYPTO_SHA3=y -# CONFIG_CRYPTO_SM3_GENERIC is not set +# CONFIG_CRYPTO_SM3 is not set CONFIG_CRYPTO_STREEBOG=m CONFIG_CRYPTO_WP512=m CONFIG_CRYPTO_XCBC=m @@ -9778,8 +9822,6 @@ CONFIG_CRYPTO_USER_API_AEAD=m # Accelerated Cryptographic Algorithms for CPU (arm64) # CONFIG_CRYPTO_GHASH_ARM64_CE=m -# CONFIG_CRYPTO_SM3_NEON is not set -CONFIG_CRYPTO_SM3_ARM64_CE=y CONFIG_CRYPTO_AES_ARM64_CE_BLK=y CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y CONFIG_CRYPTO_AES_ARM64_BS=m @@ -9836,6 +9878,12 @@ CONFIG_PKCS7_MESSAGE_PARSER=y # # Certificates for signature checking # +CONFIG_MODULE_SIG_KEY="certs/signing_key.pem" +CONFIG_MODULE_SIG_KEY_TYPE_RSA=y +# CONFIG_MODULE_SIG_KEY_TYPE_ECDSA is not set +# CONFIG_MODULE_SIG_KEY_TYPE_MLDSA_44 is not set +# CONFIG_MODULE_SIG_KEY_TYPE_MLDSA_65 is not set +# CONFIG_MODULE_SIG_KEY_TYPE_MLDSA_87 is not set CONFIG_SYSTEM_TRUSTED_KEYRING=y CONFIG_SYSTEM_TRUSTED_KEYS="" # CONFIG_SYSTEM_EXTRA_CERTIFICATE is not set @@ -9848,7 +9896,8 @@ CONFIG_SYSTEM_BLACKLIST_HASH_LIST="" CONFIG_OPENSSL_SUPPORTS_ML_DSA=y # end of Certificates for signature checking -# CONFIG_CRYPTO_KRB5 is not set +CONFIG_CRYPTO_KRB5=y +# CONFIG_CRYPTO_KRB5_SELFTESTS is not set CONFIG_BINARY_PRINTF=y # @@ -9880,23 +9929,23 @@ CONFIG_CRC_T10DIF_ARCH=y CONFIG_CRC32=y CONFIG_CRC32_ARCH=y CONFIG_CRC64=y +CONFIG_CRC64_ARCH=y CONFIG_CRC_OPTIMIZATIONS=y - -# -# Crypto library routines -# CONFIG_CRYPTO_HASH_INFO=y CONFIG_CRYPTO_LIB_UTILS=y CONFIG_CRYPTO_LIB_AES=y CONFIG_CRYPTO_LIB_AES_ARCH=y +CONFIG_CRYPTO_LIB_AES_CBC_MACS=y CONFIG_CRYPTO_LIB_ARC4=m -CONFIG_CRYPTO_LIB_GF128MUL=y +CONFIG_CRYPTO_LIB_GF128MUL=m CONFIG_CRYPTO_LIB_BLAKE2B=y CONFIG_CRYPTO_LIB_CHACHA=y CONFIG_CRYPTO_LIB_CHACHA_ARCH=y CONFIG_CRYPTO_LIB_CURVE25519=m CONFIG_CRYPTO_LIB_CURVE25519_GENERIC=y CONFIG_CRYPTO_LIB_DES=m +CONFIG_CRYPTO_LIB_GF128HASH=y +CONFIG_CRYPTO_LIB_GF128HASH_ARCH=y CONFIG_CRYPTO_LIB_MD5=y CONFIG_CRYPTO_LIB_NH=m CONFIG_CRYPTO_LIB_NH_ARCH=y @@ -9913,9 +9962,8 @@ CONFIG_CRYPTO_LIB_SHA512=y CONFIG_CRYPTO_LIB_SHA512_ARCH=y CONFIG_CRYPTO_LIB_SHA3=y CONFIG_CRYPTO_LIB_SHA3_ARCH=y -CONFIG_CRYPTO_LIB_SM3=y -# end of Crypto library routines - +CONFIG_XOR_BLOCKS=y +CONFIG_XOR_BLOCKS_ARCH=y CONFIG_XXHASH=y CONFIG_AUDIT_GENERIC=y CONFIG_AUDIT_ARCH_COMPAT_GENERIC=y @@ -9972,6 +10020,7 @@ CONFIG_ARCH_HAS_SYNC_DMA_FOR_DEVICE=y CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU=y CONFIG_ARCH_HAS_DMA_PREP_COHERENT=y CONFIG_ARCH_HAS_FORCE_DMA_UNENCRYPTED=y +CONFIG_ARCH_HAS_BATCHED_DMA_SYNC=y CONFIG_SWIOTLB=y # CONFIG_SWIOTLB_DYNAMIC is not set CONFIG_DMA_BOUNCE_UNALIGNED_KMALLOC=y @@ -10327,6 +10376,7 @@ CONFIG_SYNTH_EVENTS=y # CONFIG_SYNTH_EVENT_GEN_TEST is not set # CONFIG_KPROBE_EVENT_GEN_TEST is not set # CONFIG_RV is not set +# CONFIG_TRACE_REMOTE_TEST is not set # CONFIG_SAMPLES is not set CONFIG_HAVE_SAMPLE_FTRACE_DIRECT=y CONFIG_HAVE_SAMPLE_FTRACE_DIRECT_MULTI=y @@ -10373,3 +10423,4 @@ CONFIG_MEMTEST=y CONFIG_IO_URING_ZCRX=y CONFIG_IO_URING_BPF=y +CONFIG_IO_URING_BPF_OPS=y diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0001-ASoC-codecs-rt5640-Fix-output-mixer-input-channel-li.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0001-ASoC-codecs-rt5640-Fix-output-mixer-input-channel-li.patch new file mode 100644 index 000000000..c6c29cd60 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0001-ASoC-codecs-rt5640-Fix-output-mixer-input-channel-li.patch @@ -0,0 +1,93 @@ +From 0a07c82cce09160952c41a53f94acb084b8b6a3b Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Fri, 19 Aug 2022 22:01:23 +0200 +Subject: [PATCH 01/84] ASoC: codecs: rt5640: Fix output mixer input channel + list + +It did not match the RT5640 datasheet. Now it does. + +Signed-off-by: Ondrej Jirman +--- + sound/soc/codecs/rt5640.c | 14 +++++++------- + sound/soc/codecs/rt5640.h | 16 ++++++---------- + 2 files changed, 13 insertions(+), 17 deletions(-) + +diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c +index f6c6294e1588..e3a90be5294b 100644 +--- a/sound/soc/codecs/rt5640.c ++++ b/sound/soc/codecs/rt5640.c +@@ -651,8 +651,8 @@ static const struct snd_kcontrol_new rt5640_spk_r_mix[] = { + }; + + static const struct snd_kcontrol_new rt5640_out_l_mix[] = { +- SOC_DAPM_SINGLE("SPK MIXL Switch", RT5640_OUT_L3_MIXER, +- RT5640_M_SM_L_OM_L_SFT, 1, 1), ++ SOC_DAPM_SINGLE("BST3 Switch", RT5640_OUT_L3_MIXER, ++ RT5640_M_BST3_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5640_OUT_L3_MIXER, + RT5640_M_BST1_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("INL Switch", RT5640_OUT_L3_MIXER, +@@ -668,10 +668,10 @@ static const struct snd_kcontrol_new rt5640_out_l_mix[] = { + }; + + static const struct snd_kcontrol_new rt5640_out_r_mix[] = { +- SOC_DAPM_SINGLE("SPK MIXR Switch", RT5640_OUT_R3_MIXER, +- RT5640_M_SM_L_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5640_OUT_R3_MIXER, +- RT5640_M_BST4_OM_R_SFT, 1, 1), ++ RT5640_M_BST2_OM_R_SFT, 1, 1), ++ SOC_DAPM_SINGLE("BST3 Switch", RT5640_OUT_R3_MIXER, ++ RT5640_M_BST3_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5640_OUT_R3_MIXER, + RT5640_M_BST1_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("INR Switch", RT5640_OUT_R3_MIXER, +@@ -1603,8 +1603,8 @@ static const struct snd_soc_dapm_route rt5640_specific_dapm_routes[] = { + {"SPK MIXL", "DAC L2 Switch", "DAC L2"}, + {"SPK MIXR", "DAC R2 Switch", "DAC R2"}, + +- {"OUT MIXL", "SPK MIXL Switch", "SPK MIXL"}, +- {"OUT MIXR", "SPK MIXR Switch", "SPK MIXR"}, ++ {"OUT MIXL", "BST3 Switch", "BST3"}, ++ {"OUT MIXR", "BST3 Switch", "BST3"}, + + {"OUT MIXL", "DAC R2 Switch", "DAC R2"}, + {"OUT MIXL", "DAC L2 Switch", "DAC L2"}, +diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h +index 8a12cee76bdc..5c5398c82dcd 100644 +--- a/sound/soc/codecs/rt5640.h ++++ b/sound/soc/codecs/rt5640.h +@@ -654,12 +654,8 @@ + #define RT5640_G_DAC_L1_OM_L_SFT 7 + + /* Output Left Mixer Control 3 (0x4f) */ +-#define RT5640_M_SM_L_OM_L (0x1 << 8) +-#define RT5640_M_SM_L_OM_L_SFT 8 +-#define RT5640_M_BST3_OM_L (0x1 << 7) +-#define RT5640_M_BST3_OM_L_SFT 7 +-#define RT5640_M_BST2_OM_L (0x1 << 6) +-#define RT5640_M_BST2_OM_L_SFT 6 ++#define RT5640_M_BST3_OM_L (0x1 << 6) ++#define RT5640_M_BST3_OM_L_SFT 6 + #define RT5640_M_BST1_OM_L (0x1 << 5) + #define RT5640_M_BST1_OM_L_SFT 5 + #define RT5640_M_IN_L_OM_L (0x1 << 4) +@@ -694,12 +690,12 @@ + #define RT5640_G_DAC_R1_OM_R_SFT 7 + + /* Output Right Mixer Control 3 (0x52) */ +-#define RT5640_M_SM_L_OM_R (0x1 << 8) +-#define RT5640_M_SM_L_OM_R_SFT 8 + #define RT5640_M_BST4_OM_R (0x1 << 7) + #define RT5640_M_BST4_OM_R_SFT 7 +-#define RT5640_M_BST2_OM_R (0x1 << 6) +-#define RT5640_M_BST2_OM_R_SFT 6 ++#define RT5640_M_BST2_OM_R (0x1 << 7) ++#define RT5640_M_BST2_OM_R_SFT 7 ++#define RT5640_M_BST3_OM_R (0x1 << 6) ++#define RT5640_M_BST3_OM_R_SFT 6 + #define RT5640_M_BST1_OM_R (0x1 << 5) + #define RT5640_M_BST1_OM_R_SFT 5 + #define RT5640_M_IN_R_OM_R (0x1 << 4) +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0002-ASoC-codecs-rt5640-Fix-hpout-restore-when-lout-is-en.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0002-ASoC-codecs-rt5640-Fix-hpout-restore-when-lout-is-en.patch new file mode 100644 index 000000000..57a6c27b5 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0002-ASoC-codecs-rt5640-Fix-hpout-restore-when-lout-is-en.patch @@ -0,0 +1,32 @@ +From 06cc977b69459292246e9b08dfe433fc43e5d5f3 Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Sat, 20 Aug 2022 20:32:07 +0200 +Subject: [PATCH 02/84] ASoC: codecs: rt5640: Fix hpout restore when lout is + enabled + +When line out and heaphones are enabled, rt5640_lout_event will cause +headpone state restore to fail, by calling hp_amp_power_on again after +rt5640_pmu_depop. + +Signed-off-by: Ondrej Jirman +--- + sound/soc/codecs/rt5640.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c +index e3a90be5294b..5376206e308b 100644 +--- a/sound/soc/codecs/rt5640.c ++++ b/sound/soc/codecs/rt5640.c +@@ -995,7 +995,8 @@ static int rt5640_lout_event(struct snd_soc_dapm_widget *w, + + switch (event) { + case SND_SOC_DAPM_POST_PMU: +- hp_amp_power_on(component); ++ //hp_amp_power_on(component); ++ //XXX: ^^ breaks hpout restore + snd_soc_component_update_bits(component, RT5640_PWR_ANLG1, + RT5640_PWR_LM, RT5640_PWR_LM); + snd_soc_component_update_bits(component, RT5640_OUTPUT, +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0003-ASoC-codecs-rt5640-Add-input-mixer-input-volume-cont.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0003-ASoC-codecs-rt5640-Add-input-mixer-input-volume-cont.patch new file mode 100644 index 000000000..3217c7d66 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0003-ASoC-codecs-rt5640-Add-input-mixer-input-volume-cont.patch @@ -0,0 +1,48 @@ +From 07c3af029c04522de7b35646a6374b8241fdc28c Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Fri, 14 Apr 2023 22:35:37 +0200 +Subject: [PATCH 03/84] ASoC: codecs: rt5640: Add input mixer input volume + controls + +These are useful to attenuate strong signals from analog inputs. + +Signed-off-by: Ondrej Jirman +--- + sound/soc/codecs/rt5640.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c +index 5376206e308b..03d8196d218c 100644 +--- a/sound/soc/codecs/rt5640.c ++++ b/sound/soc/codecs/rt5640.c +@@ -342,6 +342,7 @@ static const DECLARE_TLV_DB_MINMAX(dac_vol_tlv, -6562, 0); + static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0); + static const DECLARE_TLV_DB_MINMAX(adc_vol_tlv, -1762, 3000); + static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0); ++static const DECLARE_TLV_DB_MINMAX(rec_gain_tlv, -1800, 0); + + /* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */ + static const DECLARE_TLV_DB_RANGE(bst_tlv, +@@ -413,6 +414,19 @@ static const struct snd_kcontrol_new rt5640_snd_controls[] = { + SOC_SINGLE_TLV("IN3 Boost", RT5640_IN1_IN2, + RT5640_BST_SFT2, 8, 0, bst_tlv), + ++ /* RECMIXL Gain Controls */ ++ SOC_SINGLE_TLV("RECMIXL INL Gain", RT5640_REC_L1_MIXER, 10, 6, 1, rec_gain_tlv), ++ SOC_SINGLE_TLV("RECMIXL BST2 Gain", RT5640_REC_L1_MIXER, 7, 6, 1, rec_gain_tlv), ++ SOC_SINGLE_TLV("RECMIXL BST3 Gain", RT5640_REC_L1_MIXER, 1, 6, 1, rec_gain_tlv), ++ SOC_SINGLE_TLV("RECMIXL BST1 Gain", RT5640_REC_L2_MIXER, 13, 6, 1, rec_gain_tlv), ++ SOC_SINGLE_TLV("RECMIXL OUTMIXL Gain", RT5640_REC_L2_MIXER, 10, 6, 1, rec_gain_tlv), ++ ++ SOC_SINGLE_TLV("RECMIXR INR Gain", RT5640_REC_R1_MIXER, 10, 6, 1, rec_gain_tlv), ++ SOC_SINGLE_TLV("RECMIXR BST2 Gain", RT5640_REC_R1_MIXER, 7, 6, 1, rec_gain_tlv), ++ SOC_SINGLE_TLV("RECMIXR BST3 Gain", RT5640_REC_R1_MIXER, 1, 6, 1, rec_gain_tlv), ++ SOC_SINGLE_TLV("RECMIXR BST1 Gain", RT5640_REC_R2_MIXER, 13, 6, 1, rec_gain_tlv), ++ SOC_SINGLE_TLV("RECMIXR OUTMIXR Gain", RT5640_REC_R2_MIXER, 10, 6, 1, rec_gain_tlv), ++ + /* INL/INR Volume Control */ + SOC_DOUBLE_TLV("IN Capture Volume", RT5640_INL_INR_VOL, + RT5640_INL_VOL_SFT, RT5640_INR_VOL_SFT, +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0004-ASoC-codecs-rt5640-Allow-to-control-single-ended-dif.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0004-ASoC-codecs-rt5640-Allow-to-control-single-ended-dif.patch new file mode 100644 index 000000000..eae72e075 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0004-ASoC-codecs-rt5640-Allow-to-control-single-ended-dif.patch @@ -0,0 +1,32 @@ +From 68b5fa757087e8fdf3fe6c7bad67c200503946f8 Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Fri, 14 Apr 2023 22:37:02 +0200 +Subject: [PATCH 04/84] ASoC: codecs: rt5640: Allow to control + single-ended/differential mode + +Not for upstream. This is useful for debugging, trying things without +having to modify DT. + +Signed-off-by: Ondrej Jirman +--- + sound/soc/codecs/rt5640.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c +index 03d8196d218c..1553a0b1f936 100644 +--- a/sound/soc/codecs/rt5640.c ++++ b/sound/soc/codecs/rt5640.c +@@ -427,6 +427,10 @@ static const struct snd_kcontrol_new rt5640_snd_controls[] = { + SOC_SINGLE_TLV("RECMIXR BST1 Gain", RT5640_REC_R2_MIXER, 13, 6, 1, rec_gain_tlv), + SOC_SINGLE_TLV("RECMIXR OUTMIXR Gain", RT5640_REC_R2_MIXER, 10, 6, 1, rec_gain_tlv), + ++ SOC_SINGLE("IN3 Differential Mode", RT5640_IN1_IN2, 6, 1, 0), ++ SOC_SINGLE("IN2 Differential Mode", RT5640_IN3_IN4, 6, 1, 0), ++ SOC_SINGLE("LOUT Differential Mode", 0xfa, 14, 1, 0), ++ + /* INL/INR Volume Control */ + SOC_DOUBLE_TLV("IN Capture Volume", RT5640_INL_INR_VOL, + RT5640_INL_VOL_SFT, RT5640_INR_VOL_SFT, +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0005-ASoC-codecs-rt5640-Keep-the-codec-enabled-when-idle.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0005-ASoC-codecs-rt5640-Keep-the-codec-enabled-when-idle.patch new file mode 100644 index 000000000..af2e9bdc8 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0005-ASoC-codecs-rt5640-Keep-the-codec-enabled-when-idle.patch @@ -0,0 +1,28 @@ +From 801e51af0f5dc01654220afd90a8844c8a7c0a3f Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Sat, 29 Jul 2023 17:33:24 +0200 +Subject: [PATCH 05/84] ASoC: codecs: rt5640: Keep the codec enabled when idle + +This makes analog audio work even without any i2s streams being enabled. + +Signed-off-by: Ondrej Jirman +--- + sound/soc/codecs/rt5640.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c +index 1553a0b1f936..d6859a079538 100644 +--- a/sound/soc/codecs/rt5640.c ++++ b/sound/soc/codecs/rt5640.c +@@ -2954,6 +2954,8 @@ static const struct snd_soc_component_driver soc_component_dev_rt5640 = { + .num_dapm_widgets = ARRAY_SIZE(rt5640_dapm_widgets), + .dapm_routes = rt5640_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rt5640_dapm_routes), ++ .suspend_bias_off = 1, ++ .idle_bias_on = 1, + .use_pmdown_time = 1, + .endianness = 1, + }; +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0006-ASoC-codecs-rt5640-Add-support-for-power-supplies.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0006-ASoC-codecs-rt5640-Add-support-for-power-supplies.patch new file mode 100644 index 000000000..44da1e08b --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0006-ASoC-codecs-rt5640-Add-support-for-power-supplies.patch @@ -0,0 +1,54 @@ +From fc33dcc63c708630afafbc6c0b8541680113c95a Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Thu, 7 Sep 2023 22:58:22 +0200 +Subject: [PATCH 06/84] ASoC: codecs: rt5640: Add support for power supplies + +Signed-off-by: Ondrej Jirman +--- + sound/soc/codecs/rt5640.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c +index d6859a079538..7d7dad5ed884 100644 +--- a/sound/soc/codecs/rt5640.c ++++ b/sound/soc/codecs/rt5640.c +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -38,6 +39,13 @@ + + #define RT5640_PR_BASE (RT5640_PR_RANGE_BASE + (0 * RT5640_PR_SPACING)) + ++static const char *const rt5640_supply_names[] = { ++ "avdd", ++ "cpvdd", ++ "dbvdd", ++ "spkvdd", ++}; ++ + static const struct regmap_range_cfg rt5640_ranges[] = { + { .name = "PR", .range_min = RT5640_PR_BASE, + .range_max = RT5640_PR_BASE + 0xb4, +@@ -3031,6 +3039,14 @@ static int rt5640_i2c_probe(struct i2c_client *i2c) + msleep(400); + } + ++ ret = devm_regulator_bulk_get_enable(&i2c->dev, ++ ARRAY_SIZE(rt5640_supply_names), ++ rt5640_supply_names); ++ if (ret) { ++ dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret); ++ return ret; ++ } ++ + rt5640->regmap = devm_regmap_init_i2c(i2c, &rt5640_regmap); + if (IS_ERR(rt5640->regmap)) { + ret = PTR_ERR(rt5640->regmap); +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0007-media-imx258-Add-i2c-supply.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0007-media-imx258-Add-i2c-supply.patch new file mode 100644 index 000000000..5fe0e133c --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0007-media-imx258-Add-i2c-supply.patch @@ -0,0 +1,27 @@ +From 5774ba8941ddb45470bfa9cc903d63e52a678b90 Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Sun, 22 May 2022 03:25:06 +0200 +Subject: [PATCH 07/84] media: imx258: Add i2c supply + +Sensor depends on I2C bus to be powered up to work. + +Signed-off-by: Ondrej Jirman +--- + drivers/media/i2c/imx258.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c +index bc9ee449a87c..7bfe127daf60 100644 +--- a/drivers/media/i2c/imx258.c ++++ b/drivers/media/i2c/imx258.c +@@ -486,6 +486,7 @@ static const char * const imx258_supply_name[] = { + "vana", /* Analog (2.8V) supply */ + "vdig", /* Digital Core (1.2V) supply */ + "vif", /* IF (1.8V) supply */ ++ "i2c", /* I2C BUS I/O (1.8V) supply */ + }; + + #define IMX258_NUM_SUPPLIES ARRAY_SIZE(imx258_supply_name) +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0008-media-imx258-Add-reset-gpio.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0008-media-imx258-Add-reset-gpio.patch new file mode 100644 index 000000000..22d0d76b8 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0008-media-imx258-Add-reset-gpio.patch @@ -0,0 +1,69 @@ +From faeafc9db9ac2d7f191c09fe3edfa9891a7ddc2f Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Mon, 9 Sep 2024 16:49:41 +0200 +Subject: [PATCH 08/84] media: imx258: Add reset gpio + +IMX258 features a reset input that needs to be controlled when powering +up the chip. + +Signed-off-by: Ondrej Jirman +--- + drivers/media/i2c/imx258.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c +index 7bfe127daf60..16cabbea9074 100644 +--- a/drivers/media/i2c/imx258.c ++++ b/drivers/media/i2c/imx258.c +@@ -681,6 +681,7 @@ struct imx258 { + struct mutex mutex; + + struct clk *clk; ++ struct gpio_desc *reset_gpio; + struct regulator_bulk_data supplies[IMX258_NUM_SUPPLIES]; + }; + +@@ -1125,12 +1126,20 @@ static int imx258_power_on(struct device *dev) + return ret; + } + ++ mdelay(20); ++ + ret = clk_prepare_enable(imx258->clk); + if (ret) { + dev_err(dev, "failed to enable clock\n"); + regulator_bulk_disable(IMX258_NUM_SUPPLIES, imx258->supplies); + } + ++ usleep_range(1000, 2000); ++ ++ gpiod_set_value_cansleep(imx258->reset_gpio, 0); ++ ++ usleep_range(400, 500); ++ + return ret; + } + +@@ -1140,6 +1149,7 @@ static int imx258_power_off(struct device *dev) + struct imx258 *imx258 = to_imx258(sd); + + clk_disable_unprepare(imx258->clk); ++ gpiod_set_value_cansleep(imx258->reset_gpio, 1); + regulator_bulk_disable(IMX258_NUM_SUPPLIES, imx258->supplies); + + return 0; +@@ -1388,6 +1398,11 @@ static int imx258_probe(struct i2c_client *client) + return dev_err_probe(imx258->dev, ret, + "failed to get regulators\n"); + ++ imx258->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", ++ GPIOD_OUT_HIGH); ++ if (IS_ERR(imx258->reset_gpio)) ++ return PTR_ERR(imx258->reset_gpio); ++ + imx258->clk = devm_v4l2_sensor_clk_get_legacy(imx258->dev, NULL, false, + 0); + if (IS_ERR(imx258->clk)) +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0009-media-imx258-Drop-interface-speed-to-1224-mbps.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0009-media-imx258-Drop-interface-speed-to-1224-mbps.patch new file mode 100644 index 000000000..b97a2641b --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0009-media-imx258-Drop-interface-speed-to-1224-mbps.patch @@ -0,0 +1,78 @@ +From 9b48bbc02eb1a3ef4a734f64a95c1e843b1192d1 Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Sun, 15 Sep 2024 23:41:50 +0200 +Subject: [PATCH 09/84] media: imx258: Drop interface speed to 1224 mbps + +Pinephone Pro can't do 1272 mbps. This is just a hack to make the new +upstream driver work quickly with the phone. + +Signed-off-by: Ondrej Jirman +--- + drivers/media/i2c/imx258.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c +index 16cabbea9074..f0e8b81ece48 100644 +--- a/drivers/media/i2c/imx258.c ++++ b/drivers/media/i2c/imx258.c +@@ -213,12 +213,12 @@ static const struct cci_reg_sequence mipi_1267mbps_19_2mhz_4l[] = { + { IMX258_REG_REQ_LINK_BIT_RATE_MBPS_L, 0 }, + }; + +-static const struct cci_reg_sequence mipi_1272mbps_24mhz_2l[] = { ++static const struct cci_reg_sequence mipi_1224mbps_24mhz_2l[] = { + { IMX258_REG_EXCK_FREQ, 0x1800 }, + { IMX258_REG_IVTPXCK_DIV, 10 }, + { IMX258_REG_IVTSYCK_DIV, 2 }, + { IMX258_REG_PREPLLCK_VT_DIV, 4 }, +- { IMX258_REG_PLL_IVT_MPY, 212 }, ++ { IMX258_REG_PLL_IVT_MPY, 204 }, + { IMX258_REG_IOPPXCK_DIV, 10 }, + { IMX258_REG_IOPSYCK_DIV, 1 }, + { IMX258_REG_PREPLLCK_OP_DIV, 2 }, +@@ -226,16 +226,16 @@ static const struct cci_reg_sequence mipi_1272mbps_24mhz_2l[] = { + { IMX258_REG_PLL_MULT_DRIV, 0 }, + + { IMX258_REG_CSI_LANE_MODE, 1 }, +- { IMX258_REG_REQ_LINK_BIT_RATE_MBPS_H, 1272 * 2 }, ++ { IMX258_REG_REQ_LINK_BIT_RATE_MBPS_H, 1224 * 2 }, + { IMX258_REG_REQ_LINK_BIT_RATE_MBPS_L, 0 }, + }; + +-static const struct cci_reg_sequence mipi_1272mbps_24mhz_4l[] = { ++static const struct cci_reg_sequence mipi_1224mbps_24mhz_4l[] = { + { IMX258_REG_EXCK_FREQ, 0x1800 }, + { IMX258_REG_IVTPXCK_DIV, 5 }, + { IMX258_REG_IVTSYCK_DIV, 2 }, + { IMX258_REG_PREPLLCK_VT_DIV, 4 }, +- { IMX258_REG_PLL_IVT_MPY, 212 }, ++ { IMX258_REG_PLL_IVT_MPY, 204 }, + { IMX258_REG_IOPPXCK_DIV, 10 }, + { IMX258_REG_IOPSYCK_DIV, 1 }, + { IMX258_REG_PREPLLCK_OP_DIV, 2 }, +@@ -243,7 +243,7 @@ static const struct cci_reg_sequence mipi_1272mbps_24mhz_4l[] = { + { IMX258_REG_PLL_MULT_DRIV, 0 }, + + { IMX258_REG_CSI_LANE_MODE, 3 }, +- { IMX258_REG_REQ_LINK_BIT_RATE_MBPS_H, 1272 * 4 }, ++ { IMX258_REG_REQ_LINK_BIT_RATE_MBPS_H, 1224 * 4 }, + { IMX258_REG_REQ_LINK_BIT_RATE_MBPS_L, 0 }, + }; + +@@ -568,11 +568,11 @@ static const struct imx258_link_freq_config link_freq_configs_24[] = { + .link_cfg = { + [IMX258_2_LANE_MODE] = { + .lf_to_pix_rate_factor = 2, +- .reg_list = REGS(mipi_1272mbps_24mhz_2l), ++ .reg_list = REGS(mipi_1224mbps_24mhz_2l), + }, + [IMX258_4_LANE_MODE] = { + .lf_to_pix_rate_factor = 4, +- .reg_list = REGS(mipi_1272mbps_24mhz_4l), ++ .reg_list = REGS(mipi_1224mbps_24mhz_4l), + }, + } + }, +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0010-DEBUG-media-imx258-Add-debug-register-access.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0010-DEBUG-media-imx258-Add-debug-register-access.patch new file mode 100644 index 000000000..e0200fbbe --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0010-DEBUG-media-imx258-Add-debug-register-access.patch @@ -0,0 +1,81 @@ +From a14e1b917fd223d3b5063a48c98bd92df1a97c09 Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Thu, 9 Jun 2022 01:04:18 +0200 +Subject: [PATCH 10/84] [DEBUG] media: imx258: Add debug register access + +This is useful during development. + +Signed-off-by: Ondrej Jirman +--- + drivers/media/i2c/imx258.c | 48 ++++++++++++++++++++++++++++++++++++++ + 1 file changed, 48 insertions(+) + +diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c +index f0e8b81ece48..aebe00fd878a 100644 +--- a/drivers/media/i2c/imx258.c ++++ b/drivers/media/i2c/imx258.c +@@ -1214,6 +1214,53 @@ static int imx258_identify_module(struct imx258 *imx258) + return 0; + } + ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int imx258_g_register(struct v4l2_subdev *sd, ++ struct v4l2_dbg_register *reg) ++{ ++ struct imx258 *imx258 = to_imx258(sd); ++ u64 val = 0; ++ int ret; ++ ++ if (reg->reg > 0xffff) ++ return -EINVAL; ++ ++ reg->size = 1; ++ ++ mutex_lock(&imx258->mutex); ++ ret = cci_read(imx258->regmap, CCI_REG8(reg->reg), &val, NULL); ++ mutex_unlock(&imx258->mutex); ++ if (ret) ++ return -EIO; ++ ++ reg->val = val; ++ return 0; ++} ++ ++static int imx258_s_register(struct v4l2_subdev *sd, ++ const struct v4l2_dbg_register *reg) ++{ ++ struct imx258 *imx258 = to_imx258(sd); ++ int ret; ++ ++ if (reg->reg > 0xffff || reg->val > 0xff) ++ return -EINVAL; ++ ++ mutex_lock(&imx258->mutex); ++ ret = cci_write(imx258->regmap, CCI_REG8(reg->reg), reg->val, NULL); ++ mutex_unlock(&imx258->mutex); ++ ++ return ret; ++} ++#endif ++ ++static const struct v4l2_subdev_core_ops imx258_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = imx258_g_register, ++ .s_register = imx258_s_register, ++#endif ++}; ++ + static const struct v4l2_subdev_video_ops imx258_video_ops = { + .s_stream = imx258_set_stream, + }; +@@ -1227,6 +1274,7 @@ static const struct v4l2_subdev_pad_ops imx258_pad_ops = { + }; + + static const struct v4l2_subdev_ops imx258_subdev_ops = { ++ .core = &imx258_core_ops, + .video = &imx258_video_ops, + .pad = &imx258_pad_ops, + }; +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0011-ASoC-rockchip-Fix-doubling-of-playback-speed-after-s.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0011-ASoC-rockchip-Fix-doubling-of-playback-speed-after-s.patch new file mode 100644 index 000000000..f5ab6b5a8 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0011-ASoC-rockchip-Fix-doubling-of-playback-speed-after-s.patch @@ -0,0 +1,46 @@ +From 2cfdbc171b7b0d0d03edd78fae516fa1310fcf17 Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Mon, 15 Aug 2022 02:23:37 +0200 +Subject: [PATCH 11/84] ASoC: rockchip: Fix doubling of playback speed after + system sleep + +There is some issue with CRU on RK3399 that can be reproduced by: + +- playing some audio and stopping the playback (so that runtime PM suspends I2S) +- putting system to deep sleep and resuming it (using mainline TF-A) +- playing some audio (audio plays at 2x the normal speed) + +If the audio is kept playing during system sleep cycle, the issue +does not manifest. Relevant registers in CRU are identical in bug/ +no-bug scenarios, so this patch is just touching the CRU registers +without actually changing anything in the end. Touching the registers +fixes the playback speed, though. + +Inspired by: https://github.com/djselbeck/linux/commit/cb4be5dec3fa18c4b344c11fed3fc57aa3bea424 + +Signed-off-by: Ondrej Jirman +--- + sound/soc/rockchip/rockchip_i2s.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c +index 0a0a95b4f520..6dce1db85427 100644 +--- a/sound/soc/rockchip/rockchip_i2s.c ++++ b/sound/soc/rockchip/rockchip_i2s.c +@@ -114,6 +114,13 @@ static int i2s_runtime_resume(struct device *dev) + if (ret) + clk_disable_unprepare(i2s->mclk); + ++ if (ret == 0) { ++ unsigned long rate = clk_get_rate(i2s->mclk); ++ ++ clk_set_rate(i2s->mclk, rate - 1); ++ clk_set_rate(i2s->mclk, rate); ++ } ++ + return ret; + } + +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0012-Revert-usb-dwc3-Abort-suspend-on-soft-disconnect-fai.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0012-Revert-usb-dwc3-Abort-suspend-on-soft-disconnect-fai.patch new file mode 100644 index 000000000..e7ba02960 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0012-Revert-usb-dwc3-Abort-suspend-on-soft-disconnect-fai.patch @@ -0,0 +1,89 @@ +From db566db3b72a281b3e941c1070cfb30688207950 Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Sat, 9 Aug 2025 10:10:42 +0200 +Subject: [PATCH 12/84] Revert "usb: dwc3: Abort suspend on soft disconnect + failure" + +This reverts commit 630a1dec3b0eba2a695b9063f1c205d585cbfec9. +--- + drivers/usb/dwc3/core.c | 9 ++------- + drivers/usb/dwc3/gadget.c | 22 +++++++++++++--------- + 2 files changed, 15 insertions(+), 16 deletions(-) + +diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c +index 65213896de99..9d4293f02c9a 100644 +--- a/drivers/usb/dwc3/core.c ++++ b/drivers/usb/dwc3/core.c +@@ -2476,7 +2476,6 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg) + { + u32 reg; + int i; +- int ret; + + if (!pm_runtime_suspended(dwc->dev) && !PMSG_IS_AUTO(msg)) { + dwc->susphy_state = (dwc3_readl(dwc, DWC3_GUSB2PHYCFG(0)) & +@@ -2495,9 +2494,7 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg) + case DWC3_GCTL_PRTCAP_DEVICE: + if (pm_runtime_suspended(dwc->dev)) + break; +- ret = dwc3_gadget_suspend(dwc); +- if (ret) +- return ret; ++ dwc3_gadget_suspend(dwc); + synchronize_irq(dwc->irq_gadget); + dwc3_core_exit(dwc); + break; +@@ -2533,9 +2530,7 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg) + break; + + if (dwc->current_otg_role == DWC3_OTG_ROLE_DEVICE) { +- ret = dwc3_gadget_suspend(dwc); +- if (ret) +- return ret; ++ dwc3_gadget_suspend(dwc); + synchronize_irq(dwc->irq_gadget); + } + +diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c +index 3d4ca68e584c..519a1dd23a30 100644 +--- a/drivers/usb/dwc3/gadget.c ++++ b/drivers/usb/dwc3/gadget.c +@@ -4842,15 +4842,8 @@ int dwc3_gadget_suspend(struct dwc3 *dwc) + int ret; + + ret = dwc3_gadget_soft_disconnect(dwc); +- /* +- * Attempt to reset the controller's state. Likely no +- * communication can be established until the host +- * performs a port reset. +- */ +- if (ret && dwc->softconnect) { +- dwc3_gadget_soft_connect(dwc); +- return -EAGAIN; +- } ++ if (ret) ++ goto err; + + spin_lock_irqsave(&dwc->lock, flags); + if (dwc->gadget_driver) +@@ -4858,6 +4851,17 @@ int dwc3_gadget_suspend(struct dwc3 *dwc) + spin_unlock_irqrestore(&dwc->lock, flags); + + return 0; ++ ++err: ++ /* ++ * Attempt to reset the controller's state. Likely no ++ * communication can be established until the host ++ * performs a port reset. ++ */ ++ if (dwc->softconnect) ++ dwc3_gadget_soft_connect(dwc); ++ ++ return ret; + } + + int dwc3_gadget_resume(struct dwc3 *dwc) +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0013-thermal-rockchip-Add-support-for-RV1106-SoC.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0013-thermal-rockchip-Add-support-for-RV1106-SoC.patch new file mode 100644 index 000000000..6263d5a9e --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0013-thermal-rockchip-Add-support-for-RV1106-SoC.patch @@ -0,0 +1,175 @@ +From 0b2ffa2ff9972608365e3f7395e2b0320e49b216 Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Tue, 25 Jun 2024 00:00:14 +0200 +Subject: [PATCH 13/84] thermal: rockchip: Add support for RV1106 SoC + +This SoC includes a thermal sensor, which can be supported by this +driver. Add support for it. + +Signed-off-by: Ondrej Jirman +--- + drivers/thermal/rockchip_thermal.c | 95 +++++++++++++++++++++++++++--- + 1 file changed, 86 insertions(+), 9 deletions(-) + +diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c +index c49ddf70f86e..5dc1e8f27774 100644 +--- a/drivers/thermal/rockchip_thermal.c ++++ b/drivers/thermal/rockchip_thermal.c +@@ -210,6 +210,8 @@ struct rockchip_thermal_data { + #define TSADCV2_AUTO_PERIOD_HT 0x6c + #define TSADCV3_AUTO_PERIOD 0x154 + #define TSADCV3_AUTO_PERIOD_HT 0x158 ++#define TSADCV9_Q_MAX 0x210 ++#define TSADCV9_FLOW_CON 0x218 + + #define TSADCV2_AUTO_EN BIT(0) + #define TSADCV2_AUTO_EN_MASK BIT(16) +@@ -249,10 +251,18 @@ struct rockchip_thermal_data { + #define TSADCV2_USER_INTER_PD_SOC 0x340 /* 13 clocks */ + #define TSADCV5_USER_INTER_PD_SOC 0xfc0 /* 97us, at least 90us */ + ++#define TSADCV9_AUTO_SRC (0x10001 << 0) ++#define TSADCV9_PD_MODE (0x10001 << 4) ++#define TSADCV9_Q_MAX_VAL (0xffff0400 << 0) ++ + #define GRF_SARADC_TESTBIT 0x0e644 + #define GRF_TSADC_TESTBIT_L 0x0e648 + #define GRF_TSADC_TESTBIT_H 0x0e64c + ++#define RV1106_VOGRF_TSADC_CON 0x6000C ++#define RV1106_VOGRF_TSADC_TSEN (0x10001 << 8) ++#define RV1106_VOGRF_TSADC_ANA (0xff0007 << 0) ++ + #define PX30_GRF_SOC_CON2 0x0408 + + #define RK3568_GRF_TSADC_CON 0x0600 +@@ -292,6 +302,15 @@ struct tsadc_table { + int temp; + }; + ++static const struct tsadc_table rv1106_code_table[] = { ++ {0, -40000}, ++ {396, -40000}, ++ {504, 25000}, ++ {605, 85000}, ++ {673, 125000}, ++ {TSADCV2_DATA_MASK, 125000}, ++}; ++ + static const struct tsadc_table rv1108_table[] = { + {0, -40000}, + {374, -40000}, +@@ -863,6 +882,35 @@ static void rk_tsadcv8_initialize(struct regmap *grf, void __iomem *regs, + regs + TSADCV2_AUTO_CON); + } + ++static void rk_tsadcv9_initialize(struct regmap *grf, void __iomem *regs, ++ enum tshut_polarity tshut_polarity) ++{ ++ regmap_write(grf, RV1106_VOGRF_TSADC_CON, RV1106_VOGRF_TSADC_TSEN); ++ udelay(10); ++ regmap_write(grf, RV1106_VOGRF_TSADC_CON, RV1106_VOGRF_TSADC_ANA); ++ udelay(100); ++ ++ writel_relaxed(TSADCV2_AUTO_PERIOD_TIME, regs + TSADCV3_AUTO_PERIOD); ++ writel_relaxed(TSADCV2_AUTO_PERIOD_TIME, ++ regs + TSADCV3_AUTO_PERIOD_HT); ++ writel_relaxed(TSADCV2_HIGHT_INT_DEBOUNCE_COUNT, ++ regs + TSADCV3_HIGHT_INT_DEBOUNCE); ++ writel_relaxed(TSADCV2_HIGHT_TSHUT_DEBOUNCE_COUNT, ++ regs + TSADCV3_HIGHT_TSHUT_DEBOUNCE); ++ writel_relaxed(TSADCV9_AUTO_SRC, regs + TSADCV2_INT_PD); ++ writel_relaxed(TSADCV9_PD_MODE, regs + TSADCV9_FLOW_CON); ++ writel_relaxed(TSADCV9_Q_MAX_VAL, regs + TSADCV9_Q_MAX); ++ if (tshut_polarity == TSHUT_HIGH_ACTIVE) ++ writel_relaxed(TSADCV2_AUTO_TSHUT_POLARITY_HIGH | ++ TSADCV2_AUTO_TSHUT_POLARITY_MASK, ++ regs + TSADCV2_AUTO_CON); ++ else ++ writel_relaxed(TSADCV2_AUTO_TSHUT_POLARITY_MASK, ++ regs + TSADCV2_AUTO_CON); ++ writel_relaxed(TSADCV3_AUTO_Q_SEL_EN | (TSADCV3_AUTO_Q_SEL_EN << 16), ++ regs + TSADCV2_AUTO_CON); ++} ++ + static void rk_tsadcv2_irq_ack(void __iomem *regs) + { + u32 val; +@@ -1073,6 +1121,15 @@ static void rk_tsadcv2_tshut_mode(int chn, void __iomem *regs, + writel_relaxed(val, regs + TSADCV2_INT_EN); + } + ++static int rk_tsadcv2_get_trim_code(const struct chip_tsadc_table *table, ++ int code, int trim_base, int trim_base_frac) ++{ ++ int temp = trim_base * 1000 + trim_base_frac * 100; ++ u32 base_code = rk_tsadcv2_temp_to_code(table, temp); ++ ++ return code - base_code; ++} ++ + static void rk_tsadcv4_tshut_mode(int chn, void __iomem *regs, + enum tshut_mode mode) + { +@@ -1089,15 +1146,6 @@ static void rk_tsadcv4_tshut_mode(int chn, void __iomem *regs, + writel_relaxed(val_cru, regs + TSADCV3_HSHUT_CRU_INT_EN); + } + +-static int rk_tsadcv2_get_trim_code(const struct chip_tsadc_table *table, +- int code, int trim_base, int trim_base_frac) +-{ +- int temp = trim_base * 1000 + trim_base_frac * 100; +- u32 base_code = rk_tsadcv2_temp_to_code(table, temp); +- +- return code - base_code; +-} +- + static const struct rockchip_tsadc_chip px30_tsadc_data = { + /* cpu, gpu */ + .chn_offset = 0, +@@ -1120,6 +1168,31 @@ static const struct rockchip_tsadc_chip px30_tsadc_data = { + }, + }; + ++static const struct rockchip_tsadc_chip rv1106_tsadc_data = { ++ /* cpu */ ++ .chn_offset = 0, ++ .chn_num = 1, ++ ++ .tshut_mode = TSHUT_MODE_CRU, /* default TSHUT via CRU */ ++ .tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */ ++ .tshut_temp = 95000, ++ ++ .initialize = rk_tsadcv9_initialize, ++ .irq_ack = rk_tsadcv4_irq_ack, ++ .control = rk_tsadcv4_control, ++ .get_temp = rk_tsadcv4_get_temp, ++ .set_alarm_temp = rk_tsadcv3_alarm_temp, ++ .set_tshut_temp = rk_tsadcv3_tshut_temp, ++ .set_tshut_mode = rk_tsadcv4_tshut_mode, ++ ++ .table = { ++ .id = rv1106_code_table, ++ .length = ARRAY_SIZE(rv1106_code_table), ++ .data_mask = TSADCV2_DATA_MASK, ++ .mode = ADC_INCREMENT, ++ }, ++}; ++ + static const struct rockchip_tsadc_chip rv1108_tsadc_data = { + /* cpu */ + .chn_offset = 0, +@@ -1355,6 +1428,10 @@ static const struct of_device_id of_rockchip_thermal_match[] = { + { .compatible = "rockchip,px30-tsadc", + .data = (void *)&px30_tsadc_data, + }, ++ { ++ .compatible = "rockchip,rv1106-tsadc", ++ .data = (void *)&rv1106_tsadc_data, ++ }, + { + .compatible = "rockchip,rv1108-tsadc", + .data = (void *)&rv1108_tsadc_data, +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0014-soc-rockchip-Add-support-for-power-monitoring-driver.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0014-soc-rockchip-Add-support-for-power-monitoring-driver.patch new file mode 100644 index 000000000..8c0e959ca --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0014-soc-rockchip-Add-support-for-power-monitoring-driver.patch @@ -0,0 +1,149 @@ +From 3f80fd5e6f79dc72d866cb1869a493e1e12e350d Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Mon, 24 Jun 2024 23:59:19 +0200 +Subject: [PATCH 14/84] soc: rockchip: Add support for power monitoring driver + +This driver reports brownouts into kernel log, so that the user +can debug causes of SoC instability. + +Signed-off-by: Ondrej Jirman +--- + drivers/soc/rockchip/Kconfig | 5 + + drivers/soc/rockchip/Makefile | 1 + + .../soc/rockchip/rockchip_npor_powergood.c | 101 ++++++++++++++++++ + 3 files changed, 107 insertions(+) + create mode 100644 drivers/soc/rockchip/rockchip_npor_powergood.c + +diff --git a/drivers/soc/rockchip/Kconfig b/drivers/soc/rockchip/Kconfig +index 785f60c6f3ad..9408c9a71490 100644 +--- a/drivers/soc/rockchip/Kconfig ++++ b/drivers/soc/rockchip/Kconfig +@@ -30,4 +30,9 @@ config ROCKCHIP_DTPM + on this platform. That will create all the power capping capable + devices. + ++config ROCKCHIP_NPOR_POWERGOOD ++ bool "Rockchip NPOR Powergood" ++ help ++ Say y if SOC integrate ROCKCHIP NPOR Powergood. ++ + endif +diff --git a/drivers/soc/rockchip/Makefile b/drivers/soc/rockchip/Makefile +index 23d414433c8c..06526238b9a5 100644 +--- a/drivers/soc/rockchip/Makefile ++++ b/drivers/soc/rockchip/Makefile +@@ -5,3 +5,4 @@ + obj-$(CONFIG_ROCKCHIP_GRF) += grf.o + obj-$(CONFIG_ROCKCHIP_IODOMAIN) += io-domain.o + obj-$(CONFIG_ROCKCHIP_DTPM) += dtpm.o ++obj-$(CONFIG_ROCKCHIP_NPOR_POWERGOOD) += rockchip_npor_powergood.o +diff --git a/drivers/soc/rockchip/rockchip_npor_powergood.c b/drivers/soc/rockchip/rockchip_npor_powergood.c +new file mode 100644 +index 000000000000..1c92541ce2ae +--- /dev/null ++++ b/drivers/soc/rockchip/rockchip_npor_powergood.c +@@ -0,0 +1,101 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright (c) 2022 Rockchip Electronics Co., Ltd. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct rknpor_powergood_info { ++ int irq; ++ irq_handler_t isr; ++ struct regmap *grf; ++ u32 grf_offset; ++ u8 status_bits_shift; ++}; ++ ++static irqreturn_t rv1106_npor_powergood_isr(int irq, void *data) ++{ ++ struct rknpor_powergood_info *powergood = data; ++ u32 voltage = 0; ++ ++ while (!voltage) { ++ regmap_read(powergood->grf, powergood->grf_offset, &voltage); ++ voltage = (voltage >> powergood->status_bits_shift) & 0x1; ++ } ++ ++ pr_err("%s voltage jitter detected\n", __func__); ++ ++ return IRQ_HANDLED; ++} ++ ++static struct rknpor_powergood_info rv1106_soc_data = { ++ .grf_offset = 0x20020, ++ .status_bits_shift = 4, ++ .isr = rv1106_npor_powergood_isr, ++}; ++ ++static const struct of_device_id rockchip_npor_powergood_dt_match[] = { ++ { ++ .compatible = "rockchip,rv1106-npor-powergood", ++ .data = &rv1106_soc_data ++ }, ++ {}, ++}; ++ ++static int rockchip_npor_powergood_probe(struct platform_device *pdev) ++{ ++ struct rknpor_powergood_info *powergood; ++ const struct of_device_id *match; ++ struct device *dev = &pdev->dev; ++ int ret; ++ ++ match = of_match_node(rockchip_npor_powergood_dt_match, pdev->dev.of_node); ++ powergood = (struct rknpor_powergood_info *)match->data; ++ ++ if (!powergood) ++ return -EINVAL; ++ ++ if (dev->parent && dev->parent->of_node) { ++ powergood->grf = syscon_node_to_regmap(dev->parent->of_node); ++ if (IS_ERR(powergood->grf)) ++ return dev_err_probe(&pdev->dev, PTR_ERR(powergood->grf), "fail to find grf\n"); ++ } ++ ++ powergood->irq = platform_get_irq(pdev, 0); ++ if (powergood->irq < 0) ++ return powergood->irq; ++ ++ ret = devm_request_irq(&pdev->dev, powergood->irq, powergood->isr, 0, "rknpor_powergood", powergood); ++ if (ret) ++ return dev_err_probe(&pdev->dev, ret, "request irq fail\n"); ++ ++ dev_info(&pdev->dev, "probe success!\n"); ++ ++ return 0; ++} ++ ++static struct platform_driver rockchip_npor_powergood_driver = { ++ .probe = rockchip_npor_powergood_probe, ++ .driver = { ++ .name = "rockchip,rknpor-powergood", ++ .of_match_table = rockchip_npor_powergood_dt_match, ++ }, ++}; ++ ++static int __init rockchip_npor_powergood_init(void) ++{ ++ return platform_driver_register(&rockchip_npor_powergood_driver); ++} ++subsys_initcall_sync(rockchip_npor_powergood_init); ++MODULE_DESCRIPTION("Rockchip NPOR Powergood"); ++MODULE_LICENSE("GPL"); +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0015-rtc-rockchip-Add-support-for-RTC-present-in-RV1106-S.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0015-rtc-rockchip-Add-support-for-RTC-present-in-RV1106-S.patch new file mode 100644 index 000000000..f7ea2d2c3 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0015-rtc-rockchip-Add-support-for-RTC-present-in-RV1106-S.patch @@ -0,0 +1,868 @@ +From eea2b3dbea7c25240cd594f028c5a33d92cf70df Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Tue, 25 Jun 2024 00:01:40 +0200 +Subject: [PATCH 15/84] rtc: rockchip: Add support for RTC present in RV1106 + SoC + +This driver adds support for RTC present in Rockchip RV1106 SoC. + +Signed-off-by: Ondrej Jirman +--- + drivers/rtc/Kconfig | 10 + + drivers/rtc/Makefile | 1 + + drivers/rtc/rtc-rockchip.c | 810 +++++++++++++++++++++++++++++++++++++ + 3 files changed, 821 insertions(+) + create mode 100644 drivers/rtc/rtc-rockchip.c + +diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig +index 364afc73f8ab..bc755773a31d 100644 +--- a/drivers/rtc/Kconfig ++++ b/drivers/rtc/Kconfig +@@ -456,6 +456,16 @@ config RTC_DRV_RK808 + This driver can also be built as a module. If so, the module + will be called rk808-rtc. + ++config RTC_DRV_ROCKCHIP ++ tristate "Rockchip RTC" ++ depends on ARCH_ROCKCHIP ++ help ++ If you say yes here you will get support for the ++ RTC of Rockchip. ++ ++ This driver can also be built as a module. If so, the module ++ will be called rtc-rockchip. ++ + config RTC_DRV_RS5C372 + tristate "Ricoh R2025S/D, RS5C372A/B, RV5C386, RV5C387A" + help +diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile +index 6cf7e066314e..7428e7f6274f 100644 +--- a/drivers/rtc/Makefile ++++ b/drivers/rtc/Makefile +@@ -148,6 +148,7 @@ obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.o + obj-$(CONFIG_RTC_DRV_RC5T583) += rtc-rc5t583.o + obj-$(CONFIG_RTC_DRV_RC5T619) += rtc-rc5t619.o + obj-$(CONFIG_RTC_DRV_RK808) += rtc-rk808.o ++obj-$(CONFIG_RTC_DRV_ROCKCHIP) += rtc-rockchip.o + obj-$(CONFIG_RTC_DRV_RP5C01) += rtc-rp5c01.o + obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o + obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o +diff --git a/drivers/rtc/rtc-rockchip.c b/drivers/rtc/rtc-rockchip.c +new file mode 100644 +index 000000000000..3998463565b8 +--- /dev/null ++++ b/drivers/rtc/rtc-rockchip.c +@@ -0,0 +1,810 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (c) 2022 Rockchip Electronics Co., Ltd ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* RTC_CTRL_REG bitfields */ ++ ++#define RTC_REG(x) ((x)) ++#define RTC_SET_SECONDS RTC_REG(0x0) ++#define RTC_SET_MINUTES RTC_REG(0x4) ++#define RTC_SET_HOURS RTC_REG(0x8) ++#define RTC_SET_DAYS RTC_REG(0xc) ++#define RTC_SET_MONTHS RTC_REG(0x10) ++#define RTC_SET_YEARL RTC_REG(0x14) ++#define RTC_SET_YEARH RTC_REG(0x18) ++#define RTC_SET_WEEKS RTC_REG(0x1c) ++#define RTC_ALARM_SECONDS RTC_REG(0x20) ++#define RTC_ALARM_MINUTES RTC_REG(0x24) ++#define RTC_ALARM_HOURS RTC_REG(0x28) ++#define RTC_ALARM_DAYS RTC_REG(0x2c) ++#define RTC_ALARM_MONTHS RTC_REG(0x30) ++#define RTC_ALARM_YEARL RTC_REG(0x34) ++#define RTC_ALARM_YEARH RTC_REG(0x38) ++#define RTC_CTRL RTC_REG(0x3C) ++#define RTC_STATUS0 RTC_REG(0x40) ++#define RTC_STATUS1 RTC_REG(0x44) ++#define RTC_INT0_EN RTC_REG(0x48) ++#define RTC_INT1_EN RTC_REG(0x4c) ++#define RTC_MSEC_CTRL RTC_REG(0x50) ++#define RTC_MSEC_CNT RTC_REG(0x54) ++#define RTC_COMP_H RTC_REG(0x58) ++#define RTC_COMP_D RTC_REG(0x5c) ++#define RTC_COMP_M RTC_REG(0x60) ++#define RTC_ANALOG_CTRL RTC_REG(0x64) ++#define RTC_ANALOG_TEST RTC_REG(0x68) ++#define RTC_LDO_CTRL RTC_REG(0x6c) ++#define RTC_XO_TRIM0 RTC_REG(0x70) ++#define RTC_XO_TRIM1 RTC_REG(0x74) ++#define RTC_VPTAT_TRIM RTC_REG(0x78) ++#define RTC_ANALOG_EN RTC_REG(0x7c) ++#define RTC_CLK32K_TEST RTC_REG(0x80) ++#define RTC_TEST_ST RTC_REG(0x84) ++#define RTC_TEST_LEN RTC_REG(0x88) ++#define RTC_CNT_0 RTC_REG(0x8c) ++#define RTC_CNT_1 RTC_REG(0x90) ++#define RTC_CNT_2 RTC_REG(0x94) ++#define RTC_CNT_3 RTC_REG(0x98) ++#define RTC_MAX_REGISTER RTC_CNT_3 ++ ++#define VI_GRF_VI_MISC_CON0 0x50000 ++#define RTC_CLAMP_EN BIT(6) ++ ++/* RTC_CTRL_REG bitfields */ ++#define RTC_CTRL_REG_START_RTC BIT(0) ++#define RTC_TIMEOUT (3000 * 1000) ++ ++/* RK630 has a shadowed register for saving a "frozen" RTC time. ++ * When user setting "GET_TIME" to 1, the time will save in this shadowed ++ * register. If set "READSEL" to 1, user read rtc time register, actually ++ * get the time of that moment. If we need the real time, clr this bit. ++ */ ++#define RTC_CTRL_REG_RTC_GET_TIME BIT(6) ++#define RTC_CTRL_REG_RTC_READSEL_M BIT(7) ++#define RTC_INT_REG_ALARM_EN BIT(7) ++#define RTC_D2A_XO_EN BIT(0) ++#define RTC_D2A_CLK_OUT_EN BIT(5) ++ ++#define RTC_STATUS_MASK 0xFF ++ ++#define SECONDS_REG_MSK 0x7F ++#define MINUTES_REG_MAK 0x7F ++#define HOURS_REG_MSK 0x3F ++#define DAYS_REG_MSK 0x3F ++#define MONTHS_REG_MSK 0x1F ++#define YEARS_REG_MSK 0xFF ++#define WEEKS_REG_MSK 0x7 ++ ++#define RTC_VREF_INIT 0x40 ++ ++#define D2A_POR_REG_SEL1 BIT(4) ++#define D2A_POR_REG_SEL0 BIT(1) ++ ++#define NUM_TIME_REGS 8 ++#define NUM_ALARM_REGS 7 ++ ++#define DISABLE_ALARM_INT 0x3F ++#define ENABLE_ALARM_INT 0xFF ++#define ALARM_INT_STATUS BIT(4) ++ ++#define CLK32K_TEST_EN BIT(0) ++#define CLK32K_TEST_START BIT(0) ++#define CLK32K_TEST_STATUS BIT(1) ++#define CLK32K_TEST_DONE BIT(2) ++#define CLK32K_TEST_LEN 1 ++ ++#define CLK32K_COMP_DIR_ADD BIT(7) ++#define CLK32K_COMP_EN BIT(2) ++#define CLK32K_NO_COMP 0x1 ++ ++#define CLK32K_TEST_REF_CLK 24000000 ++ ++#define RTC_WRITE_MASK 0xc4522900 ++ ++enum { ++ ROCKCHIP_RV1106_RTC = 1, ++}; ++ ++struct rockchip_rtc { ++ struct regmap *regmap; ++ struct rtc_device *rtc; ++ struct regmap *grf; ++ struct clk_bulk_data *clks; ++ int num_clks; ++ int irq; ++ unsigned int flag; ++ unsigned int mode; ++ struct delayed_work trim_work; ++}; ++ ++static unsigned int rockchip_rtc_write(struct regmap *map, ++ u32 offset, u32 val) ++{ ++ return regmap_write(map, offset, val | RTC_WRITE_MASK); ++} ++ ++static unsigned int rockchip_rtc_update_bits(struct regmap *map, ++ u32 offset, u32 mask, ++ u32 set) ++{ ++ unsigned int val; ++ ++ regmap_read(map, offset, &val); ++ return regmap_write(map, offset, (val & ~mask) | set | RTC_WRITE_MASK); ++} ++ ++/* Read current time and date in RTC */ ++static int rockchip_rtc_read_time(struct device *dev, struct rtc_time *tm) ++{ ++ struct rockchip_rtc *rtc = dev_get_drvdata(dev); ++ u32 rtc_data[NUM_TIME_REGS]; ++ int ret; ++ int yearl, yearh; ++ ++ /* No shadowed registers, need read time three time to update time */ ++ ret = regmap_bulk_read(rtc->regmap, RTC_SET_SECONDS, ++ rtc_data, NUM_TIME_REGS); ++ if (ret) { ++ dev_err(dev, "Failed to bulk read rtc_data: %d\n", ret); ++ return ret; ++ } ++ ret = regmap_bulk_read(rtc->regmap, RTC_SET_SECONDS, ++ rtc_data, NUM_TIME_REGS); ++ if (ret) { ++ dev_err(dev, "Failed to bulk read rtc_data: %d\n", ret); ++ return ret; ++ } ++ ret = regmap_bulk_read(rtc->regmap, RTC_SET_SECONDS, ++ rtc_data, NUM_TIME_REGS); ++ if (ret) { ++ dev_err(dev, "Failed to bulk read rtc_data: %d\n", ret); ++ return ret; ++ } ++ ++ tm->tm_sec = bcd2bin(rtc_data[0] & SECONDS_REG_MSK); ++ tm->tm_min = bcd2bin(rtc_data[1] & MINUTES_REG_MAK); ++ tm->tm_hour = bcd2bin(rtc_data[2] & HOURS_REG_MSK); ++ tm->tm_mday = bcd2bin(rtc_data[3] & DAYS_REG_MSK); ++ tm->tm_mon = (bcd2bin(rtc_data[4] & MONTHS_REG_MSK)) - 1; ++ yearl = (bcd2bin(rtc_data[5] & YEARS_REG_MSK)); ++ yearh = (bcd2bin(rtc_data[6] & YEARS_REG_MSK)); ++ tm->tm_year = yearh * 100 + yearl + 100; ++ tm->tm_wday = bcd2bin(rtc_data[7] & WEEKS_REG_MSK); ++ ++ dev_dbg(dev, "RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n", ++ 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday, ++ tm->tm_wday, tm->tm_hour, tm->tm_min, tm->tm_sec); ++ ++ return ret; ++} ++ ++/* Set current time and date in RTC */ ++static int rockchip_rtc_set_time(struct device *dev, struct rtc_time *tm) ++{ ++ struct rockchip_rtc *rtc = dev_get_drvdata(dev); ++ u32 rtc_data[NUM_TIME_REGS]; ++ int ret, status = 0; ++ int yearl, yearh; ++ ++ dev_dbg(dev, "set RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n", ++ 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday, ++ tm->tm_wday, tm->tm_hour, tm->tm_min, tm->tm_sec); ++ ++ rtc_data[0] = bin2bcd(tm->tm_sec) | RTC_WRITE_MASK; ++ rtc_data[1] = bin2bcd(tm->tm_min) | RTC_WRITE_MASK; ++ rtc_data[2] = bin2bcd(tm->tm_hour) | RTC_WRITE_MASK; ++ rtc_data[3] = bin2bcd(tm->tm_mday) | RTC_WRITE_MASK; ++ rtc_data[4] = bin2bcd(tm->tm_mon + 1) | RTC_WRITE_MASK; ++ if (tm->tm_year > 199) { ++ yearh = (tm->tm_year - 100) / 100; ++ yearl = tm->tm_year - 100 - yearh * 100; ++ } else { ++ yearh = 0; ++ yearl = tm->tm_year - 100 - yearh * 100; ++ } ++ rtc_data[5] = bin2bcd(yearl) | RTC_WRITE_MASK; ++ rtc_data[6] = bin2bcd(yearh) | RTC_WRITE_MASK; ++ rtc_data[7] = bin2bcd(tm->tm_wday) | RTC_WRITE_MASK; ++ ++ /* Stop RTC while updating the RTC registers */ ++ ret = rockchip_rtc_update_bits(rtc->regmap, RTC_CTRL, ++ RTC_CTRL_REG_START_RTC, 0); ++ if (ret) { ++ dev_err(dev, "Failed to update RTC control: %d\n", ret); ++ return ret; ++ } ++ ++ ret = regmap_read_poll_timeout(rtc->regmap, RTC_STATUS1, status, ++ !(status & RTC_CTRL_REG_START_RTC), ++ 1, RTC_TIMEOUT); ++ if (ret) ++ dev_err(dev, ++ "%s:timeout Update RTC_STATUS1 : %d\n", ++ __func__, ret); ++ ++ ret = regmap_bulk_write(rtc->regmap, RTC_SET_SECONDS, ++ rtc_data, NUM_TIME_REGS); ++ if (ret) { ++ dev_err(dev, "Failed to bull write rtc_data: %d\n", ret); ++ return ret; ++ } ++ ++ /* Start RTC again */ ++ ret = rockchip_rtc_update_bits(rtc->regmap, RTC_CTRL, ++ RTC_CTRL_REG_RTC_READSEL_M | ++ RTC_CTRL_REG_START_RTC, ++ RTC_CTRL_REG_RTC_READSEL_M | ++ RTC_CTRL_REG_START_RTC); ++ if (ret) { ++ dev_err(dev, "Failed to update RTC control: %d\n", ret); ++ return ret; ++ } ++ ++ ret = regmap_read_poll_timeout(rtc->regmap, RTC_STATUS1, status, ++ (status & RTC_CTRL_REG_START_RTC), ++ 1, RTC_TIMEOUT); ++ if (ret) ++ dev_err(dev, ++ "%s:timeout Update RTC_STATUS1 : %d\n", ++ __func__, ret); ++ ++ return 0; ++} ++ ++/* Read alarm time and date in RTC */ ++static int rockchip_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) ++{ ++ struct rockchip_rtc *rtc = dev_get_drvdata(dev); ++ u32 alrm_data[NUM_ALARM_REGS]; ++ u32 int_reg; ++ int yearl, yearh; ++ int ret; ++ ++ ret = regmap_bulk_read(rtc->regmap, ++ RTC_ALARM_SECONDS, ++ alrm_data, NUM_ALARM_REGS); ++ if (ret) { ++ dev_err(dev, "Failed to read RTC alarm date REG: %d\n", ret); ++ return ret; ++ } ++ ++ alrm->time.tm_sec = bcd2bin(alrm_data[0] & SECONDS_REG_MSK); ++ alrm->time.tm_min = bcd2bin(alrm_data[1] & MINUTES_REG_MAK); ++ alrm->time.tm_hour = bcd2bin(alrm_data[2] & HOURS_REG_MSK); ++ alrm->time.tm_mday = bcd2bin(alrm_data[3] & DAYS_REG_MSK); ++ alrm->time.tm_mon = (bcd2bin(alrm_data[4] & MONTHS_REG_MSK)) - 1; ++ yearl = (bcd2bin(alrm_data[5] & YEARS_REG_MSK)); ++ yearh = (bcd2bin(alrm_data[6] & YEARS_REG_MSK)); ++ alrm->time.tm_year = yearh * 100 + yearl + 100; ++ ++ ret = regmap_read(rtc->regmap, RTC_INT0_EN, &int_reg); ++ if (ret) { ++ dev_err(dev, "Failed to read RTC INT REG: %d\n", ret); ++ return ret; ++ } ++ ++ dev_dbg(dev, ++ "alrm read RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n", ++ 1900 + alrm->time.tm_year, alrm->time.tm_mon + 1, ++ alrm->time.tm_mday, alrm->time.tm_wday, alrm->time.tm_hour, ++ alrm->time.tm_min, alrm->time.tm_sec); ++ ++ alrm->enabled = (int_reg & RTC_INT_REG_ALARM_EN) ? 1 : 0; ++ ++ return 0; ++} ++ ++static int rockchip_rtc_stop_alarm(struct rockchip_rtc *rtc) ++{ ++ int ret; ++ ++ ret = rockchip_rtc_write(rtc->regmap, RTC_INT0_EN, 0); ++ ++ return ret; ++} ++ ++static int rockchip_rtc_start_alarm(struct rockchip_rtc *rtc) ++{ ++ int ret; ++ ++ ret = rockchip_rtc_write(rtc->regmap, RTC_STATUS0, RTC_STATUS_MASK); ++ ret = rockchip_rtc_write(rtc->regmap, RTC_STATUS0, 0); ++ ret = rockchip_rtc_write(rtc->regmap, RTC_INT0_EN, ENABLE_ALARM_INT); ++ ++ return ret; ++} ++ ++static int rockchip_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) ++{ ++ struct rockchip_rtc *rtc = dev_get_drvdata(dev); ++ u32 alrm_data[NUM_ALARM_REGS]; ++ int yearl, yearh; ++ int ret; ++ ++ ret = rockchip_rtc_stop_alarm(rtc); ++ if (ret) { ++ dev_err(dev, "Failed to stop alarm: %d\n", ret); ++ return ret; ++ } ++ dev_dbg(dev, ++ "alrm set RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n", ++ 1900 + alrm->time.tm_year, alrm->time.tm_mon + 1, ++ alrm->time.tm_mday, alrm->time.tm_wday, alrm->time.tm_hour, ++ alrm->time.tm_min, alrm->time.tm_sec); ++ ++ alrm_data[0] = bin2bcd(alrm->time.tm_sec) | RTC_WRITE_MASK; ++ alrm_data[1] = bin2bcd(alrm->time.tm_min) | RTC_WRITE_MASK; ++ alrm_data[2] = bin2bcd(alrm->time.tm_hour) | RTC_WRITE_MASK; ++ alrm_data[3] = bin2bcd(alrm->time.tm_mday) | RTC_WRITE_MASK; ++ alrm_data[4] = bin2bcd(alrm->time.tm_mon + 1) | RTC_WRITE_MASK; ++ if (alrm->time.tm_year > 199) { ++ yearh = (alrm->time.tm_year - 100) / 100; ++ yearl = alrm->time.tm_year - 100 - yearh * 100; ++ } else { ++ yearh = 0; ++ yearl = alrm->time.tm_year - 100 - yearh * 100; ++ } ++ alrm_data[5] = bin2bcd(yearl) | RTC_WRITE_MASK; ++ alrm_data[6] = bin2bcd(yearh) | RTC_WRITE_MASK; ++ ++ ret = regmap_bulk_write(rtc->regmap, ++ RTC_ALARM_SECONDS, ++ alrm_data, NUM_ALARM_REGS); ++ if (ret) { ++ dev_err(dev, "Failed to bulk write: %d\n", ret); ++ return ret; ++ } ++ if (alrm->enabled) { ++ ret = rockchip_rtc_start_alarm(rtc); ++ if (ret) { ++ dev_err(dev, "Failed to start alarm: %d\n", ret); ++ return ret; ++ } ++ } ++ return 0; ++} ++ ++static int rockchip_rtc_alarm_irq_enable(struct device *dev, ++ unsigned int enabled) ++{ ++ struct rockchip_rtc *rtc = dev_get_drvdata(dev); ++ ++ if (enabled) ++ return rockchip_rtc_start_alarm(rtc); ++ ++ return rockchip_rtc_stop_alarm(rtc); ++} ++ ++/* ++ * We will just handle setting the frequency and make use the framework for ++ * reading the periodic interrupts. ++ * ++ */ ++static irqreturn_t rockchip_rtc_alarm_irq(int irq, void *data) ++{ ++ struct rockchip_rtc *rtc = data; ++ int ret, status; ++ ++ ret = regmap_read(rtc->regmap, RTC_STATUS0, &status); ++ if (ret) { ++ pr_err("Failed to read RTC INT REG: %d\n", ret); ++ return ret; ++ } ++ ++ ret = rockchip_rtc_write(rtc->regmap, RTC_STATUS0, status); ++ if (ret) { ++ pr_err("%s:Failed to update RTC status: %d\n", __func__, ret); ++ return ret; ++ } ++ if (status & ALARM_INT_STATUS) { ++ pr_info("Alarm by: %s\n", __func__); ++ rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static const struct rtc_class_ops rockchip_rtc_ops = { ++ .read_time = rockchip_rtc_read_time, ++ .set_time = rockchip_rtc_set_time, ++ .read_alarm = rockchip_rtc_readalarm, ++ .set_alarm = rockchip_rtc_setalarm, ++ .alarm_irq_enable = rockchip_rtc_alarm_irq_enable, ++}; ++ ++/* ++ * Due to the analog generator 32k clock affected by ++ * temperature, voltage, clock precision need test ++ * with the environment change. In rtc test, ++ * use 24M clock as reference clock to measure the 32k clock. ++ * Before start test 32k clock, we should enable clk32k test(0x80), ++ * and configure test length, when rtc test done(0x84[2]), ++ * latch the 24M clock domain counter, ++ * and read out the counter from rtc_test ++ * registers(0x8c~0x98) via apb bus. ++ * In RTC digital design, we set three level compensation, ++ * the compensation value due to the ++ * RTC 32k clock test result, and if we need compensation, ++ * we need configure the compensation enable bit. ++ * Comp every hour, compensation at last minute every hour, ++ * and support add time and sub time by the MSB bit. ++ * Comp every day, compensation at last minute in last hour every day, ++ * and support add time and sub time by the MSB bit. ++ * Comp every month, compensation at last minute ++ * in last hour in last day every month, ++ * and support add time and sub time by the MSB bit. ++ */ ++static void rockchip_rtc_compensation_delay_work(struct work_struct *work) ++{ ++ struct rockchip_rtc *rtc = container_of(work, struct rockchip_rtc, trim_work.work); ++ u64 camp; ++ u32 count[4], counts, g_ref, tcamp; ++ int ret, done = 0, trim_dir, c_hour, ++ c_day, c_det_day, c_mon, c_det_mon; ++ ++ ret = rockchip_rtc_update_bits(rtc->regmap, RTC_CLK32K_TEST, ++ CLK32K_TEST_EN, CLK32K_TEST_EN); ++ if (ret) { ++ pr_err("%s:Failed to update RTC CLK32K TEST: %d\n", ++ __func__, ret); ++ return; ++ } ++ ++ ret = rockchip_rtc_write(rtc->regmap, RTC_TEST_LEN, ++ CLK32K_TEST_LEN); ++ if (ret) { ++ pr_err("%s:Failed to update RTC CLK32K TEST LEN: %d\n", ++ __func__, ret); ++ return; ++ } ++ ++ ret = rockchip_rtc_update_bits(rtc->regmap, RTC_TEST_ST, ++ CLK32K_TEST_START, ++ CLK32K_TEST_START); ++ if (ret) { ++ pr_err("%s:Failed to update RTC CLK32K TEST STATUS : %d\n", ++ __func__, ret); ++ return; ++ } ++ ret = regmap_read_poll_timeout(rtc->regmap, RTC_TEST_ST, done, ++ (done & CLK32K_TEST_DONE), 20000, RTC_TIMEOUT); ++ if (ret) ++ pr_err("%s:timeout waiting for RTC TEST STATUS : %d\n", ++ __func__, ret); ++ ++ ret = regmap_bulk_read(rtc->regmap, ++ RTC_CNT_0, ++ count, 4); ++ if (ret) { ++ pr_err("Failed to read RTC count REG: %d\n", ret); ++ return; ++ } ++ ++ counts = count[0] | (count[1] << 8) | ++ (count[2] << 16) | (count[3] << 24); ++ g_ref = CLK32K_TEST_REF_CLK * (CLK32K_TEST_LEN + 1); ++ ++ if (counts > g_ref) { ++ trim_dir = 0; ++ camp = 36ULL * (32768 * (counts - g_ref)); ++ do_div(camp, (g_ref / 100)); ++ } else { ++ trim_dir = CLK32K_COMP_DIR_ADD; ++ camp = 36ULL * (32768 * (g_ref - counts)); ++ do_div(camp, (g_ref / 100)); ++ } ++ tcamp = (u32)camp; ++ c_hour = DIV_ROUND_CLOSEST(tcamp, 32768); ++ c_day = DIV_ROUND_CLOSEST(24 * tcamp, 32768); ++ c_mon = DIV_ROUND_CLOSEST(30 * 24 * tcamp, 32768); ++ ++ if (c_hour > 1) ++ rockchip_rtc_write(rtc->regmap, RTC_COMP_H, bin2bcd((c_hour - 1)) | trim_dir); ++ else ++ rockchip_rtc_write(rtc->regmap, RTC_COMP_H, CLK32K_NO_COMP); ++ ++ if (c_day > c_hour * 23) { ++ c_det_day = c_day - c_hour * 23; ++ trim_dir = CLK32K_COMP_DIR_ADD; ++ } else { ++ c_det_day = c_hour * 24 - c_day; ++ trim_dir = 0; ++ } ++ ++ if (c_det_day > 1) ++ rockchip_rtc_write(rtc->regmap, RTC_COMP_D, ++ bin2bcd((c_det_day - 1)) | trim_dir); ++ else ++ rockchip_rtc_write(rtc->regmap, RTC_COMP_D, CLK32K_NO_COMP); ++ ++ if (c_mon > (29 * c_day + 23 * c_hour)) { ++ c_det_mon = c_mon - 29 * c_day - 23 * c_hour; ++ trim_dir = CLK32K_COMP_DIR_ADD; ++ } else { ++ c_det_mon = 29 * c_day + 23 * c_hour - c_mon; ++ trim_dir = 0; ++ } ++ ++ if (c_det_mon) ++ rockchip_rtc_write(rtc->regmap, RTC_COMP_M, ++ bin2bcd((c_det_mon - 1)) | trim_dir); ++ else ++ rockchip_rtc_write(rtc->regmap, RTC_COMP_M, CLK32K_NO_COMP); ++ ++ ret = regmap_read(rtc->regmap, RTC_CTRL, &done); ++ if (ret) { ++ pr_err("Failed to read RTC_CTRL: %d\n", ret); ++ return; ++ } ++ ++ ret = rockchip_rtc_update_bits(rtc->regmap, RTC_CTRL, ++ CLK32K_COMP_EN, CLK32K_COMP_EN); ++ if (ret) { ++ pr_err("%s:Failed to update RTC CTRL : %d\n", __func__, ret); ++ return; ++ } ++ return; ++} ++ ++static bool rockchip_rtc_is_trimed(struct rockchip_rtc *rtc) ++{ ++ int ret, comp_done; ++ ++ ret = regmap_read(rtc->regmap, RTC_CTRL, &comp_done); ++ if (ret) { ++ pr_err("%s: Failed to read RTC_CTRL: %d\n", __func__, ret); ++ return false; ++ } ++ return (comp_done & CLK32K_COMP_EN) == CLK32K_COMP_EN; ++} ++ ++static void rockchip_rtc_trim_start(struct rockchip_rtc *rtc) ++{ ++ if (!rockchip_rtc_is_trimed(rtc)) ++ queue_delayed_work(system_long_wq, &rtc->trim_work, ++ msecs_to_jiffies(5000)); ++} ++ ++static void __maybe_unused rockchip_rtc_trim_close(struct rockchip_rtc *rtc) ++{ ++ if (!rockchip_rtc_is_trimed(rtc)) ++ cancel_delayed_work_sync(&rtc->trim_work); ++} ++ ++/* Enable the alarm if it should be enabled (in case it was disabled to ++ * prevent use as a wake source). ++ */ ++#ifdef CONFIG_PM_SLEEP ++/* Turn off the alarm if it should not be a wake source. */ ++static int rockchip_rtc_suspend(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct rockchip_rtc *rtc = dev_get_drvdata(&pdev->dev); ++ ++ if (device_may_wakeup(dev)) ++ enable_irq_wake(rtc->irq); ++ ++ rockchip_rtc_trim_close(rtc); ++ ++ if (rtc->grf) { ++ switch (rtc->mode) { ++ case ROCKCHIP_RV1106_RTC: ++ regmap_write(rtc->grf, VI_GRF_VI_MISC_CON0, ++ (RTC_CLAMP_EN << 16)); ++ break; ++ default: ++ return -EINVAL; ++ } ++ } ++ clk_bulk_disable_unprepare(rtc->num_clks, rtc->clks); ++ ++ return 0; ++} ++ ++/* Enable the alarm if it should be enabled (in case it was disabled to ++ * prevent use as a wake source). ++ */ ++static int rockchip_rtc_resume(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct rockchip_rtc *rtc = dev_get_drvdata(&pdev->dev); ++ int ret; ++ ++ if (device_may_wakeup(dev)) ++ disable_irq_wake(rtc->irq); ++ ++ if (rtc->grf) { ++ switch (rtc->mode) { ++ case ROCKCHIP_RV1106_RTC: ++ regmap_write(rtc->grf, VI_GRF_VI_MISC_CON0, ++ (RTC_CLAMP_EN << 16) | RTC_CLAMP_EN); ++ break; ++ default: ++ return -EINVAL; ++ } ++ } ++ ret = clk_bulk_prepare_enable(rtc->num_clks, rtc->clks); ++ if (ret) { ++ dev_err(dev, "Cannot enable clock.\n"); ++ return ret; ++ } ++ rockchip_rtc_trim_start(rtc); ++ ++ return 0; ++} ++#endif ++ ++static SIMPLE_DEV_PM_OPS(rockchip_rtc_pm_ops, ++ rockchip_rtc_suspend, rockchip_rtc_resume); ++ ++static const struct of_device_id rockchip_rtc_of_match[] = { ++ { ++ .compatible = "rockchip,rv1106-rtc", ++ .data = (void *)ROCKCHIP_RV1106_RTC ++ }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, rockchip_rtc_of_match); ++ ++static void rockchip_rtc_clk_disable(void *data) ++{ ++ struct rockchip_rtc *rtc = data; ++ ++ clk_bulk_disable_unprepare(rtc->num_clks, rtc->clks); ++} ++ ++static int rockchip_rtc_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node; ++ struct rockchip_rtc *rtc; ++ int ret; ++ struct rtc_time tm_read, tm = { ++ .tm_wday = 0, ++ .tm_year = 121, ++ .tm_mon = 0, ++ .tm_mday = 1, ++ .tm_hour = 12, ++ .tm_min = 0, ++ .tm_sec = 0, ++ }; ++ ++ rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); ++ if (!rtc) ++ return -ENOMEM; ++ ++ rtc->regmap = device_node_to_regmap(np); ++ if (IS_ERR(rtc->regmap)) ++ return dev_err_probe(dev, PTR_ERR(rtc->regmap), ++ "no regmap available\n"); ++ ++ rtc->mode = (uintptr_t)device_get_match_data(dev); ++ rtc->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); ++ if (IS_ERR(rtc->grf)) { ++ dev_warn(dev, "Missing rockchip,grf property\n"); ++ rtc->grf = NULL; ++ } else { ++ switch (rtc->mode) { ++ case ROCKCHIP_RV1106_RTC: ++ regmap_write(rtc->grf, VI_GRF_VI_MISC_CON0, ++ (RTC_CLAMP_EN << 16) | RTC_CLAMP_EN); ++ break; ++ default: ++ return -EINVAL; ++ } ++ } ++ ++ platform_set_drvdata(pdev, rtc); ++ ++ rtc->num_clks = devm_clk_bulk_get_all(&pdev->dev, &rtc->clks); ++ if (rtc->num_clks < 1) ++ return -ENODEV; ++ ret = clk_bulk_prepare_enable(rtc->num_clks, rtc->clks); ++ if (ret) ++ return dev_err_probe(dev, ret, "Cannot enable clock.\n"); ++ ret = devm_add_action_or_reset(dev, rockchip_rtc_clk_disable, rtc); ++ if (ret) ++ return dev_err_probe(dev, ret, ++ "Failed to add clk disable action."); ++ ++ ret = rockchip_rtc_update_bits(rtc->regmap, RTC_VPTAT_TRIM, ++ D2A_POR_REG_SEL1, ++ D2A_POR_REG_SEL1); ++ if (ret) ++ return dev_err_probe(&pdev->dev, ret, ++ "Failed to write RTC_VPTAT_TRIM\n"); ++ ret = rockchip_rtc_update_bits(rtc->regmap, RTC_ANALOG_EN, ++ D2A_POR_REG_SEL0, ++ 0x00); ++ if (ret) ++ return dev_err_probe(&pdev->dev, ret, ++ "Failed to write RTC_ANALOG_EN\n"); ++ ++ ret = rockchip_rtc_update_bits(rtc->regmap, RTC_LDO_CTRL, ++ RTC_D2A_XO_EN, ++ RTC_D2A_XO_EN); ++ if (ret) ++ return dev_err_probe(&pdev->dev, ret, ++ "Failed to update RTC_LDO_CTRL\n"); ++ ++ ret = rockchip_rtc_update_bits(rtc->regmap, RTC_ANALOG_EN, ++ RTC_D2A_CLK_OUT_EN, ++ RTC_D2A_CLK_OUT_EN); ++ if (ret) ++ return dev_err_probe(&pdev->dev, ret, ++ "Failed to update RTC_ANALOG_EN\n"); ++ ++ /* start rtc running by default, and use shadowed timer. */ ++ ret = rockchip_rtc_update_bits(rtc->regmap, RTC_CTRL, ++ RTC_CTRL_REG_START_RTC | ++ RTC_CTRL_REG_RTC_READSEL_M, ++ RTC_CTRL_REG_RTC_READSEL_M | ++ RTC_CTRL_REG_START_RTC); ++ if (ret) ++ return dev_err_probe(&pdev->dev, ret, ++ "Failed to update RTC control\n"); ++ ++ ret = rockchip_rtc_write(rtc->regmap, RTC_STATUS0, RTC_STATUS_MASK); ++ if (ret) ++ return dev_err_probe(&pdev->dev, ret, ++ "Failed to write RTC status0\n"); ++ ++ ret = rockchip_rtc_write(rtc->regmap, RTC_STATUS0, 0); ++ if (ret) ++ return dev_err_probe(&pdev->dev, ret, ++ "Failed to write RTC status0\n"); ++ ++ device_init_wakeup(&pdev->dev, 1); ++ ++ rockchip_rtc_read_time(&pdev->dev, &tm_read); ++ if (rtc_valid_tm(&tm_read) != 0) ++ rockchip_rtc_set_time(&pdev->dev, &tm); ++ ++ rtc->rtc = devm_rtc_allocate_device(&pdev->dev); ++ if (IS_ERR(rtc->rtc)) ++ return PTR_ERR(rtc->rtc); ++ ++ rtc->rtc->ops = &rockchip_rtc_ops; ++ ++ rtc->irq = platform_get_irq(pdev, 0); ++ if (rtc->irq < 0) ++ return dev_err_probe(&pdev->dev, rtc->irq, "No IRQ resource\n"); ++ ++ /* request alarm irq of rtc */ ++ ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL, ++ &rockchip_rtc_alarm_irq, IRQF_ONESHOT, ++ "RTC alarm", rtc); ++ if (ret) ++ return dev_err_probe(&pdev->dev, ret, ++ "Failed to request alarm IRQ %d\n", ++ rtc->irq); ++ ++ INIT_DELAYED_WORK(&rtc->trim_work, rockchip_rtc_compensation_delay_work); ++ rockchip_rtc_trim_start(rtc); ++ ++ return devm_rtc_register_device(rtc->rtc); ++} ++ ++static struct platform_driver rockchip_rtc_driver = { ++ .probe = rockchip_rtc_probe, ++ .driver = { ++ .name = "rockchip-rtc", ++ .pm = &rockchip_rtc_pm_ops, ++ .of_match_table = rockchip_rtc_of_match, ++ }, ++}; ++ ++module_platform_driver(rockchip_rtc_driver); ++ ++MODULE_DESCRIPTION("RTC driver for the rockchip"); ++MODULE_AUTHOR("Zhang Qing "); ++MODULE_LICENSE("GPL"); +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0016-thermal-rockchip-Add-support-for-RK3506.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0016-thermal-rockchip-Add-support-for-RK3506.patch new file mode 100644 index 000000000..316465534 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0016-thermal-rockchip-Add-support-for-RK3506.patch @@ -0,0 +1,177 @@ +From b4c96d43b18506728a339871188209fb52fda313 Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Sun, 6 Apr 2025 01:59:17 +0200 +Subject: [PATCH 16/84] thermal: rockchip: Add support for RK3506 + +Adapted from BSP. + +Signed-off-by: Ondrej Jirman +--- + drivers/thermal/rockchip_thermal.c | 88 +++++++++++++++++++++++++++++- + 1 file changed, 87 insertions(+), 1 deletion(-) + +diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c +index 5dc1e8f27774..44bf6dad8f16 100644 +--- a/drivers/thermal/rockchip_thermal.c ++++ b/drivers/thermal/rockchip_thermal.c +@@ -106,6 +106,7 @@ struct rockchip_tsadc_chip { + void __iomem *reg, enum tshut_polarity p); + void (*irq_ack)(void __iomem *reg); + void (*control)(void __iomem *reg, bool on); ++ void (*suspend)(struct regmap *grf, void __iomem *reg); + + /* Per-sensor methods */ + int (*get_temp)(const struct chip_tsadc_table *table, +@@ -222,6 +223,7 @@ struct rockchip_thermal_data { + #define TSADCV2_AUTO_TSHUT_POLARITY_MASK BIT(24) + + #define TSADCV3_AUTO_Q_SEL_EN BIT(1) ++#define TSADCV3_AUTO_Q_SEL_EN_MASK BIT(17) + + #define TSADCV2_INT_SRC_EN(chn) BIT(chn) + #define TSADCV2_INT_SRC_EN_MASK(chn) BIT(16 + (chn)) +@@ -255,6 +257,9 @@ struct rockchip_thermal_data { + #define TSADCV9_PD_MODE (0x10001 << 4) + #define TSADCV9_Q_MAX_VAL (0xffff0400 << 0) + ++#define TSADCV13_AUTO_PERIOD_TIME 2500 /* 2.5ms */ ++#define TSADCV13_Q_MAX_VAL 0x3ff /* 10bit 1023 */ ++ + #define GRF_SARADC_TESTBIT 0x0e644 + #define GRF_TSADC_TESTBIT_L 0x0e648 + #define GRF_TSADC_TESTBIT_H 0x0e64c +@@ -265,6 +270,8 @@ struct rockchip_thermal_data { + + #define PX30_GRF_SOC_CON2 0x0408 + ++#define RK3506_GRF_TSADC_CON 0x10 ++ + #define RK3568_GRF_TSADC_CON 0x0600 + #define RK3568_GRF_TSADC_ANA_REG0 (0x10001 << 0) + #define RK3568_GRF_TSADC_ANA_REG1 (0x10001 << 1) +@@ -284,7 +291,8 @@ struct rockchip_thermal_data { + + #define GRF_CON_TSADC_CH_INV (0x10001 << 1) + +- ++/* -40 to 125 is reliable, outside the range existed unreliability */ ++#define RK_MIN_TEMP (-60000) + #define RK_MAX_TEMP (180000) + + /** +@@ -545,6 +553,17 @@ static const struct tsadc_table rk3399_code_table[] = { + {TSADCV3_DATA_MASK, 125000}, + }; + ++static const struct tsadc_table rk3506_code_table[] = { ++ {0, RK_MIN_TEMP}, ++ {362, RK_MIN_TEMP}, ++ {395, -40000}, ++ {503, 25000}, ++ {604, 85000}, ++ {672, 125000}, ++ {757, RK_MAX_TEMP}, ++ {TSADCV2_DATA_MASK, RK_MAX_TEMP}, ++}; ++ + static const struct tsadc_table rk3568_code_table[] = { + {0, -40000}, + {1584, -40000}, +@@ -911,6 +930,38 @@ static void rk_tsadcv9_initialize(struct regmap *grf, void __iomem *regs, + regs + TSADCV2_AUTO_CON); + } + ++static void rk_tsadcv13_initialize(struct regmap *grf, void __iomem *regs, ++ enum tshut_polarity tshut_polarity) ++{ ++ regmap_write(grf, RK3506_GRF_TSADC_CON, RV1106_VOGRF_TSADC_TSEN); ++ udelay(10); ++ regmap_write(grf, RK3506_GRF_TSADC_CON, RV1106_VOGRF_TSADC_ANA); ++ udelay(100); ++ ++ writel_relaxed(TSADCV13_AUTO_PERIOD_TIME, regs + TSADCV3_AUTO_PERIOD); ++ writel_relaxed(TSADCV13_AUTO_PERIOD_TIME, ++ regs + TSADCV3_AUTO_PERIOD_HT); ++ writel_relaxed(TSADCV2_HIGHT_INT_DEBOUNCE_COUNT, ++ regs + TSADCV3_HIGHT_INT_DEBOUNCE); ++ writel_relaxed(TSADCV2_HIGHT_TSHUT_DEBOUNCE_COUNT, ++ regs + TSADCV3_HIGHT_TSHUT_DEBOUNCE); ++ writel_relaxed(TSADCV13_Q_MAX_VAL, regs + TSADCV9_Q_MAX); ++ if (tshut_polarity == TSHUT_HIGH_ACTIVE) ++ writel_relaxed(TSADCV2_AUTO_TSHUT_POLARITY_HIGH | ++ TSADCV2_AUTO_TSHUT_POLARITY_MASK, ++ regs + TSADCV2_AUTO_CON); ++ else ++ writel_relaxed(TSADCV2_AUTO_TSHUT_POLARITY_MASK, ++ regs + TSADCV2_AUTO_CON); ++ writel_relaxed(TSADCV3_AUTO_Q_SEL_EN | TSADCV3_AUTO_Q_SEL_EN_MASK, ++ regs + TSADCV2_AUTO_CON); ++} ++ ++static void rk3506_tsadc_suspend(struct regmap *grf, void __iomem *regs) ++{ ++ regmap_write(grf, RK3506_GRF_TSADC_CON, RV1106_VOGRF_TSADC_TSEN & 0xffff0000); ++} ++ + static void rk_tsadcv2_irq_ack(void __iomem *regs) + { + u32 val; +@@ -1353,6 +1404,34 @@ static const struct rockchip_tsadc_chip rk3399_tsadc_data = { + }, + }; + ++static const struct rockchip_tsadc_chip rk3506_tsadc_data = { ++ /* cpu */ ++ .chn_offset = 0, ++ .chn_num = 1, ++ ++ .tshut_mode = TSHUT_MODE_CRU, /* default TSHUT via CRU */ ++ .tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */ ++ .tshut_temp = 95000, ++ ++ .initialize = rk_tsadcv13_initialize, ++ .suspend = rk3506_tsadc_suspend, ++ .irq_ack = rk_tsadcv4_irq_ack, ++ .control = rk_tsadcv4_control, ++ .get_temp = rk_tsadcv4_get_temp, ++ .set_alarm_temp = rk_tsadcv3_alarm_temp, ++ .set_tshut_temp = rk_tsadcv3_tshut_temp, ++ .set_tshut_mode = rk_tsadcv4_tshut_mode, ++ //.get_trim_code = rk_tsadcv2_get_trim_code, ++ //.trim_slope = 594, ++ ++ .table = { ++ .id = rk3506_code_table, ++ .length = ARRAY_SIZE(rk3506_code_table), ++ .data_mask = TSADCV3_DATA_MASK, ++ .mode = ADC_INCREMENT, ++ }, ++}; ++ + static const struct rockchip_tsadc_chip rk3568_tsadc_data = { + /* cpu, gpu */ + .chn_offset = 0, +@@ -1460,6 +1539,10 @@ static const struct of_device_id of_rockchip_thermal_match[] = { + .compatible = "rockchip,rk3399-tsadc", + .data = (void *)&rk3399_tsadc_data, + }, ++ { ++ .compatible = "rockchip,rk3506-tsadc", ++ .data = (void *)&rk3506_tsadc_data, ++ }, + { + .compatible = "rockchip,rk3568-tsadc", + .data = (void *)&rk3568_tsadc_data, +@@ -1894,6 +1977,9 @@ static int __maybe_unused rockchip_thermal_suspend(struct device *dev) + + thermal->chip->control(thermal->regs, false); + ++ if (thermal->chip->suspend) ++ thermal->chip->suspend(thermal->grf, thermal->regs); ++ + clk_disable(thermal->pclk); + clk_disable(thermal->clk); + +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0017-mtd-spi-nor-gigadevice-Add-support-for-gd25lq128e.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0017-mtd-spi-nor-gigadevice-Add-support-for-gd25lq128e.patch new file mode 100644 index 000000000..fa318eaab --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0017-mtd-spi-nor-gigadevice-Add-support-for-gd25lq128e.patch @@ -0,0 +1,33 @@ +From c526256757f45b4afd820f4703e85156a5f4d37e Mon Sep 17 00:00:00 2001 +From: Martijn Braam +Date: Sat, 29 Jan 2022 23:06:29 +0100 +Subject: [PATCH 17/84] mtd: spi-nor: gigadevice: Add support for gd25lq128e + +The GD25LQ128EWIGR reports an JEDEC id with a different vendor, +otherwise it seems to fit neatly in the gigadevice list. + +Signed-off-by: Martijn Braam +--- + drivers/mtd/spi-nor/gigadevice.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/mtd/spi-nor/gigadevice.c b/drivers/mtd/spi-nor/gigadevice.c +index ef1edd0add70..44ec20a9b696 100644 +--- a/drivers/mtd/spi-nor/gigadevice.c ++++ b/drivers/mtd/spi-nor/gigadevice.c +@@ -82,6 +82,12 @@ static const struct flash_info gigadevice_nor_parts[] = { + .size = SZ_16M, + .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB, + .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, ++ }, { ++ .id = SNOR_ID(0x25, 0x70, 0x18), ++ .name = "gd25lq128e", ++ .size = SZ_16M, ++ .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB, ++ .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, + }, + }; + +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0018-clk-rk3399-Export-SCLK_CIF_OUT_SRC-to-device-tree.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0018-clk-rk3399-Export-SCLK_CIF_OUT_SRC-to-device-tree.patch new file mode 100644 index 000000000..c2d4bb386 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0018-clk-rk3399-Export-SCLK_CIF_OUT_SRC-to-device-tree.patch @@ -0,0 +1,41 @@ +From 9383b1fc0830fc3a27d82fe538fb1e594525e9c2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ond=C5=99ej=20Jirman?= +Date: Fri, 22 Oct 2021 18:09:09 +0200 +Subject: [PATCH 18/84] clk: rk3399: Export SCLK_CIF_OUT_SRC to device tree + +So that it can be used in assigned-clock-parents. + +Signed-off-by: Ondrej Jirman +--- + drivers/clk/rockchip/clk-rk3399.c | 2 +- + include/dt-bindings/clock/rk3399-cru.h | 1 + + 2 files changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c +index c2b243d7a5e2..053983966b2f 100644 +--- a/drivers/clk/rockchip/clk-rk3399.c ++++ b/drivers/clk/rockchip/clk-rk3399.c +@@ -1259,7 +1259,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = { + RK3399_CLKGATE_CON(27), 6, GFLAGS), + + /* cif */ +- COMPOSITE_NODIV(0, "clk_cifout_src", mux_pll_src_cpll_gpll_npll_p, 0, ++ COMPOSITE_NODIV(SCLK_CIF_OUT_SRC, "clk_cifout_src", mux_pll_src_cpll_gpll_npll_p, 0, + RK3399_CLKSEL_CON(56), 6, 2, MFLAGS, + RK3399_CLKGATE_CON(10), 7, GFLAGS), + +diff --git a/include/dt-bindings/clock/rk3399-cru.h b/include/dt-bindings/clock/rk3399-cru.h +index 4c90c7703a83..9412df3ef6d8 100644 +--- a/include/dt-bindings/clock/rk3399-cru.h ++++ b/include/dt-bindings/clock/rk3399-cru.h +@@ -125,6 +125,7 @@ + #define SCLK_DDRC 168 + #define SCLK_TESTCLKOUT1 169 + #define SCLK_TESTCLKOUT2 170 ++#define SCLK_CIF_OUT_SRC 171 + + #define DCLK_VOP0 180 + #define DCLK_VOP1 181 +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0019-clk-rockchip-rk3399-Don-t-allow-to-reparent-dclk_vop.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0019-clk-rockchip-rk3399-Don-t-allow-to-reparent-dclk_vop.patch new file mode 100644 index 000000000..ff653621a --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0019-clk-rockchip-rk3399-Don-t-allow-to-reparent-dclk_vop.patch @@ -0,0 +1,35 @@ +From 6f8589b9204a397d5deaa8edd475322b9ec72759 Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Mon, 24 Oct 2022 03:17:57 +0200 +Subject: [PATCH 19/84] clk: rockchip: rk3399: Don't allow to reparent + dclk_vop0 to frac clock + +frac clock requires 20x difference between intput and output, and kernel +code doesn't respect this requirement. + +Signed-off-by: Ondrej Jirman +--- + drivers/clk/rockchip/clk-rk3399.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c +index 053983966b2f..1f592d2d2d85 100644 +--- a/drivers/clk/rockchip/clk-rk3399.c ++++ b/drivers/clk/rockchip/clk-rk3399.c +@@ -279,11 +279,11 @@ static struct rockchip_clk_branch rk3399_uart4_pmu_fracmux __initdata = + RK3399_PMU_CLKSEL_CON(5), 8, 2, MFLAGS); + + static struct rockchip_clk_branch rk3399_dclk_vop0_fracmux __initdata = +- MUX(DCLK_VOP0, "dclk_vop0", mux_dclk_vop0_p, CLK_SET_RATE_PARENT, ++ MUX(DCLK_VOP0, "dclk_vop0", mux_dclk_vop0_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + RK3399_CLKSEL_CON(49), 11, 1, MFLAGS); + + static struct rockchip_clk_branch rk3399_dclk_vop1_fracmux __initdata = +- MUX(DCLK_VOP1, "dclk_vop1", mux_dclk_vop1_p, CLK_SET_RATE_PARENT, ++ MUX(DCLK_VOP1, "dclk_vop1", mux_dclk_vop1_p, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, + RK3399_CLKSEL_CON(50), 11, 1, MFLAGS); + + static struct rockchip_clk_branch rk3399_pmuclk_wifi_fracmux __initdata = +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0020-power-supply-Add-support-for-USB_BC_ENABLED-and-USB_.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0020-power-supply-Add-support-for-USB_BC_ENABLED-and-USB_.patch new file mode 100644 index 000000000..3909ff4e7 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0020-power-supply-Add-support-for-USB_BC_ENABLED-and-USB_.patch @@ -0,0 +1,45 @@ +From 2b6b4c84b9ee0ad52817dac708e52962033028bb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ond=C5=99ej=20Jirman?= +Date: Mon, 22 Jun 2020 02:28:01 +0200 +Subject: [PATCH 20/84] power: supply: Add support for USB_BC_ENABLED and + USB_DCP_INPUT_CURRENT_LIMIT + +- USB_BC_ENABLED - enabling/disabling BC 1.2 USB type detection +- USB_DCP_INPUT_CURRENT_LIMIT - setting a default current limit for DCP/CDP + ports + +Signed-off-by: Ondrej Jirman +--- + drivers/power/supply/power_supply_sysfs.c | 2 ++ + include/linux/power_supply.h | 2 ++ + 2 files changed, 4 insertions(+) + +diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c +index f30a7b9ccd5e..5336a1737d5e 100644 +--- a/drivers/power/supply/power_supply_sysfs.c ++++ b/drivers/power/supply/power_supply_sysfs.c +@@ -218,6 +218,8 @@ static struct power_supply_attr power_supply_attrs[] __ro_after_init = { + POWER_SUPPLY_ATTR(TIME_TO_FULL_AVG), + POWER_SUPPLY_ENUM_ATTR(TYPE), + POWER_SUPPLY_ENUM_ATTR(USB_TYPE), ++ POWER_SUPPLY_ATTR(USB_BC_ENABLED), ++ POWER_SUPPLY_ATTR(USB_DCP_INPUT_CURRENT_LIMIT), + POWER_SUPPLY_ENUM_ATTR(SCOPE), + POWER_SUPPLY_ATTR(PRECHARGE_CURRENT), + POWER_SUPPLY_ATTR(CHARGE_TERM_CURRENT), +diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h +index 7a5e4c3242a0..161cf02e1f71 100644 +--- a/include/linux/power_supply.h ++++ b/include/linux/power_supply.h +@@ -168,6 +168,8 @@ enum power_supply_property { + POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, + POWER_SUPPLY_PROP_TIME_TO_FULL_AVG, + POWER_SUPPLY_PROP_TYPE, /* use power_supply.type instead */ ++ POWER_SUPPLY_PROP_USB_BC_ENABLED, ++ POWER_SUPPLY_PROP_USB_DCP_INPUT_CURRENT_LIMIT, + POWER_SUPPLY_PROP_USB_TYPE, + POWER_SUPPLY_PROP_SCOPE, + POWER_SUPPLY_PROP_PRECHARGE_CURRENT, +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0021-mfd-rk8xx-Enable-rk808-clkout2-function.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0021-mfd-rk8xx-Enable-rk808-clkout2-function.patch new file mode 100644 index 000000000..75ad5d1ec --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0021-mfd-rk8xx-Enable-rk808-clkout2-function.patch @@ -0,0 +1,44 @@ +From 33fe1a73fcef2b401a5b2bae0dc15809836d3604 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Kamil=20Trzci=C5=84ski?= +Date: Mon, 4 Jan 2021 17:57:49 +0100 +Subject: [PATCH 21/84] mfd: rk8xx: Enable rk808-clkout2 function +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +??? + +Signed-of-by: Kamil TrzciÅ„ski +--- + drivers/mfd/rk8xx-core.c | 1 + + include/linux/mfd/rk808.h | 2 ++ + 2 files changed, 3 insertions(+) + +diff --git a/drivers/mfd/rk8xx-core.c b/drivers/mfd/rk8xx-core.c +index 3dcf6abfda74..8dd162a5b124 100644 +--- a/drivers/mfd/rk8xx-core.c ++++ b/drivers/mfd/rk8xx-core.c +@@ -304,6 +304,7 @@ static const struct rk808_reg_data rk818_pre_init_reg[] = { + { RK818_H5V_EN_REG, BIT(0), RK818_H5V_EN }, + { RK808_VB_MON_REG, MASK_ALL, VB_LO_ACT | + VB_LO_SEL_3500MV }, ++ { RK808_CLK32OUT_REG, CLK32KOUT2_FUNC_MASK, CLK32KOUT2_FUNC }, + }; + + static const struct regmap_irq rk801_irqs[] = { +diff --git a/include/linux/mfd/rk808.h b/include/linux/mfd/rk808.h +index 7ffc904c864c..5353a470128d 100644 +--- a/include/linux/mfd/rk808.h ++++ b/include/linux/mfd/rk808.h +@@ -1051,6 +1051,8 @@ enum rk806_dvs_mode { + + #define VOUT_LO_INT BIT(0) + #define CLK32KOUT2_EN BIT(0) ++#define CLK32KOUT2_FUNC (0 << 1) ++#define CLK32KOUT2_FUNC_MASK BIT(1) + + #define TEMP105C 0x08 + #define TEMP115C 0x0c +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0022-power-supply-rk818_battery-Add-battery-charger-drive.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0022-power-supply-rk818_battery-Add-battery-charger-drive.patch new file mode 100644 index 000000000..1865d00fc --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0022-power-supply-rk818_battery-Add-battery-charger-drive.patch @@ -0,0 +1,2598 @@ +From 5e2319782b4fdf05161d264dde23ac10dc1b8949 Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Sun, 11 Jun 2023 18:29:24 +0200 +Subject: [PATCH 22/84] power: supply: rk818_battery: Add battery charger + driver for RK818 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RK818 is a PMIC used on Pinephone. This is a battery charger driver +for it. + +Signed-of-by: OndÅ™ej Jirman +--- + drivers/mfd/rk8xx-core.c | 1 + + drivers/mfd/rk8xx-i2c.c | 38 +- + drivers/power/supply/Kconfig | 8 + + drivers/power/supply/Makefile | 1 + + drivers/power/supply/rk818_battery.c | 2369 ++++++++++++++++++++++++++ + include/linux/mfd/rk808.h | 81 +- + 6 files changed, 2495 insertions(+), 3 deletions(-) + create mode 100644 drivers/power/supply/rk818_battery.c + +diff --git a/drivers/mfd/rk8xx-core.c b/drivers/mfd/rk8xx-core.c +index 8dd162a5b124..f43a886e91bf 100644 +--- a/drivers/mfd/rk8xx-core.c ++++ b/drivers/mfd/rk8xx-core.c +@@ -145,6 +145,7 @@ static const struct mfd_cell rk817s[] = { + static const struct mfd_cell rk818s[] = { + { .name = "rk808-clkout", }, + { .name = "rk808-regulator", }, ++ { .name = "rk818-charger", .of_compatible = "rockchip,rk818-charger", }, + { + .name = "rk808-rtc", + .num_resources = ARRAY_SIZE(rtc_resources), +diff --git a/drivers/mfd/rk8xx-i2c.c b/drivers/mfd/rk8xx-i2c.c +index 2951b2911a37..1f5b291e127c 100644 +--- a/drivers/mfd/rk8xx-i2c.c ++++ b/drivers/mfd/rk8xx-i2c.c +@@ -132,13 +132,47 @@ static bool rk817_is_volatile_reg(struct device *dev, unsigned int reg) + return false; + } + ++static bool rk818_is_volatile_reg(struct device *dev, unsigned int reg) ++{ ++ /* ++ * Notes: ++ * - Technically the ROUND_30s bit makes RTC_CTRL_REG volatile, but ++ * we don't use that feature. It's better to cache. ++ * - It's unlikely we care that RK808_DEVCTRL_REG is volatile since ++ * bits are cleared in case when we shutoff anyway, but better safe. ++ */ ++ ++ switch (reg) { ++ case RK808_SECONDS_REG ... RK808_WEEKS_REG: ++ case RK808_RTC_STATUS_REG: ++ case RK808_VB_MON_REG: ++ case RK808_THERMAL_REG: ++ case RK808_DCDC_EN_REG: ++ case RK808_LDO_EN_REG: ++ case RK808_DCDC_UV_STS_REG: ++ case RK808_LDO_UV_STS_REG: ++ case RK808_DCDC_PG_REG: ++ case RK808_LDO_PG_REG: ++ case RK808_DEVCTRL_REG: ++ case RK808_INT_STS_REG1: ++ case RK808_INT_STS_REG2: ++ case RK808_INT_STS_MSK_REG1: ++ case RK808_INT_STS_MSK_REG2: ++ case RK818_LDO8_ON_VSEL_REG: // TODO(ayufan):?? ++ case RK818_LDO8_SLP_VSEL_REG: // TODO(ayufan):?? ++ case RK818_SUP_STS_REG ... RK818_SAVE_DATA19: ++ return true; ++ } ++ ++ return false; ++} + + static const struct regmap_config rk818_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +- .max_register = RK818_USB_CTRL_REG, ++ .max_register = RK818_SAVE_DATA19, + .cache_type = REGCACHE_MAPLE, +- .volatile_reg = rk808_is_volatile_reg, ++ .volatile_reg = rk818_is_volatile_reg, + }; + + static const struct regmap_config rk801_regmap_config = { +diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig +index 83392ed6a8da..9a8401fc76fa 100644 +--- a/drivers/power/supply/Kconfig ++++ b/drivers/power/supply/Kconfig +@@ -1165,4 +1165,12 @@ config MACSMC_POWER + + Say Y or M here if you have an Apple Silicon based Mac. + ++config CHARGER_RK818 ++ bool "RK818 Charger driver" ++ depends on MFD_RK8XX ++ default n ++ help ++ If you say yes here you will get support for the charger of RK818 PMIC. ++ This driver can give support for Rk818 Charger Interface. ++ + endif # POWER_SUPPLY +diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile +index 7ee839dca7f3..087d75a200de 100644 +--- a/drivers/power/supply/Makefile ++++ b/drivers/power/supply/Makefile +@@ -131,3 +131,4 @@ obj-$(CONFIG_CHARGER_QCOM_SMB2) += qcom_smbx.o + obj-$(CONFIG_FUEL_GAUGE_MM8013) += mm8013.o + obj-$(CONFIG_MACSMC_POWER) += macsmc-power.o + obj-$(CONFIG_CHARGER_MAX77759) += max77759_charger.o ++obj-$(CONFIG_CHARGER_RK818) += rk818_battery.o +diff --git a/drivers/power/supply/rk818_battery.c b/drivers/power/supply/rk818_battery.c +new file mode 100644 +index 000000000000..8cac751f8644 +--- /dev/null ++++ b/drivers/power/supply/rk818_battery.c +@@ -0,0 +1,2369 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * rk818 battery and charger driver ++ * ++ * Copyright (c) 2026 Ondrej Jirman ++ * ++ * Design: ++ * - Coulomb counter is the primary SoC source; it is accurate when ++ * COFFSET is correctly calibrated. ++ * - OCV (open-circuit voltage) and relaxed voltage are used to ++ * periodically re-anchor the coulomb counter. ++ * - Display SoC (dsoc) tracks real SoC (rsoc) through a simple ++ * rate-limiter so it never jumps more than 1% per poll cycle. ++ * - At charge completion the coulomb counter is snapped to FCC. ++ * - COFFSET auto-calibration runs once per charge cycle when the ++ * charger reports RK818_CHG_STS_TERMINATED and current appears near zero. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* RK818_TS_CTRL_REG */ ++#define GG_EN BIT(7) ++#define TS1_CUR_MSK 0x03 ++#define ADC_CUR_20UA 0x00 ++#define ADC_CUR_40UA 0x01 ++#define ADC_CUR_60UA 0x02 ++#define ADC_CUR_80UA 0x03 ++ ++/* NTC battery temperature sensing on TS1 */ ++#define NTC_CALC_FACTOR_80UA 7 ++#define NTC_CALC_FACTOR_60UA 9 ++#define NTC_CALC_FACTOR_40UA 13 ++#define NTC_CALC_FACTOR_20UA 27 ++#define NTC_80UA_MAX_MEASURE 27500 ++#define NTC_60UA_MAX_MEASURE 36666 ++#define NTC_40UA_MAX_MEASURE 55000 ++#define NTC_20UA_MAX_MEASURE 110000 ++ ++/* RK818_ADC_CTRL_REG */ ++#define ADC_CUR_EN BIT(6) ++#define ADC_TS1_EN BIT(5) ++#define ADC_TS2_EN BIT(4) ++ ++/* RK818_GGCON_REG */ ++#define OCV_SAMP_MIN_MSK 0x0c ++#define OCV_SAMP_8MIN (0x00 << 2) ++#define ADC_CAL_MIN_MSK 0x30 ++#define ADC_CAL_8MIN (0x00 << 4) ++#define ADC_CUR_MODE BIT(1) ++ ++/* RK818_GGSTS_REG */ ++#define BAT_CON BIT(4) ++#define RELAX_VOL1_UPD BIT(3) ++#define RELAX_VOL2_UPD BIT(2) ++#define RELAX_VOL12_UPD_MSK (RELAX_VOL1_UPD | RELAX_VOL2_UPD) ++#define RELAX_VOL_STS BIT(0) ++ ++/* RK818_SUP_STS_REG */ ++#define BAT_EXS BIT(7) ++ ++#define RK818_CHG_STS_MASK (7u << 4) /* charger status */ ++#define RK818_CHG_STS_NONE (0u << 4) ++#define RK818_CHG_STS_WAKEUP_CUR (1u << 4) ++#define RK818_CHG_STS_TRICKLE_CUR (2u << 4) ++#define RK818_CHG_STS_CC_OR_CV (3u << 4) ++#define RK818_CHG_STS_TERMINATED (4u << 4) ++#define RK818_CHG_STS_USB_OV (5u << 4) ++#define RK818_CHG_STS_BAT_TEMP_FAULT (6u << 4) ++#define RK818_CHG_STS_TIMEOUT (7u << 4) ++ ++#define RK818_SUP_STS_USB_VLIM_EN BIT(3) /* input voltage limit enable */ ++#define RK818_SUP_STS_USB_ILIM_EN BIT(2) /* input current limit enable */ ++#define RK818_SUP_STS_USB_EXS BIT(1) /* USB power connected */ ++#define RK818_SUP_STS_USB_EFF BIT(0) /* USB fault */ ++ ++/* RK818_VB_MON_REG */ ++#define PLUG_IN_STS BIT(6) ++#define RK818_VBAT_LOW_3V4 0x06 ++ ++/* RK818_MISC_MARK_REG */ ++#define FG_INIT BIT(5) ++ ++/* RK818_INT_STS_MSK_REG1 */ ++#define VB_LOW_INT_EN BIT(1) ++ ++/* RK818_USB_CTRL_REG */ ++#define CHRG_CT_EN BIT(7) ++#define FINISH_CUR_MSK 0xc0 ++#define FINISH_100MA (0x00 << 6) ++#define FINISH_150MA (0x01 << 6) ++#define FINISH_200MA (0x02 << 6) ++#define FINISH_250MA (0x03 << 6) ++/* ++ * CHRG_TIMER_CCCV: CC/CV charging timeout threshold, REG2 bits [2:0]: ++ * 000: 4h, 001: 5h, 010: 6h, 011: 8h, ++ * 100: 10h, 101: 12h, 110: 14h, 111: 16h ++ */ ++#define CHRG_TIMER_CCCV_MSK 0x07 ++#define CHRG_TIMER_CCCV_4H 0x00 ++#define CHRG_TIMER_CCCV_5H 0x01 ++#define CHRG_TIMER_CCCV_6H 0x02 ++#define CHRG_TIMER_CCCV_8H 0x03 ++#define CHRG_TIMER_CCCV_10H 0x04 ++#define CHRG_TIMER_CCCV_12H 0x05 ++#define CHRG_TIMER_CCCV_14H 0x06 ++#define CHRG_TIMER_CCCV_16H 0x07 ++/* ++ * HOTDIE_TEMP: Hot-die temperature threshold, thermal reg bits [3:2]: ++ * 00: 85C, 01: 95C, 10: 105C, 11: 115C ++ */ ++#define HOTDIE_TEMP_MASK (0x3 << 2) ++#define HOTDIE_TEMP_85C (0x0 << 2) ++#define HOTDIE_TEMP_95C (0x1 << 2) ++#define HOTDIE_TEMP_105C (0x2 << 2) ++#define HOTDIE_TEMP_115C (0x3 << 2) ++ ++#define RK818_USB_CTRL_USB_ILIM_MASK (0xfu) ++#define RK818_USB_CTRL_USB_CHG_SD_VSEL_OFFSET 4 ++#define RK818_USB_CTRL_USB_CHG_SD_VSEL_MASK (0x7u << 4) ++ ++/* RK818_CHRG_CTRL_REG1 */ ++#define RK818_CHRG_CTRL_REG1_CHRG_EN BIT(7) ++#define RK818_CHRG_CTRL_REG1_CHRG_VOL_SEL_OFFSET 4 ++#define RK818_CHRG_CTRL_REG1_CHRG_VOL_SEL_MASK (0x7u << 4) ++#define RK818_CHRG_CTRL_REG1_CHRG_CUR_SEL_OFFSET 0 ++#define RK818_CHRG_CTRL_REG1_CHRG_CUR_SEL_MASK (0xfu << 0) ++ ++/* RK818_CHRG_CTRL_REG3 */ ++#define CHRG_TERM_DIG_SIGNAL BIT(5) ++#define CHRG_TIMER_CCCV_EN BIT(2) ++#define RK818_CHRG_CTRL_REG3_CHRG_TERM_DIGITAL BIT(5) ++ ++/* Current offset calibration */ ++#define COFFSET_MIN 0x780 ++#define COFFSET_MAX 0x980 ++#define COFFSET_DEFAULT 0x832 ++#define POFFSET_DEFAULT 42 ++/* Threshold in raw ADC counts below which current is considered zero (~12 mA) */ ++#define ADC_ZERO_THRESHOLD 4 ++#define ADC_CALIB_ITERATIONS 5 ++#define ADC_CALIB_MAX_RUNS 5 ++#define ADC_CALIB_MIN_BOOT_SEC (3 * 60) ++ ++/* SoC / capacity */ ++#define MIN_FCC 500 /* mAh */ ++ ++/* ++ * Coulomb counter LSB denominator. ++ * raw_counts / CC_LSB_DENOM * res_div = mAh (for a 20 mOhm sense resistor) ++ */ ++#define CC_LSB_DENOM 2390 ++ ++/* Maximum display SoC change per monitor cycle */ ++#define DSOC_DELTA_MAX 1 /* % */ ++ ++/* ++ * Conservative current estimate used to cross-check dsoc during sleep. ++ * The coulomb counter keeps running, so this is only used to bound ++ * how far dsoc can lag behind rsoc after a long suspend without a ++ * charger attached. ++ */ ++#define SLP_CURR_MA 20 ++ ++#define MONITOR_MS_DEFAULT (5 * 1000) ++ ++/* Safe non-zero divisor */ ++#define DIV(x) ((x) ? (x) : 1) ++ ++/* ------------------------------------------------------------------------- ++ * Platform data ++ * ------------------------------------------------------------------------- */ ++ ++/* ++ * Vendor-specific battery tunables only. ++ * ++ * Standard simple-battery properties (design capacity, design voltages, ++ * max charge current/voltage, internal resistance, OCV table, ...) are ++ * fetched by the power-supply core from the "monitored-battery" phandle ++ * and exposed via psy->battery_info. They must not be duplicated here. ++ */ ++ ++/* ------------------------------------------------------------------------- ++ * Driver state ++ * ------------------------------------------------------------------------- */ ++ ++/* ++ * Single entry in the NTC battery thermistor lookup table. ++ * Entries are sorted by temperature ascending; resistance therefore ++ * decreases monotonically as the index grows (NTC: cold = high R). ++ */ ++struct rk818_ntc_entry { ++ s32 temp; /* whole degrees Celsius */ ++ u32 res; /* thermistor resistance, ohms */ ++}; ++ ++struct rk818_battery { ++ struct platform_device *pdev; ++ struct rk808 *rk818; ++ struct regmap *regmap; ++ struct device *dev; ++ struct power_supply_battery_info *info; ++ struct workqueue_struct *wq; ++ struct delayed_work work; ++ ++ /* Device-tree tunables (previously in struct battery_platform_data) */ ++ u32 monitor_sec; ++ u32 sense_resist_mohm; /* 10 or 20 */ ++ u32 relax_entry_current_ma; ++ u32 relax_exit_current_ma; ++ u32 max_soc_offset_pct; ++ u32 feedback_temp; /* Celsius, 0 = disabled */ ++ u32 cccv_timeout_h; /* CC/CV safety timer hours; 0 = disabled */ ++ ++ /* NTC battery thermistor (TS1) */ ++ u32 ntc_size; ++ u32 ntc_factor; ++ u32 ntc_uA; ++ struct rk818_ntc_entry *ntc_entries; ++ int temperature; /* tenths of a degree C */ ++ ++ /* Boottime of last periodic calibration; see rk818_battery_work() */ ++ ktime_t last_calib; ++ ++ /* Power supplies */ ++ struct power_supply *usb_psy; ++ struct power_supply *charger_psy; ++ ++ /* USB input current limit state */ ++ bool apply_ilim; ++ ++ /* ++ * Voltage ADC calibration coefficients. ++ * voltage_mV = raw_adc * voltage_k / 1000 + voltage_b ++ */ ++ int voltage_k; ++ int voltage_b; ++ ++ /* Persistent current offset saved across reboots via POFFSET_REG */ ++ int poffset; ++ ++ /* ++ * Sense resistor divisor: ++ * 1 for 20 mOhm (default), 2 for 10 mOhm. ++ * Used to scale coulomb counter and current readings. ++ */ ++ u8 res_div; ++ ++ /* Latest measurements, updated each monitor cycle */ ++ int voltage_avg_mv; ++ int voltage_ocv_mv; ++ int voltage_relax_mv; ++ int current_avg_ma; ++ int remain_cap_mah; ++ int fcc_mah; ++ int rsoc; ++ int dsoc; ++ ++ int chrg_status; ++ bool is_charging; ++ ++ /* COFFSET auto-calibration state, reset each charge cycle */ ++ bool coffset_calib_done; ++ u32 coffset_calib_runs; ++ ++ /* Suspend/resume bookkeeping */ ++ ktime_t suspend_time; ++ bool sleep_chrg_online; ++ ++ /* Startup flags */ ++ bool is_first_power_on; ++ bool is_initialized; ++ u32 pwroff_min; ++ ++ u32 monitor_ms; ++ unsigned long boot_base_jiffies; ++}; ++ ++/* ------------------------------------------------------------------------- ++ * Time helpers ++ * ------------------------------------------------------------------------- */ ++ ++static u64 rk818_sec_since(unsigned long base_jiffies) ++{ ++ if (!base_jiffies) ++ return 0; ++ return jiffies_to_msecs(jiffies - base_jiffies) / 1000; ++} ++ ++/* ------------------------------------------------------------------------- ++ * Register access ++ * ------------------------------------------------------------------------- */ ++ ++static int rk818_read(struct rk818_battery *di, u8 reg) ++{ ++ int ret, val; ++ ++ ret = regmap_read(di->regmap, reg, &val); ++ if (ret) ++ dev_err(di->dev, "read reg 0x%02x failed: %d\n", reg, ret); ++ return val; ++} ++ ++static void rk818_write(struct rk818_battery *di, u8 reg, u8 val) ++{ ++ int ret; ++ ++ ret = regmap_write(di->regmap, reg, val); ++ if (ret) ++ dev_err(di->dev, "write reg 0x%02x failed: %d\n", reg, ret); ++} ++ ++static void rk818_clrsetbits(struct rk818_battery *di, u8 reg, u8 mask, u8 val) ++{ ++ int ret; ++ ++ ret = regmap_update_bits(di->regmap, reg, mask, val); ++ if (ret) ++ dev_err(di->dev, "update reg 0x%02x failed: %d\n", reg, ret); ++} ++ ++/* Forward declarations for helpers used before their definition. */ ++static int rk818_charger_set_current_max(struct rk818_battery *di, int val); ++static int rk818_charger_set_voltage_max(struct rk818_battery *di, int val); ++ ++/* ++ * Read a big-endian 16-bit register pair and apply linear voltage calibration. ++ * @regh is the address of the high byte; @regh+1 is the low byte. ++ */ ++static int rk818_read_vol(struct rk818_battery *di, u8 regh) ++{ ++ int raw; ++ ++ raw = rk818_read(di, regh) << 8; ++ raw |= rk818_read(di, regh + 1); ++ return di->voltage_k * raw / 1000 + di->voltage_b; ++} ++ ++/* ++ * Read a big-endian signed 12-bit current ADC word and convert to mA. ++ * ++ * The LSB size depends on the sense resistor: ++ * 20 mOhm -> 1506 uA/LSB (res_div == 1) ++ * 10 mOhm -> 3012 uA/LSB (res_div == 2) ++ */ ++static int rk818_read_cur(struct rk818_battery *di, u8 regh) ++{ ++ int raw; ++ ++ raw = rk818_read(di, regh) << 8; ++ raw |= rk818_read(di, regh + 1); ++ ++ if (raw & 0x800) ++ raw -= 4096; ++ ++ return raw * (int)di->res_div * 1506 / 1000; ++} ++ ++/* ------------------------------------------------------------------------- ++ * OCV table interpolation ++ * ------------------------------------------------------------------------- ++ * OCV lookup is delegated to power_supply_batinfo_ocv2cap(), which ++ * operates on the standard simple-battery ocv-capacity-table parsed by ++ * the power-supply core into psy->battery_info. ++ */ ++ ++static int vol_to_soc(struct rk818_battery *di, int voltage_mv) ++{ ++ int cap; ++ ++ /* ++ * power_supply_batinfo_ocv2cap() takes microvolts and a ++ * temperature in whole degrees Celsius (matching the values in ++ * the battery node's ocv-capacity-celsius property), and ++ * returns the capacity percent (or a negative errno). ++ */ ++ cap = power_supply_batinfo_ocv2cap(di->info, voltage_mv * 1000, 20); ++ return cap < 0 ? 0 : cap; ++} ++ ++static int vol_to_cap(struct rk818_battery *di, int voltage_mv) ++{ ++ return vol_to_soc(di, voltage_mv) * di->fcc_mah / 100; ++} ++ ++/* ------------------------------------------------------------------------- ++ * Coulomb counter ++ * ------------------------------------------------------------------------- */ ++ ++static int rk818_get_coulomb_cap(struct rk818_battery *di) ++{ ++ int raw = 0; ++ ++ raw |= rk818_read(di, RK818_GASCNT3_REG) << 24; ++ raw |= rk818_read(di, RK818_GASCNT2_REG) << 16; ++ raw |= rk818_read(di, RK818_GASCNT1_REG) << 8; ++ raw |= rk818_read(di, RK818_GASCNT0_REG); ++ ++ return (raw / CC_LSB_DENOM) * di->res_div; ++} ++ ++static void rk818_set_coulomb_cap(struct rk818_battery *di, int cap_mah) ++{ ++ u32 raw = (u32)cap_mah * CC_LSB_DENOM / DIV(di->res_div); ++ ++ rk818_write(di, RK818_GASCNT_CAL_REG3, (raw >> 24) & 0xff); ++ rk818_write(di, RK818_GASCNT_CAL_REG2, (raw >> 16) & 0xff); ++ rk818_write(di, RK818_GASCNT_CAL_REG1, (raw >> 8) & 0xff); ++ rk818_write(di, RK818_GASCNT_CAL_REG0, raw & 0xff); ++ ++ di->remain_cap_mah = cap_mah; ++ dev_dbg(di->dev, "coulomb cap set to %d mAh\n", cap_mah); ++} ++ ++/* ------------------------------------------------------------------------- ++ * Charger / battery presence ++ * ------------------------------------------------------------------------- */ ++ ++static bool rk818_charger_online(struct rk818_battery *di) ++{ ++ return !!(rk818_read(di, RK818_VB_MON_REG) & PLUG_IN_STS); ++} ++ ++static int rk818_get_chrg_status(struct rk818_battery *di) ++{ ++ return rk818_read(di, RK818_SUP_STS_REG) & RK818_CHG_STS_MASK; ++} ++ ++static bool rk818_battery_present(struct rk818_battery *di) ++{ ++ return !!(rk818_read(di, RK818_SUP_STS_REG) & BAT_EXS); ++} ++ ++/* ------------------------------------------------------------------------- ++ * Relaxed voltage (open-circuit approximation during low-current periods) ++ * ------------------------------------------------------------------------- */ ++ ++/* ++ * Returns the higher of the two hardware-captured relaxed voltage samples, ++ * or 0 if neither sample is valid yet. ++ */ ++static int rk818_get_relax_voltage(struct rk818_battery *di) ++{ ++ int rv1, rv2; ++ u8 sts; ++ ++ sts = rk818_read(di, RK818_GGSTS_REG); ++ if (!(sts & RELAX_VOL1_UPD) || !(sts & RELAX_VOL2_UPD)) ++ return 0; ++ ++ rv1 = rk818_read_vol(di, RK818_RELAX_VOL1_REGH); ++ rv2 = rk818_read_vol(di, RK818_RELAX_VOL2_REGH); ++ ++ return max(rv1, rv2); ++} ++ ++/* Clear the valid flags so the hardware will capture fresh samples. */ ++static void rk818_restart_relax(struct rk818_battery *di) ++{ ++ u8 sts = rk818_read(di, RK818_GGSTS_REG); ++ ++ rk818_write(di, RK818_GGSTS_REG, sts & ~RELAX_VOL12_UPD_MSK); ++} ++ ++/* ------------------------------------------------------------------------- ++ * Voltage ADC calibration (k / b coefficients) ++ * ------------------------------------------------------------------------- */ ++ ++/* ++ * The PMIC stores two factory calibration points in VCALIB0 / VCALIB1: ++ * vcalib0 = ADC code at 3000 mV ++ * vcalib1 = ADC code at 4200 mV ++ * ++ * From these we derive: ++ * k = (4200 - 3000) * 1000 / (vcalib1 - vcalib0) ++ * b = 4200 - k * vcalib1 / 1000 ++ * voltage_mV = raw * k / 1000 + b ++ */ ++static void rk818_init_voltage_kb(struct rk818_battery *di) ++{ ++ int v0, v1; ++ ++ v0 = rk818_read(di, RK818_VCALIB0_REGL); ++ v0 |= rk818_read(di, RK818_VCALIB0_REGH) << 8; ++ v1 = rk818_read(di, RK818_VCALIB1_REGL); ++ v1 |= rk818_read(di, RK818_VCALIB1_REGH) << 8; ++ ++ di->voltage_k = (4200 - 3000) * 1000 / DIV(v1 - v0); ++ di->voltage_b = 4200 - di->voltage_k * v1 / 1000; ++ ++ dev_dbg(di->dev, "voltage cal: k=%d b=%d (calib0=%d calib1=%d)\n", ++ di->voltage_k, di->voltage_b, v0, v1); ++} ++ ++/* ------------------------------------------------------------------------- ++ * Current offset calibration ++ * ------------------------------------------------------------------------- */ ++ ++static int rk818_get_coffset(struct rk818_battery *di) ++{ ++ int val; ++ ++ val = rk818_read(di, RK818_CAL_OFFSET_REGL); ++ val |= rk818_read(di, RK818_CAL_OFFSET_REGH) << 8; ++ return val; ++} ++ ++static void rk818_set_coffset(struct rk818_battery *di, int val) ++{ ++ if (val < COFFSET_MIN || val > COFFSET_MAX) { ++ dev_warn(di->dev, ++ "coffset 0x%x out of range [0x%x, 0x%x], ignoring\n", ++ val, COFFSET_MIN, COFFSET_MAX); ++ return; ++ } ++ rk818_write(di, RK818_CAL_OFFSET_REGH, (val >> 8) & 0xff); ++ rk818_write(di, RK818_CAL_OFFSET_REGL, val & 0xff); ++} ++ ++static int rk818_get_ioffset(struct rk818_battery *di) ++{ ++ int val; ++ ++ val = rk818_read(di, RK818_IOFFSET_REGL); ++ val |= rk818_read(di, RK818_IOFFSET_REGH) << 8; ++ return val; ++} ++ ++/* ++ * Read the raw signed 12-bit ADC code used for current sensing. ++ * This is the value before the COFFSET subtraction that the hardware ++ * applies internally, so it reflects the residual offset we want to zero. ++ */ ++static int rk818_get_iadc(struct rk818_battery *di) ++{ ++ int val; ++ ++ val = rk818_read(di, RK818_BAT_CUR_AVG_REGL); ++ val |= rk818_read(di, RK818_BAT_CUR_AVG_REGH) << 8; ++ if (val > 2047) ++ val -= 4096; ++ return val; ++} ++ ++/* ++ * rk818_init_coffset - restore the calibrated current offset on boot. ++ * ++ * COFFSET = IOFFSET (written by the PMIC at power-on) + POFFSET (saved by ++ * the driver after a successful auto-calibration). This combination ++ * cancels both the hardware reference offset and any board-level parasitic. ++ */ ++static void rk818_init_coffset(struct rk818_battery *di) ++{ ++ int ioffset, coffset; ++ ++ ioffset = rk818_get_ioffset(di); ++ di->poffset = rk818_read(di, RK818_POFFSET_REG); ++ if (!di->poffset) ++ di->poffset = POFFSET_DEFAULT; ++ ++ coffset = di->poffset + ioffset; ++ if (coffset < COFFSET_MIN || coffset > COFFSET_MAX) ++ coffset = COFFSET_DEFAULT; ++ ++ rk818_set_coffset(di, coffset); ++ dev_dbg(di->dev, ++ "coffset init: poffset=0x%x ioffset=0x%x -> coffset=0x%x\n", ++ di->poffset, ioffset, coffset); ++} ++ ++/* ++ * rk818_auto_calib_coffset - iteratively nudge COFFSET until BAT_CUR_AVG = 0. ++ * ++ * Only attempted when the charger reports RK818_CHG_STS_TERMINATED and the charger is ++ * present, so battery current should genuinely be close to zero. After ++ * convergence, POFFSET is saved so the correction survives a reboot. ++ * ++ * Returns true if calibration converged. ++ */ ++static bool rk818_auto_calib_coffset(struct rk818_battery *di) ++{ ++ int i, iadc, coffset, saved_coffset, ioffset; ++ ++ if (di->coffset_calib_done || ++ di->coffset_calib_runs >= ADC_CALIB_MAX_RUNS || ++ di->chrg_status != RK818_CHG_STS_TERMINATED || ++ rk818_sec_since(di->boot_base_jiffies) < ADC_CALIB_MIN_BOOT_SEC || ++ abs(di->current_avg_ma) < ADC_ZERO_THRESHOLD) ++ return false; ++ ++ di->coffset_calib_runs++; ++ saved_coffset = rk818_get_coffset(di); ++ ++ for (i = 0; i < ADC_CALIB_ITERATIONS; i++) { ++ if (!rk818_charger_online(di)) { ++ rk818_set_coffset(di, saved_coffset); ++ dev_info(di->dev, ++ "coffset calib aborted: charger removed\n"); ++ return false; ++ } ++ ++ iadc = rk818_get_iadc(di); ++ coffset = rk818_get_coffset(di); ++ rk818_set_coffset(di, coffset + iadc); ++ msleep(2000); ++ ++ iadc = rk818_get_iadc(di); ++ if (abs(iadc) < ADC_ZERO_THRESHOLD) { ++ ioffset = rk818_get_ioffset(di); ++ coffset = rk818_get_coffset(di); ++ di->poffset = coffset - ioffset; ++ rk818_write(di, RK818_POFFSET_REG, di->poffset); ++ di->coffset_calib_done = true; ++ dev_info(di->dev, ++ "coffset calib done: coffset=0x%x ioffset=0x%x poffset=0x%x\n", ++ coffset, ioffset, di->poffset); ++ return true; ++ } ++ } ++ ++ rk818_set_coffset(di, saved_coffset); ++ dev_info(di->dev, ++ "coffset calib incomplete after %d iters (run %u/%u)\n", ++ ADC_CALIB_ITERATIONS, di->coffset_calib_runs, ++ ADC_CALIB_MAX_RUNS); ++ return false; ++} ++ ++/* ------------------------------------------------------------------------- ++ * FCC (fully-charged capacity) persistence ++ * ------------------------------------------------------------------------- */ ++ ++static int rk818_read_fcc(struct rk818_battery *di) ++{ ++ u32 fcc = 0; ++ ++ fcc |= (u32)rk818_read(di, RK818_NEW_FCC_REG3) << 24; ++ fcc |= (u32)rk818_read(di, RK818_NEW_FCC_REG2) << 16; ++ fcc |= (u32)rk818_read(di, RK818_NEW_FCC_REG1) << 8; ++ fcc |= (u32)rk818_read(di, RK818_NEW_FCC_REG0); ++ ++ u32 design_mah = di->info->charge_full_design_uah / 1000; ++ ++ if (fcc < MIN_FCC || fcc > design_mah) { ++ dev_info(di->dev, ++ "stored FCC %u mAh out of range, using design capacity\n", ++ fcc); ++ fcc = design_mah; ++ } ++ ++ return (int)clamp(fcc, (u32)MIN_FCC, design_mah); ++} ++ ++static void rk818_save_fcc(struct rk818_battery *di, u32 fcc) ++{ ++ rk818_write(di, RK818_NEW_FCC_REG3, (fcc >> 24) & 0xff); ++ rk818_write(di, RK818_NEW_FCC_REG2, (fcc >> 16) & 0xff); ++ rk818_write(di, RK818_NEW_FCC_REG1, (fcc >> 8) & 0xff); ++ rk818_write(di, RK818_NEW_FCC_REG0, fcc & 0xff); ++ dev_info(di->dev, "FCC saved: %u mAh\n", fcc); ++} ++ ++/* ------------------------------------------------------------------------- ++ * State persistence ++ * ------------------------------------------------------------------------- */ ++ ++static void rk818_save_dsoc(struct rk818_battery *di) ++{ ++ rk818_write(di, RK818_SOC_REG, (u8)clamp(di->dsoc, 0, 100)); ++} ++ ++static void rk818_save_remain_cap(struct rk818_battery *di) ++{ ++ int cap = clamp(di->remain_cap_mah, 0, ++ (int)(di->info->charge_full_design_uah / 1000)); ++ ++ rk818_write(di, RK818_REMAIN_CAP_REG3, (cap >> 24) & 0xff); ++ rk818_write(di, RK818_REMAIN_CAP_REG2, (cap >> 16) & 0xff); ++ rk818_write(di, RK818_REMAIN_CAP_REG1, (cap >> 8) & 0xff); ++ rk818_write(di, RK818_REMAIN_CAP_REG0, cap & 0xff); ++} ++ ++static int rk818_read_saved_cap(struct rk818_battery *di) ++{ ++ int cap = 0; ++ ++ cap |= rk818_read(di, RK818_REMAIN_CAP_REG3) << 24; ++ cap |= rk818_read(di, RK818_REMAIN_CAP_REG2) << 16; ++ cap |= rk818_read(di, RK818_REMAIN_CAP_REG1) << 8; ++ cap |= rk818_read(di, RK818_REMAIN_CAP_REG0); ++ ++ return cap; ++} ++ ++/* ------------------------------------------------------------------------- ++ * Hardware configuration ++ * ------------------------------------------------------------------------- */ ++ ++static void rk818_enable_gauge(struct rk818_battery *di) ++{ ++ u8 val = rk818_read(di, RK818_TS_CTRL_REG); ++ ++ rk818_write(di, RK818_TS_CTRL_REG, val | GG_EN); ++} ++ ++static void rk818_configure_sampling(struct rk818_battery *di) ++{ ++ u8 ggcon = rk818_read(di, RK818_GGCON_REG); ++ ++ ggcon = (ggcon & ~OCV_SAMP_MIN_MSK) | OCV_SAMP_8MIN; ++ ggcon = (ggcon & ~ADC_CAL_MIN_MSK) | ADC_CAL_8MIN; ++ ggcon |= ADC_CUR_MODE; ++ rk818_write(di, RK818_GGCON_REG, ggcon); ++} ++ ++static void rk818_configure_relax_thresholds(struct rk818_battery *di) ++{ ++ int enter_raw, exit_raw; ++ ++ enter_raw = (int)di->relax_entry_current_ma * 1000 / 1506 / ++ DIV(di->res_div); ++ exit_raw = (int)di->relax_exit_current_ma * 1000 / 1506 / ++ DIV(di->res_div); ++ ++ rk818_write(di, RK818_RELAX_ENTRY_THRES_REGL, enter_raw & 0xff); ++ rk818_write(di, RK818_RELAX_ENTRY_THRES_REGH, (enter_raw >> 8) & 0xff); ++ rk818_write(di, RK818_RELAX_EXIT_THRES_REGL, exit_raw & 0xff); ++ rk818_write(di, RK818_RELAX_EXIT_THRES_REGH, (exit_raw >> 8) & 0xff); ++ ++ rk818_restart_relax(di); ++} ++ ++/* ++ * Set the VBAT low-voltage monitor to 3.4 V in IRQ (not hard-shutdown) mode ++ * so the system receives a wakeup event when the battery is nearly empty. ++ * Unmask the corresponding interrupt so it is actually delivered. ++ */ ++static void rk818_set_low_voltage_irq(struct rk818_battery *di) ++{ ++ u8 val = rk818_read(di, RK818_VB_MON_REG); ++ ++ val = (val & ~(VBAT_LOW_VOL_MASK | VBAT_LOW_ACT_MASK)) | ++ RK818_VBAT_LOW_3V4 | EN_VBAT_LOW_IRQ; ++ rk818_write(di, RK818_VB_MON_REG, val); ++ /* Clear the mask bit to enable the interrupt */ ++ rk818_clrsetbits(di, RK818_INT_STS_MSK_REG1, VB_LOW_INT_EN, 0); ++} ++ ++/* ++ * Encode a Celsius temperature into the HOTDIE threshold register bits, ++ * rounding down to the nearest supported table entry (85/95/105/115 C). ++ */ ++static u8 rk818_encode_hotdie_temp(u32 celsius) ++{ ++ if (celsius >= 115) ++ return HOTDIE_TEMP_115C; ++ if (celsius >= 105) ++ return HOTDIE_TEMP_105C; ++ if (celsius >= 95) ++ return HOTDIE_TEMP_95C; ++ ++ return HOTDIE_TEMP_85C; ++} ++ ++/* ++ * Encode a termination-current value (microamps) into FINISH_CUR_MSK bits. ++ * Rounds down to the nearest supported step (100/150/200/250 mA). ++ */ ++static u8 rk818_encode_finish_current(int term_ua) ++{ ++ int term_ma = term_ua / 1000; ++ ++ if (term_ma >= 250) ++ return FINISH_250MA; ++ if (term_ma >= 200) ++ return FINISH_200MA; ++ if (term_ma >= 150) ++ return FINISH_150MA; ++ return FINISH_100MA; ++} ++ ++/* ++ * Encode a CC/CV safety-timer duration (hours) into CHRG_TIMER_CCCV bits. ++ * Rounds down to the nearest supported step (4/5/6/8/10/12/14/16 h). ++ */ ++static u8 rk818_encode_cccv_timeout(u32 hours) ++{ ++ if (hours >= 16) ++ return CHRG_TIMER_CCCV_16H; ++ if (hours >= 14) ++ return CHRG_TIMER_CCCV_14H; ++ if (hours >= 12) ++ return CHRG_TIMER_CCCV_12H; ++ if (hours >= 10) ++ return CHRG_TIMER_CCCV_10H; ++ if (hours >= 8) ++ return CHRG_TIMER_CCCV_8H; ++ if (hours >= 6) ++ return CHRG_TIMER_CCCV_6H; ++ if (hours >= 5) ++ return CHRG_TIMER_CCCV_5H; ++ return CHRG_TIMER_CCCV_4H; ++} ++ ++/* ++ * Configure charge termination current and thermal feedback register. ++ * Termination current, constant-charge voltage, and constant-charge ++ * current are taken from the simple-battery info where available and ++ * fall back to safe defaults otherwise. ++ */ ++static void rk818_configure_charger(struct rk818_battery *di) ++{ ++ u8 finish_ma, usb_ctrl, chrg2, chrg3, thermal; ++ int term_ua; ++ ++ /* ++ * Apply max CC current and max CV voltage from the simple-battery ++ * info. The register set helpers clamp to supported hardware steps. ++ */ ++ if (di->info->constant_charge_current_max_ua > 0) ++ rk818_charger_set_current_max(di, ++ di->info->constant_charge_current_max_ua); ++ if (di->info->constant_charge_voltage_max_uv > 0) ++ rk818_charger_set_voltage_max(di, ++ di->info->constant_charge_voltage_max_uv); ++ ++ /* ++ * Termination current: prefer charge_term_current_ua from the DT; ++ * fall back to ~C/30 of FCC scaled by sense resistor, then encode ++ * to the nearest supported FINISH_*MA step. ++ */ ++ term_ua = di->info->charge_term_current_ua; ++ if (term_ua <= 0) { ++ if (di->sense_resist_mohm == 10) ++ term_ua = 100000; ++ else if (di->fcc_mah >= 5000) ++ term_ua = 250000; ++ else if (di->fcc_mah >= 4000) ++ term_ua = 200000; ++ else if (di->fcc_mah >= 3000) ++ term_ua = 150000; ++ else ++ term_ua = 100000; ++ } ++ finish_ma = rk818_encode_finish_current(term_ua); ++ ++ usb_ctrl = rk818_read(di, RK818_USB_CTRL_REG); ++ chrg2 = rk818_read(di, RK818_CHRG_CTRL_REG2); ++ chrg3 = rk818_read(di, RK818_CHRG_CTRL_REG3); ++ thermal = rk818_read(di, RK818_THERMAL_REG); ++ ++ /* Use digital charge-termination signal */ ++ chrg3 |= CHRG_TERM_DIG_SIGNAL; ++ ++ /* ++ * CC/CV safety timer: enable when a non-zero timeout is set in DT, ++ * otherwise leave disabled. The hardware timer guards against a ++ * stuck charger that would otherwise keep pushing CC indefinitely ++ * on a broken cell. ++ */ ++ if (di->cccv_timeout_h) { ++ chrg2 = (chrg2 & ~CHRG_TIMER_CCCV_MSK) | ++ rk818_encode_cccv_timeout(di->cccv_timeout_h); ++ chrg3 |= CHRG_TIMER_CCCV_EN; ++ } else { ++ chrg3 &= ~CHRG_TIMER_CCCV_EN; ++ } ++ ++ chrg2 = (chrg2 & ~FINISH_CUR_MSK) | finish_ma; ++ ++ if (di->feedback_temp) { ++ usb_ctrl |= CHRG_CT_EN; ++ thermal = (thermal & ~HOTDIE_TEMP_MASK) | ++ rk818_encode_hotdie_temp(di->feedback_temp); ++ } else { ++ usb_ctrl &= ~CHRG_CT_EN; ++ } ++ ++ rk818_write(di, RK818_USB_CTRL_REG, usb_ctrl); ++ rk818_write(di, RK818_CHRG_CTRL_REG2, chrg2); ++ rk818_write(di, RK818_CHRG_CTRL_REG3, chrg3); ++ rk818_write(di, RK818_THERMAL_REG, thermal); ++} ++ ++/* ------------------------------------------------------------------------- ++ * Startup SoC initialisation ++ * ------------------------------------------------------------------------- */ ++ ++static bool rk818_is_first_power_on(struct rk818_battery *di) ++{ ++ u8 val = rk818_read(di, RK818_GGSTS_REG); ++ ++ if (val & BAT_CON) { ++ rk818_write(di, RK818_GGSTS_REG, val & ~BAT_CON); ++ return true; ++ } ++ return false; ++} ++ ++static bool rk818_was_warm_initialized(struct rk818_battery *di) ++{ ++ u8 val = rk818_read(di, RK818_MISC_MARK_REG); ++ ++ if (val & FG_INIT) { ++ rk818_write(di, RK818_MISC_MARK_REG, val & ~FG_INIT); ++ return true; ++ } ++ return false; ++} ++ ++/* ++ * rk818_init_soc - choose the correct starting dsoc / remain_cap on boot. ++ * ++ * Decision priority: ++ * 1. First ever power-on: use OCV-derived SoC (battery was just connected). ++ * 2. Warm reboot (FG_INIT flag set): the coulomb counter is still live; ++ * trust it and the saved dsoc directly. ++ * 3. Cold boot after >= 30 min off: OCV has settled; re-anchor from OCV. ++ * 4. Short cold boot: start from saved dsoc, but jump to OCV if the ++ * discrepancy exceeds max_soc_offset_pct. ++ */ ++static void rk818_init_soc(struct rk818_battery *di) ++{ ++ int ocv_vol, ocv_soc, ocv_cap; ++ int saved_dsoc, saved_cap; ++ u8 cur, last; ++ ++ di->fcc_mah = rk818_read_fcc(di); ++ di->is_first_power_on = rk818_is_first_power_on(di); ++ di->is_initialized = rk818_was_warm_initialized(di); ++ ++ cur = rk818_read(di, RK818_NON_ACT_TIMER_CNT_REG); ++ last = rk818_read(di, RK818_NON_ACT_TIMER_CNT_SAVE_REG); ++ rk818_write(di, RK818_NON_ACT_TIMER_CNT_SAVE_REG, cur); ++ di->pwroff_min = (cur != last) ? cur : 0; ++ ++ ocv_vol = rk818_read_vol(di, RK818_BAT_OCV_REGH); ++ ocv_soc = vol_to_soc(di, ocv_vol); ++ ocv_cap = vol_to_cap(di, ocv_vol); ++ ++ if (di->is_first_power_on) { ++ di->dsoc = ocv_soc; ++ di->remain_cap_mah = ocv_cap; ++ rk818_save_fcc(di, (u32)di->fcc_mah); ++ dev_info(di->dev, ++ "first power-on: dsoc=%d cap=%d mAh ocv=%d mV\n", ++ di->dsoc, di->remain_cap_mah, ocv_vol); ++ goto done; ++ } ++ ++ saved_dsoc = rk818_read(di, RK818_SOC_REG); ++ saved_cap = rk818_read_saved_cap(di); ++ ++ if (di->is_initialized) { ++ di->dsoc = saved_dsoc; ++ di->remain_cap_mah = rk818_get_coulomb_cap(di); ++ dev_info(di->dev, "warm boot: dsoc=%d cap=%d mAh\n", ++ di->dsoc, di->remain_cap_mah); ++ goto done; ++ } ++ ++ if (di->pwroff_min >= 30) { ++ di->dsoc = ocv_soc; ++ di->remain_cap_mah = ocv_cap; ++ dev_info(di->dev, ++ "OCV re-anchor after %u min off: dsoc %d -> %d, cap=%d mAh\n", ++ di->pwroff_min, saved_dsoc, ++ di->dsoc, di->remain_cap_mah); ++ goto done; ++ } ++ ++ di->dsoc = saved_dsoc; ++ di->remain_cap_mah = max(0, saved_cap); ++ ++ if (abs(ocv_soc - saved_dsoc) >= (int)di->max_soc_offset_pct) { ++ dev_info(di->dev, ++ "OCV offset too large (saved=%d ocv=%d), jumping\n", ++ saved_dsoc, ocv_soc); ++ di->dsoc = ocv_soc; ++ di->remain_cap_mah = ocv_cap; ++ } ++ ++done: ++ di->dsoc = clamp(di->dsoc, 0, 100); ++ di->remain_cap_mah = max(0, di->remain_cap_mah); ++ ++ rk818_set_coulomb_cap(di, di->remain_cap_mah); ++ di->rsoc = di->dsoc; ++ ++ dev_info(di->dev, ++ "init done: dsoc=%d rsoc=%d cap=%d mAh fcc=%d mAh\n", ++ di->dsoc, di->rsoc, di->remain_cap_mah, di->fcc_mah); ++} ++ ++/* ------------------------------------------------------------------------- ++ * Periodic calibration ++ * ++ * Refreshes the voltage k/b coefficients and re-applies the current offset ++ * every CALIB_INTERVAL_MIN minutes so long-running drift is corrected ++ * without a reboot. Driven from the main monitor work via ++ * ktime_get_boottime() so suspend time is accounted for automatically. ++ * ------------------------------------------------------------------------- */ ++ ++#define CALIB_INTERVAL_MIN 8 ++ ++static void rk818_periodic_calib(struct rk818_battery *di) ++{ ++ int poffset, ioffset; ++ ++ poffset = rk818_read(di, RK818_POFFSET_REG); ++ di->poffset = poffset ? poffset : POFFSET_DEFAULT; ++ ioffset = rk818_get_ioffset(di); ++ rk818_set_coffset(di, ioffset + di->poffset); ++ rk818_init_voltage_kb(di); ++ ++ dev_dbg(di->dev, "periodic calib: coffset=0x%x poffset=%d\n", ++ rk818_get_coffset(di), di->poffset); ++} ++ ++/* ------------------------------------------------------------------------- ++ * Main monitor work ++ * ------------------------------------------------------------------------- */ ++ ++/* ++ * rk818_update_soc - recompute rsoc from the coulomb counter and step dsoc ++ * toward it by at most DSOC_DELTA_MAX per call. ++ * ++ * Special cases: ++ * - RK818_CHG_STS_TERMINATED: snap remain_cap to fcc so rsoc hits 100 cleanly. ++ * - Valid relaxed voltage: re-anchor the coulomb counter to the OCV cap. ++ * - Voltage below shutdown threshold: force dsoc to 0. ++ */ ++static void rk818_update_soc(struct rk818_battery *di) ++{ ++ di->remain_cap_mah = rk818_get_coulomb_cap(di); ++ ++ if (di->chrg_status == RK818_CHG_STS_TERMINATED && ++ di->remain_cap_mah != di->fcc_mah) { ++ dev_info(di->dev, "charge finish: cap %d -> %d mAh\n", ++ di->remain_cap_mah, di->fcc_mah); ++ rk818_set_coulomb_cap(di, di->fcc_mah); ++ } ++ ++ di->voltage_relax_mv = rk818_get_relax_voltage(di); ++ if (di->voltage_relax_mv > 0) { ++ int ocv_cap = vol_to_cap(di, di->voltage_relax_mv); ++ int ocv_soc = vol_to_soc(di, di->voltage_relax_mv); ++ ++ dev_dbg(di->dev, ++ "relax OCV re-anchor: vol=%d mV soc=%d%% cap=%d mAh (was %d mAh)\n", ++ di->voltage_relax_mv, ocv_soc, ocv_cap, ++ di->remain_cap_mah); ++ rk818_set_coulomb_cap(di, ocv_cap); ++ rk818_restart_relax(di); ++ } ++ ++ di->remain_cap_mah = rk818_get_coulomb_cap(di); ++ di->rsoc = clamp(di->remain_cap_mah * 100 / DIV(di->fcc_mah), 0, 100); ++ ++ if (di->voltage_avg_mv < di->info->voltage_min_design_uv / 1000) { ++ dev_dbg(di->dev, ++ "voltage %d mV below shutdown threshold %u mV\n", ++ di->voltage_avg_mv, di->info->voltage_min_design_uv / 1000); ++ di->dsoc = 0; ++ return; ++ } ++ ++ di->dsoc = clamp(di->dsoc + ++ clamp(di->rsoc - di->dsoc, ++ -DSOC_DELTA_MAX, DSOC_DELTA_MAX), ++ 0, 100); ++} ++ ++/* ------------------------------------------------------------------------- ++ * NTC battery temperature sensing (TS1) ++ * ------------------------------------------------------------------------- */ ++ ++static void rk818_init_ts1_detect(struct rk818_battery *di) ++{ ++ u32 rmax; ++ u8 buf; ++ ++ if (!di->ntc_size) ++ return; ++ ++ /* ++ * Pick a sample current based on the largest resistance we might ++ * need to measure. Entries are sorted by temperature ascending, ++ * so the coldest entry -- entry 0 -- has the highest resistance. ++ */ ++ rmax = di->ntc_entries[0].res; ++ ++ buf = rk818_read(di, RK818_TS_CTRL_REG); ++ buf &= ~TS1_CUR_MSK; ++ if (rmax < NTC_80UA_MAX_MEASURE) { ++ di->ntc_factor = NTC_CALC_FACTOR_80UA; ++ di->ntc_uA = 80; ++ buf |= ADC_CUR_80UA; ++ } else if (rmax < NTC_60UA_MAX_MEASURE) { ++ di->ntc_factor = NTC_CALC_FACTOR_60UA; ++ di->ntc_uA = 60; ++ buf |= ADC_CUR_60UA; ++ } else if (rmax < NTC_40UA_MAX_MEASURE) { ++ di->ntc_factor = NTC_CALC_FACTOR_40UA; ++ di->ntc_uA = 40; ++ buf |= ADC_CUR_40UA; ++ } else { ++ di->ntc_factor = NTC_CALC_FACTOR_20UA; ++ di->ntc_uA = 20; ++ buf |= ADC_CUR_20UA; ++ } ++ rk818_write(di, RK818_TS_CTRL_REG, buf); ++ ++ /* Enable ADC TS1 channel */ ++ buf = rk818_read(di, RK818_ADC_CTRL_REG); ++ buf |= ADC_TS1_EN; ++ rk818_write(di, RK818_ADC_CTRL_REG, buf); ++} ++ ++/* ++ * Due to a hardware design issue, Vdelta = (R_sample + R_other) * I_avg is ++ * folded into the TS1 ADC value. Subtract it to recover the real reading ++ * by sampling at two different excitation currents and solving for Vdelta: ++ * ++ * adc1 - Vdelta ua1 (adc2 * ua1) - (adc1 * ua2) ++ * ------------- = ----- => Vdelta = ----------------------------- ++ * adc2 - Vdelta ua2 ua1 - ua2 ++ * ++ * Then, depending on current direction: ++ * charging: ADC = adc1 - |Vdelta| ++ * discharging: ADC = adc1 + |Vdelta| ++ */ ++static int rk818_get_ntc_res(struct rk818_battery *di) ++{ ++ int adc1 = 0, adc2 = 0; ++ int ua1, ua2, v_delta, val; ++ u8 buf; ++ ++ /* Read adc1 at the configured sample current */ ++ ua1 = di->ntc_uA; ++ adc1 |= rk818_read(di, RK818_TS1_ADC_REGL) << 0; ++ adc1 |= rk818_read(di, RK818_TS1_ADC_REGH) << 8; ++ ++ /* Switch to a different reference current for adc2 */ ++ ua2 = (ua1 != 20) ? 20 : 40; ++ buf = rk818_read(di, RK818_TS_CTRL_REG); ++ buf &= ~TS1_CUR_MSK; ++ buf |= ((ua2 - 20) / 20); ++ rk818_write(di, RK818_TS_CTRL_REG, buf); ++ ++ /* Allow the new sample current to settle, then read adc2 */ ++ msleep(1000); ++ adc2 |= rk818_read(di, RK818_TS1_ADC_REGL) << 0; ++ adc2 |= rk818_read(di, RK818_TS1_ADC_REGH) << 8; ++ ++ if (adc2 != adc1) ++ v_delta = abs((adc2 * ua1 - adc1 * ua2) / (ua2 - ua1)); ++ else ++ v_delta = 0; ++ ++ val = (di->current_avg_ma >= 0) ? (adc1 - v_delta) : (adc1 + v_delta); ++ ++ /* Restore the original sample current */ ++ rk818_init_ts1_detect(di); ++ ++ return val * di->ntc_factor; ++} ++ ++/* ++ * Binary-search bracket lookup over the NTC table. ++ * ++ * Entries are sorted by temperature ascending, so resistance is strictly ++ * descending. Given a measured resistance "ohm", return indices "low" and ++ * "high" such that: ++ * ++ * entries[low].res >= ohm >= entries[high].res (with low >= high) ++ * ++ * When "ohm" is out of range or an exact match, low == high. The caller ++ * is expected to then interpolate between entries[low] and entries[high]. ++ * ++ * Lifted in spirit from drivers/hwmon/ntc_thermistor.c's lookup_comp(). ++ */ ++static void rk818_ntc_lookup(const struct rk818_battery *di, u32 ohm, ++ unsigned int *low, unsigned int *high) ++{ ++ const struct rk818_ntc_entry *e = di->ntc_entries; ++ unsigned int n = di->ntc_size; ++ unsigned int start, end, mid; ++ ++ /* Clamp: colder than coldest -> first entry */ ++ if (ohm >= e[0].res) { ++ *low = 0; ++ *high = 0; ++ return; ++ } ++ /* Clamp: hotter than hottest -> last entry */ ++ if (ohm <= e[n - 1].res) { ++ *low = n - 1; ++ *high = n - 1; ++ return; ++ } ++ ++ /* ++ * Invariant: e[start].res > ohm >= e[end].res ++ * At entry, start=0 and end=n-1 satisfy it thanks to the clamps. ++ */ ++ start = 0; ++ end = n - 1; ++ while (start < end) { ++ mid = start + (end - start) / 2; ++ ++ if (ohm >= e[mid].res) ++ end = mid; ++ else ++ start = mid + 1; ++ } ++ ++ /* ++ * start == end, and e[end].res <= ohm < e[end - 1].res. ++ * So "low" (higher resistance) is end - 1 and "high" (lower ++ * resistance) is end -- unless we hit an exact match. ++ */ ++ *high = end; ++ if (ohm == e[end].res) ++ *low = end; ++ else ++ *low = end - 1; ++} ++ ++static void rk818_update_temperature(struct rk818_battery *di) ++{ ++ static int old_temp; ++ static bool first_time = true; ++ unsigned int low, high; ++ int res, temp_mc, temp; ++ ++ if (!di->ntc_size) ++ return; ++ ++ res = rk818_get_ntc_res(di); ++ if (res < 0) ++ res = 0; ++ ++ rk818_ntc_lookup(di, (u32)res, &low, &high); ++ ++ /* ++ * Interpolate in milli-degrees for precision, then convert to ++ * tenths (the unit power_supply expects for POWER_SUPPLY_PROP_TEMP). ++ * When low == high (clamp or exact match), fixp_linear_interpolate ++ * returns y0 directly. ++ */ ++ temp_mc = fixp_linear_interpolate(di->ntc_entries[low].res, ++ di->ntc_entries[low].temp * 1000, ++ di->ntc_entries[high].res, ++ di->ntc_entries[high].temp * 1000, ++ res); ++ temp = temp_mc / 100; ++ ++ if (first_time) { ++ old_temp = temp; ++ first_time = false; ++ } ++ ++ /* ++ * Reject single-sample glitches greater than 5 C from the previous ++ * reading; trust everything else. ++ */ ++ if (abs(temp - old_temp) > 50) ++ temp = old_temp; ++ else ++ old_temp = temp; ++ ++ /* ++ * Assign only once per cycle, at the end, with the final value. ++ * Writing a placeholder at the top of the function would be ++ * visible to userspace during the ~1 s window while we wait for ++ * adc2 to settle inside rk818_get_ntc_res(), causing the reported ++ * temperature to flap between the placeholder and the real value ++ * on every monitor poll. ++ */ ++ di->temperature = temp; ++ dev_dbg(di->dev, "temperature = %d\n", di->temperature); ++} ++ ++static void rk818_battery_work(struct work_struct *work) ++{ ++ struct rk818_battery *di = ++ container_of(work, struct rk818_battery, work.work); ++ int prev_dsoc = di->dsoc; ++ bool is_charging; ++ ktime_t now = ktime_get_boottime(); ++ ++ if (!di->last_calib || ++ ktime_after(now, ktime_add_ms(di->last_calib, ++ CALIB_INTERVAL_MIN * 60 * MSEC_PER_SEC))) { ++ rk818_periodic_calib(di); ++ di->last_calib = now; ++ } ++ ++ di->voltage_avg_mv = rk818_read_vol(di, RK818_BAT_VOL_REGH); ++ di->voltage_ocv_mv = rk818_read_vol(di, RK818_BAT_OCV_REGH); ++ di->current_avg_ma = rk818_read_cur(di, RK818_BAT_CUR_AVG_REGH); ++ di->chrg_status = rk818_get_chrg_status(di); ++ rk818_update_temperature(di); ++ ++ /* ++ * Derive is_charging from CHG_STS, not the current sign: during ++ * thermal foldback or at CC->CV transition, the measured current ++ * can dip near zero while the charger is still actively regulating. ++ */ ++ switch (di->chrg_status) { ++ case RK818_CHG_STS_WAKEUP_CUR: ++ case RK818_CHG_STS_TRICKLE_CUR: ++ case RK818_CHG_STS_CC_OR_CV: ++ is_charging = true; ++ break; ++ default: ++ is_charging = false; ++ break; ++ } ++ if (is_charging != di->is_charging) { ++ di->is_charging = is_charging; ++ if (is_charging) { ++ /* ++ * Reset flag so auto-calibration will run again the ++ * next time RK818_CHG_STS_TERMINATED is reached. ++ */ ++ di->coffset_calib_done = false; ++ } ++ } ++ ++ /* Clamp coulomb counter to [0, fcc] */ ++ if (di->remain_cap_mah > di->fcc_mah) { ++ rk818_set_coulomb_cap(di, di->fcc_mah); ++ } else if (di->remain_cap_mah < 0) { ++ /* ++ * Estimate from terminal voltage when the counter underflows. ++ * Subtract the resistive drop to get a rough OCV. ++ */ ++ int est_vol = di->voltage_avg_mv - ++ (di->info->factory_internal_resistance_uohm / 1000) * ++ di->current_avg_ma / 1000; ++ int est_cap = max(0, vol_to_cap(di, est_vol)); ++ ++ dev_info(di->dev, ++ "counter underflow, voltage estimate: %d mAh\n", ++ est_cap); ++ rk818_set_coulomb_cap(di, est_cap); ++ } ++ ++ if (di->chrg_status == RK818_CHG_STS_TERMINATED && rk818_charger_online(di)) ++ rk818_auto_calib_coffset(di); ++ ++ rk818_update_soc(di); ++ ++ rk818_save_dsoc(di); ++ rk818_save_remain_cap(di); ++ ++ if (di->dsoc != prev_dsoc) { ++ if (di->charger_psy) ++ power_supply_changed(di->charger_psy); ++ dev_info(di->dev, ++ "dsoc %d -> %d (rsoc=%d v=%d mV i=%d mA cap=%d mAh fcc=%d mAh)\n", ++ prev_dsoc, di->dsoc, di->rsoc, ++ di->voltage_avg_mv, di->current_avg_ma, ++ di->remain_cap_mah, di->fcc_mah); ++ } ++ ++ dev_dbg(di->dev, ++ "v=%d ocv=%d rv=%d i=%d cap=%d rsoc=%d dsoc=%d chrg=0x%x\n", ++ di->voltage_avg_mv, di->voltage_ocv_mv, di->voltage_relax_mv, ++ di->current_avg_ma, di->remain_cap_mah, ++ di->rsoc, di->dsoc, di->chrg_status); ++ ++ queue_delayed_work(di->wq, &di->work, ++ msecs_to_jiffies(di->monitor_ms)); ++} ++ ++/* ------------------------------------------------------------------------- ++ * Battery fuel-gauge properties (used by the charger psy get_property) ++ * ------------------------------------------------------------------------- */ ++ ++static int rk818_bat_get_property(struct rk818_battery *di, ++ enum power_supply_property psp, ++ union power_supply_propval *val) ++{ ++ switch (psp) { ++ case POWER_SUPPLY_PROP_STATUS: ++ switch (di->chrg_status) { ++ case RK818_CHG_STS_WAKEUP_CUR: ++ case RK818_CHG_STS_TRICKLE_CUR: ++ case RK818_CHG_STS_CC_OR_CV: ++ val->intval = POWER_SUPPLY_STATUS_CHARGING; ++ break; ++ case RK818_CHG_STS_TERMINATED: ++ val->intval = rk818_charger_online(di) ? ++ POWER_SUPPLY_STATUS_FULL : ++ POWER_SUPPLY_STATUS_DISCHARGING; ++ break; ++ case RK818_CHG_STS_USB_OV: ++ case RK818_CHG_STS_BAT_TEMP_FAULT: ++ case RK818_CHG_STS_TIMEOUT: ++ val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; ++ break; ++ default: ++ val->intval = POWER_SUPPLY_STATUS_DISCHARGING; ++ break; ++ } ++ break; ++ case POWER_SUPPLY_PROP_PRESENT: ++ val->intval = rk818_battery_present(di); ++ break; ++ case POWER_SUPPLY_PROP_CAPACITY: ++ val->intval = di->dsoc; ++ break; ++ case POWER_SUPPLY_PROP_VOLTAGE_NOW: ++ val->intval = di->voltage_avg_mv * 1000; /* uV */ ++ break; ++ case POWER_SUPPLY_PROP_VOLTAGE_OCV: ++ val->intval = di->voltage_ocv_mv * 1000; /* uV */ ++ break; ++ case POWER_SUPPLY_PROP_CURRENT_NOW: ++ val->intval = di->current_avg_ma * 1000; /* uA */ ++ break; ++ case POWER_SUPPLY_PROP_CHARGE_FULL: ++ val->intval = di->fcc_mah * 1000; /* uAh */ ++ break; ++ case POWER_SUPPLY_PROP_TEMP: ++ val->intval = di->temperature; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++/* ------------------------------------------------------------------------- ++ * Suspend / resume ++ * ------------------------------------------------------------------------- */ ++ ++static int rk818_battery_suspend(struct platform_device *pdev, ++ pm_message_t state) ++{ ++ struct rk818_battery *di = platform_get_drvdata(pdev); ++ ++ cancel_delayed_work_sync(&di->work); ++ ++ di->sleep_chrg_online = rk818_charger_online(di); ++ di->current_avg_ma = rk818_read_cur(di, RK818_BAT_CUR_AVG_REGH); ++ di->remain_cap_mah = rk818_get_coulomb_cap(di); ++ di->rsoc = di->remain_cap_mah * 100 / DIV(di->fcc_mah); ++ di->suspend_time = ktime_get_boottime(); ++ ++ rk818_save_dsoc(di); ++ rk818_save_remain_cap(di); ++ rk818_set_low_voltage_irq(di); ++ ++ dev_info(di->dev, ++ "suspend: dsoc=%d rsoc=%d i=%d mA v=%d mV cap=%d mAh chrg=%d\n", ++ di->dsoc, di->rsoc, di->current_avg_ma, di->voltage_avg_mv, ++ di->remain_cap_mah, di->sleep_chrg_online); ++ ++ return 0; ++} ++ ++static int rk818_battery_resume(struct platform_device *pdev) ++{ ++ struct rk818_battery *di = platform_get_drvdata(pdev); ++ int sleep_sec, sleep_mah, sleep_soc_drop; ++ ++ di->current_avg_ma = rk818_read_cur(di, RK818_BAT_CUR_AVG_REGH); ++ di->voltage_avg_mv = rk818_read_vol(di, RK818_BAT_VOL_REGH); ++ di->remain_cap_mah = rk818_get_coulomb_cap(di); ++ di->rsoc = di->remain_cap_mah * 100 / DIV(di->fcc_mah); ++ ++ sleep_sec = ktime_ms_delta(ktime_get_boottime(), di->suspend_time) / ++ MSEC_PER_SEC; ++ ++ /* ++ * The coulomb counter runs through suspend, so remain_cap_mah already ++ * accounts for actual consumption. We only apply a conservative ++ * minimum-consumption correction to dsoc so it does not appear to ++ * lag behind reality after a long sleep without a charger attached. ++ * Clamp to rsoc so we never push dsoc below what the counter reports. ++ */ ++ if (!di->sleep_chrg_online && sleep_sec > 0) { ++ sleep_mah = SLP_CURR_MA * sleep_sec / 3600; ++ sleep_soc_drop = sleep_mah * 100 / DIV(di->fcc_mah); ++ di->dsoc = max(di->dsoc - sleep_soc_drop, max(di->rsoc, 0)); ++ ++ dev_info(di->dev, ++ "resume: slept %d s, est. drop %d%%, dsoc=%d rsoc=%d\n", ++ sleep_sec, sleep_soc_drop, di->dsoc, di->rsoc); ++ } ++ ++ rk818_save_dsoc(di); ++ rk818_set_low_voltage_irq(di); ++ ++ dev_info(di->dev, ++ "resume: dsoc=%d rsoc=%d i=%d mA v=%d mV cap=%d mAh\n", ++ di->dsoc, di->rsoc, di->current_avg_ma, ++ di->voltage_avg_mv, di->remain_cap_mah); ++ ++ queue_delayed_work(di->wq, &di->work, msecs_to_jiffies(1000)); ++ ++ return 0; ++} ++ ++/* ------------------------------------------------------------------------- ++ * IRQ ++ * ------------------------------------------------------------------------- */ ++ ++static irqreturn_t rk818_vb_low_irq(int irq, void *data) ++{ ++ struct rk818_battery *di = data; ++ ++ dev_warn(di->dev, "low battery IRQ: v=%d mV dsoc=%d%%\n", ++ di->voltage_avg_mv, di->dsoc); ++ return IRQ_HANDLED; ++} ++ ++/* ========================================================================= ++ * USB supply ++ * ========================================================================= */ ++ ++static int rk818_usb_set_input_current_max(struct rk818_battery *di, int val) ++{ ++ unsigned reg; ++ int ret; ++ ++ if (val < 450000) ++ reg = 1; ++ else if (val < 850000) ++ reg = 0; ++ else if (val < 1000000) ++ reg = 2; ++ else if (val < 3000000) ++ reg = 3 + (val - 1000000) / 250000; ++ else ++ reg = 11; ++ ++ dev_info(di->dev, "applying input current limit %d mA\n", val / 1000); ++ ++ ret = regmap_update_bits(di->regmap, RK818_USB_CTRL_REG, ++ RK818_USB_CTRL_USB_ILIM_MASK, reg); ++ if (ret) ++ dev_err(di->dev, ++ "USB input current limit setting failed (%d)\n", ret); ++ ++ return ret; ++} ++ ++static int rk818_usb_get_input_current_max(struct rk818_battery *di, int *val) ++{ ++ unsigned reg; ++ int ret; ++ ++ ret = regmap_read(di->regmap, RK818_USB_CTRL_REG, ®); ++ if (ret) { ++ dev_err(di->dev, ++ "USB input current limit getting failed (%d)\n", ret); ++ return ret; ++ } ++ ++ reg &= RK818_USB_CTRL_USB_ILIM_MASK; ++ if (reg == 0) ++ *val = 450000; ++ else if (reg == 1) ++ *val = 80000; ++ else if (reg == 2) ++ *val = 850000; ++ else if (reg < 11) ++ *val = 1000000 + (reg - 3) * 250000; ++ else ++ *val = 3000000; ++ ++ return 0; ++} ++ ++static int rk818_usb_set_input_voltage_min(struct rk818_battery *di, int val) ++{ ++ unsigned reg; ++ int ret; ++ ++ if (val < 2780000) ++ reg = 0; ++ else if (val < 3270000) ++ reg = (val - 2780000) / 70000; ++ else ++ reg = 7; ++ ++ ret = regmap_update_bits(di->regmap, RK818_USB_CTRL_REG, ++ RK818_USB_CTRL_USB_CHG_SD_VSEL_MASK, ++ reg << RK818_USB_CTRL_USB_CHG_SD_VSEL_OFFSET); ++ if (ret) ++ dev_err(di->dev, ++ "USB input voltage limit setting failed (%d)\n", ret); ++ ++ return ret; ++} ++ ++static int rk818_usb_get_input_voltage_min(struct rk818_battery *di, int *val) ++{ ++ unsigned reg; ++ int ret; ++ ++ ret = regmap_read(di->regmap, RK818_USB_CTRL_REG, ®); ++ if (ret) { ++ dev_err(di->dev, ++ "USB input voltage limit getting failed (%d)\n", ret); ++ return ret; ++ } ++ ++ reg &= RK818_USB_CTRL_USB_CHG_SD_VSEL_MASK; ++ reg >>= RK818_USB_CTRL_USB_CHG_SD_VSEL_OFFSET; ++ ++ *val = 2780000 + (reg * 70000); ++ ++ return 0; ++} ++ ++static int rk818_usb_power_get_property(struct power_supply *psy, ++ enum power_supply_property psp, ++ union power_supply_propval *val) ++{ ++ struct rk818_battery *di = power_supply_get_drvdata(psy); ++ unsigned reg; ++ int ret; ++ ++ switch (psp) { ++ case POWER_SUPPLY_PROP_PRESENT: ++ ret = regmap_read(di->regmap, RK818_SUP_STS_REG, ®); ++ if (ret) ++ return ret; ++ ++ val->intval = !!(reg & RK818_SUP_STS_USB_EXS); ++ break; ++ ++ case POWER_SUPPLY_PROP_HEALTH: ++ ret = regmap_read(di->regmap, RK818_SUP_STS_REG, ®); ++ if (ret) ++ return ret; ++ ++ if (!(reg & RK818_SUP_STS_USB_EXS)) { ++ val->intval = POWER_SUPPLY_HEALTH_UNKNOWN; ++ } else if (reg & RK818_SUP_STS_USB_EFF) { ++ val->intval = POWER_SUPPLY_HEALTH_GOOD; ++ } else { ++ val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE; ++ } ++ ++ break; ++ ++ case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT: ++ return rk818_usb_get_input_voltage_min(di, &val->intval); ++ ++ case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: ++ return rk818_usb_get_input_current_max(di, &val->intval); ++ ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int rk818_usb_power_set_property(struct power_supply *psy, ++ enum power_supply_property psp, ++ const union power_supply_propval *val) ++{ ++ struct rk818_battery *di = power_supply_get_drvdata(psy); ++ ++ switch (psp) { ++ case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT: ++ return rk818_usb_set_input_voltage_min(di, val->intval); ++ ++ case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: ++ return rk818_usb_set_input_current_max(di, val->intval); ++ ++ default: ++ return -EINVAL; ++ } ++} ++ ++static int rk818_usb_power_prop_writeable(struct power_supply *psy, ++ enum power_supply_property psp) ++{ ++ switch (psp) { ++ case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: ++ case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT: ++ return 1; ++ ++ default: ++ return 0; ++ } ++} ++ ++/* Sync the input-current-limit with our parent supply (if we have one) */ ++static void rk818_usb_power_external_power_changed(struct power_supply *psy) ++{ ++ struct rk818_battery *di = power_supply_get_drvdata(psy); ++ union power_supply_propval val; ++ int ret; ++ ++ ret = power_supply_get_property_from_supplier(di->usb_psy, ++ POWER_SUPPLY_PROP_CURRENT_MAX, ++ &val); ++ if (ret) ++ return; ++ ++ /* ++ * We only want to start applying input current limit after we get first ++ * non-0 value from the supplier. Until then, we keep the limit applied ++ * by the bootloader. If we lower the limit before the charger is properly ++ * detected, we risk boot failure due to insufficient power. ++ */ ++ if (!di->apply_ilim) { ++ if (!val.intval) ++ return; ++ ++ di->apply_ilim = true; ++ } ++ ++ if (val.intval < 500000) ++ val.intval = 500000; ++ ++ rk818_usb_power_set_property(di->usb_psy, ++ POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, ++ &val); ++} ++ ++static enum power_supply_property rk818_usb_power_props[] = { ++ POWER_SUPPLY_PROP_PRESENT, ++ POWER_SUPPLY_PROP_HEALTH, ++ POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, ++ POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT, ++}; ++ ++static const struct power_supply_desc rk818_usb_desc = { ++ .name = "rk818-usb", ++ .type = POWER_SUPPLY_TYPE_USB, ++ .properties = rk818_usb_power_props, ++ .num_properties = ARRAY_SIZE(rk818_usb_power_props), ++ .property_is_writeable = rk818_usb_power_prop_writeable, ++ .get_property = rk818_usb_power_get_property, ++ .set_property = rk818_usb_power_set_property, ++ .external_power_changed = rk818_usb_power_external_power_changed, ++}; ++ ++/* ========================================================================= ++ * Charger / battery supply ++ * ========================================================================= */ ++ ++static int rk818_charger_set_current_max(struct rk818_battery *di, int val) ++{ ++ unsigned reg; ++ int ret; ++ ++ if (val < 1000000) ++ reg = 0; ++ else if (val < 3000000) ++ reg = (val - 1000000) / 200000; ++ else ++ reg = 10; ++ ++ ret = regmap_update_bits(di->regmap, RK818_CHRG_CTRL_REG1, ++ RK818_CHRG_CTRL_REG1_CHRG_CUR_SEL_MASK, ++ reg << RK818_CHRG_CTRL_REG1_CHRG_CUR_SEL_OFFSET); ++ if (ret) ++ dev_err(di->dev, ++ "Charging max current setting failed (%d)\n", ret); ++ ++ return ret; ++} ++ ++static int rk818_charger_get_current_max(struct rk818_battery *di, int *val) ++{ ++ unsigned reg; ++ int ret; ++ ++ ret = regmap_read(di->regmap, RK818_CHRG_CTRL_REG1, ®); ++ if (ret) { ++ dev_err(di->dev, ++ "Charging max current getting failed (%d)\n", ret); ++ return ret; ++ } ++ ++ reg &= RK818_CHRG_CTRL_REG1_CHRG_CUR_SEL_MASK; ++ reg >>= RK818_CHRG_CTRL_REG1_CHRG_CUR_SEL_OFFSET; ++ ++ *val = 1000000 + reg * 200000; ++ ++ return 0; ++} ++ ++static int rk818_charger_set_voltage_max(struct rk818_battery *di, int val) ++{ ++ unsigned reg; ++ int ret; ++ ++ if (val < 4050000) ++ reg = 0; ++ else if (val < 4350000) ++ reg = (val - 4050000) / 50000; ++ else ++ reg = 6; ++ ++ ret = regmap_update_bits(di->regmap, RK818_CHRG_CTRL_REG1, ++ RK818_CHRG_CTRL_REG1_CHRG_VOL_SEL_MASK, ++ reg << RK818_CHRG_CTRL_REG1_CHRG_VOL_SEL_OFFSET); ++ if (ret) ++ dev_err(di->dev, ++ "Charging end voltage setting failed (%d)\n", ret); ++ ++ return ret; ++} ++ ++static int rk818_charger_get_voltage_max(struct rk818_battery *di, int *val) ++{ ++ unsigned reg; ++ int ret; ++ ++ ret = regmap_read(di->regmap, RK818_CHRG_CTRL_REG1, ®); ++ if (ret) { ++ dev_err(di->dev, ++ "Charging end voltage getting failed (%d)\n", ret); ++ return ret; ++ } ++ ++ reg &= RK818_CHRG_CTRL_REG1_CHRG_VOL_SEL_MASK; ++ reg >>= RK818_CHRG_CTRL_REG1_CHRG_VOL_SEL_OFFSET; ++ ++ *val = 4050000 + reg * 50000; ++ ++ return 0; ++} ++ ++static int rk818_charger_get_property(struct power_supply *psy, ++ enum power_supply_property psp, ++ union power_supply_propval *val) ++{ ++ struct rk818_battery *di = power_supply_get_drvdata(psy); ++ unsigned reg; ++ int ret; ++ ++ /* Properties delegated to the fuel-gauge */ ++ switch (psp) { ++ case POWER_SUPPLY_PROP_CURRENT_NOW: ++ case POWER_SUPPLY_PROP_VOLTAGE_NOW: ++ case POWER_SUPPLY_PROP_VOLTAGE_OCV: ++ case POWER_SUPPLY_PROP_PRESENT: ++ case POWER_SUPPLY_PROP_CAPACITY: ++ case POWER_SUPPLY_PROP_TEMP: ++ case POWER_SUPPLY_PROP_STATUS: ++ case POWER_SUPPLY_PROP_CHARGE_FULL: ++ return rk818_bat_get_property(di, psp, val); ++ default: ++ break; ++ } ++ ++ switch (psp) { ++ case POWER_SUPPLY_PROP_ONLINE: ++ ret = regmap_read(di->regmap, RK818_CHRG_CTRL_REG1, ®); ++ if (ret) { ++ dev_err(di->dev, "failed to read the charger state (%d)\n", ret); ++ return ret; ++ } ++ ++ val->intval = !!(reg & RK818_CHRG_CTRL_REG1_CHRG_EN); ++ break; ++ ++ case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR: ++ ret = regmap_read(di->regmap, RK818_CHRG_CTRL_REG1, ®); ++ if (ret) { ++ dev_err(di->dev, "failed to read the charger state (%d)\n", ret); ++ return ret; ++ } ++ ++ if (reg & RK818_CHRG_CTRL_REG1_CHRG_EN) ++ val->intval = POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO; ++ else ++ val->intval = POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE; ++ ++ return 0; ++ ++ case POWER_SUPPLY_PROP_CHARGE_TYPE: ++ ret = regmap_read(di->regmap, RK818_SUP_STS_REG, ®); ++ if (ret) ++ return ret; ++ ++ switch (reg & RK818_CHG_STS_MASK) { ++ case RK818_CHG_STS_WAKEUP_CUR: ++ case RK818_CHG_STS_TRICKLE_CUR: ++ val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE; ++ break; ++ case RK818_CHG_STS_CC_OR_CV: ++ val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST; ++ break; ++ case RK818_CHG_STS_TERMINATED: ++ val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE; ++ break; ++ default: ++ val->intval = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN; ++ break; ++ } ++ ++ break; ++ ++ case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: ++ ret = regmap_read(di->regmap, RK818_CHRG_CTRL_REG2, ®); ++ if (ret) ++ return ret; ++ ++ val->intval = 100000 + ((reg >> 6) & 3) * 50000; ++ break; ++ ++ case POWER_SUPPLY_PROP_HEALTH: ++ ret = regmap_read(di->regmap, RK818_SUP_STS_REG, ®); ++ if (ret) ++ return ret; ++ ++ switch (reg & RK818_CHG_STS_MASK) { ++ case RK818_CHG_STS_USB_OV: ++ val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE; ++ break; ++ case RK818_CHG_STS_BAT_TEMP_FAULT: ++ val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; ++ break; ++ case RK818_CHG_STS_TIMEOUT: ++ val->intval = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE; ++ break; ++ default: ++ val->intval = POWER_SUPPLY_HEALTH_GOOD; ++ break; ++ } ++ ++ break; ++ ++ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: ++ return rk818_charger_get_voltage_max(di, &val->intval); ++ ++ case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: ++ ret = rk818_charger_get_current_max(di, &val->intval); ++ val->intval /= 10; ++ return ret; ++ ++ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: ++ return rk818_charger_get_current_max(di, &val->intval); ++ ++ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: ++ val->intval = di->info->constant_charge_voltage_max_uv; ++ break; ++ ++ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: ++ val->intval = di->info->constant_charge_current_max_ua; ++ break; ++ ++ case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN: ++ val->intval = di->info->energy_full_design_uwh; ++ return 0; ++ ++ case POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN: ++ val->intval = 0; ++ return 0; ++ ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int rk818_charger_set_property(struct power_supply *psy, ++ enum power_supply_property psp, ++ const union power_supply_propval *val) ++{ ++ struct rk818_battery *di = power_supply_get_drvdata(psy); ++ ++ switch (psp) { ++ case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR: ++ switch (val->intval) { ++ case POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO: ++ return regmap_update_bits(di->regmap, RK818_CHRG_CTRL_REG1, ++ RK818_CHRG_CTRL_REG1_CHRG_EN, ++ RK818_CHRG_CTRL_REG1_CHRG_EN); ++ case POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE: ++ return regmap_update_bits(di->regmap, RK818_CHRG_CTRL_REG1, ++ RK818_CHRG_CTRL_REG1_CHRG_EN, 0); ++ default: ++ return -EINVAL; ++ } ++ ++ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: ++ return rk818_charger_set_voltage_max(di, val->intval); ++ ++ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: ++ return rk818_charger_set_current_max(di, val->intval); ++ ++ default: ++ return -EINVAL; ++ } ++} ++ ++static int rk818_charger_prop_writeable(struct power_supply *psy, ++ enum power_supply_property psp) ++{ ++ switch (psp) { ++ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: ++ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: ++ case POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR: ++ return 1; ++ ++ default: ++ return 0; ++ } ++} ++ ++static enum power_supply_property rk818_charger_props[] = { ++ POWER_SUPPLY_PROP_ONLINE, ++ POWER_SUPPLY_PROP_HEALTH, ++ POWER_SUPPLY_PROP_STATUS, ++ POWER_SUPPLY_PROP_CHARGE_BEHAVIOUR, ++ POWER_SUPPLY_PROP_CHARGE_TYPE, ++ POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT, ++ POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT, ++ POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, ++ POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, ++ POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX, ++ POWER_SUPPLY_PROP_PRECHARGE_CURRENT, ++ POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, ++ POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN, ++ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, ++ POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, ++ POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, ++ POWER_SUPPLY_PROP_TECHNOLOGY, ++ ++ /* Fuel-gauge properties exposed on the battery supply */ ++ POWER_SUPPLY_PROP_CURRENT_NOW, ++ POWER_SUPPLY_PROP_VOLTAGE_NOW, ++ POWER_SUPPLY_PROP_VOLTAGE_OCV, ++ POWER_SUPPLY_PROP_PRESENT, ++ POWER_SUPPLY_PROP_CAPACITY, ++ POWER_SUPPLY_PROP_TEMP, ++ POWER_SUPPLY_PROP_CHARGE_FULL, ++}; ++ ++static const struct power_supply_desc rk818_charger_desc = { ++ .name = "rk818-battery", ++ .type = POWER_SUPPLY_TYPE_BATTERY, ++ .properties = rk818_charger_props, ++ .num_properties = ARRAY_SIZE(rk818_charger_props), ++ .property_is_writeable = rk818_charger_prop_writeable, ++ .get_property = rk818_charger_get_property, ++ .set_property = rk818_charger_set_property, ++ .charge_behaviours = BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO) | ++ BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE), ++}; ++ ++static int rk818_parse_dt(struct rk818_battery *di) ++{ ++ struct device *dev = di->dev; ++ struct device_node *np = dev->of_node; ++ u32 val; ++ int length; ++ int ret; ++ ++ /* Defaults for optional properties */ ++ di->monitor_sec = 5; ++ di->relax_entry_current_ma = 300; ++ di->relax_exit_current_ma = 300; ++ di->max_soc_offset_pct = 60; ++ di->sense_resist_mohm = 20; ++ di->feedback_temp = 105; /* Celsius */ ++ di->cccv_timeout_h = 12; /* hours */ ++ ++ if (!of_property_read_u32(np, "rockchip,sense-resistor-micro-ohms", ++ &val)) ++ di->sense_resist_mohm = val / 1000; ++ ++ of_property_read_u32(np, "rockchip,monitor-sec", &di->monitor_sec); ++ ++ if (!of_property_read_u32(np, "rockchip,relax-entry-current-microamp", ++ &val)) ++ di->relax_entry_current_ma = val / 1000; ++ if (!of_property_read_u32(np, "rockchip,relax-exit-current-microamp", ++ &val)) ++ di->relax_exit_current_ma = val / 1000; ++ ++ of_property_read_u32(np, "rockchip,max-soc-offset-percent", ++ &di->max_soc_offset_pct); ++ ++ /* ++ * HOTDIE threshold, in Celsius. The register only supports ++ * 85/95/105/115 C; the nearest lower entry is selected at ++ * register-write time. A DT value of 0 disables the feature. ++ */ ++ of_property_read_u32(np, "rockchip,feedback-temp-celsius", ++ &di->feedback_temp); ++ ++ /* ++ * CC/CV safety timer, in hours. The register only supports ++ * 4/5/6/8/10/12/14/16 h; the nearest lower entry is selected at ++ * register-write time. A DT value of 0 disables the timer. ++ */ ++ of_property_read_u32(np, "rockchip,cccv-timeout-hours", ++ &di->cccv_timeout_h); ++ ++ /* ++ * NTC battery thermistor table. ++ * ++ * "rockchip,ntc-table" is a flat array of ++ * pairs. Degrees are signed (negative temperatures allowed), resistances ++ * are ohms. Entries must be sorted by temperature ascending, which for ++ * an NTC means resistance is strictly descending. The table may be ++ * sparse (any step, not necessarily 1 C) -- lookup interpolates. ++ * ++ * Example: ++ * rockchip,ntc-table = < ++ * (-20) 26458836 ++ * (-15) 20048010 ++ * ( -6) 12489321 ++ * ... ++ * >; ++ */ ++ if (of_find_property(np, "rockchip,ntc-table", &length)) { ++ unsigned int cells = length / sizeof(u32); ++ unsigned int i; ++ size_t size; ++ ++ if (cells < 4 || (cells & 1)) { ++ dev_err(di->dev, ++ "rockchip,ntc-table must be an array of >=2 pairs\n"); ++ return -EINVAL; ++ } ++ ++ di->ntc_size = cells / 2; ++ size = sizeof(*di->ntc_entries) * di->ntc_size; ++ di->ntc_entries = devm_kzalloc(di->dev, size, GFP_KERNEL); ++ if (!di->ntc_entries) ++ return -ENOMEM; ++ ++ for (i = 0; i < di->ntc_size; i++) { ++ struct rk818_ntc_entry *e = &di->ntc_entries[i]; ++ u32 temp_cell; ++ ++ /* ++ * of_property_read_s32_index does not exist -- read as ++ * u32 and reinterpret. DT cells are 32-bit two's ++ * complement, so a negative value like -20 arrives as ++ * 0xffffffec and the (s32) cast recovers -20. ++ */ ++ ret = of_property_read_u32_index(np, "rockchip,ntc-table", ++ 2 * i, &temp_cell); ++ if (ret) ++ return ret; ++ e->temp = (s32)temp_cell; ++ ++ ret = of_property_read_u32_index(np, "rockchip,ntc-table", ++ 2 * i + 1, &e->res); ++ if (ret) ++ return ret; ++ ++ if (i > 0) { ++ const struct rk818_ntc_entry *p = &di->ntc_entries[i - 1]; ++ ++ if (e->temp <= p->temp) { ++ dev_err(di->dev, ++ "rockchip,ntc-table: temps must be strictly ascending (entry %u: %d <= %d)\n", ++ i, e->temp, p->temp); ++ return -EINVAL; ++ } ++ if (e->res >= p->res) { ++ dev_err(di->dev, ++ "rockchip,ntc-table: resistances must be strictly descending (entry %u: %u >= %u)\n", ++ i, e->res, p->res); ++ return -EINVAL; ++ } ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++/* ------------------------------------------------------------------------- ++ * Probe / shutdown ++ * ------------------------------------------------------------------------- */ ++ ++static int rk818_battery_probe(struct platform_device *pdev) ++{ ++ struct rk808 *rk818 = dev_get_drvdata(pdev->dev.parent); ++ struct power_supply_config psy_cfg = { }; ++ struct device *dev = &pdev->dev; ++ struct rk818_battery *di; ++ int ret, vb_lo_irq; ++ ++ di = devm_kzalloc(dev, sizeof(*di), GFP_KERNEL); ++ if (!di) ++ return -ENOMEM; ++ ++ di->rk818 = rk818; ++ di->pdev = pdev; ++ di->dev = dev; ++ di->regmap = rk818->regmap; ++ platform_set_drvdata(pdev, di); ++ ++ ret = rk818_parse_dt(di); ++ if (ret) ++ return ret; ++ ++ if (!rk818_battery_present(di)) ++ return dev_err_probe(di->dev, -ENODEV, ++ "no battery detected\n"); ++ ++ di->res_div = (di->sense_resist_mohm == 20) ? 1 : 2; ++ di->monitor_ms = di->monitor_sec * 1000; ++ if (!di->monitor_ms) ++ di->monitor_ms = MONITOR_MS_DEFAULT; ++ ++ /* ++ * Plausible placeholder (20.0 C) until the first monitor cycle ++ * runs rk818_update_temperature(). Without this, userspace could ++ * briefly observe 0.0 C between power-supply registration and the ++ * first poll. ++ */ ++ di->temperature = 200; ++ ++ di->boot_base_jiffies = jiffies; ++ ++ /* ++ * Register power supplies first: the power-supply core will ++ * parse the "monitored-battery" phandle on our fwnode and ++ * populate psy->battery_info with the standard simple-battery ++ * properties. The gauge init sequence below depends on those ++ * values (design capacity, OCV table, internal resistance, ++ * shutdown voltage), so it must run afterwards. ++ */ ++ psy_cfg.drv_data = di; ++ psy_cfg.fwnode = dev_fwnode(dev); ++ ++ di->usb_psy = devm_power_supply_register(dev, &rk818_usb_desc, ++ &psy_cfg); ++ if (IS_ERR(di->usb_psy)) ++ return dev_err_probe(dev, PTR_ERR(di->usb_psy), ++ "register usb power supply fail\n"); ++ ++ di->charger_psy = devm_power_supply_register(dev, &rk818_charger_desc, ++ &psy_cfg); ++ if (IS_ERR(di->charger_psy)) ++ return dev_err_probe(dev, PTR_ERR(di->charger_psy), ++ "register charger power supply fail\n"); ++ ++ di->info = di->charger_psy->battery_info; ++ if (!di->info) ++ return dev_err_probe(dev, -ENODEV, ++ "monitored-battery info not available\n"); ++ ++ rk818_enable_gauge(di); ++ rk818_init_voltage_kb(di); ++ rk818_init_coffset(di); ++ rk818_configure_sampling(di); ++ rk818_configure_relax_thresholds(di); ++ rk818_init_soc(di); ++ rk818_configure_charger(di); ++ rk818_init_ts1_detect(di); ++ rk818_set_low_voltage_irq(di); ++ ++ /* disable voltage limit and enable input current limit */ ++ ret = regmap_update_bits(di->regmap, RK818_SUP_STS_REG, ++ RK818_SUP_STS_USB_ILIM_EN | RK818_SUP_STS_USB_VLIM_EN, ++ RK818_SUP_STS_USB_ILIM_EN); ++ if (ret) ++ dev_warn(di->dev, "failed to enable input current limit (%d)\n", ret); ++ ++ /* make sure analog control loop is enabled */ ++ ret = regmap_update_bits(di->regmap, RK818_CHRG_CTRL_REG3, ++ RK818_CHRG_CTRL_REG3_CHRG_TERM_DIGITAL, ++ 0); ++ if (ret) ++ dev_warn(di->dev, "failed to enable analog control loop (%d)\n", ret); ++ ++ /* enable charger and set some reasonable limits on each boot */ ++ ret = regmap_write(di->regmap, RK818_CHRG_CTRL_REG1, ++ RK818_CHRG_CTRL_REG1_CHRG_EN ++ | (1) /* 1.2A */ ++ | (5 << 4) /* 4.3V */); ++ if (ret) ++ dev_warn(di->dev, "failed to enable charger (%d)\n", ret); ++ ++ rk818_usb_power_external_power_changed(di->usb_psy); ++ ++ vb_lo_irq = regmap_irq_get_virq(rk818->irq_data, RK818_IRQ_VB_LO); ++ if (vb_lo_irq < 0) ++ return dev_err_probe(di->dev, vb_lo_irq, ++ "cannot get vb_lo virq\n"); ++ ++ ret = devm_request_threaded_irq(di->dev, vb_lo_irq, NULL, ++ rk818_vb_low_irq, ++ IRQF_TRIGGER_HIGH | IRQF_ONESHOT, ++ "rk818_vb_low", di); ++ if (ret) ++ return dev_err_probe(di->dev, ret, ++ "failed to request vb_lo IRQ\n"); ++ ++ enable_irq_wake(vb_lo_irq); ++ ++ di->wq = alloc_ordered_workqueue("rk818-bat", ++ WQ_MEM_RECLAIM | WQ_FREEZABLE); ++ if (!di->wq) ++ return -ENOMEM; ++ ++ INIT_DELAYED_WORK(&di->work, rk818_battery_work); ++ queue_delayed_work(di->wq, &di->work, msecs_to_jiffies(di->monitor_ms)); ++ ++ dev_info(di->dev, "ready: dsoc=%d%% fcc=%d mAh sense=%u mOhm\n", ++ di->dsoc, di->fcc_mah, di->sense_resist_mohm); ++ return 0; ++} ++ ++static void rk818_battery_shutdown(struct platform_device *pdev) ++{ ++ struct rk818_battery *di = platform_get_drvdata(pdev); ++ ++ cancel_delayed_work_sync(&di->work); ++ ++ rk818_save_dsoc(di); ++ rk818_save_remain_cap(di); ++ ++ dev_info(di->dev, ++ "shutdown: dsoc=%d rsoc=%d i=%d mA v=%d mV cap=%d mAh\n", ++ di->dsoc, di->rsoc, di->current_avg_ma, ++ di->voltage_avg_mv, di->remain_cap_mah); ++} ++ ++static const struct of_device_id rk818_battery_of_match[] = { ++ { .compatible = "rockchip,rk818-charger" }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, rk818_battery_of_match); ++ ++static struct platform_driver rk818_battery_driver = { ++ .probe = rk818_battery_probe, ++ .suspend = rk818_battery_suspend, ++ .resume = rk818_battery_resume, ++ .shutdown = rk818_battery_shutdown, ++ .driver = { ++ .name = "rk818-charger", ++ .of_match_table = rk818_battery_of_match, ++ }, ++}; ++module_platform_driver(rk818_battery_driver); ++ ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:rk818-charger"); ++MODULE_AUTHOR("Ondrej Jirman "); ++MODULE_DESCRIPTION("RK818 battery and charger driver"); +diff --git a/include/linux/mfd/rk808.h b/include/linux/mfd/rk808.h +index 5353a470128d..05124cf4a523 100644 +--- a/include/linux/mfd/rk808.h ++++ b/include/linux/mfd/rk808.h +@@ -280,6 +280,8 @@ enum rk818_reg { + RK818_ID_OTG_SWITCH, + }; + ++#define RK818_VB_MON_REG 0x21 ++#define RK818_THERMAL_REG 0x22 + #define RK818_DCDC_EN_REG 0x23 + #define RK818_LDO_EN_REG 0x24 + #define RK818_SLEEP_SET_OFF_REG1 0x25 +@@ -326,13 +328,90 @@ enum rk818_reg { + #define RK818_INT_STS_REG2 0x4e + #define RK818_INT_STS_MSK_REG2 0x4f + #define RK818_IO_POL_REG 0x50 ++#define RK818_OTP_VDD_EN_REG 0x51 + #define RK818_H5V_EN_REG 0x52 + #define RK818_SLEEP_SET_OFF_REG3 0x53 + #define RK818_BOOST_LDO9_ON_VSEL_REG 0x54 + #define RK818_BOOST_LDO9_SLP_VSEL_REG 0x55 + #define RK818_BOOST_CTRL_REG 0x56 +-#define RK818_DCDC_ILMAX 0x90 ++#define RK818_DCDC_ILMAX_REG 0x90 ++#define RK818_CHRG_COMP_REG 0x9a ++#define RK818_SUP_STS_REG 0xa0 + #define RK818_USB_CTRL_REG 0xa1 ++#define RK818_CHRG_CTRL_REG1 0xa3 ++#define RK818_CHRG_CTRL_REG2 0xa4 ++#define RK818_CHRG_CTRL_REG3 0xa5 ++#define RK818_BAT_CTRL_REG 0xa6 ++#define RK818_BAT_HTS_TS1_REG 0xa8 ++#define RK818_BAT_LTS_TS1_REG 0xa9 ++#define RK818_BAT_HTS_TS2_REG 0xaa ++#define RK818_BAT_LTS_TS2_REG 0xab ++#define RK818_TS_CTRL_REG 0xac ++#define RK818_ADC_CTRL_REG 0xad ++#define RK818_ON_SOURCE_REG 0xae ++#define RK818_OFF_SOURCE_REG 0xaf ++#define RK818_GGCON_REG 0xb0 ++#define RK818_GGSTS_REG 0xb1 ++#define RK818_FRAME_SMP_INTERV_REG 0xb2 ++#define RK818_AUTO_SLP_CUR_THR_REG 0xb3 ++#define RK818_GASCNT_CAL_REG3 0xb4 ++#define RK818_GASCNT_CAL_REG2 0xb5 ++#define RK818_GASCNT_CAL_REG1 0xb6 ++#define RK818_GASCNT_CAL_REG0 0xb7 ++#define RK818_GASCNT3_REG 0xb8 ++#define RK818_GASCNT2_REG 0xb9 ++#define RK818_GASCNT1_REG 0xba ++#define RK818_GASCNT0_REG 0xbb ++#define RK818_BAT_CUR_AVG_REGH 0xbc ++#define RK818_BAT_CUR_AVG_REGL 0xbd ++#define RK818_TS1_ADC_REGH 0xbe ++#define RK818_TS1_ADC_REGL 0xbf ++#define RK818_TS2_ADC_REGH 0xc0 ++#define RK818_TS2_ADC_REGL 0xc1 ++#define RK818_BAT_OCV_REGH 0xc2 ++#define RK818_BAT_OCV_REGL 0xc3 ++#define RK818_BAT_VOL_REGH 0xc4 ++#define RK818_BAT_VOL_REGL 0xc5 ++#define RK818_RELAX_ENTRY_THRES_REGH 0xc6 ++#define RK818_RELAX_ENTRY_THRES_REGL 0xc7 ++#define RK818_RELAX_EXIT_THRES_REGH 0xc8 ++#define RK818_RELAX_EXIT_THRES_REGL 0xc9 ++#define RK818_RELAX_VOL1_REGH 0xca ++#define RK818_RELAX_VOL1_REGL 0xcb ++#define RK818_RELAX_VOL2_REGH 0xcc ++#define RK818_RELAX_VOL2_REGL 0xcd ++#define RK818_BAT_CUR_R_CALC_REGH 0xce ++#define RK818_BAT_CUR_R_CALC_REGL 0xcf ++#define RK818_BAT_VOL_R_CALC_REGH 0xd0 ++#define RK818_BAT_VOL_R_CALC_REGL 0xd1 ++#define RK818_CAL_OFFSET_REGH 0xd2 ++#define RK818_CAL_OFFSET_REGL 0xd3 ++#define RK818_NON_ACT_TIMER_CNT_REG 0xd4 ++#define RK818_VCALIB0_REGH 0xd5 ++#define RK818_VCALIB0_REGL 0xd6 ++#define RK818_VCALIB1_REGH 0xd7 ++#define RK818_VCALIB1_REGL 0xd8 ++#define RK818_IOFFSET_REGH 0xdd ++#define RK818_IOFFSET_REGL 0xde ++#define RK818_SOC_REG 0xe0 ++#define RK818_REMAIN_CAP_REG3 0xe1 ++#define RK818_REMAIN_CAP_REG2 0xe2 ++#define RK818_REMAIN_CAP_REG1 0xe3 ++#define RK818_REMAIN_CAP_REG0 0xe4 ++#define RK818_UPDAT_LEVE_REG 0xe5 ++#define RK818_NEW_FCC_REG3 0xe6 ++#define RK818_NEW_FCC_REG2 0xe7 ++#define RK818_NEW_FCC_REG1 0xe8 ++#define RK818_NEW_FCC_REG0 0xe9 ++#define RK818_NON_ACT_TIMER_CNT_SAVE_REG 0xea ++#define RK818_OCV_VOL_VALID_REG 0xeb ++#define RK818_REBOOT_CNT_REG 0xec ++#define RK818_POFFSET_REG 0xed ++#define RK818_MISC_MARK_REG 0xee ++#define RK818_HALT_CNT_REG 0xef ++#define RK818_CALC_REST_REGH 0xf0 ++#define RK818_CALC_REST_REGL 0xf1 ++#define RK818_SAVE_DATA19 0xf2 + + #define RK818_H5V_EN BIT(0) + #define RK818_REF_RDY_CTRL BIT(1) +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0023-power-supply-rk818_battery-Add-code-docs-for-the-HW-.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0023-power-supply-rk818_battery-Add-code-docs-for-the-HW-.patch new file mode 100644 index 000000000..e514ec63f --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0023-power-supply-rk818_battery-Add-code-docs-for-the-HW-.patch @@ -0,0 +1,281 @@ +From 4d1a2cabfffeed3f41c697d6712941adbc74f6b6 Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Sat, 11 Apr 2026 16:38:03 +0200 +Subject: [PATCH 23/84] power: supply: rk818_battery: Add code/docs for the HW + reverse engineering +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-of-by: OndÅ™ej Jirman +--- + drivers/power/supply/rk818_battery.c | 246 +++++++++++++++++++++++++++ + 1 file changed, 246 insertions(+) + +diff --git a/drivers/power/supply/rk818_battery.c b/drivers/power/supply/rk818_battery.c +index 8cac751f8644..a4af2631d3bf 100644 +--- a/drivers/power/supply/rk818_battery.c ++++ b/drivers/power/supply/rk818_battery.c +@@ -2195,6 +2195,247 @@ static int rk818_parse_dt(struct rk818_battery *di) + return 0; + } + ++/* HW assessment code for bringup, remove in the future */ ++ ++static unsigned rk818_v2_read16(struct rk818_battery *di, unsigned regh, ++ unsigned mul, unsigned off) ++{ ++ unsigned val; ++ ++ val = rk818_read(di, regh + 1); ++ val |= rk818_read(di, regh) << 8; ++ ++ return val * mul / 1000 + off; ++} ++ ++static int rk818_v2_read16s(struct rk818_battery *di, unsigned regh, int mul) ++{ ++ int val; ++ ++ val = rk818_read(di, regh + 1); ++ val |= rk818_read(di, regh) << 8; ++ ++ if (val & 0x800) ++ val -= 4096; ++ ++ return val * mul / 1000; ++} ++ ++static void rk818_v2_write16(struct rk818_battery *di, unsigned regh, int val, ++ unsigned mul, unsigned off) ++{ ++ unsigned r = (val - off) * 1000 / mul; ++ ++ rk818_write(di, regh + 1, r & 0xff); ++ rk818_write(di, regh, (r >> 8) & 0xff); ++} ++ ++static int rk818_v2_get_coulomb_cap(struct rk818_battery *di) ++{ ++ int val = 0; ++ ++ val |= rk818_read(di, RK818_GASCNT3_REG) << 24; ++ val |= rk818_read(di, RK818_GASCNT2_REG) << 16; ++ val |= rk818_read(di, RK818_GASCNT1_REG) << 8; ++ val |= rk818_read(di, RK818_GASCNT0_REG); ++ ++ return val; ++} ++ ++static void rk818_v2_set_coulomb_cap(struct rk818_battery *di, u32 capacity) ++{ ++ rk818_write(di, RK818_GASCNT_CAL_REG3, (capacity >> 24) & 0xff); ++ rk818_write(di, RK818_GASCNT_CAL_REG2, (capacity >> 16) & 0xff); ++ rk818_write(di, RK818_GASCNT_CAL_REG1, (capacity >> 8) & 0xff); ++ rk818_write(di, RK818_GASCNT_CAL_REG0, capacity & 0xff); ++} ++ ++ ++/* ++ * ADC Voltage readout calibration ++ * ------------------------------- ++ * ++ * Two values are stored in VCALIB registers: ++ * ++ * vcalib0 = adc register value at 3.0V ++ * vcalib1 = adc register value at 4.2V ++ * ++ * k = (4200 - 3000) * 1000 / (vcalib1 - vcalib0); ++ * b = 4200 - (k * vcalib1) / 1000; ++ * vol = reg_val * k / 1000 + b ++ * ++ * Max range for ADC seems to be ~4.4V (reg val is approx. 4095) ++ * ++ * ++ * ADC Current sensing calibration ++ * ------------------------------- ++ * ++ * For current sensing, we need to eliminate offset at 0A. PMIC stores the value ++ * read out from ADC when the current should be 0 (eg. when the system is off and ++ * not charging) to IOFFSET register. ++ * ++ * We can use this value to calculate current offset and write it to CAL_OFFSET ++ * register during driver initialization. Valid range is 0x780 - 0x980 ++ * ++ * This is usually not enough, so the driver has to perform its own offset removal, ++ * by waiting for a suitable state of the device (after charging is finished or ++ * when charging is blocked, while the device is connected to external power ++ * source) and then assume there's no current flow to/from the battery and cancel ++ * the offset based on reading out the BAT_CUR_AVG code word and adding it to ++ * CAL_OFFSET, until BAT_CUR_AVG becomes 0 over several iterations. ++ * ++ * General algorithm: ++ * ++ * while (abs(BAT_CUR_AVG) > 2) { ++ * CAL_OFFSET = CAL_OFFSET + BAT_CUR_AVG ++ * wait 2s ++ * } ++ * ++ * // save a difference of CAL_OFFSET from IOFFSET for reuse later ++ * POFFSET = CAL_OFFSET - IOFFSET ++ * ++ * POFFSET is used after re-boot to initialize COFFSET to POFFSET + IOFFSET. ++ * ++ * BAT_CUR_AVG is an averaged ADC reading for current sensing resistor compensated ++ * by subtracting CAL_OFFSET from the actual ADC value. ++ * ++ * BAT_CUR_AVG range is 0-4095, format 12bit 2's complement, representing values ++ * -2048 - 2047. ++ * ++ * Current sensing resistor can be arbitrary value, but two values are supported ++ * by the original driver: ++ * ++ * 20 mOhm - ADC code word needs to be multiplied by 1.506 to get current ++ * 10 mOhm - ADC code word needs to be multiplied by 3.012 to get current (PPP) ++ * ++ * Differential voltage range on sensing resistor is +- 61.65mV ++ * ++ * That means that full range is 2047 * 3.012 = +-6.165 A and LSB is 3mA ++ * ++ * Reasonalbe COFFSET initial value for my PPP is 0x81b (when IOFFSET is 0x804) ++ * ++ * ++ * Relaxed voltage measurement ++ * --------------------------- ++ * ++ * This is a voltage measured on battery after current decreases below ++ * RELAX_ENTRY_THRES or increases above RELAX_EXIT_THRES. ++ * ++ * To measure the voltage, configure the current thresholds and clear ++ * bits 2 and 3 in GGSTS, and wait until they're set again. ++ * ++ * After COFFSET is calibrated, it's possible to detect low current scenario. ++ * After 8 minutes of BAT_CUR_AVG being < RELAX_ENTRY_THRES, BAT_VOL is ++ * written to RELAX_VOL1 and RELAX_VOL1 is written to RELAX_VOL2. This happens ++ * every 8 minutes the condition is satisfied, whithout any need to trigger ++ * this behavior. It's a 2 level queue, where RELAX_VOL1 is last item, and ++ * RELAX_VOL2 is previous one. ++ * ++ * GGSTS.RELAX_VOL1_UPD and GGSTS.RELAX_VOL2_UPD are flags indicating validity ++ * of data in RELAX_VOL# registers. They can be cleared by the driver and are ++ * set by HW when registers are updated. ++ * ++ * GGCON.OCV_SAMPL_INTERV controls the update period? ++ * ++ * ++ * Automatic switch to lower sampling frequency when current is low ++ * ---------------------------------------------------------------- ++ * ++ * This is a "sleep" mode, and supposed to be used in suspend to ram state, when ++ * current is very stable, there doesn't need to be high sampling frequency for ++ * coulomb meter. ++ * ++ * AUTO_SLP_CUR_THR - current threshold for switching to sleep mode ++ * FRAME_SMP_INTERV - sampling interval in sleep mode ++ * AUTO_SLP_EN - enable bit ++ * NON_ACT_TIMER_CNT - sleep off counter? (minutes) ++ * ++ * ++ * Coulomb meter ++ * ------------- ++ * ++ * TS_CTRL.GG_EN - enable coulomb meter (default on) ++ * ADC_CUR_VOL_MODE - bit switching between voltage/0 and current/1 mode ++ * GASCNT_CAL - sets value directly to GASCNT ++ * GASCNT - accumulates values from ADC_RES_MODE every second when in current mode ++ * ++ * ++ * OCV and Rint sensing ++ * -------------------- ++ * ++ * BAT_OCV is also updated at this time. ++ * ++ * ADC_RES_MODE - enable flag ++ * RES_CUR_AVG_SEL - amount of ripple used for Rint sensing ++ * IV_AVG_UPD_STS - flag when sensing was successful, when set? ++ * BAT_VOL_R_CALC - stable voltage for Rint calc ++ * BAT_CUR_R_CALC - stable current for Rint calc ++ * BAT_OCV - voltage? ++ */ ++ ++static void rk818_v2_work(struct work_struct *work) ++{ ++ struct rk818_battery *di = ++ container_of(work, struct rk818_battery, work.work); ++ ++ unsigned vcalib0 = rk818_v2_read16(di, RK818_VCALIB0_REGH, 1000, 0); ++ unsigned vcalib1 = rk818_v2_read16(di, RK818_VCALIB1_REGH, 1000, 0); ++ unsigned ioffset = rk818_v2_read16(di, RK818_IOFFSET_REGH, 1000, 0); ++ ++ unsigned k = (4200 - 3000) * 1000 / (vcalib1 - vcalib0); ++ unsigned b = 4200 - (k * vcalib1) / 1000; ++ int csens = 3012; /* conductance of sensing resistor */ ++ ++ unsigned vol = rk818_v2_read16(di, RK818_BAT_VOL_REGH, k, b); ++ unsigned ocv = rk818_v2_read16(di, RK818_BAT_OCV_REGH, k, b); ++ unsigned rv1 = rk818_v2_read16(di, RK818_RELAX_VOL1_REGH, k, b); ++ unsigned rv2 = rk818_v2_read16(di, RK818_RELAX_VOL2_REGH, k, b); ++ ++ unsigned sts = rk818_read(di, RK818_GGSTS_REG); ++ unsigned rv1s = !!(sts & RELAX_VOL1_UPD); ++ unsigned rv2s = !!(sts & RELAX_VOL2_UPD); ++ unsigned rs = !!(sts & RELAX_VOL_STS); ++ ++ unsigned vol_r = rk818_v2_read16(di, RK818_BAT_VOL_R_CALC_REGH, k, b); ++ int cur_r = rk818_v2_read16s(di, RK818_BAT_CUR_R_CALC_REGH, csens); ++ ++ unsigned caloff = rk818_v2_read16(di, RK818_CAL_OFFSET_REGH, 1000, 0); ++ int cur_raw = rk818_v2_read16s(di, RK818_BAT_CUR_AVG_REGH, 1000); ++ int cur = rk818_v2_read16s(di, RK818_BAT_CUR_AVG_REGH, csens); ++ ++ int cap = rk818_v2_get_coulomb_cap(di); ++ ++ dev_info(di->dev, ++ "v2: cap=%d cur=%d cur_raw=%d caloff=%u ioffset=%u vol=%u rv1=%u(%u) rv2=%u(%u) rs=%u ocv=%u cur_r=%d vol_r=%u\n", ++ cap, cur, cur_raw, caloff, ioffset, vol, rv1, rv1s, rv2, rv2s, ++ rs, ocv, cur_r, vol_r); ++ ++ queue_delayed_work(di->wq, &di->work, msecs_to_jiffies(250)); ++} ++ ++static void rk818_v2_init(struct rk818_battery *di) ++{ ++ int csens = 3012; /* conductance of sensing resistor */ ++ unsigned sts; ++ ++ rk818_v2_set_coulomb_cap(di, 0); ++ ++ /* 100 mA relax thresholds */ ++ rk818_v2_write16(di, RK818_RELAX_ENTRY_THRES_REGH, 100, csens, 0); ++ rk818_v2_write16(di, RK818_RELAX_EXIT_THRES_REGH, 100, csens, 0); ++ ++ sts = rk818_read(di, RK818_GGSTS_REG); ++ rk818_write(di, RK818_GGSTS_REG, sts & ~RELAX_VOL12_UPD_MSK); ++ ++ di->wq = alloc_ordered_workqueue("%s", ++ WQ_MEM_RECLAIM | WQ_FREEZABLE, ++ "rk818-v2-bat-work"); ++ INIT_DELAYED_WORK(&di->work, rk818_v2_work); ++ queue_delayed_work(di->wq, &di->work, msecs_to_jiffies(2000)); ++ ++ dev_info(di->dev, "v2 driver ready\n"); ++} ++ + /* ------------------------------------------------------------------------- + * Probe / shutdown + * ------------------------------------------------------------------------- */ +@@ -2217,6 +2458,11 @@ static int rk818_battery_probe(struct platform_device *pdev) + di->regmap = rk818->regmap; + platform_set_drvdata(pdev, di); + ++ if (device_property_read_bool(dev, "debug")) { ++ rk818_v2_init(di); ++ return 0; ++ } ++ + ret = rk818_parse_dt(di); + if (ret) + return ret; +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0024-Revert-usb-typec-tcpm-unregister-existing-source-cap.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0024-Revert-usb-typec-tcpm-unregister-existing-source-cap.patch new file mode 100644 index 000000000..711a53e0c --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0024-Revert-usb-typec-tcpm-unregister-existing-source-cap.patch @@ -0,0 +1,41 @@ +From 89a656eae098b2a5089daba98f522eb3afadfcc2 Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Tue, 7 May 2024 18:39:12 +0200 +Subject: [PATCH 24/84] Revert "usb: typec: tcpm: unregister existing source + caps before re-registration" + +This reverts commit 230ecdf71a644c9c73e0e6735b33173074ae3f94. + +(cherry picked from commit c64dcf8a8fb966ba3c537fd9722875a6fd1dd9ad) +--- + drivers/usb/typec/tcpm/tcpm.c | 7 +------ + 1 file changed, 1 insertion(+), 6 deletions(-) + +diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c +index 7ef746a90a17..d839c72fa8ee 100644 +--- a/drivers/usb/typec/tcpm/tcpm.c ++++ b/drivers/usb/typec/tcpm/tcpm.c +@@ -3306,7 +3306,7 @@ static int tcpm_register_source_caps(struct tcpm_port *port) + { + struct usb_power_delivery_desc desc = { port->negotiated_rev }; + struct usb_power_delivery_capabilities_desc caps = { }; +- struct usb_power_delivery_capabilities *cap = port->partner_source_caps; ++ struct usb_power_delivery_capabilities *cap; + + if (!port->partner_pd) + port->partner_pd = usb_power_delivery_register(NULL, &desc); +@@ -3316,11 +3316,6 @@ static int tcpm_register_source_caps(struct tcpm_port *port) + memcpy(caps.pdo, port->source_caps, sizeof(u32) * port->nr_source_caps); + caps.role = TYPEC_SOURCE; + +- if (cap) { +- usb_power_delivery_unregister_capabilities(cap); +- port->partner_source_caps = NULL; +- } +- + cap = usb_power_delivery_register_capabilities(port->partner_pd, &caps); + if (IS_ERR(cap)) + return PTR_ERR(cap); +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0025-usb-typec-altmodes-displayport-Respect-DP_CAP_RECEPT.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0025-usb-typec-altmodes-displayport-Respect-DP_CAP_RECEPT.patch new file mode 100644 index 000000000..f93b226f4 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0025-usb-typec-altmodes-displayport-Respect-DP_CAP_RECEPT.patch @@ -0,0 +1,105 @@ +From e2139511dc9de1531aba8bed11bc20c4be3ea80a Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Mon, 5 Sep 2022 00:56:07 +0200 +Subject: [PATCH 25/84] usb: typec: altmodes: displayport: Respect + DP_CAP_RECEPTACLE bit + +DP_CAP_RECEPTACLE swaps the meaning of pin assignments. So eg. +pin assignments for DFP_D plug are stored in DP_CAP_UFP_D_PIN_ASSIGN +bits. Yes, it's slightly confusing. :) + +Make the kernel report lack of match in supported pin configurations +between connected ports, so that the user is not confused why their +USB-C dock doesn't have working Alt-DP mode, in case the dock returns +wrong VDO. + +Signed-off-by: Ondrej Jirman +(cherry picked from commit 24fc74e1651b5ad8c83ac073b4327b09e09ca5a5) +--- + drivers/usb/typec/altmodes/displayport.c | 54 +++++++++++++++++++++--- + 1 file changed, 48 insertions(+), 6 deletions(-) + +diff --git a/drivers/usb/typec/altmodes/displayport.c b/drivers/usb/typec/altmodes/displayport.c +index 263a89c5f324..722030137015 100644 +--- a/drivers/usb/typec/altmodes/displayport.c ++++ b/drivers/usb/typec/altmodes/displayport.c +@@ -128,11 +128,29 @@ static int dp_altmode_configure(struct dp_altmode *dp, u8 con) + /* Account for active cable capabilities */ + if (dp->plug_prime) + pin_assign &= DP_CAP_UFP_D_PIN_ASSIGN(dp->plug_prime->vdo); ++ ++ /* ++ * The Display Port Alt mode standard is not publicly available, ++ * so this is based on guesswork and real VDOs received from ++ * receptacle based and plug based Type-C alt mode supporting ++ * docks to make configuration work in practice: ++ * ++ * Plug (captive cable) based dock: port=c46 alt=c05 ++ * Recpetacle based dock: port=c46 alt=c0045 ++ * ++ pin_assign = DP_CAP_DFP_D_PIN_ASSIGN(dp->port->vdo); ++ pin_assign &= dp->alt->vdo & DP_CAP_RECEPTACLE ? ++ DP_CAP_UFP_D_PIN_ASSIGN(dp->alt->vdo) : ++ DP_CAP_DFP_D_PIN_ASSIGN(dp->alt->vdo); ++ */ + break; + default: + break; + } + ++ dev_info(&dp->alt->dev, "con=%d pin_assign=%x (port=%x alt=%x)\n", ++ (int)con, (unsigned)pin_assign, dp->port->vdo, dp->alt->vdo); ++ + /* Determining the initial pin assignment. */ + if (!DP_CONF_GET_PIN_ASSIGN(dp->data.conf)) { + /* Is USB together with DP preferred */ +@@ -764,16 +782,40 @@ int dp_altmode_probe(struct typec_altmode *alt) + struct typec_altmode *plug = typec_altmode_get_plug(alt, TYPEC_PLUG_SOP_P); + struct fwnode_handle *fwnode; + struct dp_altmode *dp; ++ u32 port_pins, alt_pins; + + /* Port can only be DFP_U. */ +- if (typec_altmode_get_data_role(alt) != TYPEC_HOST) ++ if (typec_altmode_get_data_role(alt) != TYPEC_HOST) { ++ typec_altmode_put_plug(plug); + return -EPROTO; ++ } ++ ++ /* ++ * When port is a receptacle DP_CAP_xFP_D_PIN_ASSIGN macros have the ++ * regular meaning. When the port is a plug, the meaning is swapped. ++ * ++ * Check if we have any matching DFP_D<->UFP_D or UFP_D<->DFP_D pin assignment. ++ */ ++ port_pins = port->vdo & DP_CAP_RECEPTACLE ? ++ DP_CAP_DFP_D_PIN_ASSIGN(port->vdo) | DP_CAP_UFP_D_PIN_ASSIGN(port->vdo) << 8 : ++ DP_CAP_UFP_D_PIN_ASSIGN(port->vdo) | DP_CAP_DFP_D_PIN_ASSIGN(port->vdo) << 8; ++ ++ alt_pins = alt->vdo & DP_CAP_RECEPTACLE ? ++ DP_CAP_UFP_D_PIN_ASSIGN(alt->vdo) | DP_CAP_DFP_D_PIN_ASSIGN(alt->vdo) << 8 : ++ DP_CAP_DFP_D_PIN_ASSIGN(alt->vdo) | DP_CAP_UFP_D_PIN_ASSIGN(alt->vdo) << 8; ++ ++ /* Can't plug plug into a plug */ ++ if (!(port->vdo & DP_CAP_RECEPTACLE) && !(alt->vdo & DP_CAP_RECEPTACLE)) { ++ dev_warn(&alt->dev, "Our Alt-DP VDO 0x%06x and peer port VDO 0x%06x are not compatible (both are reported as plugs!)\n", ++ port->vdo, alt->vdo); ++ typec_altmode_put_plug(plug); ++ return -ENODEV; ++ } + +- /* Make sure we have compatible pin configurations */ +- if (!(DP_CAP_PIN_ASSIGN_DFP_D(port->vdo) & +- DP_CAP_PIN_ASSIGN_UFP_D(alt->vdo)) && +- !(DP_CAP_PIN_ASSIGN_UFP_D(port->vdo) & +- DP_CAP_PIN_ASSIGN_DFP_D(alt->vdo))) { ++ /* Make sure we have compatiple pin configurations */ ++ if (!(port_pins & alt_pins)) { ++ dev_warn(&alt->dev, "Our Alt-DP VDO 0x%06x and peer port VDO 0x%06x are not compatible (no shared pinconf %04x<->%04x (UUDD))\n", ++ port->vdo, alt->vdo, port_pins, alt_pins); + typec_altmode_put_plug(plug); + return -ENODEV; + } +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0026-usb-typec-tcpm-Unregister-altmodes-before-registerin.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0026-usb-typec-tcpm-Unregister-altmodes-before-registerin.patch new file mode 100644 index 000000000..2bd737a7e --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0026-usb-typec-tcpm-Unregister-altmodes-before-registerin.patch @@ -0,0 +1,54 @@ +From 75ba5f3d7e740107b5e471f23e06015c8ae552e3 Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Sun, 14 Aug 2022 16:23:28 +0200 +Subject: [PATCH 26/84] usb: typec: tcpm: Unregister altmodes before + registering new ones + +Just in case there are already altmodes registered. Otherwise the +kernel will fail with: + +[50554.467172] sysfs: cannot create duplicate filename '/bus/typec/devices/port0-partner.0' +[50554.467198] CPU: 2 PID: 897 Comm: 4-0022 Tainted: G C 5.18.15-1-MANJARO-ARM #1 +[50554.467208] Hardware name: Pine64 PinePhonePro (DT) +[50554.467214] Call trace: +[50554.467218] dump_backtrace.part.0+0xcc/0xe0 +[50554.467241] show_stack+0x18/0x6c +[50554.467249] dump_stack_lvl+0x64/0x80 +[50554.467262] dump_stack+0x18/0x34 +[50554.467270] sysfs_warn_dup+0x60/0x7c +[50554.467279] sysfs_do_create_link_sd+0xf0/0x100 +[50554.467286] sysfs_create_link+0x24/0x44 +[50554.467292] bus_add_device+0x64/0x120 +[50554.467304] device_add+0x320/0x890 +[50554.467312] device_register+0x20/0x30 +[50554.467318] typec_register_altmode+0x1e4/0x35c +[50554.467330] typec_partner_register_altmode+0x10/0x20 +[50554.467339] tcpm_pd_rx_handler+0x1804/0x18e0 +[50554.467346] kthread_worker_fn+0xa0/0x180 +[50554.467357] kthread+0x108/0x10c +[50554.467364] ret_from_fork+0x10/0x20 +[50554.467528] typec port0-partner: failed to register alternate mode (-17) + +Signed-off-by: Ondrej Jirman +(cherry picked from commit 30d0f1a4e665f05a1b3a455c84be97ae9011285f) +--- + drivers/usb/typec/tcpm/tcpm.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c +index d839c72fa8ee..d30d7a0a4ac3 100644 +--- a/drivers/usb/typec/tcpm/tcpm.c ++++ b/drivers/usb/typec/tcpm/tcpm.c +@@ -2030,6 +2030,9 @@ static void tcpm_register_partner_altmodes(struct tcpm_port *port) + return; + + for (i = 0; i < modep->altmodes; i++) { ++ typec_unregister_altmode(port->partner_altmode[i]); ++ port->partner_altmode[i] = NULL; ++ + altmode = typec_partner_register_altmode(port->partner, + &modep->altmode_desc[i]); + if (IS_ERR(altmode)) { +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0027-usb-typec-tcpm-Fix-PD-devices-capabilities-registrat.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0027-usb-typec-tcpm-Fix-PD-devices-capabilities-registrat.patch new file mode 100644 index 000000000..95fa5587e --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0027-usb-typec-tcpm-Fix-PD-devices-capabilities-registrat.patch @@ -0,0 +1,97 @@ +From dc4a3a79432f9cadd1e384806150ee0c50caac40 Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Sat, 18 Feb 2023 00:38:44 +0100 +Subject: [PATCH 27/84] usb: typec: tcpm: Fix PD devices/capabilities + registration + +Unregister caps before registering them. Store NULL to the struct +if registration fails, so that next attempt can succeed. + +Fixes "sysfs: cannot create duplicate filename +'/devices/virtual/usb_power_delivery/pd1/source-capabilities'" error. + +Signed-off-by: Ondrej Jirman +(cherry picked from commit 49530effc5b55eaee992aca23ef4302c64543e6d) +--- + drivers/usb/typec/tcpm/tcpm.c | 37 +++++++++++++++++++++++++++-------- + 1 file changed, 29 insertions(+), 8 deletions(-) + +diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c +index d30d7a0a4ac3..3ba7511a2785 100644 +--- a/drivers/usb/typec/tcpm/tcpm.c ++++ b/drivers/usb/typec/tcpm/tcpm.c +@@ -3310,15 +3310,22 @@ static int tcpm_register_source_caps(struct tcpm_port *port) + struct usb_power_delivery_desc desc = { port->negotiated_rev }; + struct usb_power_delivery_capabilities_desc caps = { }; + struct usb_power_delivery_capabilities *cap; ++ struct usb_power_delivery *partner_pd; ++ ++ if (!port->partner_pd) { ++ partner_pd = usb_power_delivery_register(NULL, &desc); ++ if (IS_ERR(partner_pd)) ++ return PTR_ERR(partner_pd); + +- if (!port->partner_pd) +- port->partner_pd = usb_power_delivery_register(NULL, &desc); +- if (IS_ERR(port->partner_pd)) +- return PTR_ERR(port->partner_pd); ++ port->partner_pd = partner_pd; ++ } + + memcpy(caps.pdo, port->source_caps, sizeof(u32) * port->nr_source_caps); + caps.role = TYPEC_SOURCE; + ++ usb_power_delivery_unregister_capabilities(port->partner_source_caps); ++ port->partner_source_caps = NULL; ++ + cap = usb_power_delivery_register_capabilities(port->partner_pd, &caps); + if (IS_ERR(cap)) + return PTR_ERR(cap); +@@ -3333,15 +3340,22 @@ static int tcpm_register_sink_caps(struct tcpm_port *port) + struct usb_power_delivery_desc desc = { port->negotiated_rev }; + struct usb_power_delivery_capabilities_desc caps = { }; + struct usb_power_delivery_capabilities *cap; ++ struct usb_power_delivery *partner_pd; ++ ++ if (!port->partner_pd) { ++ partner_pd = usb_power_delivery_register(NULL, &desc); ++ if (IS_ERR(partner_pd)) ++ return PTR_ERR(partner_pd); + +- if (!port->partner_pd) +- port->partner_pd = usb_power_delivery_register(NULL, &desc); +- if (IS_ERR(port->partner_pd)) +- return PTR_ERR(port->partner_pd); ++ port->partner_pd = partner_pd; ++ } + + memcpy(caps.pdo, port->sink_caps, sizeof(u32) * port->nr_sink_caps); + caps.role = TYPEC_SINK; + ++ usb_power_delivery_unregister_capabilities(port->partner_sink_caps); ++ port->partner_sink_caps = NULL; ++ + cap = usb_power_delivery_register_capabilities(port->partner_pd, &caps); + if (IS_ERR(cap)) + return PTR_ERR(cap); +@@ -7746,10 +7760,17 @@ static int tcpm_port_register_pd(struct tcpm_port *port) + port->pds[i] = usb_power_delivery_register(port->dev, &desc); + if (IS_ERR(port->pds[i])) { + ret = PTR_ERR(port->pds[i]); ++ port->pds[i] = NULL; + goto err_unregister; + } + port->pd_list[i]->pd = port->pds[i]; + ++ usb_power_delivery_unregister_capabilities(port->pd_list[i]->source_cap); ++ port->pd_list[i]->source_cap = NULL; ++ ++ usb_power_delivery_unregister_capabilities(port->pd_list[i]->sink_cap); ++ port->pd_list[i]->sink_cap = NULL; ++ + if (port->pd_list[i]->source_desc.pdo[0]) { + cap = usb_power_delivery_register_capabilities(port->pds[i], + &port->pd_list[i]->source_desc); +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0028-usb-typec-fusb302-Slightly-increase-wait-time-for-BC.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0028-usb-typec-fusb302-Slightly-increase-wait-time-for-BC.patch new file mode 100644 index 000000000..f30f184c3 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0028-usb-typec-fusb302-Slightly-increase-wait-time-for-BC.patch @@ -0,0 +1,35 @@ +From 00a769f5a26e2aad92648a76fbe243224701322f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ond=C5=99ej=20Jirman?= +Date: Sun, 30 Jan 2022 23:46:37 +0100 +Subject: [PATCH 28/84] usb: typec: fusb302: Slightly increase wait time for + BC1.2 result + +This is not strictly necessary, but it should not hurt. Looking at +kernel log timing, the BC1.2 detection completion time and this +timeout are quite tight. This adds some headspace just in case. + +Signed-off-by: Ondrej Jirman +(cherry picked from commit f374eae3ca1bf1b0b2fdced9bb6eb475e92110c0) +--- + drivers/usb/typec/tcpm/fusb302.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c +index 9ab1277b7ed1..7ccdb9df7dde 100644 +--- a/drivers/usb/typec/tcpm/fusb302.c ++++ b/drivers/usb/typec/tcpm/fusb302.c +@@ -448,9 +448,9 @@ static int tcpm_get_current_limit(struct tcpc_dev *dev) + + /* + * USB2 Charger detection may still be in progress when we get here, +- * this can take upto 600ms, wait 800ms max. ++ * this can take upto 600ms, wait 1000ms max. + */ +- timeout = jiffies + msecs_to_jiffies(800); ++ timeout = jiffies + msecs_to_jiffies(1000); + do { + if (extcon_get_state(chip->extcon, EXTCON_CHG_USB_SDP) == 1) + current_limit = 500; +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0029-usb-typec-fusb302-Set-the-current-before-enabling-pu.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0029-usb-typec-fusb302-Set-the-current-before-enabling-pu.patch new file mode 100644 index 000000000..f545450ba --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0029-usb-typec-fusb302-Set-the-current-before-enabling-pu.patch @@ -0,0 +1,52 @@ +From 52f27d4d137c4a1d5743618d8c4e5eb4b9fec2d3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ond=C5=99ej=20Jirman?= +Date: Sun, 7 Nov 2021 19:28:27 +0100 +Subject: [PATCH 29/84] usb: typec: fusb302: Set the current before enabling + pullups + +This seems more reasonable and should avoid short period of incorrect +current setting being applied to CC pin. + +Signed-off-by: Ondrej Jirman +(cherry picked from commit 7c245e878d2f39174a142921dcb14bcd6fd71878) +--- + drivers/usb/typec/tcpm/fusb302.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c +index 7ccdb9df7dde..a0382b550e3f 100644 +--- a/drivers/usb/typec/tcpm/fusb302.c ++++ b/drivers/usb/typec/tcpm/fusb302.c +@@ -638,6 +638,14 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum typec_cc_status cc) + goto done; + } + ++ /* adjust current for SRC */ ++ ret = fusb302_set_src_current(chip, cc_src_current[cc]); ++ if (ret < 0) { ++ fusb302_log(chip, "cannot set src current %s, ret=%d", ++ typec_cc_status_name[cc], ret); ++ goto done; ++ } ++ + ret = fusb302_i2c_mask_write(chip, FUSB_REG_SWITCHES0, + switches0_mask, switches0_data); + if (ret < 0) { +@@ -648,14 +656,6 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum typec_cc_status cc) + chip->cc1 = TYPEC_CC_OPEN; + chip->cc2 = TYPEC_CC_OPEN; + +- /* adjust current for SRC */ +- ret = fusb302_set_src_current(chip, cc_src_current[cc]); +- if (ret < 0) { +- fusb302_log(chip, "cannot set src current %s, ret=%d", +- typec_cc_status_name[cc], ret); +- goto done; +- } +- + /* enable/disable interrupts, BC_LVL for SNK and COMP_CHNG for SRC */ + switch (cc) { + case TYPEC_CC_RP_DEF: +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0030-usb-typec-fusb302-Retry-reading-of-CC-pins-status-if.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0030-usb-typec-fusb302-Retry-reading-of-CC-pins-status-if.patch new file mode 100644 index 000000000..827bc40dd --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0030-usb-typec-fusb302-Retry-reading-of-CC-pins-status-if.patch @@ -0,0 +1,77 @@ +From c4f121b253c37de7cc2aee59bff8dd523dfa562d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ond=C5=99ej=20Jirman?= +Date: Tue, 23 Nov 2021 17:53:27 +0100 +Subject: [PATCH 30/84] usb: typec: fusb302: Retry reading of CC pins status if + activity is detected + +This is just for testing, to see if this ever happens. It should +also help when this happens. + +Signed-off-by: Ondrej Jirman +(cherry picked from commit 48646c9a3afd88fb7cf7f1941bc3666fc23deea6) +--- + drivers/usb/typec/tcpm/fusb302.c | 34 ++++++++++++++++++++++++++++++-- + 1 file changed, 32 insertions(+), 2 deletions(-) + +diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c +index a0382b550e3f..0de0dc561c8f 100644 +--- a/drivers/usb/typec/tcpm/fusb302.c ++++ b/drivers/usb/typec/tcpm/fusb302.c +@@ -1248,6 +1248,36 @@ static int fusb302_handle_togdone_snk(struct fusb302_chip *chip, + return ret; + } + ++static int fusb302_get_status0_stable(struct fusb302_chip *chip, u8 *status0) ++{ ++ int ret, tries = 0; ++ u8 reg; ++ ++try_again: ++ ret = fusb302_i2c_read(chip, FUSB_REG_STATUS0, ®); ++ if (ret < 0) ++ return ret; ++ ++ if (reg & FUSB_REG_STATUS0_ACTIVITY) { ++ fusb302_log(chip, "activity reading CC status"); ++ if (++tries == 5) { ++ fusb302_log(chip, "failed to read stable status0 value"); ++ ++ /* ++ * The best we can do is to return at least something. ++ */ ++ *status0 = reg; ++ return 0; ++ } ++ ++ usleep_range(50, 100); ++ goto try_again; ++ } ++ ++ *status0 = reg; ++ return 0; ++} ++ + /* On error returns < 0, otherwise a typec_cc_status value */ + static int fusb302_get_src_cc_status(struct fusb302_chip *chip, + enum typec_cc_polarity cc_polarity, +@@ -1275,7 +1305,7 @@ static int fusb302_get_src_cc_status(struct fusb302_chip *chip, + return ret; + + usleep_range(50, 100); +- ret = fusb302_i2c_read(chip, FUSB_REG_STATUS0, &status0); ++ ret = fusb302_get_status0_stable(chip, &status0); + if (ret < 0) + return ret; + +@@ -1291,7 +1321,7 @@ static int fusb302_get_src_cc_status(struct fusb302_chip *chip, + return ret; + + usleep_range(50, 100); +- ret = fusb302_i2c_read(chip, FUSB_REG_STATUS0, &status0); ++ ret = fusb302_get_status0_stable(chip, &status0); + if (ret < 0) + return ret; + +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0031-usb-typec-fusb302-Update-VBUS-state-even-if-VBUS-int.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0031-usb-typec-fusb302-Update-VBUS-state-even-if-VBUS-int.patch new file mode 100644 index 000000000..0aff562db --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0031-usb-typec-fusb302-Update-VBUS-state-even-if-VBUS-int.patch @@ -0,0 +1,44 @@ +From 91a432b505c84f9552e2d048b1cc4c863a84497f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ond=C5=99ej=20Jirman?= +Date: Tue, 23 Nov 2021 17:57:06 +0100 +Subject: [PATCH 31/84] usb: typec: fusb302: Update VBUS state even if VBUS + interrupt is not triggered + +This seems to improve robustness. + +Signed-off-by: Ondrej Jirman +(cherry picked from commit 5097f6ffab505803eae7fb02a411f0c0d9be2732) +--- + drivers/usb/typec/tcpm/fusb302.c | 14 ++++++++------ + 1 file changed, 8 insertions(+), 6 deletions(-) + +diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c +index 0de0dc561c8f..20c9790a4fad 100644 +--- a/drivers/usb/typec/tcpm/fusb302.c ++++ b/drivers/usb/typec/tcpm/fusb302.c +@@ -1567,14 +1567,16 @@ static void fusb302_irq_work(struct work_struct *work) + "IRQ: 0x%02x, a: 0x%02x, b: 0x%02x, status0: 0x%02x", + interrupt, interrupta, interruptb, status0); + +- if (interrupt & FUSB_REG_INTERRUPT_VBUSOK) { +- vbus_present = !!(status0 & FUSB_REG_STATUS0_VBUSOK); ++ vbus_present = !!(status0 & FUSB_REG_STATUS0_VBUSOK); ++ if (interrupt & FUSB_REG_INTERRUPT_VBUSOK) + fusb302_log(chip, "IRQ: VBUS_OK, vbus=%s", + str_on_off(vbus_present)); +- if (vbus_present != chip->vbus_present) { +- chip->vbus_present = vbus_present; +- tcpm_vbus_change(chip->tcpm_port); +- } ++ if (vbus_present != chip->vbus_present) { ++ chip->vbus_present = vbus_present; ++ if (!(interrupt & FUSB_REG_INTERRUPT_VBUSOK)) ++ fusb302_log(chip, "IRQ: VBUS changed without interrupt, vbus=%s", ++ str_on_off(vbus_present)); ++ tcpm_vbus_change(chip->tcpm_port); + } + + if ((interrupta & FUSB_REG_INTERRUPTA_TOGDONE) && intr_togdone) { +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0032-usb-typec-fusb302-Add-OF-extcon-support.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0032-usb-typec-fusb302-Add-OF-extcon-support.patch new file mode 100644 index 000000000..e0b5b60d0 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0032-usb-typec-fusb302-Add-OF-extcon-support.patch @@ -0,0 +1,45 @@ +From aec8f45667160d719b2e938ae6f48b641a4a1a6c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ond=C5=99ej=20Jirman?= +Date: Sun, 14 Nov 2021 01:14:25 +0100 +Subject: [PATCH 32/84] usb: typec: fusb302: Add OF extcon support + +Look the extcon provider up by phandle, so a device tree can point at the +USB2 PHY that runs BC1.2 charger detection. Until now it could only be +named through linux,extcon-name, which probe reserves for ACPI platforms, +leaving a DT board on a dedicated charger stuck on whatever the Type-C +resistors advertise. + +Resolve it on first use rather than in probe, because the provider can sit +behind a driver that waits on this one and resolving it during probe would +close that cycle. + +Signed-off-by: Ondrej Jirman +(cherry picked from commit fe3483dca7f8cdc09397019ba583c345177f27c0) +--- + drivers/usb/typec/tcpm/fusb302.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c +index 20c9790a4fad..756582f551be 100644 +--- a/drivers/usb/typec/tcpm/fusb302.c ++++ b/drivers/usb/typec/tcpm/fusb302.c +@@ -443,6 +443,16 @@ static int tcpm_get_current_limit(struct tcpc_dev *dev) + int current_limit = 0; + unsigned long timeout; + ++ /* ++ * To avoid cycles in OF dependencies, we get extcon when necessary ++ * outside of probe function. ++ */ ++ if (of_property_present(chip->dev->of_node, "extcon") && !chip->extcon) { ++ chip->extcon = extcon_get_edev_by_phandle(chip->dev, 0); ++ if (IS_ERR(chip->extcon)) ++ chip->extcon = NULL; ++ } ++ + if (!chip->extcon) + return 0; + +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0033-usb-typec-fusb302-Fix-register-definitions.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0033-usb-typec-fusb302-Fix-register-definitions.patch new file mode 100644 index 000000000..bccca0324 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0033-usb-typec-fusb302-Fix-register-definitions.patch @@ -0,0 +1,50 @@ +From 007feb7fc3b91608df648b7e88a734907213c35a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ond=C5=99ej=20Jirman?= +Date: Sat, 20 Nov 2021 14:33:58 +0100 +Subject: [PATCH 33/84] usb: typec: fusb302: Fix register definitions + +MEASURE_VBUS bit is at position 6. MDAC bits are also wrong. + +Signed-off-by: Ondrej Jirman +(cherry picked from commit 3d44e93f55bb27844753bb8b142d61ff80347f3a) +--- + drivers/usb/typec/tcpm/fusb302_reg.h | 16 +++++++--------- + 1 file changed, 7 insertions(+), 9 deletions(-) + +diff --git a/drivers/usb/typec/tcpm/fusb302_reg.h b/drivers/usb/typec/tcpm/fusb302_reg.h +index edc0e4b0f1e6..f37d226c5027 100644 +--- a/drivers/usb/typec/tcpm/fusb302_reg.h ++++ b/drivers/usb/typec/tcpm/fusb302_reg.h +@@ -27,14 +27,13 @@ + #define FUSB_REG_SWITCHES1_TXCC2_EN BIT(1) + #define FUSB_REG_SWITCHES1_TXCC1_EN BIT(0) + #define FUSB_REG_MEASURE 0x04 +-#define FUSB_REG_MEASURE_MDAC5 BIT(7) +-#define FUSB_REG_MEASURE_MDAC4 BIT(6) +-#define FUSB_REG_MEASURE_MDAC3 BIT(5) +-#define FUSB_REG_MEASURE_MDAC2 BIT(4) +-#define FUSB_REG_MEASURE_MDAC1 BIT(3) +-#define FUSB_REG_MEASURE_MDAC0 BIT(2) +-#define FUSB_REG_MEASURE_VBUS BIT(1) +-#define FUSB_REG_MEASURE_XXXX5 BIT(0) ++#define FUSB_REG_MEASURE_VBUS BIT(6) ++#define FUSB_REG_MEASURE_MDAC5 BIT(5) ++#define FUSB_REG_MEASURE_MDAC4 BIT(4) ++#define FUSB_REG_MEASURE_MDAC3 BIT(3) ++#define FUSB_REG_MEASURE_MDAC2 BIT(2) ++#define FUSB_REG_MEASURE_MDAC1 BIT(1) ++#define FUSB_REG_MEASURE_MDAC0 BIT(0) + #define FUSB_REG_CONTROL0 0x06 + #define FUSB_REG_CONTROL0_TX_FLUSH BIT(6) + #define FUSB_REG_CONTROL0_INT_MASK BIT(5) +@@ -105,7 +104,6 @@ + #define FUSB_REG_STATUS0A_RX_SOFT_RESET BIT(1) + #define FUSB_REG_STATUS0A_RX_HARD_RESET BIT(0) + #define FUSB_REG_STATUS1A 0x3D +-#define FUSB_REG_STATUS1A_TOGSS BIT(3) + #define FUSB_REG_STATUS1A_TOGSS_RUNNING 0x0 + #define FUSB_REG_STATUS1A_TOGSS_SRC1 0x1 + #define FUSB_REG_STATUS1A_TOGSS_SRC2 0x2 +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0034-usb-typec-fusb302-Clear-interrupts-before-we-start-t.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0034-usb-typec-fusb302-Clear-interrupts-before-we-start-t.patch new file mode 100644 index 000000000..da3171f18 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0034-usb-typec-fusb302-Clear-interrupts-before-we-start-t.patch @@ -0,0 +1,42 @@ +From 415988faed2eca45c77ae549d9a5ee67df31bf7c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ond=C5=99ej=20Jirman?= +Date: Sat, 20 Nov 2021 14:35:10 +0100 +Subject: [PATCH 34/84] usb: typec: fusb302: Clear interrupts before we start + toggling + +This is recommended by the datasheet. + +Signed-off-by: Ondrej Jirman +(cherry picked from commit 58df0404dd80e7fff7fe3e7c2e4dc1f61614153c) +--- + drivers/usb/typec/tcpm/fusb302.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c +index 756582f551be..fe5ac6ec954a 100644 +--- a/drivers/usb/typec/tcpm/fusb302.c ++++ b/drivers/usb/typec/tcpm/fusb302.c +@@ -511,6 +511,7 @@ static int fusb302_set_toggling(struct fusb302_chip *chip, + enum toggling_mode mode) + { + int ret = 0; ++ u8 reg; + + /* first disable toggling */ + ret = fusb302_i2c_clear_bits(chip, FUSB_REG_CONTROL2, +@@ -569,6 +570,12 @@ static int fusb302_set_toggling(struct fusb302_chip *chip, + } else { + /* Datasheet says vconn MUST be off when toggling */ + WARN(chip->vconn_on, "Vconn is on during toggle start"); ++ ++ /* clear interrupts */ ++ ret = fusb302_i2c_read(chip, FUSB_REG_INTERRUPT, ®); ++ if (ret < 0) ++ return ret; ++ + /* unmask TOGDONE interrupt */ + ret = fusb302_i2c_clear_bits(chip, FUSB_REG_MASKA, + FUSB_REG_MASKA_TOGDONE); +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0035-usb-typec-fusb302-Turn-off-VBUS-and-VCONN-on-shutdow.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0035-usb-typec-fusb302-Turn-off-VBUS-and-VCONN-on-shutdow.patch new file mode 100644 index 000000000..fcefc872a --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0035-usb-typec-fusb302-Turn-off-VBUS-and-VCONN-on-shutdow.patch @@ -0,0 +1,59 @@ +From 6190b644bd853b35f7908a27e17f30aa7b09a785 Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Tue, 21 Jul 2026 08:45:42 +0200 +Subject: [PATCH 35/84] usb: typec: fusb302: Turn off VBUS and VCONN on + shutdown + +Nothing turns the port off on the way down, so a source keeps VBUS and +VCONN applied across a reboot. The next kernel comes up with the port +already powered, which starts BC1.2 charger detection before any role is +known and leaves the Type-C state machine attaching to a port it never +saw come up. + +Drop both in a shutdown handler so a reboot looks like a cold boot. + +(cherry picked from commit 4109d433711e9873a50152640c5a89cf0c91cbe2) +--- + drivers/usb/typec/tcpm/fusb302.c | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c +index fe5ac6ec954a..ba886c949e47 100644 +--- a/drivers/usb/typec/tcpm/fusb302.c ++++ b/drivers/usb/typec/tcpm/fusb302.c +@@ -1839,6 +1839,24 @@ static int fusb302_probe(struct i2c_client *client) + return ret; + } + ++static void fusb302_shutdown(struct i2c_client *client) ++{ ++ struct fusb302_chip *chip = i2c_get_clientdata(client); ++ ++ /* ++ * Nothing else turns the port off on the way down, so a source ++ * would keep VBUS and VCONN applied across a reboot. The next ++ * kernel then comes up with the port already powered, which ++ * confuses both charger detection and the Type-C state machine. ++ */ ++ disable_irq(chip->gpio_int_n_irq); ++ cancel_work_sync(&chip->irq_work); ++ cancel_delayed_work_sync(&chip->bc_lvl_handler); ++ ++ tcpm_set_vconn(&chip->tcpc_dev, false); ++ tcpm_set_vbus(&chip->tcpc_dev, false, false); ++} ++ + static void fusb302_remove(struct i2c_client *client) + { + struct fusb302_chip *chip = i2c_get_clientdata(client); +@@ -1908,6 +1926,7 @@ static struct i2c_driver fusb302_driver = { + }, + .probe = fusb302_probe, + .remove = fusb302_remove, ++ .shutdown = fusb302_shutdown, + .id_table = fusb302_i2c_device_id, + }; + module_i2c_driver(fusb302_driver); +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0036-phy-rockchip-inno-usb2-Add-support-for-RV1106-RV1103.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0036-phy-rockchip-inno-usb2-Add-support-for-RV1106-RV1103.patch new file mode 100644 index 000000000..cd076d828 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0036-phy-rockchip-inno-usb2-Add-support-for-RV1106-RV1103.patch @@ -0,0 +1,209 @@ +From 8188ebbecf26e4e5666b5e306da6d3b675451a0c Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Fri, 21 Jun 2024 01:42:38 +0200 +Subject: [PATCH 36/84] phy: rockchip-inno-usb2: Add support for RV1106/RV1103 + +Ported from BSP driver. + +Signed-off-by: Ondrej Jirman +(cherry picked from commit 9ce7df89d6d1a4408de349a80e51dceb49d95227) +--- + drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 133 ++++++++++++++++++ + 1 file changed, 133 insertions(+) + +diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +index 8f4c08e599aa..4ef42d9affb3 100644 +--- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c ++++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +@@ -143,6 +143,7 @@ struct rockchip_usb2phy_port_cfg { + struct usb2phy_reg bvalid_det_en; + struct usb2phy_reg bvalid_det_st; + struct usb2phy_reg bvalid_det_clr; ++ struct usb2phy_reg bvalid_grf_sel; + struct usb2phy_reg disfall_en; + struct usb2phy_reg disfall_st; + struct usb2phy_reg disfall_clr; +@@ -248,6 +249,7 @@ struct rockchip_usb2phy { + struct regmap *grf; + struct regmap *usbgrf; + struct clk_bulk_data *clks; ++ void __iomem *phy_base; + struct clk *clk480m; + struct clk_hw clk480m_hw; + int num_clks; +@@ -1284,6 +1286,7 @@ static int rockchip_usb2phy_otg_port_init(struct rockchip_usb2phy *rphy, + struct rockchip_usb2phy_port *rport, + struct device_node *child_np) + { ++ struct regmap *base = get_reg_base(rphy); + int ret, id; + + rport->port_id = USB2PHY_PORT_OTG; +@@ -1317,6 +1320,23 @@ static int rockchip_usb2phy_otg_port_init(struct rockchip_usb2phy *rphy, + goto out; + } + ++ /* ++ * Set the utmi bvalid come from the usb phy or grf. ++ * For most of Rockchip SoCs, them have VBUSDET pin ++ * for the usb phy to detect the USB VBUS and set ++ * the bvalid signal, so select the bvalid from the ++ * usb phy by default. And for those SoCs which don't ++ * have VBUSDET pin (e.g. RV1103), it needs to select ++ * the bvaid from the grf and set bvalid to be valid ++ * (high) by default. ++ */ ++ if (rport->port_cfg->bvalid_grf_sel.enable != 0) { ++ if (of_machine_is_compatible("rockchip,rv1103")) ++ property_enable(base, &rport->port_cfg->bvalid_grf_sel, true); ++ else ++ property_enable(base, &rport->port_cfg->bvalid_grf_sel, false); ++ } ++ + if (!IS_ERR(rphy->edev)) { + rport->event_nb.notifier_call = rockchip_otg_event; + +@@ -1388,6 +1408,13 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev) + } + } + ++ if (of_device_is_compatible(np, "rockchip,rv1106-usb2phy")) { ++ rphy->phy_base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); ++ if (IS_ERR(rphy->phy_base)) ++ return dev_err_probe(dev, PTR_ERR(rphy->phy_base), ++ "missing memory resource\n"); ++ } ++ + rphy->dev = dev; + phy_cfgs = device_get_match_data(dev); + rphy->chg_state = USB_CHG_STATE_UNDEFINED; +@@ -1506,6 +1533,63 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev) + return ret; + } + ++static inline void phy_clear_bits(void __iomem *reg, u32 bits) ++{ ++ u32 tmp = readl(reg); ++ ++ tmp &= ~bits; ++ writel(tmp, reg); ++} ++ ++static inline void phy_set_bits(void __iomem *reg, u32 bits) ++{ ++ u32 tmp = readl(reg); ++ ++ tmp |= bits; ++ writel(tmp, reg); ++} ++ ++static inline void phy_update_bits(void __iomem *reg, u32 mask, u32 val) ++{ ++ u32 tmp = readl(reg); ++ ++ tmp &= ~mask; ++ tmp |= val & mask; ++ writel(tmp, reg); ++} ++ ++static int rv1106_usb2phy_tuning(struct rockchip_usb2phy *rphy) ++{ ++ /* Always enable pre-emphasis in SOF & EOP & chirp & non-chirp state */ ++ phy_update_bits(rphy->phy_base + 0x30, GENMASK(2, 0), 0x07); ++ ++// if (rockchip_get_cpu_version()) { ++// /* Set Tx HS pre_emphasize strength to 3'b001 */ ++// phy_update_bits(rphy->phy_base + 0x40, GENMASK(5, 3), (0x01 << 3)); ++// } else { ++ /* Set Tx HS pre_emphasize strength to 3'b011 */ ++ phy_update_bits(rphy->phy_base + 0x40, GENMASK(5, 3), (0x03 << 3)); ++// } ++ ++ /* Set RX Squelch trigger point configure to 4'b0000(112.5 mV) */ ++ phy_update_bits(rphy->phy_base + 0x64, GENMASK(6, 3), (0x00 << 3)); ++ ++ /* Turn off differential receiver by default to save power */ ++ phy_clear_bits(rphy->phy_base + 0x100, BIT(6)); ++ ++ /* Set 45ohm HS ODT value to 5'b10111 to increase driver strength */ ++ phy_update_bits(rphy->phy_base + 0x11c, GENMASK(4, 0), 0x17); ++ ++ /* Set Tx HS eye height tuning to 3'b011(462 mV)*/ ++ phy_update_bits(rphy->phy_base + 0x124, GENMASK(4, 2), (0x03 << 2)); ++ ++ /* Bypass Squelch detector calibration */ ++ phy_update_bits(rphy->phy_base + 0x1a4, GENMASK(7, 4), (0x01 << 4)); ++ phy_update_bits(rphy->phy_base + 0x1b4, GENMASK(7, 4), (0x01 << 4)); ++ ++ return 0; ++} ++ + static int rk3128_usb2phy_tuning(struct rockchip_usb2phy *rphy) + { + /* Turn off differential receiver in suspend mode */ +@@ -2243,6 +2327,54 @@ static const struct rockchip_usb2phy_cfg rk3588_phy_cfgs[] = { + { /* sentinel */ } + }; + ++static const struct rockchip_usb2phy_cfg rv1106_phy_cfgs[] = { ++ { ++ .reg = 0xff3e0000, ++ .num_ports = 1, ++ .phy_tuning = rv1106_usb2phy_tuning, ++ .clkout_ctl = { 0x0058, 4, 4, 1, 0 }, ++ .port_cfgs = { ++ [USB2PHY_PORT_OTG] = { ++ .phy_sus = { 0x0050, 8, 0, 0, 0x1d1 }, ++ .bvalid_det_en = { 0x0100, 2, 2, 0, 1 }, ++ .bvalid_det_st = { 0x0104, 2, 2, 0, 1 }, ++ .bvalid_det_clr = { 0x0108, 2, 2, 0, 1 }, ++ .bvalid_grf_sel = { 0x0058, 15, 14, 0, 3 }, ++ /* ++ .iddig_output = { 0x0050, 10, 10, 0, 1 }, ++ .iddig_en = { 0x0050, 9, 9, 0, 1 }, ++ */ ++ .idfall_det_en = { 0x0100, 5, 5, 0, 1 }, ++ .idfall_det_st = { 0x0104, 5, 5, 0, 1 }, ++ .idfall_det_clr = { 0x0108, 5, 5, 0, 1 }, ++ .idrise_det_en = { 0x0100, 4, 4, 0, 1 }, ++ .idrise_det_st = { 0x0104, 4, 4, 0, 1 }, ++ .idrise_det_clr = { 0x0108, 4, 4, 0, 1 }, ++ .ls_det_en = { 0x0100, 0, 0, 0, 1 }, ++ .ls_det_st = { 0x0104, 0, 0, 0, 1 }, ++ .ls_det_clr = { 0x0108, 0, 0, 0, 1 }, ++ .utmi_avalid = { 0x0060, 10, 10, 0, 1 }, ++ .utmi_bvalid = { 0x0060, 9, 9, 0, 1 }, ++ //.utmi_iddig = { 0x0060, 6, 6, 0, 1 }, ++ .utmi_ls = { 0x0060, 5, 4, 0, 1 }, ++ }, ++ }, ++ .chg_det = { ++ //.chg_mode = { 0x0050, 8, 0, 0, 0x1d7 }, ++ .cp_det = { 0x0060, 13, 13, 0, 1 }, ++ .dcp_det = { 0x0060, 12, 12, 0, 1 }, ++ .dp_det = { 0x0060, 14, 14, 0, 1 }, ++ .idm_sink_en = { 0x0058, 8, 8, 0, 1 }, ++ .idp_sink_en = { 0x0058, 7, 7, 0, 1 }, ++ .idp_src_en = { 0x0058, 9, 9, 0, 1 }, ++ .rdm_pdwn_en = { 0x0058, 10, 10, 0, 1 }, ++ .vdm_src_en = { 0x0058, 12, 12, 0, 1 }, ++ .vdp_src_en = { 0x0058, 11, 11, 0, 1 }, ++ }, ++ }, ++ { /* sentinel */ } ++}; ++ + static const struct rockchip_usb2phy_cfg rv1108_phy_cfgs[] = { + { + .reg = 0x100, +@@ -2299,6 +2431,7 @@ static const struct of_device_id rockchip_usb2phy_dt_match[] = { + { .compatible = "rockchip,rk3576-usb2phy", .data = &rk3576_phy_cfgs }, + { .compatible = "rockchip,rk3588-usb2phy", .data = &rk3588_phy_cfgs }, + { .compatible = "rockchip,rv1108-usb2phy", .data = &rv1108_phy_cfgs }, ++ { .compatible = "rockchip,rv1106-usb2phy", .data = &rv1106_phy_cfgs }, + {} + }; + MODULE_DEVICE_TABLE(of, rockchip_usb2phy_dt_match); +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0037-phy-rockchip-inno-usb2-Add-support-for-RK3506.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0037-phy-rockchip-inno-usb2-Add-support-for-RK3506.patch new file mode 100644 index 000000000..96a5b6e87 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0037-phy-rockchip-inno-usb2-Add-support-for-RK3506.patch @@ -0,0 +1,156 @@ +From 6b13b8431d4bb87a6186a4855f4855470e0c9191 Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Sun, 6 Apr 2025 02:00:19 +0200 +Subject: [PATCH 37/84] phy: rockchip-inno-usb2: Add support for RK3506 + +Adapted from BSP. + +Signed-off-by: Ondrej Jirman +(cherry picked from commit 370adcd5cf6464363b7ceb30ebd43243b11dded1) +--- + drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 115 ++++++++++++++++++ + 1 file changed, 115 insertions(+) + +diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +index 4ef42d9affb3..ffc0a7112b6e 100644 +--- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c ++++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +@@ -1598,6 +1598,31 @@ static int rk3128_usb2phy_tuning(struct rockchip_usb2phy *rphy) + BIT(2) << BIT_WRITEABLE_SHIFT | 0); + } + ++static int rk3506_usb2phy_tuning(struct rockchip_usb2phy *rphy) ++{ ++ int ret = 0; ++ ++ /* Turn off otg0 port differential receiver in suspend mode */ ++ phy_clear_bits(rphy->phy_base + 0x30, BIT(2)); ++ ++ /* Turn off otg1 port differential receiver in suspend mode */ ++ phy_clear_bits(rphy->phy_base + 0x430, BIT(2)); ++ ++ /* Set otg0 port HS eye height to 425mv(default is 450mv) */ ++ phy_update_bits(rphy->phy_base + 0x30, GENMASK(6, 4), (0x05 << 4)); ++ ++ /* Set otg1 port HS eye height to 425mv(default is 450mv) */ ++ phy_update_bits(rphy->phy_base + 0x430, GENMASK(6, 4), (0x05 << 4)); ++ ++ /* Choose the Tx fs/ls data as linestate from TX driver for otg0 port */ ++ phy_update_bits(rphy->phy_base + 0x94, GENMASK(6, 3), (0x03 << 3)); ++ ++ /* Choose the Tx fs/ls data as linestate from TX driver for otg1 port */ ++ phy_update_bits(rphy->phy_base + 0x494, GENMASK(6, 3), (0x03 << 3)); ++ ++ return ret; ++} ++ + static int rk3576_usb2phy_tuning(struct rockchip_usb2phy *rphy) + { + int ret; +@@ -2059,6 +2084,95 @@ static const struct rockchip_usb2phy_cfg rk3562_phy_cfgs[] = { + { /* sentinel */ } + }; + ++static const struct rockchip_usb2phy_cfg rk3506_phy_cfgs[] = { ++ { ++ .reg = 0xff2b0000, ++ .num_ports = 2, ++ .phy_tuning = rk3506_usb2phy_tuning, ++ //.vbus_detect = rockchip_usb2phy_vbus_det_control, ++ //.clkout_ctl_phy = { 0x041c, 7, 2, 0, 0x27 }, ++ .port_cfgs = { ++ [USB2PHY_PORT_OTG] = { ++ .phy_sus = { 0x0060, 8, 0, 0, 0x1d1 }, ++ .bvalid_det_en = { 0x0150, 2, 2, 0, 1 }, ++ .bvalid_det_st = { 0x0154, 2, 2, 0, 1 }, ++ .bvalid_det_clr = { 0x0158, 2, 2, 0, 1 }, ++ .bvalid_grf_sel = { 0x0060, 14, 14, 0, 1 }, ++ //.bvalid_grf_con = { 0x0060, 15, 14, 1, 3 }, ++ //.iddig_output = { 0x0060, 10, 10, 0, 1 }, ++ //.iddig_en = { 0x0060, 9, 9, 0, 1 }, ++ .idfall_det_en = { 0x0150, 5, 5, 0, 1 }, ++ .idfall_det_st = { 0x0154, 5, 5, 0, 1 }, ++ .idfall_det_clr = { 0x0158, 5, 5, 0, 1 }, ++ .idrise_det_en = { 0x0150, 4, 4, 0, 1 }, ++ .idrise_det_st = { 0x0154, 4, 4, 0, 1 }, ++ .idrise_det_clr = { 0x0158, 4, 4, 0, 1 }, ++ .ls_det_en = { 0x0150, 0, 0, 0, 1 }, ++ .ls_det_st = { 0x0154, 0, 0, 0, 1 }, ++ .ls_det_clr = { 0x0158, 0, 0, 0, 1 }, ++ .disfall_en = { 0x0150, 7, 7, 0, 0 }, ++ .disfall_st = { 0x0154, 7, 7, 0, 1 }, ++ .disfall_clr = { 0x0158, 7, 7, 0, 1 }, ++ .disrise_en = { 0x0150, 6, 6, 0, 0 }, ++ .disrise_st = { 0x0154, 6, 6, 0, 1 }, ++ .disrise_clr = { 0x0158, 6, 6, 0, 1 }, ++ .utmi_avalid = { 0x0118, 1, 1, 0, 1 }, ++ .utmi_bvalid = { 0x0118, 0, 0, 0, 1 }, ++ //.utmi_iddig = { 0x0118, 6, 6, 0, 1 }, ++ .utmi_ls = { 0x0118, 5, 4, 0, 1 }, ++ .utmi_hstdet = { 0x0118, 7, 7, 0, 1 }, ++ //.vbus_det_en = { 0x003c, 15, 15, 1, 0 }, ++ //.port_ls_filter_con = { 0x0160, 19, 0, 0x30100, 0x20 }, ++ }, ++ [USB2PHY_PORT_HOST] = { ++ .phy_sus = { 0x0070, 8, 0, 0, 0x1d1 }, ++ .bvalid_det_en = { 0x0170, 2, 2, 0, 1 }, ++ .bvalid_det_st = { 0x0174, 2, 2, 0, 1 }, ++ .bvalid_det_clr = { 0x0178, 2, 2, 0, 1 }, ++ .bvalid_grf_sel = { 0x0070, 14, 14, 0, 1 }, ++ //.bvalid_grf_con = { 0x0070, 15, 14, 1, 3 }, ++ //.iddig_output = { 0x0070, 10, 10, 0, 1 }, ++ //.iddig_en = { 0x0070, 9, 9, 0, 1 }, ++ .idfall_det_en = { 0x0170, 5, 5, 0, 1 }, ++ .idfall_det_st = { 0x0174, 5, 5, 0, 1 }, ++ .idfall_det_clr = { 0x0178, 5, 5, 0, 1 }, ++ .idrise_det_en = { 0x0170, 4, 4, 0, 1 }, ++ .idrise_det_st = { 0x0174, 4, 4, 0, 1 }, ++ .idrise_det_clr = { 0x0178, 4, 4, 0, 1 }, ++ .ls_det_en = { 0x0170, 0, 0, 0, 1 }, ++ .ls_det_st = { 0x0174, 0, 0, 0, 1 }, ++ .ls_det_clr = { 0x0178, 0, 0, 0, 1 }, ++ .disfall_en = { 0x0170, 7, 7, 0, 0 }, ++ .disfall_st = { 0x0174, 7, 7, 0, 1 }, ++ .disfall_clr = { 0x0178, 7, 7, 0, 1 }, ++ .disrise_en = { 0x0170, 6, 6, 0, 0 }, ++ .disrise_st = { 0x0174, 6, 6, 0, 1 }, ++ .disrise_clr = { 0x0178, 6, 6, 0, 1 }, ++ .utmi_avalid = { 0x0118, 9, 9, 0, 1 }, ++ .utmi_bvalid = { 0x0118, 8, 8, 0, 1 }, ++ //.utmi_iddig = { 0x0118, 14, 14, 0, 1 }, ++ .utmi_ls = { 0x0118, 13, 12, 0, 1 }, ++ .utmi_hstdet = { 0x0118, 15, 15, 0, 1 }, ++ //.vbus_det_en = { 0x043c, 15, 15, 1, 0 }, ++ //.port_ls_filter_con = { 0x0180, 19, 0, 0x30100, 0x20 }, ++ } ++ }, ++ .chg_det = { ++ //.chg_mode = { 0x0060, 8, 0, 0, 0x1d7 }, ++ .cp_det = { 0x0118, 19, 19, 0, 1 }, ++ .dcp_det = { 0x0118, 18, 18, 0, 1 }, ++ .dp_det = { 0x0118, 20, 20, 0, 1 }, ++ .idm_sink_en = { 0x006c, 1, 1, 0, 1 }, ++ .idp_sink_en = { 0x006c, 0, 0, 0, 1 }, ++ .idp_src_en = { 0x006c, 2, 2, 0, 1 }, ++ .rdm_pdwn_en = { 0x006c, 3, 3, 0, 1 }, ++ .vdm_src_en = { 0x006c, 5, 5, 0, 1 }, ++ .vdp_src_en = { 0x006c, 4, 4, 0, 1 }, ++ }, ++ }, ++ { /* sentinel */ } ++}; ++ + static const struct rockchip_usb2phy_cfg rk3568_phy_cfgs[] = { + { + .reg = 0xfe8a0000, +@@ -2426,6 +2540,7 @@ static const struct of_device_id rockchip_usb2phy_dt_match[] = { + { .compatible = "rockchip,rk3328-usb2phy", .data = &rk3328_phy_cfgs }, + { .compatible = "rockchip,rk3366-usb2phy", .data = &rk3366_phy_cfgs }, + { .compatible = "rockchip,rk3399-usb2phy", .data = &rk3399_phy_cfgs }, ++ { .compatible = "rockchip,rk3506-usb2phy", .data = &rk3506_phy_cfgs }, + { .compatible = "rockchip,rk3562-usb2phy", .data = &rk3562_phy_cfgs }, + { .compatible = "rockchip,rk3568-usb2phy", .data = &rk3568_phy_cfgs }, + { .compatible = "rockchip,rk3576-usb2phy", .data = &rk3576_phy_cfgs }, +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0038-phy-rockchip-inno-usb2-Add-PHY-tuning-for-rk3566-rk3.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0038-phy-rockchip-inno-usb2-Add-PHY-tuning-for-rk3566-rk3.patch new file mode 100644 index 000000000..59c0bf5c6 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0038-phy-rockchip-inno-usb2-Add-PHY-tuning-for-rk3566-rk3.patch @@ -0,0 +1,99 @@ +From 60b2f6a212c936c221b23c6051d89c23a8799d01 Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Sun, 19 Jul 2026 16:21:40 +0200 +Subject: [PATCH 38/84] phy: rockchip-inno-usb2: Add PHY tuning for + rk3566/rk3568 + +Add a phy_tuning callback for the rk3566/rk3568 USB2 PHY and map its +analog register block so the tuning can reach it. + +The tuning enables HS transmitter pre-emphasis on the otg and host +ports, raises the otg port HS eye height to 437.5mV and sets the +bvalid/id detection filter times. Without it the otg port's HS +transmitter runs at reset defaults that are out of spec, so while host +mode works, peripheral mode fails to enumerate on the connected host. +This is visible on the PineTab2 v2.0 bottom USB-C port. + +Signed-off-by: Ondrej Jirman +(cherry picked from commit 47213f62f6eda5aca1f18251f9d4e3edd2f2712a) +--- + drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 35 ++++++++++++++++++- + 1 file changed, 34 insertions(+), 1 deletion(-) + +diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +index ffc0a7112b6e..d9d14cc8cf79 100644 +--- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c ++++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +@@ -31,6 +31,9 @@ + #define SCHEDULE_DELAY (60 * HZ) + #define OTG_SCHEDULE_DELAY (2 * HZ) + ++/* Filter time of 10ms based on the usb2 phy grf pclk of 100MHz. */ ++#define FILTER_COUNTER 0xf4240 ++ + struct rockchip_usb2phy; + + enum rockchip_usb2phy_port_id { +@@ -1408,7 +1411,8 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev) + } + } + +- if (of_device_is_compatible(np, "rockchip,rv1106-usb2phy")) { ++ if (of_device_is_compatible(np, "rockchip,rv1106-usb2phy") || ++ of_device_is_compatible(np, "rockchip,rk3568-usb2phy")) { + rphy->phy_base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); + if (IS_ERR(rphy->phy_base)) + return dev_err_probe(dev, PTR_ERR(rphy->phy_base), +@@ -1623,6 +1627,33 @@ static int rk3506_usb2phy_tuning(struct rockchip_usb2phy *rphy) + return ret; + } + ++static int rk3568_usb2phy_tuning(struct rockchip_usb2phy *rphy) ++{ ++ int ret = 0; ++ ++ /* Turn off differential receiver by default to save power */ ++ phy_clear_bits(rphy->phy_base + 0x30, BIT(2)); ++ ++ /* Enable otg port pre-emphasis during non-chirp phase */ ++ phy_update_bits(rphy->phy_base, GENMASK(2, 0), 0x04); ++ ++ /* Enable host port pre-emphasis during non-chirp phase */ ++ phy_update_bits(rphy->phy_base + 0x0400, GENMASK(2, 0), 0x04); ++ ++ if (rphy->phy_cfg->reg == 0xfe8a0000) { ++ /* Set otg port HS eye height to 437.5mv (default is 400mv) */ ++ phy_update_bits(rphy->phy_base + 0x30, GENMASK(6, 4), (0x06 << 4)); ++ ++ /* Set the bvalid filter time to 10ms */ ++ ret |= regmap_write(rphy->grf, 0x0048, FILTER_COUNTER); ++ ++ /* Set the id filter time to 10ms */ ++ ret |= regmap_write(rphy->grf, 0x004c, FILTER_COUNTER); ++ } ++ ++ return ret; ++} ++ + static int rk3576_usb2phy_tuning(struct rockchip_usb2phy *rphy) + { + int ret; +@@ -2177,6 +2208,7 @@ static const struct rockchip_usb2phy_cfg rk3568_phy_cfgs[] = { + { + .reg = 0xfe8a0000, + .num_ports = 2, ++ .phy_tuning = rk3568_usb2phy_tuning, + .clkout_ctl = { 0x0008, 4, 4, 1, 0 }, + .port_cfgs = { + [USB2PHY_PORT_OTG] = { +@@ -2220,6 +2252,7 @@ static const struct rockchip_usb2phy_cfg rk3568_phy_cfgs[] = { + { + .reg = 0xfe8b0000, + .num_ports = 2, ++ .phy_tuning = rk3568_usb2phy_tuning, + .clkout_ctl = { 0x0008, 4, 4, 1, 0 }, + .port_cfgs = { + [USB2PHY_PORT_OTG] = { +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0039-drm-rockchip-cdn-dp-Disable-CDN-DP-on-disconnect.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0039-drm-rockchip-cdn-dp-Disable-CDN-DP-on-disconnect.patch new file mode 100644 index 000000000..e12c80a97 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0039-drm-rockchip-cdn-dp-Disable-CDN-DP-on-disconnect.patch @@ -0,0 +1,28 @@ +From 6eb3bfc132cc355363c40a8f7d17ad9469c03307 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ond=C5=99ej=20Jirman?= +Date: Sat, 20 Nov 2021 14:35:52 +0100 +Subject: [PATCH 39/84] drm/rockchip: cdn-dp: Disable CDN DP on disconnect + +Why not? + +Signed-off-by: Ondrej Jirman +(cherry picked from commit bf7cc5c78bcfcf8017573bbd21d69f955e47276e) +--- + drivers/gpu/drm/rockchip/cdn-dp-core.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c +index 177e30445ee8..13b83fe8feed 100644 +--- a/drivers/gpu/drm/rockchip/cdn-dp-core.c ++++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c +@@ -898,6 +898,7 @@ static void cdn_dp_pd_event_work(struct work_struct *work) + DRM_DEV_INFO(dp->dev, "Not connected; disabling cdn\n"); + dp->connected = false; + ++ cdn_dp_disable(dp); + /* Connected but not enabled, enable the block */ + } else if (!dp->active) { + DRM_DEV_INFO(dp->dev, "Connected, not enabled; enabling cdn\n"); +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0040-phy-rockchip-inno-usb2-Decrease-delay-between-port-i.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0040-phy-rockchip-inno-usb2-Decrease-delay-between-port-i.patch new file mode 100644 index 000000000..5277cb47e --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0040-phy-rockchip-inno-usb2-Decrease-delay-between-port-i.patch @@ -0,0 +1,41 @@ +From 6b34febb9343481e8b855a6f540cb9353a8ab2f6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ond=C5=99ej=20Jirman?= +Date: Sun, 30 Jan 2022 23:44:42 +0100 +Subject: [PATCH 40/84] phy: rockchip-inno-usb2: Decrease delay between port + init and charger detection + +When used on systems with TCPM, the charger detection via USB2.0 PHY +will take too much time during boot, so the fusb302 driver will not +be able to get the result, and will set incorrect current_max on +its power supply device. + +This will lead to failure to charge when the device is powered up +while connected to non-PD charger. + +Decreasing delay of otg_sm_work from 6s to 500ms ensures that +port type detection via the PHY will finish well in time for +TCPM to be able to use its result when Rp=default is detected +via CC pins. + +Signed-off-by: Ondrej Jirman +(cherry picked from commit 41ad83ccb484296caec829ca3bc871e181a589cb) +--- + drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +index d9d14cc8cf79..1a01169817de 100644 +--- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c ++++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +@@ -541,7 +541,7 @@ static int rockchip_usb2phy_init(struct phy *phy) + goto out; + + schedule_delayed_work(&rport->otg_sm_work, +- OTG_SCHEDULE_DELAY * 3); ++ msecs_to_jiffies(500)); + } else { + /* If OTG works in host only mode, do nothing. */ + dev_dbg(&rport->phy->dev, "mode %d\n", rport->mode); +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0041-phy-rockchip-inno-usb2-More-robust-charger-detection.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0041-phy-rockchip-inno-usb2-More-robust-charger-detection.patch new file mode 100644 index 000000000..c678556b5 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0041-phy-rockchip-inno-usb2-More-robust-charger-detection.patch @@ -0,0 +1,115 @@ +From e42f271b4064adc4f2bd77d27842da5ce29712eb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ond=C5=99ej=20Jirman?= +Date: Fri, 4 Feb 2022 02:25:34 +0100 +Subject: [PATCH 41/84] phy: rockchip-inno-usb2: More robust charger detection + extcon updates + +Make sure we always clear the charger detection results. Allow to +disable updates of EXTCON_USB state via extcon,ignore-usb DT property. +The previous method was smart, but assumed !vbus_branch would +always be called. + +Signed-off-by: Ondrej Jirman +(cherry picked from commit 3b27a37fbd058db8a780e2ad364728a4d4e5fd1a) +--- + drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 39 +++++++++++-------- + 1 file changed, 23 insertions(+), 16 deletions(-) + +diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +index 1a01169817de..ef9f7a45c122 100644 +--- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c ++++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +@@ -661,21 +661,27 @@ static const struct phy_ops rockchip_usb2phy_ops = { + .owner = THIS_MODULE, + }; + ++const int rockchip_usb2phy_cable_types[] = { ++ EXTCON_CHG_USB_SDP, ++ EXTCON_CHG_USB_DCP, ++ EXTCON_CHG_USB_CDP, ++ EXTCON_CHG_USB_ACA, ++}; ++ + static void rockchip_usb2phy_otg_sm_work(struct work_struct *work) + { + struct rockchip_usb2phy_port *rport = + container_of(work, struct rockchip_usb2phy_port, + otg_sm_work.work); + struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent); +- static unsigned int cable; ++ unsigned int cable = 0, i; + unsigned long delay; +- bool vbus_attach, sch_work, notify_charger; ++ bool vbus_attach, sch_work; + + vbus_attach = property_enabled(rphy->grf, + &rport->port_cfg->utmi_bvalid); + + sch_work = false; +- notify_charger = false; + delay = OTG_SCHEDULE_DELAY; + dev_dbg(&rport->phy->dev, "%s otg sm work\n", + usb_otg_state_string(rport->state)); +@@ -704,14 +710,12 @@ static void rockchip_usb2phy_otg_sm_work(struct work_struct *work) + dev_dbg(&rport->phy->dev, "sdp cable is connected\n"); + rockchip_usb2phy_power_on(rport->phy); + rport->state = OTG_STATE_B_PERIPHERAL; +- notify_charger = true; + sch_work = true; + cable = EXTCON_CHG_USB_SDP; + break; + case POWER_SUPPLY_TYPE_USB_DCP: + dev_dbg(&rport->phy->dev, "dcp cable is connected\n"); + rockchip_usb2phy_power_off(rport->phy); +- notify_charger = true; + sch_work = true; + cable = EXTCON_CHG_USB_DCP; + break; +@@ -719,7 +723,6 @@ static void rockchip_usb2phy_otg_sm_work(struct work_struct *work) + dev_dbg(&rport->phy->dev, "cdp cable is connected\n"); + rockchip_usb2phy_power_on(rport->phy); + rport->state = OTG_STATE_B_PERIPHERAL; +- notify_charger = true; + sch_work = true; + cable = EXTCON_CHG_USB_CDP; + break; +@@ -731,22 +734,26 @@ static void rockchip_usb2phy_otg_sm_work(struct work_struct *work) + break; + } + } else { +- notify_charger = true; + rphy->chg_state = USB_CHG_STATE_UNDEFINED; + rphy->chg_type = POWER_SUPPLY_TYPE_UNKNOWN; + } + +- if (rport->vbus_attached != vbus_attach) { +- rport->vbus_attached = vbus_attach; ++ if (rphy->edev && extcon_get_state(rphy->edev, cable) != vbus_attach) { ++ for (i = 0; i < ARRAY_SIZE(rockchip_usb2phy_cable_types); i++) { ++ int type = rockchip_usb2phy_cable_types[i]; + +- if (notify_charger && rphy->edev) { +- extcon_set_state_sync(rphy->edev, +- cable, vbus_attach); +- if (cable == EXTCON_CHG_USB_SDP) +- extcon_set_state_sync(rphy->edev, +- EXTCON_USB, +- vbus_attach); ++ if (extcon_get_state(rphy->edev, type)) ++ extcon_set_state_sync(rphy->edev, type, 0); + } ++ ++ if (vbus_attach) ++ extcon_set_state_sync(rphy->edev, cable, vbus_attach); ++ ++ if ((cable == EXTCON_CHG_USB_SDP || cable == POWER_SUPPLY_TYPE_USB_CDP) ++ && extcon_get_state(rphy->edev, EXTCON_USB) != vbus_attach ++ && !of_property_read_bool(rphy->dev->of_node, "extcon,ignore-usb")) ++ extcon_set_state_sync(rphy->edev, ++ EXTCON_USB, vbus_attach); + } + break; + case OTG_STATE_B_PERIPHERAL: +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0042-usb-dwc3-Track-the-power-state-of-usb3_generic_phy.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0042-usb-dwc3-Track-the-power-state-of-usb3_generic_phy.patch new file mode 100644 index 000000000..54c78cc95 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0042-usb-dwc3-Track-the-power-state-of-usb3_generic_phy.patch @@ -0,0 +1,73 @@ +From ce3115635dc842403bad5d6287a765802741ae74 Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Mon, 20 Jul 2026 17:46:22 +0200 +Subject: [PATCH 42/84] usb: dwc3: Track the power state of usb3_generic_phy + +The USB3 PHYs will need to be powered off and on again from within the +set_mode work, independently of the rest of the controller. There is no +way to recover from a failure there, so track whether the PHYs are +actually powered to keep the phy_power_on()/phy_power_off() calls +balanced. + +Signed-off-by: Ondrej Jirman +(cherry picked from commit bc1f2513d49d2a23ac923380f72a5ca2729122e8) +--- + drivers/usb/dwc3/core.c | 10 ++++++++-- + drivers/usb/dwc3/core.h | 6 ++++++ + 2 files changed, 14 insertions(+), 2 deletions(-) + +diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c +index 9d4293f02c9a..9c6bd173798c 100644 +--- a/drivers/usb/dwc3/core.c ++++ b/drivers/usb/dwc3/core.c +@@ -919,6 +919,8 @@ static int dwc3_phy_power_on(struct dwc3 *dwc) + goto err_power_off_usb3_phy; + } + ++ dwc->usb3_phy_powered = true; ++ + return 0; + + err_power_off_usb3_phy: +@@ -939,8 +941,12 @@ static void dwc3_phy_power_off(struct dwc3 *dwc) + { + int i; + +- for (i = 0; i < dwc->num_usb3_ports; i++) +- phy_power_off(dwc->usb3_generic_phy[i]); ++ if (dwc->usb3_phy_powered) { ++ for (i = 0; i < dwc->num_usb3_ports; i++) ++ phy_power_off(dwc->usb3_generic_phy[i]); ++ ++ dwc->usb3_phy_powered = false; ++ } + + for (i = 0; i < dwc->num_usb2_ports; i++) + phy_power_off(dwc->usb2_generic_phy[i]); +diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h +index e0dee9d28740..19a93c3dd668 100644 +--- a/drivers/usb/dwc3/core.h ++++ b/drivers/usb/dwc3/core.h +@@ -1067,6 +1067,10 @@ struct dwc3_glue_ops { + * @usb3_generic_phy: pointer to array of USB3 PHYs + * @num_usb2_ports: number of USB2 ports + * @num_usb3_ports: number of USB3 ports ++ * @usb3_phy_powered: flag to indicate that the USB3 PHYs are powered on. The ++ * USB3 PHYs may be powered off independently of the rest of ++ * the controller, so their state has to be tracked to keep ++ * the phy_power_on()/phy_power_off() calls balanced. + * @phys_ready: flag to indicate that PHYs are ready + * @ulpi: pointer to ulpi interface + * @ulpi_ready: flag to indicate that ULPI is initialized +@@ -1233,6 +1237,8 @@ struct dwc3 { + u8 num_usb2_ports; + u8 num_usb3_ports; + ++ bool usb3_phy_powered; ++ + bool phys_ready; + + struct ulpi *ulpi; +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0043-usb-dwc3-Always-disable-SUSPHY-when-entering-a-role.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0043-usb-dwc3-Always-disable-SUSPHY-when-entering-a-role.patch new file mode 100644 index 000000000..70e3f2860 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0043-usb-dwc3-Always-disable-SUSPHY-when-entering-a-role.patch @@ -0,0 +1,47 @@ +From c11a7d364f9ae037e9c0f9e13ec9eefcd9f526cf Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Mon, 20 Jul 2026 22:09:48 +0200 +Subject: [PATCH 43/84] usb: dwc3: Always disable SUSPHY when entering a role + +__dwc3_set_mode() leaves the old role, which enables SUSPHY, and then +re-initializes the new one, which requires SUSPHY to be disabled. The +only thing disabling it again is dwc3_set_prtcap(), and only when the +value already in GCTL.PrtCapDir differs from the one being set. + +That is not the same question as whether a role transition took place. +At probe, current_dr_role is 0 while GCTL.PrtCapDir may already hold the +role being switched to, so the transition runs with SUSPHY left enabled. + +Disable it in __dwc3_set_mode() directly, so entering a role does not +depend on what the register happened to hold. + +Signed-off-by: Ondrej Jirman +(cherry picked from commit 01e90addf2c0380dc29c550fa565e71127217c18) +--- + drivers/usb/dwc3/core.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c +index 9c6bd173798c..86ddf91ae454 100644 +--- a/drivers/usb/dwc3/core.c ++++ b/drivers/usb/dwc3/core.c +@@ -235,7 +235,15 @@ static void __dwc3_set_mode(struct work_struct *work) + + spin_lock_irqsave(&dwc->lock, flags); + +- dwc3_set_prtcap(dwc, desired_dr_role, false); ++ /* ++ * Leaving the old role enabled SUSPHY, and re-initializing the new one ++ * requires it to be disabled. dwc3_set_prtcap() only does that when the ++ * value already in GCTL.PrtCapDir differs from the one being set, which ++ * is not the same question, so do it here and tell dwc3_set_prtcap() to ++ * keep its hands off. ++ */ ++ dwc3_enable_susphy(dwc, false); ++ dwc3_set_prtcap(dwc, desired_dr_role, true); + + spin_unlock_irqrestore(&dwc->lock, flags); + +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0044-usb-dwc3-Track-cable-connection-state-separately-fro.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0044-usb-dwc3-Track-cable-connection-state-separately-fro.patch new file mode 100644 index 000000000..88aacabcd --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0044-usb-dwc3-Track-cable-connection-state-separately-fro.patch @@ -0,0 +1,143 @@ +From 23e9a265cd549dbd99cf1109ad706f8a25337e42 Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Mon, 20 Jul 2026 17:48:45 +0200 +Subject: [PATCH 44/84] usb: dwc3: Track cable connection state separately from + dr_role + +A Type-C port can be unplugged and replugged into the same kind of port +without the DRD role ever changing. __dwc3_set_mode() bails out early +when the desired role equals the current one, so such a transition is +invisible to the driver, even though it may need to act on it. + +Track connectedness in its own pair of flags rather than encoding it in +current_dr_role. current_dr_role holds a GCTL.PrtCapDir register value +and is compared against DWC3_GCTL_PRTCAP_* throughout the driver, in the +glue drivers, in debugfs and in tracing, so giving it an out-of-range +value would mean auditing every one of those users. + +dwc3_set_mode() keeps its meaning and implies "connected", so existing +callers are unaffected. Only callers that can actually distinguish a +cable from no cable use dwc3_set_mode_connected(). + +No functional change. + +Signed-off-by: Ondrej Jirman +(cherry picked from commit e862414522584a466af62c055fe7e17a504c9bcd) +--- + drivers/usb/dwc3/core.c | 20 ++++++++++++++++++-- + drivers/usb/dwc3/core.h | 9 +++++++++ + 2 files changed, 27 insertions(+), 2 deletions(-) + +diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c +index 86ddf91ae454..a4416759fac8 100644 +--- a/drivers/usb/dwc3/core.c ++++ b/drivers/usb/dwc3/core.c +@@ -169,11 +169,13 @@ static void __dwc3_set_mode(struct work_struct *work) + int ret; + u32 reg; + u32 desired_dr_role; ++ bool desired_dr_connected; + int i; + + mutex_lock(&dwc->mutex); + spin_lock_irqsave(&dwc->lock, flags); + desired_dr_role = dwc->desired_dr_role; ++ desired_dr_connected = dwc->desired_dr_connected; + spin_unlock_irqrestore(&dwc->lock, flags); + + pm_runtime_get_sync(dwc->dev); +@@ -184,7 +186,8 @@ static void __dwc3_set_mode(struct work_struct *work) + if (!desired_dr_role) + goto out; + +- if (desired_dr_role == dwc->current_dr_role) ++ if (desired_dr_role == dwc->current_dr_role && ++ desired_dr_connected == dwc->current_dr_connected) + goto out; + + if (desired_dr_role == DWC3_GCTL_PRTCAP_OTG && dwc->edev) +@@ -244,6 +247,7 @@ static void __dwc3_set_mode(struct work_struct *work) + */ + dwc3_enable_susphy(dwc, false); + dwc3_set_prtcap(dwc, desired_dr_role, true); ++ dwc->current_dr_connected = desired_dr_connected; + + spin_unlock_irqrestore(&dwc->lock, flags); + +@@ -295,7 +299,7 @@ static void __dwc3_set_mode(struct work_struct *work) + mutex_unlock(&dwc->mutex); + } + +-void dwc3_set_mode(struct dwc3 *dwc, u32 mode) ++void dwc3_set_mode_connected(struct dwc3 *dwc, u32 mode, bool connected) + { + unsigned long flags; + +@@ -304,11 +308,17 @@ void dwc3_set_mode(struct dwc3 *dwc, u32 mode) + + spin_lock_irqsave(&dwc->lock, flags); + dwc->desired_dr_role = mode; ++ dwc->desired_dr_connected = connected; + spin_unlock_irqrestore(&dwc->lock, flags); + + queue_work(system_freezable_wq, &dwc->drd_work); + } + ++void dwc3_set_mode(struct dwc3 *dwc, u32 mode) ++{ ++ dwc3_set_mode_connected(dwc, mode, true); ++} ++ + u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type) + { + struct dwc3 *dwc = dep->dwc; +@@ -1669,6 +1679,12 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) + break; + case USB_DR_MODE_OTG: + INIT_WORK(&dwc->drd_work, __dwc3_set_mode); ++ /* ++ * Default to "connected", which is what dwc3_set_mode() implies. ++ * Only users that can actually tell a cable apart from no cable ++ * ever clear this, via dwc3_set_mode_connected(). ++ */ ++ dwc->current_dr_connected = true; + ret = dwc3_drd_init(dwc); + if (ret) + return dev_err_probe(dev, ret, "failed to initialize dual-role\n"); +diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h +index 19a93c3dd668..03fd08d0dca1 100644 +--- a/drivers/usb/dwc3/core.h ++++ b/drivers/usb/dwc3/core.h +@@ -1050,6 +1050,12 @@ struct dwc3_glue_ops { + * @dr_mode: requested mode of operation + * @current_dr_role: current role of operation when in dual-role mode + * @desired_dr_role: desired role of operation when in dual-role mode ++ * @current_dr_connected: set if a cable is currently known to be connected ++ * @desired_dr_connected: set if a cable is desired to be considered connected. ++ * Tracked separately from @desired_dr_role because the ++ * role does not change when a cable is unplugged from ++ * and replugged into the same kind of port, yet the ++ * transition still has to be acted upon. + * @edev: extcon handle + * @edev_nb: extcon notifier + * @hsphy_mode: UTMI phy mode, one of following: +@@ -1250,6 +1256,8 @@ struct dwc3 { + enum usb_dr_mode dr_mode; + u32 current_dr_role; + u32 desired_dr_role; ++ bool current_dr_connected; ++ bool desired_dr_connected; + struct extcon_dev *edev; + struct notifier_block edev_nb; + enum usb_phy_interface hsphy_mode; +@@ -1596,6 +1604,7 @@ struct dwc3_gadget_ep_cmd_params { + /* prototypes */ + void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode, bool ignore_susphy); + void dwc3_set_mode(struct dwc3 *dwc, u32 mode); ++void dwc3_set_mode_connected(struct dwc3 *dwc, u32 mode, bool connected); + u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type); + + #define DWC3_IP_IS(_ip) \ +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0045-usb-dwc3-Power-cycle-USB3-PHY-on-role-connection-cha.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0045-usb-dwc3-Power-cycle-USB3-PHY-on-role-connection-cha.patch new file mode 100644 index 000000000..6a8e67f6b --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0045-usb-dwc3-Power-cycle-USB3-PHY-on-role-connection-cha.patch @@ -0,0 +1,311 @@ +From e69fe48a25b340f8f46e8144a76a04e80fb1d4fc Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Mon, 20 Jul 2026 17:52:42 +0200 +Subject: [PATCH 45/84] usb: dwc3: Power cycle USB3 PHY on role/connection + change + +The RK3399 Type-C PHY latches the plug orientation while it is being +powered on, and per the TRM this may only happen while the USB3 OTG +controller is held in reset, to keep the pipe power state at P2. The PHY +driver is passive: it has no extcon notifier and only reprograms the +orientation on power_on after a preceding power_off. So it can not +reconfigure itself and needs the controller driver to power cycle it. + +Do the power cycle in __dwc3_set_mode(), between asserting and +deasserting GCTL.CoreSoftReset, which is exactly the window the PHY +needs. Leave the PHY powered off while no cable is connected, both to +save power and so that the orientation is picked up at plug-in. + +The connection state is what makes this work for the plugout/plugin +cycle into the same kind of port, where the role never changes. + +For extcon, EXTCON_USB has to be watched besides EXTCON_USB_HOST to tell +a disconnect apart from device mode. The notifier for all cable types is +not told which cable changed, so subscribe to all of them, re-read the +state, and drop the updates that change neither the role nor the +connection state. Boards that do not enable the quirk never look at +EXTCON_USB and so keep behaving exactly as before. + +For usb_role_switch, USB_ROLE_NONE keeps falling back to +role_switch_default_mode as before, but is now remembered as +disconnected, and is reported back as USB_ROLE_NONE. + +While no cable is connected the USB3 PHY is powered off, so there is +nothing to run on top of it. Skip the role init in that case, and skip +the matching teardown for a role that was entered while disconnected. +Otherwise the gadget is brought up against a powered off PHY, which +fails to enable ep0out and then takes seconds to tear down again, all +of it under dwc->mutex. + +Signed-off-by: Ondrej Jirman +(cherry picked from commit 1579c94e43edea5ade9beb012a224d7a68e10774) +--- + drivers/usb/dwc3/core.c | 51 ++++++++++++++++++++++++-- + drivers/usb/dwc3/core.h | 7 ++++ + drivers/usb/dwc3/drd.c | 79 +++++++++++++++++++++++++++++++---------- + 3 files changed, 116 insertions(+), 21 deletions(-) + +diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c +index a4416759fac8..21554e8d3ffa 100644 +--- a/drivers/usb/dwc3/core.c ++++ b/drivers/usb/dwc3/core.c +@@ -193,7 +193,11 @@ static void __dwc3_set_mode(struct work_struct *work) + if (desired_dr_role == DWC3_GCTL_PRTCAP_OTG && dwc->edev) + goto out; + +- switch (dwc->current_dr_role) { ++ /* ++ * Nothing was brought up for a role entered while no cable was ++ * connected, so there is nothing to tear down either. ++ */ ++ switch (dwc->current_dr_connected ? dwc->current_dr_role : 0) { + case DWC3_GCTL_PRTCAP_HOST: + dwc3_host_exit(dwc); + break; +@@ -217,12 +221,45 @@ static void __dwc3_set_mode(struct work_struct *work) + * Only perform GCTL.CoreSoftReset when there's DRD role switching. + */ + if (dwc->current_dr_role && ((DWC3_IP_IS(DWC3) || +- DWC3_VER_IS_PRIOR(DWC31, 190A)) && ++ DWC3_VER_IS_PRIOR(DWC31, 190A) || ++ dwc->usb3_phy_power_cycle) && + desired_dr_role != DWC3_GCTL_PRTCAP_OTG)) { + reg = dwc3_readl(dwc, DWC3_GCTL); + reg |= DWC3_GCTL_CORESOFTRESET; + dwc3_writel(dwc, DWC3_GCTL, reg); + ++ /* ++ * The USB3 PHY may only be reconfigured while the controller is ++ * held in reset, so do it here, between asserting and ++ * deasserting GCTL.CoreSoftReset. ++ * ++ * The PHY is left powered off while no cable is connected, both ++ * to save power and so that it picks up the current Type-C plug ++ * orientation when it is powered on again at plug-in. ++ */ ++ if (dwc->usb3_phy_power_cycle) { ++ if (dwc->usb3_phy_powered) { ++ for (i = 0; i < dwc->num_usb3_ports; i++) ++ phy_power_off(dwc->usb3_generic_phy[i]); ++ ++ dwc->usb3_phy_powered = false; ++ } ++ ++ if (desired_dr_connected) { ++ for (i = 0; i < dwc->num_usb3_ports; i++) { ++ ret = phy_power_on(dwc->usb3_generic_phy[i]); ++ if (ret < 0) { ++ dev_err(dwc->dev, "failed to power on usb3 phy %d\n", i); ++ while (--i >= 0) ++ phy_power_off(dwc->usb3_generic_phy[i]); ++ break; ++ } ++ } ++ ++ dwc->usb3_phy_powered = i == dwc->num_usb3_ports; ++ } ++ } ++ + /* + * Wait for internal clocks to synchronized. DWC_usb31 and + * DWC_usb32 may need at least 50ms (less for DWC_usb3). To +@@ -251,7 +288,12 @@ static void __dwc3_set_mode(struct work_struct *work) + + spin_unlock_irqrestore(&dwc->lock, flags); + +- switch (desired_dr_role) { ++ /* ++ * With no cable connected the USB3 PHY is powered off, so there is ++ * nothing to bring up on top of it. Leave the controller idle until a ++ * cable shows up. ++ */ ++ switch (desired_dr_connected ? desired_dr_role : 0) { + case DWC3_GCTL_PRTCAP_HOST: + ret = dwc3_host_init(dwc); + if (ret) { +@@ -1908,6 +1950,9 @@ static void dwc3_get_properties(struct dwc3 *dwc) + dwc->dis_split_quirk = device_property_read_bool(dev, + "snps,dis-split-quirk"); + ++ dwc->usb3_phy_power_cycle = device_property_read_bool(dev, ++ "usb3-phy-power-cycle-on-role-change"); ++ + dwc->lpm_nyet_threshold = lpm_nyet_threshold; + dwc->tx_de_emphasis = tx_de_emphasis; + +diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h +index 03fd08d0dca1..b0cae898d7fe 100644 +--- a/drivers/usb/dwc3/core.h ++++ b/drivers/usb/dwc3/core.h +@@ -1174,6 +1174,12 @@ struct dwc3_glue_ops { + * 3 - Reserved + * @dis_metastability_quirk: set to disable metastability quirk. + * @dis_split_quirk: set to disable split boundary. ++ * @usb3_phy_power_cycle: set if the USB3 PHY has to be power cycled whenever ++ * the role or the cable connection state changes, and ++ * left powered off while no cable is connected. Needed ++ * on platforms whose Type-C PHY can only pick up the ++ * plug orientation while it is being powered on, and ++ * only while the controller is held in reset. + * @enable_usb2_transceiver_delay: Set to insert a delay before the + * assertion of the TxValid signal during a HS Chirp. + * @sys_wakeup: set if the device may do system wakeup. +@@ -1423,6 +1429,7 @@ struct dwc3 { + unsigned dis_metastability_quirk:1; + + unsigned dis_split_quirk:1; ++ unsigned usb3_phy_power_cycle:1; + unsigned enable_usb2_transceiver_delay:1; + unsigned async_callbacks:1; + unsigned sys_wakeup:1; +diff --git a/drivers/usb/dwc3/drd.c b/drivers/usb/dwc3/drd.c +index f3e37d383627..fa622d9abfcd 100644 +--- a/drivers/usb/dwc3/drd.c ++++ b/drivers/usb/dwc3/drd.c +@@ -419,28 +419,56 @@ void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus) + + static void dwc3_drd_update(struct dwc3 *dwc) + { ++ unsigned long flags; ++ bool connected = true; ++ bool changed; ++ u32 mode; + int id; + +- if (dwc->edev) { +- id = extcon_get_state(dwc->edev, EXTCON_USB_HOST); +- if (id < 0) +- id = 0; +- dwc3_set_mode(dwc, id ? +- DWC3_GCTL_PRTCAP_HOST : +- DWC3_GCTL_PRTCAP_DEVICE); +- } ++ if (!dwc->edev) ++ return; ++ ++ id = extcon_get_state(dwc->edev, EXTCON_USB_HOST); ++ if (id < 0) ++ id = 0; ++ ++ mode = id ? DWC3_GCTL_PRTCAP_HOST : DWC3_GCTL_PRTCAP_DEVICE; ++ ++ /* ++ * EXTCON_USB is what tells a device mode cable apart from no cable at ++ * all. Boards that do not need the distinction ignore it and keep ++ * assuming a cable is always connected, as before. ++ */ ++ if (dwc->usb3_phy_power_cycle) ++ connected = id || extcon_get_state(dwc->edev, EXTCON_USB) > 0; ++ ++ /* ++ * All cable types are subscribed to, but only the ones read above make ++ * any difference here. Drop the rest rather than queueing work that ++ * would only find that there is nothing to do. ++ */ ++ spin_lock_irqsave(&dwc->lock, flags); ++ changed = mode != dwc->desired_dr_role || ++ connected != dwc->desired_dr_connected; ++ spin_unlock_irqrestore(&dwc->lock, flags); ++ ++ if (!changed) ++ return; ++ ++ dwc3_pre_set_role(dwc, id ? USB_ROLE_HOST : USB_ROLE_DEVICE); ++ dwc3_set_mode_connected(dwc, mode, connected); + } + + static int dwc3_drd_notifier(struct notifier_block *nb, + unsigned long event, void *ptr) + { + struct dwc3 *dwc = container_of(nb, struct dwc3, edev_nb); +- u32 mode = event ? DWC3_GCTL_PRTCAP_HOST : DWC3_GCTL_PRTCAP_DEVICE; +- enum usb_role role = mode == DWC3_GCTL_PRTCAP_HOST ? +- USB_ROLE_HOST : USB_ROLE_DEVICE; + +- dwc3_pre_set_role(dwc, role); +- dwc3_set_mode(dwc, mode); ++ /* ++ * The notifier for all cable types is not told which one changed, so ++ * the state has to be re-read rather than derived from @event. ++ */ ++ dwc3_drd_update(dwc); + + return NOTIFY_DONE; + } +@@ -451,6 +479,7 @@ static int dwc3_usb_role_switch_set(struct usb_role_switch *sw, + enum usb_role role) + { + struct dwc3 *dwc = usb_role_switch_get_drvdata(sw); ++ bool connected = true; + u32 mode; + + switch (role) { +@@ -461,6 +490,11 @@ static int dwc3_usb_role_switch_set(struct usb_role_switch *sw, + mode = DWC3_GCTL_PRTCAP_DEVICE; + break; + default: ++ /* ++ * Keep falling back to role_switch_default_mode, but remember ++ * that nothing is actually connected. ++ */ ++ connected = !dwc->usb3_phy_power_cycle; + if (dwc->role_switch_default_mode == USB_DR_MODE_HOST) + mode = DWC3_GCTL_PRTCAP_HOST; + else +@@ -469,7 +503,7 @@ static int dwc3_usb_role_switch_set(struct usb_role_switch *sw, + } + + dwc3_pre_set_role(dwc, role); +- dwc3_set_mode(dwc, mode); ++ dwc3_set_mode_connected(dwc, mode, connected); + return 0; + } + +@@ -480,6 +514,11 @@ static enum usb_role dwc3_usb_role_switch_get(struct usb_role_switch *sw) + enum usb_role role; + + spin_lock_irqsave(&dwc->lock, flags); ++ if (!dwc->current_dr_connected) { ++ role = USB_ROLE_NONE; ++ goto unlock; ++ } ++ + switch (dwc->current_dr_role) { + case DWC3_GCTL_PRTCAP_HOST: + role = USB_ROLE_HOST; +@@ -497,6 +536,7 @@ static enum usb_role dwc3_usb_role_switch_get(struct usb_role_switch *sw) + role = USB_ROLE_DEVICE; + break; + } ++unlock: + spin_unlock_irqrestore(&dwc->lock, flags); + return role; + } +@@ -553,8 +593,12 @@ int dwc3_drd_init(struct dwc3 *dwc) + + if (dwc->edev) { + dwc->edev_nb.notifier_call = dwc3_drd_notifier; +- ret = extcon_register_notifier(dwc->edev, EXTCON_USB_HOST, +- &dwc->edev_nb); ++ /* ++ * EXTCON_USB has to be watched besides EXTCON_USB_HOST to tell ++ * a disconnect apart from device mode, so subscribe to all ++ * cable types and let dwc3_drd_update() ignore the rest. ++ */ ++ ret = extcon_register_notifier_all(dwc->edev, &dwc->edev_nb); + if (ret < 0) { + dev_err(dwc->dev, "couldn't register cable notifier\n"); + return ret; +@@ -601,8 +645,7 @@ void dwc3_drd_exit(struct dwc3 *dwc) + usb_role_switch_unregister(dwc->role_sw); + + if (dwc->edev) +- extcon_unregister_notifier(dwc->edev, EXTCON_USB_HOST, +- &dwc->edev_nb); ++ extcon_unregister_notifier_all(dwc->edev, &dwc->edev_nb); + + cancel_work_sync(&dwc->drd_work); + +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0046-usb-dwc3-Register-the-role-even-when-no-cable-is-con.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0046-usb-dwc3-Register-the-role-even-when-no-cable-is-con.patch new file mode 100644 index 000000000..22a7bc892 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0046-usb-dwc3-Register-the-role-even-when-no-cable-is-con.patch @@ -0,0 +1,69 @@ +From 364a17c0e659ea1a6a2727bdbf9936218b7d0583 Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Mon, 20 Jul 2026 22:42:25 +0200 +Subject: [PATCH 46/84] usb: dwc3: Register the role even when no cable is + connected + +Gating the role init on the connection state went too far. Entering a +role is what registers the gadget or the host, and for the gadget that +means registering the UDC. With nothing plugged in at boot the UDC was +never registered at all, so userspace could not bind a gadget driver to +it, and by the time a cable showed up and the UDC appeared there was +nothing left pending to bind. + +Only skip the role init for a connection change within a role that is +already entered. That still keeps the gadget from being brought up on +top of a powered off USB3 PHY, which is what the gating was for. + +Fixup for "usb: dwc3: Power cycle USB3 PHY on role/connection change". + +Signed-off-by: Ondrej Jirman +(cherry picked from commit 790a415b4c5d14ae379946381f8ff40ba7c23a1f) +--- + drivers/usb/dwc3/core.c | 15 +++++++++++---- + 1 file changed, 11 insertions(+), 4 deletions(-) + +diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c +index 21554e8d3ffa..0e20e70b9163 100644 +--- a/drivers/usb/dwc3/core.c ++++ b/drivers/usb/dwc3/core.c +@@ -170,6 +170,7 @@ static void __dwc3_set_mode(struct work_struct *work) + u32 reg; + u32 desired_dr_role; + bool desired_dr_connected; ++ bool role_changed; + int i; + + mutex_lock(&dwc->mutex); +@@ -193,6 +194,8 @@ static void __dwc3_set_mode(struct work_struct *work) + if (desired_dr_role == DWC3_GCTL_PRTCAP_OTG && dwc->edev) + goto out; + ++ role_changed = desired_dr_role != dwc->current_dr_role; ++ + /* + * Nothing was brought up for a role entered while no cable was + * connected, so there is nothing to tear down either. +@@ -289,11 +292,15 @@ static void __dwc3_set_mode(struct work_struct *work) + spin_unlock_irqrestore(&dwc->lock, flags); + + /* +- * With no cable connected the USB3 PHY is powered off, so there is +- * nothing to bring up on top of it. Leave the controller idle until a +- * cable shows up. ++ * Entering a role registers the gadget or the host, which has to happen ++ * even with no cable connected so that userspace can bind a gadget ++ * driver to the UDC before anything is plugged in. ++ * ++ * A connection change within the same role is different: the USB3 PHY ++ * has just been powered off, so there is nothing to bring up on top of ++ * it, and the role is already entered anyway. + */ +- switch (desired_dr_connected ? desired_dr_role : 0) { ++ switch (desired_dr_connected || role_changed ? desired_dr_role : 0) { + case DWC3_GCTL_PRTCAP_HOST: + ret = dwc3_host_init(dwc); + if (ret) { +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0047-phy-rockchip-inno-usb2-Set-up-charger-detection-mode.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0047-phy-rockchip-inno-usb2-Set-up-charger-detection-mode.patch new file mode 100644 index 000000000..6c788cfdb --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0047-phy-rockchip-inno-usb2-Set-up-charger-detection-mode.patch @@ -0,0 +1,189 @@ +From 45981a4220fe965b0dabd39870943e3da097e26c Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Mon, 20 Jul 2026 22:59:13 +0200 +Subject: [PATCH 47/84] phy: rockchip-inno-usb2: Set up charger detection mode + on RK3399 + +BC1.2 detection has to run with the transceiver held off the bus, or the +data contact detection stage cannot see the host's D+ pull-down. On a +PinePhone Pro with a gadget driver bound, DCD reads dp_det = 0 for all +six polls, detection times out and reports a floating charger, and +rockchip_usb2phy_otg_sm_work() powers the USB2 PHY off in response. +USB 2.0 then does not enumerate at all: the host gets -32 on the +descriptor read, then -71, then gives up. Unbind the gadget and the same +cable is correctly detected as SDP on the first poll. + +The driver models 0xe454 as two overlapping narrow fields, phy_sus over +bits 1:0 and chg_det.opmode over bits 3:0, and only ever writes opmode +while VBUS is absent. Charger detection only runs while VBUS is present, +so on RK3399 opmode is never written at all and non-driving mode is +never entered. + +Rockchip's own driver describes the same register as one nine bit field +and writes 0x1d7 to it for the duration of detection, which per its +comment selects normal mode, non-driving opmode, full speed xcvrselect +and termselect, and the DP/DM pull-downs. Do the same, and save and +restore exactly the bits being overwritten so nothing has to be assumed +about what the rest of them mean. + +SoCs without a chg_mode field keep poking opmode as before, including +the VBUS condition from commit 7d8f725b79e3 ("phy: rockchip: inno-usb2: +fix communication disruption in gadget mode"), so they are unaffected. + +Signed-off-by: Ondrej Jirman +(cherry picked from commit b92d132cafcf20c5cf7413f14bae79bd44e3ca84) +--- + drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 81 +++++++++++++++++-- + 1 file changed, 73 insertions(+), 8 deletions(-) + +diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +index ef9f7a45c122..a138417f0b2e 100644 +--- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c ++++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +@@ -100,6 +100,8 @@ struct usb2phy_reg { + * @vdm_src_en: open dm voltage source. + * @vdp_src_en: open dp voltage source. + * @opmode: utmi operational mode. ++ * @chg_mode: charger detection mode, covering everything that has to be set ++ * up for BC1.2 at once. Takes precedence over @opmode. + */ + struct rockchip_chg_det_reg { + struct usb2phy_reg cp_det; +@@ -112,6 +114,7 @@ struct rockchip_chg_det_reg { + struct usb2phy_reg vdm_src_en; + struct usb2phy_reg vdp_src_en; + struct usb2phy_reg opmode; ++ struct usb2phy_reg chg_mode; + }; + + /** +@@ -246,6 +249,8 @@ struct rockchip_usb2phy_port { + * @irq: muxed interrupt for single irq configuration + * @phy_cfg: phy register configuration, assigned by driver data. + * @ports: phy port instance. ++ * @chg_mode_cfg: saved contents of the charger detection mode field, so that ++ * it can be restored once detection is done. + */ + struct rockchip_usb2phy { + struct device *dev; +@@ -260,6 +265,7 @@ struct rockchip_usb2phy { + enum usb_chg_state chg_state; + enum power_supply_type chg_type; + u8 dcd_retries; ++ unsigned int chg_mode_cfg; + struct extcon_dev *edev; + int irq; + const struct rockchip_usb2phy_cfg *phy_cfg; +@@ -823,6 +829,68 @@ static void rockchip_chg_enable_secondary_det(struct rockchip_usb2phy *rphy, + property_enable(base, &rphy->phy_cfg->chg_det.idp_sink_en, en); + } + ++/* ++ * BC1.2 detection needs the transceiver held off the bus: utmi_opmode in ++ * non-driving mode, xcvrselect and termselect at full speed, and the DP/DM ++ * pull-down resistors enabled. On SoCs where that is described as a single ++ * chg_mode field, set it up in one go and put the register back afterwards. ++ * ++ * Otherwise only utmi_opmode can be poked, and only while nothing is ++ * connected: doing it with a cable attached kills an active gadget, see ++ * commit 7d8f725b79e3 ("phy: rockchip: inno-usb2: fix communication ++ * disruption in gadget mode"). That leaves detection running with the ++ * transceiver driving, which is unreliable, but it is not a regression. ++ */ ++static bool rockchip_chg_has_chg_mode(struct rockchip_usb2phy *rphy) ++{ ++ /* An unpopulated usb2phy_reg leaves nothing to write. */ ++ return rphy->phy_cfg->chg_det.chg_mode.enable != 0; ++} ++ ++static void rockchip_chg_enter_mode(struct rockchip_usb2phy *rphy, ++ struct rockchip_usb2phy_port *rport, ++ bool vbus_attach) ++{ ++ const struct usb2phy_reg *chg_mode = &rphy->phy_cfg->chg_det.chg_mode; ++ struct regmap *base = get_reg_base(rphy); ++ ++ if (!rockchip_chg_has_chg_mode(rphy)) { ++ if (!vbus_attach) ++ property_enable(base, &rphy->phy_cfg->chg_det.opmode, ++ false); ++ return; ++ } ++ ++ /* ++ * Save exactly the bits that are about to be overwritten, so they can ++ * be put back afterwards without having to know what they mean. ++ */ ++ regmap_read(base, chg_mode->offset, &rphy->chg_mode_cfg); ++ rphy->chg_mode_cfg &= GENMASK(chg_mode->bitend, chg_mode->bitstart); ++ ++ property_enable(base, chg_mode, true); ++} ++ ++static void rockchip_chg_leave_mode(struct rockchip_usb2phy *rphy, ++ struct rockchip_usb2phy_port *rport, ++ bool vbus_attach) ++{ ++ const struct usb2phy_reg *chg_mode = &rphy->phy_cfg->chg_det.chg_mode; ++ struct regmap *base = get_reg_base(rphy); ++ unsigned int mask; ++ ++ if (!rockchip_chg_has_chg_mode(rphy)) { ++ if (!vbus_attach) ++ property_enable(base, &rphy->phy_cfg->chg_det.opmode, ++ true); ++ return; ++ } ++ ++ mask = GENMASK(chg_mode->bitend, chg_mode->bitstart); ++ regmap_write(base, chg_mode->offset, ++ rphy->chg_mode_cfg | (mask << BIT_WRITEABLE_SHIFT)); ++} ++ + #define CHG_DCD_POLL_TIME (100 * HZ / 1000) + #define CHG_DCD_MAX_RETRIES 6 + #define CHG_PRIMARY_DET_TIME (40 * HZ / 1000) +@@ -832,7 +900,6 @@ static void rockchip_chg_detect_work(struct work_struct *work) + struct rockchip_usb2phy_port *rport = + container_of(work, struct rockchip_usb2phy_port, chg_work.work); + struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent); +- struct regmap *base = get_reg_base(rphy); + bool is_dcd, tmout, vout, vbus_attach; + unsigned long delay; + +@@ -844,9 +911,8 @@ static void rockchip_chg_detect_work(struct work_struct *work) + case USB_CHG_STATE_UNDEFINED: + if (!rport->suspended && !vbus_attach) + rockchip_usb2phy_power_off(rport->phy); +- /* put the controller in non-driving mode */ +- if (!vbus_attach) +- property_enable(base, &rphy->phy_cfg->chg_det.opmode, false); ++ /* put the controller in charger detection mode */ ++ rockchip_chg_enter_mode(rphy, rport, vbus_attach); + /* Start DCD processing stage 1 */ + rockchip_chg_enable_dcd(rphy, true); + rphy->chg_state = USB_CHG_STATE_WAIT_FOR_DCD; +@@ -908,9 +974,8 @@ static void rockchip_chg_detect_work(struct work_struct *work) + rphy->chg_state = USB_CHG_STATE_DETECTED; + fallthrough; + case USB_CHG_STATE_DETECTED: +- /* put the controller in normal mode */ +- if (!vbus_attach) +- property_enable(base, &rphy->phy_cfg->chg_det.opmode, true); ++ /* put the controller back in normal mode */ ++ rockchip_chg_leave_mode(rphy, rport, vbus_attach); + rockchip_usb2phy_otg_sm_work(&rport->otg_sm_work.work); + dev_dbg(&rport->phy->dev, "charger = %s\n", + chg_to_string(rphy->chg_type)); +@@ -2029,7 +2094,7 @@ static const struct rockchip_usb2phy_cfg rk3399_phy_cfgs[] = { + } + }, + .chg_det = { +- .opmode = { 0xe454, 3, 0, 5, 1 }, ++ .chg_mode = { 0xe454, 8, 0, 0, 0x1d7 }, + .cp_det = { 0xe2ac, 2, 2, 0, 1 }, + .dcp_det = { 0xe2ac, 1, 1, 0, 1 }, + .dp_det = { 0xe2ac, 0, 0, 0, 1 }, +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0048-usb-dwc3-Do-not-re-register-the-gadget-on-cable-even.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0048-usb-dwc3-Do-not-re-register-the-gadget-on-cable-even.patch new file mode 100644 index 000000000..6bf86173c --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0048-usb-dwc3-Do-not-re-register-the-gadget-on-cable-even.patch @@ -0,0 +1,106 @@ +From 9d5233641333d58478d65d40101e36fdf2c8bbac Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Mon, 20 Jul 2026 23:15:39 +0200 +Subject: [PATCH 48/84] usb: dwc3: Do not re-register the gadget on cable + events + +The role init and exit ended up with different conditions: init ran for +a role change or a connected cable, exit only for a role that was +entered while connected. After a boot with nothing plugged in the role +is entered but marked disconnected, so the next plug took the init path +again without ever having taken the exit path, and the gadget was added +twice: + + kobject: kobject_add_internal failed for fe800000.usb with -EEXIST + dwc3 fe800000.usb: failed to add gadget + +Entering and leaving a role is what registers and unregisters the gadget +or the host, so drive it purely from the role, as upstream does. A cable +coming or going does not change the role, so park the controller instead +the way the runtime PM path already does: soft disconnect and drop the +event buffers before the reset window, then soft reset, restore the +event buffers and soft connect after it. + +The UDC is now registered exactly once, at probe, and stays registered. +Only its pullup follows the cable. That also stops usb_del_gadget() and +usb_add_gadget() from running on every plug and unplug, which was taking +seconds at a time under dwc->mutex. + +Fixup for "usb: dwc3: Register the role even when no cable is +connected". + +Signed-off-by: Ondrej Jirman +(cherry picked from commit d0b96cd58562bb50012a08ab1bd44389abfd8c28) +--- + drivers/usb/dwc3/core.c | 40 +++++++++++++++++++++++++++------------- + 1 file changed, 27 insertions(+), 13 deletions(-) + +diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c +index 0e20e70b9163..18d50856d3b6 100644 +--- a/drivers/usb/dwc3/core.c ++++ b/drivers/usb/dwc3/core.c +@@ -197,10 +197,19 @@ static void __dwc3_set_mode(struct work_struct *work) + role_changed = desired_dr_role != dwc->current_dr_role; + + /* +- * Nothing was brought up for a role entered while no cable was +- * connected, so there is nothing to tear down either. ++ * Entering and leaving a role registers and unregisters the gadget or ++ * the host, so it has to follow the role and nothing else. A cable ++ * coming or going does not change the role, and must not take the UDC ++ * away from userspace: the controller is parked below instead, the way ++ * the runtime PM path does it. + */ +- switch (dwc->current_dr_connected ? dwc->current_dr_role : 0) { ++ if (!role_changed && dwc->current_dr_role == DWC3_GCTL_PRTCAP_DEVICE && ++ dwc->current_dr_connected) { ++ dwc3_gadget_suspend(dwc); ++ dwc3_event_buffers_cleanup(dwc); ++ } ++ ++ switch (role_changed ? dwc->current_dr_role : 0) { + case DWC3_GCTL_PRTCAP_HOST: + dwc3_host_exit(dwc); + break; +@@ -291,16 +300,7 @@ static void __dwc3_set_mode(struct work_struct *work) + + spin_unlock_irqrestore(&dwc->lock, flags); + +- /* +- * Entering a role registers the gadget or the host, which has to happen +- * even with no cable connected so that userspace can bind a gadget +- * driver to the UDC before anything is plugged in. +- * +- * A connection change within the same role is different: the USB3 PHY +- * has just been powered off, so there is nothing to bring up on top of +- * it, and the role is already entered anyway. +- */ +- switch (desired_dr_connected || role_changed ? desired_dr_role : 0) { ++ switch (role_changed ? desired_dr_role : 0) { + case DWC3_GCTL_PRTCAP_HOST: + ret = dwc3_host_init(dwc); + if (ret) { +@@ -343,6 +343,20 @@ static void __dwc3_set_mode(struct work_struct *work) + break; + } + ++ /* ++ * GCTL.CoreSoftReset above wiped the controller state, so put it back ++ * for a cable that just showed up. The gadget stays registered ++ * throughout, only its pullup follows the cable. ++ */ ++ if (!role_changed && desired_dr_role == DWC3_GCTL_PRTCAP_DEVICE && ++ desired_dr_connected) { ++ dwc3_core_soft_reset(dwc); ++ dwc3_event_buffers_setup(dwc); ++ phy_set_mode(dwc->usb2_generic_phy[0], PHY_MODE_USB_DEVICE); ++ phy_set_mode(dwc->usb3_generic_phy[0], PHY_MODE_USB_DEVICE); ++ dwc3_gadget_resume(dwc); ++ } ++ + out: + pm_runtime_put_autosuspend(dwc->dev); + mutex_unlock(&dwc->mutex); +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0049-phy-rockchip-typec-Support-a-Type-C-orientation-swit.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0049-phy-rockchip-typec-Support-a-Type-C-orientation-swit.patch new file mode 100644 index 000000000..2218099eb --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0049-phy-rockchip-typec-Support-a-Type-C-orientation-swit.patch @@ -0,0 +1,150 @@ +From bedb89fb5c6876434dad80435ede0a71f55f446a Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Mon, 20 Jul 2026 23:39:05 +0200 +Subject: [PATCH 49/84] phy: rockchip-typec: Support a Type-C orientation + switch + +Register a typec_switch when the DT node is marked as one, and take the +plug orientation from it rather than the extcon polarity property. + +The property can only be read at power_on() time, and only once the +extcon provider has published it; a switch lets the port manager hand the +orientation over whenever it knows it. This is the API RK3588's +phy-rockchip-usbdp.c already uses. Boards that do not mark the node keep +reading the extcon property. + +Keep the last orientation on TYPEC_ORIENTATION_NONE, which only says the +cable is gone: the PHY is powered off through phy_power_off() then, so +there is no reason to clear it to a value nothing should read. + +Signed-off-by: Ondrej Jirman +(cherry picked from commit ba3d9cfa99e2ba9a5543aaef821faa82187c1ac8) +--- + drivers/phy/rockchip/phy-rockchip-typec.c | 80 +++++++++++++++++++++-- + 1 file changed, 73 insertions(+), 7 deletions(-) + +diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c +index d9701b6106d5..717015f33364 100644 +--- a/drivers/phy/rockchip/phy-rockchip-typec.c ++++ b/drivers/phy/rockchip/phy-rockchip-typec.c +@@ -49,11 +49,13 @@ + #include + #include + #include ++#include + #include + #include + + #include + #include ++#include + + #define CMN_SSM_BANDGAP (0x21 << 2) + #define CMN_SSM_BIAS (0x22 << 2) +@@ -384,6 +386,14 @@ struct rockchip_typec_phy { + + bool flip; + u8 mode; ++ ++ /* ++ * Optional Type-C orientation switch. When one is registered the plug ++ * orientation is taken from it instead of from the extcon polarity ++ * property, so that it no longer has to be re-read on every power_on. ++ */ ++ struct typec_switch_dev *sw; ++ bool sw_flip; + }; + + struct phy_reg { +@@ -838,18 +848,68 @@ static int tcphy_get_mode(struct rockchip_typec_phy *tcphy) + mode |= MODE_DFP_USB; + } + +- ret = extcon_get_property(edev, id, EXTCON_PROP_USB_TYPEC_POLARITY, +- &property); +- if (ret) { +- dev_err(tcphy->dev, "get polarity property failed\n"); +- return ret; +- } ++ if (tcphy->sw) { ++ tcphy->flip = tcphy->sw_flip; ++ } else { ++ ret = extcon_get_property(edev, id, ++ EXTCON_PROP_USB_TYPEC_POLARITY, ++ &property); ++ if (ret) { ++ dev_err(tcphy->dev, "get polarity property failed\n"); ++ return ret; ++ } + +- tcphy->flip = property.intval ? 1 : 0; ++ tcphy->flip = property.intval ? 1 : 0; ++ } + + return mode; + } + ++static int tcphy_orien_sw_set(struct typec_switch_dev *sw, ++ enum typec_orientation orien) ++{ ++ struct rockchip_typec_phy *tcphy = typec_switch_get_drvdata(sw); ++ ++ mutex_lock(&tcphy->lock); ++ ++ /* ++ * TYPEC_ORIENTATION_NONE only means the cable is gone. The PHY is ++ * powered off through phy_power_off() in that case, and the last ++ * orientation is kept so that nothing reads a stale value from a ++ * half-updated state. ++ */ ++ if (orien != TYPEC_ORIENTATION_NONE) ++ tcphy->sw_flip = orien == TYPEC_ORIENTATION_REVERSE; ++ ++ mutex_unlock(&tcphy->lock); ++ ++ return 0; ++} ++ ++static void tcphy_orien_switch_unregister(void *data) ++{ ++ struct rockchip_typec_phy *tcphy = data; ++ ++ typec_switch_unregister(tcphy->sw); ++} ++ ++static int tcphy_setup_orien_switch(struct rockchip_typec_phy *tcphy) ++{ ++ struct typec_switch_desc sw_desc = { }; ++ ++ sw_desc.drvdata = tcphy; ++ sw_desc.fwnode = dev_fwnode(tcphy->dev); ++ sw_desc.set = tcphy_orien_sw_set; ++ ++ tcphy->sw = typec_switch_register(tcphy->dev, &sw_desc); ++ if (IS_ERR(tcphy->sw)) ++ return dev_err_probe(tcphy->dev, PTR_ERR(tcphy->sw), ++ "failed to register orientation switch\n"); ++ ++ return devm_add_action_or_reset(tcphy->dev, ++ tcphy_orien_switch_unregister, tcphy); ++} ++ + static int tcphy_cfg_usb3_to_usb2_only(struct rockchip_typec_phy *tcphy, + bool value) + { +@@ -1158,6 +1218,12 @@ static int rockchip_typec_phy_probe(struct platform_device *pdev) + } + } + ++ if (device_property_present(dev, "orientation-switch")) { ++ ret = tcphy_setup_orien_switch(tcphy); ++ if (ret) ++ return ret; ++ } ++ + pm_runtime_enable(dev); + + for_each_available_child_of_node(np, child_np) { +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0050-phy-rockchip-typec-Support-a-Type-C-mode-mux.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0050-phy-rockchip-typec-Support-a-Type-C-mode-mux.patch new file mode 100644 index 000000000..4a7973caf --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0050-phy-rockchip-typec-Support-a-Type-C-mode-mux.patch @@ -0,0 +1,225 @@ +From 0690ea7581e1b3d7a07d92f291874d423d7b5e5b Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Mon, 20 Jul 2026 23:50:24 +0200 +Subject: [PATCH 50/84] phy: rockchip-typec: Support a Type-C mode mux + +Register a typec_mux when the DT node is marked as one, and take what the +lanes carry from it. Map TYPEC_STATE_USB, TYPEC_DP_STATE_C/E and +TYPEC_DP_STATE_D onto the existing MODE_DFP_USB, MODE_DFP_DP and the +combination of both. + +This was read from the extcon cables at power_on() time, too late for a +port manager that has already negotiated an alternate mode, and a mux is +in any case what alternate mode switching goes through. Boards with no mux +keep reading the extcon cables. + +The mux does not carry the USB data role, and this driver does not need +it: MODE_UFP_USB and MODE_DFP_USB are only ever tested together, so +report USB as MODE_DFP_USB throughout. + +Signed-off-by: Ondrej Jirman +(cherry picked from commit f7dfd3a3fec221817aa35d3ec00130fe5dd5b998) +--- + drivers/phy/rockchip/phy-rockchip-typec.c | 145 +++++++++++++++++----- + 1 file changed, 117 insertions(+), 28 deletions(-) + +diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c +index 717015f33364..25e89ce7856e 100644 +--- a/drivers/phy/rockchip/phy-rockchip-typec.c ++++ b/drivers/phy/rockchip/phy-rockchip-typec.c +@@ -55,6 +55,7 @@ + + #include + #include ++#include + #include + + #define CMN_SSM_BANDGAP (0x21 << 2) +@@ -394,6 +395,15 @@ struct rockchip_typec_phy { + */ + struct typec_switch_dev *sw; + bool sw_flip; ++ ++ /* ++ * Optional Type-C mode mux. When one is registered it says what the ++ * lanes carry, so the extcon cables no longer have to be read for it. ++ * Starts out as MODE_DFP_USB, which is what the extcon path falls back ++ * to when it has been told nothing yet. ++ */ ++ struct typec_mux_dev *mux; ++ u8 mux_mode; + }; + + struct phy_reg { +@@ -817,40 +827,44 @@ static int tcphy_get_mode(struct rockchip_typec_phy *tcphy) + { + struct extcon_dev *edev = tcphy->extcon; + union extcon_property_value property; +- unsigned int id; +- u8 mode; +- int ret, ufp, dp; +- +- if (!edev) +- return MODE_DFP_USB; +- +- ufp = extcon_get_state(edev, EXTCON_USB); +- dp = extcon_get_state(edev, EXTCON_DISP_DP); ++ unsigned int id = EXTCON_USB_HOST; ++ u8 mode = MODE_DFP_USB; ++ int ret; + +- mode = MODE_DFP_USB; +- id = EXTCON_USB_HOST; +- +- if (ufp > 0) { +- mode = MODE_UFP_USB; +- id = EXTCON_USB; +- } else if (dp > 0) { +- mode = MODE_DFP_DP; +- id = EXTCON_DISP_DP; +- +- ret = extcon_get_property(edev, id, EXTCON_PROP_USB_SS, +- &property); +- if (ret) { +- dev_err(tcphy->dev, "get superspeed property failed\n"); +- return ret; ++ /* ++ * A Type-C mode mux and orientation switch each replace one half of ++ * what would otherwise be read from extcon, so a board can be wired ++ * either way, or both ways during a conversion. ++ */ ++ if (tcphy->mux) { ++ mode = tcphy->mux_mode; ++ id = mode & MODE_DFP_DP ? EXTCON_DISP_DP : EXTCON_USB_HOST; ++ } else if (edev) { ++ int ufp = extcon_get_state(edev, EXTCON_USB); ++ int dp = extcon_get_state(edev, EXTCON_DISP_DP); ++ ++ if (ufp > 0) { ++ mode = MODE_UFP_USB; ++ id = EXTCON_USB; ++ } else if (dp > 0) { ++ mode = MODE_DFP_DP; ++ id = EXTCON_DISP_DP; ++ ++ ret = extcon_get_property(edev, id, EXTCON_PROP_USB_SS, ++ &property); ++ if (ret) { ++ dev_err(tcphy->dev, "get superspeed property failed\n"); ++ return ret; ++ } ++ ++ if (property.intval) ++ mode |= MODE_DFP_USB; + } +- +- if (property.intval) +- mode |= MODE_DFP_USB; + } + + if (tcphy->sw) { + tcphy->flip = tcphy->sw_flip; +- } else { ++ } else if (edev) { + ret = extcon_get_property(edev, id, + EXTCON_PROP_USB_TYPEC_POLARITY, + &property); +@@ -910,6 +924,74 @@ static int tcphy_setup_orien_switch(struct rockchip_typec_phy *tcphy) + tcphy_orien_switch_unregister, tcphy); + } + ++static int tcphy_mux_set(struct typec_mux_dev *mux, ++ struct typec_mux_state *state) ++{ ++ struct rockchip_typec_phy *tcphy = typec_mux_get_drvdata(mux); ++ bool is_dp = state->alt && state->alt->svid == USB_TYPEC_DP_SID; ++ u8 mode; ++ ++ /* ++ * The mux does not carry the data role, and this driver does not care ++ * about it: MODE_UFP_USB and MODE_DFP_USB are only ever tested ++ * together. Report USB as MODE_DFP_USB throughout. ++ */ ++ switch (state->mode) { ++ case TYPEC_STATE_SAFE: ++ mode = MODE_DISCONNECT; ++ break; ++ case TYPEC_STATE_USB: ++ mode = MODE_DFP_USB; ++ break; ++ case TYPEC_DP_STATE_C: ++ case TYPEC_DP_STATE_E: ++ if (!is_dp) ++ return 0; ++ /* four lanes of DP, no USB SuperSpeed */ ++ mode = MODE_DFP_DP; ++ break; ++ case TYPEC_DP_STATE_D: ++ if (!is_dp) ++ return 0; ++ /* two lanes of DP alongside USB SuperSpeed */ ++ mode = MODE_DFP_DP | MODE_DFP_USB; ++ break; ++ default: ++ dev_warn(tcphy->dev, "unhandled mux mode %lu\n", state->mode); ++ return 0; ++ } ++ ++ mutex_lock(&tcphy->lock); ++ tcphy->mux_mode = mode; ++ mutex_unlock(&tcphy->lock); ++ ++ return 0; ++} ++ ++static void tcphy_mux_unregister(void *data) ++{ ++ struct rockchip_typec_phy *tcphy = data; ++ ++ typec_mux_unregister(tcphy->mux); ++} ++ ++static int tcphy_setup_mux(struct rockchip_typec_phy *tcphy) ++{ ++ struct typec_mux_desc mux_desc = { }; ++ ++ mux_desc.drvdata = tcphy; ++ mux_desc.fwnode = dev_fwnode(tcphy->dev); ++ mux_desc.set = tcphy_mux_set; ++ ++ tcphy->mux = typec_mux_register(tcphy->dev, &mux_desc); ++ if (IS_ERR(tcphy->mux)) ++ return dev_err_probe(tcphy->dev, PTR_ERR(tcphy->mux), ++ "failed to register mode mux\n"); ++ ++ return devm_add_action_or_reset(tcphy->dev, tcphy_mux_unregister, ++ tcphy); ++} ++ + static int tcphy_cfg_usb3_to_usb2_only(struct rockchip_typec_phy *tcphy, + bool value) + { +@@ -1153,6 +1235,7 @@ static void typec_phy_pre_init(struct rockchip_typec_phy *tcphy) + property_enable(tcphy, &cfg->usb3tousb2_en, 0); + + tcphy->mode = MODE_DISCONNECT; ++ tcphy->mux_mode = MODE_DFP_USB; + } + + static int rockchip_typec_phy_probe(struct platform_device *pdev) +@@ -1224,6 +1307,12 @@ static int rockchip_typec_phy_probe(struct platform_device *pdev) + return ret; + } + ++ if (device_property_present(dev, "mode-switch")) { ++ ret = tcphy_setup_mux(tcphy); ++ if (ret) ++ return ret; ++ } ++ + pm_runtime_enable(dev); + + for_each_available_child_of_node(np, child_np) { +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0051-phy-rockchip-typec-Publish-the-DP-lane-count.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0051-phy-rockchip-typec-Publish-the-DP-lane-count.patch new file mode 100644 index 000000000..4819948b2 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0051-phy-rockchip-typec-Publish-the-DP-lane-count.patch @@ -0,0 +1,106 @@ +From c5d1fecc501008af68641d44c93b8bb81cceca5f Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Tue, 21 Jul 2026 23:15:20 +0200 +Subject: [PATCH 51/84] phy: rockchip-typec: Publish the DP lane count + +Publish the negotiated lane count from the mode mux with +phy_set_bus_width(): four lanes for DP alone, two when it shares the +connector with USB SuperSpeed, and zero whenever the lanes carry USB or +no sink has raised HPD. + +The DP controller sits behind this PHY and is the one the mux configures, +so it has no other way to learn how many lanes it was left; it reads the +count back over the phandle it already holds. Zero doubles as "nothing to +drive", sparing it from telling "no alternate mode" from "alternate mode +without a sink". + +Signed-off-by: Ondrej Jirman +(cherry picked from commit 23febe23e8959ed5219186aa6892d8b42268fd18) +--- + drivers/phy/rockchip/phy-rockchip-typec.c | 28 ++++++++++++++++++++++- + 1 file changed, 27 insertions(+), 1 deletion(-) + +diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c +index 25e89ce7856e..989274f456b9 100644 +--- a/drivers/phy/rockchip/phy-rockchip-typec.c ++++ b/drivers/phy/rockchip/phy-rockchip-typec.c +@@ -404,6 +404,13 @@ struct rockchip_typec_phy { + */ + struct typec_mux_dev *mux; + u8 mux_mode; ++ ++ /* ++ * The DP PHY, kept so that the lane count the alternate mode settled ++ * on can be published on it. The DP controller sits behind this PHY ++ * and has no other way of learning how many lanes it was left. ++ */ ++ struct phy *dp_phy; + }; + + struct phy_reg { +@@ -929,6 +936,8 @@ static int tcphy_mux_set(struct typec_mux_dev *mux, + { + struct rockchip_typec_phy *tcphy = typec_mux_get_drvdata(mux); + bool is_dp = state->alt && state->alt->svid == USB_TYPEC_DP_SID; ++ struct typec_displayport_data *data; ++ u8 lanes = 0; + u8 mode; + + /* +@@ -949,12 +958,18 @@ static int tcphy_mux_set(struct typec_mux_dev *mux, + return 0; + /* four lanes of DP, no USB SuperSpeed */ + mode = MODE_DFP_DP; ++ data = state->data; ++ if (data->status & DP_STATUS_HPD_STATE) ++ lanes = 4; + break; + case TYPEC_DP_STATE_D: + if (!is_dp) + return 0; + /* two lanes of DP alongside USB SuperSpeed */ + mode = MODE_DFP_DP | MODE_DFP_USB; ++ data = state->data; ++ if (data->status & DP_STATUS_HPD_STATE) ++ lanes = 2; + break; + default: + dev_warn(tcphy->dev, "unhandled mux mode %lu\n", state->mode); +@@ -965,6 +980,13 @@ static int tcphy_mux_set(struct typec_mux_dev *mux, + tcphy->mux_mode = mode; + mutex_unlock(&tcphy->lock); + ++ /* ++ * Publish the lane count on the DP PHY. Zero means the DP controller ++ * has nothing to drive, either because the lanes carry USB or because ++ * no sink has raised HPD yet. ++ */ ++ phy_set_bus_width(tcphy->dp_phy, lanes); ++ + return 0; + } + +@@ -1317,8 +1339,9 @@ static int rockchip_typec_phy_probe(struct platform_device *pdev) + + for_each_available_child_of_node(np, child_np) { + struct phy *phy; ++ bool is_dp = of_node_name_eq(child_np, "dp-port"); + +- if (of_node_name_eq(child_np, "dp-port")) ++ if (is_dp) + phy = devm_phy_create(dev, child_np, + &rockchip_dp_phy_ops); + else if (of_node_name_eq(child_np, "usb3-port")) +@@ -1336,6 +1359,9 @@ static int rockchip_typec_phy_probe(struct platform_device *pdev) + } + + phy_set_drvdata(phy, tcphy); ++ ++ if (is_dp) ++ tcphy->dp_phy = phy; + } + + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0052-drm-rockchip-cdn-dp-Support-ports-driven-by-a-Type-C.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0052-drm-rockchip-cdn-dp-Support-ports-driven-by-a-Type-C.patch new file mode 100644 index 000000000..9bb437d43 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0052-drm-rockchip-cdn-dp-Support-ports-driven-by-a-Type-C.patch @@ -0,0 +1,169 @@ +From dde8b3728ec4e6844e479e989e6492cbda1074c1 Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Tue, 21 Jul 2026 23:17:37 +0200 +Subject: [PATCH 52/84] drm/rockchip: cdn-dp: Support ports driven by a Type-C + PHY + +Support a Type-C port whose lanes reach the connector through a Type-C +PHY. Take the lane count from the PHY with phy_get_bus_width(), where zero +means nothing to drive, and take the alternate mode's HPD out of band +through the bridge's hpd_notify, which drm_connector_oob_hotplug_event() +feeds from the DP altmode driver. Orientation needs no handling: the PHY +reverses the lanes itself, so the controller sees them in order. + +Nothing publishes extcon cables on such a port, which is all the driver +otherwise reads a Type-C port from, so probe skipped it for want of an +extcon and a board with no other port failed to bind with "missing extcon +or phy". + +A port now needs a PHY and nothing else. Ports that have an extcon keep +reading all of it from there. + +Signed-off-by: Ondrej Jirman +(cherry picked from commit a0dfa262516e05183118110165ce9744e07ab95f) +--- + drivers/gpu/drm/rockchip/cdn-dp-core.c | 69 ++++++++++++++++++++++---- + 1 file changed, 60 insertions(+), 9 deletions(-) + +diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c +index 13b83fe8feed..08257a3d1dbd 100644 +--- a/drivers/gpu/drm/rockchip/cdn-dp-core.c ++++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c +@@ -157,6 +157,15 @@ static int cdn_dp_get_port_lanes(struct cdn_dp_port *port) + int dptx; + u8 lanes; + ++ /* ++ * A port that has no extcon is driven by a Type-C PHY, which publishes ++ * how many lanes the alternate mode left for DP. Zero of them means ++ * there is nothing to drive, either because the lanes carry USB or ++ * because no sink has raised HPD. ++ */ ++ if (!edev) ++ return phy_get_bus_width(port->phy); ++ + dptx = extcon_get_state(edev, EXTCON_DISP_DP); + if (dptx > 0) { + extcon_get_property(edev, EXTCON_DISP_DP, +@@ -220,7 +229,7 @@ static bool cdn_dp_check_sink_connection(struct cdn_dp_device *dp) + * some docks need more time to power up. + */ + while (time_before(jiffies, timeout)) { +- if (!extcon_get_state(port->extcon, EXTCON_DISP_DP)) ++ if (!cdn_dp_get_port_lanes(port)) + return false; + + if (!cdn_dp_get_sink_count(dp, &sink_count)) +@@ -360,6 +369,7 @@ static int cdn_dp_get_sink_capability(struct cdn_dp_device *dp) + static int cdn_dp_enable_phy(struct cdn_dp_device *dp, struct cdn_dp_port *port) + { + union extcon_property_value property; ++ bool flip; + int ret; + + if (!port->phy_enabled) { +@@ -386,15 +396,26 @@ static int cdn_dp_enable_phy(struct cdn_dp_device *dp, struct cdn_dp_port *port) + goto err_power_on; + } + +- ret = extcon_get_property(port->extcon, EXTCON_DISP_DP, +- EXTCON_PROP_USB_TYPEC_POLARITY, &property); +- if (ret) { +- DRM_DEV_ERROR(dp->dev, "get property failed\n"); +- goto err_power_on; ++ if (port->extcon) { ++ ret = extcon_get_property(port->extcon, EXTCON_DISP_DP, ++ EXTCON_PROP_USB_TYPEC_POLARITY, ++ &property); ++ if (ret) { ++ DRM_DEV_ERROR(dp->dev, "get property failed\n"); ++ goto err_power_on; ++ } ++ ++ flip = property.intval; ++ } else { ++ /* ++ * A Type-C PHY reverses the lanes itself when the plug is ++ * upside down, so the controller always sees them in order. ++ */ ++ flip = false; + } + + port->lanes = cdn_dp_get_port_lanes(port); +- ret = cdn_dp_set_host_cap(dp, port->lanes, property.intval); ++ ret = cdn_dp_set_host_cap(dp, port->lanes, flip); + if (ret) { + DRM_DEV_ERROR(dp->dev, "set host capabilities failed: %d\n", + ret); +@@ -822,11 +843,34 @@ static int cdn_dp_audio_mute_stream(struct drm_bridge *bridge, + return ret; + } + ++/* ++ * A port driven by a Type-C PHY has no extcon to notify us, so the alternate ++ * mode's HPD arrives out of band instead: the DP alt mode driver resolves the ++ * connector's displayport phandle to this bridge and reports it here. ++ * ++ * cdn_dp_pd_event_work() finishes by reporting the state it settled on, which ++ * comes back through this same path. Only act on a status that disagrees with ++ * what we already concluded, or the two would keep waking each other. ++ */ ++static void cdn_dp_bridge_hpd_notify(struct drm_bridge *bridge, ++ struct drm_connector *connector, ++ enum drm_connector_status status) ++{ ++ struct cdn_dp_device *dp = bridge_to_dp(bridge); ++ bool connected = status == connector_status_connected; ++ ++ if (dp->connected == connected) ++ return; ++ ++ schedule_work(&dp->event_work); ++} ++ + static const struct drm_bridge_funcs cdn_dp_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, + .detect = cdn_dp_bridge_detect, ++ .hpd_notify = cdn_dp_bridge_hpd_notify, + .edid_read = cdn_dp_bridge_edid_read, + .atomic_enable = cdn_dp_bridge_atomic_enable, + .atomic_disable = cdn_dp_bridge_atomic_disable, +@@ -1030,6 +1074,9 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data) + for (i = 0; i < dp->ports; i++) { + port = dp->port[i]; + ++ if (!port->extcon) ++ continue; ++ + port->event_nb.notifier_call = cdn_dp_pd_event; + ret = devm_extcon_register_notifier(dp->dev, port->extcon, + EXTCON_DISP_DP, +@@ -1122,9 +1169,13 @@ static int cdn_dp_probe(struct platform_device *pdev) + PTR_ERR(phy) == -EPROBE_DEFER) + return -EPROBE_DEFER; + +- if (IS_ERR(extcon) || IS_ERR(phy)) ++ if (IS_ERR(phy)) + continue; + ++ /* Type-C PHY driven ports have no extcon. */ ++ if (IS_ERR(extcon)) ++ extcon = NULL; ++ + port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); + if (!port) + return -ENOMEM; +@@ -1137,7 +1188,7 @@ static int cdn_dp_probe(struct platform_device *pdev) + } + + if (!dp->ports) { +- DRM_DEV_ERROR(dev, "missing extcon or phy\n"); ++ DRM_DEV_ERROR(dev, "missing phy\n"); + return -EINVAL; + } + +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0053-phy-rockchip-inno-usb2-Learn-the-host-role-from-phy_.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0053-phy-rockchip-inno-usb2-Learn-the-host-role-from-phy_.patch new file mode 100644 index 000000000..c2b005a55 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0053-phy-rockchip-inno-usb2-Learn-the-host-role-from-phy_.patch @@ -0,0 +1,141 @@ +From 642e715b3a43fe3a73dfb1f4a01e28f57916e72f Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Tue, 21 Jul 2026 00:20:41 +0200 +Subject: [PATCH 53/84] phy: rockchip-inno-usb2: Learn the host role from + phy_set_mode() + +The OTG state machine finds out whether the port is acting as a host by +reading EXTCON_USB_HOST. That only works when something else supplies +the extcon device and writes to it; when this driver registers its own, +the only writer is its own ID pin handling, which nothing outside can +see, so a board with no ID pin has no way to reach OTG_STATE_A_HOST. + +Take the role from phy_set_mode() in that case. The controller already +calls it on every role change, so the information is there for the +asking, and on a Type-C board it comes from the port manager rather than +having to be routed back in through an extcon device. + +Boards with an extcon phandle keep reading EXTCON_USB_HOST and are not +affected. Boards without one cannot regress either: nothing consumed the +EXTCON_USB_HOST this driver published to its own extcon device, so the +ID pin never reached the controller there to begin with. + +Signed-off-by: Ondrej Jirman +(cherry picked from commit 9d26be6b0bb1456a25fc39aa91dcaaa072c8bbad) +--- + drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 59 ++++++++++++++++++- + 1 file changed, 57 insertions(+), 2 deletions(-) + +diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +index a138417f0b2e..63acee6a4310 100644 +--- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c ++++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +@@ -229,6 +229,7 @@ struct rockchip_usb2phy_port { + struct notifier_block event_nb; + enum usb_otg_state state; + enum usb_dr_mode mode; ++ bool host_mode; + }; + + /** +@@ -267,6 +268,8 @@ struct rockchip_usb2phy { + u8 dcd_retries; + unsigned int chg_mode_cfg; + struct extcon_dev *edev; ++ /* the extcon device came from a phandle rather than being ours */ ++ bool edev_external; + int irq; + const struct rockchip_usb2phy_cfg *phy_cfg; + struct rockchip_usb2phy_port ports[USB2PHY_NUM_PORTS]; +@@ -456,6 +459,7 @@ static int rockchip_usb2phy_extcon_register(struct rockchip_usb2phy *rphy) + if (IS_ERR(edev)) + return dev_err_probe(rphy->dev, PTR_ERR(edev), + "invalid or missing extcon\n"); ++ rphy->edev_external = true; + } else { + /* Initialize extcon device */ + edev = devm_extcon_dev_allocate(rphy->dev, +@@ -659,11 +663,62 @@ static int rockchip_usb2phy_exit(struct phy *phy) + return 0; + } + ++/* ++ * Whether the OTG port is acting as a host. ++ * ++ * With an extcon device supplied by someone else, EXTCON_USB_HOST is what ++ * says so, either driven by a Type-C port manager or looped back from this ++ * driver's own ID pin handling. Otherwise nothing external writes to our ++ * extcon device and the controller tells us instead, through phy_set_mode(). ++ */ ++static bool rockchip_usb2phy_host_mode(struct rockchip_usb2phy *rphy, ++ struct rockchip_usb2phy_port *rport) ++{ ++ if (!rphy->edev_external) ++ return rport->host_mode; ++ ++ return extcon_get_state(rphy->edev, EXTCON_USB_HOST) > 0; ++} ++ ++static int rockchip_usb2phy_set_mode(struct phy *phy, enum phy_mode mode, ++ int submode) ++{ ++ struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy); ++ struct rockchip_usb2phy *rphy = dev_get_drvdata(phy->dev.parent); ++ bool host_mode; ++ ++ if (rport->port_id != USB2PHY_PORT_OTG || rphy->edev_external) ++ return 0; ++ ++ switch (mode) { ++ case PHY_MODE_USB_HOST: ++ host_mode = true; ++ break; ++ case PHY_MODE_USB_DEVICE: ++ host_mode = false; ++ break; ++ default: ++ return 0; ++ } ++ ++ if (rport->host_mode == host_mode) ++ return 0; ++ ++ dev_err(&rport->phy->dev, "U2PHY set_mode: host=%d\n", host_mode); ++ rport->host_mode = host_mode; ++ ++ /* let the state machine act on the new role */ ++ mod_delayed_work(system_wq, &rport->otg_sm_work, 0); ++ ++ return 0; ++} ++ + static const struct phy_ops rockchip_usb2phy_ops = { + .init = rockchip_usb2phy_init, + .exit = rockchip_usb2phy_exit, + .power_on = rockchip_usb2phy_power_on, + .power_off = rockchip_usb2phy_power_off, ++ .set_mode = rockchip_usb2phy_set_mode, + .owner = THIS_MODULE, + }; + +@@ -699,7 +754,7 @@ static void rockchip_usb2phy_otg_sm_work(struct work_struct *work) + rockchip_usb2phy_power_off(rport->phy); + fallthrough; + case OTG_STATE_B_IDLE: +- if (extcon_get_state(rphy->edev, EXTCON_USB_HOST) > 0) { ++ if (rockchip_usb2phy_host_mode(rphy, rport)) { + dev_dbg(&rport->phy->dev, "usb otg host connect\n"); + rport->state = OTG_STATE_A_HOST; + rockchip_usb2phy_power_on(rport->phy); +@@ -774,7 +829,7 @@ static void rockchip_usb2phy_otg_sm_work(struct work_struct *work) + sch_work = true; + break; + case OTG_STATE_A_HOST: +- if (extcon_get_state(rphy->edev, EXTCON_USB_HOST) == 0) { ++ if (!rockchip_usb2phy_host_mode(rphy, rport)) { + dev_dbg(&rport->phy->dev, "usb otg host disconnect\n"); + rport->state = OTG_STATE_B_IDLE; + rockchip_usb2phy_power_off(rport->phy); +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0054-usb-dwc3-Tell-the-UDC-core-when-there-is-no-cable.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0054-usb-dwc3-Tell-the-UDC-core-when-there-is-no-cable.patch new file mode 100644 index 000000000..11a8a75e9 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0054-usb-dwc3-Tell-the-UDC-core-when-there-is-no-cable.patch @@ -0,0 +1,102 @@ +From 8a289a732202204e0c19c6f38da071d3b4e96f7a Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Tue, 21 Jul 2026 07:22:48 +0200 +Subject: [PATCH 54/84] usb: dwc3: Tell the UDC core when there is no cable + +The USB3 PHY is powered off while no cable is connected, so anything +that touches the endpoints in that state fails. Binding a gadget driver +does exactly that: the UDC core pulls up as soon as a driver binds, +because udc->vbus starts out true and nothing ever says otherwise, and +the pullup runs __dwc3_gadget_start() against the powered off PHY: + + dwc3 fe800000.usb: failed to enable ep0out + +Report the connection state with usb_udc_vbus_handler() so the core only +pulls up when there is a cable. That also replaces the +dwc3_gadget_suspend()/dwc3_gadget_resume() pair that was approximating +it: the pullup is what has to follow the cable, and the core already +knows how to do that, including for a driver that binds later while +still disconnected. + +usb_udc_vbus_handler() only records the new state and schedules the +pullup change to a workqueue, though, while __dwc3_set_mode() goes +straight on with the teardown: event buffers freed, GCTL.CORESOFTRESET +asserted for 100ms and the USB3 PHY powered off. A soft disconnect +scheduled at unplug races into that window and runs against a core held +in reset with its PHY clocks gone: the endpoint end transfer commands +read back fake completions, the DCTL/DSTS/DEVTEN accesses are lost, and +the controller is left in a state even the DCTL.CSFTRST on the next +plug-in does not recover from. The next session then comes up with a +mute ep0 (host: 'Device not responding to setup address') and a stuck +event interrupt that ends in a softirq lockup and 'irq: nobody cared'. + +So change the pullup synchronously with the cable state on top of the +bookkeeping: usb_gadget_disconnect() before touching the event buffers, +the core reset or the PHY power, and usb_gadget_connect() after the +core is set back up. The scheduled work then finds the pullup already +in the requested state and does nothing. Both directions serialize on +the UDC connect lock, so a quick unplug also waits for an in-flight +connect instead of resetting the core under it. + +Signed-off-by: Ondrej Jirman +(cherry picked from commit 406dea5dc6471bc2d8809df426f32445ed1d39a1) +--- + drivers/usb/dwc3/core.c | 35 ++++++++++++++++++++++++++++++++--- + 1 file changed, 32 insertions(+), 3 deletions(-) + +diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c +index 18d50856d3b6..2c1cada5d637 100644 +--- a/drivers/usb/dwc3/core.c ++++ b/drivers/usb/dwc3/core.c +@@ -204,8 +204,20 @@ static void __dwc3_set_mode(struct work_struct *work) + * the runtime PM path does it. + */ + if (!role_changed && dwc->current_dr_role == DWC3_GCTL_PRTCAP_DEVICE && +- dwc->current_dr_connected) { +- dwc3_gadget_suspend(dwc); ++ dwc->current_dr_connected && dwc->gadget) { ++ /* ++ * usb_udc_vbus_handler() only records the state and schedules ++ * the pullup change for later, but the controller reset and ++ * PHY power off below must not run while the gadget is still ++ * live: the soft disconnect (endpoint end transfer commands, ++ * DCTL/DEVTEN writes) would then hit a core that is held in ++ * reset with its PHY clocks gone, be silently lost, and leave ++ * the controller in a state the next plug-in cannot recover ++ * from. Stop the gadget synchronously first; the scheduled ++ * work then finds nothing left to do. ++ */ ++ usb_udc_vbus_handler(dwc->gadget, false); ++ usb_gadget_disconnect(dwc->gadget); + dwc3_event_buffers_cleanup(dwc); + } + +@@ -354,7 +366,24 @@ static void __dwc3_set_mode(struct work_struct *work) + dwc3_event_buffers_setup(dwc); + phy_set_mode(dwc->usb2_generic_phy[0], PHY_MODE_USB_DEVICE); + phy_set_mode(dwc->usb3_generic_phy[0], PHY_MODE_USB_DEVICE); +- dwc3_gadget_resume(dwc); ++ } ++ ++ /* ++ * Tell the UDC core whether there is a cable, so that it only pulls up ++ * when there is one. Without this it pulls up as soon as a gadget ++ * driver binds, which starts the endpoints on a USB3 PHY that is ++ * powered off while disconnected, and ep0 fails to come up. ++ * ++ * Perform the connect synchronously as well, instead of leaving it to ++ * the scheduled vbus work: the pullup then happens strictly after the ++ * core and event buffer setup above, and a disconnect that follows a ++ * quick unplug serializes against it on the UDC connect lock instead ++ * of tearing the controller down under a half-finished connect. ++ */ ++ if (desired_dr_role == DWC3_GCTL_PRTCAP_DEVICE && dwc->gadget) { ++ usb_udc_vbus_handler(dwc->gadget, desired_dr_connected); ++ if (desired_dr_connected) ++ usb_gadget_connect(dwc->gadget); + } + + out: +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0055-phy-rockchip-inno-usb2-Do-not-run-charger-detection-.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0055-phy-rockchip-inno-usb2-Do-not-run-charger-detection-.patch new file mode 100644 index 000000000..ba98f6018 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0055-phy-rockchip-inno-usb2-Do-not-run-charger-detection-.patch @@ -0,0 +1,114 @@ +From b715f77b5a03b5ff3f5ec9d315424478e933a445 Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Tue, 21 Jul 2026 07:35:49 +0200 +Subject: [PATCH 55/84] phy: rockchip-inno-usb2: Do not run charger detection + as a host + +VBUS comes up before anything says which way round the port is: the +Type-C port manager turns it on at SRC_ATTACHED, the PHY's bvalid +interrupt fires, and the OTG state machine starts BC1.2 while the role +is still unknown. By the time dwc3 calls phy_set_mode(PHY_MODE_USB_HOST) +detection is already several stages in. + +That used to be harmless because chg_det.opmode was never written, so +detection did not really park the transceiver. Now that it does, the +consequences show up on the bus: + + 16.578 OTGSM b_idle vbus=1 host=0 detection starts + 16.583 mode[0xe454]=0x1d7 transceiver parked, FS, pull-downs + 16.994 U2PHY set_mode: host=1 role finally known + 17.177 usb 8-1: new full-speed USB device number 2 + 17.377 dcd timed out -> DCP no charger, we are sourcing VBUS + +A high speed device enumerated at full speed, because its chirp happened +while the transceiver was parked. Then the bogus DCP outlived the +connection: OTG_STATE_A_HOST never cleared it, so the next time a real +host was plugged in the state machine still saw DCP and powered the USB2 +PHY off, leaving the gadget dead. + +Cancel detection when the role changes, undoing whichever stage it had +reached, and clear the result when leaving host mode. There is still a +window between VBUS and the role being known, but nothing acts on +detection until it finishes, and it no longer finishes. + +Signed-off-by: Ondrej Jirman +(cherry picked from commit b4a35830d0c92b801c7878f1f2f1984516d53a5e) +--- + drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 40 +++++++++++++++++++ + 1 file changed, 40 insertions(+) + +diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +index 63acee6a4310..49994c2390b7 100644 +--- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c ++++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +@@ -680,6 +680,9 @@ static bool rockchip_usb2phy_host_mode(struct rockchip_usb2phy *rphy, + return extcon_get_state(rphy->edev, EXTCON_USB_HOST) > 0; + } + ++static void rockchip_chg_detect_cancel(struct rockchip_usb2phy *rphy, ++ struct rockchip_usb2phy_port *rport); ++ + static int rockchip_usb2phy_set_mode(struct phy *phy, enum phy_mode mode, + int submode) + { +@@ -707,6 +710,14 @@ static int rockchip_usb2phy_set_mode(struct phy *phy, enum phy_mode mode, + dev_err(&rport->phy->dev, "U2PHY set_mode: host=%d\n", host_mode); + rport->host_mode = host_mode; + ++ /* ++ * VBUS comes up before anyone says which way round the port is, so ++ * charger detection may already be running against a bus that is about ++ * to be used the other way. Whatever it has decided belongs to the old ++ * role either way. ++ */ ++ rockchip_chg_detect_cancel(rphy, rport); ++ + /* let the state machine act on the new role */ + mod_delayed_work(system_wq, &rport->otg_sm_work, 0); + +@@ -832,6 +843,12 @@ static void rockchip_usb2phy_otg_sm_work(struct work_struct *work) + if (!rockchip_usb2phy_host_mode(rphy, rport)) { + dev_dbg(&rport->phy->dev, "usb otg host disconnect\n"); + rport->state = OTG_STATE_B_IDLE; ++ /* ++ * Nothing was ever detected here, we were sourcing ++ * VBUS. Do not let that reach the next connection. ++ */ ++ rphy->chg_state = USB_CHG_STATE_UNDEFINED; ++ rphy->chg_type = POWER_SUPPLY_TYPE_UNKNOWN; + rockchip_usb2phy_power_off(rport->phy); + } + break; +@@ -946,6 +963,29 @@ static void rockchip_chg_leave_mode(struct rockchip_usb2phy *rphy, + rphy->chg_mode_cfg | (mask << BIT_WRITEABLE_SHIFT)); + } + ++/* ++ * Charger detection parks the transceiver and drives DP/DM, so it must not be ++ * left running once the port turns out to be a host: there is no charger to ++ * find, VBUS is ours, and the bus is about to be enumerated. Undo whichever ++ * stage it had reached and drop the result. ++ */ ++static void rockchip_chg_detect_cancel(struct rockchip_usb2phy *rphy, ++ struct rockchip_usb2phy_port *rport) ++{ ++ cancel_delayed_work_sync(&rport->chg_work); ++ ++ if (rphy->chg_state != USB_CHG_STATE_UNDEFINED && ++ rphy->chg_state != USB_CHG_STATE_DETECTED) { ++ rockchip_chg_enable_dcd(rphy, false); ++ rockchip_chg_enable_primary_det(rphy, false); ++ rockchip_chg_enable_secondary_det(rphy, false); ++ rockchip_chg_leave_mode(rphy, rport, false); ++ } ++ ++ rphy->chg_state = USB_CHG_STATE_UNDEFINED; ++ rphy->chg_type = POWER_SUPPLY_TYPE_UNKNOWN; ++} ++ + #define CHG_DCD_POLL_TIME (100 * HZ / 1000) + #define CHG_DCD_MAX_RETRIES 6 + #define CHG_PRIMARY_DET_TIME (40 * HZ / 1000) +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0056-usb-dwc3-Set-the-PHY-mode-before-starting-the-host.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0056-usb-dwc3-Set-the-PHY-mode-before-starting-the-host.patch new file mode 100644 index 000000000..88f325a8d --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0056-usb-dwc3-Set-the-PHY-mode-before-starting-the-host.patch @@ -0,0 +1,73 @@ +From 7ac552f6eeb21d5d1782a07530f0a87d7d7b4022 Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Tue, 21 Jul 2026 07:43:34 +0200 +Subject: [PATCH 56/84] usb: dwc3: Set the PHY mode before starting the host + +The device case tells the PHYs the role before dwc3_gadget_init(), but +the host case tells them only after dwc3_host_init() has returned. +dwc3_host_init() runs the xHCI probe, which uses the PHYs and can take a +long time, so a PHY that acts on the mode does not find out until the +controller has already been using it the other way round. + +On a PinePhone Pro the USB2 PHY uses the mode to know it must not run +BC1.2 charger detection, because in host mode VBUS is ours and the bus +is in use. It was told 15.7 s after VBUS came up, by which point +detection had run to completion, decided the port was a floating +charger, and powered the USB2 PHY off underneath the probe: + + 46.498 FUSB vbus := on + 46.774 xhci-hcd: new USB bus registered, assigned bus number 8 + 48.514 charger = USB_DCP_CHARGER + 48.534 U2PHY power_off + 62.238 xhci-hcd: Host halt failed, -110 + 62.254 U2PHY set_mode: host=1 + +Move the mode setting ahead of dwc3_host_init(), which also makes the +two cases consistent. + +Signed-off-by: Ondrej Jirman +(cherry picked from commit 82f8bbb2eadcff8cf5840c016745165130b1761f) +--- + drivers/usb/dwc3/core.c | 22 ++++++++++++++-------- + 1 file changed, 14 insertions(+), 8 deletions(-) + +diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c +index 2c1cada5d637..fa961b84d2b5 100644 +--- a/drivers/usb/dwc3/core.c ++++ b/drivers/usb/dwc3/core.c +@@ -314,18 +314,24 @@ static void __dwc3_set_mode(struct work_struct *work) + + switch (role_changed ? desired_dr_role : 0) { + case DWC3_GCTL_PRTCAP_HOST: ++ /* ++ * Tell the PHYs the role before starting the host, the way the ++ * device case does. dwc3_host_init() runs the xHCI probe, which ++ * uses the PHYs and can take a long time, so a PHY that acts on ++ * the mode must not be told about it only afterwards. ++ */ ++ if (dwc->usb2_phy) ++ otg_set_vbus(dwc->usb2_phy->otg, true); ++ ++ for (i = 0; i < dwc->num_usb2_ports; i++) ++ phy_set_mode(dwc->usb2_generic_phy[i], PHY_MODE_USB_HOST); ++ for (i = 0; i < dwc->num_usb3_ports; i++) ++ phy_set_mode(dwc->usb3_generic_phy[i], PHY_MODE_USB_HOST); ++ + ret = dwc3_host_init(dwc); + if (ret) { + dev_err(dwc->dev, "failed to initialize host\n"); + } else { +- if (dwc->usb2_phy) +- otg_set_vbus(dwc->usb2_phy->otg, true); +- +- for (i = 0; i < dwc->num_usb2_ports; i++) +- phy_set_mode(dwc->usb2_generic_phy[i], PHY_MODE_USB_HOST); +- for (i = 0; i < dwc->num_usb3_ports; i++) +- phy_set_mode(dwc->usb3_generic_phy[i], PHY_MODE_USB_HOST); +- + if (dwc->dis_split_quirk) { + reg = dwc3_readl(dwc, DWC3_GUCTL3); + reg |= DWC3_GUCTL3_SPLITDISABLE; +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0057-usb-dwc3-Do-not-connect-the-gadget-while-no-cable-is.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0057-usb-dwc3-Do-not-connect-the-gadget-while-no-cable-is.patch new file mode 100644 index 000000000..ee67b9e73 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0057-usb-dwc3-Do-not-connect-the-gadget-while-no-cable-is.patch @@ -0,0 +1,60 @@ +From df015e8b9599ef975a1a90429f64bf1990dba73d Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Tue, 21 Jul 2026 07:43:49 +0200 +Subject: [PATCH 57/84] usb: dwc3: Do not connect the gadget while no cable is + present + +usb_add_gadget() starts out assuming VBUS is present and binds any +gadget driver that was waiting, so the connect happens inside +dwc3_gadget_init(), before dwc3 has any way to say there is no cable. +With the USB3 PHY powered down while disconnected, that runs the +endpoint setup against a PHY that is off: + + dwc3 fe800000.usb: request 000000002e1b5f5e was not queued to ep0out + udc fe800000.usb: failed to start adbd: -524 + configfs-gadget.adbd gadget.2: probe with driver configfs-gadget.adbd + failed with error -524 + +The gadget driver is then unbound for good, so the port stays dead until +userspace sets it up again. It shows up after a host to device role +change with nothing plugged in, which is where the gadget is registered +while disconnected. + +Remember the request instead and leave the pullup to the connection +state, which __dwc3_set_mode() already reports through +usb_udc_vbus_handler(). + +Signed-off-by: Ondrej Jirman +(cherry picked from commit 2ef635fb2667eb4e12fe0260152c261a25c414d6) +--- + drivers/usb/dwc3/gadget.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c +index 519a1dd23a30..4fbcad5bb2b2 100644 +--- a/drivers/usb/dwc3/gadget.c ++++ b/drivers/usb/dwc3/gadget.c +@@ -2797,6 +2797,20 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on) + + dwc->softconnect = is_on; + ++ /* ++ * The UDC core connects as soon as a gadget driver binds, because it ++ * assumes VBUS is present until told otherwise, and it can only be ++ * told once the gadget is registered. On a port that powers its PHYs ++ * down while nothing is plugged in, that would run the endpoint setup ++ * against a PHY that is off and fail the bind. ++ * ++ * Record the request and let the connection state drive it instead. ++ * __dwc3_set_mode() reports that state, so the pullup follows the ++ * cable either way. ++ */ ++ if (is_on && dwc->dr_mode == USB_DR_MODE_OTG && !dwc->current_dr_connected) ++ return 0; ++ + /* + * Avoid issuing a runtime resume if the device is already in the + * suspended state during gadget disconnect. DWC3 gadget was already +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0058-phy-rockchip-inno-usb2-Power-the-PHY-up-before-the-h.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0058-phy-rockchip-inno-usb2-Power-the-PHY-up-before-the-h.patch new file mode 100644 index 000000000..f6aa7c84b --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0058-phy-rockchip-inno-usb2-Power-the-PHY-up-before-the-h.patch @@ -0,0 +1,61 @@ +From bc44b71cbbaec180d07ac4961c99e7b82e5f086a Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Tue, 21 Jul 2026 07:52:19 +0200 +Subject: [PATCH 58/84] phy: rockchip-inno-usb2: Power the PHY up before the + host starts + +Switching to host mode only queued the OTG state machine, so the PHY was +powered up whenever that work happened to run. dwc3 sets the PHY mode +and then immediately starts the host controller, which put the power up +in the middle of the xHCI probe: + + 8.009 U2PHY set_mode: host=1 + 8.011 xhci-hcd: xHCI Host Controller + 8.044 xhci-hcd: new USB bus registered, assigned bus number 8 + 8.054 U2PHY power_on + 8.066 xhci-hcd: new USB bus registered, assigned bus number 9 + +A device that is already attached has to be visible by the time the root +hub is registered, and here it was not: an attached storage dongle never +enumerated at all. It used to work by accident, because the mode was set +after the host was up and the power up landed after the whole probe. + +Take the host transition immediately instead. Device mode still goes +through the state machine, which has to work out what the port is facing +before it can do anything anyway. + +Signed-off-by: Ondrej Jirman +(cherry picked from commit 04db52e4ec332802c34c202252c37f9e37d414c1) +--- + drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 15 ++++++++++++++- + 1 file changed, 14 insertions(+), 1 deletion(-) + +diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +index 49994c2390b7..22ef0e8dd117 100644 +--- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c ++++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +@@ -718,7 +718,20 @@ static int rockchip_usb2phy_set_mode(struct phy *phy, enum phy_mode mode, + */ + rockchip_chg_detect_cancel(rphy, rport); + +- /* let the state machine act on the new role */ ++ if (host_mode) { ++ /* ++ * The controller starts the host right after this returns, and ++ * the device is already attached, so its connect has to be ++ * visible by then. Leaving the power up to the state machine ++ * lands it somewhere in the middle of the host controller ++ * probe, and the connect is missed. ++ */ ++ rport->state = OTG_STATE_A_HOST; ++ rockchip_usb2phy_power_on(phy); ++ return 0; ++ } ++ ++ /* let the state machine work out what a device mode port is facing */ + mod_delayed_work(system_wq, &rport->otg_sm_work, 0); + + return 0; +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0059-usb-dwc3-Require-MPS-aligned-OUT-buffers.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0059-usb-dwc3-Require-MPS-aligned-OUT-buffers.patch new file mode 100644 index 000000000..56b843c77 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0059-usb-dwc3-Require-MPS-aligned-OUT-buffers.patch @@ -0,0 +1,44 @@ +From 2575cfc3439b3a876b35644780657e87cb5739cd Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Tue, 21 Jul 2026 10:22:14 +0200 +Subject: [PATCH 59/84] usb: dwc3: Require MPS-aligned OUT buffers + +An OUT request whose length is not a multiple of the maximum packet size +gets an extra TRB pointing at a shared bounce buffer, so that a final +full packet from the host has somewhere to land. Bytes the host sends +past the end of the request land in that buffer and are dropped without +the function driver ever hearing about it, silently desynchronising a +byte stream. + +Set quirk_ep_out_aligned_size so the framework rounds OUT buffers up to +the maximum packet size and the overflow cannot happen. + +(cherry picked from commit 7b6bedf1b7096d2ce9dd3d9d0006508e1852e816) +--- + drivers/usb/dwc3/gadget.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c +index 4fbcad5bb2b2..c5f5efda2185 100644 +--- a/drivers/usb/dwc3/gadget.c ++++ b/drivers/usb/dwc3/gadget.c +@@ -4782,6 +4782,16 @@ int dwc3_gadget_init(struct dwc3 *dwc) + dwc->revision); + + dwc->gadget->max_speed = dwc->maximum_speed; ++ ++ /* ++ * An OUT request that is not a multiple of the maximum packet size gets ++ * an extra TRB pointing at a shared bounce buffer, so that a final full ++ * packet from the host has somewhere to land. Anything the host sends ++ * past the end of the request ends up in that buffer and is discarded - ++ * see dwc3_gadget_ep_reclaim_completed_trb(). Tell the gadget framework ++ * to round OUT buffers up instead, so the situation cannot arise. ++ */ ++ dwc->gadget->quirk_ep_out_aligned_size = true; + dwc->gadget->max_ssp_rate = dwc->max_ssp_rate; + + /* +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0060-usb-typec-displayport-Update-the-mux-before-signalli.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0060-usb-typec-displayport-Update-the-mux-before-signalli.patch new file mode 100644 index 000000000..36e3ebf54 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0060-usb-typec-displayport-Update-the-mux-before-signalli.patch @@ -0,0 +1,106 @@ +From c0b9ffa7d04334b0ba1a136f4cda14ac725eb929 Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Wed, 22 Jul 2026 14:03:03 +0200 +Subject: [PATCH 60/84] usb: typec: displayport: Update the mux before + signalling hotplug + +On HPD changes the DP alt mode driver signalled the DRM side first and +only updated the mux afterwards. The DRM driver handling the event may +depend on what the mux publishes for the new status: on RK3399 the +Type-C PHY reports through phy_get_bus_width() how many lanes the +alternate mode left for DP, and cdn-dp treats zero as 'nothing to +drive'. + +That ordering breaks both directions of hotplug: + +On plug-in, when the dock raised HPD via Attention, cdn-dp's event work +ran off the hotplug event, read the lane count before tcphy_mux_set() +had stored it, concluded 'Not connected; disabling cdn' and never +looked again, so the external display stayed dark. + +On unplug, dp_altmode_remove() raised the hotplug event with the mux +still publishing the old lane count. The event blocks on DRM locks held +by a commit that is still driving the vanished sink, and as long as the +lanes look present cdn-dp keeps re-enabling the output against a dead +AUX channel, each attempt a 5 second DPCD timeout under those same +locks. The disconnect handshake sat blocked behind that for over ten +seconds before the pipeline finally tore down. + +Notify the mux first everywhere hotplug is signalled: the status update +path, the deferred HPD signalling after configuration, and the alt mode +removal. With the lane count cleared first, an in-flight enable aborts +at the next lane check instead of timing out, and the teardown is +immediate. The extra notification dp_altmode_attention() does +afterwards is left in place; repeating the same state to the mux is +harmless. + +Signed-off-by: Ondrej Jirman +--- + drivers/usb/typec/altmodes/displayport.c | 28 +++++++++++++++++++++++- + 1 file changed, 27 insertions(+), 1 deletion(-) + +diff --git a/drivers/usb/typec/altmodes/displayport.c b/drivers/usb/typec/altmodes/displayport.c +index 722030137015..380bd4215404 100644 +--- a/drivers/usb/typec/altmodes/displayport.c ++++ b/drivers/usb/typec/altmodes/displayport.c +@@ -205,6 +205,14 @@ static int dp_altmode_status_update(struct dp_altmode *dp) + dp->pending_irq_hpd = true; + } + } else { ++ /* ++ * Update the mux before signalling the hotplug event: the DRM ++ * driver handling the event may look at what the mux published ++ * for the new status (e.g. how many lanes the alternate mode ++ * left for DP), and with the event sent first it would race ++ * with the mux update and read stale state. ++ */ ++ ret = dp_altmode_notify(dp); + drm_connector_oob_hotplug_event(dp->connector_fwnode, + hpd ? connector_status_connected : + connector_status_disconnected); +@@ -221,8 +229,14 @@ static int dp_altmode_status_update(struct dp_altmode *dp) + + static int dp_altmode_configured(struct dp_altmode *dp) + { ++ int ret; ++ + sysfs_notify(&dp->alt->dev.kobj, "displayport", "configuration"); + sysfs_notify(&dp->alt->dev.kobj, "displayport", "pin_assignment"); ++ ++ /* Update the mux before signalling the hotplug event, see above. */ ++ ret = dp_altmode_notify(dp); ++ + /* + * If the DFP_D/UFP_D sends a change in HPD when first notifying the + * DisplayPort driver that it is connected, then we wait until +@@ -240,7 +254,7 @@ static int dp_altmode_configured(struct dp_altmode *dp) + } + } + +- return dp_altmode_notify(dp); ++ return ret; + } + + static int dp_altmode_configure_vdm(struct dp_altmode *dp, u32 conf) +@@ -869,6 +883,18 @@ void dp_altmode_remove(struct typec_altmode *alt) + cancel_work_sync(&dp->work); + typec_altmode_put_plug(dp->plug_prime); + ++ /* ++ * Same ordering as on status updates: tell the mux the lanes are gone ++ * before signalling the disconnect. The hotplug event can block on DRM ++ * locks held by a commit that is still driving the vanished sink, and ++ * until the mux is updated the DRM driver keeps finding lanes to ++ * drive and re-enables the output against a dead AUX channel instead ++ * of tearing it down. ++ */ ++ dp->data.status = 0; ++ dp->data.conf = 0; ++ dp_altmode_notify(dp); ++ + if (dp->connector_fwnode) { + drm_connector_oob_hotplug_event(dp->connector_fwnode, + connector_status_disconnected); +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0061-arm64-dts-rockchip-rk3399-Disable-debug-nodes.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0061-arm64-dts-rockchip-rk3399-Disable-debug-nodes.patch new file mode 100644 index 000000000..ff1a50ba1 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0061-arm64-dts-rockchip-rk3399-Disable-debug-nodes.patch @@ -0,0 +1,36 @@ +From c82f7cbc063dbc0867e635ac66b0a3b255c03340 Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Sun, 4 Sep 2022 22:34:56 +0200 +Subject: [PATCH 61/84] arm64: dts: rockchip: rk3399: Disable debug nodes + +They hang boot with older levinboot, due to levinboot not enabling their PD. + +Signed-off-by: Ondrej Jirman +(cherry picked from commit 809a83d59f3cf8a98ff00640c0f2fdca5bde4d54) +--- + arch/arm64/boot/dts/rockchip/rk3399-base.dtsi | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-base.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-base.dtsi +index 49c68fe65de6..4b81ac05fe44 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-base.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399-base.dtsi +@@ -479,6 +479,7 @@ usb_host1_ohci: usb@fe3e0000 { + status = "disabled"; + }; + ++ /* + debug@fe430000 { + compatible = "arm,coresight-cpu-debug", "arm,primecell"; + reg = <0 0xfe430000 0 0x1000>; +@@ -526,6 +527,7 @@ debug@fe710000 { + clock-names = "apb_pclk"; + cpu = <&cpu_b1>; + }; ++ */ + + usbdrd3_0: usb@fe800000 { + compatible = "rockchip,rk3399-dwc3"; +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0062-arm64-dts-rockchip-rk3399-Add-reboot-mode-driver.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0062-arm64-dts-rockchip-rk3399-Add-reboot-mode-driver.patch new file mode 100644 index 000000000..8f4b85be6 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0062-arm64-dts-rockchip-rk3399-Add-reboot-mode-driver.patch @@ -0,0 +1,36 @@ +From d8e9516106835ed6c44c8feae5ea65e2f51f8803 Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Sun, 4 Sep 2022 22:49:46 +0200 +Subject: [PATCH 62/84] arm64: dts: rockchip: rk3399: Add reboot mode driver + +U-Boot uses value 0xef08a53c to jump back to USB loader maskrom +mode instead of normal boot. Add support for reboot to maskrom +from the kernel. + +Signed-off-by: Ondrej Jirman +(cherry picked from commit 5c4b81ba4f37d81edd20000581625a76e724a205) +--- + arch/arm64/boot/dts/rockchip/rk3399-base.dtsi | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-base.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-base.dtsi +index 4b81ac05fe44..d1d124501759 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-base.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399-base.dtsi +@@ -1312,6 +1312,13 @@ pmu_io_domains: io-domains { + compatible = "rockchip,rk3399-pmu-io-voltage-domain"; + status = "disabled"; + }; ++ ++ reboot-mode { ++ compatible = "syscon-reboot-mode"; ++ offset = <0x300>; ++ mode-normal = <0>; ++ mode-maskrom = <0xef08a53c>; ++ }; + }; + + spi3: spi@ff350000 { +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0063-arm64-dts-rockchip-rk3399-Power-cycle-the-USB3-PHY-o.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0063-arm64-dts-rockchip-rk3399-Power-cycle-the-USB3-PHY-o.patch new file mode 100644 index 000000000..5973199f1 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0063-arm64-dts-rockchip-rk3399-Power-cycle-the-USB3-PHY-o.patch @@ -0,0 +1,43 @@ +From 7eb7d7f09537f33afa30863269dc72460f20420f Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Mon, 20 Jul 2026 17:53:56 +0200 +Subject: [PATCH 63/84] arm64: dts: rockchip: rk3399: Power cycle the USB3 PHY + on role change + +The Type-C PHY on RK3399 latches the plug orientation while it is being +powered on, and only while the USB3 OTG controller is held in reset, so +the controller driver has to power cycle it. + +The property is inert unless the port is actually in dual-role mode with +either an extcon or a usb-role-switch to report the cable state, so it +can be set at the SoC level. + +Signed-off-by: Ondrej Jirman +(cherry picked from commit f1061493a904add60e12c268d8efa2fefd57a421) +--- + arch/arm64/boot/dts/rockchip/rk3399-base.dtsi | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-base.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-base.dtsi +index d1d124501759..c9ee3a20943b 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-base.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399-base.dtsi +@@ -555,6 +555,7 @@ usbdrd_dwc3_0: usb@fe800000 { + phys = <&u2phy0_otg>, <&tcphy0_usb3>; + phy-names = "usb2-phy", "usb3-phy"; + phy_type = "utmi_wide"; ++ usb3-phy-power-cycle-on-role-change; + snps,dis_enblslpm_quirk; + snps,dis-u2-freeclk-exists-quirk; + snps,dis_u2_susphy_quirk; +@@ -591,6 +592,7 @@ usbdrd_dwc3_1: usb@fe900000 { + phys = <&u2phy1_otg>, <&tcphy1_usb3>; + phy-names = "usb2-phy", "usb3-phy"; + phy_type = "utmi_wide"; ++ usb3-phy-power-cycle-on-role-change; + snps,dis_enblslpm_quirk; + snps,dis-u2-freeclk-exists-quirk; + snps,dis_u2_susphy_quirk; +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0064-arm64-dts-rockchip-rk3399-Add-dmc_opp_table.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0064-arm64-dts-rockchip-rk3399-Add-dmc_opp_table.patch new file mode 100644 index 000000000..8013c59c5 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0064-arm64-dts-rockchip-rk3399-Add-dmc_opp_table.patch @@ -0,0 +1,63 @@ +From 38b6000236d688997fa789a32006dee308870488 Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Fri, 22 Nov 2024 23:41:48 +0100 +Subject: [PATCH 64/84] arm64: dts: rockchip: rk3399: Add dmc_opp_table + +This was removed in v6.12. Re-add it with original values. + +Signed-off-by: Ondrej Jirman +(cherry picked from commit df46950af61c404d9b0251f674015e35f03471bd) +--- + arch/arm64/boot/dts/rockchip/rk3399.dtsi | 29 ++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi +index 6bc1249d99e6..bb9205bebf9f 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi +@@ -104,6 +104,31 @@ opp05 { + opp-microvolt = <1100000 1100000 1150000>; + }; + }; ++ ++ dmc_opp_table: opp-table-3 { ++ compatible = "operating-points-v2"; ++ ++ opp00 { ++ opp-hz = /bits/ 64 <328000000>; ++ opp-microvolt = <900000>; ++ }; ++ opp01 { ++ opp-hz = /bits/ 64 <416000000>; ++ opp-microvolt = <900000>; ++ }; ++ opp02 { ++ opp-hz = /bits/ 64 <666000000>; ++ opp-microvolt = <900000>; ++ }; ++ opp03 { ++ opp-hz = /bits/ 64 <856000000>; ++ opp-microvolt = <900000>; ++ }; ++ opp04 { ++ opp-hz = /bits/ 64 <928000000>; ++ opp-microvolt = <925000>; ++ }; ++ }; + }; + + &cpu_l0 { +@@ -130,6 +155,10 @@ &cpu_b1 { + operating-points-v2 = <&cluster1_opp>; + }; + ++&dmc { ++ operating-points-v2 = <&dmc_opp_table>; ++}; ++ + &gpu { + operating-points-v2 = <&gpu_opp_table>; + }; +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0065-arm64-dts-rockchip-rk3399-s-Add-DMC-table.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0065-arm64-dts-rockchip-rk3399-s-Add-DMC-table.patch new file mode 100644 index 000000000..6a67a7bac --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0065-arm64-dts-rockchip-rk3399-s-Add-DMC-table.patch @@ -0,0 +1,63 @@ +From 92232266830ad5fddeb4cc74cef6eb9df7997df8 Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Thu, 28 Nov 2024 11:16:31 +0100 +Subject: [PATCH 65/84] arm64: dts: rockchip: rk3399-s: Add DMC table + +This is used by Pinephone Pro. + +Signed-off-by: Ondrej Jirman +(cherry picked from commit 456dec0546a630cdf298b9931912c03a33bce84c) +--- + arch/arm64/boot/dts/rockchip/rk3399-s.dtsi | 29 ++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-s.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-s.dtsi +index e54f451af9f3..82b941720294 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-s.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399-s.dtsi +@@ -92,6 +92,31 @@ opp05 { + opp-microvolt = <1100000 1100000 1150000>; + }; + }; ++ ++ dmc_opp_table: opp-table-3 { ++ compatible = "operating-points-v2"; ++ ++ opp00 { ++ opp-hz = /bits/ 64 <328000000>; ++ opp-microvolt = <900000>; ++ }; ++ opp01 { ++ opp-hz = /bits/ 64 <416000000>; ++ opp-microvolt = <900000>; ++ }; ++ opp02 { ++ opp-hz = /bits/ 64 <666000000>; ++ opp-microvolt = <900000>; ++ }; ++ opp03 { ++ opp-hz = /bits/ 64 <856000000>; ++ opp-microvolt = <900000>; ++ }; ++ opp04 { ++ opp-hz = /bits/ 64 <928000000>; ++ opp-microvolt = <925000>; ++ }; ++ }; + }; + + &cpu_l0 { +@@ -118,6 +143,10 @@ &cpu_b1 { + operating-points-v2 = <&cluster1_opp>; + }; + ++&dmc { ++ operating-points-v2 = <&dmc_opp_table>; ++}; ++ + &gpu { + operating-points-v2 = <&gpu_opp_table>; + }; +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0066-arm64-dts-rockchip-rk3399-Number-the-CDN-DP-ports.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0066-arm64-dts-rockchip-rk3399-Number-the-CDN-DP-ports.patch new file mode 100644 index 000000000..752d07dcb --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0066-arm64-dts-rockchip-rk3399-Number-the-CDN-DP-ports.patch @@ -0,0 +1,54 @@ +From 2aa1ea8136426e790aa954ceacfb02e7fabcc52b Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Tue, 21 Jul 2026 22:43:47 +0200 +Subject: [PATCH 66/84] arm64: dts: rockchip: rk3399: Number the CDN DP ports + +Number the input port and add the output port. The binding requires both +port@0 (VOP input) and port@1 (output), but the node had only a single +unnamed input port, so every board that enables the DP fails validation: + + ports: 'port@0' is a required property + ports: 'port@1' is a required property + +The output is what a Type-C connector reaches when the DP is behind an +alternate mode, which no board could describe until now. Endpoint +numbering inside the input port is unchanged and nothing looks the ports +up by name, so boards that already enable the DP are unaffected. + +Signed-off-by: Ondrej Jirman +(cherry picked from commit de379c02ca5cbb6763e47fd63b2b9c3e6e9053e3) +--- + arch/arm64/boot/dts/rockchip/rk3399-base.dtsi | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-base.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-base.dtsi +index c9ee3a20943b..3cb02ba78a77 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-base.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399-base.dtsi +@@ -622,7 +622,11 @@ cdn_dp: dp@fec00000 { + status = "disabled"; + + ports { +- dp_in: port { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ dp_in: port@0 { ++ reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + +@@ -636,6 +640,10 @@ dp_in_vopl: endpoint@1 { + remote-endpoint = <&vopl_out_dp>; + }; + }; ++ ++ dp_out: port@1 { ++ reg = <1>; ++ }; + }; + }; + +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0067-arm64-dts-rockchip-rk3399-pinephone-pro-Add-Type-C-p.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0067-arm64-dts-rockchip-rk3399-pinephone-pro-Add-Type-C-p.patch new file mode 100644 index 000000000..736cffe1d --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0067-arm64-dts-rockchip-rk3399-pinephone-pro-Add-Type-C-p.patch @@ -0,0 +1,302 @@ +From b1c760223654de5c5a6233382a58c69b484fb003 Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Tue, 21 Jul 2026 19:20:33 +0200 +Subject: [PATCH 67/84] arm64: dts: rockchip: rk3399-pinephone-pro: Add Type-C + port support + +Pinephone Pro has: + +- FUSB302 Type-C port controller on i2c4, doing CC detection and PD +- dual role data on the port, USB 2.0 and SuperSpeed +- DisplayPort alternate mode out of the same connector +- a 5V boost for sourcing VBUS when the port is a host + +It is also the port the phone charges from. + +Let's enable it. + +Signed-off-by: Ondrej Jirman +(cherry picked from commit 4671fc6d1131e0030f6789c6b4c8ca3662d71f93) +--- + .../dts/rockchip/rk3399-pinephone-pro.dts | 196 ++++++++++++++++++ + 1 file changed, 196 insertions(+) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts +index 8d26bd9b7500..159ccc47d6fd 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + #include "rk3399-s.dtsi" + + / { +@@ -114,6 +115,50 @@ avdd2v8_dvp: regulator-avdd2v8-dvp { + vin-supply = <&vcc3v3_sys>; + }; + ++ vcc5v0_sys: regulator-vcc5v0-host { ++ compatible = "regulator-fixed"; ++ regulator-name = "vcc5v0_sys"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ regulator-always-on; ++ regulator-boot-on; ++ vin-supply = <&boost_otg>; ++ ++ regulator-state-mem { ++ regulator-on-in-suspend; ++ }; ++ }; ++ ++ /* ++ * GPIO0_A6 is used to force enable the VCC_SYS <-> VBAT+ Q7 switch that ++ * helps boost the RK818's power path's current carrying capacity when ++ * operating the phone from the battery in case VBUS_TYPEC has 5V ++ * provided by the phone itself and not by the external power supply. ++ * (this happens in USB host mode) ++ * ++ * GPIO0_A6 low: Q7 is enabled if there's 0V on VBUS_TYPEC (phone is not ++ * powered from external power supply) ++ * GPIO0_A6 high: Q7 is enabled no matter what ++ * ++ * GPIO0_A6 must be high when the phone is providing VBUS_TYPEC power. ++ * This keeps the power path boost enabled for all cases when the phone ++ * runs from the battery. ++ * ++ * In other words, GPIO0_A6 is used to override the automatic disabling ++ * of Q7 when VBUS_TYPEC has 5V in USB host mode. ++ */ ++ vcc5v0_typec: regulator-vcc5v0-typec { ++ compatible = "regulator-fixed"; ++ enable-active-high; ++ gpio = <&gpio0 RK_PA6 GPIO_ACTIVE_HIGH>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&vcc5v0_typec_en>; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ regulator-name = "vcc5v0_typec"; ++ vin-supply = <&boost_otg>; ++ }; ++ + vcc3v3_sys: regulator-vcc3v3-sys { + compatible = "regulator-fixed"; + regulator-name = "vcc3v3_sys"; +@@ -237,6 +282,17 @@ &cpu_b1 { + cpu-supply = <&vdd_cpu_b>; + }; + ++&cdn_dp { ++ status = "okay"; ++ phys = <&tcphy0_dp>; ++}; ++ ++&dp_out { ++ cdn_dp_out: endpoint { ++ remote-endpoint = <&tcphy0_dp_in>; ++ }; ++}; ++ + &emmc_phy { + status = "okay"; + }; +@@ -272,6 +328,7 @@ rk818: pmic@1c { + vcc7-supply = <&vcc3v3_sys>; + vcc8-supply = <&vcc_sys>; + vcc9-supply = <&vcc3v3_sys>; ++ usb-supply = <&vcc5v0_typec>; + + regulators { + vdd_cpu_l: DCDC_REG1 { +@@ -402,6 +459,21 @@ regulator-state-mem { + regulator-on-in-suspend; + }; + }; ++ ++ boost_otg: DCDC_BOOST { ++ regulator-name = "boost_otg"; ++ regulator-always-on; ++ regulator-boot-on; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ regulator-state-mem { ++ regulator-on-in-suspend; ++ }; ++ }; ++ ++ otg_switch: OTG_SWITCH { ++ regulator-name = "otg_switch"; ++ }; + }; + }; + +@@ -570,6 +642,61 @@ af8133j: compass@1c { + }; + }; + ++&i2c4 { ++ fusb0: typec-portc@22 { ++ compatible = "fcs,fusb302"; ++ reg = <0x22>; ++ interrupt-parent = <&gpio1>; ++ interrupts = ; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&fusb0_int>; ++ extcon = <&u2phy0>; ++ vbus-supply = <&otg_switch>; ++ ++ connector { ++ compatible = "usb-c-connector"; ++ data-role = "dual"; ++ label = "USB-C"; ++ op-sink-microwatt = <2500000>; ++ power-role = "dual"; ++ sink-pdos = ; ++ source-pdos = ; ++ try-power-role = "sink"; ++ displayport = <&cdn_dp>; ++ ++ altmodes { ++ displayport { ++ svid = /bits/ 16 <0xff01>; ++ vdo = <0x0c46>; ++ }; ++ }; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ reg = <0>; ++ ++ usbc_hs: endpoint { ++ remote-endpoint = ++ <&dwc3_0_role_switch>; ++ }; ++ }; ++ ++ port@1 { ++ reg = <1>; ++ ++ usbc_ss: endpoint { ++ remote-endpoint = ++ <&tcphy0_typec>; ++ }; ++ }; ++ }; ++ }; ++ }; ++}; ++ + &io_domains { + bt656-supply = <&vcc1v8_dvp>; + audio-supply = <&vcca1v8_codec>; +@@ -688,6 +815,12 @@ compass_rst_l: compass-rst-l { + }; + }; + ++ fusb302x { ++ fusb0_int: fusb0-int { ++ rockchip,pins = <1 RK_PA2 RK_FUNC_GPIO &pcfg_pull_up>; ++ }; ++ }; ++ + leds { + red_led_pin: red-led-pin { + rockchip,pins = <4 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>; +@@ -740,6 +873,12 @@ wifi_host_wake_l: wifi-host-wake-l { + }; + }; + ++ usb-typec { ++ vcc5v0_typec_en: vcc5v0_typec_en { ++ rockchip,pins = <0 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up>; ++ }; ++ }; ++ + wireless-bluetooth { + bt_wake_pin: bt-wake-pin { + rockchip,pins = <2 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>; +@@ -821,12 +960,45 @@ flash@0 { + }; + }; + ++&tcphy0 { ++ mode-switch; ++ orientation-switch; ++ status = "okay"; ++ ++ port { ++ tcphy0_typec: endpoint { ++ remote-endpoint = <&usbc_ss>; ++ }; ++ }; ++}; ++ ++&tcphy0_dp { ++ port { ++ tcphy0_dp_in: endpoint { ++ remote-endpoint = <&cdn_dp_out>; ++ }; ++ }; ++}; ++ + &tsadc { + rockchip,hw-tshut-mode = <1>; + rockchip,hw-tshut-polarity = <1>; + status = "okay"; + }; + ++&u2phy0 { ++ status = "okay"; ++}; ++ ++&u2phy0_otg { ++ status = "okay"; ++}; ++ ++&u2phy0_host { ++ status = "okay"; ++ phy-supply = <&vcc5v0_sys>; ++}; ++ + &uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_xfer &uart0_cts &uart0_rts>; +@@ -852,6 +1024,30 @@ &uart2 { + status = "okay"; + }; + ++&usb_host0_ehci { ++ status = "okay"; ++}; ++ ++&usb_host0_ohci { ++ status = "okay"; ++}; ++ ++&usbdrd3_0 { ++ status = "okay"; ++}; ++ ++&usbdrd_dwc3_0 { ++ dr_mode = "otg"; ++ usb-role-switch; ++ status = "okay"; ++ ++ port { ++ dwc3_0_role_switch: endpoint { ++ remote-endpoint = <&usbc_hs>; ++ }; ++ }; ++}; ++ + &vopb { + status = "okay"; + assigned-clocks = <&cru DCLK_VOP0_DIV>, <&cru DCLK_VOP0>, +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0068-arm64-dts-rockchip-rk3399-pinephone-pro-Add-internal.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0068-arm64-dts-rockchip-rk3399-pinephone-pro-Add-internal.patch new file mode 100644 index 000000000..f54bd80e5 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0068-arm64-dts-rockchip-rk3399-pinephone-pro-Add-internal.patch @@ -0,0 +1,71 @@ +From 02ced21a4dee8dcb0ecd639e940c19b32162fffe Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Sun, 4 Sep 2022 23:11:02 +0200 +Subject: [PATCH 68/84] arm64: dts: rockchip: rk3399-pinephone-pro: Add + internal display support + +Touch screen improvememtns in suspend. + +Signed-off-by: Ondrej Jirman +(cherry picked from commit f9f2c2082f1c935a147456f2f111b0427b4fd2b3) +--- + .../boot/dts/rockchip/rk3399-pinephone-pro.dts | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts +index 159ccc47d6fd..3f78611bfd1a 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts +@@ -231,6 +231,8 @@ vcc1v8_lcd: regulator-vcc1v8-lcd { + regulator-max-microvolt = <1800000>; + vin-supply = <&vcc3v3_sys>; + gpio = <&gpio3 RK_PA5 GPIO_ACTIVE_HIGH>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&display_pwren1>; + }; + + /* MIPI DSI panel 2.8v supply */ +@@ -242,6 +244,8 @@ vcc2v8_lcd: regulator-vcc2v8-lcd { + regulator-max-microvolt = <2800000>; + vin-supply = <&vcc3v3_sys>; + gpio = <&gpio3 RK_PA1 GPIO_ACTIVE_HIGH>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&display_pwren>; + }; + + vibrator { +@@ -385,6 +389,9 @@ vcc3v0_touch: LDO_REG2 { + regulator-name = "vcc3v0_touch"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; ++ regulator-state-mem { ++ regulator-off-in-suspend; ++ }; + }; + + vcca1v8_codec: LDO_REG3 { +@@ -591,6 +598,8 @@ touchscreen@14 { + VDDIO-supply = <&vcc3v0_touch>; + touchscreen-size-x = <720>; + touchscreen-size-y = <1440>; ++ use-dt-irq-flags; ++ poweroff-in-suspend; + }; + + light-sensor@48 { +@@ -795,6 +804,12 @@ lcd { + lcd1_rst_pin: lcd1-rst-pin { + rockchip,pins = <4 RK_PD1 RK_FUNC_GPIO &pcfg_pull_none>; + }; ++ display_pwren: display-pwren { ++ rockchip,pins = <3 RK_PA1 RK_FUNC_GPIO &pcfg_pull_down>; ++ }; ++ display_pwren1: display-pwren1 { ++ rockchip,pins = <3 RK_PA5 RK_FUNC_GPIO &pcfg_pull_down>; ++ }; + }; + + cameras { +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0069-arm64-dts-rockchip-rk3399-pinephone-pro-Add-battery-.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0069-arm64-dts-rockchip-rk3399-pinephone-pro-Add-battery-.patch new file mode 100644 index 000000000..e09bcb1c5 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0069-arm64-dts-rockchip-rk3399-pinephone-pro-Add-battery-.patch @@ -0,0 +1,178 @@ +From 49d86cb04330d0fa36e3d6762022f9dbe9f0fcab Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Tue, 21 Jul 2026 19:20:54 +0200 +Subject: [PATCH 69/84] arm64: dts: rockchip: rk3399-pinephone-pro: Add battery + charger support + +Describe Pinephone battery and battery charger. Battery has internal +NTC R25=3kOhm. Table was generated by aproximated beta model constant +as measured in my fridge. :) + +The input current limit comes from the Type-C port controller, so the +charger takes fusb302 as its power supply. + +Signed-off-by: Ondrej Jirman +(cherry picked from commit 7bb2b9094fda320593c8f9eecb961b1758fea928) +--- + .../dts/rockchip/rk3399-pinephone-pro.dts | 138 ++++++++++++++++++ + 1 file changed, 138 insertions(+) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts +index 3f78611bfd1a..e7577f92cb44 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts +@@ -51,6 +51,44 @@ button-down { + }; + }; + ++ bat: battery { ++ compatible = "simple-battery"; ++ device-chemistry = "lithium-ion-polymer"; ++ voltage-min-design-microvolt = <3400000>; ++ voltage-max-design-microvolt = <4350000>; ++ energy-full-design-microwatt-hours = <10290400>; ++ charge-full-design-microamp-hours = <2708000>; ++ precharge-current-microamp = <120000>; ++ charge-term-current-microamp = <150000>; ++ constant-charge-current-max-microamp = <1500000>; ++ constant-charge-voltage-max-microvolt = <4300000>; ++ factory-internal-resistance-micro-ohms = <150000>; ++ resistance-temp-table = <20 150>; ++ ocv-capacity-celsius = <20>; ++ ocv-capacity-table-0 = ++ <4308000 100>, ++ <4217000 95>, ++ <4161000 90>, ++ <4110000 85>, ++ <4066000 80>, ++ <4007000 75>, ++ <3974000 70>, ++ <3937000 65>, ++ <3896000 60>, ++ <3853000 55>, ++ <3827000 50>, ++ <3807000 45>, ++ <3793000 40>, ++ <3780000 35>, ++ <3768000 30>, ++ <3756000 25>, ++ <3740000 20>, ++ <3716000 15>, ++ <3689000 10>, ++ <3675000 5>, ++ <3400000 0>; ++ }; ++ + backlight: backlight { + compatible = "pwm-backlight"; + pwms = <&pwm0 0 50000 0>; +@@ -482,6 +520,106 @@ otg_switch: OTG_SWITCH { + regulator-name = "otg_switch"; + }; + }; ++ ++ charger { ++ compatible = "rockchip,rk818-charger"; ++ power-supplies = <&fusb0>; ++ monitored-battery = <&bat>; ++ ++ /* ++ * Vendor-specific tunables that do not map to the ++ * standard simple-battery binding. ++ */ ++ rockchip,sense-resistor-micro-ohms = <10000>; ++ rockchip,relax-entry-current-microamp = <300000>; ++ rockchip,relax-exit-current-microamp = <300000>; ++ rockchip,max-soc-offset-percent = <60>; ++ rockchip,feedback-temp-celsius = <105>; ++ rockchip,monitor-sec = <5>; ++ rockchip,ntc-table = < ++ (-20) 26459 ++ (-19) 25009 ++ (-18) 23649 ++ (-17) 22372 ++ (-16) 21174 ++ (-15) 20048 ++ (-14) 18990 ++ (-13) 17996 ++ (-12) 17060 ++ (-11) 16180 ++ (-10) 15352 ++ (-9) 14571 ++ (-8) 13836 ++ (-7) 13143 ++ (-6) 12489 ++ (-5) 11873 ++ (-4) 11291 ++ (-3) 10742 ++ (-2) 10223 ++ (-1) 9733 ++ 0 9269 ++ 1 8831 ++ 2 8416 ++ 3 8024 ++ 4 7653 ++ 5 7301 ++ 6 6968 ++ 7 6652 ++ 8 6353 ++ 9 6069 ++ 10 5800 ++ 11 5544 ++ 12 5301 ++ 13 5071 ++ 14 4852 ++ 15 4644 ++ 16 4446 ++ 17 4258 ++ 18 4079 ++ 19 3909 ++ 20 3747 ++ 21 3593 ++ 22 3446 ++ 23 3306 ++ 24 3172 ++ 25 3045 ++ 26 2924 ++ 27 2808 ++ 28 2697 ++ 29 2592 ++ 30 2491 ++ 31 2395 ++ 32 2304 ++ 33 2216 ++ 34 2132 ++ 35 2052 ++ 36 1975 ++ 37 1902 ++ 38 1832 ++ 39 1765 ++ 40 1700 ++ 41 1639 ++ 42 1580 ++ 43 1523 ++ 44 1469 ++ 45 1417 ++ 46 1368 ++ 47 1320 ++ 48 1274 ++ 49 1230 ++ 50 1188 ++ 51 1148 ++ 52 1109 ++ 53 1072 ++ 54 1036 ++ 55 1001 ++ 56 968 ++ 57 937 ++ 58 906 ++ 59 877 ++ 60 848 ++ >; ++ }; + }; + + vdd_cpu_b: regulator@40 { +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0070-arm64-dts-rockchip-rk3399-pinephone-pro-Add-sound-su.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0070-arm64-dts-rockchip-rk3399-pinephone-pro-Add-sound-su.patch new file mode 100644 index 000000000..7096f8536 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0070-arm64-dts-rockchip-rk3399-pinephone-pro-Add-sound-su.patch @@ -0,0 +1,194 @@ +From af417cc22fa4dcefc192cb0390b287380e7c0d55 Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Sun, 4 Sep 2022 23:25:19 +0200 +Subject: [PATCH 70/84] arm64: dts: rockchip: rk3399-pinephone-pro: Add sound + support + +Add support for Pinephone Pro sound card and codec. + +It also adds a jack detection GPIO to the sound card definition, and +creates a new set of ADC keys for handling headset buttons. + +Co-developed-by: Arnaud Ferraris +Signed-off-by: Arnaud Ferraris +Signed-off-by: Ondrej Jirman +(cherry picked from commit 77c8d97a95e0e4c12ea6e32fe82f1d8eab8997d2) +--- + .../dts/rockchip/rk3399-pinephone-pro.dts | 117 ++++++++++++++++++ + 1 file changed, 117 insertions(+) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts +index e7577f92cb44..977b3d186a9a 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts +@@ -136,6 +136,70 @@ multi-led { + leds = <&led_red>, <&led_green>, <&led_blue>; + }; + ++ // in1 - digital mic daughhterboard ++ // in2 - headset mic ++ // in3 - modem output (muxed with mono) ++ // spol - earphone ++ // hpo - heaphones ++ // lout - modem input ++ // spaker - amp enabled by SPK_CTL_H ++ // ++ // mclk - GPIO4_A0/I2S_CLK ++ ++ rt5640-sound { ++ compatible = "simple-audio-card"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&hp_det>; ++ simple-audio-card,name = "PinePhonePro"; ++ simple-audio-card,aux-devs = <&speaker_amp>; ++ simple-audio-card,format = "i2s"; ++ simple-audio-card,mclk-fs = <256>; ++ simple-audio-card,hp-det-gpio = <&gpio4 RK_PD4 GPIO_ACTIVE_LOW>; ++ simple-audio-card,pin-switches = "Internal Speaker"; ++ ++ simple-audio-card,widgets = ++ "Microphone", "Headset Microphone", ++ "Microphone", "Internal Microphone", ++ "Headphone", "Headphones", ++ "Speaker", "Internal Earpiece", ++ "Speaker", "Internal Speaker", ++ "Line", "Line In Modem", ++ "Line", "Line Out Modem"; ++ ++ simple-audio-card,routing = ++ "Headphones", "HPOL", ++ "Headphones", "HPOR", ++ "Internal Earpiece", "SPOLP", ++ "Internal Earpiece", "SPOLN", ++ "Internal Speaker", "Speaker Amp OUTL", ++ "Internal Speaker", "Speaker Amp OUTR", ++ "Speaker Amp INL", "HPOL", ++ "Speaker Amp INR", "HPOR", ++ "DMIC1", "Internal Microphone", ++ "Headset Microphone", "MICBIAS1", ++ "IN2P", "Headset Microphone", ++ "Line Out Modem", "LOUTL", ++ "Line Out Modem", "LOUTR", ++ "IN3P", "Line In Modem", ++ "IN3N", "Line In Modem"; ++ ++ simple-audio-card,cpu { ++ sound-dai = <&i2s0>; ++ }; ++ ++ simple-audio-card,codec { ++ sound-dai = <&rt5640>; ++ }; ++ }; ++ ++ speaker_amp: audio-amplifier { ++ compatible = "simple-audio-amplifier"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spk_en>; ++ enable-gpios = <&gpio0 RK_PB3 GPIO_ACTIVE_HIGH>; ++ sound-name-prefix = "Speaker Amp"; ++ }; ++ + vcc_sys: regulator-vcc-sys { + compatible = "regulator-fixed"; + regulator-name = "vcc_sys"; +@@ -224,6 +288,8 @@ vcc1v8_codec: regulator-vcc1v8-codec { + pinctrl-names = "default"; + pinctrl-0 = <&vcc1v8_codec_en>; + regulator-name = "vcc1v8_codec"; ++ regulator-always-on; ++ regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + vin-supply = <&vcc3v3_sys>; +@@ -419,8 +485,13 @@ regulator-state-mem { + + vcca3v0_codec: LDO_REG1 { + regulator-name = "vcca3v0_codec"; ++ regulator-always-on; ++ regulator-boot-on; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; ++ regulator-state-mem { ++ regulator-on-in-suspend; ++ }; + }; + + vcc3v0_touch: LDO_REG2 { +@@ -438,6 +509,9 @@ vcca1v8_codec: LDO_REG3 { + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; ++ regulator-state-mem { ++ regulator-on-in-suspend; ++ }; + }; + + rk818_pwr_on: LDO_REG4 { +@@ -789,6 +863,34 @@ af8133j: compass@1c { + }; + }; + ++&i2c1 { ++ status = "okay"; ++ ++ clock-frequency = <400000>; ++ i2c-scl-rising-time-ns = <300>; ++ i2c-scl-falling-time-ns = <15>; ++ // XXX: modem codec supplies: ++ // - vcc1v8_codec ++ // - vcca3v0_codec ++ ++ // supplies: (always on currently) ++ // - vcca3v0_codec ++ // - vcca1v8_codec ++ // - vcc5v0_sys - spk_vcc ++ rt5640: rt5640@1c { ++ compatible = "realtek,rt5640"; ++ reg = <0x1c>; ++ clocks = <&cru SCLK_I2S_8CH_OUT>; ++ clock-names = "mclk"; ++ assigned-clocks = <&cru SCLK_I2S0_8CH>; ++ assigned-clock-rates = <11289599>; ++ realtek,dmic1-data-pin = <1>; ++ realtek,in3-differential; ++ realtek,lout-differential; ++ #sound-dai-cells = <0>; ++ }; ++}; ++ + &i2c4 { + fusb0: typec-portc@22 { + compatible = "fcs,fusb302"; +@@ -844,6 +946,13 @@ usbc_ss: endpoint { + }; + }; + ++&i2s0 { ++ rockchip,playback-channels = <2>; ++ rockchip,capture-channels = <2>; ++ pinctrl-0 = <&i2s0_2ch_bus>; ++ status = "okay"; ++}; ++ + &io_domains { + bt656-supply = <&vcc1v8_dvp>; + audio-supply = <&vcca1v8_codec>; +@@ -1012,6 +1121,14 @@ sound { + vcc1v8_codec_en: vcc1v8-codec-en { + rockchip,pins = <3 RK_PA4 RK_FUNC_GPIO &pcfg_pull_down>; + }; ++ ++ hp_det: hp-det { ++ rockchip,pins = <4 RK_PD4 RK_FUNC_GPIO &pcfg_pull_none>; ++ }; ++ ++ spk_en: spk-en { ++ rockchip,pins = <0 RK_PB3 RK_FUNC_GPIO &pcfg_pull_none>; ++ }; + }; + + stk3311 { +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0071-arm64-dts-rockchip-rk3399-pinephone-pro-Add-modem-su.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0071-arm64-dts-rockchip-rk3399-pinephone-pro-Add-modem-su.patch new file mode 100644 index 000000000..2c6c22931 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0071-arm64-dts-rockchip-rk3399-pinephone-pro-Add-modem-su.patch @@ -0,0 +1,151 @@ +From 9e0e6397372096009e4c9c0b10447ab31c54f741 Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Fri, 9 Sep 2022 16:39:58 +0200 +Subject: [PATCH 71/84] arm64: dts: rockchip: rk3399-pinephone-pro: Add modem + support + +- Host USB for the modem +- Power supplies +- Power controller driver + +Signed-off-by: Ondrej Jirman +(cherry picked from commit 88e10241f189011429c9587ac44eea465244b8c3) +--- + .../dts/rockchip/rk3399-pinephone-pro.dts | 93 +++++++++++++++++++ + 1 file changed, 93 insertions(+) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts +index 977b3d186a9a..07dfaa31c361 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts +@@ -281,6 +281,30 @@ vcca1v8_s3: regulator-vcc1v8-s3 { + regulator-boot-on; + }; + ++ vcc_4g_5v: regulator-vcc-4g-5v { ++ compatible = "regulator-fixed"; ++ enable-active-high; ++ gpio = <&gpio1 RK_PC7 GPIO_ACTIVE_HIGH>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&vcc_4g_5v_en>; ++ regulator-name = "vcc_4g_5v"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ vin-supply = <&vcc5v0_sys>; ++ }; ++ ++ vcc_4g: regulator-vcc-4g { ++ compatible = "regulator-fixed"; ++ enable-active-high; ++ gpio = <&gpio4 RK_PC7 GPIO_ACTIVE_HIGH>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&vcc_4g_en>; ++ regulator-name = "vcc_4g"; ++ regulator-min-microvolt = <3800000>; ++ regulator-max-microvolt = <3800000>; ++ vin-supply = <&vcc_sys>; ++ }; ++ + vcc1v8_codec: regulator-vcc1v8-codec { + compatible = "regulator-fixed"; + enable-active-high; +@@ -1035,6 +1059,35 @@ &mipi_dsi1 { + status = "okay"; + }; + ++&uart3 { ++ status = "okay"; ++ ++ modem { ++ compatible = "quectel,eg25"; ++ char-device-name = "modem-power"; ++ ++ pinctrl-names = "default"; ++ pinctrl-0 = <&modem_control_pins>; ++ ++ power-supply = <&vcc_4g>; ++ vbus-supply = <&vcc_4g_5v>; ++ ++ enable-gpios = <&gpio0 RK_PB0 GPIO_ACTIVE_HIGH>; // W_DISABLE# ++ reset-gpios = <&gpio3 RK_PB0 GPIO_ACTIVE_HIGH>; ++ status-gpios = <&gpio3 RK_PA6 GPIO_ACTIVE_HIGH>; ++ pwrkey-gpios = <&gpio0 RK_PB5 GPIO_ACTIVE_HIGH>; ++ ++ host-ready-gpios = <&gpio0 RK_PB4 GPIO_ACTIVE_HIGH>; // apready ++ wakeup-gpios = <&gpio0 RK_PA1 GPIO_ACTIVE_HIGH>; // ri ++ ++ dtr-gpios = <&gpio0 RK_PA3 GPIO_ACTIVE_HIGH>; ++ cts-gpios = <&gpio3 RK_PC0 GPIO_ACTIVE_HIGH>; ++ rts-gpios = <&gpio3 RK_PC1 GPIO_ACTIVE_HIGH>; ++ ++ quectel,qdai = "3,0,0,4,0,0,1,1"; ++ }; ++}; ++ + &pmu_io_domains { + pmu1830-supply = <&vcc_1v8>; + status = "okay"; +@@ -1097,6 +1150,29 @@ blue_led_pin: blue-led-pin { + }; + }; + ++ modem { ++ vcc_4g_5v_en: vcc-4g-5v-en-pin { ++ rockchip,pins = <1 RK_PC7 RK_FUNC_GPIO &pcfg_pull_none>; ++ }; ++ ++ vcc_4g_en: vcc-4g-en-pin { ++ rockchip,pins = <4 RK_PC7 RK_FUNC_GPIO &pcfg_pull_none>; ++ }; ++ ++ modem_control_pins: modem-control-pins { ++ rockchip,pins = ++ <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>, ++ <3 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>, ++ <3 RK_PA6 RK_FUNC_GPIO &pcfg_pull_none>, ++ <0 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>, ++ <0 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>, ++ <0 RK_PA1 RK_FUNC_GPIO &pcfg_pull_none>, ++ <0 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>, ++ <3 RK_PC0 RK_FUNC_GPIO &pcfg_pull_none>, ++ <3 RK_PC1 RK_FUNC_GPIO &pcfg_pull_none>; ++ }; ++ }; ++ + pmic { + pmic_int_l: pmic-int-l { + rockchip,pins = <1 RK_PC5 RK_FUNC_GPIO &pcfg_pull_up>; +@@ -1269,6 +1345,15 @@ &u2phy0_host { + phy-supply = <&vcc5v0_sys>; + }; + ++&u2phy1 { ++ status = "okay"; ++}; ++ ++&u2phy1_host { ++ status = "okay"; ++ phy-supply = <&vcc5v0_sys>; ++}; ++ + &uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_xfer &uart0_cts &uart0_rts>; +@@ -1302,6 +1387,14 @@ &usb_host0_ohci { + status = "okay"; + }; + ++&usb_host1_ehci { ++ status = "okay"; ++}; ++ ++&usb_host1_ohci { ++ status = "okay"; ++}; ++ + &usbdrd3_0 { + status = "okay"; + }; +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0072-arm64-dts-rockchip-rk3399-pinephone-pro-Change-modem.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0072-arm64-dts-rockchip-rk3399-pinephone-pro-Change-modem.patch new file mode 100644 index 000000000..7f7266ea1 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0072-arm64-dts-rockchip-rk3399-pinephone-pro-Change-modem.patch @@ -0,0 +1,28 @@ +From bebc6b2cffeb6ab469434cb45aa631d38784ba0e Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Tue, 20 Feb 2024 18:31:33 +0100 +Subject: [PATCH 72/84] arm64: dts: rockchip: rk3399-pinephone-pro: Change + modem codec samplerate to 16kHz + +Signed-off-by: Ondrej Jirman +(cherry picked from commit b31904967a902b2dfea20b2b333c579ddd64c026) +--- + arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts +index 07dfaa31c361..7eed48fa1a7e 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts +@@ -1084,7 +1084,7 @@ modem { + cts-gpios = <&gpio3 RK_PC0 GPIO_ACTIVE_HIGH>; + rts-gpios = <&gpio3 RK_PC1 GPIO_ACTIVE_HIGH>; + +- quectel,qdai = "3,0,0,4,0,0,1,1"; ++ quectel,qdai = "3,0,0,4,0,1,1,1"; + }; + }; + +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0073-arm64-dts-rockchip-rk3399-pinephone-pro-Add-light-pr.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0073-arm64-dts-rockchip-rk3399-pinephone-pro-Add-light-pr.patch new file mode 100644 index 000000000..e50aa7389 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0073-arm64-dts-rockchip-rk3399-pinephone-pro-Add-light-pr.patch @@ -0,0 +1,30 @@ +From 97d822b3e75c5652824bb46d18d2e1f69f795586 Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Sun, 11 Jun 2023 19:39:10 +0200 +Subject: [PATCH 73/84] arm64: dts: rockchip: rk3399-pinephone-pro: Add + light/proximity sensor support + +Pinephone Pro uses STK3311 + +Signed-off-by: Ondrej Jirman +(cherry picked from commit e7f1d9ee0452df59f4a2f7c201db6798c39b9945) +--- + arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts +index 7eed48fa1a7e..564cbe307d0c 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts +@@ -846,6 +846,8 @@ light-sensor@48 { + pinctrl-names = "default"; + pinctrl-0 = <&light_int_l>; + proximity-near-level = <300>; ++ vdd-supply = <&vcc_3v0>; ++ leda-supply = <&vcc_3v0>; + }; + }; + +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0074-arm64-dts-rockchip-rk3399-pinephone-pro-Add-I2C-supp.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0074-arm64-dts-rockchip-rk3399-pinephone-pro-Add-I2C-supp.patch new file mode 100644 index 000000000..69e2a4b37 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0074-arm64-dts-rockchip-rk3399-pinephone-pro-Add-I2C-supp.patch @@ -0,0 +1,30 @@ +From e423b662f45bf3be22e5f4b2e4602d01bbc45a66 Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Sun, 11 Jun 2023 19:39:57 +0200 +Subject: [PATCH 74/84] arm64: dts: rockchip: rk3399-pinephone-pro: Add I2C + supply to stk3311 + +It is needed to communicate with the device, when other users of +vcc3v0_touch shut down the regulator. + +Signed-off-by: Ondrej Jirman +(cherry picked from commit 658fe4ad25378e4e8c030623e7bbe11eed74498f) +--- + arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts +index 564cbe307d0c..2a2568caf975 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts +@@ -848,6 +848,7 @@ light-sensor@48 { + proximity-near-level = <300>; + vdd-supply = <&vcc_3v0>; + leda-supply = <&vcc_3v0>; ++ i2c-supply = <&vcc3v0_touch>; + }; + }; + +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0075-arm64-dts-rockchip-rk3399-pinephone-pro-Add-magnetom.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0075-arm64-dts-rockchip-rk3399-pinephone-pro-Add-magnetom.patch new file mode 100644 index 000000000..fa8b50b3e --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0075-arm64-dts-rockchip-rk3399-pinephone-pro-Add-magnetom.patch @@ -0,0 +1,36 @@ +From 15b7efa2d0b5c2f75542d5d91c2b914c3131cbbe Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Fri, 9 Sep 2022 16:42:07 +0200 +Subject: [PATCH 75/84] arm64: dts: rockchip: rk3399-pinephone-pro: Add + magnetometer sensor support + +Pinephone Pro uses AF8133J. + +Signed-off-by: Ondrej Jirman +(cherry picked from commit 6aa4fc189489549c065a1474b42f52ab3ca9f034) +--- + arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts +index 2a2568caf975..927b481bd588 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts +@@ -971,6 +971,14 @@ usbc_ss: endpoint { + }; + }; + }; ++ ++ af8133j: compass@1c { ++ compatible = "voltafield,af8133j"; ++ reg = <0x1c>; ++ reset-gpios = <&gpio1 RK_PA1 GPIO_ACTIVE_LOW>; ++ avdd-supply = <&vcc_3v0>; ++ dvdd-supply = <&vcc_1v8>; ++ }; + }; + + &i2s0 { +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0076-arm64-dts-rockchip-rk3399-pinephone-pro-Add-mount-ma.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0076-arm64-dts-rockchip-rk3399-pinephone-pro-Add-mount-ma.patch new file mode 100644 index 000000000..bd0e701c8 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0076-arm64-dts-rockchip-rk3399-pinephone-pro-Add-mount-ma.patch @@ -0,0 +1,38 @@ +From 666714d7bfbf33f54beb6e263d4f40a6bf6c1eee Mon Sep 17 00:00:00 2001 +From: "Leonardo G. Trombetta" +Date: Mon, 13 Mar 2023 17:45:19 +0100 +Subject: [PATCH 76/84] arm64: dts: rockchip: rk3399-pinephone-pro: Add + mount-matrix for magnetometer + +After experimenting with the magnetometer on the Pinephone Pro I found out the +mount-matrix currently reported by the AF8133J driver is just the identity +matrix (no rotation), which is wrong. It would seem to me that there is +currently no `mount-matrix` info and that's why the driver reports a trivial +answer. As far as I can tell from my tests, a 90 degree clockwise rotation in +the XY plane would align it properly. + +Signed-of-by: Leonardo G. Trombetta +(cherry picked from commit 16abfccfc65a9022c7478e75f35d69869eae076f) +--- + arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts +index 927b481bd588..fd1c04c3868a 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts +@@ -978,6 +978,11 @@ af8133j: compass@1c { + reset-gpios = <&gpio1 RK_PA1 GPIO_ACTIVE_LOW>; + avdd-supply = <&vcc_3v0>; + dvdd-supply = <&vcc_1v8>; ++ ++ mount-matrix = ++ "0", "1", "0", ++ "-1", "0", "0", ++ "0", "0", "1"; + }; + }; + +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0077-arm64-dts-rockchip-rk3399-pinephone-pro-Enable-POGO-.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0077-arm64-dts-rockchip-rk3399-pinephone-pro-Enable-POGO-.patch new file mode 100644 index 000000000..2200282d7 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0077-arm64-dts-rockchip-rk3399-pinephone-pro-Enable-POGO-.patch @@ -0,0 +1,49 @@ +From 58499e1fac35c15529a15c7ebcd10234b50f612f Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Fri, 9 Sep 2022 16:42:51 +0200 +Subject: [PATCH 77/84] arm64: dts: rockchip: rk3399-pinephone-pro: Enable POGO + pins I2C + +So that userspace apps can use it. + +Signed-off-by: Ondrej Jirman +(cherry picked from commit a91c41c0dbfacd256b8beeafe28c0bfaa3202166) +--- + .../boot/dts/rockchip/rk3399-pinephone-pro.dts | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts +index fd1c04c3868a..bbc56d8d0c5b 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts +@@ -986,6 +986,14 @@ af8133j: compass@1c { + }; + }; + ++/* This bus is exposed on POGO pins */ ++&i2c5 { ++ i2c-scl-rising-time-ns = <450>; ++ i2c-scl-falling-time-ns = <15>; ++ pinctrl-0 = <&i2c5_xfer &pogo_int_pin>; ++ status = "okay"; ++}; ++ + &i2s0 { + rockchip,playback-channels = <2>; + rockchip,capture-channels = <2>; +@@ -1203,6 +1211,12 @@ vsel2_pin: vsel2-pin { + }; + }; + ++ pogo { ++ pogo_int_pin: pogo-int { ++ rockchip,pins = <3 RK_PA0 RK_FUNC_GPIO &pcfg_pull_up>; ++ }; ++ }; ++ + sdio-pwrseq { + wifi_enable_h_pin: wifi-enable-h-pin { + rockchip,pins = <0 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>; +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0078-arm64-dts-rockchip-rk3399-pinephone-pro-Add-pinephon.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0078-arm64-dts-rockchip-rk3399-pinephone-pro-Add-pinephon.patch new file mode 100644 index 000000000..9bd378af4 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0078-arm64-dts-rockchip-rk3399-pinephone-pro-Add-pinephon.patch @@ -0,0 +1,187 @@ +From 74636887a5f0870ddd82a7e4608e131bab8b85e6 Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Fri, 9 Sep 2022 16:43:39 +0200 +Subject: [PATCH 78/84] arm64: dts: rockchip: rk3399-pinephone-pro: Add + pinephone keyboard support + +Keyboard can be connected over I2C. + +Signed-off-by: Ondrej Jirman +(cherry picked from commit a1e59835ded8ecf3ac45f1bfd2f46420ab96d6e9) +--- + .../dts/rockchip/rk3399-pinephone-pro.dts | 145 ++++++++++++++++++ + 1 file changed, 145 insertions(+) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts +index bbc56d8d0c5b..e1cd2f607fd3 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts +@@ -89,6 +89,122 @@ bat: battery { + <3400000 0>; + }; + ++ ppkb_battery: keyboard-battery { ++ compatible = "simple-battery"; ++ voltage-min-design-microvolt = <3000000>; ++ voltage-max-design-microvolt = <4200000>; ++ energy-full-design-microwatt-hours = <21000000>; ++ charge-full-design-microamp-hours = <6000000>; ++ precharge-current-microamp = <100000>; ++ charge-term-current-microamp = <50000>; ++ constant-charge-current-max-microamp = <2000000>; ++ constant-charge-voltage-max-microvolt = <4200000>; ++ factory-internal-resistance-micro-ohms = <120000>; ++ ocv-capacity-celsius = <20>; ++ ocv-capacity-table-0 = ++ <4147328 100>, ++ <4132636 99>, ++ <4121720 98>, ++ <4110905 97>, ++ <4102063 96>, ++ <4092428 95>, ++ <4082371 94>, ++ <4074137 93>, ++ <4064172 92>, ++ <4056387 91>, ++ <4047198 90>, ++ <4038599 89>, ++ <4030933 88>, ++ <4021831 87>, ++ <4012613 86>, ++ <4003863 85>, ++ <3995132 84>, ++ <3986108 83>, ++ <3977434 82>, ++ <3967977 81>, ++ <3960286 80>, ++ <3951737 79>, ++ <3943518 78>, ++ <3935723 77>, ++ <3928692 76>, ++ <3920093 75>, ++ <3912676 74>, ++ <3905481 73>, ++ <3899881 72>, ++ <3892341 71>, ++ <3887140 70>, ++ <3880005 69>, ++ <3876060 68>, ++ <3869195 67>, ++ <3863234 66>, ++ <3857808 65>, ++ <3851464 64>, ++ <3846976 63>, ++ <3840724 62>, ++ <3835254 61>, ++ <3830946 60>, ++ <3826564 59>, ++ <3821275 58>, ++ <3817413 57>, ++ <3811941 56>, ++ <3808947 55>, ++ <3804959 54>, ++ <3800958 53>, ++ <3797447 52>, ++ <3794303 51>, ++ <3790341 50>, ++ <3787022 49>, ++ <3783436 48>, ++ <3779936 47>, ++ <3776176 46>, ++ <3772160 45>, ++ <3769348 44>, ++ <3766705 43>, ++ <3762481 42>, ++ <3760894 41>, ++ <3758396 40>, ++ <3755803 39>, ++ <3753543 38>, ++ <3749691 37>, ++ <3747026 36>, ++ <3743937 35>, ++ <3741872 34>, ++ <3738529 33>, ++ <3737528 32>, ++ <3734059 31>, ++ <3731586 30>, ++ <3728576 29>, ++ <3725939 28>, ++ <3721208 27>, ++ <3718239 26>, ++ <3713032 25>, ++ <3709785 24>, ++ <3704045 23>, ++ <3701203 22>, ++ <3695965 21>, ++ <3691074 20>, ++ <3684562 19>, ++ <3679140 18>, ++ <3670993 17>, ++ <3664243 16>, ++ <3655383 15>, ++ <3647666 14>, ++ <3642747 13>, ++ <3637775 12>, ++ <3632593 11>, ++ <3627120 10>, ++ <3620923 9>, ++ <3611465 8>, ++ <3597536 7>, ++ <3577366 6>, ++ <3545253 5>, ++ <3497377 4>, ++ <3430377 3>, ++ <3337780 2>, ++ <3183953 1>, ++ <3064061 0>; ++ }; ++ + backlight: backlight { + compatible = "pwm-backlight"; + pwms = <&pwm0 0 50000 0>; +@@ -381,6 +497,15 @@ vibrator { + enable-gpios = <&gpio3 RK_PB1 GPIO_ACTIVE_HIGH>; + vcc-supply = <&vcc3v3_sys>; + }; ++ ++ keyboard-power { ++ compatible = "megi,pinephone-keyboard-power-manager"; ++ phone-battery = "rk818-battery"; ++ phone-usb = "rk818-usb"; ++ kb-battery = "ip5xxx-battery"; ++ kb-boost = "ip5xxx-boost"; ++ kb-usb = "ip5xxx-usb"; ++ }; + }; + + &cpu_alert0 { +@@ -992,6 +1117,26 @@ &i2c5 { + i2c-scl-falling-time-ns = <15>; + pinctrl-0 = <&i2c5_xfer &pogo_int_pin>; + status = "okay"; ++ ++ ppkb: keyboard@15 { ++ compatible = "pine64,pinephone-keyboard"; ++ reg = <0x15>; ++ interrupt-parent = <&gpio3>; ++ interrupts = ; ++ vbat-supply = <&vcc5v0_sys>; ++ wakeup-source; ++ ++ i2c { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ charger@75 { ++ compatible = "injoinic,ip5209"; ++ reg = <0x75>; ++ monitored-battery = <&ppkb_battery>; ++ }; ++ }; ++ }; + }; + + &i2s0 { +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0079-arm64-dts-rockchip-rk3399-pinephone-pro-Switch-LED-b.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0079-arm64-dts-rockchip-rk3399-pinephone-pro-Switch-LED-b.patch new file mode 100644 index 000000000..5cbf93a4b --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0079-arm64-dts-rockchip-rk3399-pinephone-pro-Switch-LED-b.patch @@ -0,0 +1,42 @@ +From f8b352c3ea9ab947c39843aa8613f37eff53f2d0 Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Thu, 30 Mar 2023 13:45:08 +0200 +Subject: [PATCH 79/84] arm64: dts: rockchip: rk3399-pinephone-pro: Switch LED + backlight PWM from 1kHz to 20kHz + +This gets rid of measurable backlight flicker, because LED driver's feedback +voltage reference lowpass filter is now driven above the cutoff frequency +of 5 kHz. + +Also adapt the brightness levels curve, to make sure the lowest setting +satisfies requirement to have duty cycle at least 250ns. Backlight LED +driver doesn't react to smaller pulses on the EN/PWM pin. + +Signed-off-by: Ondrej Jirman +(cherry picked from commit 42222d8aab5e43e8240985cb4724f503715a1054) +--- + arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts +index e1cd2f607fd3..efd478d70d25 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts +@@ -208,6 +208,14 @@ ppkb_battery: keyboard-battery { + backlight: backlight { + compatible = "pwm-backlight"; + pwms = <&pwm0 0 50000 0>; ++ brightness-levels = ++ <0 250 360 470 580 690 810 949 1110 1294 1502 ++ 1737 1998 2289 2610 2964 3351 3774 4233 4731 ++ 5268 5847 6467 7133 7845 8604 9412 10271 11182 ++ 12146 13164 14239 15374 16568 17822 19140 20521 ++ 21969 23483 25068 26722 28447 30247 32121 34071 ++ 36099 38210 40400 42669 45026 47468 50000>; ++ default-brightness-level = <17>; + }; + + gpio-keys { +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0080-arm64-dts-rockchip-rk3399-pinephone-pro-Pre-configur.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0080-arm64-dts-rockchip-rk3399-pinephone-pro-Pre-configur.patch new file mode 100644 index 000000000..ea347de40 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0080-arm64-dts-rockchip-rk3399-pinephone-pro-Pre-configur.patch @@ -0,0 +1,111 @@ +From 640b4b539e3e667d3ef50026eaddf090afda0541 Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Sun, 21 May 2023 01:42:25 +0200 +Subject: [PATCH 80/84] arm64: dts: rockchip: rk3399-pinephone-pro: + Pre-configure DMC + +This enables dynamic DRAM reclocking. The node needs to be okayed +by U-Boot/firmware combo known to support it. Do not enable &dmc +by default. + +Signed-off-by: Ondrej Jirman +(cherry picked from commit fbae8f31862e79cec310206acba287343d372d50) +--- + .../dts/rockchip/rk3399-pinephone-pro.dts | 33 +++++++++++++++++++ + arch/arm64/boot/dts/rockchip/rk3399-t.dtsi | 29 ++++++++++++++++ + 2 files changed, 62 insertions(+) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts +index efd478d70d25..41eede2b7c60 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts +@@ -558,6 +558,39 @@ cdn_dp_out: endpoint { + }; + }; + ++&dfi { ++ status = "okay"; ++}; ++ ++&dmc { ++ // This node can only be enabled by FDT patching from U-Boot that ++ // uses Rockchip TPL/TF-A. DMC only works with the downstream firmware. ++ // If you enabled this on mainline, your phone will lock up on boot. ++ //status = "okay"; ++ ++ center-supply = <&vdd_center>; ++ ++ rockchip,pd-idle-ns = <160>; ++ rockchip,sr-idle-ns = <10240>; ++ rockchip,sr-mc-gate-idle-ns = <40960>; ++ rockchip,srpd-lite-idle-ns = <61440>; ++ rockchip,standby-idle-ns = <81920>; ++ ++ rockchip,lpddr4_odt_dis_freq = <666000000>; ++ ++ rockchip,srpd-lite-idle-dis-freq-hz = <0>; ++ rockchip,standby-idle-dis-freq-hz = <928000000>; ++ rockchip,sr-mc-gate-idle-dis-freq-hz = <800000000>; ++ rockchip,pd-idle-dis-freq-hz = <800000000>; ++ rockchip,sr-idle-dis-freq-hz = <800000000>; ++}; ++ ++&dmc_opp_table { ++ opp00 { ++ opp-suspend; ++ }; ++}; ++ + &emmc_phy { + status = "okay"; + }; +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-t.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-t.dtsi +index 72989f03fcb1..20a9c1ce383d 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-t.dtsi ++++ b/arch/arm64/boot/dts/rockchip/rk3399-t.dtsi +@@ -85,6 +85,31 @@ opp03 { + opp-microvolt = <975000 975000 1150000>; + }; + }; ++ ++ dmc_opp_table: opp-table-3 { ++ compatible = "operating-points-v2"; ++ ++ opp00 { ++ opp-hz = /bits/ 64 <328000000>; ++ opp-microvolt = <900000>; ++ }; ++ opp01 { ++ opp-hz = /bits/ 64 <416000000>; ++ opp-microvolt = <900000>; ++ }; ++ opp02 { ++ opp-hz = /bits/ 64 <666000000>; ++ opp-microvolt = <900000>; ++ }; ++ opp03 { ++ opp-hz = /bits/ 64 <856000000>; ++ opp-microvolt = <900000>; ++ }; ++ opp04 { ++ opp-hz = /bits/ 64 <928000000>; ++ opp-microvolt = <925000>; ++ }; ++ }; + }; + + &cpu_l0 { +@@ -111,6 +136,10 @@ &cpu_b1 { + operating-points-v2 = <&cluster1_opp>; + }; + ++&dmc { ++ operating-points-v2 = <&dmc_opp_table>; ++}; ++ + &gpu { + operating-points-v2 = <&gpu_opp_table>; + }; +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0081-arm64-dts-rockchip-rk3399-pinephone-pro-Improve-SPI-.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0081-arm64-dts-rockchip-rk3399-pinephone-pro-Improve-SPI-.patch new file mode 100644 index 000000000..e270f4aad --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0081-arm64-dts-rockchip-rk3399-pinephone-pro-Improve-SPI-.patch @@ -0,0 +1,37 @@ +From 22256b60a41f614c7491cda57f62622af230ec4b Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Thu, 29 Jun 2023 16:28:08 +0200 +Subject: [PATCH 81/84] arm64: dts: rockchip: rk3399-pinephone-pro: Improve SPI + access speed + +From 300 KiB/s to 2MiB/s. + +Signed-off-by: Ondrej Jirman +(cherry picked from commit 9f2f299bd46901a703d16f39fca9b219dcc8b09c) +--- + arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts +index 41eede2b7c60..ece5473efcd6 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts +@@ -1513,11 +1513,14 @@ &sdhci { + + &spi1 { + status = "okay"; ++ assigned-clocks = <&cru SCLK_SPI1>; ++ assigned-clock-rates = <100000000>; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; +- spi-max-frequency = <10000000>; ++ m25p,fast-read; ++ spi-max-frequency = <50000000>; + vcc-supply = <&vcc_1v8>; + }; + }; +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0082-arm64-dts-rockchip-rk3399-pinephone-pro-Assign-power.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0082-arm64-dts-rockchip-rk3399-pinephone-pro-Assign-power.patch new file mode 100644 index 000000000..d24818b34 --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0082-arm64-dts-rockchip-rk3399-pinephone-pro-Assign-power.patch @@ -0,0 +1,30 @@ +From 3e56a1d0de12219b746d8959a84259c65d070d0b Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Tue, 9 Sep 2025 08:31:21 +0200 +Subject: [PATCH 82/84] arm64: dts: rockchip: rk3399-pinephone-pro: Assign + power supplies to audio codec + +Signed-off-by: Ondrej Jirman +(cherry picked from commit 4400cddfa923adb0183b157603581172137f6790) +--- + arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts +index ece5473efcd6..489e005bf872 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts +@@ -1077,6 +1077,10 @@ rt5640: rt5640@1c { + clock-names = "mclk"; + assigned-clocks = <&cru SCLK_I2S0_8CH>; + assigned-clock-rates = <11289599>; ++ avdd-supply = <&vcca3v0_codec>; ++ cpvdd-supply = <&vcca3v0_codec>; ++ spkvdd-supply = <&vcc5v0_sys>; ++ dbvdd-supply = <&vcca1v8_codec>; + realtek,dmic1-data-pin = <1>; + realtek,in3-differential; + realtek,lout-differential; +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0083-arm64-dts-rockchip-rk3399-pinephone-pro-Add-camera-f.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0083-arm64-dts-rockchip-rk3399-pinephone-pro-Add-camera-f.patch new file mode 100644 index 000000000..797de3ccd --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0083-arm64-dts-rockchip-rk3399-pinephone-pro-Add-camera-f.patch @@ -0,0 +1,75 @@ +From 6f77254d3715eec8649b422c06758be6965bc907 Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Tue, 9 Sep 2025 10:17:32 +0200 +Subject: [PATCH 83/84] arm64: dts: rockchip: rk3399-pinephone-pro: Add camera + flash controller + +This exact controller is not present on the board, and the real control +interface is slightly different. Don't upstream this. + +It's good enough for experiments/basic lighting. + +Signed-off-by: Ondrej Jirman +(cherry picked from commit 56488ecd7be24b83bf8775c6ba5f01c9c061b42a) +--- + .../dts/rockchip/rk3399-pinephone-pro.dts | 23 +++++++++++++++++++ + 1 file changed, 23 insertions(+) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts +index 489e005bf872..67b28f70b6f9 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts +@@ -260,6 +260,21 @@ multi-led { + leds = <&led_red>, <&led_green>, <&led_blue>; + }; + ++ sgm3140: led-controller { ++ compatible = "sgmicro,sgm3140"; ++ vin-supply = <&vcc3v3_sys>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&flash_pins>; ++ enable-gpios = <&gpio4 RK_PC6 GPIO_ACTIVE_HIGH>; ++ flash-gpios = <&gpio1 RK_PA3 GPIO_ACTIVE_HIGH>; ++ ++ sgm3140_flash: led { ++ function = LED_FUNCTION_FLASH; ++ color = ; ++ flash-max-timeout-us = <250000>; ++ }; ++ }; ++ + // in1 - digital mic daughhterboard + // in2 - headset mic + // in3 - modem output (muxed with mono) +@@ -935,6 +950,7 @@ wcam: camera@1a { + compatible = "sony,imx258-pdaf"; + reg = <0x1a>; + clocks = <&cru SCLK_CIF_OUT>; /* MIPI_MCLK0, derived from CIF_CLKO */ ++ flash-leds = <&sgm3140_flash>; + lens-focus = <&wcam_lens>; + orientation = <1>; /* V4L2_CAMERA_ORIENTATION_BACK */ + pinctrl-names = "default"; +@@ -942,6 +958,7 @@ wcam: camera@1a { + reset-gpios = <&gpio1 RK_PA0 GPIO_ACTIVE_LOW>; + rotation = <270>; + /* Note: both cameras also depend on vcca1v8_codec to power the I2C bus. */ ++ i2c-supply = <&vcca1v8_codec>; + vif-supply = <&vcc1v8_dvp>; + vana-supply = <&avdd2v8_dvp>; + vdig-supply = <&vcc1v2_dvp>; /* DVDD_DVP is the same as VCC1V2_DVP */ +@@ -1362,6 +1379,12 @@ green_led_pin: green-led-pin { + blue_led_pin: blue-led-pin { + rockchip,pins = <4 RK_PD6 RK_FUNC_GPIO &pcfg_pull_none>; + }; ++ ++ flash_pins: flash-pins { ++ rockchip,pins = ++ <1 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>, ++ <4 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>; ++ }; + }; + + modem { +-- +2.55.0 + diff --git a/device/community/linux-pine64-pinephonepro/megi_patches/0084-arm64-dts-rockchip-rk3399-pinephone-pro-Disable-inte.patch b/device/community/linux-pine64-pinephonepro/megi_patches/0084-arm64-dts-rockchip-rk3399-pinephone-pro-Disable-inte.patch new file mode 100644 index 000000000..80abed38a --- /dev/null +++ b/device/community/linux-pine64-pinephonepro/megi_patches/0084-arm64-dts-rockchip-rk3399-pinephone-pro-Disable-inte.patch @@ -0,0 +1,36 @@ +From 8e72c70536c1349eea588a8ddf1f7f9cd383112f Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Sun, 4 Jan 2026 23:54:58 +0100 +Subject: [PATCH 84/84] arm64: dts: rockchip: rk3399-pinephone-pro: Disable + interrupt GPIO for WiFi for the Pinephone Pro + +This breaks at least dev version of Pinephone Pro. Or use of Pinephone +Pro +with firmware configurations that don't use OOB interrupts. + +Signed-off-by: Ondrej Jirman +(cherry picked from commit 99623d100af024386f2ca07a55b9f0148e444bfd) +--- + arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts +index 67b28f70b6f9..7a3fa599f541 100644 +--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts ++++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts +@@ -1501,9 +1501,9 @@ &sdio0 { + brcmf: wifi@1 { + compatible = "brcm,bcm4329-fmac"; + reg = <1>; +- interrupt-parent = <&gpio4>; +- interrupts = ; +- interrupt-names = "host-wake"; ++ //interrupt-parent = <&gpio4>; ++ //interrupts = ; ++ //interrupt-names = "host-wake"; + pinctrl-names = "default"; + pinctrl-0 = <&wifi_host_wake_l>; + }; +-- +2.55.0 +