summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/stable/sysfs-driver-dma-idxd51
-rw-r--r--Documentation/devicetree/bindings/dma/apple,admac.yaml1
-rw-r--r--Documentation/devicetree/bindings/dma/qcom,gpi.yaml1
-rw-r--r--Documentation/devicetree/bindings/dma/renesas,rz-dmac.yaml14
-rw-r--r--Documentation/devicetree/bindings/dma/snps,dw-axi-dmac.yaml23
-rw-r--r--Documentation/devicetree/bindings/dma/ti/k3-udma.yaml2
-rw-r--r--Documentation/devicetree/bindings/dma/xilinx/xlnx,zynqmp-dma-1.0.yaml2
-rw-r--r--Documentation/devicetree/bindings/dma/xilinx/xlnx,zynqmp-dpdma.yaml2
-rw-r--r--Documentation/devicetree/bindings/pci/rockchip-dw-pcie.yaml6
-rw-r--r--Documentation/devicetree/bindings/phy/allwinner,sun50i-h6-usb3-phy.yaml4
-rw-r--r--Documentation/devicetree/bindings/phy/allwinner,sun6i-a31-mipi-dphy.yaml2
-rw-r--r--Documentation/devicetree/bindings/phy/amlogic,axg-mipi-dphy.yaml4
-rw-r--r--Documentation/devicetree/bindings/phy/amlogic,g12a-mipi-dphy-analog.yaml4
-rw-r--r--Documentation/devicetree/bindings/phy/amlogic,g12a-usb2-phy.yaml4
-rw-r--r--Documentation/devicetree/bindings/phy/amlogic,g12a-usb3-pcie-phy.yaml4
-rw-r--r--Documentation/devicetree/bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml4
-rw-r--r--Documentation/devicetree/bindings/phy/amlogic,meson-axg-pcie.yaml4
-rw-r--r--Documentation/devicetree/bindings/phy/amlogic,meson8-hdmi-tx-phy.yaml4
-rw-r--r--Documentation/devicetree/bindings/phy/amlogic,meson8b-usb2-phy.yaml4
-rw-r--r--Documentation/devicetree/bindings/phy/brcm,bcm63xx-usbh-phy.yaml4
-rw-r--r--Documentation/devicetree/bindings/phy/brcm,sata-phy.yaml4
-rw-r--r--Documentation/devicetree/bindings/phy/cdns,salvo-phy.yaml4
-rw-r--r--Documentation/devicetree/bindings/phy/hisilicon,hi3660-usb3.yaml4
-rw-r--r--Documentation/devicetree/bindings/phy/hisilicon,hi3670-usb3.yaml6
-rw-r--r--Documentation/devicetree/bindings/phy/intel,phy-thunderbay-emmc.yaml45
-rw-r--r--Documentation/devicetree/bindings/phy/marvell,armada-3700-utmi-phy.yaml4
-rw-r--r--Documentation/devicetree/bindings/phy/marvell,armada-cp110-utmi-phy.yaml4
-rw-r--r--Documentation/devicetree/bindings/phy/marvell,mmp3-hsic-phy.yaml4
-rw-r--r--Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml1
-rw-r--r--Documentation/devicetree/bindings/phy/mediatek,mt7621-pci-phy.yaml4
-rw-r--r--Documentation/devicetree/bindings/phy/phy-cadence-sierra.yaml12
-rw-r--r--Documentation/devicetree/bindings/phy/phy-cadence-torrent.yaml10
-rw-r--r--Documentation/devicetree/bindings/phy/phy-rockchip-naneng-combphy.yaml1
-rw-r--r--Documentation/devicetree/bindings/phy/phy-tegra194-p2u.yaml4
-rw-r--r--Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml4
-rw-r--r--Documentation/devicetree/bindings/phy/qcom,qusb2-phy.yaml4
-rw-r--r--Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml1
-rw-r--r--Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml27
-rw-r--r--Documentation/devicetree/bindings/phy/qcom,usb-hs-28nm.yaml4
-rw-r--r--Documentation/devicetree/bindings/phy/qcom,usb-snps-femto-v2.yaml4
-rw-r--r--Documentation/devicetree/bindings/phy/qcom,usb-ss.yaml4
-rw-r--r--Documentation/devicetree/bindings/phy/qcom-usb-ipq4019-phy.yaml4
-rw-r--r--Documentation/devicetree/bindings/phy/samsung,exynos-pcie-phy.yaml4
-rw-r--r--Documentation/devicetree/bindings/phy/samsung,ufs-phy.yaml2
-rw-r--r--Documentation/devicetree/bindings/phy/sunplus,sp7021-usb2-phy.yaml4
-rw-r--r--Documentation/devicetree/bindings/phy/ti,phy-am654-serdes.yaml5
-rw-r--r--Documentation/devicetree/bindings/phy/ti,phy-gmii-sel.yaml8
-rw-r--r--Documentation/devicetree/bindings/phy/ti,phy-j721e-wiz.yaml25
-rw-r--r--Documentation/devicetree/bindings/phy/ti,tcan104x-can.yaml4
-rw-r--r--Documentation/devicetree/bindings/pwm/apple,s5l-fpwm.yaml51
-rw-r--r--Documentation/devicetree/bindings/pwm/mediatek,mt2712-pwm.yaml1
-rw-r--r--Documentation/devicetree/bindings/pwm/pwm-amlogic.yaml70
-rw-r--r--Documentation/devicetree/bindings/pwm/pwm-meson.txt29
-rw-r--r--Documentation/devicetree/bindings/thermal/imx-thermal.yaml14
-rw-r--r--Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm-hc.yaml4
-rw-r--r--Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm5.yaml9
-rw-r--r--Documentation/devicetree/bindings/thermal/qcom-tsens.yaml4
-rw-r--r--Documentation/devicetree/bindings/timestamp/nvidia,tegra194-hte.yaml66
-rw-r--r--Documentation/driver-api/hte/index.rst2
-rw-r--r--Documentation/driver-api/hte/tegra-hte.rst (renamed from Documentation/driver-api/hte/tegra194-hte.rst)33
-rw-r--r--Documentation/driver-api/pwm.rst13
-rw-r--r--MAINTAINERS12
-rw-r--r--arch/arm64/boot/dts/nvidia/tegra234.dtsi17
-rw-r--r--arch/um/include/shared/as-layout.h3
-rw-r--r--arch/um/kernel/skas/clone.c5
-rw-r--r--arch/um/kernel/skas/mmu.c6
-rw-r--r--arch/um/kernel/um_arch.c10
-rw-r--r--arch/um/os-Linux/skas/process.c6
-rw-r--r--arch/um/os-Linux/user_syms.c104
-rw-r--r--arch/um/scripts/Makefile.rules4
-rw-r--r--arch/x86/um/shared/sysdep/stub_32.h8
-rw-r--r--arch/x86/um/shared/sysdep/stub_64.h8
-rw-r--r--arch/x86/um/stub_segv.c2
-rw-r--r--drivers/acpi/power.c19
-rw-r--r--drivers/acpi/thermal.c45
-rw-r--r--drivers/acpi/x86/apple.c11
-rw-r--r--drivers/acpi/x86/utils.c10
-rw-r--r--drivers/dma/Kconfig1
-rw-r--r--drivers/dma/at_xdmac.c107
-rw-r--r--drivers/dma/bestcomm/sram.c19
-rw-r--r--drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c40
-rw-r--r--drivers/dma/dw-axi-dmac/dw-axi-dmac.h1
-rw-r--r--drivers/dma/dw-edma/dw-edma-core.c27
-rw-r--r--drivers/dma/dw-edma/dw-edma-v0-core.c56
-rw-r--r--drivers/dma/idxd/Makefile2
-rw-r--r--drivers/dma/idxd/cdev.c334
-rw-r--r--drivers/dma/idxd/debugfs.c138
-rw-r--r--drivers/dma/idxd/device.c113
-rw-r--r--drivers/dma/idxd/idxd.h67
-rw-r--r--drivers/dma/idxd/init.c60
-rw-r--r--drivers/dma/idxd/irq.c210
-rw-r--r--drivers/dma/idxd/registers.h126
-rw-r--r--drivers/dma/idxd/sysfs.c146
-rw-r--r--drivers/dma/imx-dma.c1
-rw-r--r--drivers/dma/ioat/init.c12
-rw-r--r--drivers/dma/ioat/registers.h7
-rw-r--r--drivers/dma/mv_xor_v2.c35
-rw-r--r--drivers/dma/of-dma.c2
-rw-r--r--drivers/dma/qcom/gpi.c1
-rw-r--r--drivers/dma/qcom/hidma_mgmt.c2
-rw-r--r--drivers/dma/sh/rz-dmac.c18
-rw-r--r--drivers/dma/tegra20-apb-dma.c5
-rw-r--r--drivers/dma/ti/Makefile3
-rw-r--r--drivers/dma/ti/edma.c8
-rw-r--r--drivers/dma/ti/k3-psil-j784s4.c354
-rw-r--r--drivers/dma/ti/k3-psil-priv.h1
-rw-r--r--drivers/dma/ti/k3-psil.c1
-rw-r--r--drivers/dma/ti/k3-udma.c75
-rw-r--r--drivers/dma/xilinx/zynqmp_dma.c6
-rw-r--r--drivers/gpio/gpio-tegra186.c1
-rw-r--r--drivers/hte/hte-tegra194-test.c2
-rw-r--r--drivers/hte/hte-tegra194.c169
-rw-r--r--drivers/hte/hte.c2
-rw-r--r--drivers/idle/intel_idle.c59
-rw-r--r--drivers/mtd/ubi/build.c2
-rw-r--r--drivers/mtd/ubi/eba.c19
-rw-r--r--drivers/phy/Kconfig2
-rw-r--r--drivers/phy/allwinner/phy-sun4i-usb.c8
-rw-r--r--drivers/phy/amlogic/phy-meson-axg-mipi-dphy.c4
-rw-r--r--drivers/phy/broadcom/phy-bcm-ns-usb2.c2
-rw-r--r--drivers/phy/broadcom/phy-brcm-usb.c6
-rw-r--r--drivers/phy/cadence/cdns-dphy-rx.c32
-rw-r--r--drivers/phy/cadence/cdns-dphy.c6
-rw-r--r--drivers/phy/cadence/phy-cadence-sierra.c250
-rw-r--r--drivers/phy/cadence/phy-cadence-torrent.c6
-rw-r--r--drivers/phy/freescale/phy-fsl-imx8qm-lvds-phy.c6
-rw-r--r--drivers/phy/intel/Kconfig10
-rw-r--r--drivers/phy/intel/Makefile1
-rw-r--r--drivers/phy/intel/phy-intel-lgm-combo.c5
-rw-r--r--drivers/phy/intel/phy-intel-thunderbay-emmc.c509
-rw-r--r--drivers/phy/marvell/phy-pxa-28nm-hsic.c2
-rw-r--r--drivers/phy/marvell/phy-pxa-28nm-usb2.c2
-rw-r--r--drivers/phy/mediatek/Makefile1
-rw-r--r--drivers/phy/mediatek/phy-mtk-hdmi-mt8195.c495
-rw-r--r--drivers/phy/mediatek/phy-mtk-hdmi-mt8195.h113
-rw-r--r--drivers/phy/mediatek/phy-mtk-hdmi.c15
-rw-r--r--drivers/phy/mediatek/phy-mtk-hdmi.h3
-rw-r--r--drivers/phy/mediatek/phy-mtk-mipi-dsi.c5
-rw-r--r--drivers/phy/motorola/phy-cpcap-usb.c6
-rw-r--r--drivers/phy/motorola/phy-mapphone-mdm6600.c6
-rw-r--r--drivers/phy/phy-lgm-usb.c6
-rw-r--r--drivers/phy/qualcomm/phy-qcom-apq8064-sata.c6
-rw-r--r--drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c8
-rw-r--r--drivers/phy/qualcomm/phy-qcom-ipq806x-sata.c6
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-combo.c19
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-pcie.c263
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v4_20.h2
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v5_20.h3
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-pcs-v5_20.h1
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v5_20.h24
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-ufs.c98
-rw-r--r--drivers/phy/renesas/phy-rcar-gen3-pcie.c6
-rw-r--r--drivers/phy/renesas/phy-rcar-gen3-usb2.c6
-rw-r--r--drivers/phy/renesas/phy-rcar-gen3-usb3.c6
-rw-r--r--drivers/phy/renesas/r8a779f0-ether-serdes.c6
-rw-r--r--drivers/phy/rockchip/phy-rockchip-inno-csidphy.c6
-rw-r--r--drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c11
-rw-r--r--drivers/phy/rockchip/phy-rockchip-inno-hdmi.c6
-rw-r--r--drivers/phy/rockchip/phy-rockchip-naneng-combphy.c184
-rw-r--r--drivers/phy/rockchip/phy-rockchip-pcie.c15
-rw-r--r--drivers/phy/rockchip/phy-rockchip-typec.c6
-rw-r--r--drivers/phy/st/phy-miphy28lp.c42
-rw-r--r--drivers/phy/st/phy-spear1310-miphy.c2
-rw-r--r--drivers/phy/st/phy-spear1340-miphy.c2
-rw-r--r--drivers/phy/st/phy-stm32-usbphyc.c9
-rw-r--r--drivers/phy/tegra/xusb-tegra186.c20
-rw-r--r--drivers/phy/tegra/xusb.c8
-rw-r--r--drivers/phy/tegra/xusb.h1
-rw-r--r--drivers/phy/ti/phy-am654-serdes.c6
-rw-r--r--drivers/phy/ti/phy-da8xx-usb.c6
-rw-r--r--drivers/phy/ti/phy-dm816x-usb.c6
-rw-r--r--drivers/phy/ti/phy-j721e-wiz.c19
-rw-r--r--drivers/phy/ti/phy-omap-usb2.c14
-rw-r--r--drivers/phy/ti/phy-ti-pipe3.c6
-rw-r--r--drivers/phy/ti/phy-twl4030-usb.c6
-rw-r--r--drivers/phy/xilinx/phy-zynqmp.c5
-rw-r--r--drivers/pwm/Kconfig12
-rw-r--r--drivers/pwm/Makefile1
-rw-r--r--drivers/pwm/core.c71
-rw-r--r--drivers/pwm/pwm-apple.c159
-rw-r--r--drivers/pwm/pwm-atmel-hlcdc.c6
-rw-r--r--drivers/pwm/pwm-atmel-tcb.c6
-rw-r--r--drivers/pwm/pwm-atmel.c6
-rw-r--r--drivers/pwm/pwm-bcm-iproc.c6
-rw-r--r--drivers/pwm/pwm-bcm2835.c6
-rw-r--r--drivers/pwm/pwm-berlin.c6
-rw-r--r--drivers/pwm/pwm-brcmstb.c6
-rw-r--r--drivers/pwm/pwm-clk.c6
-rw-r--r--drivers/pwm/pwm-cros-ec.c6
-rw-r--r--drivers/pwm/pwm-hibvt.c6
-rw-r--r--drivers/pwm/pwm-img.c6
-rw-r--r--drivers/pwm/pwm-imx-tpm.c6
-rw-r--r--drivers/pwm/pwm-lpc18xx-sct.c6
-rw-r--r--drivers/pwm/pwm-lpss-platform.c5
-rw-r--r--drivers/pwm/pwm-meson.c6
-rw-r--r--drivers/pwm/pwm-mtk-disp.c40
-rw-r--r--drivers/pwm/pwm-omap-dmtimer.c6
-rw-r--r--drivers/pwm/pwm-rcar.c8
-rw-r--r--drivers/pwm/pwm-rockchip.c6
-rw-r--r--drivers/pwm/pwm-samsung.c6
-rw-r--r--drivers/pwm/pwm-sifive.c6
-rw-r--r--drivers/pwm/pwm-spear.c6
-rw-r--r--drivers/pwm/pwm-sprd.c6
-rw-r--r--drivers/pwm/pwm-sti.c6
-rw-r--r--drivers/pwm/pwm-stm32-lp.c2
-rw-r--r--drivers/pwm/pwm-stm32.c10
-rw-r--r--drivers/pwm/pwm-sun4i.c6
-rw-r--r--drivers/pwm/pwm-tegra.c6
-rw-r--r--drivers/pwm/pwm-tiecap.c6
-rw-r--r--drivers/pwm/pwm-tiehrpwm.c6
-rw-r--r--drivers/pwm/pwm-vt8500.c6
-rw-r--r--drivers/pwm/pwm-xilinx.c5
-rw-r--r--drivers/soundwire/Kconfig10
-rw-r--r--drivers/soundwire/Makefile7
-rw-r--r--drivers/soundwire/amd_manager.c1208
-rw-r--r--drivers/soundwire/amd_manager.h258
-rw-r--r--drivers/soundwire/bus.c112
-rw-r--r--drivers/soundwire/bus.h20
-rw-r--r--drivers/soundwire/cadence_master.c139
-rw-r--r--drivers/soundwire/cadence_master.h5
-rw-r--r--drivers/soundwire/dmi-quirks.c25
-rw-r--r--drivers/soundwire/generic_bandwidth_allocation.c15
-rw-r--r--drivers/soundwire/intel.c336
-rw-r--r--drivers/soundwire/intel.h67
-rw-r--r--drivers/soundwire/intel_auxdevice.c6
-rw-r--r--drivers/soundwire/intel_bus_common.c259
-rw-r--r--drivers/soundwire/qcom.c20
-rw-r--r--drivers/soundwire/stream.c20
-rw-r--r--drivers/thermal/cpuidle_cooling.c3
-rw-r--r--drivers/thermal/gov_step_wise.c28
-rw-r--r--drivers/thermal/intel/Kconfig9
-rw-r--r--drivers/thermal/intel/Makefile1
-rw-r--r--drivers/thermal/intel/intel_menlow.c521
-rw-r--r--drivers/thermal/intel/intel_pch_thermal.c3
-rw-r--r--drivers/thermal/mediatek/auxadc_thermal.c89
-rw-r--r--drivers/thermal/thermal_core.c6
-rw-r--r--fs/Makefile2
-rw-r--r--fs/hostfs/Makefile6
-rw-r--r--fs/hostfs/hostfs_user_exp.c28
-rw-r--r--fs/proc/proc_sysctl.c55
-rw-r--r--fs/ubifs/compress.c1
-rw-r--r--fs/ubifs/dir.c7
-rw-r--r--fs/ubifs/tnc.c142
-rw-r--r--include/linux/dma/ti-cppi5.h1
-rw-r--r--include/linux/mfd/stm32-timers.h1
-rw-r--r--include/linux/pwm.h13
-rw-r--r--include/linux/soundwire/sdw_amd.h109
-rw-r--r--include/linux/soundwire/sdw_intel.h11
-rw-r--r--include/linux/sysctl.h12
-rw-r--r--include/linux/thermal.h1
-rw-r--r--include/uapi/linux/idxd.h48
-rw-r--r--kernel/pid_namespace.c3
-rw-r--r--kernel/pid_sysctl.h3
-rw-r--r--kernel/power/hibernate.c15
-rw-r--r--kernel/power/power.h1
-rw-r--r--kernel/power/swap.c8
-rwxr-xr-xscripts/check-sysctl-docs16
257 files changed, 6722 insertions, 2885 deletions
diff --git a/Documentation/ABI/stable/sysfs-driver-dma-idxd b/Documentation/ABI/stable/sysfs-driver-dma-idxd
index 3becc9a82bdf..534b7a3d59fc 100644
--- a/Documentation/ABI/stable/sysfs-driver-dma-idxd
+++ b/Documentation/ABI/stable/sysfs-driver-dma-idxd
@@ -136,6 +136,22 @@ Description: The last executed device administrative command's status/error.
Also last configuration error overloaded.
Writing to it will clear the status.
+What: /sys/bus/dsa/devices/dsa<m>/iaa_cap
+Date: Sept 14, 2022
+KernelVersion: 6.0.0
+Contact: dmaengine@vger.kernel.org
+Description: IAA (IAX) capability mask. Exported to user space for application
+ consumption. This attribute should only be visible on IAA devices
+ that are version 2 or later.
+
+What: /sys/bus/dsa/devices/dsa<m>/event_log_size
+Date: Sept 14, 2022
+KernelVersion: 6.4.0
+Contact: dmaengine@vger.kernel.org
+Description: The event log size to be configured. Default is 64 entries and
+ occupies 4k size if the evl entry is 64 bytes. It's visible
+ only on platforms that support the capability.
+
What: /sys/bus/dsa/devices/wq<m>.<n>/block_on_fault
Date: Oct 27, 2020
KernelVersion: 5.11.0
@@ -219,6 +235,16 @@ Contact: dmaengine@vger.kernel.org
Description: Indicate whether ATS disable is turned on for the workqueue.
0 indicates ATS is on, and 1 indicates ATS is off for the workqueue.
+What: /sys/bus/dsa/devices/wq<m>.<n>/prs_disable
+Date: Sept 14, 2022
+KernelVersion: 6.4.0
+Contact: dmaengine@vger.kernel.org
+Description: Controls whether PRS disable is turned on for the workqueue.
+ 0 indicates PRS is on, and 1 indicates PRS is off for the
+ workqueue. This option overrides block_on_fault attribute
+ if set. It's visible only on platforms that support the
+ capability.
+
What: /sys/bus/dsa/devices/wq<m>.<n>/occupancy
Date May 25, 2021
KernelVersion: 5.14.0
@@ -302,3 +328,28 @@ Description: Allows control of the number of batch descriptors that can be
1 (1/2 of max value), 2 (1/4 of the max value), and 3 (1/8 of
the max value). It's visible only on platforms that support
the capability.
+
+What: /sys/bus/dsa/devices/wq<m>.<n>/dsa<x>\!wq<m>.<n>/file<y>/cr_faults
+Date: Sept 14, 2022
+KernelVersion: 6.4.0
+Contact: dmaengine@vger.kernel.org
+Description: Show the number of Completion Record (CR) faults this application
+ has caused.
+
+What: /sys/bus/dsa/devices/wq<m>.<n>/dsa<x>\!wq<m>.<n>/file<y>/cr_fault_failures
+Date: Sept 14, 2022
+KernelVersion: 6.4.0
+Contact: dmaengine@vger.kernel.org
+Description: Show the number of Completion Record (CR) faults failures that this
+ application has caused. The failure counter is incremented when the
+ driver cannot fault in the address for the CR. Typically this is caused
+ by a bad address programmed in the submitted descriptor or a malicious
+ submitter is using bad CR address on purpose.
+
+What: /sys/bus/dsa/devices/wq<m>.<n>/dsa<x>\!wq<m>.<n>/file<y>/pid
+Date: Sept 14, 2022
+KernelVersion: 6.4.0
+Contact: dmaengine@vger.kernel.org
+Description: Show the process id of the application that opened the file. This is
+ helpful information for a monitor daemon that wants to kill the
+ application that opened the file.
diff --git a/Documentation/devicetree/bindings/dma/apple,admac.yaml b/Documentation/devicetree/bindings/dma/apple,admac.yaml
index 05163d124ec3..ab193bc8bdbb 100644
--- a/Documentation/devicetree/bindings/dma/apple,admac.yaml
+++ b/Documentation/devicetree/bindings/dma/apple,admac.yaml
@@ -26,6 +26,7 @@ properties:
- enum:
- apple,t6000-admac
- apple,t8103-admac
+ - apple,t8112-admac
- const: apple,admac
reg:
diff --git a/Documentation/devicetree/bindings/dma/qcom,gpi.yaml b/Documentation/devicetree/bindings/dma/qcom,gpi.yaml
index fc5de7b6f19e..f61145c91b6d 100644
--- a/Documentation/devicetree/bindings/dma/qcom,gpi.yaml
+++ b/Documentation/devicetree/bindings/dma/qcom,gpi.yaml
@@ -24,6 +24,7 @@ properties:
- qcom,sm6350-gpi-dma
- items:
- enum:
+ - qcom,qcm2290-gpi-dma
- qcom,qdu1000-gpi-dma
- qcom,sc7280-gpi-dma
- qcom,sm6115-gpi-dma
diff --git a/Documentation/devicetree/bindings/dma/renesas,rz-dmac.yaml b/Documentation/devicetree/bindings/dma/renesas,rz-dmac.yaml
index f638d3934e71..c284abc6784a 100644
--- a/Documentation/devicetree/bindings/dma/renesas,rz-dmac.yaml
+++ b/Documentation/devicetree/bindings/dma/renesas,rz-dmac.yaml
@@ -54,6 +54,11 @@ properties:
- description: DMA main clock
- description: DMA register access clock
+ clock-names:
+ items:
+ - const: main
+ - const: register
+
'#dma-cells':
const: 1
description:
@@ -77,16 +82,23 @@ properties:
- description: Reset for DMA ARESETN reset terminal
- description: Reset for DMA RST_ASYNC reset terminal
+ reset-names:
+ items:
+ - const: arst
+ - const: rst_async
+
required:
- compatible
- reg
- interrupts
- interrupt-names
- clocks
+ - clock-names
- '#dma-cells'
- dma-channels
- power-domains
- resets
+ - reset-names
additionalProperties: false
@@ -124,9 +136,11 @@ examples:
"ch12", "ch13", "ch14", "ch15";
clocks = <&cpg CPG_MOD R9A07G044_DMAC_ACLK>,
<&cpg CPG_MOD R9A07G044_DMAC_PCLK>;
+ clock-names = "main", "register";
power-domains = <&cpg>;
resets = <&cpg R9A07G044_DMAC_ARESETN>,
<&cpg R9A07G044_DMAC_RST_ASYNC>;
+ reset-names = "arst", "rst_async";
#dma-cells = <1>;
dma-channels = <16>;
};
diff --git a/Documentation/devicetree/bindings/dma/snps,dw-axi-dmac.yaml b/Documentation/devicetree/bindings/dma/snps,dw-axi-dmac.yaml
index 5c81194e2300..363cf8bd150d 100644
--- a/Documentation/devicetree/bindings/dma/snps,dw-axi-dmac.yaml
+++ b/Documentation/devicetree/bindings/dma/snps,dw-axi-dmac.yaml
@@ -20,6 +20,7 @@ properties:
enum:
- snps,axi-dma-1.01a
- intel,kmb-axi-dma
+ - starfive,jh7110-axi-dma
reg:
minItems: 1
@@ -58,7 +59,8 @@ properties:
maximum: 8
resets:
- maxItems: 1
+ minItems: 1
+ maxItems: 2
snps,dma-masters:
description: |
@@ -109,6 +111,25 @@ required:
- snps,priority
- snps,block-size
+if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - starfive,jh7110-axi-dma
+then:
+ properties:
+ resets:
+ minItems: 2
+ items:
+ - description: AXI reset line
+ - description: AHB reset line
+ - description: module reset
+else:
+ properties:
+ resets:
+ maxItems: 1
+
additionalProperties: false
examples:
diff --git a/Documentation/devicetree/bindings/dma/ti/k3-udma.yaml b/Documentation/devicetree/bindings/dma/ti/k3-udma.yaml
index 97f6ae9b1236..22f6c5e2f7f4 100644
--- a/Documentation/devicetree/bindings/dma/ti/k3-udma.yaml
+++ b/Documentation/devicetree/bindings/dma/ti/k3-udma.yaml
@@ -43,7 +43,7 @@ description: |
configuration of the legacy peripheral.
allOf:
- - $ref: "../dma-controller.yaml#"
+ - $ref: ../dma-controller.yaml#
- $ref: /schemas/arm/keystone/ti,k3-sci-common.yaml#
properties:
diff --git a/Documentation/devicetree/bindings/dma/xilinx/xlnx,zynqmp-dma-1.0.yaml b/Documentation/devicetree/bindings/dma/xilinx/xlnx,zynqmp-dma-1.0.yaml
index c0a1408b12ec..23ada8f87526 100644
--- a/Documentation/devicetree/bindings/dma/xilinx/xlnx,zynqmp-dma-1.0.yaml
+++ b/Documentation/devicetree/bindings/dma/xilinx/xlnx,zynqmp-dma-1.0.yaml
@@ -15,7 +15,7 @@ maintainers:
- Michael Tretter <m.tretter@pengutronix.de>
allOf:
- - $ref: "../dma-controller.yaml#"
+ - $ref: ../dma-controller.yaml#
properties:
"#dma-cells":
diff --git a/Documentation/devicetree/bindings/dma/xilinx/xlnx,zynqmp-dpdma.yaml b/Documentation/devicetree/bindings/dma/xilinx/xlnx,zynqmp-dpdma.yaml
index 825294e3f0e8..d6cbd95ec26d 100644
--- a/Documentation/devicetree/bindings/dma/xilinx/xlnx,zynqmp-dpdma.yaml
+++ b/Documentation/devicetree/bindings/dma/xilinx/xlnx,zynqmp-dpdma.yaml
@@ -16,7 +16,7 @@ maintainers:
- Laurent Pinchart <laurent.pinchart@ideasonboard.com>
allOf:
- - $ref: "../dma-controller.yaml#"
+ - $ref: ../dma-controller.yaml#
properties:
"#dma-cells":
diff --git a/Documentation/devicetree/bindings/pci/rockchip-dw-pcie.yaml b/Documentation/devicetree/bindings/pci/rockchip-dw-pcie.yaml
index 2be72ae1169f..24c88942e59e 100644
--- a/Documentation/devicetree/bindings/pci/rockchip-dw-pcie.yaml
+++ b/Documentation/devicetree/bindings/pci/rockchip-dw-pcie.yaml
@@ -21,8 +21,12 @@ allOf:
properties:
compatible:
- items:
+ oneOf:
- const: rockchip,rk3568-pcie
+ - items:
+ - enum:
+ - rockchip,rk3588-pcie
+ - const: rockchip,rk3568-pcie
reg:
items:
diff --git a/Documentation/devicetree/bindings/phy/allwinner,sun50i-h6-usb3-phy.yaml b/Documentation/devicetree/bindings/phy/allwinner,sun50i-h6-usb3-phy.yaml
index c03b83103e87..cf4eed230565 100644
--- a/Documentation/devicetree/bindings/phy/allwinner,sun50i-h6-usb3-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/allwinner,sun50i-h6-usb3-phy.yaml
@@ -2,8 +2,8 @@
# Copyright 2019 Ondrej Jirman <megous@megous.com>
%YAML 1.2
---
-$id: "http://devicetree.org/schemas/phy/allwinner,sun50i-h6-usb3-phy.yaml#"
-$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+$id: http://devicetree.org/schemas/phy/allwinner,sun50i-h6-usb3-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Allwinner H6 USB3 PHY
diff --git a/Documentation/devicetree/bindings/phy/allwinner,sun6i-a31-mipi-dphy.yaml b/Documentation/devicetree/bindings/phy/allwinner,sun6i-a31-mipi-dphy.yaml
index fe9702e7bdd8..6a4fd4929959 100644
--- a/Documentation/devicetree/bindings/phy/allwinner,sun6i-a31-mipi-dphy.yaml
+++ b/Documentation/devicetree/bindings/phy/allwinner,sun6i-a31-mipi-dphy.yaml
@@ -45,7 +45,7 @@ properties:
maxItems: 1
allwinner,direction:
- $ref: '/schemas/types.yaml#/definitions/string'
+ $ref: /schemas/types.yaml#/definitions/string
description: |
Direction of the D-PHY:
- "rx" for receiving (e.g. when used with MIPI CSI-2);
diff --git a/Documentation/devicetree/bindings/phy/amlogic,axg-mipi-dphy.yaml b/Documentation/devicetree/bindings/phy/amlogic,axg-mipi-dphy.yaml
index 5eddaed3d853..64795f170f32 100644
--- a/Documentation/devicetree/bindings/phy/amlogic,axg-mipi-dphy.yaml
+++ b/Documentation/devicetree/bindings/phy/amlogic,axg-mipi-dphy.yaml
@@ -2,8 +2,8 @@
# Copyright 2020 BayLibre, SAS
%YAML 1.2
---
-$id: "http://devicetree.org/schemas/phy/amlogic,axg-mipi-dphy.yaml#"
-$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+$id: http://devicetree.org/schemas/phy/amlogic,axg-mipi-dphy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Amlogic AXG MIPI D-PHY
diff --git a/Documentation/devicetree/bindings/phy/amlogic,g12a-mipi-dphy-analog.yaml b/Documentation/devicetree/bindings/phy/amlogic,g12a-mipi-dphy-analog.yaml
index 7aa0c05d6ce4..c8c83acfb871 100644
--- a/Documentation/devicetree/bindings/phy/amlogic,g12a-mipi-dphy-analog.yaml
+++ b/Documentation/devicetree/bindings/phy/amlogic,g12a-mipi-dphy-analog.yaml
@@ -1,8 +1,8 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
-$id: "http://devicetree.org/schemas/phy/amlogic,g12a-mipi-dphy-analog.yaml#"
-$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+$id: http://devicetree.org/schemas/phy/amlogic,g12a-mipi-dphy-analog.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Amlogic G12A MIPI analog PHY
diff --git a/Documentation/devicetree/bindings/phy/amlogic,g12a-usb2-phy.yaml b/Documentation/devicetree/bindings/phy/amlogic,g12a-usb2-phy.yaml
index bb01c6b34dab..0031fb6a4e76 100644
--- a/Documentation/devicetree/bindings/phy/amlogic,g12a-usb2-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/amlogic,g12a-usb2-phy.yaml
@@ -2,8 +2,8 @@
# Copyright 2019 BayLibre, SAS
%YAML 1.2
---
-$id: "http://devicetree.org/schemas/phy/amlogic,g12a-usb2-phy.yaml#"
-$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+$id: http://devicetree.org/schemas/phy/amlogic,g12a-usb2-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Amlogic G12A USB2 PHY
diff --git a/Documentation/devicetree/bindings/phy/amlogic,g12a-usb3-pcie-phy.yaml b/Documentation/devicetree/bindings/phy/amlogic,g12a-usb3-pcie-phy.yaml
index 3314711292d6..1a5a12adb72b 100644
--- a/Documentation/devicetree/bindings/phy/amlogic,g12a-usb3-pcie-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/amlogic,g12a-usb3-pcie-phy.yaml
@@ -2,8 +2,8 @@
# Copyright 2019 BayLibre, SAS
%YAML 1.2
---
-$id: "http://devicetree.org/schemas/phy/amlogic,g12a-usb3-pcie-phy.yaml#"
-$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+$id: http://devicetree.org/schemas/phy/amlogic,g12a-usb3-pcie-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Amlogic G12A USB3 + PCIE Combo PHY
diff --git a/Documentation/devicetree/bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml b/Documentation/devicetree/bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml
index a90fa1baadab..009a39808318 100644
--- a/Documentation/devicetree/bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml
+++ b/Documentation/devicetree/bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml
@@ -1,8 +1,8 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
-$id: "http://devicetree.org/schemas/phy/amlogic,meson-axg-mipi-pcie-analog.yaml#"
-$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+$id: http://devicetree.org/schemas/phy/amlogic,meson-axg-mipi-pcie-analog.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Amlogic AXG shared MIPI/PCIE analog PHY
diff --git a/Documentation/devicetree/bindings/phy/amlogic,meson-axg-pcie.yaml b/Documentation/devicetree/bindings/phy/amlogic,meson-axg-pcie.yaml
index 45f3d72b1cca..40fbf8ac3271 100644
--- a/Documentation/devicetree/bindings/phy/amlogic,meson-axg-pcie.yaml
+++ b/Documentation/devicetree/bindings/phy/amlogic,meson-axg-pcie.yaml
@@ -1,8 +1,8 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
-$id: "http://devicetree.org/schemas/phy/amlogic,meson-axg-pcie.yaml#"
-$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+$id: http://devicetree.org/schemas/phy/amlogic,meson-axg-pcie.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Amlogic AXG PCIE PHY
diff --git a/Documentation/devicetree/bindings/phy/amlogic,meson8-hdmi-tx-phy.yaml b/Documentation/devicetree/bindings/phy/amlogic,meson8-hdmi-tx-phy.yaml
index 1f085cdd1c85..6f9fd1c953f0 100644
--- a/Documentation/devicetree/bindings/phy/amlogic,meson8-hdmi-tx-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/amlogic,meson8-hdmi-tx-phy.yaml
@@ -1,8 +1,8 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
-$id: "http://devicetree.org/schemas/phy/amlogic,meson8-hdmi-tx-phy.yaml#"
-$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+$id: http://devicetree.org/schemas/phy/amlogic,meson8-hdmi-tx-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Amlogic Meson8, Meson8b and Meson8m2 HDMI TX PHY
diff --git a/Documentation/devicetree/bindings/phy/amlogic,meson8b-usb2-phy.yaml b/Documentation/devicetree/bindings/phy/amlogic,meson8b-usb2-phy.yaml
index 03c4809dbe8d..df68bfe5f407 100644
--- a/Documentation/devicetree/bindings/phy/amlogic,meson8b-usb2-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/amlogic,meson8b-usb2-phy.yaml
@@ -1,8 +1,8 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
-$id: "http://devicetree.org/schemas/phy/amlogic,meson8b-usb2-phy.yaml#"
-$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+$id: http://devicetree.org/schemas/phy/amlogic,meson8b-usb2-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Amlogic Meson8, Meson8b, Meson8m2 and GXBB USB2 PHY
diff --git a/Documentation/devicetree/bindings/phy/brcm,bcm63xx-usbh-phy.yaml b/Documentation/devicetree/bindings/phy/brcm,bcm63xx-usbh-phy.yaml
index 0f0bcde9eb88..bd527f566c3b 100644
--- a/Documentation/devicetree/bindings/phy/brcm,bcm63xx-usbh-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/brcm,bcm63xx-usbh-phy.yaml
@@ -1,8 +1,8 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
-$id: "http://devicetree.org/schemas/phy/brcm,bcm63xx-usbh-phy.yaml#"
-$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+$id: http://devicetree.org/schemas/phy/brcm,bcm63xx-usbh-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
title: BCM63xx USBH PHY
diff --git a/Documentation/devicetree/bindings/phy/brcm,sata-phy.yaml b/Documentation/devicetree/bindings/phy/brcm,sata-phy.yaml
index 435b971dfd9b..8467c8e6368c 100644
--- a/Documentation/devicetree/bindings/phy/brcm,sata-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/brcm,sata-phy.yaml
@@ -1,8 +1,8 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
-$id: "http://devicetree.org/schemas/phy/brcm,sata-phy.yaml#"
-$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+$id: http://devicetree.org/schemas/phy/brcm,sata-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Broadcom SATA3 PHY
diff --git a/Documentation/devicetree/bindings/phy/cdns,salvo-phy.yaml b/Documentation/devicetree/bindings/phy/cdns,salvo-phy.yaml
index 3a07285b5470..c9e65a2facd5 100644
--- a/Documentation/devicetree/bindings/phy/cdns,salvo-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/cdns,salvo-phy.yaml
@@ -2,8 +2,8 @@
# Copyright (c) 2020 NXP
%YAML 1.2
---
-$id: "http://devicetree.org/schemas/phy/cdns,salvo-phy.yaml#"
-$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+$id: http://devicetree.org/schemas/phy/cdns,salvo-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Cadence SALVO PHY
diff --git a/Documentation/devicetree/bindings/phy/hisilicon,hi3660-usb3.yaml b/Documentation/devicetree/bindings/phy/hisilicon,hi3660-usb3.yaml
index b11d9873854a..405c6b0b88c0 100644
--- a/Documentation/devicetree/bindings/phy/hisilicon,hi3660-usb3.yaml
+++ b/Documentation/devicetree/bindings/phy/hisilicon,hi3660-usb3.yaml
@@ -19,11 +19,11 @@ properties:
const: 0
hisilicon,pericrg-syscon:
- $ref: '/schemas/types.yaml#/definitions/phandle'
+ $ref: /schemas/types.yaml#/definitions/phandle
description: phandle of syscon used to control iso refclk.
hisilicon,pctrl-syscon:
- $ref: '/schemas/types.yaml#/definitions/phandle'
+ $ref: /schemas/types.yaml#/definitions/phandle
description: phandle of syscon used to control usb tcxo.
hisilicon,eye-diagram-param:
diff --git a/Documentation/devicetree/bindings/phy/hisilicon,hi3670-usb3.yaml b/Documentation/devicetree/bindings/phy/hisilicon,hi3670-usb3.yaml
index 3c69aca6c7eb..a1a8a84dfc54 100644
--- a/Documentation/devicetree/bindings/phy/hisilicon,hi3670-usb3.yaml
+++ b/Documentation/devicetree/bindings/phy/hisilicon,hi3670-usb3.yaml
@@ -20,15 +20,15 @@ properties:
const: 0
hisilicon,pericrg-syscon:
- $ref: '/schemas/types.yaml#/definitions/phandle'
+ $ref: /schemas/types.yaml#/definitions/phandle
description: phandle of syscon used to control iso refclk.
hisilicon,pctrl-syscon:
- $ref: '/schemas/types.yaml#/definitions/phandle'
+ $ref: /schemas/types.yaml#/definitions/phandle
description: phandle of syscon used to control usb tcxo.
hisilicon,sctrl-syscon:
- $ref: '/schemas/types.yaml#/definitions/phandle'
+ $ref: /schemas/types.yaml#/definitions/phandle
description: phandle of syscon used to control phy deep sleep.
hisilicon,eye-diagram-param:
diff --git a/Documentation/devicetree/bindings/phy/intel,phy-thunderbay-emmc.yaml b/Documentation/devicetree/bindings/phy/intel,phy-thunderbay-emmc.yaml
deleted file mode 100644
index 361ffc35b16b..000000000000
--- a/Documentation/devicetree/bindings/phy/intel,phy-thunderbay-emmc.yaml
+++ /dev/null
@@ -1,45 +0,0 @@
-# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
-%YAML 1.2
----
-$id: http://devicetree.org/schemas/phy/intel,phy-thunderbay-emmc.yaml#
-$schema: http://devicetree.org/meta-schemas/core.yaml#
-
-title: Intel Thunder Bay eMMC PHY
-
-maintainers:
- - Srikandan Nandhini <nandhini.srikandan@intel.com>
-
-properties:
- compatible:
- const: intel,thunderbay-emmc-phy
-
- "#phy-cells":
- const: 0
-
- reg:
- maxItems: 1
-
- clocks:
- maxItems: 1
-
- clock-names:
- items:
- - const: emmcclk
-
-required:
- - "#phy-cells"
- - compatible
- - reg
- - clocks
-
-additionalProperties: false
-
-examples:
- - |
- mmc_phy@80440800 {
- #phy-cells = <0x0>;
- compatible = "intel,thunderbay-emmc-phy";
- reg = <0x80440800 0x100>;
- clocks = <&emmc>;
- clock-names = "emmcclk";
- };
diff --git a/Documentation/devicetree/bindings/phy/marvell,armada-3700-utmi-phy.yaml b/Documentation/devicetree/bindings/phy/marvell,armada-3700-utmi-phy.yaml
index 632d61c07f40..3aa1a46796dd 100644
--- a/Documentation/devicetree/bindings/phy/marvell,armada-3700-utmi-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/marvell,armada-3700-utmi-phy.yaml
@@ -2,8 +2,8 @@
%YAML 1.2
---
-$id: "http://devicetree.org/schemas/phy/marvell,armada-3700-utmi-phy.yaml#"
-$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+$id: http://devicetree.org/schemas/phy/marvell,armada-3700-utmi-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Marvell Armada UTMI/UTMI+ PHY
diff --git a/Documentation/devicetree/bindings/phy/marvell,armada-cp110-utmi-phy.yaml b/Documentation/devicetree/bindings/phy/marvell,armada-cp110-utmi-phy.yaml
index 43416c216190..9ce7b4c6d208 100644
--- a/Documentation/devicetree/bindings/phy/marvell,armada-cp110-utmi-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/marvell,armada-cp110-utmi-phy.yaml
@@ -2,8 +2,8 @@
%YAML 1.2
---
-$id: "http://devicetree.org/schemas/phy/marvell,armada-cp110-utmi-phy.yaml#"
-$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+$id: http://devicetree.org/schemas/phy/marvell,armada-cp110-utmi-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Marvell Armada CP110/CP115 UTMI PHY
diff --git a/Documentation/devicetree/bindings/phy/marvell,mmp3-hsic-phy.yaml b/Documentation/devicetree/bindings/phy/marvell,mmp3-hsic-phy.yaml
index ff255aa4cc10..bd3bd2f8b1cd 100644
--- a/Documentation/devicetree/bindings/phy/marvell,mmp3-hsic-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/marvell,mmp3-hsic-phy.yaml
@@ -2,8 +2,8 @@
# Copyright 2019 Lubomir Rintel <lkundrak@v3.sk>
%YAML 1.2
---
-$id: "http://devicetree.org/schemas/phy/marvell,mmp3-hsic-phy.yaml#"
-$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+$id: http://devicetree.org/schemas/phy/marvell,mmp3-hsic-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Marvell MMP3 HSIC PHY
diff --git a/Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml b/Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml
index 6cfdaadec085..f3a8b0b745d1 100644
--- a/Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/mediatek,hdmi-phy.yaml
@@ -28,6 +28,7 @@ properties:
- const: mediatek,mt2701-hdmi-phy
- const: mediatek,mt2701-hdmi-phy
- const: mediatek,mt8173-hdmi-phy
+ - const: mediatek,mt8195-hdmi-phy
reg:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/phy/mediatek,mt7621-pci-phy.yaml b/Documentation/devicetree/bindings/phy/mediatek,mt7621-pci-phy.yaml
index c2f4cb0b254a..b35c4d256e40 100644
--- a/Documentation/devicetree/bindings/phy/mediatek,mt7621-pci-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/mediatek,mt7621-pci-phy.yaml
@@ -1,8 +1,8 @@
# SPDX-License-Identifier: (GPL-2.0-only or BSD-2-Clause)
%YAML 1.2
---
-$id: "http://devicetree.org/schemas/phy/mediatek,mt7621-pci-phy.yaml#"
-$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+$id: http://devicetree.org/schemas/phy/mediatek,mt7621-pci-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Mediatek Mt7621 PCIe PHY
diff --git a/Documentation/devicetree/bindings/phy/phy-cadence-sierra.yaml b/Documentation/devicetree/bindings/phy/phy-cadence-sierra.yaml
index 6a09472740ed..37f028f7a095 100644
--- a/Documentation/devicetree/bindings/phy/phy-cadence-sierra.yaml
+++ b/Documentation/devicetree/bindings/phy/phy-cadence-sierra.yaml
@@ -1,8 +1,8 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
-$id: "http://devicetree.org/schemas/phy/phy-cadence-sierra.yaml#"
-$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+$id: http://devicetree.org/schemas/phy/phy-cadence-sierra.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Cadence Sierra PHY
@@ -61,14 +61,6 @@ properties:
- const: pll0_refclk
- const: pll1_refclk
- assigned-clocks:
- minItems: 1
- maxItems: 2
-
- assigned-clock-parents:
- minItems: 1
- maxItems: 2
-
cdns,autoconf:
type: boolean
description:
diff --git a/Documentation/devicetree/bindings/phy/phy-cadence-torrent.yaml b/Documentation/devicetree/bindings/phy/phy-cadence-torrent.yaml
index 2ad1faadda2a..dfb31314face 100644
--- a/Documentation/devicetree/bindings/phy/phy-cadence-torrent.yaml
+++ b/Documentation/devicetree/bindings/phy/phy-cadence-torrent.yaml
@@ -1,8 +1,8 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
-$id: "http://devicetree.org/schemas/phy/phy-cadence-torrent.yaml#"
-$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+$id: http://devicetree.org/schemas/phy/phy-cadence-torrent.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Cadence Torrent SD0801 PHY
@@ -44,12 +44,6 @@ properties:
- const: refclk
- const: phy_en_refclk
- assigned-clocks:
- maxItems: 3
-
- assigned-clock-parents:
- maxItems: 3
-
reg:
minItems: 1
items:
diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-naneng-combphy.yaml b/Documentation/devicetree/bindings/phy/phy-rockchip-naneng-combphy.yaml
index 8d8698412de0..9ae514fa7533 100644
--- a/Documentation/devicetree/bindings/phy/phy-rockchip-naneng-combphy.yaml
+++ b/Documentation/devicetree/bindings/phy/phy-rockchip-naneng-combphy.yaml
@@ -13,6 +13,7 @@ properties:
compatible:
enum:
- rockchip,rk3568-naneng-combphy
+ - rockchip,rk3588-naneng-combphy
reg:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/phy/phy-tegra194-p2u.yaml b/Documentation/devicetree/bindings/phy/phy-tegra194-p2u.yaml
index 445b2467f4f6..4790c6238a40 100644
--- a/Documentation/devicetree/bindings/phy/phy-tegra194-p2u.yaml
+++ b/Documentation/devicetree/bindings/phy/phy-tegra194-p2u.yaml
@@ -1,8 +1,8 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
-$id: "http://devicetree.org/schemas/phy/phy-tegra194-p2u.yaml#"
-$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+$id: http://devicetree.org/schemas/phy/phy-tegra194-p2u.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
title: NVIDIA Tegra194 & Tegra234 P2U
diff --git a/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml
index 1e104ae76ee6..c4f8e6ffa5c3 100644
--- a/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/qcom,edp-phy.yaml
@@ -2,8 +2,8 @@
%YAML 1.2
---
-$id: "http://devicetree.org/schemas/phy/qcom,edp-phy.yaml#"
-$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+$id: http://devicetree.org/schemas/phy/qcom,edp-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm eDP PHY
diff --git a/Documentation/devicetree/bindings/phy/qcom,qusb2-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,qusb2-phy.yaml
index 7f403e77f320..543c1a2811a5 100644
--- a/Documentation/devicetree/bindings/phy/qcom,qusb2-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/qcom,qusb2-phy.yaml
@@ -2,8 +2,8 @@
%YAML 1.2
---
-$id: "http://devicetree.org/schemas/phy/qcom,qusb2-phy.yaml#"
-$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+$id: http://devicetree.org/schemas/phy/qcom,qusb2-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm QUSB2 phy controller
diff --git a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml
index ef49efbd0a20..a0407fc79563 100644
--- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml
@@ -19,6 +19,7 @@ properties:
- qcom,sc8280xp-qmp-gen3x1-pcie-phy
- qcom,sc8280xp-qmp-gen3x2-pcie-phy
- qcom,sc8280xp-qmp-gen3x4-pcie-phy
+ - qcom,sdx65-qmp-gen4x2-pcie-phy
- qcom,sm8350-qmp-gen3x1-pcie-phy
- qcom,sm8550-qmp-gen3x2-pcie-phy
- qcom,sm8550-qmp-gen4x2-pcie-phy
diff --git a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml
index 64ed331880f6..94c0fab065a8 100644
--- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml
@@ -16,20 +16,25 @@ description:
properties:
compatible:
enum:
+ - qcom,sa8775p-qmp-ufs-phy
- qcom,sc8280xp-qmp-ufs-phy
- qcom,sm6125-qmp-ufs-phy
+ - qcom,sm7150-qmp-ufs-phy
- qcom,sm8550-qmp-ufs-phy
reg:
maxItems: 1
clocks:
- maxItems: 2
+ minItems: 2
+ maxItems: 3
clock-names:
+ minItems: 2
items:
- const: ref
- const: ref_aux
+ - const: qref
power-domains:
maxItems: 1
@@ -63,6 +68,26 @@ required:
- vdda-pll-supply
- "#phy-cells"
+allOf:
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - qcom,sa8775p-qmp-ufs-phy
+ then:
+ properties:
+ clocks:
+ maxItems: 3
+ clock-names:
+ maxItems: 3
+ else:
+ properties:
+ clocks:
+ maxItems: 2
+ clock-names:
+ maxItems: 2
+
additionalProperties: false
examples:
diff --git a/Documentation/devicetree/bindings/phy/qcom,usb-hs-28nm.yaml b/Documentation/devicetree/bindings/phy/qcom,usb-hs-28nm.yaml
index ca6a0836b53c..6c99e02b2b4f 100644
--- a/Documentation/devicetree/bindings/phy/qcom,usb-hs-28nm.yaml
+++ b/Documentation/devicetree/bindings/phy/qcom,usb-hs-28nm.yaml
@@ -1,8 +1,8 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
-$id: "http://devicetree.org/schemas/phy/qcom,usb-hs-28nm.yaml#"
-$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+$id: http://devicetree.org/schemas/phy/qcom,usb-hs-28nm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm Synopsys DesignWare Core 28nm High-Speed PHY
diff --git a/Documentation/devicetree/bindings/phy/qcom,usb-snps-femto-v2.yaml b/Documentation/devicetree/bindings/phy/qcom,usb-snps-femto-v2.yaml
index 85d405e028b9..a26524b7e7b7 100644
--- a/Documentation/devicetree/bindings/phy/qcom,usb-snps-femto-v2.yaml
+++ b/Documentation/devicetree/bindings/phy/qcom,usb-snps-femto-v2.yaml
@@ -1,8 +1,8 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
-$id: "http://devicetree.org/schemas/phy/qcom,usb-snps-femto-v2.yaml#"
-$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+$id: http://devicetree.org/schemas/phy/qcom,usb-snps-femto-v2.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm Synopsys Femto High-Speed USB PHY V2
diff --git a/Documentation/devicetree/bindings/phy/qcom,usb-ss.yaml b/Documentation/devicetree/bindings/phy/qcom,usb-ss.yaml
index bd1388d62ce0..6e4254ff1cd7 100644
--- a/Documentation/devicetree/bindings/phy/qcom,usb-ss.yaml
+++ b/Documentation/devicetree/bindings/phy/qcom,usb-ss.yaml
@@ -1,8 +1,8 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
-$id: "http://devicetree.org/schemas/phy/qcom,usb-ss.yaml#"
-$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+$id: http://devicetree.org/schemas/phy/qcom,usb-ss.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm Synopsys 1.0.0 SuperSpeed USB PHY
diff --git a/Documentation/devicetree/bindings/phy/qcom-usb-ipq4019-phy.yaml b/Documentation/devicetree/bindings/phy/qcom-usb-ipq4019-phy.yaml
index 3e7191b168fb..09c614952fea 100644
--- a/Documentation/devicetree/bindings/phy/qcom-usb-ipq4019-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/qcom-usb-ipq4019-phy.yaml
@@ -1,8 +1,8 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
-$id: "http://devicetree.org/schemas/phy/qcom-usb-ipq4019-phy.yaml#"
-$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+$id: http://devicetree.org/schemas/phy/qcom-usb-ipq4019-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcom IPQ40xx Dakota HS/SS USB PHY
diff --git a/Documentation/devicetree/bindings/phy/samsung,exynos-pcie-phy.yaml b/Documentation/devicetree/bindings/phy/samsung,exynos-pcie-phy.yaml
index 28e299a9609d..41df8bb08ff7 100644
--- a/Documentation/devicetree/bindings/phy/samsung,exynos-pcie-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/samsung,exynos-pcie-phy.yaml
@@ -21,12 +21,12 @@ properties:
maxItems: 1
samsung,pmu-syscon:
- $ref: '/schemas/types.yaml#/definitions/phandle'
+ $ref: /schemas/types.yaml#/definitions/phandle
description: phandle for PMU system controller interface, used to
control PMU registers bits for PCIe PHY
samsung,fsys-sysreg:
- $ref: '/schemas/types.yaml#/definitions/phandle'
+ $ref: /schemas/types.yaml#/definitions/phandle
description: phandle for FSYS sysreg interface, used to control
sysreg registers bits for PCIe PHY
diff --git a/Documentation/devicetree/bindings/phy/samsung,ufs-phy.yaml b/Documentation/devicetree/bindings/phy/samsung,ufs-phy.yaml
index c5dbb91ac402..782f975b43ae 100644
--- a/Documentation/devicetree/bindings/phy/samsung,ufs-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/samsung,ufs-phy.yaml
@@ -35,7 +35,7 @@ properties:
maxItems: 4
samsung,pmu-syscon:
- $ref: '/schemas/types.yaml#/definitions/phandle-array'
+ $ref: /schemas/types.yaml#/definitions/phandle-array
maxItems: 1
items:
minItems: 1
diff --git a/Documentation/devicetree/bindings/phy/sunplus,sp7021-usb2-phy.yaml b/Documentation/devicetree/bindings/phy/sunplus,sp7021-usb2-phy.yaml
index 069d422775bb..57914f214e06 100644
--- a/Documentation/devicetree/bindings/phy/sunplus,sp7021-usb2-phy.yaml
+++ b/Documentation/devicetree/bindings/phy/sunplus,sp7021-usb2-phy.yaml
@@ -2,8 +2,8 @@
# Copyright (C) Sunplus Co., Ltd. 2021
%YAML 1.2
---
-$id: "http://devicetree.org/schemas/phy/sunplus,sp7021-usb2-phy.yaml#"
-$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+$id: http://devicetree.org/schemas/phy/sunplus,sp7021-usb2-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Sunplus SP7021 USB 2.0 PHY Controller
diff --git a/Documentation/devicetree/bindings/phy/ti,phy-am654-serdes.yaml b/Documentation/devicetree/bindings/phy/ti,phy-am654-serdes.yaml
index 738c92bb7518..854e554eae67 100644
--- a/Documentation/devicetree/bindings/phy/ti,phy-am654-serdes.yaml
+++ b/Documentation/devicetree/bindings/phy/ti,phy-am654-serdes.yaml
@@ -34,11 +34,6 @@ properties:
Three input clocks referring to left input reference clock, refclk and right input reference
clock.
- assigned-clocks:
- $ref: "/schemas/types.yaml#/definitions/phandle-array"
- assigned-clock-parents:
- $ref: "/schemas/types.yaml#/definitions/phandle-array"
-
'#phy-cells':
const: 2
description:
diff --git a/Documentation/devicetree/bindings/phy/ti,phy-gmii-sel.yaml b/Documentation/devicetree/bindings/phy/ti,phy-gmii-sel.yaml
index 6d46f57fa1b4..be41b4547ec6 100644
--- a/Documentation/devicetree/bindings/phy/ti,phy-gmii-sel.yaml
+++ b/Documentation/devicetree/bindings/phy/ti,phy-gmii-sel.yaml
@@ -2,8 +2,8 @@
# Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com/
%YAML 1.2
---
-$id: "http://devicetree.org/schemas/phy/ti,phy-gmii-sel.yaml#"
-$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+$id: http://devicetree.org/schemas/phy/ti,phy-gmii-sel.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
title: CPSW Port's Interface Mode Selection PHY
@@ -55,6 +55,7 @@ properties:
- ti,am654-phy-gmii-sel
- ti,j7200-cpsw5g-phy-gmii-sel
- ti,j721e-cpsw9g-phy-gmii-sel
+ - ti,j784s4-cpsw9g-phy-gmii-sel
reg:
maxItems: 1
@@ -87,6 +88,7 @@ allOf:
- ti,am654-phy-gmii-sel
- ti,j7200-cpsw5g-phy-gmii-sel
- ti,j721e-cpsw9g-phy-gmii-sel
+ - ti,j784s4-cpsw9g-phy-gmii-sel
then:
properties:
'#phy-cells':
@@ -113,6 +115,7 @@ allOf:
contains:
enum:
- ti,j721e-cpsw9g-phy-gmii-sel
+ - ti,j784s4-cpsw9g-phy-gmii-sel
then:
properties:
ti,qsgmii-main-ports:
@@ -130,6 +133,7 @@ allOf:
enum:
- ti,j7200-cpsw5g-phy-gmii-sel
- ti,j721e-cpsw9g-phy-gmii-sel
+ - ti,j784s4-cpsw9g-phy-gmii-sel
then:
properties:
ti,qsgmii-main-ports: false
diff --git a/Documentation/devicetree/bindings/phy/ti,phy-j721e-wiz.yaml b/Documentation/devicetree/bindings/phy/ti,phy-j721e-wiz.yaml
index c54b36c104ab..9ea30eaba314 100644
--- a/Documentation/devicetree/bindings/phy/ti,phy-j721e-wiz.yaml
+++ b/Documentation/devicetree/bindings/phy/ti,phy-j721e-wiz.yaml
@@ -2,8 +2,8 @@
# Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
%YAML 1.2
---
-$id: "http://devicetree.org/schemas/phy/ti,phy-j721e-wiz.yaml#"
-$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+$id: http://devicetree.org/schemas/phy/ti,phy-j721e-wiz.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
title: TI J721E WIZ (SERDES Wrapper)
@@ -54,18 +54,6 @@ properties:
ranges: true
- assigned-clocks:
- minItems: 1
- maxItems: 2
-
- assigned-clock-parents:
- minItems: 1
- maxItems: 2
-
- assigned-clock-rates:
- minItems: 1
- maxItems: 2
-
typec-dir-gpios:
maxItems: 1
description:
@@ -101,6 +89,9 @@ properties:
"#clock-cells":
const: 0
+ clock-output-names:
+ maxItems: 1
+
assigned-clocks:
maxItems: 1
@@ -134,6 +125,9 @@ patternProperties:
"#clock-cells":
const: 0
+ clock-output-names:
+ maxItems: 1
+
assigned-clocks:
maxItems: 1
@@ -162,6 +156,9 @@ patternProperties:
"#clock-cells":
const: 0
+ clock-output-names:
+ maxItems: 1
+
required:
- clocks
- "#clock-cells"
diff --git a/Documentation/devicetree/bindings/phy/ti,tcan104x-can.yaml b/Documentation/devicetree/bindings/phy/ti,tcan104x-can.yaml
index 237295b2b5a8..79dad3e89aa6 100644
--- a/Documentation/devicetree/bindings/phy/ti,tcan104x-can.yaml
+++ b/Documentation/devicetree/bindings/phy/ti,tcan104x-can.yaml
@@ -1,8 +1,8 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
-$id: "http://devicetree.org/schemas/phy/ti,tcan104x-can.yaml#"
-$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+$id: http://devicetree.org/schemas/phy/ti,tcan104x-can.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
title: TCAN104x CAN TRANSCEIVER PHY
diff --git a/Documentation/devicetree/bindings/pwm/apple,s5l-fpwm.yaml b/Documentation/devicetree/bindings/pwm/apple,s5l-fpwm.yaml
new file mode 100644
index 000000000000..142157bff0cd
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/apple,s5l-fpwm.yaml
@@ -0,0 +1,51 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pwm/apple,s5l-fpwm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Apple FPWM controller
+
+maintainers:
+ - asahi@lists.linux.dev
+ - Sasha Finkelstein <fnkl.kernel@gmail.com>
+
+description: PWM controller used for keyboard backlight on ARM Macs
+
+properties:
+ compatible:
+ items:
+ - enum:
+ - apple,t8103-fpwm
+ - apple,t6000-fpwm
+ - apple,t8112-fpwm
+ - const: apple,s5l-fpwm
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ power-domains:
+ maxItems: 1
+
+ "#pwm-cells":
+ const: 2
+
+required:
+ - compatible
+ - reg
+ - clocks
+
+additionalProperties: false
+
+examples:
+ - |
+ pwm@235044000 {
+ compatible = "apple,t8103-fpwm", "apple,s5l-fpwm";
+ reg = <0x35044000 0x4000>;
+ power-domains = <&ps_fpwm1>;
+ clocks = <&clkref>;
+ #pwm-cells = <2>;
+ };
diff --git a/Documentation/devicetree/bindings/pwm/mediatek,mt2712-pwm.yaml b/Documentation/devicetree/bindings/pwm/mediatek,mt2712-pwm.yaml
index dbc974bff9e9..8e176ba7a525 100644
--- a/Documentation/devicetree/bindings/pwm/mediatek,mt2712-pwm.yaml
+++ b/Documentation/devicetree/bindings/pwm/mediatek,mt2712-pwm.yaml
@@ -22,6 +22,7 @@ properties:
- mediatek,mt7623-pwm
- mediatek,mt7628-pwm
- mediatek,mt7629-pwm
+ - mediatek,mt7986-pwm
- mediatek,mt8183-pwm
- mediatek,mt8365-pwm
- mediatek,mt8516-pwm
diff --git a/Documentation/devicetree/bindings/pwm/pwm-amlogic.yaml b/Documentation/devicetree/bindings/pwm/pwm-amlogic.yaml
new file mode 100644
index 000000000000..527864a4d855
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/pwm-amlogic.yaml
@@ -0,0 +1,70 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pwm/pwm-amlogic.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Amlogic PWM
+
+maintainers:
+ - Heiner Kallweit <hkallweit1@gmail.com>
+
+allOf:
+ - $ref: pwm.yaml#
+
+properties:
+ compatible:
+ oneOf:
+ - enum:
+ - amlogic,meson8b-pwm
+ - amlogic,meson-gxbb-pwm
+ - amlogic,meson-gxbb-ao-pwm
+ - amlogic,meson-axg-ee-pwm
+ - amlogic,meson-axg-ao-pwm
+ - amlogic,meson-g12a-ee-pwm
+ - amlogic,meson-g12a-ao-pwm-ab
+ - amlogic,meson-g12a-ao-pwm-cd
+ - amlogic,meson-s4-pwm
+ - items:
+ - const: amlogic,meson-gx-pwm
+ - const: amlogic,meson-gxbb-pwm
+ - items:
+ - const: amlogic,meson-gx-ao-pwm
+ - const: amlogic,meson-gxbb-ao-pwm
+ - items:
+ - const: amlogic,meson8-pwm
+ - const: amlogic,meson8b-pwm
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ minItems: 1
+ maxItems: 2
+
+ clock-names:
+ oneOf:
+ - items:
+ - enum: [clkin0, clkin1]
+ - items:
+ - const: clkin0
+ - const: clkin1
+
+ "#pwm-cells":
+ const: 3
+
+required:
+ - compatible
+ - reg
+
+additionalProperties: false
+
+examples:
+ - |
+ pwm@8550 {
+ compatible = "amlogic,meson-gxbb-pwm";
+ reg = <0x08550 0x10>;
+ clocks = <&xtal>, <&xtal>;
+ clock-names = "clkin0", "clkin1";
+ #pwm-cells = <3>;
+ };
diff --git a/Documentation/devicetree/bindings/pwm/pwm-meson.txt b/Documentation/devicetree/bindings/pwm/pwm-meson.txt
deleted file mode 100644
index bd02b0a1496f..000000000000
--- a/Documentation/devicetree/bindings/pwm/pwm-meson.txt
+++ /dev/null
@@ -1,29 +0,0 @@
-Amlogic Meson PWM Controller
-============================
-
-Required properties:
-- compatible: Shall contain "amlogic,meson8b-pwm"
- or "amlogic,meson-gxbb-pwm"
- or "amlogic,meson-gxbb-ao-pwm"
- or "amlogic,meson-axg-ee-pwm"
- or "amlogic,meson-axg-ao-pwm"
- or "amlogic,meson-g12a-ee-pwm"
- or "amlogic,meson-g12a-ao-pwm-ab"
- or "amlogic,meson-g12a-ao-pwm-cd"
-- #pwm-cells: Should be 3. See pwm.yaml in this directory for a description of
- the cells format.
-
-Optional properties:
-- clocks: Could contain one or two parents clocks phandle for each of the two
- PWM channels.
-- clock-names: Could contain at least the "clkin0" and/or "clkin1" names.
-
-Example:
-
- pwm_ab: pwm@8550 {
- compatible = "amlogic,meson-gxbb-pwm";
- reg = <0x0 0x08550 0x0 0x10>;
- #pwm-cells = <3>;
- clocks = <&xtal>, <&xtal>;
- clock-names = "clkin0", "clkin1";
- }
diff --git a/Documentation/devicetree/bindings/thermal/imx-thermal.yaml b/Documentation/devicetree/bindings/thermal/imx-thermal.yaml
index fe599e443eaf..3aecea77869f 100644
--- a/Documentation/devicetree/bindings/thermal/imx-thermal.yaml
+++ b/Documentation/devicetree/bindings/thermal/imx-thermal.yaml
@@ -12,10 +12,16 @@ maintainers:
properties:
compatible:
- enum:
- - fsl,imx6q-tempmon
- - fsl,imx6sx-tempmon
- - fsl,imx7d-tempmon
+ oneOf:
+ - enum:
+ - fsl,imx6q-tempmon
+ - fsl,imx6sx-tempmon
+ - fsl,imx7d-tempmon
+ - items:
+ - enum:
+ - fsl,imx6sll-tempmon
+ - fsl,imx6ul-tempmon
+ - const: fsl,imx6sx-tempmon
interrupts:
description: |
diff --git a/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm-hc.yaml b/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm-hc.yaml
index 8273ac55b63f..01253d58bf9f 100644
--- a/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm-hc.yaml
+++ b/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm-hc.yaml
@@ -124,8 +124,8 @@ examples:
#size-cells = <0>;
#io-channel-cells = <1>;
- /* Other propreties are omitted */
- adc-chan@4c {
+ /* Other properties are omitted */
+ channel@4c {
reg = <ADC5_XO_THERM_100K_PU>;
};
};
diff --git a/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm5.yaml b/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm5.yaml
index 52ec18cf1eda..3c81def03c84 100644
--- a/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm5.yaml
+++ b/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm5.yaml
@@ -178,10 +178,11 @@ examples:
#io-channel-cells = <1>;
/* Other properties are omitted */
- conn-therm@4f {
+ channel@4f {
reg = <ADC5_AMUX_THM3_100K_PU>;
qcom,ratiometric;
qcom,hw-settle-time = <200>;
+ label = "conn_therm";
};
};
@@ -217,16 +218,18 @@ examples:
#io-channel-cells = <1>;
/* Other properties are omitted */
- xo-therm@44 {
+ channel@44 {
reg = <PMK8350_ADC7_AMUX_THM1_100K_PU>;
qcom,ratiometric;
qcom,hw-settle-time = <200>;
+ label = "xo_therm";
};
- conn-therm@147 {
+ channel@147 {
reg = <PM8350_ADC7_AMUX_THM4_100K_PU(1)>;
qcom,ratiometric;
qcom,hw-settle-time = <200>;
+ label = "conn_therm";
};
};
diff --git a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml
index 926e9c51c93c..d1ec963a6834 100644
--- a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml
+++ b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml
@@ -326,7 +326,7 @@ examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
// Example 1 (new calbiration data: for pre v1 IP):
- thermal-sensor@900000 {
+ thermal-sensor@4a9000 {
compatible = "qcom,msm8916-tsens", "qcom,tsens-v0_1";
reg = <0x4a9000 0x1000>, /* TM */
<0x4a8000 0x1000>; /* SROT */
@@ -356,7 +356,7 @@ examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
// Example 1 (legacy: for pre v1 IP):
- tsens1: thermal-sensor@900000 {
+ tsens1: thermal-sensor@4a9000 {
compatible = "qcom,msm8916-tsens", "qcom,tsens-v0_1";
reg = <0x4a9000 0x1000>, /* TM */
<0x4a8000 0x1000>; /* SROT */
diff --git a/Documentation/devicetree/bindings/timestamp/nvidia,tegra194-hte.yaml b/Documentation/devicetree/bindings/timestamp/nvidia,tegra194-hte.yaml
index c31e207d1652..456797967adc 100644
--- a/Documentation/devicetree/bindings/timestamp/nvidia,tegra194-hte.yaml
+++ b/Documentation/devicetree/bindings/timestamp/nvidia,tegra194-hte.yaml
@@ -4,7 +4,7 @@
$id: http://devicetree.org/schemas/timestamp/nvidia,tegra194-hte.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
-title: Tegra194 on chip generic hardware timestamping engine (HTE)
+title: Tegra on chip generic hardware timestamping engine (HTE) provider
maintainers:
- Dipen Patel <dipenp@nvidia.com>
@@ -23,6 +23,8 @@ properties:
enum:
- nvidia,tegra194-gte-aon
- nvidia,tegra194-gte-lic
+ - nvidia,tegra234-gte-aon
+ - nvidia,tegra234-gte-lic
reg:
maxItems: 1
@@ -40,12 +42,20 @@ properties:
nvidia,slices:
$ref: /schemas/types.yaml#/definitions/uint32
+ deprecated: true
description:
HTE lines are arranged in 32 bit slice where each bit represents different
line/signal that it can enable/configure for the timestamp. It is u32
- property and depends on the HTE instance in the chip. The value 3 is for
- GPIO GTE and 11 for IRQ GTE.
- enum: [3, 11]
+ property and the value depends on the HTE instance in the chip. The AON
+ GTE instances for both Tegra194 and Tegra234 has 3 slices. The Tegra194
+ LIC instance has 11 slices and Tegra234 LIC has 17 slices.
+ enum: [3, 11, 17]
+
+ nvidia,gpio-controller:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description:
+ The phandle to AON gpio controller instance. This is required to handle
+ namespace conversion between GPIO and GTE.
'#timestamp-cells':
description:
@@ -59,9 +69,53 @@ required:
- compatible
- reg
- interrupts
- - nvidia,slices
- "#timestamp-cells"
+allOf:
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - nvidia,tegra194-gte-aon
+ - nvidia,tegra234-gte-aon
+ then:
+ properties:
+ nvidia,slices:
+ const: 3
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - nvidia,tegra194-gte-lic
+ then:
+ properties:
+ nvidia,slices:
+ const: 11
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - nvidia,tegra234-gte-lic
+ then:
+ properties:
+ nvidia,slices:
+ const: 17
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - nvidia,tegra234-gte-aon
+ then:
+ required:
+ - nvidia,gpio-controller
+
additionalProperties: false
examples:
@@ -71,7 +125,6 @@ examples:
reg = <0xc1e0000 0x10000>;
interrupts = <0 13 0x4>;
nvidia,int-threshold = <1>;
- nvidia,slices = <3>;
#timestamp-cells = <1>;
};
@@ -81,7 +134,6 @@ examples:
reg = <0x3aa0000 0x10000>;
interrupts = <0 11 0x4>;
nvidia,int-threshold = <1>;
- nvidia,slices = <11>;
#timestamp-cells = <1>;
};
diff --git a/Documentation/driver-api/hte/index.rst b/Documentation/driver-api/hte/index.rst
index 9f43301c05dc..29011de9a4b8 100644
--- a/Documentation/driver-api/hte/index.rst
+++ b/Documentation/driver-api/hte/index.rst
@@ -18,5 +18,5 @@ HTE Tegra Provider
.. toctree::
:maxdepth: 1
- tegra194-hte
+ tegra-hte
diff --git a/Documentation/driver-api/hte/tegra194-hte.rst b/Documentation/driver-api/hte/tegra-hte.rst
index f2d617265546..85e654772782 100644
--- a/Documentation/driver-api/hte/tegra194-hte.rst
+++ b/Documentation/driver-api/hte/tegra-hte.rst
@@ -5,25 +5,25 @@ HTE Kernel provider driver
Description
-----------
-The Nvidia tegra194 HTE provider driver implements two GTE
-(Generic Timestamping Engine) instances: 1) GPIO GTE and 2) LIC
-(Legacy Interrupt Controller) IRQ GTE. Both GTE instances get the
-timestamp from the system counter TSC which has 31.25MHz clock rate, and the
-driver converts clock tick rate to nanoseconds before storing it as timestamp
-value.
+The Nvidia tegra HTE provider also known as GTE (Generic Timestamping Engine)
+driver implements two GTE instances: 1) GPIO GTE and 2) LIC
+(Legacy Interrupt Controller) IRQ GTE. Both GTE instances get the timestamp
+from the system counter TSC which has 31.25MHz clock rate, and the driver
+converts clock tick rate to nanoseconds before storing it as timestamp value.
GPIO GTE
--------
This GTE instance timestamps GPIO in real time. For that to happen GPIO
-needs to be configured as input. The always on (AON) GPIO controller instance
-supports timestamping GPIOs in real time and it has 39 GPIO lines. The GPIO GTE
-and AON GPIO controller are tightly coupled as it requires very specific bits
-to be set in GPIO config register before GPIO GTE can be used, for that GPIOLIB
-adds two optional APIs as below. The GPIO GTE code supports both kernel
-and userspace consumers. The kernel space consumers can directly talk to HTE
-subsystem while userspace consumers timestamp requests go through GPIOLIB CDEV
-framework to HTE subsystem.
+needs to be configured as input. Only the always on (AON) GPIO controller
+instance supports timestamping GPIOs in real time as it is tightly coupled with
+the GPIO GTE. To support this, GPIOLIB adds two optional APIs as mentioned
+below. The GPIO GTE code supports both kernel and userspace consumers. The
+kernel space consumers can directly talk to HTE subsystem while userspace
+consumers timestamp requests go through GPIOLIB CDEV framework to HTE
+subsystem. The hte devicetree binding described at
+``Documentation/devicetree/bindings/timestamp`` provides an example of how a
+consumer can request an GPIO line.
See gpiod_enable_hw_timestamp_ns() and gpiod_disable_hw_timestamp_ns().
@@ -34,9 +34,8 @@ returns the timestamp in nanoseconds.
LIC (Legacy Interrupt Controller) IRQ GTE
-----------------------------------------
-This GTE instance timestamps LIC IRQ lines in real time. There are 352 IRQ
-lines which this instance can add timestamps to in real time. The hte
-devicetree binding described at ``Documentation/devicetree/bindings/timestamp``
+This GTE instance timestamps LIC IRQ lines in real time. The hte devicetree
+binding described at ``Documentation/devicetree/bindings/timestamp``
provides an example of how a consumer can request an IRQ line. Since it is a
one-to-one mapping with IRQ GTE provider, consumers can simply specify the IRQ
number that they are interested in. There is no userspace consumer support for
diff --git a/Documentation/driver-api/pwm.rst b/Documentation/driver-api/pwm.rst
index 8c71a2055d27..3fdc95f7a1d1 100644
--- a/Documentation/driver-api/pwm.rst
+++ b/Documentation/driver-api/pwm.rst
@@ -35,12 +35,9 @@ consumers to providers, as given in the following example::
Using PWMs
----------
-Legacy users can request a PWM device using pwm_request() and free it
-after usage with pwm_free().
-
-New users should use the pwm_get() function and pass to it the consumer
-device or a consumer name. pwm_put() is used to free the PWM device. Managed
-variants of the getter, devm_pwm_get() and devm_fwnode_pwm_get(), also exist.
+Consumers use the pwm_get() function and pass to it the consumer device or a
+consumer name. pwm_put() is used to free the PWM device. Managed variants of
+the getter, devm_pwm_get() and devm_fwnode_pwm_get(), also exist.
After being requested, a PWM has to be configured using::
@@ -165,8 +162,8 @@ consumers should implement it as described in the "Using PWMs" section.
Locking
-------
-The PWM core list manipulations are protected by a mutex, so pwm_request()
-and pwm_free() may not be called from an atomic context. Currently the
+The PWM core list manipulations are protected by a mutex, so pwm_get()
+and pwm_put() may not be called from an atomic context. Currently the
PWM core does not enforce any locking to pwm_enable(), pwm_disable() and
pwm_config(), so the calling context is currently driver specific. This
is an issue derived from the former barebone API and should be fixed soon.
diff --git a/MAINTAINERS b/MAINTAINERS
index cb932c6f8959..c0cde28c62c6 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1961,6 +1961,7 @@ F: Documentation/devicetree/bindings/nvmem/apple,efuses.yaml
F: Documentation/devicetree/bindings/pci/apple,pcie.yaml
F: Documentation/devicetree/bindings/pinctrl/apple,pinctrl.yaml
F: Documentation/devicetree/bindings/power/apple*
+F: Documentation/devicetree/bindings/pwm/pwm-apple.yaml
F: Documentation/devicetree/bindings/watchdog/apple,wdt.yaml
F: arch/arm64/boot/dts/apple/
F: drivers/bluetooth/hci_bcm4377.c
@@ -1976,6 +1977,7 @@ F: drivers/mailbox/apple-mailbox.c
F: drivers/nvme/host/apple.c
F: drivers/nvmem/apple-efuses.c
F: drivers/pinctrl/pinctrl-apple-gpio.c
+F: drivers/pwm/pwm-apple.c
F: drivers/soc/apple/*
F: drivers/watchdog/apple_wdt.c
F: include/dt-bindings/interrupt-controller/apple-aic.h
@@ -9489,6 +9491,9 @@ F: drivers/input/touchscreen/htcpen.c
HTE SUBSYSTEM
M: Dipen Patel <dipenp@nvidia.com>
+L: timestamp@lists.linux.dev
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/pateldipen1984/linux.git
+Q: https://patchwork.kernel.org/project/timestamp/list/
S: Maintained
F: Documentation/devicetree/bindings/timestamp/
F: Documentation/driver-api/hte/
@@ -10527,13 +10532,6 @@ F: drivers/crypto/intel/keembay/keembay-ocs-hcu-core.c
F: drivers/crypto/intel/keembay/ocs-hcu.c
F: drivers/crypto/intel/keembay/ocs-hcu.h
-INTEL THUNDER BAY EMMC PHY DRIVER
-M: Nandhini Srikandan <nandhini.srikandan@intel.com>
-M: Rashmi A <rashmi.a@intel.com>
-S: Maintained
-F: Documentation/devicetree/bindings/phy/intel,phy-thunderbay-emmc.yaml
-F: drivers/phy/intel/phy-intel-thunderbay-emmc.c
-
INTEL MANAGEMENT ENGINE (mei)
M: Tomas Winkler <tomas.winkler@intel.com>
L: linux-kernel@vger.kernel.org
diff --git a/arch/arm64/boot/dts/nvidia/tegra234.dtsi b/arch/arm64/boot/dts/nvidia/tegra234.dtsi
index 5d354f8923b4..18b4c2b2c42c 100644
--- a/arch/arm64/boot/dts/nvidia/tegra234.dtsi
+++ b/arch/arm64/boot/dts/nvidia/tegra234.dtsi
@@ -1154,6 +1154,14 @@
clock-names = "fuse";
};
+ hte_lic: hardware-timestamp@3aa0000 {
+ compatible = "nvidia,tegra234-gte-lic";
+ reg = <0x0 0x3aa0000 0x0 0x10000>;
+ interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
+ nvidia,int-threshold = <1>;
+ #timestamp-cells = <1>;
+ };
+
hsp_top0: hsp@3c00000 {
compatible = "nvidia,tegra234-hsp", "nvidia,tegra194-hsp";
reg = <0x0 0x03c00000 0x0 0xa0000>;
@@ -1671,6 +1679,15 @@
#mbox-cells = <2>;
};
+ hte_aon: hardware-timestamp@c1e0000 {
+ compatible = "nvidia,tegra234-gte-aon";
+ reg = <0x0 0xc1e0000 0x0 0x10000>;
+ interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
+ nvidia,int-threshold = <1>;
+ nvidia,gpio-controller = <&gpio_aon>;
+ #timestamp-cells = <1>;
+ };
+
gen2_i2c: i2c@c240000 {
compatible = "nvidia,tegra194-i2c";
reg = <0x0 0xc240000 0x0 0x100>;
diff --git a/arch/um/include/shared/as-layout.h b/arch/um/include/shared/as-layout.h
index 9a0bd648d872..9ec3015bc5e2 100644
--- a/arch/um/include/shared/as-layout.h
+++ b/arch/um/include/shared/as-layout.h
@@ -23,7 +23,8 @@
#define STUB_START stub_start
#define STUB_CODE STUB_START
#define STUB_DATA (STUB_CODE + UM_KERN_PAGE_SIZE)
-#define STUB_END (STUB_DATA + UM_KERN_PAGE_SIZE)
+#define STUB_DATA_PAGES 1 /* must be a power of two */
+#define STUB_END (STUB_DATA + STUB_DATA_PAGES * UM_KERN_PAGE_SIZE)
#ifndef __ASSEMBLY__
diff --git a/arch/um/kernel/skas/clone.c b/arch/um/kernel/skas/clone.c
index ff5061f29167..62435187dda4 100644
--- a/arch/um/kernel/skas/clone.c
+++ b/arch/um/kernel/skas/clone.c
@@ -24,11 +24,12 @@
void __attribute__ ((__section__ (".__syscall_stub")))
stub_clone_handler(void)
{
- struct stub_data *data = get_stub_page();
+ struct stub_data *data = get_stub_data();
long err;
err = stub_syscall2(__NR_clone, CLONE_PARENT | CLONE_FILES | SIGCHLD,
- (unsigned long)data + UM_KERN_PAGE_SIZE / 2);
+ (unsigned long)data +
+ STUB_DATA_PAGES * UM_KERN_PAGE_SIZE / 2);
if (err) {
data->parent_err = err;
goto done;
diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c
index 125df465e8ea..656fe16c9b63 100644
--- a/arch/um/kernel/skas/mmu.c
+++ b/arch/um/kernel/skas/mmu.c
@@ -21,7 +21,7 @@ int init_new_context(struct task_struct *task, struct mm_struct *mm)
unsigned long stack = 0;
int ret = -ENOMEM;
- stack = get_zeroed_page(GFP_KERNEL);
+ stack = __get_free_pages(GFP_KERNEL | __GFP_ZERO, ilog2(STUB_DATA_PAGES));
if (stack == 0)
goto out;
@@ -52,7 +52,7 @@ int init_new_context(struct task_struct *task, struct mm_struct *mm)
out_free:
if (to_mm->id.stack != 0)
- free_page(to_mm->id.stack);
+ free_pages(to_mm->id.stack, ilog2(STUB_DATA_PAGES));
out:
return ret;
}
@@ -74,6 +74,6 @@ void destroy_context(struct mm_struct *mm)
}
os_kill_ptraced_process(mmu->id.u.pid, 1);
- free_page(mmu->id.stack);
+ free_pages(mmu->id.stack, ilog2(STUB_DATA_PAGES));
free_ldt(mmu);
}
diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c
index 8dcda617b8bf..0a23a98d4ca0 100644
--- a/arch/um/kernel/um_arch.c
+++ b/arch/um/kernel/um_arch.c
@@ -326,9 +326,13 @@ int __init linux_main(int argc, char **argv)
add_arg(DEFAULT_COMMAND_LINE_CONSOLE);
host_task_size = os_get_top_address();
- /* reserve two pages for the stubs */
- host_task_size -= 2 * PAGE_SIZE;
- stub_start = host_task_size;
+ /* reserve a few pages for the stubs (taking care of data alignment) */
+ /* align the data portion */
+ BUILD_BUG_ON(!is_power_of_2(STUB_DATA_PAGES));
+ stub_start = (host_task_size - 1) & ~(STUB_DATA_PAGES * PAGE_SIZE - 1);
+ /* another page for the code portion */
+ stub_start -= PAGE_SIZE;
+ host_task_size = stub_start;
/*
* TASK_SIZE needs to be PGDIR_SIZE aligned or else exit_mmap craps
diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c
index b1ea53285af1..9464833e741a 100644
--- a/arch/um/os-Linux/skas/process.c
+++ b/arch/um/os-Linux/skas/process.c
@@ -262,7 +262,7 @@ static int userspace_tramp(void *stack)
if (stack != NULL) {
fd = phys_mapping(uml_to_phys(stack), &offset);
addr = mmap((void *) STUB_DATA,
- UM_KERN_PAGE_SIZE, PROT_READ | PROT_WRITE,
+ STUB_DATA_PAGES * UM_KERN_PAGE_SIZE, PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_SHARED, fd, offset);
if (addr == MAP_FAILED) {
printk(UM_KERN_ERR "mapping segfault stack at 0x%lx failed, errno = %d\n",
@@ -277,7 +277,7 @@ static int userspace_tramp(void *stack)
(unsigned long) stub_segv_handler -
(unsigned long) __syscall_stub_start;
- set_sigstack((void *) STUB_DATA, UM_KERN_PAGE_SIZE);
+ set_sigstack((void *) STUB_DATA, STUB_DATA_PAGES * UM_KERN_PAGE_SIZE);
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_ONSTACK | SA_NODEFER | SA_SIGINFO;
sa.sa_sigaction = (void *) v;
@@ -515,7 +515,7 @@ static int __init init_thread_regs(void)
thread_regs[REGS_IP_INDEX] = STUB_CODE +
(unsigned long) stub_clone_handler -
(unsigned long) __syscall_stub_start;
- thread_regs[REGS_SP_INDEX] = STUB_DATA + UM_KERN_PAGE_SIZE -
+ thread_regs[REGS_SP_INDEX] = STUB_DATA + STUB_DATA_PAGES * UM_KERN_PAGE_SIZE -
sizeof(void *);
#ifdef __SIGNAL_FRAMESIZE
thread_regs[REGS_SP_INDEX] -= __SIGNAL_FRAMESIZE;
diff --git a/arch/um/os-Linux/user_syms.c b/arch/um/os-Linux/user_syms.c
index fd575ecbcaec..9b62a9d352b3 100644
--- a/arch/um/os-Linux/user_syms.c
+++ b/arch/um/os-Linux/user_syms.c
@@ -3,112 +3,40 @@
#include <linux/types.h>
#include <linux/module.h>
-/* Some of this are builtin function (some are not but could in the future),
- * so I *must* declare good prototypes for them and then EXPORT them.
- * The kernel code uses the macro defined by include/linux/string.h,
- * so I undef macros; the userspace code does not include that and I
- * add an EXPORT for the glibc one.
+/*
+ * This file exports some critical string functions and compiler
+ * built-in functions (where calls are emitted by the compiler
+ * itself that we cannot avoid even in kernel code) to modules.
+ *
+ * "_user.c" code that previously used exports here such as hostfs
+ * really should be considered part of the 'hypervisor' and define
+ * its own API boundary like hostfs does now; don't add exports to
+ * this file for such cases.
*/
-#undef strlen
-#undef strstr
-#undef memcpy
-#undef memset
-
-extern size_t strlen(const char *);
-extern void *memmove(void *, const void *, size_t);
-extern void *memset(void *, int, size_t);
-extern int printf(const char *, ...);
-
/* If it's not defined, the export is included in lib/string.c.*/
#ifdef __HAVE_ARCH_STRSTR
+#undef strstr
EXPORT_SYMBOL(strstr);
#endif
#ifndef __x86_64__
+#undef memcpy
extern void *memcpy(void *, const void *, size_t);
EXPORT_SYMBOL(memcpy);
+extern void *memmove(void *, const void *, size_t);
EXPORT_SYMBOL(memmove);
+#undef memset
+extern void *memset(void *, int, size_t);
EXPORT_SYMBOL(memset);
#endif
-EXPORT_SYMBOL(printf);
-
-/* Here, instead, I can provide a fake prototype. Yes, someone cares: genksyms.
- * However, the modules will use the CRC defined *here*, no matter if it is
- * good; so the versions of these symbols will always match
- */
-#define EXPORT_SYMBOL_PROTO(sym) \
- int sym(void); \
- EXPORT_SYMBOL(sym);
-
-extern void readdir64(void) __attribute__((weak));
-EXPORT_SYMBOL(readdir64);
-extern void truncate64(void) __attribute__((weak));
-EXPORT_SYMBOL(truncate64);
-
#ifdef CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA
+/* needed for __access_ok() */
EXPORT_SYMBOL(vsyscall_ehdr);
EXPORT_SYMBOL(vsyscall_end);
#endif
-EXPORT_SYMBOL_PROTO(__errno_location);
-
-EXPORT_SYMBOL_PROTO(access);
-EXPORT_SYMBOL_PROTO(open);
-EXPORT_SYMBOL_PROTO(open64);
-EXPORT_SYMBOL_PROTO(close);
-EXPORT_SYMBOL_PROTO(read);
-EXPORT_SYMBOL_PROTO(write);
-EXPORT_SYMBOL_PROTO(dup2);
-EXPORT_SYMBOL_PROTO(__xstat);
-EXPORT_SYMBOL_PROTO(__lxstat);
-EXPORT_SYMBOL_PROTO(__lxstat64);
-EXPORT_SYMBOL_PROTO(__fxstat64);
-EXPORT_SYMBOL_PROTO(lseek);
-EXPORT_SYMBOL_PROTO(lseek64);
-EXPORT_SYMBOL_PROTO(chown);
-EXPORT_SYMBOL_PROTO(fchown);
-EXPORT_SYMBOL_PROTO(truncate);
-EXPORT_SYMBOL_PROTO(ftruncate64);
-EXPORT_SYMBOL_PROTO(utime);
-EXPORT_SYMBOL_PROTO(utimes);
-EXPORT_SYMBOL_PROTO(futimes);
-EXPORT_SYMBOL_PROTO(chmod);
-EXPORT_SYMBOL_PROTO(fchmod);
-EXPORT_SYMBOL_PROTO(rename);
-EXPORT_SYMBOL_PROTO(__xmknod);
-
-EXPORT_SYMBOL_PROTO(symlink);
-EXPORT_SYMBOL_PROTO(link);
-EXPORT_SYMBOL_PROTO(unlink);
-EXPORT_SYMBOL_PROTO(readlink);
-
-EXPORT_SYMBOL_PROTO(mkdir);
-EXPORT_SYMBOL_PROTO(rmdir);
-EXPORT_SYMBOL_PROTO(opendir);
-EXPORT_SYMBOL_PROTO(readdir);
-EXPORT_SYMBOL_PROTO(closedir);
-EXPORT_SYMBOL_PROTO(seekdir);
-EXPORT_SYMBOL_PROTO(telldir);
-
-EXPORT_SYMBOL_PROTO(ioctl);
-
-EXPORT_SYMBOL_PROTO(pread64);
-EXPORT_SYMBOL_PROTO(pwrite64);
-
-EXPORT_SYMBOL_PROTO(statfs);
-EXPORT_SYMBOL_PROTO(statfs64);
-
-EXPORT_SYMBOL_PROTO(getuid);
-
-EXPORT_SYMBOL_PROTO(fsync);
-EXPORT_SYMBOL_PROTO(fdatasync);
-
-EXPORT_SYMBOL_PROTO(lstat64);
-EXPORT_SYMBOL_PROTO(fstat64);
-EXPORT_SYMBOL_PROTO(mknod);
-
/* Export symbols used by GCC for the stack protector. */
extern void __stack_smash_handler(void *) __attribute__((weak));
EXPORT_SYMBOL(__stack_smash_handler);
@@ -117,6 +45,6 @@ extern long __guard __attribute__((weak));
EXPORT_SYMBOL(__guard);
#ifdef _FORTIFY_SOURCE
-extern int __sprintf_chk(char *str, int flag, size_t strlen, const char *format);
+extern int __sprintf_chk(char *str, int flag, size_t len, const char *format);
EXPORT_SYMBOL(__sprintf_chk);
#endif
diff --git a/arch/um/scripts/Makefile.rules b/arch/um/scripts/Makefile.rules
index a4dfa7d7636e..a8b7d9dab0a6 100644
--- a/arch/um/scripts/Makefile.rules
+++ b/arch/um/scripts/Makefile.rules
@@ -4,8 +4,8 @@
# ===========================================================================
USER_SINGLE_OBJS := \
- $(foreach f,$(patsubst %.o,%,$(obj-y) $(obj-m)),$($(f)-objs))
-USER_OBJS += $(filter %_user.o,$(obj-y) $(obj-m) $(USER_SINGLE_OBJS))
+ $(foreach f,$(patsubst %.o,%,$(obj-y)),$($(f)-objs))
+USER_OBJS += $(filter %_user.o,$(obj-y) $(USER_SINGLE_OBJS))
USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
$(USER_OBJS:.o=.%): \
diff --git a/arch/x86/um/shared/sysdep/stub_32.h b/arch/x86/um/shared/sysdep/stub_32.h
index 4c6c2be0c899..38fa894b65d0 100644
--- a/arch/x86/um/shared/sysdep/stub_32.h
+++ b/arch/x86/um/shared/sysdep/stub_32.h
@@ -89,19 +89,19 @@ static inline void remap_stack_and_trap(void)
"addl %4,%%ebx ; movl %%eax, (%%ebx) ;"
"int $3"
: :
- "g" (~(UM_KERN_PAGE_SIZE - 1)),
+ "g" (~(STUB_DATA_PAGES * UM_KERN_PAGE_SIZE - 1)),
"g" (STUB_MMAP_NR),
"g" (UML_STUB_FIELD_FD),
"g" (UML_STUB_FIELD_OFFSET),
"g" (UML_STUB_FIELD_CHILD_ERR),
- "c" (UM_KERN_PAGE_SIZE),
+ "c" (STUB_DATA_PAGES * UM_KERN_PAGE_SIZE),
"d" (PROT_READ | PROT_WRITE),
"S" (MAP_FIXED | MAP_SHARED)
:
"memory");
}
-static __always_inline void *get_stub_page(void)
+static __always_inline void *get_stub_data(void)
{
unsigned long ret;
@@ -109,7 +109,7 @@ static __always_inline void *get_stub_page(void)
"movl %%esp,%0 ;"
"andl %1,%0"
: "=a" (ret)
- : "g" (~(UM_KERN_PAGE_SIZE - 1)));
+ : "g" (~(STUB_DATA_PAGES * UM_KERN_PAGE_SIZE - 1)));
return (void *)ret;
}
diff --git a/arch/x86/um/shared/sysdep/stub_64.h b/arch/x86/um/shared/sysdep/stub_64.h
index 92ea1670cf1c..2de1c8f88173 100644
--- a/arch/x86/um/shared/sysdep/stub_64.h
+++ b/arch/x86/um/shared/sysdep/stub_64.h
@@ -98,18 +98,18 @@ static inline void remap_stack_and_trap(void)
"int3"
: :
"g" (STUB_MMAP_NR),
- "g" (~(UM_KERN_PAGE_SIZE - 1)),
+ "g" (~(STUB_DATA_PAGES * UM_KERN_PAGE_SIZE - 1)),
"g" (MAP_FIXED | MAP_SHARED),
"g" (UML_STUB_FIELD_FD),
"g" (UML_STUB_FIELD_OFFSET),
"g" (UML_STUB_FIELD_CHILD_ERR),
- "S" (UM_KERN_PAGE_SIZE),
+ "S" (STUB_DATA_PAGES * UM_KERN_PAGE_SIZE),
"d" (PROT_READ | PROT_WRITE)
:
__syscall_clobber, "r10", "r8", "r9");
}
-static __always_inline void *get_stub_page(void)
+static __always_inline void *get_stub_data(void)
{
unsigned long ret;
@@ -117,7 +117,7 @@ static __always_inline void *get_stub_page(void)
"movq %%rsp,%0 ;"
"andq %1,%0"
: "=a" (ret)
- : "g" (~(UM_KERN_PAGE_SIZE - 1)));
+ : "g" (~(STUB_DATA_PAGES * UM_KERN_PAGE_SIZE - 1)));
return (void *)ret;
}
diff --git a/arch/x86/um/stub_segv.c b/arch/x86/um/stub_segv.c
index f7eefba034f9..040668b989b5 100644
--- a/arch/x86/um/stub_segv.c
+++ b/arch/x86/um/stub_segv.c
@@ -11,7 +11,7 @@
void __attribute__ ((__section__ (".__syscall_stub")))
stub_segv_handler(int sig, siginfo_t *info, void *p)
{
- struct faultinfo *f = get_stub_page();
+ struct faultinfo *f = get_stub_data();
ucontext_t *uc = p;
GET_FAULTINFO_FROM_MC(*f, &uc->uc_mcontext);
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index 23507d29f000..c2c70139c4f1 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -23,6 +23,7 @@
#define pr_fmt(fmt) "ACPI: PM: " fmt
+#include <linux/dmi.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -1022,6 +1023,21 @@ void acpi_resume_power_resources(void)
}
#endif
+static const struct dmi_system_id dmi_leave_unused_power_resources_on[] = {
+ {
+ /*
+ * The Toshiba Click Mini has a CPR3 power-resource which must
+ * be on for the touchscreen to work, but which is not in any
+ * _PR? lists. The other 2 affected power-resources are no-ops.
+ */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "SATELLITE Click Mini L9W-B"),
+ },
+ },
+ {}
+};
+
/**
* acpi_turn_off_unused_power_resources - Turn off power resources not in use.
*/
@@ -1029,6 +1045,9 @@ void acpi_turn_off_unused_power_resources(void)
{
struct acpi_power_resource *resource;
+ if (dmi_check_system(dmi_leave_unused_power_resources_on))
+ return;
+
mutex_lock(&power_resource_list_lock);
list_for_each_entry_reverse(resource, &acpi_power_resource_list, list_node) {
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index ec002ecfe4cf..4720a3649a61 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -786,6 +786,32 @@ static struct thermal_zone_device_ops acpi_thermal_zone_ops = {
.critical = acpi_thermal_zone_device_critical,
};
+static int acpi_thermal_zone_sysfs_add(struct acpi_thermal *tz)
+{
+ struct device *tzdev = thermal_zone_device(tz->thermal_zone);
+ int ret;
+
+ ret = sysfs_create_link(&tz->device->dev.kobj,
+ &tzdev->kobj, "thermal_zone");
+ if (ret)
+ return ret;
+
+ ret = sysfs_create_link(&tzdev->kobj,
+ &tz->device->dev.kobj, "device");
+ if (ret)
+ sysfs_remove_link(&tz->device->dev.kobj, "thermal_zone");
+
+ return ret;
+}
+
+static void acpi_thermal_zone_sysfs_remove(struct acpi_thermal *tz)
+{
+ struct device *tzdev = thermal_zone_device(tz->thermal_zone);
+
+ sysfs_remove_link(&tz->device->dev.kobj, "thermal_zone");
+ sysfs_remove_link(&tzdev->kobj, "device");
+}
+
static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
{
int trips = 0;
@@ -819,21 +845,15 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
if (IS_ERR(tz->thermal_zone))
return -ENODEV;
- result = sysfs_create_link(&tz->device->dev.kobj,
- &tz->thermal_zone->device.kobj, "thermal_zone");
+ result = acpi_thermal_zone_sysfs_add(tz);
if (result)
goto unregister_tzd;
- result = sysfs_create_link(&tz->thermal_zone->device.kobj,
- &tz->device->dev.kobj, "device");
- if (result)
- goto remove_tz_link;
-
status = acpi_bus_attach_private_data(tz->device->handle,
tz->thermal_zone);
if (ACPI_FAILURE(status)) {
result = -ENODEV;
- goto remove_dev_link;
+ goto remove_links;
}
result = thermal_zone_device_enable(tz->thermal_zone);
@@ -847,10 +867,8 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
acpi_bus_detach:
acpi_bus_detach_private_data(tz->device->handle);
-remove_dev_link:
- sysfs_remove_link(&tz->thermal_zone->device.kobj, "device");
-remove_tz_link:
- sysfs_remove_link(&tz->device->dev.kobj, "thermal_zone");
+remove_links:
+ acpi_thermal_zone_sysfs_remove(tz);
unregister_tzd:
thermal_zone_device_unregister(tz->thermal_zone);
@@ -859,8 +877,7 @@ unregister_tzd:
static void acpi_thermal_unregister_thermal_zone(struct acpi_thermal *tz)
{
- sysfs_remove_link(&tz->device->dev.kobj, "thermal_zone");
- sysfs_remove_link(&tz->thermal_zone->device.kobj, "device");
+ acpi_thermal_zone_sysfs_remove(tz);
thermal_zone_device_unregister(tz->thermal_zone);
tz->thermal_zone = NULL;
acpi_bus_detach_private_data(tz->device->handle);
diff --git a/drivers/acpi/x86/apple.c b/drivers/acpi/x86/apple.c
index 8812ecd03d55..45d0f16f374f 100644
--- a/drivers/acpi/x86/apple.c
+++ b/drivers/acpi/x86/apple.c
@@ -71,13 +71,16 @@ void acpi_extract_apple_properties(struct acpi_device *adev)
if ( key->type != ACPI_TYPE_STRING ||
(val->type != ACPI_TYPE_INTEGER &&
- val->type != ACPI_TYPE_BUFFER))
+ val->type != ACPI_TYPE_BUFFER &&
+ val->type != ACPI_TYPE_STRING))
continue; /* skip invalid properties */
__set_bit(i, valid);
newsize += key->string.length + 1;
if ( val->type == ACPI_TYPE_BUFFER)
newsize += val->buffer.length;
+ else if (val->type == ACPI_TYPE_STRING)
+ newsize += val->string.length + 1;
}
numvalid = bitmap_weight(valid, numprops);
@@ -119,6 +122,12 @@ void acpi_extract_apple_properties(struct acpi_device *adev)
newprops[v].type = val->type;
if (val->type == ACPI_TYPE_INTEGER) {
newprops[v].integer.value = val->integer.value;
+ } else if (val->type == ACPI_TYPE_STRING) {
+ newprops[v].string.length = val->string.length;
+ newprops[v].string.pointer = free_space;
+ memcpy(free_space, val->string.pointer,
+ val->string.length);
+ free_space += val->string.length + 1;
} else {
newprops[v].buffer.length = val->buffer.length;
newprops[v].buffer.pointer = free_space;
diff --git a/drivers/acpi/x86/utils.c b/drivers/acpi/x86/utils.c
index ba420a28a4aa..9c2d6f35f88a 100644
--- a/drivers/acpi/x86/utils.c
+++ b/drivers/acpi/x86/utils.c
@@ -143,6 +143,16 @@ static const struct override_status_id override_status_ids[] = {
DMI_EXACT_MATCH(DMI_BOARD_SERIAL, "Default string"),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Default string"),
}),
+
+ /*
+ * The LSM303D on the Lenovo Yoga Tablet 2 series is present
+ * as both ACCL0001 and MAGN0001. As we can only ever register an
+ * i2c client for one of them, ignore MAGN0001.
+ */
+ NOT_PRESENT_ENTRY_HID("MAGN0001", "1", ATOM_SILVERMONT, {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_FAMILY, "YOGATablet2"),
+ }),
};
bool acpi_device_override_status(struct acpi_device *adev, unsigned long long *status)
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index fb7073fc034f..f5f422f9b850 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -623,6 +623,7 @@ config TEGRA186_GPC_DMA
depends on (ARCH_TEGRA || COMPILE_TEST) && ARCH_DMA_ADDR_T_64BIT
depends on IOMMU_API
select DMA_ENGINE
+ select DMA_VIRTUAL_CHANNELS
help
Support for the NVIDIA Tegra General Purpose Central DMA controller.
The DMA controller has multiple DMA channels which can be configured
diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c
index 1f0fab180f8f..7da6d9b6098e 100644
--- a/drivers/dma/at_xdmac.c
+++ b/drivers/dma/at_xdmac.c
@@ -187,6 +187,7 @@
enum atc_status {
AT_XDMAC_CHAN_IS_CYCLIC = 0,
AT_XDMAC_CHAN_IS_PAUSED,
+ AT_XDMAC_CHAN_IS_PAUSED_INTERNAL,
};
struct at_xdmac_layout {
@@ -245,6 +246,7 @@ struct at_xdmac {
int irq;
struct clk *clk;
u32 save_gim;
+ u32 save_gs;
struct dma_pool *at_xdmac_desc_pool;
const struct at_xdmac_layout *layout;
struct at_xdmac_chan chan[];
@@ -347,6 +349,11 @@ static inline int at_xdmac_chan_is_paused(struct at_xdmac_chan *atchan)
return test_bit(AT_XDMAC_CHAN_IS_PAUSED, &atchan->status);
}
+static inline int at_xdmac_chan_is_paused_internal(struct at_xdmac_chan *atchan)
+{
+ return test_bit(AT_XDMAC_CHAN_IS_PAUSED_INTERNAL, &atchan->status);
+}
+
static inline bool at_xdmac_chan_is_peripheral_xfer(u32 cfg)
{
return cfg & AT_XDMAC_CC_TYPE_PER_TRAN;
@@ -412,7 +419,7 @@ static bool at_xdmac_chan_is_enabled(struct at_xdmac_chan *atchan)
return ret;
}
-static void at_xdmac_off(struct at_xdmac *atxdmac)
+static void at_xdmac_off(struct at_xdmac *atxdmac, bool suspend_descriptors)
{
struct dma_chan *chan, *_chan;
struct at_xdmac_chan *atchan;
@@ -431,7 +438,7 @@ static void at_xdmac_off(struct at_xdmac *atxdmac)
at_xdmac_write(atxdmac, AT_XDMAC_GID, -1L);
/* Decrement runtime PM ref counter for each active descriptor. */
- if (!list_empty(&atxdmac->dma.channels)) {
+ if (!list_empty(&atxdmac->dma.channels) && suspend_descriptors) {
list_for_each_entry_safe(chan, _chan, &atxdmac->dma.channels,
device_node) {
atchan = to_at_xdmac_chan(chan);
@@ -1898,6 +1905,26 @@ static int at_xdmac_device_config(struct dma_chan *chan,
return ret;
}
+static void at_xdmac_device_pause_set(struct at_xdmac *atxdmac,
+ struct at_xdmac_chan *atchan)
+{
+ at_xdmac_write(atxdmac, atxdmac->layout->grws, atchan->mask);
+ while (at_xdmac_chan_read(atchan, AT_XDMAC_CC) &
+ (AT_XDMAC_CC_WRIP | AT_XDMAC_CC_RDIP))
+ cpu_relax();
+}
+
+static void at_xdmac_device_pause_internal(struct at_xdmac_chan *atchan)
+{
+ struct at_xdmac *atxdmac = to_at_xdmac(atchan->chan.device);
+ unsigned long flags;
+
+ spin_lock_irqsave(&atchan->lock, flags);
+ set_bit(AT_XDMAC_CHAN_IS_PAUSED_INTERNAL, &atchan->status);
+ at_xdmac_device_pause_set(atxdmac, atchan);
+ spin_unlock_irqrestore(&atchan->lock, flags);
+}
+
static int at_xdmac_device_pause(struct dma_chan *chan)
{
struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan);
@@ -1915,11 +1942,8 @@ static int at_xdmac_device_pause(struct dma_chan *chan)
return ret;
spin_lock_irqsave(&atchan->lock, flags);
- at_xdmac_write(atxdmac, atxdmac->layout->grws, atchan->mask);
- while (at_xdmac_chan_read(atchan, AT_XDMAC_CC)
- & (AT_XDMAC_CC_WRIP | AT_XDMAC_CC_RDIP))
- cpu_relax();
+ at_xdmac_device_pause_set(atxdmac, atchan);
/* Decrement runtime PM ref counter for each active descriptor. */
at_xdmac_runtime_suspend_descriptors(atchan);
@@ -1931,6 +1955,17 @@ static int at_xdmac_device_pause(struct dma_chan *chan)
return 0;
}
+static void at_xdmac_device_resume_internal(struct at_xdmac_chan *atchan)
+{
+ struct at_xdmac *atxdmac = to_at_xdmac(atchan->chan.device);
+ unsigned long flags;
+
+ spin_lock_irqsave(&atchan->lock, flags);
+ at_xdmac_write(atxdmac, atxdmac->layout->grwr, atchan->mask);
+ clear_bit(AT_XDMAC_CHAN_IS_PAUSED_INTERNAL, &atchan->status);
+ spin_unlock_irqrestore(&atchan->lock, flags);
+}
+
static int at_xdmac_device_resume(struct dma_chan *chan)
{
struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan);
@@ -2118,19 +2153,26 @@ static int __maybe_unused atmel_xdmac_suspend(struct device *dev)
atchan->save_cc = at_xdmac_chan_read(atchan, AT_XDMAC_CC);
if (at_xdmac_chan_is_cyclic(atchan)) {
- if (!at_xdmac_chan_is_paused(atchan))
- at_xdmac_device_pause(chan);
+ if (!at_xdmac_chan_is_paused(atchan)) {
+ dev_warn(chan2dev(chan), "%s: channel %d not paused\n",
+ __func__, chan->chan_id);
+ at_xdmac_device_pause_internal(atchan);
+ at_xdmac_runtime_suspend_descriptors(atchan);
+ }
atchan->save_cim = at_xdmac_chan_read(atchan, AT_XDMAC_CIM);
atchan->save_cnda = at_xdmac_chan_read(atchan, AT_XDMAC_CNDA);
atchan->save_cndc = at_xdmac_chan_read(atchan, AT_XDMAC_CNDC);
}
-
- at_xdmac_runtime_suspend_descriptors(atchan);
}
atxdmac->save_gim = at_xdmac_read(atxdmac, AT_XDMAC_GIM);
+ atxdmac->save_gs = at_xdmac_read(atxdmac, AT_XDMAC_GS);
+
+ at_xdmac_off(atxdmac, false);
+ pm_runtime_mark_last_busy(atxdmac->dev);
+ pm_runtime_put_noidle(atxdmac->dev);
+ clk_disable_unprepare(atxdmac->clk);
- at_xdmac_off(atxdmac);
- return pm_runtime_force_suspend(atxdmac->dev);
+ return 0;
}
static int __maybe_unused atmel_xdmac_resume(struct device *dev)
@@ -2139,13 +2181,14 @@ static int __maybe_unused atmel_xdmac_resume(struct device *dev)
struct at_xdmac_chan *atchan;
struct dma_chan *chan, *_chan;
struct platform_device *pdev = container_of(dev, struct platform_device, dev);
- int i;
- int ret;
+ int i, ret;
- ret = pm_runtime_force_resume(atxdmac->dev);
- if (ret < 0)
+ ret = clk_prepare_enable(atxdmac->clk);
+ if (ret)
return ret;
+ pm_runtime_get_noresume(atxdmac->dev);
+
at_xdmac_axi_config(pdev);
/* Clear pending interrupts. */
@@ -2159,19 +2202,33 @@ static int __maybe_unused atmel_xdmac_resume(struct device *dev)
list_for_each_entry_safe(chan, _chan, &atxdmac->dma.channels, device_node) {
atchan = to_at_xdmac_chan(chan);
- ret = at_xdmac_runtime_resume_descriptors(atchan);
- if (ret < 0)
- return ret;
-
at_xdmac_chan_write(atchan, AT_XDMAC_CC, atchan->save_cc);
if (at_xdmac_chan_is_cyclic(atchan)) {
- if (at_xdmac_chan_is_paused(atchan))
- at_xdmac_device_resume(chan);
+ /*
+ * Resume only channels not explicitly paused by
+ * consumers.
+ */
+ if (at_xdmac_chan_is_paused_internal(atchan)) {
+ ret = at_xdmac_runtime_resume_descriptors(atchan);
+ if (ret < 0)
+ return ret;
+ at_xdmac_device_resume_internal(atchan);
+ }
+
+ /*
+ * We may resume from a deep sleep state where power
+ * to DMA controller is cut-off. Thus, restore the
+ * suspend state of channels set though dmaengine API.
+ */
+ else if (at_xdmac_chan_is_paused(atchan))
+ at_xdmac_device_pause_set(atxdmac, atchan);
+
at_xdmac_chan_write(atchan, AT_XDMAC_CNDA, atchan->save_cnda);
at_xdmac_chan_write(atchan, AT_XDMAC_CNDC, atchan->save_cndc);
at_xdmac_chan_write(atchan, AT_XDMAC_CIE, atchan->save_cim);
wmb();
- at_xdmac_write(atxdmac, AT_XDMAC_GE, atchan->mask);
+ if (atxdmac->save_gs & atchan->mask)
+ at_xdmac_write(atxdmac, AT_XDMAC_GE, atchan->mask);
}
}
@@ -2312,7 +2369,7 @@ static int at_xdmac_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&atxdmac->dma.channels);
/* Disable all chans and interrupts. */
- at_xdmac_off(atxdmac);
+ at_xdmac_off(atxdmac, true);
for (i = 0; i < nr_channels; i++) {
struct at_xdmac_chan *atchan = &atxdmac->chan[i];
@@ -2376,7 +2433,7 @@ static int at_xdmac_remove(struct platform_device *pdev)
struct at_xdmac *atxdmac = (struct at_xdmac *)platform_get_drvdata(pdev);
int i;
- at_xdmac_off(atxdmac);
+ at_xdmac_off(atxdmac, true);
of_dma_controller_free(pdev->dev.of_node);
dma_async_device_unregister(&atxdmac->dma);
pm_runtime_disable(atxdmac->dev);
diff --git a/drivers/dma/bestcomm/sram.c b/drivers/dma/bestcomm/sram.c
index c465758e7193..0553956f7456 100644
--- a/drivers/dma/bestcomm/sram.c
+++ b/drivers/dma/bestcomm/sram.c
@@ -38,7 +38,7 @@ int bcom_sram_init(struct device_node *sram_node, char *owner)
{
int rv;
const u32 *regaddr_p;
- u64 regaddr64, size64;
+ struct resource res;
unsigned int psize;
/* Create our state struct */
@@ -56,21 +56,18 @@ int bcom_sram_init(struct device_node *sram_node, char *owner)
}
/* Get address and size of the sram */
- regaddr_p = of_get_address(sram_node, 0, &size64, NULL);
- if (!regaddr_p) {
+ rv = of_address_to_resource(sram_node, 0, &res);
+ if (rv) {
printk(KERN_ERR "%s: bcom_sram_init: "
"Invalid device node !\n", owner);
- rv = -EINVAL;
goto error_free;
}
- regaddr64 = of_translate_address(sram_node, regaddr_p);
-
- bcom_sram->base_phys = (phys_addr_t) regaddr64;
- bcom_sram->size = (unsigned int) size64;
+ bcom_sram->base_phys = res.start;
+ bcom_sram->size = resource_size(&res);
/* Request region */
- if (!request_mem_region(bcom_sram->base_phys, bcom_sram->size, owner)) {
+ if (!request_mem_region(res.start, resource_size(&res), owner)) {
printk(KERN_ERR "%s: bcom_sram_init: "
"Couldn't request region !\n", owner);
rv = -EBUSY;
@@ -79,7 +76,7 @@ int bcom_sram_init(struct device_node *sram_node, char *owner)
/* Map SRAM */
/* sram is not really __iomem */
- bcom_sram->base_virt = (void*) ioremap(bcom_sram->base_phys, bcom_sram->size);
+ bcom_sram->base_virt = (void *)ioremap(res.start, resource_size(&res));
if (!bcom_sram->base_virt) {
printk(KERN_ERR "%s: bcom_sram_init: "
@@ -120,7 +117,7 @@ int bcom_sram_init(struct device_node *sram_node, char *owner)
return 0;
error_release:
- release_mem_region(bcom_sram->base_phys, bcom_sram->size);
+ release_mem_region(res.start, resource_size(&res));
error_free:
kfree(bcom_sram);
bcom_sram = NULL;
diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
index 4169e1d7d5ca..6937cc0c0b65 100644
--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
+++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
@@ -21,10 +21,12 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/of_dma.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/property.h>
+#include <linux/reset.h>
#include <linux/slab.h>
#include <linux/types.h>
@@ -46,6 +48,10 @@
DMA_SLAVE_BUSWIDTH_32_BYTES | \
DMA_SLAVE_BUSWIDTH_64_BYTES)
+#define AXI_DMA_FLAG_HAS_APB_REGS BIT(0)
+#define AXI_DMA_FLAG_HAS_RESETS BIT(1)
+#define AXI_DMA_FLAG_USE_CFG2 BIT(2)
+
static inline void
axi_dma_iowrite32(struct axi_dma_chip *chip, u32 reg, u32 val)
{
@@ -86,7 +92,8 @@ static inline void axi_chan_config_write(struct axi_dma_chan *chan,
cfg_lo = (config->dst_multblk_type << CH_CFG_L_DST_MULTBLK_TYPE_POS |
config->src_multblk_type << CH_CFG_L_SRC_MULTBLK_TYPE_POS);
- if (chan->chip->dw->hdata->reg_map_8_channels) {
+ if (chan->chip->dw->hdata->reg_map_8_channels &&
+ !chan->chip->dw->hdata->use_cfg2) {
cfg_hi = config->tt_fc << CH_CFG_H_TT_FC_POS |
config->hs_sel_src << CH_CFG_H_HS_SEL_SRC_POS |
config->hs_sel_dst << CH_CFG_H_HS_SEL_DST_POS |
@@ -1140,7 +1147,7 @@ static int dma_chan_terminate_all(struct dma_chan *dchan)
axi_chan_disable(chan);
ret = readl_poll_timeout_atomic(chan->chip->regs + DMAC_CHEN, val,
- !(val & chan_active), 1000, 10000);
+ !(val & chan_active), 1000, 50000);
if (ret == -ETIMEDOUT)
dev_warn(dchan2dev(dchan),
"%s failed to stop\n", axi_chan_name(chan));
@@ -1367,10 +1374,11 @@ static int parse_device_properties(struct axi_dma_chip *chip)
static int dw_probe(struct platform_device *pdev)
{
- struct device_node *node = pdev->dev.of_node;
struct axi_dma_chip *chip;
struct dw_axi_dma *dw;
struct dw_axi_dma_hcfg *hdata;
+ struct reset_control *resets;
+ unsigned int flags;
u32 i;
int ret;
@@ -1398,12 +1406,25 @@ static int dw_probe(struct platform_device *pdev)
if (IS_ERR(chip->regs))
return PTR_ERR(chip->regs);
- if (of_device_is_compatible(node, "intel,kmb-axi-dma")) {
+ flags = (uintptr_t)of_device_get_match_data(&pdev->dev);
+ if (flags & AXI_DMA_FLAG_HAS_APB_REGS) {
chip->apb_regs = devm_platform_ioremap_resource(pdev, 1);
if (IS_ERR(chip->apb_regs))
return PTR_ERR(chip->apb_regs);
}
+ if (flags & AXI_DMA_FLAG_HAS_RESETS) {
+ resets = devm_reset_control_array_get_exclusive(&pdev->dev);
+ if (IS_ERR(resets))
+ return PTR_ERR(resets);
+
+ ret = reset_control_deassert(resets);
+ if (ret)
+ return ret;
+ }
+
+ chip->dw->hdata->use_cfg2 = !!(flags & AXI_DMA_FLAG_USE_CFG2);
+
chip->core_clk = devm_clk_get(chip->dev, "core-clk");
if (IS_ERR(chip->core_clk))
return PTR_ERR(chip->core_clk);
@@ -1554,8 +1575,15 @@ static const struct dev_pm_ops dw_axi_dma_pm_ops = {
};
static const struct of_device_id dw_dma_of_id_table[] = {
- { .compatible = "snps,axi-dma-1.01a" },
- { .compatible = "intel,kmb-axi-dma" },
+ {
+ .compatible = "snps,axi-dma-1.01a"
+ }, {
+ .compatible = "intel,kmb-axi-dma",
+ .data = (void *)AXI_DMA_FLAG_HAS_APB_REGS,
+ }, {
+ .compatible = "starfive,jh7110-axi-dma",
+ .data = (void *)(AXI_DMA_FLAG_HAS_RESETS | AXI_DMA_FLAG_USE_CFG2),
+ },
{}
};
MODULE_DEVICE_TABLE(of, dw_dma_of_id_table);
diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h
index e9d5eb0fd594..eb267cb24f67 100644
--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h
+++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h
@@ -33,6 +33,7 @@ struct dw_axi_dma_hcfg {
/* Register map for DMAX_NUM_CHANNELS <= 8 */
bool reg_map_8_channels;
bool restrict_axi_burst_len;
+ bool use_cfg2;
};
struct axi_dma_chan {
diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index 1906a836f0aa..7d2b73ef0872 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -181,7 +181,7 @@ static void vchan_free_desc(struct virt_dma_desc *vdesc)
dw_edma_free_desc(vd2dw_edma_desc(vdesc));
}
-static void dw_edma_start_transfer(struct dw_edma_chan *chan)
+static int dw_edma_start_transfer(struct dw_edma_chan *chan)
{
struct dw_edma_chunk *child;
struct dw_edma_desc *desc;
@@ -189,16 +189,16 @@ static void dw_edma_start_transfer(struct dw_edma_chan *chan)
vd = vchan_next_desc(&chan->vc);
if (!vd)
- return;
+ return 0;
desc = vd2dw_edma_desc(vd);
if (!desc)
- return;
+ return 0;
child = list_first_entry_or_null(&desc->chunk->list,
struct dw_edma_chunk, list);
if (!child)
- return;
+ return 0;
dw_edma_v0_core_start(child, !desc->xfer_sz);
desc->xfer_sz += child->ll_region.sz;
@@ -206,6 +206,8 @@ static void dw_edma_start_transfer(struct dw_edma_chan *chan)
list_del(&child->list);
kfree(child);
desc->chunks_alloc--;
+
+ return 1;
}
static void dw_edma_device_caps(struct dma_chan *dchan,
@@ -306,9 +308,12 @@ static void dw_edma_device_issue_pending(struct dma_chan *dchan)
struct dw_edma_chan *chan = dchan2dw_edma_chan(dchan);
unsigned long flags;
+ if (!chan->configured)
+ return;
+
spin_lock_irqsave(&chan->vc.lock, flags);
- if (chan->configured && chan->request == EDMA_REQ_NONE &&
- chan->status == EDMA_ST_IDLE && vchan_issue_pending(&chan->vc)) {
+ if (vchan_issue_pending(&chan->vc) && chan->request == EDMA_REQ_NONE &&
+ chan->status == EDMA_ST_IDLE) {
chan->status = EDMA_ST_BUSY;
dw_edma_start_transfer(chan);
}
@@ -602,14 +607,14 @@ static void dw_edma_done_interrupt(struct dw_edma_chan *chan)
switch (chan->request) {
case EDMA_REQ_NONE:
desc = vd2dw_edma_desc(vd);
- if (desc->chunks_alloc) {
- chan->status = EDMA_ST_BUSY;
- dw_edma_start_transfer(chan);
- } else {
+ if (!desc->chunks_alloc) {
list_del(&vd->node);
vchan_cookie_complete(vd);
- chan->status = EDMA_ST_IDLE;
}
+
+ /* Continue transferring if there are remaining chunks or issued requests.
+ */
+ chan->status = dw_edma_start_transfer(chan) ? EDMA_ST_BUSY : EDMA_ST_IDLE;
break;
case EDMA_REQ_STOP:
diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.c b/drivers/dma/dw-edma/dw-edma-v0-core.c
index 72e79a0c0a4e..32f834a3848a 100644
--- a/drivers/dma/dw-edma/dw-edma-v0-core.c
+++ b/drivers/dma/dw-edma/dw-edma-v0-core.c
@@ -159,62 +159,6 @@ static inline u32 readl_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
#define GET_CH_32(dw, dir, ch, name) \
readl_ch(dw, dir, ch, &(__dw_ch_regs(dw, dir, ch)->name))
-static inline void writeq_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
- u64 value, void __iomem *addr)
-{
- if (dw->chip->mf == EDMA_MF_EDMA_LEGACY) {
- u32 viewport_sel;
- unsigned long flags;
-
- raw_spin_lock_irqsave(&dw->lock, flags);
-
- viewport_sel = FIELD_PREP(EDMA_V0_VIEWPORT_MASK, ch);
- if (dir == EDMA_DIR_READ)
- viewport_sel |= BIT(31);
-
- writel(viewport_sel,
- &(__dw_regs(dw)->type.legacy.viewport_sel));
- writeq(value, addr);
-
- raw_spin_unlock_irqrestore(&dw->lock, flags);
- } else {
- writeq(value, addr);
- }
-}
-
-static inline u64 readq_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
- const void __iomem *addr)
-{
- u64 value;
-
- if (dw->chip->mf == EDMA_MF_EDMA_LEGACY) {
- u32 viewport_sel;
- unsigned long flags;
-
- raw_spin_lock_irqsave(&dw->lock, flags);
-
- viewport_sel = FIELD_PREP(EDMA_V0_VIEWPORT_MASK, ch);
- if (dir == EDMA_DIR_READ)
- viewport_sel |= BIT(31);
-
- writel(viewport_sel,
- &(__dw_regs(dw)->type.legacy.viewport_sel));
- value = readq(addr);
-
- raw_spin_unlock_irqrestore(&dw->lock, flags);
- } else {
- value = readq(addr);
- }
-
- return value;
-}
-
-#define SET_CH_64(dw, dir, ch, name, value) \
- writeq_ch(dw, dir, ch, value, &(__dw_ch_regs(dw, dir, ch)->name))
-
-#define GET_CH_64(dw, dir, ch, name) \
- readq_ch(dw, dir, ch, &(__dw_ch_regs(dw, dir, ch)->name))
-
/* eDMA management callbacks */
void dw_edma_v0_core_off(struct dw_edma *dw)
{
diff --git a/drivers/dma/idxd/Makefile b/drivers/dma/idxd/Makefile
index a1e9f2b3a37c..dc096839ac63 100644
--- a/drivers/dma/idxd/Makefile
+++ b/drivers/dma/idxd/Makefile
@@ -1,7 +1,7 @@
ccflags-y += -DDEFAULT_SYMBOL_NAMESPACE=IDXD
obj-$(CONFIG_INTEL_IDXD) += idxd.o
-idxd-y := init.o irq.o device.o sysfs.o submit.o dma.o cdev.o
+idxd-y := init.o irq.o device.o sysfs.o submit.o dma.o cdev.o debugfs.o
idxd-$(CONFIG_INTEL_IDXD_PERFMON) += perfmon.o
diff --git a/drivers/dma/idxd/cdev.c b/drivers/dma/idxd/cdev.c
index 674bfefca088..ecbf67c2ad2b 100644
--- a/drivers/dma/idxd/cdev.c
+++ b/drivers/dma/idxd/cdev.c
@@ -11,7 +11,9 @@
#include <linux/fs.h>
#include <linux/poll.h>
#include <linux/iommu.h>
+#include <linux/highmem.h>
#include <uapi/linux/idxd.h>
+#include <linux/xarray.h>
#include "registers.h"
#include "idxd.h"
@@ -22,6 +24,13 @@ struct idxd_cdev_context {
};
/*
+ * Since user file names are global in DSA devices, define their ida's as
+ * global to avoid conflict file names.
+ */
+static DEFINE_IDA(file_ida);
+static DEFINE_MUTEX(ida_lock);
+
+/*
* ictx is an array based off of accelerator types. enum idxd_type
* is used as index
*/
@@ -34,8 +43,119 @@ struct idxd_user_context {
struct idxd_wq *wq;
struct task_struct *task;
unsigned int pasid;
+ struct mm_struct *mm;
unsigned int flags;
struct iommu_sva *sva;
+ struct idxd_dev idxd_dev;
+ u64 counters[COUNTER_MAX];
+ int id;
+ pid_t pid;
+};
+
+static void idxd_cdev_evl_drain_pasid(struct idxd_wq *wq, u32 pasid);
+static void idxd_xa_pasid_remove(struct idxd_user_context *ctx);
+
+static inline struct idxd_user_context *dev_to_uctx(struct device *dev)
+{
+ struct idxd_dev *idxd_dev = confdev_to_idxd_dev(dev);
+
+ return container_of(idxd_dev, struct idxd_user_context, idxd_dev);
+}
+
+static ssize_t cr_faults_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct idxd_user_context *ctx = dev_to_uctx(dev);
+
+ return sysfs_emit(buf, "%llu\n", ctx->counters[COUNTER_FAULTS]);
+}
+static DEVICE_ATTR_RO(cr_faults);
+
+static ssize_t cr_fault_failures_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct idxd_user_context *ctx = dev_to_uctx(dev);
+
+ return sysfs_emit(buf, "%llu\n", ctx->counters[COUNTER_FAULT_FAILS]);
+}
+static DEVICE_ATTR_RO(cr_fault_failures);
+
+static ssize_t pid_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct idxd_user_context *ctx = dev_to_uctx(dev);
+
+ return sysfs_emit(buf, "%u\n", ctx->pid);
+}
+static DEVICE_ATTR_RO(pid);
+
+static struct attribute *cdev_file_attributes[] = {
+ &dev_attr_cr_faults.attr,
+ &dev_attr_cr_fault_failures.attr,
+ &dev_attr_pid.attr,
+ NULL
+};
+
+static umode_t cdev_file_attr_visible(struct kobject *kobj, struct attribute *a, int n)
+{
+ struct device *dev = container_of(kobj, typeof(*dev), kobj);
+ struct idxd_user_context *ctx = dev_to_uctx(dev);
+ struct idxd_wq *wq = ctx->wq;
+
+ if (!wq_pasid_enabled(wq))
+ return 0;
+
+ return a->mode;
+}
+
+static const struct attribute_group cdev_file_attribute_group = {
+ .attrs = cdev_file_attributes,
+ .is_visible = cdev_file_attr_visible,
+};
+
+static const struct attribute_group *cdev_file_attribute_groups[] = {
+ &cdev_file_attribute_group,
+ NULL
+};
+
+static void idxd_file_dev_release(struct device *dev)
+{
+ struct idxd_user_context *ctx = dev_to_uctx(dev);
+ struct idxd_wq *wq = ctx->wq;
+ struct idxd_device *idxd = wq->idxd;
+ int rc;
+
+ mutex_lock(&ida_lock);
+ ida_free(&file_ida, ctx->id);
+ mutex_unlock(&ida_lock);
+
+ /* Wait for in-flight operations to complete. */
+ if (wq_shared(wq)) {
+ idxd_device_drain_pasid(idxd, ctx->pasid);
+ } else {
+ if (device_user_pasid_enabled(idxd)) {
+ /* The wq disable in the disable pasid function will drain the wq */
+ rc = idxd_wq_disable_pasid(wq);
+ if (rc < 0)
+ dev_err(dev, "wq disable pasid failed.\n");
+ } else {
+ idxd_wq_drain(wq);
+ }
+ }
+
+ if (ctx->sva) {
+ idxd_cdev_evl_drain_pasid(wq, ctx->pasid);
+ iommu_sva_unbind_device(ctx->sva);
+ idxd_xa_pasid_remove(ctx);
+ }
+ kfree(ctx);
+ mutex_lock(&wq->wq_lock);
+ idxd_wq_put(wq);
+ mutex_unlock(&wq->wq_lock);
+}
+
+static struct device_type idxd_cdev_file_type = {
+ .name = "idxd_file",
+ .release = idxd_file_dev_release,
+ .groups = cdev_file_attribute_groups,
};
static void idxd_cdev_dev_release(struct device *dev)
@@ -68,15 +188,46 @@ static inline struct idxd_wq *inode_wq(struct inode *inode)
return idxd_cdev->wq;
}
+static void idxd_xa_pasid_remove(struct idxd_user_context *ctx)
+{
+ struct idxd_wq *wq = ctx->wq;
+ void *ptr;
+
+ mutex_lock(&wq->uc_lock);
+ ptr = xa_cmpxchg(&wq->upasid_xa, ctx->pasid, ctx, NULL, GFP_KERNEL);
+ if (ptr != (void *)ctx)
+ dev_warn(&wq->idxd->pdev->dev, "xarray cmpxchg failed for pasid %u\n",
+ ctx->pasid);
+ mutex_unlock(&wq->uc_lock);
+}
+
+void idxd_user_counter_increment(struct idxd_wq *wq, u32 pasid, int index)
+{
+ struct idxd_user_context *ctx;
+
+ if (index >= COUNTER_MAX)
+ return;
+
+ mutex_lock(&wq->uc_lock);
+ ctx = xa_load(&wq->upasid_xa, pasid);
+ if (!ctx) {
+ mutex_unlock(&wq->uc_lock);
+ return;
+ }
+ ctx->counters[index]++;
+ mutex_unlock(&wq->uc_lock);
+}
+
static int idxd_cdev_open(struct inode *inode, struct file *filp)
{
struct idxd_user_context *ctx;
struct idxd_device *idxd;
struct idxd_wq *wq;
- struct device *dev;
+ struct device *dev, *fdev;
int rc = 0;
struct iommu_sva *sva;
unsigned int pasid;
+ struct idxd_cdev *idxd_cdev;
wq = inode_wq(inode);
idxd = wq->idxd;
@@ -97,6 +248,7 @@ static int idxd_cdev_open(struct inode *inode, struct file *filp)
ctx->wq = wq;
filp->private_data = ctx;
+ ctx->pid = current->pid;
if (device_user_pasid_enabled(idxd)) {
sva = iommu_sva_bind_device(dev, current->mm);
@@ -108,65 +260,118 @@ static int idxd_cdev_open(struct inode *inode, struct file *filp)
pasid = iommu_sva_get_pasid(sva);
if (pasid == IOMMU_PASID_INVALID) {
- iommu_sva_unbind_device(sva);
rc = -EINVAL;
- goto failed;
+ goto failed_get_pasid;
}
ctx->sva = sva;
ctx->pasid = pasid;
+ ctx->mm = current->mm;
+
+ mutex_lock(&wq->uc_lock);
+ rc = xa_insert(&wq->upasid_xa, pasid, ctx, GFP_KERNEL);
+ mutex_unlock(&wq->uc_lock);
+ if (rc < 0)
+ dev_warn(dev, "PASID entry already exist in xarray.\n");
if (wq_dedicated(wq)) {
rc = idxd_wq_set_pasid(wq, pasid);
if (rc < 0) {
iommu_sva_unbind_device(sva);
dev_err(dev, "wq set pasid failed: %d\n", rc);
- goto failed;
+ goto failed_set_pasid;
}
}
}
+ idxd_cdev = wq->idxd_cdev;
+ mutex_lock(&ida_lock);
+ ctx->id = ida_alloc(&file_ida, GFP_KERNEL);
+ mutex_unlock(&ida_lock);
+ if (ctx->id < 0) {
+ dev_warn(dev, "ida alloc failure\n");
+ goto failed_ida;
+ }
+ ctx->idxd_dev.type = IDXD_DEV_CDEV_FILE;
+ fdev = user_ctx_dev(ctx);
+ device_initialize(fdev);
+ fdev->parent = cdev_dev(idxd_cdev);
+ fdev->bus = &dsa_bus_type;
+ fdev->type = &idxd_cdev_file_type;
+
+ rc = dev_set_name(fdev, "file%d", ctx->id);
+ if (rc < 0) {
+ dev_warn(dev, "set name failure\n");
+ goto failed_dev_name;
+ }
+
+ rc = device_add(fdev);
+ if (rc < 0) {
+ dev_warn(dev, "file device add failure\n");
+ goto failed_dev_add;
+ }
+
idxd_wq_get(wq);
mutex_unlock(&wq->wq_lock);
return 0;
- failed:
+failed_dev_add:
+failed_dev_name:
+ put_device(fdev);
+failed_ida:
+failed_set_pasid:
+ if (device_user_pasid_enabled(idxd))
+ idxd_xa_pasid_remove(ctx);
+failed_get_pasid:
+ if (device_user_pasid_enabled(idxd))
+ iommu_sva_unbind_device(sva);
+failed:
mutex_unlock(&wq->wq_lock);
kfree(ctx);
return rc;
}
+static void idxd_cdev_evl_drain_pasid(struct idxd_wq *wq, u32 pasid)
+{
+ struct idxd_device *idxd = wq->idxd;
+ struct idxd_evl *evl = idxd->evl;
+ union evl_status_reg status;
+ u16 h, t, size;
+ int ent_size = evl_ent_size(idxd);
+ struct __evl_entry *entry_head;
+
+ if (!evl)
+ return;
+
+ spin_lock(&evl->lock);
+ status.bits = ioread64(idxd->reg_base + IDXD_EVLSTATUS_OFFSET);
+ t = status.tail;
+ h = evl->head;
+ size = evl->size;
+
+ while (h != t) {
+ entry_head = (struct __evl_entry *)(evl->log + (h * ent_size));
+ if (entry_head->pasid == pasid && entry_head->wq_idx == wq->id)
+ set_bit(h, evl->bmap);
+ h = (h + 1) % size;
+ }
+ spin_unlock(&evl->lock);
+
+ drain_workqueue(wq->wq);
+}
+
static int idxd_cdev_release(struct inode *node, struct file *filep)
{
struct idxd_user_context *ctx = filep->private_data;
struct idxd_wq *wq = ctx->wq;
struct idxd_device *idxd = wq->idxd;
struct device *dev = &idxd->pdev->dev;
- int rc;
dev_dbg(dev, "%s called\n", __func__);
filep->private_data = NULL;
- /* Wait for in-flight operations to complete. */
- if (wq_shared(wq)) {
- idxd_device_drain_pasid(idxd, ctx->pasid);
- } else {
- if (device_user_pasid_enabled(idxd)) {
- /* The wq disable in the disable pasid function will drain the wq */
- rc = idxd_wq_disable_pasid(wq);
- if (rc < 0)
- dev_err(dev, "wq disable pasid failed.\n");
- } else {
- idxd_wq_drain(wq);
- }
- }
+ device_unregister(user_ctx_dev(ctx));
- if (ctx->sva)
- iommu_sva_unbind_device(ctx->sva);
- kfree(ctx);
- mutex_lock(&wq->wq_lock);
- idxd_wq_put(wq);
- mutex_unlock(&wq->wq_lock);
return 0;
}
@@ -297,6 +502,7 @@ void idxd_wq_del_cdev(struct idxd_wq *wq)
struct idxd_cdev *idxd_cdev;
idxd_cdev = wq->idxd_cdev;
+ ida_destroy(&file_ida);
wq->idxd_cdev = NULL;
cdev_device_del(&idxd_cdev->cdev, cdev_dev(idxd_cdev));
put_device(cdev_dev(idxd_cdev));
@@ -330,6 +536,13 @@ static int idxd_user_drv_probe(struct idxd_dev *idxd_dev)
}
mutex_lock(&wq->wq_lock);
+
+ wq->wq = create_workqueue(dev_name(wq_confdev(wq)));
+ if (!wq->wq) {
+ rc = -ENOMEM;
+ goto wq_err;
+ }
+
wq->type = IDXD_WQT_USER;
rc = drv_enable_wq(wq);
if (rc < 0)
@@ -348,7 +561,9 @@ static int idxd_user_drv_probe(struct idxd_dev *idxd_dev)
err_cdev:
drv_disable_wq(wq);
err:
+ destroy_workqueue(wq->wq);
wq->type = IDXD_WQT_NONE;
+wq_err:
mutex_unlock(&wq->wq_lock);
return rc;
}
@@ -361,6 +576,8 @@ static void idxd_user_drv_remove(struct idxd_dev *idxd_dev)
idxd_wq_del_cdev(wq);
drv_disable_wq(wq);
wq->type = IDXD_WQT_NONE;
+ destroy_workqueue(wq->wq);
+ wq->wq = NULL;
mutex_unlock(&wq->wq_lock);
}
@@ -407,3 +624,70 @@ void idxd_cdev_remove(void)
ida_destroy(&ictx[i].minor_ida);
}
}
+
+/**
+ * idxd_copy_cr - copy completion record to user address space found by wq and
+ * PASID
+ * @wq: work queue
+ * @pasid: PASID
+ * @addr: user fault address to write
+ * @cr: completion record
+ * @len: number of bytes to copy
+ *
+ * This is called by a work that handles completion record fault.
+ *
+ * Return: number of bytes copied.
+ */
+int idxd_copy_cr(struct idxd_wq *wq, ioasid_t pasid, unsigned long addr,
+ void *cr, int len)
+{
+ struct device *dev = &wq->idxd->pdev->dev;
+ int left = len, status_size = 1;
+ struct idxd_user_context *ctx;
+ struct mm_struct *mm;
+
+ mutex_lock(&wq->uc_lock);
+
+ ctx = xa_load(&wq->upasid_xa, pasid);
+ if (!ctx) {
+ dev_warn(dev, "No user context\n");
+ goto out;
+ }
+
+ mm = ctx->mm;
+ /*
+ * The completion record fault handling work is running in kernel
+ * thread context. It temporarily switches to the mm to copy cr
+ * to addr in the mm.
+ */
+ kthread_use_mm(mm);
+ left = copy_to_user((void __user *)addr + status_size, cr + status_size,
+ len - status_size);
+ /*
+ * Copy status only after the rest of completion record is copied
+ * successfully so that the user gets the complete completion record
+ * when a non-zero status is polled.
+ */
+ if (!left) {
+ u8 status;
+
+ /*
+ * Ensure that the completion record's status field is written
+ * after the rest of the completion record has been written.
+ * This ensures that the user receives the correct completion
+ * record information once polling for a non-zero status.
+ */
+ wmb();
+ status = *(u8 *)cr;
+ if (put_user(status, (u8 __user *)addr))
+ left += status_size;
+ } else {
+ left += status_size;
+ }
+ kthread_unuse_mm(mm);
+
+out:
+ mutex_unlock(&wq->uc_lock);
+
+ return len - left;
+}
diff --git a/drivers/dma/idxd/debugfs.c b/drivers/dma/idxd/debugfs.c
new file mode 100644
index 000000000000..9cfbd9b14c4c
--- /dev/null
+++ b/drivers/dma/idxd/debugfs.c
@@ -0,0 +1,138 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2021 Intel Corporation. All rights rsvd. */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/debugfs.h>
+#include <linux/io-64-nonatomic-lo-hi.h>
+#include <uapi/linux/idxd.h>
+#include "idxd.h"
+#include "registers.h"
+
+static struct dentry *idxd_debugfs_dir;
+
+static void dump_event_entry(struct idxd_device *idxd, struct seq_file *s,
+ u16 index, int *count, bool processed)
+{
+ struct idxd_evl *evl = idxd->evl;
+ struct dsa_evl_entry *entry;
+ struct dsa_completion_record *cr;
+ u64 *raw;
+ int i;
+ int evl_strides = evl_ent_size(idxd) / sizeof(u64);
+
+ entry = (struct dsa_evl_entry *)evl->log + index;
+
+ if (!entry->e.desc_valid)
+ return;
+
+ seq_printf(s, "Event Log entry %d (real index %u) processed: %u\n",
+ *count, index, processed);
+
+ seq_printf(s, "desc valid %u wq idx valid %u\n"
+ "batch %u fault rw %u priv %u error 0x%x\n"
+ "wq idx %u op %#x pasid %u batch idx %u\n"
+ "fault addr %#llx\n",
+ entry->e.desc_valid, entry->e.wq_idx_valid,
+ entry->e.batch, entry->e.fault_rw, entry->e.priv,
+ entry->e.error, entry->e.wq_idx, entry->e.operation,
+ entry->e.pasid, entry->e.batch_idx, entry->e.fault_addr);
+
+ cr = &entry->cr;
+ seq_printf(s, "status %#x result %#x fault_info %#x bytes_completed %u\n"
+ "fault addr %#llx inv flags %#x\n\n",
+ cr->status, cr->result, cr->fault_info, cr->bytes_completed,
+ cr->fault_addr, cr->invalid_flags);
+
+ raw = (u64 *)entry;
+
+ for (i = 0; i < evl_strides; i++)
+ seq_printf(s, "entry[%d] = %#llx\n", i, raw[i]);
+
+ seq_puts(s, "\n");
+ *count += 1;
+}
+
+static int debugfs_evl_show(struct seq_file *s, void *d)
+{
+ struct idxd_device *idxd = s->private;
+ struct idxd_evl *evl = idxd->evl;
+ union evl_status_reg evl_status;
+ u16 h, t, evl_size, i;
+ int count = 0;
+ bool processed = true;
+
+ if (!evl || !evl->log)
+ return 0;
+
+ spin_lock(&evl->lock);
+
+ h = evl->head;
+ evl_status.bits = ioread64(idxd->reg_base + IDXD_EVLSTATUS_OFFSET);
+ t = evl_status.tail;
+ evl_size = evl->size;
+
+ seq_printf(s, "Event Log head %u tail %u interrupt pending %u\n\n",
+ evl_status.head, evl_status.tail, evl_status.int_pending);
+
+ i = t;
+ while (1) {
+ i = (i + 1) % evl_size;
+ if (i == t)
+ break;
+
+ if (processed && i == h)
+ processed = false;
+ dump_event_entry(idxd, s, i, &count, processed);
+ }
+
+ spin_unlock(&evl->lock);
+ return 0;
+}
+
+DEFINE_SHOW_ATTRIBUTE(debugfs_evl);
+
+int idxd_device_init_debugfs(struct idxd_device *idxd)
+{
+ if (IS_ERR_OR_NULL(idxd_debugfs_dir))
+ return 0;
+
+ idxd->dbgfs_dir = debugfs_create_dir(dev_name(idxd_confdev(idxd)), idxd_debugfs_dir);
+ if (IS_ERR(idxd->dbgfs_dir))
+ return PTR_ERR(idxd->dbgfs_dir);
+
+ if (idxd->evl) {
+ idxd->dbgfs_evl_file = debugfs_create_file("event_log", 0400,
+ idxd->dbgfs_dir, idxd,
+ &debugfs_evl_fops);
+ if (IS_ERR(idxd->dbgfs_evl_file)) {
+ debugfs_remove_recursive(idxd->dbgfs_dir);
+ idxd->dbgfs_dir = NULL;
+ return PTR_ERR(idxd->dbgfs_evl_file);
+ }
+ }
+
+ return 0;
+}
+
+void idxd_device_remove_debugfs(struct idxd_device *idxd)
+{
+ debugfs_remove_recursive(idxd->dbgfs_dir);
+}
+
+int idxd_init_debugfs(void)
+{
+ if (!debugfs_initialized())
+ return 0;
+
+ idxd_debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL);
+ if (IS_ERR(idxd_debugfs_dir))
+ return PTR_ERR(idxd_debugfs_dir);
+ return 0;
+}
+
+void idxd_remove_debugfs(void)
+{
+ debugfs_remove_recursive(idxd_debugfs_dir);
+}
diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c
index 6fca8fa8d3a8..5abbcc61c528 100644
--- a/drivers/dma/idxd/device.c
+++ b/drivers/dma/idxd/device.c
@@ -752,6 +752,101 @@ void idxd_device_clear_state(struct idxd_device *idxd)
spin_unlock(&idxd->dev_lock);
}
+static int idxd_device_evl_setup(struct idxd_device *idxd)
+{
+ union gencfg_reg gencfg;
+ union evlcfg_reg evlcfg;
+ union genctrl_reg genctrl;
+ struct device *dev = &idxd->pdev->dev;
+ void *addr;
+ dma_addr_t dma_addr;
+ int size;
+ struct idxd_evl *evl = idxd->evl;
+ unsigned long *bmap;
+ int rc;
+
+ if (!evl)
+ return 0;
+
+ size = evl_size(idxd);
+
+ bmap = bitmap_zalloc(size, GFP_KERNEL);
+ if (!bmap) {
+ rc = -ENOMEM;
+ goto err_bmap;
+ }
+
+ /*
+ * Address needs to be page aligned. However, dma_alloc_coherent() provides
+ * at minimal page size aligned address. No manual alignment required.
+ */
+ addr = dma_alloc_coherent(dev, size, &dma_addr, GFP_KERNEL);
+ if (!addr) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+
+ memset(addr, 0, size);
+
+ spin_lock(&evl->lock);
+ evl->log = addr;
+ evl->dma = dma_addr;
+ evl->log_size = size;
+ evl->bmap = bmap;
+
+ memset(&evlcfg, 0, sizeof(evlcfg));
+ evlcfg.bits[0] = dma_addr & GENMASK(63, 12);
+ evlcfg.size = evl->size;
+
+ iowrite64(evlcfg.bits[0], idxd->reg_base + IDXD_EVLCFG_OFFSET);
+ iowrite64(evlcfg.bits[1], idxd->reg_base + IDXD_EVLCFG_OFFSET + 8);
+
+ genctrl.bits = ioread32(idxd->reg_base + IDXD_GENCTRL_OFFSET);
+ genctrl.evl_int_en = 1;
+ iowrite32(genctrl.bits, idxd->reg_base + IDXD_GENCTRL_OFFSET);
+
+ gencfg.bits = ioread32(idxd->reg_base + IDXD_GENCFG_OFFSET);
+ gencfg.evl_en = 1;
+ iowrite32(gencfg.bits, idxd->reg_base + IDXD_GENCFG_OFFSET);
+
+ spin_unlock(&evl->lock);
+ return 0;
+
+err_alloc:
+ bitmap_free(bmap);
+err_bmap:
+ return rc;
+}
+
+static void idxd_device_evl_free(struct idxd_device *idxd)
+{
+ union gencfg_reg gencfg;
+ union genctrl_reg genctrl;
+ struct device *dev = &idxd->pdev->dev;
+ struct idxd_evl *evl = idxd->evl;
+
+ gencfg.bits = ioread32(idxd->reg_base + IDXD_GENCFG_OFFSET);
+ if (!gencfg.evl_en)
+ return;
+
+ spin_lock(&evl->lock);
+ gencfg.evl_en = 0;
+ iowrite32(gencfg.bits, idxd->reg_base + IDXD_GENCFG_OFFSET);
+
+ genctrl.bits = ioread32(idxd->reg_base + IDXD_GENCTRL_OFFSET);
+ genctrl.evl_int_en = 0;
+ iowrite32(genctrl.bits, idxd->reg_base + IDXD_GENCTRL_OFFSET);
+
+ iowrite64(0, idxd->reg_base + IDXD_EVLCFG_OFFSET);
+ iowrite64(0, idxd->reg_base + IDXD_EVLCFG_OFFSET + 8);
+
+ dma_free_coherent(dev, evl->log_size, evl->log, evl->dma);
+ bitmap_free(evl->bmap);
+ evl->log = NULL;
+ evl->size = IDXD_EVL_SIZE_MIN;
+ spin_unlock(&evl->lock);
+}
+
static void idxd_group_config_write(struct idxd_group *group)
{
struct idxd_device *idxd = group->idxd;
@@ -872,12 +967,16 @@ static int idxd_wq_config_write(struct idxd_wq *wq)
wq->wqcfg->priority = wq->priority;
if (idxd->hw.gen_cap.block_on_fault &&
- test_bit(WQ_FLAG_BLOCK_ON_FAULT, &wq->flags))
+ test_bit(WQ_FLAG_BLOCK_ON_FAULT, &wq->flags) &&
+ !test_bit(WQ_FLAG_PRS_DISABLE, &wq->flags))
wq->wqcfg->bof = 1;
if (idxd->hw.wq_cap.wq_ats_support)
wq->wqcfg->wq_ats_disable = test_bit(WQ_FLAG_ATS_DISABLE, &wq->flags);
+ if (idxd->hw.wq_cap.wq_prs_support)
+ wq->wqcfg->wq_prs_disable = test_bit(WQ_FLAG_PRS_DISABLE, &wq->flags);
+
/* bytes 12-15 */
wq->wqcfg->max_xfer_shift = ilog2(wq->max_xfer_bytes);
idxd_wqcfg_set_max_batch_shift(idxd->data->type, wq->wqcfg, ilog2(wq->max_batch_size));
@@ -1451,15 +1550,24 @@ int idxd_device_drv_probe(struct idxd_dev *idxd_dev)
if (rc < 0)
return -ENXIO;
+ rc = idxd_device_evl_setup(idxd);
+ if (rc < 0) {
+ idxd->cmd_status = IDXD_SCMD_DEV_EVL_ERR;
+ return rc;
+ }
+
/* Start device */
rc = idxd_device_enable(idxd);
- if (rc < 0)
+ if (rc < 0) {
+ idxd_device_evl_free(idxd);
return rc;
+ }
/* Setup DMA device without channels */
rc = idxd_register_dma_device(idxd);
if (rc < 0) {
idxd_device_disable(idxd);
+ idxd_device_evl_free(idxd);
idxd->cmd_status = IDXD_SCMD_DEV_DMA_ERR;
return rc;
}
@@ -1488,6 +1596,7 @@ void idxd_device_drv_remove(struct idxd_dev *idxd_dev)
idxd_device_disable(idxd);
if (test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags))
idxd_device_reset(idxd);
+ idxd_device_evl_free(idxd);
}
static enum idxd_dev_type dev_types[] = {
diff --git a/drivers/dma/idxd/idxd.h b/drivers/dma/idxd/idxd.h
index dd2a6ed8949b..5428a2e1b1ec 100644
--- a/drivers/dma/idxd/idxd.h
+++ b/drivers/dma/idxd/idxd.h
@@ -32,6 +32,7 @@ enum idxd_dev_type {
IDXD_DEV_GROUP,
IDXD_DEV_ENGINE,
IDXD_DEV_CDEV,
+ IDXD_DEV_CDEV_FILE,
IDXD_DEV_MAX_TYPE,
};
@@ -127,6 +128,12 @@ struct idxd_pmu {
#define IDXD_MAX_PRIORITY 0xf
+enum {
+ COUNTER_FAULTS = 0,
+ COUNTER_FAULT_FAILS,
+ COUNTER_MAX
+};
+
enum idxd_wq_state {
IDXD_WQ_DISABLED = 0,
IDXD_WQ_ENABLED,
@@ -136,6 +143,7 @@ enum idxd_wq_flag {
WQ_FLAG_DEDICATED = 0,
WQ_FLAG_BLOCK_ON_FAULT,
WQ_FLAG_ATS_DISABLE,
+ WQ_FLAG_PRS_DISABLE,
};
enum idxd_wq_type {
@@ -185,6 +193,7 @@ struct idxd_wq {
struct idxd_dev idxd_dev;
struct idxd_cdev *idxd_cdev;
struct wait_queue_head err_queue;
+ struct workqueue_struct *wq;
struct idxd_device *idxd;
int id;
struct idxd_irq_entry ie;
@@ -214,6 +223,10 @@ struct idxd_wq {
char name[WQ_NAME_SIZE + 1];
u64 max_xfer_bytes;
u32 max_batch_size;
+
+ /* Lock to protect upasid_xa access. */
+ struct mutex uc_lock;
+ struct xarray upasid_xa;
};
struct idxd_engine {
@@ -232,6 +245,7 @@ struct idxd_hw {
union engine_cap_reg engine_cap;
struct opcap opcap;
u32 cmd_cap;
+ union iaa_cap_reg iaa_cap;
};
enum idxd_device_state {
@@ -258,6 +272,32 @@ struct idxd_driver_data {
struct device_type *dev_type;
int compl_size;
int align;
+ int evl_cr_off;
+ int cr_status_off;
+ int cr_result_off;
+};
+
+struct idxd_evl {
+ /* Lock to protect event log access. */
+ spinlock_t lock;
+ void *log;
+ dma_addr_t dma;
+ /* Total size of event log = number of entries * entry size. */
+ unsigned int log_size;
+ /* The number of entries in the event log. */
+ u16 size;
+ u16 head;
+ unsigned long *bmap;
+ bool batch_fail[IDXD_MAX_BATCH_IDENT];
+};
+
+struct idxd_evl_fault {
+ struct work_struct work;
+ struct idxd_wq *wq;
+ u8 status;
+
+ /* make this last member always */
+ struct __evl_entry entry[];
};
struct idxd_device {
@@ -316,8 +356,24 @@ struct idxd_device {
struct idxd_pmu *idxd_pmu;
unsigned long *opcap_bmap;
+ struct idxd_evl *evl;
+ struct kmem_cache *evl_cache;
+
+ struct dentry *dbgfs_dir;
+ struct dentry *dbgfs_evl_file;
};
+static inline unsigned int evl_ent_size(struct idxd_device *idxd)
+{
+ return idxd->hw.gen_cap.evl_support ?
+ (32 * (1 << idxd->hw.gen_cap.evl_support)) : 0;
+}
+
+static inline unsigned int evl_size(struct idxd_device *idxd)
+{
+ return idxd->evl->size * evl_ent_size(idxd);
+}
+
/* IDXD software descriptor */
struct idxd_desc {
union {
@@ -351,6 +407,7 @@ enum idxd_completion_status {
#define engine_confdev(engine) &engine->idxd_dev.conf_dev
#define group_confdev(group) &group->idxd_dev.conf_dev
#define cdev_dev(cdev) &cdev->idxd_dev.conf_dev
+#define user_ctx_dev(ctx) (&(ctx)->idxd_dev.conf_dev)
#define confdev_to_idxd_dev(dev) container_of(dev, struct idxd_dev, conf_dev)
#define idxd_dev_to_idxd(idxd_dev) container_of(idxd_dev, struct idxd_device, idxd_dev)
@@ -598,6 +655,7 @@ int idxd_register_driver(void);
void idxd_unregister_driver(void);
void idxd_wqs_quiesce(struct idxd_device *idxd);
bool idxd_queue_int_handle_resubmit(struct idxd_desc *desc);
+void multi_u64_to_bmap(unsigned long *bmap, u64 *val, int count);
/* device interrupt control */
irqreturn_t idxd_misc_thread(int vec, void *data);
@@ -662,6 +720,9 @@ void idxd_cdev_remove(void);
int idxd_cdev_get_major(struct idxd_device *idxd);
int idxd_wq_add_cdev(struct idxd_wq *wq);
void idxd_wq_del_cdev(struct idxd_wq *wq);
+int idxd_copy_cr(struct idxd_wq *wq, ioasid_t pasid, unsigned long addr,
+ void *buf, int len);
+void idxd_user_counter_increment(struct idxd_wq *wq, u32 pasid, int index);
/* perfmon */
#if IS_ENABLED(CONFIG_INTEL_IDXD_PERFMON)
@@ -678,4 +739,10 @@ static inline void perfmon_init(void) {}
static inline void perfmon_exit(void) {}
#endif
+/* debugfs */
+int idxd_device_init_debugfs(struct idxd_device *idxd);
+void idxd_device_remove_debugfs(struct idxd_device *idxd);
+int idxd_init_debugfs(void);
+void idxd_remove_debugfs(void);
+
#endif
diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c
index 99985123001b..1aa823974cda 100644
--- a/drivers/dma/idxd/init.c
+++ b/drivers/dma/idxd/init.c
@@ -9,7 +9,6 @@
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/workqueue.h>
-#include <linux/aer.h>
#include <linux/fs.h>
#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/device.h>
@@ -47,6 +46,9 @@ static struct idxd_driver_data idxd_driver_data[] = {
.compl_size = sizeof(struct dsa_completion_record),
.align = 32,
.dev_type = &dsa_device_type,
+ .evl_cr_off = offsetof(struct dsa_evl_entry, cr),
+ .cr_status_off = offsetof(struct dsa_completion_record, status),
+ .cr_result_off = offsetof(struct dsa_completion_record, result),
},
[IDXD_TYPE_IAX] = {
.name_prefix = "iax",
@@ -54,6 +56,9 @@ static struct idxd_driver_data idxd_driver_data[] = {
.compl_size = sizeof(struct iax_completion_record),
.align = 64,
.dev_type = &iax_device_type,
+ .evl_cr_off = offsetof(struct iax_evl_entry, cr),
+ .cr_status_off = offsetof(struct iax_completion_record, status),
+ .cr_result_off = offsetof(struct iax_completion_record, error_code),
},
};
@@ -200,6 +205,8 @@ static int idxd_setup_wqs(struct idxd_device *idxd)
}
bitmap_copy(wq->opcap_bmap, idxd->opcap_bmap, IDXD_MAX_OPCAP_BITS);
}
+ mutex_init(&wq->uc_lock);
+ xa_init(&wq->upasid_xa);
idxd->wqs[i] = wq;
}
@@ -332,6 +339,33 @@ static void idxd_cleanup_internals(struct idxd_device *idxd)
destroy_workqueue(idxd->wq);
}
+static int idxd_init_evl(struct idxd_device *idxd)
+{
+ struct device *dev = &idxd->pdev->dev;
+ struct idxd_evl *evl;
+
+ if (idxd->hw.gen_cap.evl_support == 0)
+ return 0;
+
+ evl = kzalloc_node(sizeof(*evl), GFP_KERNEL, dev_to_node(dev));
+ if (!evl)
+ return -ENOMEM;
+
+ spin_lock_init(&evl->lock);
+ evl->size = IDXD_EVL_SIZE_MIN;
+
+ idxd->evl_cache = kmem_cache_create(dev_name(idxd_confdev(idxd)),
+ sizeof(struct idxd_evl_fault) + evl_ent_size(idxd),
+ 0, 0, NULL);
+ if (!idxd->evl_cache) {
+ kfree(evl);
+ return -ENOMEM;
+ }
+
+ idxd->evl = evl;
+ return 0;
+}
+
static int idxd_setup_internals(struct idxd_device *idxd)
{
struct device *dev = &idxd->pdev->dev;
@@ -357,8 +391,14 @@ static int idxd_setup_internals(struct idxd_device *idxd)
goto err_wkq_create;
}
+ rc = idxd_init_evl(idxd);
+ if (rc < 0)
+ goto err_evl;
+
return 0;
+ err_evl:
+ destroy_workqueue(idxd->wq);
err_wkq_create:
for (i = 0; i < idxd->max_groups; i++)
put_device(group_confdev(idxd->groups[i]));
@@ -389,7 +429,7 @@ static void idxd_read_table_offsets(struct idxd_device *idxd)
dev_dbg(dev, "IDXD Perfmon Offset: %#x\n", idxd->perfmon_offset);
}
-static void multi_u64_to_bmap(unsigned long *bmap, u64 *val, int count)
+void multi_u64_to_bmap(unsigned long *bmap, u64 *val, int count)
{
int i, j, nr;
@@ -461,6 +501,10 @@ static void idxd_read_caps(struct idxd_device *idxd)
dev_dbg(dev, "opcap[%d]: %#llx\n", i, idxd->hw.opcap.bits[i]);
}
multi_u64_to_bmap(idxd->opcap_bmap, &idxd->hw.opcap.bits[0], 4);
+
+ /* read iaa cap */
+ if (idxd->data->type == IDXD_TYPE_IAX && idxd->hw.version >= DEVICE_VERSION_2)
+ idxd->hw.iaa_cap.bits = ioread64(idxd->reg_base + IDXD_IAACAP_OFFSET);
}
static struct idxd_device *idxd_alloc(struct pci_dev *pdev, struct idxd_driver_data *data)
@@ -661,6 +705,10 @@ static int idxd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto err_dev_register;
}
+ rc = idxd_device_init_debugfs(idxd);
+ if (rc)
+ dev_warn(dev, "IDXD debugfs failed to setup\n");
+
dev_info(&pdev->dev, "Intel(R) Accelerator Device (v%x)\n",
idxd->hw.version);
@@ -723,6 +771,7 @@ static void idxd_remove(struct pci_dev *pdev)
idxd_shutdown(pdev);
if (device_pasid_enabled(idxd))
idxd_disable_system_pasid(idxd);
+ idxd_device_remove_debugfs(idxd);
irq_entry = idxd_get_ie(idxd, 0);
free_irq(irq_entry->vector, irq_entry);
@@ -780,6 +829,10 @@ static int __init idxd_init_module(void)
if (err)
goto err_cdev_register;
+ err = idxd_init_debugfs();
+ if (err)
+ goto err_debugfs;
+
err = pci_register_driver(&idxd_pci_driver);
if (err)
goto err_pci_register;
@@ -787,6 +840,8 @@ static int __init idxd_init_module(void)
return 0;
err_pci_register:
+ idxd_remove_debugfs();
+err_debugfs:
idxd_cdev_remove();
err_cdev_register:
idxd_driver_unregister(&idxd_user_drv);
@@ -807,5 +862,6 @@ static void __exit idxd_exit_module(void)
pci_unregister_driver(&idxd_pci_driver);
idxd_cdev_remove();
perfmon_exit();
+ idxd_remove_debugfs();
}
module_exit(idxd_exit_module);
diff --git a/drivers/dma/idxd/irq.c b/drivers/dma/idxd/irq.c
index 242f1f0b9f09..b501320a9c7a 100644
--- a/drivers/dma/idxd/irq.c
+++ b/drivers/dma/idxd/irq.c
@@ -7,6 +7,8 @@
#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/dmaengine.h>
#include <linux/delay.h>
+#include <linux/iommu.h>
+#include <linux/sched/mm.h>
#include <uapi/linux/idxd.h>
#include "../dmaengine.h"
#include "idxd.h"
@@ -217,13 +219,187 @@ static void idxd_int_handle_revoke(struct work_struct *work)
kfree(revoke);
}
-static int process_misc_interrupts(struct idxd_device *idxd, u32 cause)
+static void idxd_evl_fault_work(struct work_struct *work)
{
+ struct idxd_evl_fault *fault = container_of(work, struct idxd_evl_fault, work);
+ struct idxd_wq *wq = fault->wq;
+ struct idxd_device *idxd = wq->idxd;
+ struct device *dev = &idxd->pdev->dev;
+ struct idxd_evl *evl = idxd->evl;
+ struct __evl_entry *entry_head = fault->entry;
+ void *cr = (void *)entry_head + idxd->data->evl_cr_off;
+ int cr_size = idxd->data->compl_size;
+ u8 *status = (u8 *)cr + idxd->data->cr_status_off;
+ u8 *result = (u8 *)cr + idxd->data->cr_result_off;
+ int copied, copy_size;
+ bool *bf;
+
+ switch (fault->status) {
+ case DSA_COMP_CRA_XLAT:
+ if (entry_head->batch && entry_head->first_err_in_batch)
+ evl->batch_fail[entry_head->batch_id] = false;
+
+ copy_size = cr_size;
+ idxd_user_counter_increment(wq, entry_head->pasid, COUNTER_FAULTS);
+ break;
+ case DSA_COMP_BATCH_EVL_ERR:
+ bf = &evl->batch_fail[entry_head->batch_id];
+
+ copy_size = entry_head->rcr || *bf ? cr_size : 0;
+ if (*bf) {
+ if (*status == DSA_COMP_SUCCESS)
+ *status = DSA_COMP_BATCH_FAIL;
+ *result = 1;
+ *bf = false;
+ }
+ idxd_user_counter_increment(wq, entry_head->pasid, COUNTER_FAULTS);
+ break;
+ case DSA_COMP_DRAIN_EVL:
+ copy_size = cr_size;
+ break;
+ default:
+ copy_size = 0;
+ dev_dbg_ratelimited(dev, "Unrecognized error code: %#x\n", fault->status);
+ break;
+ }
+
+ if (copy_size == 0)
+ return;
+
+ /*
+ * Copy completion record to fault_addr in user address space
+ * that is found by wq and PASID.
+ */
+ copied = idxd_copy_cr(wq, entry_head->pasid, entry_head->fault_addr,
+ cr, copy_size);
+ /*
+ * The task that triggered the page fault is unknown currently
+ * because multiple threads may share the user address
+ * space or the task exits already before this fault.
+ * So if the copy fails, SIGSEGV can not be sent to the task.
+ * Just print an error for the failure. The user application
+ * waiting for the completion record will time out on this
+ * failure.
+ */
+ switch (fault->status) {
+ case DSA_COMP_CRA_XLAT:
+ if (copied != copy_size) {
+ idxd_user_counter_increment(wq, entry_head->pasid, COUNTER_FAULT_FAILS);
+ dev_dbg_ratelimited(dev, "Failed to write to completion record: (%d:%d)\n",
+ copy_size, copied);
+ if (entry_head->batch)
+ evl->batch_fail[entry_head->batch_id] = true;
+ }
+ break;
+ case DSA_COMP_BATCH_EVL_ERR:
+ if (copied != copy_size) {
+ idxd_user_counter_increment(wq, entry_head->pasid, COUNTER_FAULT_FAILS);
+ dev_dbg_ratelimited(dev, "Failed to write to batch completion record: (%d:%d)\n",
+ copy_size, copied);
+ }
+ break;
+ case DSA_COMP_DRAIN_EVL:
+ if (copied != copy_size)
+ dev_dbg_ratelimited(dev, "Failed to write to drain completion record: (%d:%d)\n",
+ copy_size, copied);
+ break;
+ }
+
+ kmem_cache_free(idxd->evl_cache, fault);
+}
+
+static void process_evl_entry(struct idxd_device *idxd,
+ struct __evl_entry *entry_head, unsigned int index)
+{
+ struct device *dev = &idxd->pdev->dev;
+ struct idxd_evl *evl = idxd->evl;
+ u8 status;
+
+ if (test_bit(index, evl->bmap)) {
+ clear_bit(index, evl->bmap);
+ } else {
+ status = DSA_COMP_STATUS(entry_head->error);
+
+ if (status == DSA_COMP_CRA_XLAT || status == DSA_COMP_DRAIN_EVL ||
+ status == DSA_COMP_BATCH_EVL_ERR) {
+ struct idxd_evl_fault *fault;
+ int ent_size = evl_ent_size(idxd);
+
+ if (entry_head->rci)
+ dev_dbg(dev, "Completion Int Req set, ignoring!\n");
+
+ if (!entry_head->rcr && status == DSA_COMP_DRAIN_EVL)
+ return;
+
+ fault = kmem_cache_alloc(idxd->evl_cache, GFP_ATOMIC);
+ if (fault) {
+ struct idxd_wq *wq = idxd->wqs[entry_head->wq_idx];
+
+ fault->wq = wq;
+ fault->status = status;
+ memcpy(&fault->entry, entry_head, ent_size);
+ INIT_WORK(&fault->work, idxd_evl_fault_work);
+ queue_work(wq->wq, &fault->work);
+ } else {
+ dev_warn(dev, "Failed to service fault work.\n");
+ }
+ } else {
+ dev_warn_ratelimited(dev, "Device error %#x operation: %#x fault addr: %#llx\n",
+ status, entry_head->operation,
+ entry_head->fault_addr);
+ }
+ }
+}
+
+static void process_evl_entries(struct idxd_device *idxd)
+{
+ union evl_status_reg evl_status;
+ unsigned int h, t;
+ struct idxd_evl *evl = idxd->evl;
+ struct __evl_entry *entry_head;
+ unsigned int ent_size = evl_ent_size(idxd);
+ u32 size;
+
+ evl_status.bits = 0;
+ evl_status.int_pending = 1;
+
+ spin_lock(&evl->lock);
+ /* Clear interrupt pending bit */
+ iowrite32(evl_status.bits_upper32,
+ idxd->reg_base + IDXD_EVLSTATUS_OFFSET + sizeof(u32));
+ h = evl->head;
+ evl_status.bits = ioread64(idxd->reg_base + IDXD_EVLSTATUS_OFFSET);
+ t = evl_status.tail;
+ size = idxd->evl->size;
+
+ while (h != t) {
+ entry_head = (struct __evl_entry *)(evl->log + (h * ent_size));
+ process_evl_entry(idxd, entry_head, h);
+ h = (h + 1) % size;
+ }
+
+ evl->head = h;
+ evl_status.head = h;
+ iowrite32(evl_status.bits_lower32, idxd->reg_base + IDXD_EVLSTATUS_OFFSET);
+ spin_unlock(&evl->lock);
+}
+
+irqreturn_t idxd_misc_thread(int vec, void *data)
+{
+ struct idxd_irq_entry *irq_entry = data;
+ struct idxd_device *idxd = ie_to_idxd(irq_entry);
struct device *dev = &idxd->pdev->dev;
union gensts_reg gensts;
u32 val = 0;
int i;
bool err = false;
+ u32 cause;
+
+ cause = ioread32(idxd->reg_base + IDXD_INTCAUSE_OFFSET);
+ if (!cause)
+ return IRQ_NONE;
+
+ iowrite32(cause, idxd->reg_base + IDXD_INTCAUSE_OFFSET);
if (cause & IDXD_INTC_HALT_STATE)
goto halt;
@@ -295,13 +471,18 @@ static int process_misc_interrupts(struct idxd_device *idxd, u32 cause)
perfmon_counter_overflow(idxd);
}
+ if (cause & IDXD_INTC_EVL) {
+ val |= IDXD_INTC_EVL;
+ process_evl_entries(idxd);
+ }
+
val ^= cause;
if (val)
dev_warn_once(dev, "Unexpected interrupt cause bits set: %#x\n",
val);
if (!err)
- return 0;
+ goto out;
halt:
gensts.bits = ioread32(idxd->reg_base + IDXD_GENSTATS_OFFSET);
@@ -324,33 +505,10 @@ halt:
"idxd halted, need %s.\n",
gensts.reset_type == IDXD_DEVICE_RESET_FLR ?
"FLR" : "system reset");
- return -ENXIO;
}
}
- return 0;
-}
-
-irqreturn_t idxd_misc_thread(int vec, void *data)
-{
- struct idxd_irq_entry *irq_entry = data;
- struct idxd_device *idxd = ie_to_idxd(irq_entry);
- int rc;
- u32 cause;
-
- cause = ioread32(idxd->reg_base + IDXD_INTCAUSE_OFFSET);
- if (cause)
- iowrite32(cause, idxd->reg_base + IDXD_INTCAUSE_OFFSET);
-
- while (cause) {
- rc = process_misc_interrupts(idxd, cause);
- if (rc < 0)
- break;
- cause = ioread32(idxd->reg_base + IDXD_INTCAUSE_OFFSET);
- if (cause)
- iowrite32(cause, idxd->reg_base + IDXD_INTCAUSE_OFFSET);
- }
-
+out:
return IRQ_HANDLED;
}
diff --git a/drivers/dma/idxd/registers.h b/drivers/dma/idxd/registers.h
index fe3b8d04f9db..7b54a3939ea1 100644
--- a/drivers/dma/idxd/registers.h
+++ b/drivers/dma/idxd/registers.h
@@ -3,6 +3,8 @@
#ifndef _IDXD_REGISTERS_H_
#define _IDXD_REGISTERS_H_
+#include <uapi/linux/idxd.h>
+
/* PCI Config */
#define PCI_DEVICE_ID_INTEL_DSA_SPR0 0x0b25
#define PCI_DEVICE_ID_INTEL_IAX_SPR0 0x0cfe
@@ -31,7 +33,9 @@ union gen_cap_reg {
u64 rsvd:3;
u64 dest_readback:1;
u64 drain_readback:1;
- u64 rsvd2:6;
+ u64 rsvd2:3;
+ u64 evl_support:2;
+ u64 batch_continuation:1;
u64 max_xfer_shift:5;
u64 max_batch_shift:4;
u64 max_ims_mult:6;
@@ -55,7 +59,8 @@ union wq_cap_reg {
u64 occupancy:1;
u64 occupancy_int:1;
u64 op_config:1;
- u64 rsvd3:9;
+ u64 wq_prs_support:1;
+ u64 rsvd4:8;
};
u64 bits;
} __packed;
@@ -117,7 +122,8 @@ union gencfg_reg {
u32 rdbuf_limit:8;
u32 rsvd:4;
u32 user_int_en:1;
- u32 rsvd2:19;
+ u32 evl_en:1;
+ u32 rsvd2:18;
};
u32 bits;
} __packed;
@@ -127,7 +133,8 @@ union genctrl_reg {
struct {
u32 softerr_int_en:1;
u32 halt_int_en:1;
- u32 rsvd:30;
+ u32 evl_int_en:1;
+ u32 rsvd:29;
};
u32 bits;
} __packed;
@@ -162,6 +169,7 @@ enum idxd_device_reset_type {
#define IDXD_INTC_OCCUPY 0x04
#define IDXD_INTC_PERFMON_OVFL 0x08
#define IDXD_INTC_HALT_STATE 0x10
+#define IDXD_INTC_EVL 0x20
#define IDXD_INTC_INT_HANDLE_REVOKED 0x80000000
#define IDXD_CMD_OFFSET 0xa0
@@ -276,6 +284,45 @@ union sw_err_reg {
u64 bits[4];
} __packed;
+union iaa_cap_reg {
+ struct {
+ u64 dec_aecs_format_ver:1;
+ u64 drop_init_bits:1;
+ u64 chaining:1;
+ u64 force_array_output_mod:1;
+ u64 load_part_aecs:1;
+ u64 comp_early_abort:1;
+ u64 nested_comp:1;
+ u64 diction_comp:1;
+ u64 header_gen:1;
+ u64 crypto_gcm:1;
+ u64 crypto_cfb:1;
+ u64 crypto_xts:1;
+ u64 rsvd:52;
+ };
+ u64 bits;
+} __packed;
+
+#define IDXD_IAACAP_OFFSET 0x180
+
+#define IDXD_EVLCFG_OFFSET 0xe0
+union evlcfg_reg {
+ struct {
+ u64 pasid_en:1;
+ u64 priv:1;
+ u64 rsvd:10;
+ u64 base_addr:52;
+
+ u64 size:16;
+ u64 pasid:20;
+ u64 rsvd2:28;
+ };
+ u64 bits[2];
+} __packed;
+
+#define IDXD_EVL_SIZE_MIN 0x0040
+#define IDXD_EVL_SIZE_MAX 0xffff
+
union msix_perm {
struct {
u32 rsvd:2;
@@ -325,7 +372,7 @@ union wqcfg {
u32 mode:1; /* shared or dedicated */
u32 bof:1; /* block on fault */
u32 wq_ats_disable:1;
- u32 rsvd2:1;
+ u32 wq_prs_disable:1;
u32 priority:4;
u32 pasid:20;
u32 pasid_en:1;
@@ -513,4 +560,73 @@ union filter_cfg {
u64 val;
} __packed;
+#define IDXD_EVLSTATUS_OFFSET 0xf0
+
+union evl_status_reg {
+ struct {
+ u32 head:16;
+ u32 rsvd:16;
+ u32 tail:16;
+ u32 rsvd2:14;
+ u32 int_pending:1;
+ u32 rsvd3:1;
+ };
+ struct {
+ u32 bits_lower32;
+ u32 bits_upper32;
+ };
+ u64 bits;
+} __packed;
+
+#define IDXD_MAX_BATCH_IDENT 256
+
+struct __evl_entry {
+ u64 rsvd:2;
+ u64 desc_valid:1;
+ u64 wq_idx_valid:1;
+ u64 batch:1;
+ u64 fault_rw:1;
+ u64 priv:1;
+ u64 err_info_valid:1;
+ u64 error:8;
+ u64 wq_idx:8;
+ u64 batch_id:8;
+ u64 operation:8;
+ u64 pasid:20;
+ u64 rsvd2:4;
+
+ u16 batch_idx;
+ u16 rsvd3;
+ union {
+ /* Invalid Flags 0x11 */
+ u32 invalid_flags;
+ /* Invalid Int Handle 0x19 */
+ /* Page fault 0x1a */
+ /* Page fault 0x06, 0x1f, only operand_id */
+ /* Page fault before drain or in batch, 0x26, 0x27 */
+ struct {
+ u16 int_handle;
+ u16 rci:1;
+ u16 ims:1;
+ u16 rcr:1;
+ u16 first_err_in_batch:1;
+ u16 rsvd4_2:9;
+ u16 operand_id:3;
+ };
+ };
+ u64 fault_addr;
+ u64 rsvd5;
+} __packed;
+
+struct dsa_evl_entry {
+ struct __evl_entry e;
+ struct dsa_completion_record cr;
+} __packed;
+
+struct iax_evl_entry {
+ struct __evl_entry e;
+ u64 rsvd[4];
+ struct iax_completion_record cr;
+} __packed;
+
#endif
diff --git a/drivers/dma/idxd/sysfs.c b/drivers/dma/idxd/sysfs.c
index 18cd8151dee0..293739ac5596 100644
--- a/drivers/dma/idxd/sysfs.c
+++ b/drivers/dma/idxd/sysfs.c
@@ -822,10 +822,14 @@ static ssize_t wq_block_on_fault_store(struct device *dev,
if (rc < 0)
return rc;
- if (bof)
+ if (bof) {
+ if (test_bit(WQ_FLAG_PRS_DISABLE, &wq->flags))
+ return -EOPNOTSUPP;
+
set_bit(WQ_FLAG_BLOCK_ON_FAULT, &wq->flags);
- else
+ } else {
clear_bit(WQ_FLAG_BLOCK_ON_FAULT, &wq->flags);
+ }
return count;
}
@@ -1109,6 +1113,44 @@ static ssize_t wq_ats_disable_store(struct device *dev, struct device_attribute
static struct device_attribute dev_attr_wq_ats_disable =
__ATTR(ats_disable, 0644, wq_ats_disable_show, wq_ats_disable_store);
+static ssize_t wq_prs_disable_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct idxd_wq *wq = confdev_to_wq(dev);
+
+ return sysfs_emit(buf, "%u\n", test_bit(WQ_FLAG_PRS_DISABLE, &wq->flags));
+}
+
+static ssize_t wq_prs_disable_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct idxd_wq *wq = confdev_to_wq(dev);
+ struct idxd_device *idxd = wq->idxd;
+ bool prs_dis;
+ int rc;
+
+ if (wq->state != IDXD_WQ_DISABLED)
+ return -EPERM;
+
+ if (!idxd->hw.wq_cap.wq_prs_support)
+ return -EOPNOTSUPP;
+
+ rc = kstrtobool(buf, &prs_dis);
+ if (rc < 0)
+ return rc;
+
+ if (prs_dis) {
+ set_bit(WQ_FLAG_PRS_DISABLE, &wq->flags);
+ /* when PRS is disabled, BOF needs to be off as well */
+ clear_bit(WQ_FLAG_BLOCK_ON_FAULT, &wq->flags);
+ } else {
+ clear_bit(WQ_FLAG_PRS_DISABLE, &wq->flags);
+ }
+ return count;
+}
+
+static struct device_attribute dev_attr_wq_prs_disable =
+ __ATTR(prs_disable, 0644, wq_prs_disable_show, wq_prs_disable_store);
+
static ssize_t wq_occupancy_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct idxd_wq *wq = confdev_to_wq(dev);
@@ -1239,6 +1281,7 @@ static struct attribute *idxd_wq_attributes[] = {
&dev_attr_wq_max_transfer_size.attr,
&dev_attr_wq_max_batch_size.attr,
&dev_attr_wq_ats_disable.attr,
+ &dev_attr_wq_prs_disable.attr,
&dev_attr_wq_occupancy.attr,
&dev_attr_wq_enqcmds_retries.attr,
&dev_attr_wq_op_config.attr,
@@ -1260,6 +1303,13 @@ static bool idxd_wq_attr_max_batch_size_invisible(struct attribute *attr,
idxd->data->type == IDXD_TYPE_IAX;
}
+static bool idxd_wq_attr_wq_prs_disable_invisible(struct attribute *attr,
+ struct idxd_device *idxd)
+{
+ return attr == &dev_attr_wq_prs_disable.attr &&
+ !idxd->hw.wq_cap.wq_prs_support;
+}
+
static umode_t idxd_wq_attr_visible(struct kobject *kobj,
struct attribute *attr, int n)
{
@@ -1273,6 +1323,9 @@ static umode_t idxd_wq_attr_visible(struct kobject *kobj,
if (idxd_wq_attr_max_batch_size_invisible(attr, idxd))
return 0;
+ if (idxd_wq_attr_wq_prs_disable_invisible(attr, idxd))
+ return 0;
+
return attr->mode;
}
@@ -1292,6 +1345,7 @@ static void idxd_conf_wq_release(struct device *dev)
bitmap_free(wq->opcap_bmap);
kfree(wq->wqcfg);
+ xa_destroy(&wq->upasid_xa);
kfree(wq);
}
@@ -1452,15 +1506,13 @@ static ssize_t errors_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct idxd_device *idxd = confdev_to_idxd(dev);
- int i, out = 0;
+ DECLARE_BITMAP(swerr_bmap, 256);
+ bitmap_zero(swerr_bmap, 256);
spin_lock(&idxd->dev_lock);
- for (i = 0; i < 4; i++)
- out += sysfs_emit_at(buf, out, "%#018llx ", idxd->sw_err.bits[i]);
+ multi_u64_to_bmap(swerr_bmap, &idxd->sw_err.bits[0], 4);
spin_unlock(&idxd->dev_lock);
- out--;
- out += sysfs_emit_at(buf, out, "\n");
- return out;
+ return sysfs_emit(buf, "%*pb\n", 256, swerr_bmap);
}
static DEVICE_ATTR_RO(errors);
@@ -1563,6 +1615,59 @@ static ssize_t cmd_status_store(struct device *dev, struct device_attribute *att
}
static DEVICE_ATTR_RW(cmd_status);
+static ssize_t iaa_cap_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct idxd_device *idxd = confdev_to_idxd(dev);
+
+ if (idxd->hw.version < DEVICE_VERSION_2)
+ return -EOPNOTSUPP;
+
+ return sysfs_emit(buf, "%#llx\n", idxd->hw.iaa_cap.bits);
+}
+static DEVICE_ATTR_RO(iaa_cap);
+
+static ssize_t event_log_size_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct idxd_device *idxd = confdev_to_idxd(dev);
+
+ if (!idxd->evl)
+ return -EOPNOTSUPP;
+
+ return sysfs_emit(buf, "%u\n", idxd->evl->size);
+}
+
+static ssize_t event_log_size_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct idxd_device *idxd = confdev_to_idxd(dev);
+ unsigned long val;
+ int rc;
+
+ if (!idxd->evl)
+ return -EOPNOTSUPP;
+
+ rc = kstrtoul(buf, 10, &val);
+ if (rc < 0)
+ return -EINVAL;
+
+ if (idxd->state == IDXD_DEV_ENABLED)
+ return -EPERM;
+
+ if (!test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags))
+ return -EPERM;
+
+ if (val < IDXD_EVL_SIZE_MIN || val > IDXD_EVL_SIZE_MAX ||
+ (val * evl_ent_size(idxd) > ULONG_MAX - idxd->evl->dma))
+ return -EINVAL;
+
+ idxd->evl->size = val;
+ return count;
+}
+static DEVICE_ATTR_RW(event_log_size);
+
static bool idxd_device_attr_max_batch_size_invisible(struct attribute *attr,
struct idxd_device *idxd)
{
@@ -1585,6 +1690,21 @@ static bool idxd_device_attr_read_buffers_invisible(struct attribute *attr,
idxd->data->type == IDXD_TYPE_IAX;
}
+static bool idxd_device_attr_iaa_cap_invisible(struct attribute *attr,
+ struct idxd_device *idxd)
+{
+ return attr == &dev_attr_iaa_cap.attr &&
+ (idxd->data->type != IDXD_TYPE_IAX ||
+ idxd->hw.version < DEVICE_VERSION_2);
+}
+
+static bool idxd_device_attr_event_log_size_invisible(struct attribute *attr,
+ struct idxd_device *idxd)
+{
+ return (attr == &dev_attr_event_log_size.attr &&
+ !idxd->hw.gen_cap.evl_support);
+}
+
static umode_t idxd_device_attr_visible(struct kobject *kobj,
struct attribute *attr, int n)
{
@@ -1597,6 +1717,12 @@ static umode_t idxd_device_attr_visible(struct kobject *kobj,
if (idxd_device_attr_read_buffers_invisible(attr, idxd))
return 0;
+ if (idxd_device_attr_iaa_cap_invisible(attr, idxd))
+ return 0;
+
+ if (idxd_device_attr_event_log_size_invisible(attr, idxd))
+ return 0;
+
return attr->mode;
}
@@ -1622,6 +1748,8 @@ static struct attribute *idxd_device_attributes[] = {
&dev_attr_read_buffer_limit.attr,
&dev_attr_cdev_major.attr,
&dev_attr_cmd_status.attr,
+ &dev_attr_iaa_cap.attr,
+ &dev_attr_event_log_size.attr,
NULL,
};
@@ -1643,6 +1771,8 @@ static void idxd_conf_device_release(struct device *dev)
bitmap_free(idxd->wq_enable_map);
kfree(idxd->wqs);
kfree(idxd->engines);
+ kfree(idxd->evl);
+ kmem_cache_destroy(idxd->evl_cache);
ida_free(&idxd_ida, idxd->id);
bitmap_free(idxd->opcap_bmap);
kfree(idxd);
diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c
index 80086977973f..f040751690af 100644
--- a/drivers/dma/imx-dma.c
+++ b/drivers/dma/imx-dma.c
@@ -750,7 +750,6 @@ static int imxdma_alloc_chan_resources(struct dma_chan *chan)
desc = kzalloc(sizeof(*desc), GFP_KERNEL);
if (!desc)
break;
- memset(&desc->desc, 0, sizeof(struct dma_async_tx_descriptor));
dma_async_tx_descriptor_init(&desc->desc, chan);
desc->desc.tx_submit = imxdma_tx_submit;
/* txd.flags will be overwritten in prep funcs */
diff --git a/drivers/dma/ioat/init.c b/drivers/dma/ioat/init.c
index 5d707ff63554..c4602bfc9c74 100644
--- a/drivers/dma/ioat/init.c
+++ b/drivers/dma/ioat/init.c
@@ -15,7 +15,6 @@
#include <linux/workqueue.h>
#include <linux/prefetch.h>
#include <linux/dca.h>
-#include <linux/aer.h>
#include <linux/sizes.h>
#include "dma.h"
#include "registers.h"
@@ -1191,13 +1190,13 @@ static int ioat3_dma_probe(struct ioatdma_device *ioat_dma, int dca)
ioat_dma->dca = ioat_dca_init(pdev, ioat_dma->reg_base);
/* disable relaxed ordering */
- err = pcie_capability_read_word(pdev, IOAT_DEVCTRL_OFFSET, &val16);
+ err = pcie_capability_read_word(pdev, PCI_EXP_DEVCTL, &val16);
if (err)
return pcibios_err_to_errno(err);
/* clear relaxed ordering enable */
- val16 &= ~IOAT_DEVCTRL_ROE;
- err = pcie_capability_write_word(pdev, IOAT_DEVCTRL_OFFSET, val16);
+ val16 &= ~PCI_EXP_DEVCTL_RELAX_EN;
+ err = pcie_capability_write_word(pdev, PCI_EXP_DEVCTL, val16);
if (err)
return pcibios_err_to_errno(err);
@@ -1380,15 +1379,11 @@ static int ioat_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (is_skx_ioat(pdev))
device->version = IOAT_VER_3_2;
err = ioat3_dma_probe(device, ioat_dca_enabled);
-
- if (device->version >= IOAT_VER_3_3)
- pci_enable_pcie_error_reporting(pdev);
} else
return -ENODEV;
if (err) {
dev_err(dev, "Intel(R) I/OAT DMA Engine init failed\n");
- pci_disable_pcie_error_reporting(pdev);
return -ENODEV;
}
@@ -1411,7 +1406,6 @@ static void ioat_remove(struct pci_dev *pdev)
device->dca = NULL;
}
- pci_disable_pcie_error_reporting(pdev);
ioat_dma_remove(device);
}
diff --git a/drivers/dma/ioat/registers.h b/drivers/dma/ioat/registers.h
index f55a5f92f185..54cf0ad39887 100644
--- a/drivers/dma/ioat/registers.h
+++ b/drivers/dma/ioat/registers.h
@@ -14,13 +14,6 @@
#define IOAT_PCI_CHANERR_INT_OFFSET 0x180
#define IOAT_PCI_CHANERRMASK_INT_OFFSET 0x184
-/* PCIe config registers */
-
-/* EXPCAPID + N */
-#define IOAT_DEVCTRL_OFFSET 0x8
-/* relaxed ordering enable */
-#define IOAT_DEVCTRL_ROE 0x10
-
/* MMIO Device Registers */
#define IOAT_CHANCNT_OFFSET 0x00 /* 8-bit */
diff --git a/drivers/dma/mv_xor_v2.c b/drivers/dma/mv_xor_v2.c
index b4de7d4a3105..0e1e9ca1c005 100644
--- a/drivers/dma/mv_xor_v2.c
+++ b/drivers/dma/mv_xor_v2.c
@@ -739,32 +739,18 @@ static int mv_xor_v2_probe(struct platform_device *pdev)
if (ret)
return ret;
- xor_dev->reg_clk = devm_clk_get(&pdev->dev, "reg");
- if (PTR_ERR(xor_dev->reg_clk) != -ENOENT) {
- if (!IS_ERR(xor_dev->reg_clk)) {
- ret = clk_prepare_enable(xor_dev->reg_clk);
- if (ret)
- return ret;
- } else {
- return PTR_ERR(xor_dev->reg_clk);
- }
- }
+ xor_dev->reg_clk = devm_clk_get_optional_enabled(&pdev->dev, "reg");
+ if (IS_ERR(xor_dev->reg_clk))
+ return PTR_ERR(xor_dev->reg_clk);
- xor_dev->clk = devm_clk_get(&pdev->dev, NULL);
- if (PTR_ERR(xor_dev->clk) == -EPROBE_DEFER) {
- ret = EPROBE_DEFER;
- goto disable_reg_clk;
- }
- if (!IS_ERR(xor_dev->clk)) {
- ret = clk_prepare_enable(xor_dev->clk);
- if (ret)
- goto disable_reg_clk;
- }
+ xor_dev->clk = devm_clk_get_enabled(&pdev->dev, NULL);
+ if (IS_ERR(xor_dev->clk))
+ return PTR_ERR(xor_dev->clk);
ret = platform_msi_domain_alloc_irqs(&pdev->dev, 1,
mv_xor_v2_set_msi_msg);
if (ret)
- goto disable_clk;
+ return ret;
xor_dev->irq = msi_get_virq(&pdev->dev, 0);
@@ -866,10 +852,6 @@ free_hw_desq:
xor_dev->hw_desq_virt, xor_dev->hw_desq);
free_msi_irqs:
platform_msi_domain_free_irqs(&pdev->dev);
-disable_clk:
- clk_disable_unprepare(xor_dev->clk);
-disable_reg_clk:
- clk_disable_unprepare(xor_dev->reg_clk);
return ret;
}
@@ -889,9 +871,6 @@ static int mv_xor_v2_remove(struct platform_device *pdev)
tasklet_kill(&xor_dev->irq_tasklet);
- clk_disable_unprepare(xor_dev->clk);
- clk_disable_unprepare(xor_dev->reg_clk);
-
return 0;
}
diff --git a/drivers/dma/of-dma.c b/drivers/dma/of-dma.c
index ac61ecda2926..775a7f408b9a 100644
--- a/drivers/dma/of-dma.c
+++ b/drivers/dma/of-dma.c
@@ -264,7 +264,7 @@ struct dma_chan *of_dma_request_slave_channel(struct device_node *np,
}
/* Silently fail if there is not even the "dmas" property */
- if (!of_find_property(np, "dmas", NULL))
+ if (!of_property_present(np, "dmas"))
return ERR_PTR(-ENODEV);
count = of_property_count_strings(np, "dma-names");
diff --git a/drivers/dma/qcom/gpi.c b/drivers/dma/qcom/gpi.c
index 59a36cbf9b5f..932628b319c8 100644
--- a/drivers/dma/qcom/gpi.c
+++ b/drivers/dma/qcom/gpi.c
@@ -1966,7 +1966,6 @@ error_alloc_ev_ring:
error_config_int:
gpi_free_ring(&gpii->ev_ring, gpii);
exit_gpi_init:
- mutex_unlock(&gpii->ctrl_lock);
return ret;
}
diff --git a/drivers/dma/qcom/hidma_mgmt.c b/drivers/dma/qcom/hidma_mgmt.c
index 62026607f3f8..05e96b31d871 100644
--- a/drivers/dma/qcom/hidma_mgmt.c
+++ b/drivers/dma/qcom/hidma_mgmt.c
@@ -12,6 +12,8 @@
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
diff --git a/drivers/dma/sh/rz-dmac.c b/drivers/dma/sh/rz-dmac.c
index 476847a4916b..9479f29692d3 100644
--- a/drivers/dma/sh/rz-dmac.c
+++ b/drivers/dma/sh/rz-dmac.c
@@ -20,6 +20,7 @@
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/reset.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
@@ -66,8 +67,6 @@ struct rz_dmac_chan {
struct rz_dmac_desc *desc;
int descs_allocated;
- enum dma_slave_buswidth src_word_size;
- enum dma_slave_buswidth dst_word_size;
dma_addr_t src_per_address;
dma_addr_t dst_per_address;
@@ -92,6 +91,7 @@ struct rz_dmac_chan {
struct rz_dmac {
struct dma_device engine;
struct device *dev;
+ struct reset_control *rstc;
void __iomem *base;
void __iomem *ext_base;
@@ -601,9 +601,7 @@ static int rz_dmac_config(struct dma_chan *chan,
u32 val;
channel->src_per_address = config->src_addr;
- channel->src_word_size = config->src_addr_width;
channel->dst_per_address = config->dst_addr;
- channel->dst_word_size = config->dst_addr_width;
val = rz_dmac_ds_to_val_mapping(config->dst_addr_width);
if (val == CHCFG_DS_INVALID)
@@ -889,6 +887,11 @@ static int rz_dmac_probe(struct platform_device *pdev)
/* Initialize the channels. */
INIT_LIST_HEAD(&dmac->engine.channels);
+ dmac->rstc = devm_reset_control_array_get_exclusive(&pdev->dev);
+ if (IS_ERR(dmac->rstc))
+ return dev_err_probe(&pdev->dev, PTR_ERR(dmac->rstc),
+ "failed to get resets\n");
+
pm_runtime_enable(&pdev->dev);
ret = pm_runtime_resume_and_get(&pdev->dev);
if (ret < 0) {
@@ -896,6 +899,10 @@ static int rz_dmac_probe(struct platform_device *pdev)
goto err_pm_disable;
}
+ ret = reset_control_deassert(dmac->rstc);
+ if (ret)
+ goto err_pm_runtime_put;
+
for (i = 0; i < dmac->n_channels; i++) {
ret = rz_dmac_chan_probe(dmac, &dmac->channels[i], i);
if (ret < 0)
@@ -940,6 +947,7 @@ static int rz_dmac_probe(struct platform_device *pdev)
dma_register_err:
of_dma_controller_free(pdev->dev.of_node);
err:
+ reset_control_assert(dmac->rstc);
channel_num = i ? i - 1 : 0;
for (i = 0; i < channel_num; i++) {
struct rz_dmac_chan *channel = &dmac->channels[i];
@@ -950,6 +958,7 @@ err:
channel->lmdesc.base_dma);
}
+err_pm_runtime_put:
pm_runtime_put(&pdev->dev);
err_pm_disable:
pm_runtime_disable(&pdev->dev);
@@ -972,6 +981,7 @@ static int rz_dmac_remove(struct platform_device *pdev)
}
of_dma_controller_free(pdev->dev.of_node);
dma_async_device_unregister(&dmac->engine);
+ reset_control_assert(dmac->rstc);
pm_runtime_put(&pdev->dev);
pm_runtime_disable(&pdev->dev);
diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c
index eaafcbe4ca94..cc6b91f48979 100644
--- a/drivers/dma/tegra20-apb-dma.c
+++ b/drivers/dma/tegra20-apb-dma.c
@@ -233,11 +233,6 @@ static inline void tdma_write(struct tegra_dma *tdma, u32 reg, u32 val)
writel(val, tdma->base_addr + reg);
}
-static inline u32 tdma_read(struct tegra_dma *tdma, u32 reg)
-{
- return readl(tdma->base_addr + reg);
-}
-
static inline void tdc_write(struct tegra_dma_channel *tdc,
u32 reg, u32 val)
{
diff --git a/drivers/dma/ti/Makefile b/drivers/dma/ti/Makefile
index bd1e07fda559..acc950bf609c 100644
--- a/drivers/dma/ti/Makefile
+++ b/drivers/dma/ti/Makefile
@@ -11,6 +11,7 @@ k3-psil-lib-objs := k3-psil.o \
k3-psil-am64.o \
k3-psil-j721s2.o \
k3-psil-am62.o \
- k3-psil-am62a.o
+ k3-psil-am62a.o \
+ k3-psil-j784s4.o
obj-$(CONFIG_TI_K3_PSIL) += k3-psil-lib.o
obj-$(CONFIG_TI_DMA_CROSSBAR) += dma-crossbar.o
diff --git a/drivers/dma/ti/edma.c b/drivers/dma/ti/edma.c
index fa06d7e6d8e3..9ea91c640c32 100644
--- a/drivers/dma/ti/edma.c
+++ b/drivers/dma/ti/edma.c
@@ -318,14 +318,6 @@ static inline void edma_modify(struct edma_cc *ecc, int offset, unsigned and,
edma_write(ecc, offset, val);
}
-static inline void edma_and(struct edma_cc *ecc, int offset, unsigned and)
-{
- unsigned val = edma_read(ecc, offset);
-
- val &= and;
- edma_write(ecc, offset, val);
-}
-
static inline void edma_or(struct edma_cc *ecc, int offset, unsigned or)
{
unsigned val = edma_read(ecc, offset);
diff --git a/drivers/dma/ti/k3-psil-j784s4.c b/drivers/dma/ti/k3-psil-j784s4.c
new file mode 100644
index 000000000000..12bfa2478f92
--- /dev/null
+++ b/drivers/dma/ti/k3-psil-j784s4.c
@@ -0,0 +1,354 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 Texas Instruments Incorporated - https://www.ti.com
+ */
+
+#include <linux/kernel.h>
+
+#include "k3-psil-priv.h"
+
+#define PSIL_PDMA_XY_TR(x) \
+ { \
+ .thread_id = x, \
+ .ep_config = { \
+ .ep_type = PSIL_EP_PDMA_XY, \
+ }, \
+ }
+
+#define PSIL_PDMA_XY_PKT(x) \
+ { \
+ .thread_id = x, \
+ .ep_config = { \
+ .ep_type = PSIL_EP_PDMA_XY, \
+ .pkt_mode = 1, \
+ }, \
+ }
+
+#define PSIL_PDMA_MCASP(x) \
+ { \
+ .thread_id = x, \
+ .ep_config = { \
+ .ep_type = PSIL_EP_PDMA_XY, \
+ .pdma_acc32 = 1, \
+ .pdma_burst = 1, \
+ }, \
+ }
+
+#define PSIL_ETHERNET(x) \
+ { \
+ .thread_id = x, \
+ .ep_config = { \
+ .ep_type = PSIL_EP_NATIVE, \
+ .pkt_mode = 1, \
+ .needs_epib = 1, \
+ .psd_size = 16, \
+ }, \
+ }
+
+#define PSIL_SA2UL(x, tx) \
+ { \
+ .thread_id = x, \
+ .ep_config = { \
+ .ep_type = PSIL_EP_NATIVE, \
+ .pkt_mode = 1, \
+ .needs_epib = 1, \
+ .psd_size = 64, \
+ .notdpkt = tx, \
+ }, \
+ }
+
+#define PSIL_CSI2RX(x) \
+ { \
+ .thread_id = x, \
+ .ep_config = { \
+ .ep_type = PSIL_EP_NATIVE, \
+ }, \
+ }
+
+/* PSI-L source thread IDs, used for RX (DMA_DEV_TO_MEM) */
+static struct psil_ep j784s4_src_ep_map[] = {
+ /* PDMA_MCASP - McASP0-4 */
+ PSIL_PDMA_MCASP(0x4400),
+ PSIL_PDMA_MCASP(0x4401),
+ PSIL_PDMA_MCASP(0x4402),
+ PSIL_PDMA_MCASP(0x4403),
+ PSIL_PDMA_MCASP(0x4404),
+ /* PDMA_SPI_G0 - SPI0-3 */
+ PSIL_PDMA_XY_PKT(0x4600),
+ PSIL_PDMA_XY_PKT(0x4601),
+ PSIL_PDMA_XY_PKT(0x4602),
+ PSIL_PDMA_XY_PKT(0x4603),
+ PSIL_PDMA_XY_PKT(0x4604),
+ PSIL_PDMA_XY_PKT(0x4605),
+ PSIL_PDMA_XY_PKT(0x4606),
+ PSIL_PDMA_XY_PKT(0x4607),
+ PSIL_PDMA_XY_PKT(0x4608),
+ PSIL_PDMA_XY_PKT(0x4609),
+ PSIL_PDMA_XY_PKT(0x460a),
+ PSIL_PDMA_XY_PKT(0x460b),
+ PSIL_PDMA_XY_PKT(0x460c),
+ PSIL_PDMA_XY_PKT(0x460d),
+ PSIL_PDMA_XY_PKT(0x460e),
+ PSIL_PDMA_XY_PKT(0x460f),
+ /* PDMA_SPI_G1 - SPI4-7 */
+ PSIL_PDMA_XY_PKT(0x4620),
+ PSIL_PDMA_XY_PKT(0x4621),
+ PSIL_PDMA_XY_PKT(0x4622),
+ PSIL_PDMA_XY_PKT(0x4623),
+ PSIL_PDMA_XY_PKT(0x4624),
+ PSIL_PDMA_XY_PKT(0x4625),
+ PSIL_PDMA_XY_PKT(0x4626),
+ PSIL_PDMA_XY_PKT(0x4627),
+ PSIL_PDMA_XY_PKT(0x4628),
+ PSIL_PDMA_XY_PKT(0x4629),
+ PSIL_PDMA_XY_PKT(0x462a),
+ PSIL_PDMA_XY_PKT(0x462b),
+ PSIL_PDMA_XY_PKT(0x462c),
+ PSIL_PDMA_XY_PKT(0x462d),
+ PSIL_PDMA_XY_PKT(0x462e),
+ PSIL_PDMA_XY_PKT(0x462f),
+ /* MAIN_CPSW2G */
+ PSIL_ETHERNET(0x4640),
+ /* PDMA_USART_G0 - UART0-1 */
+ PSIL_PDMA_XY_PKT(0x4700),
+ PSIL_PDMA_XY_PKT(0x4701),
+ /* PDMA_USART_G1 - UART2-3 */
+ PSIL_PDMA_XY_PKT(0x4702),
+ PSIL_PDMA_XY_PKT(0x4703),
+ /* PDMA_USART_G2 - UART4-9 */
+ PSIL_PDMA_XY_PKT(0x4704),
+ PSIL_PDMA_XY_PKT(0x4705),
+ PSIL_PDMA_XY_PKT(0x4706),
+ PSIL_PDMA_XY_PKT(0x4707),
+ PSIL_PDMA_XY_PKT(0x4708),
+ PSIL_PDMA_XY_PKT(0x4709),
+ /* CSI2RX */
+ PSIL_CSI2RX(0x4900),
+ PSIL_CSI2RX(0x4901),
+ PSIL_CSI2RX(0x4902),
+ PSIL_CSI2RX(0x4903),
+ PSIL_CSI2RX(0x4940),
+ PSIL_CSI2RX(0x4941),
+ PSIL_CSI2RX(0x4942),
+ PSIL_CSI2RX(0x4943),
+ PSIL_CSI2RX(0x4944),
+ PSIL_CSI2RX(0x4945),
+ PSIL_CSI2RX(0x4946),
+ PSIL_CSI2RX(0x4947),
+ PSIL_CSI2RX(0x4948),
+ PSIL_CSI2RX(0x4949),
+ PSIL_CSI2RX(0x494a),
+ PSIL_CSI2RX(0x494b),
+ PSIL_CSI2RX(0x494c),
+ PSIL_CSI2RX(0x494d),
+ PSIL_CSI2RX(0x494e),
+ PSIL_CSI2RX(0x494f),
+ PSIL_CSI2RX(0x4950),
+ PSIL_CSI2RX(0x4951),
+ PSIL_CSI2RX(0x4952),
+ PSIL_CSI2RX(0x4953),
+ PSIL_CSI2RX(0x4954),
+ PSIL_CSI2RX(0x4955),
+ PSIL_CSI2RX(0x4956),
+ PSIL_CSI2RX(0x4957),
+ PSIL_CSI2RX(0x4958),
+ PSIL_CSI2RX(0x4959),
+ PSIL_CSI2RX(0x495a),
+ PSIL_CSI2RX(0x495b),
+ PSIL_CSI2RX(0x495c),
+ PSIL_CSI2RX(0x495d),
+ PSIL_CSI2RX(0x495e),
+ PSIL_CSI2RX(0x495f),
+ PSIL_CSI2RX(0x4960),
+ PSIL_CSI2RX(0x4961),
+ PSIL_CSI2RX(0x4962),
+ PSIL_CSI2RX(0x4963),
+ PSIL_CSI2RX(0x4964),
+ PSIL_CSI2RX(0x4965),
+ PSIL_CSI2RX(0x4966),
+ PSIL_CSI2RX(0x4967),
+ PSIL_CSI2RX(0x4968),
+ PSIL_CSI2RX(0x4969),
+ PSIL_CSI2RX(0x496a),
+ PSIL_CSI2RX(0x496b),
+ PSIL_CSI2RX(0x496c),
+ PSIL_CSI2RX(0x496d),
+ PSIL_CSI2RX(0x496e),
+ PSIL_CSI2RX(0x496f),
+ PSIL_CSI2RX(0x4970),
+ PSIL_CSI2RX(0x4971),
+ PSIL_CSI2RX(0x4972),
+ PSIL_CSI2RX(0x4973),
+ PSIL_CSI2RX(0x4974),
+ PSIL_CSI2RX(0x4975),
+ PSIL_CSI2RX(0x4976),
+ PSIL_CSI2RX(0x4977),
+ PSIL_CSI2RX(0x4978),
+ PSIL_CSI2RX(0x4979),
+ PSIL_CSI2RX(0x497a),
+ PSIL_CSI2RX(0x497b),
+ PSIL_CSI2RX(0x497c),
+ PSIL_CSI2RX(0x497d),
+ PSIL_CSI2RX(0x497e),
+ PSIL_CSI2RX(0x497f),
+ PSIL_CSI2RX(0x4980),
+ PSIL_CSI2RX(0x4981),
+ PSIL_CSI2RX(0x4982),
+ PSIL_CSI2RX(0x4983),
+ PSIL_CSI2RX(0x4984),
+ PSIL_CSI2RX(0x4985),
+ PSIL_CSI2RX(0x4986),
+ PSIL_CSI2RX(0x4987),
+ PSIL_CSI2RX(0x4988),
+ PSIL_CSI2RX(0x4989),
+ PSIL_CSI2RX(0x498a),
+ PSIL_CSI2RX(0x498b),
+ PSIL_CSI2RX(0x498c),
+ PSIL_CSI2RX(0x498d),
+ PSIL_CSI2RX(0x498e),
+ PSIL_CSI2RX(0x498f),
+ PSIL_CSI2RX(0x4990),
+ PSIL_CSI2RX(0x4991),
+ PSIL_CSI2RX(0x4992),
+ PSIL_CSI2RX(0x4993),
+ PSIL_CSI2RX(0x4994),
+ PSIL_CSI2RX(0x4995),
+ PSIL_CSI2RX(0x4996),
+ PSIL_CSI2RX(0x4997),
+ PSIL_CSI2RX(0x4998),
+ PSIL_CSI2RX(0x4999),
+ PSIL_CSI2RX(0x499a),
+ PSIL_CSI2RX(0x499b),
+ PSIL_CSI2RX(0x499c),
+ PSIL_CSI2RX(0x499d),
+ PSIL_CSI2RX(0x499e),
+ PSIL_CSI2RX(0x499f),
+ /* MAIN_CPSW9G */
+ PSIL_ETHERNET(0x4a00),
+ /* MAIN-SA2UL */
+ PSIL_SA2UL(0x4a40, 0),
+ PSIL_SA2UL(0x4a41, 0),
+ PSIL_SA2UL(0x4a42, 0),
+ PSIL_SA2UL(0x4a43, 0),
+ /* MCU_CPSW0 */
+ PSIL_ETHERNET(0x7000),
+ /* MCU_PDMA0 (MCU_PDMA_MISC_G0) - SPI0 */
+ PSIL_PDMA_XY_PKT(0x7100),
+ PSIL_PDMA_XY_PKT(0x7101),
+ PSIL_PDMA_XY_PKT(0x7102),
+ PSIL_PDMA_XY_PKT(0x7103),
+ /* MCU_PDMA1 (MCU_PDMA_MISC_G1) - SPI1-2 */
+ PSIL_PDMA_XY_PKT(0x7200),
+ PSIL_PDMA_XY_PKT(0x7201),
+ PSIL_PDMA_XY_PKT(0x7202),
+ PSIL_PDMA_XY_PKT(0x7203),
+ PSIL_PDMA_XY_PKT(0x7204),
+ PSIL_PDMA_XY_PKT(0x7205),
+ PSIL_PDMA_XY_PKT(0x7206),
+ PSIL_PDMA_XY_PKT(0x7207),
+ /* MCU_PDMA2 (MCU_PDMA_MISC_G2) - UART0 */
+ PSIL_PDMA_XY_PKT(0x7300),
+ /* MCU_PDMA_ADC - ADC0-1 */
+ PSIL_PDMA_XY_TR(0x7400),
+ PSIL_PDMA_XY_TR(0x7401),
+ PSIL_PDMA_XY_TR(0x7402),
+ PSIL_PDMA_XY_TR(0x7403),
+ /* MCU_SA2UL */
+ PSIL_SA2UL(0x7500, 0),
+ PSIL_SA2UL(0x7501, 0),
+ PSIL_SA2UL(0x7502, 0),
+ PSIL_SA2UL(0x7503, 0),
+};
+
+/* PSI-L destination thread IDs, used for TX (DMA_MEM_TO_DEV) */
+static struct psil_ep j784s4_dst_ep_map[] = {
+ /* MAIN_CPSW2G */
+ PSIL_ETHERNET(0xc640),
+ PSIL_ETHERNET(0xc641),
+ PSIL_ETHERNET(0xc642),
+ PSIL_ETHERNET(0xc643),
+ PSIL_ETHERNET(0xc644),
+ PSIL_ETHERNET(0xc645),
+ PSIL_ETHERNET(0xc646),
+ PSIL_ETHERNET(0xc647),
+ /* MAIN_CPSW9G */
+ PSIL_ETHERNET(0xca00),
+ PSIL_ETHERNET(0xca01),
+ PSIL_ETHERNET(0xca02),
+ PSIL_ETHERNET(0xca03),
+ PSIL_ETHERNET(0xca04),
+ PSIL_ETHERNET(0xca05),
+ PSIL_ETHERNET(0xca06),
+ PSIL_ETHERNET(0xca07),
+ /* MAIN-SA2UL */
+ PSIL_SA2UL(0xca40, 1),
+ PSIL_SA2UL(0xca41, 1),
+ /* PDMA_SPI_G0 - SPI0-3 */
+ PSIL_PDMA_XY_PKT(0xc600),
+ PSIL_PDMA_XY_PKT(0xc601),
+ PSIL_PDMA_XY_PKT(0xc602),
+ PSIL_PDMA_XY_PKT(0xc603),
+ PSIL_PDMA_XY_PKT(0xc604),
+ PSIL_PDMA_XY_PKT(0xc605),
+ PSIL_PDMA_XY_PKT(0xc606),
+ PSIL_PDMA_XY_PKT(0xc607),
+ PSIL_PDMA_XY_PKT(0xc608),
+ PSIL_PDMA_XY_PKT(0xc609),
+ PSIL_PDMA_XY_PKT(0xc60a),
+ PSIL_PDMA_XY_PKT(0xc60b),
+ PSIL_PDMA_XY_PKT(0xc60c),
+ PSIL_PDMA_XY_PKT(0xc60d),
+ PSIL_PDMA_XY_PKT(0xc60e),
+ PSIL_PDMA_XY_PKT(0xc60f),
+ /* PDMA_SPI_G1 - SPI4-7 */
+ PSIL_PDMA_XY_PKT(0xc620),
+ PSIL_PDMA_XY_PKT(0xc621),
+ PSIL_PDMA_XY_PKT(0xc622),
+ PSIL_PDMA_XY_PKT(0xc623),
+ PSIL_PDMA_XY_PKT(0xc624),
+ PSIL_PDMA_XY_PKT(0xc625),
+ PSIL_PDMA_XY_PKT(0xc626),
+ PSIL_PDMA_XY_PKT(0xc627),
+ PSIL_PDMA_XY_PKT(0xc628),
+ PSIL_PDMA_XY_PKT(0xc629),
+ PSIL_PDMA_XY_PKT(0xc62a),
+ PSIL_PDMA_XY_PKT(0xc62b),
+ PSIL_PDMA_XY_PKT(0xc62c),
+ PSIL_PDMA_XY_PKT(0xc62d),
+ PSIL_PDMA_XY_PKT(0xc62e),
+ PSIL_PDMA_XY_PKT(0xc62f),
+ /* MCU_CPSW0 */
+ PSIL_ETHERNET(0xf000),
+ PSIL_ETHERNET(0xf001),
+ PSIL_ETHERNET(0xf002),
+ PSIL_ETHERNET(0xf003),
+ PSIL_ETHERNET(0xf004),
+ PSIL_ETHERNET(0xf005),
+ PSIL_ETHERNET(0xf006),
+ PSIL_ETHERNET(0xf007),
+ /* MCU_PDMA_MISC_G0 - SPI0 */
+ PSIL_PDMA_XY_PKT(0xf100),
+ PSIL_PDMA_XY_PKT(0xf101),
+ PSIL_PDMA_XY_PKT(0xf102),
+ PSIL_PDMA_XY_PKT(0xf103),
+ /* MCU_PDMA_MISC_G1 - SPI1-2 */
+ PSIL_PDMA_XY_PKT(0xf200),
+ PSIL_PDMA_XY_PKT(0xf201),
+ PSIL_PDMA_XY_PKT(0xf202),
+ PSIL_PDMA_XY_PKT(0xf203),
+ PSIL_PDMA_XY_PKT(0xf204),
+ PSIL_PDMA_XY_PKT(0xf205),
+ PSIL_PDMA_XY_PKT(0xf206),
+ PSIL_PDMA_XY_PKT(0xf207),
+ /* MCU_SA2UL */
+ PSIL_SA2UL(0xf500, 1),
+ PSIL_SA2UL(0xf501, 1),
+};
+
+struct psil_ep_map j784s4_ep_map = {
+ .name = "j784s4",
+ .src = j784s4_src_ep_map,
+ .src_count = ARRAY_SIZE(j784s4_src_ep_map),
+ .dst = j784s4_dst_ep_map,
+ .dst_count = ARRAY_SIZE(j784s4_dst_ep_map),
+};
diff --git a/drivers/dma/ti/k3-psil-priv.h b/drivers/dma/ti/k3-psil-priv.h
index abd650bb7600..c383723d1c8f 100644
--- a/drivers/dma/ti/k3-psil-priv.h
+++ b/drivers/dma/ti/k3-psil-priv.h
@@ -44,5 +44,6 @@ extern struct psil_ep_map am64_ep_map;
extern struct psil_ep_map j721s2_ep_map;
extern struct psil_ep_map am62_ep_map;
extern struct psil_ep_map am62a_ep_map;
+extern struct psil_ep_map j784s4_ep_map;
#endif /* K3_PSIL_PRIV_H_ */
diff --git a/drivers/dma/ti/k3-psil.c b/drivers/dma/ti/k3-psil.c
index 2da6988a0e7b..c11389d67a3f 100644
--- a/drivers/dma/ti/k3-psil.c
+++ b/drivers/dma/ti/k3-psil.c
@@ -25,6 +25,7 @@ static const struct soc_device_attribute k3_soc_devices[] = {
{ .family = "J721S2", .data = &j721s2_ep_map },
{ .family = "AM62X", .data = &am62_ep_map },
{ .family = "AM62AX", .data = &am62a_ep_map },
+ { .family = "J784S4", .data = &j784s4_ep_map },
{ /* sentinel */ }
};
diff --git a/drivers/dma/ti/k3-udma.c b/drivers/dma/ti/k3-udma.c
index 7e23a6fdef95..fc3a2a05ab7b 100644
--- a/drivers/dma/ti/k3-udma.c
+++ b/drivers/dma/ti/k3-udma.c
@@ -305,6 +305,8 @@ struct udma_chan {
/* Channel configuration parameters */
struct udma_chan_config config;
+ /* Channel configuration parameters (backup) */
+ struct udma_chan_config backup_config;
/* dmapool for packet mode descriptors */
bool use_dma_pool;
@@ -2964,6 +2966,7 @@ udma_prep_slave_sg_triggered_tr(struct udma_chan *uc, struct scatterlist *sgl,
struct scatterlist *sgent;
struct cppi5_tr_type15_t *tr_req = NULL;
enum dma_slave_buswidth dev_width;
+ u32 csf = CPPI5_TR_CSF_SUPR_EVT;
u16 tr_cnt0, tr_cnt1;
dma_addr_t dev_addr;
struct udma_desc *d;
@@ -3034,6 +3037,7 @@ udma_prep_slave_sg_triggered_tr(struct udma_chan *uc, struct scatterlist *sgl,
if (uc->ud->match_data->type == DMA_TYPE_UDMA) {
asel = 0;
+ csf |= CPPI5_TR_CSF_EOL_ICNT0;
} else {
asel = (u64)uc->config.asel << K3_ADDRESS_ASEL_SHIFT;
dev_addr |= asel;
@@ -3057,7 +3061,7 @@ udma_prep_slave_sg_triggered_tr(struct udma_chan *uc, struct scatterlist *sgl,
cppi5_tr_init(&tr_req[tr_idx].flags, CPPI5_TR_TYPE15, false,
true, CPPI5_TR_EVENT_SIZE_COMPLETION, 0);
- cppi5_tr_csf_set(&tr_req[tr_idx].flags, CPPI5_TR_CSF_SUPR_EVT);
+ cppi5_tr_csf_set(&tr_req[tr_idx].flags, csf);
cppi5_tr_set_trigger(&tr_req[tr_idx].flags,
uc->config.tr_trigger_type,
CPPI5_TR_TRIGGER_TYPE_ICNT2_DEC, 0, 0);
@@ -3103,8 +3107,7 @@ udma_prep_slave_sg_triggered_tr(struct udma_chan *uc, struct scatterlist *sgl,
cppi5_tr_init(&tr_req[tr_idx].flags, CPPI5_TR_TYPE15,
false, true,
CPPI5_TR_EVENT_SIZE_COMPLETION, 0);
- cppi5_tr_csf_set(&tr_req[tr_idx].flags,
- CPPI5_TR_CSF_SUPR_EVT);
+ cppi5_tr_csf_set(&tr_req[tr_idx].flags, csf);
cppi5_tr_set_trigger(&tr_req[tr_idx].flags,
uc->config.tr_trigger_type,
CPPI5_TR_TRIGGER_TYPE_ICNT2_DEC,
@@ -3148,8 +3151,7 @@ udma_prep_slave_sg_triggered_tr(struct udma_chan *uc, struct scatterlist *sgl,
d->residue += sg_len;
}
- cppi5_tr_csf_set(&tr_req[tr_idx - 1].flags,
- CPPI5_TR_CSF_SUPR_EVT | CPPI5_TR_CSF_EOP);
+ cppi5_tr_csf_set(&tr_req[tr_idx - 1].flags, csf | CPPI5_TR_CSF_EOP);
return d;
}
@@ -3678,6 +3680,7 @@ udma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
int num_tr;
size_t tr_size = sizeof(struct cppi5_tr_type15_t);
u16 tr0_cnt0, tr0_cnt1, tr1_cnt0;
+ u32 csf = CPPI5_TR_CSF_SUPR_EVT;
if (uc->config.dir != DMA_MEM_TO_MEM) {
dev_err(chan->device->dev,
@@ -3708,13 +3711,15 @@ udma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
if (uc->ud->match_data->type != DMA_TYPE_UDMA) {
src |= (u64)uc->ud->asel << K3_ADDRESS_ASEL_SHIFT;
dest |= (u64)uc->ud->asel << K3_ADDRESS_ASEL_SHIFT;
+ } else {
+ csf |= CPPI5_TR_CSF_EOL_ICNT0;
}
tr_req = d->hwdesc[0].tr_req_base;
cppi5_tr_init(&tr_req[0].flags, CPPI5_TR_TYPE15, false, true,
CPPI5_TR_EVENT_SIZE_COMPLETION, 0);
- cppi5_tr_csf_set(&tr_req[0].flags, CPPI5_TR_CSF_SUPR_EVT);
+ cppi5_tr_csf_set(&tr_req[0].flags, csf);
tr_req[0].addr = src;
tr_req[0].icnt0 = tr0_cnt0;
@@ -3733,7 +3738,7 @@ udma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
if (num_tr == 2) {
cppi5_tr_init(&tr_req[1].flags, CPPI5_TR_TYPE15, false, true,
CPPI5_TR_EVENT_SIZE_COMPLETION, 0);
- cppi5_tr_csf_set(&tr_req[1].flags, CPPI5_TR_CSF_SUPR_EVT);
+ cppi5_tr_csf_set(&tr_req[1].flags, csf);
tr_req[1].addr = src + tr0_cnt1 * tr0_cnt0;
tr_req[1].icnt0 = tr1_cnt0;
@@ -3748,8 +3753,7 @@ udma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
tr_req[1].dicnt3 = 1;
}
- cppi5_tr_csf_set(&tr_req[num_tr - 1].flags,
- CPPI5_TR_CSF_SUPR_EVT | CPPI5_TR_CSF_EOP);
+ cppi5_tr_csf_set(&tr_req[num_tr - 1].flags, csf | CPPI5_TR_CSF_EOP);
if (uc->config.metadata_size)
d->vd.tx.metadata_ops = &metadata_ops;
@@ -4412,6 +4416,7 @@ static const struct soc_device_attribute k3_soc_devices[] = {
{ .family = "J721S2", .data = &j721e_soc_data},
{ .family = "AM62X", .data = &am64_soc_data },
{ .family = "AM62AX", .data = &am64_soc_data },
+ { .family = "J784S4", .data = &j721e_soc_data },
{ /* sentinel */ }
};
@@ -5522,11 +5527,63 @@ static int udma_probe(struct platform_device *pdev)
return ret;
}
+static int udma_pm_suspend(struct device *dev)
+{
+ struct udma_dev *ud = dev_get_drvdata(dev);
+ struct dma_device *dma_dev = &ud->ddev;
+ struct dma_chan *chan;
+ struct udma_chan *uc;
+
+ list_for_each_entry(chan, &dma_dev->channels, device_node) {
+ if (chan->client_count) {
+ uc = to_udma_chan(chan);
+ /* backup the channel configuration */
+ memcpy(&uc->backup_config, &uc->config,
+ sizeof(struct udma_chan_config));
+ dev_dbg(dev, "Suspending channel %s\n",
+ dma_chan_name(chan));
+ ud->ddev.device_free_chan_resources(chan);
+ }
+ }
+
+ return 0;
+}
+
+static int udma_pm_resume(struct device *dev)
+{
+ struct udma_dev *ud = dev_get_drvdata(dev);
+ struct dma_device *dma_dev = &ud->ddev;
+ struct dma_chan *chan;
+ struct udma_chan *uc;
+ int ret;
+
+ list_for_each_entry(chan, &dma_dev->channels, device_node) {
+ if (chan->client_count) {
+ uc = to_udma_chan(chan);
+ /* restore the channel configuration */
+ memcpy(&uc->config, &uc->backup_config,
+ sizeof(struct udma_chan_config));
+ dev_dbg(dev, "Resuming channel %s\n",
+ dma_chan_name(chan));
+ ret = ud->ddev.device_alloc_chan_resources(chan);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static const struct dev_pm_ops udma_pm_ops = {
+ SET_LATE_SYSTEM_SLEEP_PM_OPS(udma_pm_suspend, udma_pm_resume)
+};
+
static struct platform_driver udma_driver = {
.driver = {
.name = "ti-udma",
.of_match_table = udma_of_match,
.suppress_bind_attrs = true,
+ .pm = &udma_pm_ops,
},
.probe = udma_probe,
};
diff --git a/drivers/dma/xilinx/zynqmp_dma.c b/drivers/dma/xilinx/zynqmp_dma.c
index ce359058c638..9360f43b8e0f 100644
--- a/drivers/dma/xilinx/zynqmp_dma.c
+++ b/drivers/dma/xilinx/zynqmp_dma.c
@@ -1060,7 +1060,11 @@ static int zynqmp_dma_probe(struct platform_device *pdev)
zdev->dev = &pdev->dev;
INIT_LIST_HEAD(&zdev->common.channels);
- dma_set_mask(&pdev->dev, DMA_BIT_MASK(44));
+ ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(44));
+ if (ret) {
+ dev_err(&pdev->dev, "DMA not available for address range\n");
+ return ret;
+ }
dma_cap_set(DMA_MEMCPY, zdev->common.cap_mask);
p = &zdev->common;
diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c
index 14c872b6ad05..b904de0b1784 100644
--- a/drivers/gpio/gpio-tegra186.c
+++ b/drivers/gpio/gpio-tegra186.c
@@ -1134,6 +1134,7 @@ static const struct tegra_gpio_soc tegra234_aon_soc = {
.name = "tegra234-gpio-aon",
.instance = 1,
.num_irqs_per_bank = 8,
+ .has_gte = true,
};
#define TEGRA241_MAIN_GPIO_PORT(_name, _bank, _port, _pins) \
diff --git a/drivers/hte/hte-tegra194-test.c b/drivers/hte/hte-tegra194-test.c
index 358d4a10c6a1..ba37a5efbf82 100644
--- a/drivers/hte/hte-tegra194-test.c
+++ b/drivers/hte/hte-tegra194-test.c
@@ -16,7 +16,7 @@
#include <linux/workqueue.h>
/*
- * This sample HTE GPIO test driver demonstrates HTE API usage by enabling
+ * This sample HTE test driver demonstrates HTE API usage by enabling
* hardware timestamp on gpio_in and specified LIC IRQ lines.
*
* Note: gpio_out and gpio_in need to be shorted externally in order for this
diff --git a/drivers/hte/hte-tegra194.c b/drivers/hte/hte-tegra194.c
index 49a27af22742..06ef349a2265 100644
--- a/drivers/hte/hte-tegra194.c
+++ b/drivers/hte/hte-tegra194.c
@@ -62,6 +62,10 @@
#define NV_AON_HTE_SLICE2_IRQ_GPIO_25 25
#define NV_AON_HTE_SLICE2_IRQ_GPIO_26 26
#define NV_AON_HTE_SLICE2_IRQ_GPIO_27 27
+#define NV_AON_HTE_SLICE2_IRQ_GPIO_28 28
+#define NV_AON_HTE_SLICE2_IRQ_GPIO_29 29
+#define NV_AON_HTE_SLICE2_IRQ_GPIO_30 30
+#define NV_AON_HTE_SLICE2_IRQ_GPIO_31 31
#define HTE_TECTRL 0x0
#define HTE_TETSCH 0x4
@@ -114,6 +118,7 @@ struct tegra_hte_line_data {
struct tegra_hte_data {
enum tegra_hte_type type;
+ u32 slices;
u32 map_sz;
u32 sec_map_sz;
const struct tegra_hte_line_mapped *map;
@@ -220,18 +225,129 @@ static const struct tegra_hte_line_mapped tegra194_aon_gpio_sec_map[] = {
[39] = {NV_AON_SLICE_INVALID, 0},
};
-static const struct tegra_hte_data aon_hte = {
+static const struct tegra_hte_line_mapped tegra234_aon_gpio_map[] = {
+ /* gpio, slice, bit_index */
+ /* AA port */
+ [0] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_11},
+ [1] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_10},
+ [2] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_9},
+ [3] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_8},
+ [4] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_7},
+ [5] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_6},
+ [6] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_5},
+ [7] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_4},
+ /* BB port */
+ [8] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_3},
+ [9] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_2},
+ [10] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_1},
+ [11] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_0},
+ /* CC port */
+ [12] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_22},
+ [13] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_21},
+ [14] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_20},
+ [15] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_19},
+ [16] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_18},
+ [17] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_17},
+ [18] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_16},
+ [19] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_15},
+ /* DD port */
+ [20] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_14},
+ [21] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_13},
+ [22] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_12},
+ /* EE port */
+ [23] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_31},
+ [24] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_30},
+ [25] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_29},
+ [26] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_28},
+ [27] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_27},
+ [28] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_26},
+ [29] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_25},
+ [30] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_24},
+ /* GG port */
+ [31] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_23},
+};
+
+static const struct tegra_hte_line_mapped tegra234_aon_gpio_sec_map[] = {
+ /* gpio, slice, bit_index */
+ /* AA port */
+ [0] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_11},
+ [1] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_10},
+ [2] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_9},
+ [3] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_8},
+ [4] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_7},
+ [5] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_6},
+ [6] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_5},
+ [7] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_4},
+ /* BB port */
+ [8] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_3},
+ [9] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_2},
+ [10] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_1},
+ [11] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_0},
+ [12] = {NV_AON_SLICE_INVALID, 0},
+ [13] = {NV_AON_SLICE_INVALID, 0},
+ [14] = {NV_AON_SLICE_INVALID, 0},
+ [15] = {NV_AON_SLICE_INVALID, 0},
+ /* CC port */
+ [16] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_22},
+ [17] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_21},
+ [18] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_20},
+ [19] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_19},
+ [20] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_18},
+ [21] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_17},
+ [22] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_16},
+ [23] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_15},
+ /* DD port */
+ [24] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_14},
+ [25] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_13},
+ [26] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_12},
+ [27] = {NV_AON_SLICE_INVALID, 0},
+ [28] = {NV_AON_SLICE_INVALID, 0},
+ [29] = {NV_AON_SLICE_INVALID, 0},
+ [30] = {NV_AON_SLICE_INVALID, 0},
+ [31] = {NV_AON_SLICE_INVALID, 0},
+ /* EE port */
+ [32] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_31},
+ [33] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_30},
+ [34] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_29},
+ [35] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_28},
+ [36] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_27},
+ [37] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_26},
+ [38] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_25},
+ [39] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_24},
+ /* GG port */
+ [40] = {2, NV_AON_HTE_SLICE2_IRQ_GPIO_23},
+};
+
+static const struct tegra_hte_data t194_aon_hte = {
.map_sz = ARRAY_SIZE(tegra194_aon_gpio_map),
.map = tegra194_aon_gpio_map,
.sec_map_sz = ARRAY_SIZE(tegra194_aon_gpio_sec_map),
.sec_map = tegra194_aon_gpio_sec_map,
.type = HTE_TEGRA_TYPE_GPIO,
+ .slices = 3,
};
-static const struct tegra_hte_data lic_hte = {
+static const struct tegra_hte_data t234_aon_hte = {
+ .map_sz = ARRAY_SIZE(tegra234_aon_gpio_map),
+ .map = tegra234_aon_gpio_map,
+ .sec_map_sz = ARRAY_SIZE(tegra234_aon_gpio_sec_map),
+ .sec_map = tegra234_aon_gpio_sec_map,
+ .type = HTE_TEGRA_TYPE_GPIO,
+ .slices = 3,
+};
+
+static const struct tegra_hte_data t194_lic_hte = {
+ .map_sz = 0,
+ .map = NULL,
+ .type = HTE_TEGRA_TYPE_LIC,
+ .slices = 11,
+};
+
+static const struct tegra_hte_data t234_lic_hte = {
.map_sz = 0,
.map = NULL,
.type = HTE_TEGRA_TYPE_LIC,
+ .slices = 17,
};
static inline u32 tegra_hte_readl(struct tegra_hte_soc *hte, u32 reg)
@@ -251,7 +367,7 @@ static int tegra_hte_map_to_line_id(u32 eid,
{
if (m) {
- if (eid > map_sz)
+ if (eid >= map_sz)
return -EINVAL;
if (m[eid].slice == NV_AON_SLICE_INVALID)
return -EINVAL;
@@ -534,8 +650,10 @@ static bool tegra_hte_match_from_linedata(const struct hte_chip *chip,
}
static const struct of_device_id tegra_hte_of_match[] = {
- { .compatible = "nvidia,tegra194-gte-lic", .data = &lic_hte},
- { .compatible = "nvidia,tegra194-gte-aon", .data = &aon_hte},
+ { .compatible = "nvidia,tegra194-gte-lic", .data = &t194_lic_hte},
+ { .compatible = "nvidia,tegra194-gte-aon", .data = &t194_aon_hte},
+ { .compatible = "nvidia,tegra234-gte-lic", .data = &t234_lic_hte},
+ { .compatible = "nvidia,tegra234-gte-aon", .data = &t234_aon_hte},
{ }
};
MODULE_DEVICE_TABLE(of, tegra_hte_of_match);
@@ -561,6 +679,11 @@ static int tegra_get_gpiochip_from_name(struct gpio_chip *chip, void *data)
return !strcmp(chip->label, data);
}
+static int tegra_gpiochip_match(struct gpio_chip *chip, void *data)
+{
+ return chip->fwnode == of_node_to_fwnode(data);
+}
+
static int tegra_hte_probe(struct platform_device *pdev)
{
int ret;
@@ -569,16 +692,10 @@ static int tegra_hte_probe(struct platform_device *pdev)
struct device *dev;
struct tegra_hte_soc *hte_dev;
struct hte_chip *gc;
+ struct device_node *gpio_ctrl;
dev = &pdev->dev;
- ret = of_property_read_u32(dev->of_node, "nvidia,slices", &slices);
- if (ret != 0) {
- dev_err(dev, "Could not read slices\n");
- return -EINVAL;
- }
- nlines = slices << 5;
-
hte_dev = devm_kzalloc(dev, sizeof(*hte_dev), GFP_KERNEL);
if (!hte_dev)
return -ENOMEM;
@@ -590,6 +707,13 @@ static int tegra_hte_probe(struct platform_device *pdev)
dev_set_drvdata(&pdev->dev, hte_dev);
hte_dev->prov_data = of_device_get_match_data(&pdev->dev);
+ ret = of_property_read_u32(dev->of_node, "nvidia,slices", &slices);
+ if (ret != 0)
+ slices = hte_dev->prov_data->slices;
+
+ dev_dbg(dev, "slices:%d\n", slices);
+ nlines = slices << 5;
+
hte_dev->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(hte_dev->regs))
return PTR_ERR(hte_dev->regs);
@@ -635,8 +759,25 @@ static int tegra_hte_probe(struct platform_device *pdev)
gc->match_from_linedata = tegra_hte_match_from_linedata;
- hte_dev->c = gpiochip_find("tegra194-gpio-aon",
- tegra_get_gpiochip_from_name);
+ if (of_device_is_compatible(dev->of_node,
+ "nvidia,tegra194-gte-aon")) {
+ hte_dev->c = gpiochip_find("tegra194-gpio-aon",
+ tegra_get_gpiochip_from_name);
+ } else {
+ gpio_ctrl = of_parse_phandle(dev->of_node,
+ "nvidia,gpio-controller",
+ 0);
+ if (!gpio_ctrl) {
+ dev_err(dev,
+ "gpio controller node not found\n");
+ return -ENODEV;
+ }
+
+ hte_dev->c = gpiochip_find(gpio_ctrl,
+ tegra_gpiochip_match);
+ of_node_put(gpio_ctrl);
+ }
+
if (!hte_dev->c)
return dev_err_probe(dev, -EPROBE_DEFER,
"wait for gpio controller\n");
diff --git a/drivers/hte/hte.c b/drivers/hte/hte.c
index 9f3221462e75..67c15724ee78 100644
--- a/drivers/hte/hte.c
+++ b/drivers/hte/hte.c
@@ -444,7 +444,7 @@ static struct hte_device *of_node_to_htedevice(struct device_node *np)
list_for_each_entry(gdev, &hte_devices, list)
if (gdev->chip && gdev->chip->dev &&
- gdev->chip->dev->of_node == np) {
+ device_match_of_node(gdev->chip->dev, np)) {
spin_unlock(&hte_lock);
return gdev;
}
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
index 938c17f25d94..aa2d19db2b1d 100644
--- a/drivers/idle/intel_idle.c
+++ b/drivers/idle/intel_idle.c
@@ -66,8 +66,9 @@ static struct cpuidle_driver intel_idle_driver = {
};
/* intel_idle.max_cstate=0 disables driver */
static int max_cstate = CPUIDLE_STATE_MAX - 1;
-static unsigned int disabled_states_mask;
-static unsigned int preferred_states_mask;
+static unsigned int disabled_states_mask __read_mostly;
+static unsigned int preferred_states_mask __read_mostly;
+static bool force_irq_on __read_mostly;
static struct cpuidle_device __percpu *intel_idle_cpuidle_devices;
@@ -1838,9 +1839,6 @@ static bool __init intel_idle_verify_cstate(unsigned int mwait_hint)
return true;
}
-static bool force_irq_on __read_mostly;
-module_param(force_irq_on, bool, 0444);
-
static void __init intel_idle_init_cstates_icpu(struct cpuidle_driver *drv)
{
int cstate;
@@ -1871,6 +1869,7 @@ static void __init intel_idle_init_cstates_icpu(struct cpuidle_driver *drv)
}
for (cstate = 0; cstate < CPUIDLE_STATE_MAX; ++cstate) {
+ struct cpuidle_state *state;
unsigned int mwait_hint;
if (intel_idle_max_cstate_reached(cstate))
@@ -1893,29 +1892,39 @@ static void __init intel_idle_init_cstates_icpu(struct cpuidle_driver *drv)
/* Structure copy. */
drv->states[drv->state_count] = cpuidle_state_table[cstate];
-
- if ((cpuidle_state_table[cstate].flags & CPUIDLE_FLAG_IRQ_ENABLE) || force_irq_on) {
- printk("intel_idle: forced intel_idle_irq for state %d\n", cstate);
- drv->states[drv->state_count].enter = intel_idle_irq;
- }
-
- if (cpu_feature_enabled(X86_FEATURE_KERNEL_IBRS) &&
- cpuidle_state_table[cstate].flags & CPUIDLE_FLAG_IBRS) {
- WARN_ON_ONCE(cpuidle_state_table[cstate].flags & CPUIDLE_FLAG_IRQ_ENABLE);
- drv->states[drv->state_count].enter = intel_idle_ibrs;
+ state = &drv->states[drv->state_count];
+
+ if (state->flags & CPUIDLE_FLAG_INIT_XSTATE) {
+ /*
+ * Combining with XSTATE with IBRS or IRQ_ENABLE flags
+ * is not currently supported but this driver.
+ */
+ WARN_ON_ONCE(state->flags & CPUIDLE_FLAG_IBRS);
+ WARN_ON_ONCE(state->flags & CPUIDLE_FLAG_IRQ_ENABLE);
+ state->enter = intel_idle_xstate;
+ } else if (cpu_feature_enabled(X86_FEATURE_KERNEL_IBRS) &&
+ state->flags & CPUIDLE_FLAG_IBRS) {
+ /*
+ * IBRS mitigation requires that C-states are entered
+ * with interrupts disabled.
+ */
+ WARN_ON_ONCE(state->flags & CPUIDLE_FLAG_IRQ_ENABLE);
+ state->enter = intel_idle_ibrs;
+ } else if (state->flags & CPUIDLE_FLAG_IRQ_ENABLE) {
+ state->enter = intel_idle_irq;
+ } else if (force_irq_on) {
+ pr_info("forced intel_idle_irq for state %d\n", cstate);
+ state->enter = intel_idle_irq;
}
- if (cpuidle_state_table[cstate].flags & CPUIDLE_FLAG_INIT_XSTATE)
- drv->states[drv->state_count].enter = intel_idle_xstate;
-
if ((disabled_states_mask & BIT(drv->state_count)) ||
((icpu->use_acpi || force_use_acpi) &&
intel_idle_off_by_default(mwait_hint) &&
- !(cpuidle_state_table[cstate].flags & CPUIDLE_FLAG_ALWAYS_ENABLE)))
- drv->states[drv->state_count].flags |= CPUIDLE_FLAG_OFF;
+ !(state->flags & CPUIDLE_FLAG_ALWAYS_ENABLE)))
+ state->flags |= CPUIDLE_FLAG_OFF;
- if (intel_idle_state_needs_timer_stop(&drv->states[drv->state_count]))
- drv->states[drv->state_count].flags |= CPUIDLE_FLAG_TIMER_STOP;
+ if (intel_idle_state_needs_timer_stop(state))
+ state->flags |= CPUIDLE_FLAG_TIMER_STOP;
drv->state_count++;
}
@@ -2146,3 +2155,9 @@ MODULE_PARM_DESC(states_off, "Mask of disabled idle states");
*/
module_param_named(preferred_cstates, preferred_states_mask, uint, 0444);
MODULE_PARM_DESC(preferred_cstates, "Mask of preferred idle states");
+/*
+ * Debugging option that forces the driver to enter all C-states with
+ * interrupts enabled. Does not apply to C-states with
+ * 'CPUIDLE_FLAG_INIT_XSTATE' and 'CPUIDLE_FLAG_IBRS' flags.
+ */
+module_param(force_irq_on, bool, 0444);
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index 9cd565daad36..8b91a55ec0d2 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -1266,7 +1266,7 @@ static int __init ubi_init(void)
mutex_lock(&ubi_devices_mutex);
err = ubi_attach_mtd_dev(mtd, p->ubi_num,
p->vid_hdr_offs, p->max_beb_per1024,
- p->enable_fm == 0 ? true : false);
+ p->enable_fm == 0);
mutex_unlock(&ubi_devices_mutex);
if (err < 0) {
pr_err("UBI error: cannot attach mtd%d\n",
diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c
index 403b79d6efd5..655ff41863e2 100644
--- a/drivers/mtd/ubi/eba.c
+++ b/drivers/mtd/ubi/eba.c
@@ -946,7 +946,7 @@ static int try_write_vid_and_data(struct ubi_volume *vol, int lnum,
int offset, int len)
{
struct ubi_device *ubi = vol->ubi;
- int pnum, opnum, err, vol_id = vol->vol_id;
+ int pnum, opnum, err, err2, vol_id = vol->vol_id;
pnum = ubi_wl_get_peb(ubi);
if (pnum < 0) {
@@ -981,10 +981,19 @@ static int try_write_vid_and_data(struct ubi_volume *vol, int lnum,
out_put:
up_read(&ubi->fm_eba_sem);
- if (err && pnum >= 0)
- err = ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1);
- else if (!err && opnum >= 0)
- err = ubi_wl_put_peb(ubi, vol_id, lnum, opnum, 0);
+ if (err && pnum >= 0) {
+ err2 = ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1);
+ if (err2) {
+ ubi_warn(ubi, "failed to return physical eraseblock %d, error %d",
+ pnum, err2);
+ }
+ } else if (!err && opnum >= 0) {
+ err2 = ubi_wl_put_peb(ubi, vol_id, lnum, opnum, 0);
+ if (err2) {
+ ubi_warn(ubi, "failed to return physical eraseblock %d, error %d",
+ opnum, err2);
+ }
+ }
return err;
}
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 7bd00a11d074..f46e3148d286 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -44,7 +44,7 @@ config PHY_PISTACHIO_USB
config PHY_XGENE
tristate "APM X-Gene 15Gbps PHY support"
- depends on HAS_IOMEM && OF && (ARM64 || COMPILE_TEST)
+ depends on HAS_IOMEM && OF && (ARCH_XGENE || COMPILE_TEST)
select GENERIC_PHY
help
This option enables support for APM X-Gene SoC multi-purpose PHY.
diff --git a/drivers/phy/allwinner/phy-sun4i-usb.c b/drivers/phy/allwinner/phy-sun4i-usb.c
index fbcd7014ab43..56d53f78d002 100644
--- a/drivers/phy/allwinner/phy-sun4i-usb.c
+++ b/drivers/phy/allwinner/phy-sun4i-usb.c
@@ -698,7 +698,7 @@ static struct phy *sun4i_usb_phy_xlate(struct device *dev,
return data->phys[args->args[0]].phy;
}
-static int sun4i_usb_phy_remove(struct platform_device *pdev)
+static void sun4i_usb_phy_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct sun4i_usb_phy_data *data = dev_get_drvdata(dev);
@@ -711,8 +711,6 @@ static int sun4i_usb_phy_remove(struct platform_device *pdev)
devm_free_irq(dev, data->vbus_det_irq, data);
cancel_delayed_work_sync(&data->detect);
-
- return 0;
}
static const unsigned int sun4i_usb_phy0_cable[] = {
@@ -758,7 +756,7 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev)
return PTR_ERR(data->vbus_det_gpio);
}
- if (of_find_property(np, "usb0_vbus_power-supply", NULL)) {
+ if (of_property_present(np, "usb0_vbus_power-supply")) {
data->vbus_power_supply = devm_power_supply_get_by_phandle(dev,
"usb0_vbus_power-supply");
if (IS_ERR(data->vbus_power_supply)) {
@@ -1054,7 +1052,7 @@ MODULE_DEVICE_TABLE(of, sun4i_usb_phy_of_match);
static struct platform_driver sun4i_usb_phy_driver = {
.probe = sun4i_usb_phy_probe,
- .remove = sun4i_usb_phy_remove,
+ .remove_new = sun4i_usb_phy_remove,
.driver = {
.of_match_table = sun4i_usb_phy_of_match,
.name = "sun4i-usb-phy",
diff --git a/drivers/phy/amlogic/phy-meson-axg-mipi-dphy.c b/drivers/phy/amlogic/phy-meson-axg-mipi-dphy.c
index 32d1ff09befb..6e9af79e152c 100644
--- a/drivers/phy/amlogic/phy-meson-axg-mipi-dphy.c
+++ b/drivers/phy/amlogic/phy-meson-axg-mipi-dphy.c
@@ -335,7 +335,6 @@ static int phy_meson_axg_mipi_dphy_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct phy_provider *phy_provider;
- struct resource *res;
struct phy_meson_axg_mipi_dphy_priv *priv;
struct phy *phy;
void __iomem *base;
@@ -348,8 +347,7 @@ static int phy_meson_axg_mipi_dphy_probe(struct platform_device *pdev)
priv->dev = dev;
platform_set_drvdata(pdev, priv);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- base = devm_ioremap_resource(dev, res);
+ base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
return PTR_ERR(base);
diff --git a/drivers/phy/broadcom/phy-bcm-ns-usb2.c b/drivers/phy/broadcom/phy-bcm-ns-usb2.c
index 6a36e187d100..269564bdf687 100644
--- a/drivers/phy/broadcom/phy-bcm-ns-usb2.c
+++ b/drivers/phy/broadcom/phy-bcm-ns-usb2.c
@@ -107,7 +107,7 @@ static int bcm_ns_usb2_probe(struct platform_device *pdev)
return -ENOMEM;
usb2->dev = dev;
- if (of_find_property(dev->of_node, "brcm,syscon-clkset", NULL)) {
+ if (of_property_present(dev->of_node, "brcm,syscon-clkset")) {
usb2->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(usb2->base)) {
dev_err(dev, "Failed to map control reg\n");
diff --git a/drivers/phy/broadcom/phy-brcm-usb.c b/drivers/phy/broadcom/phy-brcm-usb.c
index 4de39999f43d..a4cfb777dd83 100644
--- a/drivers/phy/broadcom/phy-brcm-usb.c
+++ b/drivers/phy/broadcom/phy-brcm-usb.c
@@ -572,14 +572,12 @@ static int brcm_usb_phy_probe(struct platform_device *pdev)
return PTR_ERR_OR_ZERO(phy_provider);
}
-static int brcm_usb_phy_remove(struct platform_device *pdev)
+static void brcm_usb_phy_remove(struct platform_device *pdev)
{
struct brcm_usb_phy_data *priv = dev_get_drvdata(&pdev->dev);
sysfs_remove_group(&pdev->dev.kobj, &brcm_usb_phy_group);
unregister_pm_notifier(&priv->pm_notifier);
-
- return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -670,7 +668,7 @@ MODULE_DEVICE_TABLE(of, brcm_usb_dt_ids);
static struct platform_driver brcm_usb_driver = {
.probe = brcm_usb_phy_probe,
- .remove = brcm_usb_phy_remove,
+ .remove_new = brcm_usb_phy_remove,
.driver = {
.name = "brcmstb-usb-phy",
.pm = &brcm_usb_phy_pm_ops,
diff --git a/drivers/phy/cadence/cdns-dphy-rx.c b/drivers/phy/cadence/cdns-dphy-rx.c
index 572c70089a94..c05b043893a9 100644
--- a/drivers/phy/cadence/cdns-dphy-rx.c
+++ b/drivers/phy/cadence/cdns-dphy-rx.c
@@ -11,10 +11,12 @@
#include <linux/phy/phy.h>
#include <linux/phy/phy-mipi-dphy.h>
#include <linux/platform_device.h>
+#include <linux/sys_soc.h>
#define DPHY_PMA_CMN(reg) (reg)
#define DPHY_PCS(reg) (0xb00 + (reg))
#define DPHY_ISO(reg) (0xc00 + (reg))
+#define DPHY_WRAP(reg) (0x1000 + (reg))
#define DPHY_CMN_SSM DPHY_PMA_CMN(0x20)
#define DPHY_CMN_RX_MODE_EN BIT(10)
@@ -33,6 +35,9 @@
#define DPHY_POWER_ISLAND_EN_CLK DPHY_PCS(0xc)
#define DPHY_POWER_ISLAND_EN_CLK_VAL 0xaa
+#define DPHY_LANE DPHY_WRAP(0x0)
+#define DPHY_LANE_RESET_CMN_EN BIT(23)
+
#define DPHY_ISO_CL_CTRL_L DPHY_ISO(0x10)
#define DPHY_ISO_DL_CTRL_L0 DPHY_ISO(0x14)
#define DPHY_ISO_DL_CTRL_L1 DPHY_ISO(0x20)
@@ -57,6 +62,10 @@ struct cdns_dphy_rx_band {
unsigned int max_rate;
};
+struct cdns_dphy_soc_data {
+ bool has_hw_cmn_rstb;
+};
+
/* Order of bands is important since the index is the band number. */
static const struct cdns_dphy_rx_band bands[] = {
{ 80, 100 }, { 100, 120 }, { 120, 160 }, { 160, 200 }, { 200, 240 },
@@ -142,13 +151,36 @@ static int cdns_dphy_rx_wait_lane_ready(struct cdns_dphy_rx *dphy,
return 0;
}
+static struct cdns_dphy_soc_data j721e_soc_data = {
+ .has_hw_cmn_rstb = true,
+};
+
+static const struct soc_device_attribute cdns_dphy_socinfo[] = {
+ {
+ .family = "J721E",
+ .revision = "SR1.0",
+ .data = &j721e_soc_data,
+ },
+ {/* sentinel */}
+};
+
static int cdns_dphy_rx_configure(struct phy *phy,
union phy_configure_opts *opts)
{
struct cdns_dphy_rx *dphy = phy_get_drvdata(phy);
unsigned int reg, lanes = opts->mipi_dphy.lanes;
+ const struct cdns_dphy_soc_data *soc_data = NULL;
+ const struct soc_device_attribute *soc;
int band_ctrl, ret;
+ soc = soc_device_match(cdns_dphy_socinfo);
+ if (soc && soc->data)
+ soc_data = soc->data;
+ if (!soc || (soc_data && !soc_data->has_hw_cmn_rstb)) {
+ reg = DPHY_LANE_RESET_CMN_EN;
+ writel(reg, dphy->regs + DPHY_LANE);
+ }
+
/* Data lanes. Minimum one lane is mandatory. */
if (lanes < DPHY_LANES_MIN || lanes > DPHY_LANES_MAX)
return -EINVAL;
diff --git a/drivers/phy/cadence/cdns-dphy.c b/drivers/phy/cadence/cdns-dphy.c
index 3dfdfb33cd0a..6e58012b6488 100644
--- a/drivers/phy/cadence/cdns-dphy.c
+++ b/drivers/phy/cadence/cdns-dphy.c
@@ -456,14 +456,12 @@ static int cdns_dphy_probe(struct platform_device *pdev)
return PTR_ERR_OR_ZERO(phy_provider);
}
-static int cdns_dphy_remove(struct platform_device *pdev)
+static void cdns_dphy_remove(struct platform_device *pdev)
{
struct cdns_dphy *dphy = dev_get_drvdata(&pdev->dev);
if (dphy->ops->remove)
dphy->ops->remove(dphy);
-
- return 0;
}
static const struct of_device_id cdns_dphy_of_match[] = {
@@ -475,7 +473,7 @@ MODULE_DEVICE_TABLE(of, cdns_dphy_of_match);
static struct platform_driver cdns_dphy_platform_driver = {
.probe = cdns_dphy_probe,
- .remove = cdns_dphy_remove,
+ .remove_new = cdns_dphy_remove,
.driver = {
.name = "cdns-mipi-dphy",
.of_match_table = cdns_dphy_of_match,
diff --git a/drivers/phy/cadence/phy-cadence-sierra.c b/drivers/phy/cadence/phy-cadence-sierra.c
index 6e86a6517f37..13fcd3a65fe9 100644
--- a/drivers/phy/cadence/phy-cadence-sierra.c
+++ b/drivers/phy/cadence/phy-cadence-sierra.c
@@ -24,7 +24,7 @@
#include <dt-bindings/phy/phy-cadence.h>
#define NUM_SSC_MODE 3
-#define NUM_PHY_TYPE 4
+#define NUM_PHY_TYPE 5
/* PHY register offsets */
#define SIERRA_COMMON_CDB_OFFSET 0x0
@@ -46,7 +46,9 @@
#define SIERRA_CMN_REFRCV_PREG 0x98
#define SIERRA_CMN_REFRCV1_PREG 0xB8
#define SIERRA_CMN_PLLLC1_GEN_PREG 0xC2
+#define SIERRA_CMN_PLLLC1_FBDIV_INT_PREG 0xC3
#define SIERRA_CMN_PLLLC1_LF_COEFF_MODE0_PREG 0xCA
+#define SIERRA_CMN_PLLLC1_CLK0_PREG 0xCE
#define SIERRA_CMN_PLLLC1_BWCAL_MODE0_PREG 0xD0
#define SIERRA_CMN_PLLLC1_SS_TIME_STEPSIZE_MODE_PREG 0xE2
@@ -74,6 +76,7 @@
#define SIERRA_PSC_RX_A1_PREG 0x031
#define SIERRA_PSC_RX_A2_PREG 0x032
#define SIERRA_PSC_RX_A3_PREG 0x033
+#define SIERRA_PLLCTRL_FBDIV_MODE01_PREG 0x039
#define SIERRA_PLLCTRL_SUBRATE_PREG 0x03A
#define SIERRA_PLLCTRL_GEN_A_PREG 0x03B
#define SIERRA_PLLCTRL_GEN_D_PREG 0x03E
@@ -206,13 +209,11 @@
#define PLL_LOCK_TIME 100000
#define CDNS_SIERRA_OUTPUT_CLOCKS 3
-#define CDNS_SIERRA_INPUT_CLOCKS 5
+#define CDNS_SIERRA_INPUT_CLOCKS 3
enum cdns_sierra_clock_input {
PHY_CLK,
CMN_REFCLK_DIG_DIV,
CMN_REFCLK1_DIG_DIV,
- PLL0_REFCLK,
- PLL1_REFCLK,
};
#define SIERRA_NUM_CMN_PLLC 2
@@ -274,9 +275,18 @@ struct cdns_sierra_pll_mux {
#define to_cdns_sierra_pll_mux(_hw) \
container_of(_hw, struct cdns_sierra_pll_mux, hw)
-static const int pll_mux_parent_index[][SIERRA_NUM_CMN_PLLC_PARENTS] = {
- [CMN_PLLLC] = { PLL0_REFCLK, PLL1_REFCLK },
- [CMN_PLLLC1] = { PLL1_REFCLK, PLL0_REFCLK },
+#define PLL0_REFCLK_NAME "pll0_refclk"
+#define PLL1_REFCLK_NAME "pll1_refclk"
+
+static const struct clk_parent_data pll_mux_parent_data[][SIERRA_NUM_CMN_PLLC_PARENTS] = {
+ [CMN_PLLLC] = {
+ { .fw_name = PLL0_REFCLK_NAME },
+ { .fw_name = PLL1_REFCLK_NAME }
+ },
+ [CMN_PLLLC1] = {
+ { .fw_name = PLL1_REFCLK_NAME },
+ { .fw_name = PLL0_REFCLK_NAME }
+ },
};
static u32 cdns_sierra_pll_mux_table[][SIERRA_NUM_CMN_PLLC_PARENTS] = {
@@ -298,6 +308,7 @@ enum cdns_sierra_phy_type {
TYPE_NONE,
TYPE_PCIE,
TYPE_USB,
+ TYPE_SGMII,
TYPE_QSGMII
};
@@ -371,8 +382,8 @@ struct cdns_sierra_phy {
u32 num_lanes;
bool autoconf;
int already_configured;
- struct clk_onecell_data clk_data;
- struct clk *output_clks[CDNS_SIERRA_OUTPUT_CLOCKS];
+ struct clk *pll_clks[SIERRA_NUM_CMN_PLLC];
+ struct clk_hw_onecell_data clk_data;
};
static int cdns_regmap_write(void *context, unsigned int reg, unsigned int val)
@@ -722,38 +733,21 @@ static int cdns_sierra_pll_mux_register(struct cdns_sierra_phy *sp,
struct cdns_sierra_pll_mux *mux;
struct device *dev = sp->dev;
struct clk_init_data *init;
- const char **parent_names;
- unsigned int num_parents;
char clk_name[100];
- struct clk *clk;
- int i;
+ int ret;
mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
if (!mux)
return -ENOMEM;
- num_parents = SIERRA_NUM_CMN_PLLC_PARENTS;
- parent_names = devm_kzalloc(dev, (sizeof(char *) * num_parents), GFP_KERNEL);
- if (!parent_names)
- return -ENOMEM;
-
- for (i = 0; i < num_parents; i++) {
- clk = sp->input_clks[pll_mux_parent_index[clk_index][i]];
- if (IS_ERR_OR_NULL(clk)) {
- dev_err(dev, "No parent clock for PLL mux clocks\n");
- return IS_ERR(clk) ? PTR_ERR(clk) : -ENOENT;
- }
- parent_names[i] = __clk_get_name(clk);
- }
-
snprintf(clk_name, sizeof(clk_name), "%s_%s", dev_name(dev), clk_names[clk_index]);
init = &mux->clk_data;
init->ops = &cdns_sierra_pll_mux_ops;
init->flags = CLK_SET_RATE_NO_REPARENT;
- init->parent_names = parent_names;
- init->num_parents = num_parents;
+ init->parent_data = pll_mux_parent_data[clk_index];
+ init->num_parents = SIERRA_NUM_CMN_PLLC_PARENTS;
init->name = clk_name;
mux->pfdclk_sel_preg = pfdclk1_sel_field;
@@ -761,11 +755,14 @@ static int cdns_sierra_pll_mux_register(struct cdns_sierra_phy *sp,
mux->termen_field = termen_field;
mux->hw.init = init;
- clk = devm_clk_register(dev, &mux->hw);
- if (IS_ERR(clk))
- return PTR_ERR(clk);
+ ret = devm_clk_hw_register(dev, &mux->hw);
+ if (ret)
+ return ret;
- sp->output_clks[clk_index] = clk;
+ sp->clk_data.hws[clk_index] = &mux->hw;
+
+ sp->pll_clks[clk_index] = devm_clk_hw_get_clk(dev, &mux->hw,
+ clk_names[clk_index]);
return 0;
}
@@ -838,7 +835,7 @@ static int cdns_sierra_derived_refclk_register(struct cdns_sierra_phy *sp)
struct clk_init_data *init;
struct regmap *regmap;
char clk_name[100];
- struct clk *clk;
+ int ret;
derived_refclk = devm_kzalloc(dev, sizeof(*derived_refclk), GFP_KERNEL);
if (!derived_refclk)
@@ -871,11 +868,11 @@ static int cdns_sierra_derived_refclk_register(struct cdns_sierra_phy *sp)
derived_refclk->hw.init = init;
- clk = devm_clk_register(dev, &derived_refclk->hw);
- if (IS_ERR(clk))
- return PTR_ERR(clk);
+ ret = devm_clk_hw_register(dev, &derived_refclk->hw);
+ if (ret)
+ return ret;
- sp->output_clks[CDNS_SIERRA_DERIVED_REFCLK] = clk;
+ sp->clk_data.hws[CDNS_SIERRA_DERIVED_REFCLK] = &derived_refclk->hw;
return 0;
}
@@ -906,9 +903,9 @@ static int cdns_sierra_clk_register(struct cdns_sierra_phy *sp)
return ret;
}
- sp->clk_data.clks = sp->output_clks;
- sp->clk_data.clk_num = CDNS_SIERRA_OUTPUT_CLOCKS;
- ret = of_clk_add_provider(node, of_clk_src_onecell_get, &sp->clk_data);
+ sp->clk_data.num = CDNS_SIERRA_OUTPUT_CLOCKS;
+ ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get,
+ &sp->clk_data);
if (ret)
dev_err(dev, "Failed to add clock provider: %s\n", node->name);
@@ -936,6 +933,9 @@ static int cdns_sierra_get_optional(struct cdns_sierra_inst *inst,
case PHY_TYPE_USB3:
inst->phy_type = TYPE_USB;
break;
+ case PHY_TYPE_SGMII:
+ inst->phy_type = TYPE_SGMII;
+ break;
case PHY_TYPE_QSGMII:
inst->phy_type = TYPE_QSGMII;
break;
@@ -1147,22 +1147,6 @@ static int cdns_sierra_phy_get_clocks(struct cdns_sierra_phy *sp,
}
sp->input_clks[CMN_REFCLK1_DIG_DIV] = clk;
- clk = devm_clk_get_optional(dev, "pll0_refclk");
- if (IS_ERR(clk)) {
- dev_err(dev, "pll0_refclk clock not found\n");
- ret = PTR_ERR(clk);
- return ret;
- }
- sp->input_clks[PLL0_REFCLK] = clk;
-
- clk = devm_clk_get_optional(dev, "pll1_refclk");
- if (IS_ERR(clk)) {
- dev_err(dev, "pll1_refclk clock not found\n");
- ret = PTR_ERR(clk);
- return ret;
- }
- sp->input_clks[PLL1_REFCLK] = clk;
-
return 0;
}
@@ -1190,26 +1174,26 @@ static int cdns_sierra_phy_enable_clocks(struct cdns_sierra_phy *sp)
{
int ret;
- ret = clk_prepare_enable(sp->output_clks[CDNS_SIERRA_PLL_CMNLC]);
+ ret = clk_prepare_enable(sp->pll_clks[CDNS_SIERRA_PLL_CMNLC]);
if (ret)
return ret;
- ret = clk_prepare_enable(sp->output_clks[CDNS_SIERRA_PLL_CMNLC1]);
+ ret = clk_prepare_enable(sp->pll_clks[CDNS_SIERRA_PLL_CMNLC1]);
if (ret)
goto err_pll_cmnlc1;
return 0;
err_pll_cmnlc1:
- clk_disable_unprepare(sp->output_clks[CDNS_SIERRA_PLL_CMNLC]);
+ clk_disable_unprepare(sp->pll_clks[CDNS_SIERRA_PLL_CMNLC]);
return ret;
}
static void cdns_sierra_phy_disable_clocks(struct cdns_sierra_phy *sp)
{
- clk_disable_unprepare(sp->output_clks[CDNS_SIERRA_PLL_CMNLC1]);
- clk_disable_unprepare(sp->output_clks[CDNS_SIERRA_PLL_CMNLC]);
+ clk_disable_unprepare(sp->pll_clks[CDNS_SIERRA_PLL_CMNLC1]);
+ clk_disable_unprepare(sp->pll_clks[CDNS_SIERRA_PLL_CMNLC]);
if (!sp->already_configured)
clk_disable_unprepare(sp->input_clks[PHY_CLK]);
}
@@ -1339,7 +1323,7 @@ static int cdns_sierra_phy_configure_multilink(struct cdns_sierra_phy *sp)
}
}
- if (phy_t1 == TYPE_QSGMII)
+ if (phy_t1 == TYPE_SGMII || phy_t1 == TYPE_QSGMII)
reset_control_deassert(sp->phys[node].lnk_rst);
}
@@ -1370,7 +1354,9 @@ static int cdns_sierra_phy_probe(struct platform_device *pdev)
if (!data)
return -EINVAL;
- sp = devm_kzalloc(dev, sizeof(*sp), GFP_KERNEL);
+ sp = devm_kzalloc(dev, struct_size(sp, clk_data.hws,
+ CDNS_SIERRA_OUTPUT_CLOCKS),
+ GFP_KERNEL);
if (!sp)
return -ENOMEM;
dev_set_drvdata(dev, sp);
@@ -1513,7 +1499,7 @@ unregister_clk:
return ret;
}
-static int cdns_sierra_phy_remove(struct platform_device *pdev)
+static void cdns_sierra_phy_remove(struct platform_device *pdev)
{
struct cdns_sierra_phy *phy = platform_get_drvdata(pdev);
int i;
@@ -1533,10 +1519,73 @@ static int cdns_sierra_phy_remove(struct platform_device *pdev)
}
cdns_sierra_clk_unregister(phy);
-
- return 0;
}
+/* SGMII PHY PMA lane configuration */
+static struct cdns_reg_pairs sgmii_phy_pma_ln_regs[] = {
+ {0x9010, SIERRA_PHY_PMA_XCVR_CTRL}
+};
+
+static struct cdns_sierra_vals sgmii_phy_pma_ln_vals = {
+ .reg_pairs = sgmii_phy_pma_ln_regs,
+ .num_regs = ARRAY_SIZE(sgmii_phy_pma_ln_regs),
+};
+
+/* SGMII refclk 100MHz, no ssc, opt3 and GE1 links using PLL LC1 */
+static const struct cdns_reg_pairs sgmii_100_no_ssc_plllc1_opt3_cmn_regs[] = {
+ {0x002D, SIERRA_CMN_PLLLC1_FBDIV_INT_PREG},
+ {0x2085, SIERRA_CMN_PLLLC1_LF_COEFF_MODE0_PREG},
+ {0x1005, SIERRA_CMN_PLLLC1_CLK0_PREG},
+ {0x0000, SIERRA_CMN_PLLLC1_BWCAL_MODE0_PREG},
+ {0x0800, SIERRA_CMN_PLLLC1_SS_TIME_STEPSIZE_MODE_PREG}
+};
+
+static const struct cdns_reg_pairs sgmii_100_no_ssc_plllc1_opt3_ln_regs[] = {
+ {0x688E, SIERRA_DET_STANDEC_D_PREG},
+ {0x0004, SIERRA_PSC_LN_IDLE_PREG},
+ {0x0FFE, SIERRA_PSC_RX_A0_PREG},
+ {0x0106, SIERRA_PLLCTRL_FBDIV_MODE01_PREG},
+ {0x0013, SIERRA_PLLCTRL_SUBRATE_PREG},
+ {0x0003, SIERRA_PLLCTRL_GEN_A_PREG},
+ {0x0106, SIERRA_PLLCTRL_GEN_D_PREG},
+ {0x5231, SIERRA_PLLCTRL_CPGAIN_MODE_PREG },
+ {0x0000, SIERRA_DRVCTRL_ATTEN_PREG},
+ {0x9702, SIERRA_DRVCTRL_BOOST_PREG},
+ {0x0051, SIERRA_RX_CREQ_FLTR_A_MODE0_PREG},
+ {0x3C0E, SIERRA_CREQ_CCLKDET_MODE01_PREG},
+ {0x3220, SIERRA_CREQ_FSMCLK_SEL_PREG},
+ {0x0000, SIERRA_CREQ_EQ_CTRL_PREG},
+ {0x0002, SIERRA_DEQ_PHALIGN_CTRL},
+ {0x0186, SIERRA_DEQ_GLUT0},
+ {0x0186, SIERRA_DEQ_GLUT1},
+ {0x0186, SIERRA_DEQ_GLUT2},
+ {0x0186, SIERRA_DEQ_GLUT3},
+ {0x0186, SIERRA_DEQ_GLUT4},
+ {0x0861, SIERRA_DEQ_ALUT0},
+ {0x07E0, SIERRA_DEQ_ALUT1},
+ {0x079E, SIERRA_DEQ_ALUT2},
+ {0x071D, SIERRA_DEQ_ALUT3},
+ {0x03F5, SIERRA_DEQ_DFETAP_CTRL_PREG},
+ {0x0C01, SIERRA_DEQ_TAU_CTRL1_FAST_MAINT_PREG},
+ {0x3C40, SIERRA_DEQ_TAU_CTRL1_SLOW_MAINT_PREG},
+ {0x1C04, SIERRA_DEQ_TAU_CTRL2_PREG},
+ {0x0033, SIERRA_DEQ_PICTRL_PREG},
+ {0x0000, SIERRA_CPI_OUTBUF_RATESEL_PREG},
+ {0x0B6D, SIERRA_CPI_RESBIAS_BIN_PREG},
+ {0x0102, SIERRA_RXBUFFER_CTLECTRL_PREG},
+ {0x0002, SIERRA_RXBUFFER_RCDFECTRL_PREG}
+};
+
+static struct cdns_sierra_vals sgmii_100_no_ssc_plllc1_opt3_cmn_vals = {
+ .reg_pairs = sgmii_100_no_ssc_plllc1_opt3_cmn_regs,
+ .num_regs = ARRAY_SIZE(sgmii_100_no_ssc_plllc1_opt3_cmn_regs),
+};
+
+static struct cdns_sierra_vals sgmii_100_no_ssc_plllc1_opt3_ln_vals = {
+ .reg_pairs = sgmii_100_no_ssc_plllc1_opt3_ln_regs,
+ .num_regs = ARRAY_SIZE(sgmii_100_no_ssc_plllc1_opt3_ln_regs),
+};
+
/* QSGMII PHY PMA lane configuration */
static struct cdns_reg_pairs qsgmii_phy_pma_ln_regs[] = {
{0x9010, SIERRA_PHY_PMA_XCVR_CTRL}
@@ -2363,6 +2412,11 @@ static const struct cdns_sierra_data cdns_map_sierra = {
[EXTERNAL_SSC] = &pcie_phy_pcs_cmn_vals,
[INTERNAL_SSC] = &pcie_phy_pcs_cmn_vals,
},
+ [TYPE_SGMII] = {
+ [NO_SSC] = &pcie_phy_pcs_cmn_vals,
+ [EXTERNAL_SSC] = &pcie_phy_pcs_cmn_vals,
+ [INTERNAL_SSC] = &pcie_phy_pcs_cmn_vals,
+ },
[TYPE_QSGMII] = {
[NO_SSC] = &pcie_phy_pcs_cmn_vals,
[EXTERNAL_SSC] = &pcie_phy_pcs_cmn_vals,
@@ -2377,6 +2431,11 @@ static const struct cdns_sierra_data cdns_map_sierra = {
[EXTERNAL_SSC] = &pcie_100_ext_ssc_cmn_vals,
[INTERNAL_SSC] = &pcie_100_int_ssc_cmn_vals,
},
+ [TYPE_SGMII] = {
+ [NO_SSC] = &pcie_100_no_ssc_plllc_cmn_vals,
+ [EXTERNAL_SSC] = &pcie_100_ext_ssc_plllc_cmn_vals,
+ [INTERNAL_SSC] = &pcie_100_int_ssc_plllc_cmn_vals,
+ },
[TYPE_QSGMII] = {
[NO_SSC] = &pcie_100_no_ssc_plllc_cmn_vals,
[EXTERNAL_SSC] = &pcie_100_ext_ssc_plllc_cmn_vals,
@@ -2388,6 +2447,13 @@ static const struct cdns_sierra_data cdns_map_sierra = {
[EXTERNAL_SSC] = &usb_100_ext_ssc_cmn_vals,
},
},
+ [TYPE_SGMII] = {
+ [TYPE_PCIE] = {
+ [NO_SSC] = &sgmii_100_no_ssc_plllc1_opt3_cmn_vals,
+ [EXTERNAL_SSC] = &sgmii_100_no_ssc_plllc1_opt3_cmn_vals,
+ [INTERNAL_SSC] = &sgmii_100_no_ssc_plllc1_opt3_cmn_vals,
+ },
+ },
[TYPE_QSGMII] = {
[TYPE_PCIE] = {
[NO_SSC] = &qsgmii_100_no_ssc_plllc1_cmn_vals,
@@ -2403,6 +2469,11 @@ static const struct cdns_sierra_data cdns_map_sierra = {
[EXTERNAL_SSC] = &pcie_100_ext_ssc_ln_vals,
[INTERNAL_SSC] = &pcie_100_int_ssc_ln_vals,
},
+ [TYPE_SGMII] = {
+ [NO_SSC] = &ml_pcie_100_no_ssc_ln_vals,
+ [EXTERNAL_SSC] = &ml_pcie_100_ext_ssc_ln_vals,
+ [INTERNAL_SSC] = &ml_pcie_100_int_ssc_ln_vals,
+ },
[TYPE_QSGMII] = {
[NO_SSC] = &ml_pcie_100_no_ssc_ln_vals,
[EXTERNAL_SSC] = &ml_pcie_100_ext_ssc_ln_vals,
@@ -2414,6 +2485,13 @@ static const struct cdns_sierra_data cdns_map_sierra = {
[EXTERNAL_SSC] = &usb_100_ext_ssc_ln_vals,
},
},
+ [TYPE_SGMII] = {
+ [TYPE_PCIE] = {
+ [NO_SSC] = &sgmii_100_no_ssc_plllc1_opt3_ln_vals,
+ [EXTERNAL_SSC] = &sgmii_100_no_ssc_plllc1_opt3_ln_vals,
+ [INTERNAL_SSC] = &sgmii_100_no_ssc_plllc1_opt3_ln_vals,
+ },
+ },
[TYPE_QSGMII] = {
[TYPE_PCIE] = {
[NO_SSC] = &qsgmii_100_no_ssc_plllc1_ln_vals,
@@ -2435,6 +2513,11 @@ static const struct cdns_sierra_data cdns_ti_map_sierra = {
[EXTERNAL_SSC] = &pcie_phy_pcs_cmn_vals,
[INTERNAL_SSC] = &pcie_phy_pcs_cmn_vals,
},
+ [TYPE_SGMII] = {
+ [NO_SSC] = &pcie_phy_pcs_cmn_vals,
+ [EXTERNAL_SSC] = &pcie_phy_pcs_cmn_vals,
+ [INTERNAL_SSC] = &pcie_phy_pcs_cmn_vals,
+ },
[TYPE_QSGMII] = {
[NO_SSC] = &pcie_phy_pcs_cmn_vals,
[EXTERNAL_SSC] = &pcie_phy_pcs_cmn_vals,
@@ -2443,6 +2526,13 @@ static const struct cdns_sierra_data cdns_ti_map_sierra = {
},
},
.phy_pma_ln_vals = {
+ [TYPE_SGMII] = {
+ [TYPE_PCIE] = {
+ [NO_SSC] = &sgmii_phy_pma_ln_vals,
+ [EXTERNAL_SSC] = &sgmii_phy_pma_ln_vals,
+ [INTERNAL_SSC] = &sgmii_phy_pma_ln_vals,
+ },
+ },
[TYPE_QSGMII] = {
[TYPE_PCIE] = {
[NO_SSC] = &qsgmii_phy_pma_ln_vals,
@@ -2458,6 +2548,11 @@ static const struct cdns_sierra_data cdns_ti_map_sierra = {
[EXTERNAL_SSC] = &pcie_100_ext_ssc_cmn_vals,
[INTERNAL_SSC] = &pcie_100_int_ssc_cmn_vals,
},
+ [TYPE_SGMII] = {
+ [NO_SSC] = &pcie_100_no_ssc_plllc_cmn_vals,
+ [EXTERNAL_SSC] = &pcie_100_ext_ssc_plllc_cmn_vals,
+ [INTERNAL_SSC] = &pcie_100_int_ssc_plllc_cmn_vals,
+ },
[TYPE_QSGMII] = {
[NO_SSC] = &pcie_100_no_ssc_plllc_cmn_vals,
[EXTERNAL_SSC] = &pcie_100_ext_ssc_plllc_cmn_vals,
@@ -2469,6 +2564,13 @@ static const struct cdns_sierra_data cdns_ti_map_sierra = {
[EXTERNAL_SSC] = &usb_100_ext_ssc_cmn_vals,
},
},
+ [TYPE_SGMII] = {
+ [TYPE_PCIE] = {
+ [NO_SSC] = &sgmii_100_no_ssc_plllc1_opt3_cmn_vals,
+ [EXTERNAL_SSC] = &sgmii_100_no_ssc_plllc1_opt3_cmn_vals,
+ [INTERNAL_SSC] = &sgmii_100_no_ssc_plllc1_opt3_cmn_vals,
+ },
+ },
[TYPE_QSGMII] = {
[TYPE_PCIE] = {
[NO_SSC] = &qsgmii_100_no_ssc_plllc1_cmn_vals,
@@ -2484,6 +2586,11 @@ static const struct cdns_sierra_data cdns_ti_map_sierra = {
[EXTERNAL_SSC] = &pcie_100_ext_ssc_ln_vals,
[INTERNAL_SSC] = &pcie_100_int_ssc_ln_vals,
},
+ [TYPE_SGMII] = {
+ [NO_SSC] = &ti_ml_pcie_100_no_ssc_ln_vals,
+ [EXTERNAL_SSC] = &ti_ml_pcie_100_ext_ssc_ln_vals,
+ [INTERNAL_SSC] = &ti_ml_pcie_100_int_ssc_ln_vals,
+ },
[TYPE_QSGMII] = {
[NO_SSC] = &ti_ml_pcie_100_no_ssc_ln_vals,
[EXTERNAL_SSC] = &ti_ml_pcie_100_ext_ssc_ln_vals,
@@ -2495,6 +2602,13 @@ static const struct cdns_sierra_data cdns_ti_map_sierra = {
[EXTERNAL_SSC] = &usb_100_ext_ssc_ln_vals,
},
},
+ [TYPE_SGMII] = {
+ [TYPE_PCIE] = {
+ [NO_SSC] = &sgmii_100_no_ssc_plllc1_opt3_ln_vals,
+ [EXTERNAL_SSC] = &sgmii_100_no_ssc_plllc1_opt3_ln_vals,
+ [INTERNAL_SSC] = &sgmii_100_no_ssc_plllc1_opt3_ln_vals,
+ },
+ },
[TYPE_QSGMII] = {
[TYPE_PCIE] = {
[NO_SSC] = &qsgmii_100_no_ssc_plllc1_ln_vals,
@@ -2520,7 +2634,7 @@ MODULE_DEVICE_TABLE(of, cdns_sierra_id_table);
static struct platform_driver cdns_sierra_driver = {
.probe = cdns_sierra_phy_probe,
- .remove = cdns_sierra_phy_remove,
+ .remove_new = cdns_sierra_phy_remove,
.driver = {
.name = "cdns-sierra-phy",
.of_match_table = cdns_sierra_id_table,
diff --git a/drivers/phy/cadence/phy-cadence-torrent.c b/drivers/phy/cadence/phy-cadence-torrent.c
index f099053c583c..3831f596d50c 100644
--- a/drivers/phy/cadence/phy-cadence-torrent.c
+++ b/drivers/phy/cadence/phy-cadence-torrent.c
@@ -2777,7 +2777,7 @@ clk_cleanup:
return ret;
}
-static int cdns_torrent_phy_remove(struct platform_device *pdev)
+static void cdns_torrent_phy_remove(struct platform_device *pdev)
{
struct cdns_torrent_phy *cdns_phy = platform_get_drvdata(pdev);
int i;
@@ -2791,8 +2791,6 @@ static int cdns_torrent_phy_remove(struct platform_device *pdev)
clk_disable_unprepare(cdns_phy->clk);
cdns_torrent_clk_cleanup(cdns_phy);
-
- return 0;
}
/* Single DisplayPort(DP) link configuration */
@@ -4708,7 +4706,7 @@ MODULE_DEVICE_TABLE(of, cdns_torrent_phy_of_match);
static struct platform_driver cdns_torrent_phy_driver = {
.probe = cdns_torrent_phy_probe,
- .remove = cdns_torrent_phy_remove,
+ .remove_new = cdns_torrent_phy_remove,
.driver = {
.name = "cdns-torrent-phy",
.of_match_table = cdns_torrent_phy_of_match,
diff --git a/drivers/phy/freescale/phy-fsl-imx8qm-lvds-phy.c b/drivers/phy/freescale/phy-fsl-imx8qm-lvds-phy.c
index e514b64bfdab..0ae052df3765 100644
--- a/drivers/phy/freescale/phy-fsl-imx8qm-lvds-phy.c
+++ b/drivers/phy/freescale/phy-fsl-imx8qm-lvds-phy.c
@@ -391,11 +391,9 @@ err:
return ret;
}
-static int mixel_lvds_phy_remove(struct platform_device *pdev)
+static void mixel_lvds_phy_remove(struct platform_device *pdev)
{
pm_runtime_disable(&pdev->dev);
-
- return 0;
}
static int __maybe_unused mixel_lvds_phy_runtime_suspend(struct device *dev)
@@ -436,7 +434,7 @@ MODULE_DEVICE_TABLE(of, mixel_lvds_phy_of_match);
static struct platform_driver mixel_lvds_phy_driver = {
.probe = mixel_lvds_phy_probe,
- .remove = mixel_lvds_phy_remove,
+ .remove_new = mixel_lvds_phy_remove,
.driver = {
.pm = &mixel_lvds_phy_pm_ops,
.name = "mixel-lvds-phy",
diff --git a/drivers/phy/intel/Kconfig b/drivers/phy/intel/Kconfig
index 18a3cc5b98c0..ac42bb2fb394 100644
--- a/drivers/phy/intel/Kconfig
+++ b/drivers/phy/intel/Kconfig
@@ -46,13 +46,3 @@ config PHY_INTEL_LGM_EMMC
select GENERIC_PHY
help
Enable this to support the Intel EMMC PHY
-
-config PHY_INTEL_THUNDERBAY_EMMC
- tristate "Intel Thunder Bay eMMC PHY driver"
- depends on OF && (ARCH_THUNDERBAY || COMPILE_TEST)
- select GENERIC_PHY
- help
- This option enables support for Intel Thunder Bay SoC eMMC PHY.
-
- To compile this driver as a module, choose M here: the module
- will be called phy-intel-thunderbay-emmc.ko.
diff --git a/drivers/phy/intel/Makefile b/drivers/phy/intel/Makefile
index b7321d56b0bb..14550981a707 100644
--- a/drivers/phy/intel/Makefile
+++ b/drivers/phy/intel/Makefile
@@ -3,4 +3,3 @@ obj-$(CONFIG_PHY_INTEL_KEEMBAY_EMMC) += phy-intel-keembay-emmc.o
obj-$(CONFIG_PHY_INTEL_KEEMBAY_USB) += phy-intel-keembay-usb.o
obj-$(CONFIG_PHY_INTEL_LGM_COMBO) += phy-intel-lgm-combo.o
obj-$(CONFIG_PHY_INTEL_LGM_EMMC) += phy-intel-lgm-emmc.o
-obj-$(CONFIG_PHY_INTEL_THUNDERBAY_EMMC) += phy-intel-thunderbay-emmc.o
diff --git a/drivers/phy/intel/phy-intel-lgm-combo.c b/drivers/phy/intel/phy-intel-lgm-combo.c
index 8c764c457c1c..d32e267c0001 100644
--- a/drivers/phy/intel/phy-intel-lgm-combo.c
+++ b/drivers/phy/intel/phy-intel-lgm-combo.c
@@ -589,13 +589,12 @@ static int intel_cbphy_probe(struct platform_device *pdev)
return intel_cbphy_create(cbphy);
}
-static int intel_cbphy_remove(struct platform_device *pdev)
+static void intel_cbphy_remove(struct platform_device *pdev)
{
struct intel_combo_phy *cbphy = platform_get_drvdata(pdev);
intel_cbphy_rst_assert(cbphy);
clk_disable_unprepare(cbphy->core_clk);
- return 0;
}
static const struct of_device_id of_intel_cbphy_match[] = {
@@ -606,7 +605,7 @@ static const struct of_device_id of_intel_cbphy_match[] = {
static struct platform_driver intel_cbphy_driver = {
.probe = intel_cbphy_probe,
- .remove = intel_cbphy_remove,
+ .remove_new = intel_cbphy_remove,
.driver = {
.name = "intel-combo-phy",
.of_match_table = of_intel_cbphy_match,
diff --git a/drivers/phy/intel/phy-intel-thunderbay-emmc.c b/drivers/phy/intel/phy-intel-thunderbay-emmc.c
deleted file mode 100644
index 593f6970b81e..000000000000
--- a/drivers/phy/intel/phy-intel-thunderbay-emmc.c
+++ /dev/null
@@ -1,509 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Intel ThunderBay eMMC PHY driver
- *
- * Copyright (C) 2021 Intel Corporation
- *
- */
-
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/iopoll.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/phy/phy.h>
-#include <linux/platform_device.h>
-
-/* eMMC/SD/SDIO core/phy configuration registers */
-#define CTRL_CFG_0 0x00
-#define CTRL_CFG_1 0x04
-#define CTRL_PRESET_0 0x08
-#define CTRL_PRESET_1 0x0c
-#define CTRL_PRESET_2 0x10
-#define CTRL_PRESET_3 0x14
-#define CTRL_PRESET_4 0x18
-#define CTRL_CFG_2 0x1c
-#define CTRL_CFG_3 0x20
-#define PHY_CFG_0 0x24
-#define PHY_CFG_1 0x28
-#define PHY_CFG_2 0x2c
-#define PHYBIST_CTRL 0x30
-#define SDHC_STAT3 0x34
-#define PHY_STAT 0x38
-#define PHYBIST_STAT_0 0x3c
-#define PHYBIST_STAT_1 0x40
-#define EMMC_AXI 0x44
-
-/* CTRL_PRESET_3 */
-#define CTRL_PRESET3_MASK GENMASK(31, 0)
-#define CTRL_PRESET3_SHIFT 0
-
-/* CTRL_CFG_0 bit fields */
-#define SUPPORT_HS_MASK BIT(26)
-#define SUPPORT_HS_SHIFT 26
-
-#define SUPPORT_8B_MASK BIT(24)
-#define SUPPORT_8B_SHIFT 24
-
-/* CTRL_CFG_1 bit fields */
-#define SUPPORT_SDR50_MASK BIT(28)
-#define SUPPORT_SDR50_SHIFT 28
-#define SLOT_TYPE_MASK GENMASK(27, 26)
-#define SLOT_TYPE_OFFSET 26
-#define SUPPORT_64B_MASK BIT(24)
-#define SUPPORT_64B_SHIFT 24
-#define SUPPORT_HS400_MASK BIT(2)
-#define SUPPORT_HS400_SHIFT 2
-#define SUPPORT_DDR50_MASK BIT(1)
-#define SUPPORT_DDR50_SHIFT 1
-#define SUPPORT_SDR104_MASK BIT(0)
-#define SUPPORT_SDR104_SHIFT 0
-
-/* PHY_CFG_0 bit fields */
-#define SEL_DLY_TXCLK_MASK BIT(29)
-#define SEL_DLY_TXCLK_SHIFT 29
-#define SEL_DLY_RXCLK_MASK BIT(28)
-#define SEL_DLY_RXCLK_SHIFT 28
-
-#define OTAP_DLY_ENA_MASK BIT(27)
-#define OTAP_DLY_ENA_SHIFT 27
-#define OTAP_DLY_SEL_MASK GENMASK(26, 23)
-#define OTAP_DLY_SEL_SHIFT 23
-#define ITAP_CHG_WIN_MASK BIT(22)
-#define ITAP_CHG_WIN_SHIFT 22
-#define ITAP_DLY_ENA_MASK BIT(21)
-#define ITAP_DLY_ENA_SHIFT 21
-#define ITAP_DLY_SEL_MASK GENMASK(20, 16)
-#define ITAP_DLY_SEL_SHIFT 16
-#define RET_ENB_MASK BIT(15)
-#define RET_ENB_SHIFT 15
-#define RET_EN_MASK BIT(14)
-#define RET_EN_SHIFT 14
-#define DLL_IFF_MASK GENMASK(13, 11)
-#define DLL_IFF_SHIFT 11
-#define DLL_EN_MASK BIT(10)
-#define DLL_EN_SHIFT 10
-#define DLL_TRIM_ICP_MASK GENMASK(9, 6)
-#define DLL_TRIM_ICP_SHIFT 6
-#define RETRIM_EN_MASK BIT(5)
-#define RETRIM_EN_SHIFT 5
-#define RETRIM_MASK BIT(4)
-#define RETRIM_SHIFT 4
-#define DR_TY_MASK GENMASK(3, 1)
-#define DR_TY_SHIFT 1
-#define PWR_DOWN_MASK BIT(0)
-#define PWR_DOWN_SHIFT 0
-
-/* PHY_CFG_1 bit fields */
-#define REN_DAT_MASK GENMASK(19, 12)
-#define REN_DAT_SHIFT 12
-#define REN_CMD_MASK BIT(11)
-#define REN_CMD_SHIFT 11
-#define REN_STRB_MASK BIT(10)
-#define REN_STRB_SHIFT 10
-#define PU_STRB_MASK BIT(20)
-#define PU_STRB_SHIFT 20
-
-/* PHY_CFG_2 bit fields */
-#define CLKBUF_MASK GENMASK(24, 21)
-#define CLKBUF_SHIFT 21
-#define SEL_STRB_MASK GENMASK(20, 13)
-#define SEL_STRB_SHIFT 13
-#define SEL_FREQ_MASK GENMASK(12, 10)
-#define SEL_FREQ_SHIFT 10
-
-/* PHY_STAT bit fields */
-#define CAL_DONE BIT(6)
-#define DLL_RDY BIT(5)
-
-#define OTAP_DLY 0x0
-#define ITAP_DLY 0x0
-#define STRB 0x33
-
-/* From ACS_eMMC51_16nFFC_RO1100_Userguide_v1p0.pdf p17 */
-#define FREQSEL_200M_170M 0x0
-#define FREQSEL_170M_140M 0x1
-#define FREQSEL_140M_110M 0x2
-#define FREQSEL_110M_80M 0x3
-#define FREQSEL_80M_50M 0x4
-#define FREQSEL_275M_250M 0x5
-#define FREQSEL_250M_225M 0x6
-#define FREQSEL_225M_200M 0x7
-
-/* Phy power status */
-#define PHY_UNINITIALIZED 0
-#define PHY_INITIALIZED 1
-
-/*
- * During init(400KHz) phy_settings will be called with 200MHZ clock
- * To avoid incorrectly setting the phy for init(400KHZ) "phy_power_sts" is used.
- * When actual clock is set always phy is powered off once and then powered on.
- * (sdhci_arasan_set_clock). That feature will be used to identify whether the
- * settings are for init phy_power_on or actual clock phy_power_on
- * 0 --> init settings
- * 1 --> actual settings
- */
-
-struct thunderbay_emmc_phy {
- void __iomem *reg_base;
- struct clk *emmcclk;
- int phy_power_sts;
-};
-
-static inline void update_reg(struct thunderbay_emmc_phy *tbh_phy, u32 offset,
- u32 mask, u32 shift, u32 val)
-{
- u32 tmp;
-
- tmp = readl(tbh_phy->reg_base + offset);
- tmp &= ~mask;
- tmp |= val << shift;
- writel(tmp, tbh_phy->reg_base + offset);
-}
-
-static int thunderbay_emmc_phy_power(struct phy *phy, bool power_on)
-{
- struct thunderbay_emmc_phy *tbh_phy = phy_get_drvdata(phy);
- unsigned int freqsel = FREQSEL_200M_170M;
- unsigned long rate;
- static int lock;
- u32 val;
- int ret;
-
- /* Disable DLL */
- rate = clk_get_rate(tbh_phy->emmcclk);
- switch (rate) {
- case 200000000:
- /* lock dll only when it is used, i.e only if SEL_DLY_TXCLK/RXCLK are 0 */
- update_reg(tbh_phy, PHY_CFG_0, DLL_EN_MASK, DLL_EN_SHIFT, 0x0);
- break;
-
- /* dll lock not required for other frequencies */
- case 50000000 ... 52000000:
- case 400000:
- default:
- break;
- }
-
- if (!power_on)
- return 0;
-
- rate = clk_get_rate(tbh_phy->emmcclk);
- switch (rate) {
- case 170000001 ... 200000000:
- freqsel = FREQSEL_200M_170M;
- break;
-
- case 140000001 ... 170000000:
- freqsel = FREQSEL_170M_140M;
- break;
-
- case 110000001 ... 140000000:
- freqsel = FREQSEL_140M_110M;
- break;
-
- case 80000001 ... 110000000:
- freqsel = FREQSEL_110M_80M;
- break;
-
- case 50000000 ... 80000000:
- freqsel = FREQSEL_80M_50M;
- break;
-
- case 250000001 ... 275000000:
- freqsel = FREQSEL_275M_250M;
- break;
-
- case 225000001 ... 250000000:
- freqsel = FREQSEL_250M_225M;
- break;
-
- case 200000001 ... 225000000:
- freqsel = FREQSEL_225M_200M;
- break;
- default:
- break;
- }
- /* Clock rate is checked against upper limit. It may fall low during init */
- if (rate > 200000000)
- dev_warn(&phy->dev, "Unsupported rate: %lu\n", rate);
-
- udelay(5);
-
- if (lock == 0) {
- /* PDB will be done only once per boot */
- update_reg(tbh_phy, PHY_CFG_0, PWR_DOWN_MASK,
- PWR_DOWN_SHIFT, 0x1);
- lock = 1;
- /*
- * According to the user manual, it asks driver to wait 5us for
- * calpad busy trimming. However it is documented that this value is
- * PVT(A.K.A. process, voltage and temperature) relevant, so some
- * failure cases are found which indicates we should be more tolerant
- * to calpad busy trimming.
- */
- ret = readl_poll_timeout(tbh_phy->reg_base + PHY_STAT,
- val, (val & CAL_DONE), 10, 50);
- if (ret) {
- dev_err(&phy->dev, "caldone failed, ret=%d\n", ret);
- return ret;
- }
- }
- rate = clk_get_rate(tbh_phy->emmcclk);
- switch (rate) {
- case 200000000:
- /* Set frequency of the DLL operation */
- update_reg(tbh_phy, PHY_CFG_2, SEL_FREQ_MASK, SEL_FREQ_SHIFT, freqsel);
-
- /* Enable DLL */
- update_reg(tbh_phy, PHY_CFG_0, DLL_EN_MASK, DLL_EN_SHIFT, 0x1);
-
- /*
- * After enabling analog DLL circuits docs say that we need 10.2 us if
- * our source clock is at 50 MHz and that lock time scales linearly
- * with clock speed. If we are powering on the PHY and the card clock
- * is super slow (like 100kHz) this could take as long as 5.1 ms as
- * per the math: 10.2 us * (50000000 Hz / 100000 Hz) => 5.1 ms
- * hopefully we won't be running at 100 kHz, but we should still make
- * sure we wait long enough.
- *
- * NOTE: There appear to be corner cases where the DLL seems to take
- * extra long to lock for reasons that aren't understood. In some
- * extreme cases we've seen it take up to over 10ms (!). We'll be
- * generous and give it 50ms.
- */
- ret = readl_poll_timeout(tbh_phy->reg_base + PHY_STAT,
- val, (val & DLL_RDY), 10, 50 * USEC_PER_MSEC);
- if (ret) {
- dev_err(&phy->dev, "dllrdy failed, ret=%d\n", ret);
- return ret;
- }
- break;
-
- default:
- break;
- }
- return 0;
-}
-
-static int thunderbay_emmc_phy_init(struct phy *phy)
-{
- struct thunderbay_emmc_phy *tbh_phy = phy_get_drvdata(phy);
-
- tbh_phy->emmcclk = clk_get(&phy->dev, "emmcclk");
-
- return PTR_ERR_OR_ZERO(tbh_phy->emmcclk);
-}
-
-static int thunderbay_emmc_phy_exit(struct phy *phy)
-{
- struct thunderbay_emmc_phy *tbh_phy = phy_get_drvdata(phy);
-
- clk_put(tbh_phy->emmcclk);
-
- return 0;
-}
-
-static int thunderbay_emmc_phy_power_on(struct phy *phy)
-{
- struct thunderbay_emmc_phy *tbh_phy = phy_get_drvdata(phy);
- unsigned long rate;
-
- /* Overwrite capability bits configurable in bootloader */
- update_reg(tbh_phy, CTRL_CFG_0,
- SUPPORT_HS_MASK, SUPPORT_HS_SHIFT, 0x1);
- update_reg(tbh_phy, CTRL_CFG_0,
- SUPPORT_8B_MASK, SUPPORT_8B_SHIFT, 0x1);
- update_reg(tbh_phy, CTRL_CFG_1,
- SUPPORT_SDR50_MASK, SUPPORT_SDR50_SHIFT, 0x1);
- update_reg(tbh_phy, CTRL_CFG_1,
- SUPPORT_DDR50_MASK, SUPPORT_DDR50_SHIFT, 0x1);
- update_reg(tbh_phy, CTRL_CFG_1,
- SUPPORT_SDR104_MASK, SUPPORT_SDR104_SHIFT, 0x1);
- update_reg(tbh_phy, CTRL_CFG_1,
- SUPPORT_HS400_MASK, SUPPORT_HS400_SHIFT, 0x1);
- update_reg(tbh_phy, CTRL_CFG_1,
- SUPPORT_64B_MASK, SUPPORT_64B_SHIFT, 0x1);
-
- if (tbh_phy->phy_power_sts == PHY_UNINITIALIZED) {
- /* Indicates initialization, settings for init, same as 400KHZ setting */
- update_reg(tbh_phy, PHY_CFG_0, SEL_DLY_TXCLK_MASK, SEL_DLY_TXCLK_SHIFT, 0x1);
- update_reg(tbh_phy, PHY_CFG_0, SEL_DLY_RXCLK_MASK, SEL_DLY_RXCLK_SHIFT, 0x1);
- update_reg(tbh_phy, PHY_CFG_0, ITAP_DLY_ENA_MASK, ITAP_DLY_ENA_SHIFT, 0x0);
- update_reg(tbh_phy, PHY_CFG_0, ITAP_DLY_SEL_MASK, ITAP_DLY_SEL_SHIFT, 0x0);
- update_reg(tbh_phy, PHY_CFG_0, OTAP_DLY_ENA_MASK, OTAP_DLY_ENA_SHIFT, 0x0);
- update_reg(tbh_phy, PHY_CFG_0, OTAP_DLY_SEL_MASK, OTAP_DLY_SEL_SHIFT, 0);
- update_reg(tbh_phy, PHY_CFG_0, DLL_TRIM_ICP_MASK, DLL_TRIM_ICP_SHIFT, 0);
- update_reg(tbh_phy, PHY_CFG_0, DR_TY_MASK, DR_TY_SHIFT, 0x1);
-
- } else if (tbh_phy->phy_power_sts == PHY_INITIALIZED) {
- /* Indicates actual clock setting */
- rate = clk_get_rate(tbh_phy->emmcclk);
- switch (rate) {
- case 200000000:
- update_reg(tbh_phy, PHY_CFG_0, SEL_DLY_TXCLK_MASK,
- SEL_DLY_TXCLK_SHIFT, 0x0);
- update_reg(tbh_phy, PHY_CFG_0, SEL_DLY_RXCLK_MASK,
- SEL_DLY_RXCLK_SHIFT, 0x0);
- update_reg(tbh_phy, PHY_CFG_0, ITAP_DLY_ENA_MASK,
- ITAP_DLY_ENA_SHIFT, 0x0);
- update_reg(tbh_phy, PHY_CFG_0, ITAP_DLY_SEL_MASK,
- ITAP_DLY_SEL_SHIFT, 0x0);
- update_reg(tbh_phy, PHY_CFG_0, OTAP_DLY_ENA_MASK,
- OTAP_DLY_ENA_SHIFT, 0x1);
- update_reg(tbh_phy, PHY_CFG_0, OTAP_DLY_SEL_MASK,
- OTAP_DLY_SEL_SHIFT, 2);
- update_reg(tbh_phy, PHY_CFG_0, DLL_TRIM_ICP_MASK,
- DLL_TRIM_ICP_SHIFT, 0x8);
- update_reg(tbh_phy, PHY_CFG_0, DR_TY_MASK,
- DR_TY_SHIFT, 0x1);
- /* For HS400 only */
- update_reg(tbh_phy, PHY_CFG_2, SEL_STRB_MASK,
- SEL_STRB_SHIFT, STRB);
- break;
-
- case 50000000 ... 52000000:
- /* For both HS and DDR52 this setting works */
- update_reg(tbh_phy, PHY_CFG_0, SEL_DLY_TXCLK_MASK,
- SEL_DLY_TXCLK_SHIFT, 0x1);
- update_reg(tbh_phy, PHY_CFG_0, SEL_DLY_RXCLK_MASK,
- SEL_DLY_RXCLK_SHIFT, 0x1);
- update_reg(tbh_phy, PHY_CFG_0, ITAP_DLY_ENA_MASK,
- ITAP_DLY_ENA_SHIFT, 0x0);
- update_reg(tbh_phy, PHY_CFG_0, ITAP_DLY_SEL_MASK,
- ITAP_DLY_SEL_SHIFT, 0x0);
- update_reg(tbh_phy, PHY_CFG_0, OTAP_DLY_ENA_MASK,
- OTAP_DLY_ENA_SHIFT, 0x1);
- update_reg(tbh_phy, PHY_CFG_0, OTAP_DLY_SEL_MASK,
- OTAP_DLY_SEL_SHIFT, 4);
- update_reg(tbh_phy, PHY_CFG_0, DLL_TRIM_ICP_MASK,
- DLL_TRIM_ICP_SHIFT, 0x8);
- update_reg(tbh_phy, PHY_CFG_0,
- DR_TY_MASK, DR_TY_SHIFT, 0x1);
- break;
-
- case 400000:
- update_reg(tbh_phy, PHY_CFG_0, SEL_DLY_TXCLK_MASK,
- SEL_DLY_TXCLK_SHIFT, 0x1);
- update_reg(tbh_phy, PHY_CFG_0, SEL_DLY_RXCLK_MASK,
- SEL_DLY_RXCLK_SHIFT, 0x1);
- update_reg(tbh_phy, PHY_CFG_0, ITAP_DLY_ENA_MASK,
- ITAP_DLY_ENA_SHIFT, 0x0);
- update_reg(tbh_phy, PHY_CFG_0, ITAP_DLY_SEL_MASK,
- ITAP_DLY_SEL_SHIFT, 0x0);
- update_reg(tbh_phy, PHY_CFG_0, OTAP_DLY_ENA_MASK,
- OTAP_DLY_ENA_SHIFT, 0x0);
- update_reg(tbh_phy, PHY_CFG_0, OTAP_DLY_SEL_MASK,
- OTAP_DLY_SEL_SHIFT, 0);
- update_reg(tbh_phy, PHY_CFG_0, DLL_TRIM_ICP_MASK,
- DLL_TRIM_ICP_SHIFT, 0);
- update_reg(tbh_phy, PHY_CFG_0, DR_TY_MASK, DR_TY_SHIFT, 0x1);
- break;
-
- default:
- update_reg(tbh_phy, PHY_CFG_0, SEL_DLY_TXCLK_MASK,
- SEL_DLY_TXCLK_SHIFT, 0x1);
- update_reg(tbh_phy, PHY_CFG_0, SEL_DLY_RXCLK_MASK,
- SEL_DLY_RXCLK_SHIFT, 0x1);
- update_reg(tbh_phy, PHY_CFG_0, ITAP_DLY_ENA_MASK,
- ITAP_DLY_ENA_SHIFT, 0x0);
- update_reg(tbh_phy, PHY_CFG_0, ITAP_DLY_SEL_MASK,
- ITAP_DLY_SEL_SHIFT, 0x0);
- update_reg(tbh_phy, PHY_CFG_0, OTAP_DLY_ENA_MASK,
- OTAP_DLY_ENA_SHIFT, 0x1);
- update_reg(tbh_phy, PHY_CFG_0, OTAP_DLY_SEL_MASK,
- OTAP_DLY_SEL_SHIFT, 2);
- update_reg(tbh_phy, PHY_CFG_0, DLL_TRIM_ICP_MASK,
- DLL_TRIM_ICP_SHIFT, 0x8);
- update_reg(tbh_phy, PHY_CFG_0, DR_TY_MASK,
- DR_TY_SHIFT, 0x1);
- break;
- }
- /* Reset, init seq called without phy_power_off, this indicates init seq */
- tbh_phy->phy_power_sts = PHY_UNINITIALIZED;
- }
-
- update_reg(tbh_phy, PHY_CFG_0, RETRIM_EN_MASK, RETRIM_EN_SHIFT, 0x1);
- update_reg(tbh_phy, PHY_CFG_0, RETRIM_MASK, RETRIM_SHIFT, 0x0);
-
- return thunderbay_emmc_phy_power(phy, 1);
-}
-
-static int thunderbay_emmc_phy_power_off(struct phy *phy)
-{
- struct thunderbay_emmc_phy *tbh_phy = phy_get_drvdata(phy);
-
- tbh_phy->phy_power_sts = PHY_INITIALIZED;
-
- return thunderbay_emmc_phy_power(phy, 0);
-}
-
-static const struct phy_ops thunderbay_emmc_phy_ops = {
- .init = thunderbay_emmc_phy_init,
- .exit = thunderbay_emmc_phy_exit,
- .power_on = thunderbay_emmc_phy_power_on,
- .power_off = thunderbay_emmc_phy_power_off,
- .owner = THIS_MODULE,
-};
-
-static const struct of_device_id thunderbay_emmc_phy_of_match[] = {
- { .compatible = "intel,thunderbay-emmc-phy",
- (void *)&thunderbay_emmc_phy_ops },
- {}
-};
-MODULE_DEVICE_TABLE(of, thunderbay_emmc_phy_of_match);
-
-static int thunderbay_emmc_phy_probe(struct platform_device *pdev)
-{
- struct thunderbay_emmc_phy *tbh_phy;
- struct phy_provider *phy_provider;
- struct device *dev = &pdev->dev;
- const struct of_device_id *id;
- struct phy *generic_phy;
- struct resource *res;
-
- if (!dev->of_node)
- return -ENODEV;
-
- tbh_phy = devm_kzalloc(dev, sizeof(*tbh_phy), GFP_KERNEL);
- if (!tbh_phy)
- return -ENOMEM;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- tbh_phy->reg_base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(tbh_phy->reg_base))
- return PTR_ERR(tbh_phy->reg_base);
-
- tbh_phy->phy_power_sts = PHY_UNINITIALIZED;
- id = of_match_node(thunderbay_emmc_phy_of_match, pdev->dev.of_node);
- if (!id) {
- dev_err(dev, "failed to get match_node\n");
- return -EINVAL;
- }
-
- generic_phy = devm_phy_create(dev, dev->of_node, id->data);
- if (IS_ERR(generic_phy)) {
- dev_err(dev, "failed to create PHY\n");
- return PTR_ERR(generic_phy);
- }
-
- phy_set_drvdata(generic_phy, tbh_phy);
- phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
-
- return PTR_ERR_OR_ZERO(phy_provider);
-}
-
-static struct platform_driver thunderbay_emmc_phy_driver = {
- .probe = thunderbay_emmc_phy_probe,
- .driver = {
- .name = "thunderbay-emmc-phy",
- .of_match_table = thunderbay_emmc_phy_of_match,
- },
-};
-module_platform_driver(thunderbay_emmc_phy_driver);
-
-MODULE_AUTHOR("Nandhini S <nandhini.srikandan@intel.com>");
-MODULE_AUTHOR("Rashmi A <rashmi.a@intel.com>");
-MODULE_DESCRIPTION("Intel Thunder Bay eMMC PHY driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/marvell/phy-pxa-28nm-hsic.c b/drivers/phy/marvell/phy-pxa-28nm-hsic.c
index c5c100563f55..eff6dd6b2dd0 100644
--- a/drivers/phy/marvell/phy-pxa-28nm-hsic.c
+++ b/drivers/phy/marvell/phy-pxa-28nm-hsic.c
@@ -199,7 +199,7 @@ static struct platform_driver mv_hsic_phy_driver = {
.probe = mv_hsic_phy_probe,
.driver = {
.name = "mv-hsic-phy",
- .of_match_table = of_match_ptr(mv_hsic_phy_dt_match),
+ .of_match_table = mv_hsic_phy_dt_match,
},
};
module_platform_driver(mv_hsic_phy_driver);
diff --git a/drivers/phy/marvell/phy-pxa-28nm-usb2.c b/drivers/phy/marvell/phy-pxa-28nm-usb2.c
index 0b390b9d2ae1..1b2107f80f3a 100644
--- a/drivers/phy/marvell/phy-pxa-28nm-usb2.c
+++ b/drivers/phy/marvell/phy-pxa-28nm-usb2.c
@@ -331,7 +331,7 @@ static struct platform_driver mv_usb2_phy_driver = {
.probe = mv_usb2_phy_probe,
.driver = {
.name = "mv-usb2-phy",
- .of_match_table = of_match_ptr(mv_usbphy_dt_match),
+ .of_match_table = mv_usbphy_dt_match,
},
};
module_platform_driver(mv_usb2_phy_driver);
diff --git a/drivers/phy/mediatek/Makefile b/drivers/phy/mediatek/Makefile
index fb1f8edaffa7..c9a50395533e 100644
--- a/drivers/phy/mediatek/Makefile
+++ b/drivers/phy/mediatek/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_PHY_MTK_XSPHY) += phy-mtk-xsphy.o
phy-mtk-hdmi-drv-y := phy-mtk-hdmi.o
phy-mtk-hdmi-drv-y += phy-mtk-hdmi-mt2701.o
phy-mtk-hdmi-drv-y += phy-mtk-hdmi-mt8173.o
+phy-mtk-hdmi-drv-y += phy-mtk-hdmi-mt8195.o
obj-$(CONFIG_PHY_MTK_HDMI) += phy-mtk-hdmi-drv.o
phy-mtk-mipi-dsi-drv-y := phy-mtk-mipi-dsi.o
diff --git a/drivers/phy/mediatek/phy-mtk-hdmi-mt8195.c b/drivers/phy/mediatek/phy-mtk-hdmi-mt8195.c
new file mode 100644
index 000000000000..abfc077fb0a8
--- /dev/null
+++ b/drivers/phy/mediatek/phy-mtk-hdmi-mt8195.c
@@ -0,0 +1,495 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ * Copyright (c) 2022 BayLibre, SAS
+ */
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <linux/units.h>
+#include <linux/nvmem-consumer.h>
+
+#include "phy-mtk-io.h"
+#include "phy-mtk-hdmi.h"
+#include "phy-mtk-hdmi-mt8195.h"
+
+static void mtk_hdmi_ana_fifo_en(struct mtk_hdmi_phy *hdmi_phy)
+{
+ /* make data fifo writable for hdmi2.0 */
+ mtk_phy_set_bits(hdmi_phy->regs + HDMI_ANA_CTL, REG_ANA_HDMI20_FIFO_EN);
+}
+
+static void
+mtk_phy_tmds_clk_ratio(struct mtk_hdmi_phy *hdmi_phy, bool enable)
+{
+ void __iomem *regs = hdmi_phy->regs;
+
+ mtk_hdmi_ana_fifo_en(hdmi_phy);
+
+ /* HDMI 2.0 specification, 3.4Gbps <= TMDS Bit Rate <= 6G,
+ * clock bit ratio 1:40, under 3.4Gbps, clock bit ratio 1:10
+ */
+ if (enable)
+ mtk_phy_update_field(regs + HDMI20_CLK_CFG, REG_TXC_DIV, 3);
+ else
+ mtk_phy_clear_bits(regs + HDMI20_CLK_CFG, REG_TXC_DIV);
+}
+
+static void mtk_hdmi_pll_sel_src(struct clk_hw *hw)
+{
+ struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw);
+ void __iomem *regs = hdmi_phy->regs;
+
+ mtk_phy_clear_bits(regs + HDMI_CTL_3, REG_HDMITX_REF_XTAL_SEL);
+ mtk_phy_clear_bits(regs + HDMI_CTL_3, REG_HDMITX_REF_RESPLL_SEL);
+
+ /* DA_HDMITX21_REF_CK for TXPLL input source */
+ mtk_phy_clear_bits(regs + HDMI_1_CFG_10, RG_HDMITXPLL_REF_CK_SEL);
+}
+
+static void mtk_hdmi_pll_perf(struct clk_hw *hw)
+{
+ struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw);
+ void __iomem *regs = hdmi_phy->regs;
+
+ mtk_phy_set_bits(regs + HDMI_1_PLL_CFG_0, RG_HDMITXPLL_BP2);
+ mtk_phy_set_bits(regs + HDMI_1_PLL_CFG_2, RG_HDMITXPLL_BC);
+ mtk_phy_update_field(regs + HDMI_1_PLL_CFG_2, RG_HDMITXPLL_IC, 0x1);
+ mtk_phy_update_field(regs + HDMI_1_PLL_CFG_2, RG_HDMITXPLL_BR, 0x2);
+ mtk_phy_update_field(regs + HDMI_1_PLL_CFG_2, RG_HDMITXPLL_IR, 0x2);
+ mtk_phy_set_bits(regs + HDMI_1_PLL_CFG_2, RG_HDMITXPLL_BP);
+ mtk_phy_clear_bits(regs + HDMI_1_PLL_CFG_0, RG_HDMITXPLL_IBAND_FIX_EN);
+ mtk_phy_clear_bits(regs + HDMI_1_PLL_CFG_1, RG_HDMITXPLL_RESERVE_BIT14);
+ mtk_phy_clear_bits(regs + HDMI_1_PLL_CFG_2, RG_HDMITXPLL_HIKVCO);
+ mtk_phy_update_field(regs + HDMI_1_PLL_CFG_0, RG_HDMITXPLL_HREN, 0x1);
+ mtk_phy_update_field(regs + HDMI_1_PLL_CFG_0, RG_HDMITXPLL_LVR_SEL, 0x1);
+ mtk_phy_set_bits(regs + HDMI_1_PLL_CFG_1, RG_HDMITXPLL_RESERVE_BIT12_11);
+ mtk_phy_set_bits(regs + HDMI_1_PLL_CFG_0, RG_HDMITXPLL_TCL_EN);
+}
+
+static int mtk_hdmi_pll_set_hw(struct clk_hw *hw, u8 prediv,
+ u8 fbkdiv_high,
+ u32 fbkdiv_low,
+ u8 fbkdiv_hs3, u8 posdiv1,
+ u8 posdiv2, u8 txprediv,
+ u8 txposdiv,
+ u8 digital_div)
+{
+ u8 txposdiv_value;
+ u8 div3_ctrl_value;
+ u8 posdiv_vallue;
+ u8 div_ctrl_value;
+ u8 reserve_3_2_value;
+ u8 prediv_value;
+ u8 reserve13_value;
+ struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw);
+ void __iomem *regs = hdmi_phy->regs;
+
+ mtk_hdmi_pll_sel_src(hw);
+
+ mtk_hdmi_pll_perf(hw);
+
+ mtk_phy_update_field(regs + HDMI_1_CFG_10, RG_HDMITX21_BIAS_PE_BG_VREF_SEL, 0x2);
+ mtk_phy_clear_bits(regs + HDMI_1_CFG_10, RG_HDMITX21_VREF_SEL);
+ mtk_phy_update_field(regs + HDMI_1_CFG_9, RG_HDMITX21_SLDO_VREF_SEL, 0x2);
+ mtk_phy_clear_bits(regs + HDMI_1_CFG_10, RG_HDMITX21_BIAS_PE_VREF_SELB);
+ mtk_phy_set_bits(regs + HDMI_1_CFG_3, RG_HDMITX21_SLDOLPF_EN);
+ mtk_phy_update_field(regs + HDMI_1_CFG_6, RG_HDMITX21_INTR_CAL, 0x11);
+ mtk_phy_set_bits(regs + HDMI_1_PLL_CFG_2, RG_HDMITXPLL_PWD);
+
+ /* TXPOSDIV */
+ txposdiv_value = ilog2(txposdiv);
+
+ mtk_phy_update_field(regs + HDMI_1_CFG_6, RG_HDMITX21_TX_POSDIV, txposdiv_value);
+ mtk_phy_set_bits(regs + HDMI_1_CFG_6, RG_HDMITX21_TX_POSDIV_EN);
+ mtk_phy_clear_bits(regs + HDMI_1_CFG_6, RG_HDMITX21_FRL_EN);
+
+ /* TXPREDIV */
+ switch (txprediv) {
+ case 2:
+ div3_ctrl_value = 0x0;
+ posdiv_vallue = 0x0;
+ break;
+ case 4:
+ div3_ctrl_value = 0x0;
+ posdiv_vallue = 0x1;
+ break;
+ case 6:
+ div3_ctrl_value = 0x1;
+ posdiv_vallue = 0x0;
+ break;
+ case 12:
+ div3_ctrl_value = 0x1;
+ posdiv_vallue = 0x1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ mtk_phy_update_field(regs + HDMI_1_PLL_CFG_4, RG_HDMITXPLL_POSDIV_DIV3_CTRL, div3_ctrl_value);
+ mtk_phy_update_field(regs + HDMI_1_PLL_CFG_4, RG_HDMITXPLL_POSDIV, posdiv_vallue);
+
+ /* POSDIV1 */
+ switch (posdiv1) {
+ case 5:
+ div_ctrl_value = 0x0;
+ break;
+ case 10:
+ div_ctrl_value = 0x1;
+ break;
+ case 12:
+ div_ctrl_value = 0x2;
+ break;
+ case 15:
+ div_ctrl_value = 0x3;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ mtk_phy_update_field(regs + HDMI_1_PLL_CFG_4, RG_HDMITXPLL_DIV_CTRL, div_ctrl_value);
+
+ /* DE add new setting */
+ mtk_phy_clear_bits(regs + HDMI_1_PLL_CFG_1, RG_HDMITXPLL_RESERVE_BIT14);
+
+ /* POSDIV2 */
+ switch (posdiv2) {
+ case 1:
+ reserve_3_2_value = 0x0;
+ break;
+ case 2:
+ reserve_3_2_value = 0x1;
+ break;
+ case 4:
+ reserve_3_2_value = 0x2;
+ break;
+ case 6:
+ reserve_3_2_value = 0x3;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ mtk_phy_update_field(regs + HDMI_1_PLL_CFG_1, RG_HDMITXPLL_RESERVE_BIT3_2, reserve_3_2_value);
+
+ /* DE add new setting */
+ mtk_phy_update_field(regs + HDMI_1_PLL_CFG_1, RG_HDMITXPLL_RESERVE_BIT1_0, 0x2);
+
+ /* PREDIV */
+ prediv_value = ilog2(prediv);
+
+ mtk_phy_update_field(regs + HDMI_1_PLL_CFG_4, RG_HDMITXPLL_PREDIV, prediv_value);
+
+ /* FBKDIV_HS3 */
+ reserve13_value = ilog2(fbkdiv_hs3);
+
+ mtk_phy_update_field(regs + HDMI_1_PLL_CFG_1, RG_HDMITXPLL_RESERVE_BIT13, reserve13_value);
+
+ /* FBDIV */
+ mtk_phy_update_field(regs + HDMI_1_PLL_CFG_4, RG_HDMITXPLL_FBKDIV_HIGH, fbkdiv_high);
+ mtk_phy_update_field(regs + HDMI_1_PLL_CFG_3, RG_HDMITXPLL_FBKDIV_LOW, fbkdiv_low);
+
+ /* Digital DIVIDER */
+ mtk_phy_clear_bits(regs + HDMI_CTL_3, REG_PIXEL_CLOCK_SEL);
+
+ if (digital_div == 1) {
+ mtk_phy_clear_bits(regs + HDMI_CTL_3, REG_HDMITX_PIXEL_CLOCK);
+ } else {
+ mtk_phy_set_bits(regs + HDMI_CTL_3, REG_HDMITX_PIXEL_CLOCK);
+ mtk_phy_update_field(regs + HDMI_CTL_3, REG_HDMITXPLL_DIV, digital_div - 1);
+ }
+
+ return 0;
+}
+
+static int mtk_hdmi_pll_calc(struct mtk_hdmi_phy *hdmi_phy, struct clk_hw *hw,
+ unsigned long rate, unsigned long parent_rate)
+{
+ u8 digital_div, txprediv, txposdiv, fbkdiv_high, posdiv1, posdiv2;
+ u64 tmds_clk, pixel_clk, da_hdmitx21_ref_ck, ns_hdmipll_ck, pcw;
+ u8 txpredivs[4] = { 2, 4, 6, 12 };
+ u32 fbkdiv_low;
+ int i, ret;
+
+ pixel_clk = rate;
+ tmds_clk = pixel_clk;
+
+ if (tmds_clk < 25 * MEGA || tmds_clk > 594 * MEGA)
+ return -EINVAL;
+
+ if (tmds_clk >= 340 * MEGA)
+ hdmi_phy->tmds_over_340M = true;
+ else
+ hdmi_phy->tmds_over_340M = false;
+
+ /* in Hz */
+ da_hdmitx21_ref_ck = 26 * MEGA;
+
+ /* TXPOSDIV stage treatment:
+ * 0M < TMDS clk < 54M /8
+ * 54M <= TMDS clk < 148.35M /4
+ * 148.35M <=TMDS clk < 296.7M /2
+ * 296.7 <=TMDS clk <= 594M /1
+ */
+ if (tmds_clk < 54 * MEGA)
+ txposdiv = 8;
+ else if (tmds_clk >= 54 * MEGA && tmds_clk < 148.35 * MEGA)
+ txposdiv = 4;
+ else if (tmds_clk >= 148.35 * MEGA && tmds_clk < 296.7 * MEGA)
+ txposdiv = 2;
+ else if (tmds_clk >= 296.7 * MEGA && tmds_clk <= 594 * MEGA)
+ txposdiv = 1;
+ else
+ return -EINVAL;
+
+ /* calculate txprediv: can be 2, 4, 6, 12
+ * ICO clk = 5*TMDS_CLK*TXPOSDIV*TXPREDIV
+ * ICO clk constraint: 5G =< ICO clk <= 12G
+ */
+ for (i = 0; i < ARRAY_SIZE(txpredivs); i++) {
+ ns_hdmipll_ck = 5 * tmds_clk * txposdiv * txpredivs[i];
+ if (ns_hdmipll_ck >= 5 * GIGA &&
+ ns_hdmipll_ck <= 1 * GIGA)
+ break;
+ }
+ if (i == (ARRAY_SIZE(txpredivs) - 1) &&
+ (ns_hdmipll_ck < 5 * GIGA || ns_hdmipll_ck > 12 * GIGA)) {
+ return -EINVAL;
+ }
+ if (i == ARRAY_SIZE(txpredivs))
+ return -EINVAL;
+
+ txprediv = txpredivs[i];
+
+ /* PCW calculation: FBKDIV
+ * formula: pcw=(frequency_out*2^pcw_bit) / frequency_in / FBKDIV_HS3;
+ * RG_HDMITXPLL_FBKDIV[32:0]:
+ * [32,24] 9bit integer, [23,0]:24bit fraction
+ */
+ pcw = div_u64(((u64)ns_hdmipll_ck) << PCW_DECIMAL_WIDTH,
+ da_hdmitx21_ref_ck / PLL_FBKDIV_HS3);
+
+ if (pcw > GENMASK_ULL(32, 0))
+ return -EINVAL;
+
+ fbkdiv_high = FIELD_GET(GENMASK_ULL(63, 32), pcw);
+ fbkdiv_low = FIELD_GET(GENMASK(31, 0), pcw);
+
+ /* posdiv1:
+ * posdiv1 stage treatment according to color_depth:
+ * 24bit -> posdiv1 /10, 30bit -> posdiv1 /12.5,
+ * 36bit -> posdiv1 /15, 48bit -> posdiv1 /10
+ */
+ posdiv1 = 10;
+ posdiv2 = 1;
+
+ /* Digital clk divider, max /32 */
+ digital_div = div_u64((u64)ns_hdmipll_ck, posdiv1 / posdiv2 / pixel_clk);
+ if (!(digital_div <= 32 && digital_div >= 1))
+ return -EINVAL;
+
+ mtk_hdmi_pll_set_hw(hw, PLL_PREDIV, fbkdiv_high, fbkdiv_low,
+ PLL_FBKDIV_HS3, posdiv1, posdiv2, txprediv,
+ txposdiv, digital_div);
+ if (ret)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int mtk_hdmi_pll_drv_setting(struct clk_hw *hw)
+{
+ struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw);
+ void __iomem *regs = hdmi_phy->regs;
+ u8 data_channel_bias, clk_channel_bias;
+ u8 impedance, impedance_en;
+ u32 tmds_clk;
+ u32 pixel_clk = hdmi_phy->pll_rate;
+
+ tmds_clk = pixel_clk;
+
+ /* bias & impedance setting:
+ * 3G < data rate <= 6G: enable impedance 100ohm,
+ * data channel bias 24mA, clock channel bias 20mA
+ * pixel clk >= HD, 74.175MHZ <= pixel clk <= 300MHZ:
+ * enalbe impedance 100ohm
+ * data channel 20mA, clock channel 16mA
+ * 27M =< pixel clk < 74.175: disable impedance
+ * data channel & clock channel bias 10mA
+ */
+
+ /* 3G < data rate <= 6G, 300M < tmds rate <= 594M */
+ if (tmds_clk > 300 * MEGA && tmds_clk <= 594 * MEGA) {
+ data_channel_bias = 0x3c; /* 24mA */
+ clk_channel_bias = 0x34; /* 20mA */
+ impedance_en = 0xf;
+ impedance = 0x36; /* 100ohm */
+ } else if (pixel_clk >= 74.175 * MEGA && pixel_clk <= 300 * MEGA) {
+ data_channel_bias = 0x34; /* 20mA */
+ clk_channel_bias = 0x2c; /* 16mA */
+ impedance_en = 0xf;
+ impedance = 0x36; /* 100ohm */
+ } else if (pixel_clk >= 27 * MEGA && pixel_clk < 74.175 * MEGA) {
+ data_channel_bias = 0x14; /* 10mA */
+ clk_channel_bias = 0x14; /* 10mA */
+ impedance_en = 0x0;
+ impedance = 0x0;
+ } else {
+ return -EINVAL;
+ }
+
+ /* bias */
+ mtk_phy_update_field(regs + HDMI_1_CFG_1, RG_HDMITX21_DRV_IBIAS_D0, data_channel_bias);
+ mtk_phy_update_field(regs + HDMI_1_CFG_1, RG_HDMITX21_DRV_IBIAS_D1, data_channel_bias);
+ mtk_phy_update_field(regs + HDMI_1_CFG_1, RG_HDMITX21_DRV_IBIAS_D2, data_channel_bias);
+ mtk_phy_update_field(regs + HDMI_1_CFG_0, RG_HDMITX21_DRV_IBIAS_CLK, clk_channel_bias);
+
+ /* impedance */
+ mtk_phy_update_field(regs + HDMI_1_CFG_0, RG_HDMITX21_DRV_IMP_EN, impedance_en);
+ mtk_phy_update_field(regs + HDMI_1_CFG_2, RG_HDMITX21_DRV_IMP_D0_EN1, impedance);
+ mtk_phy_update_field(regs + HDMI_1_CFG_2, RG_HDMITX21_DRV_IMP_D1_EN1, impedance);
+ mtk_phy_update_field(regs + HDMI_1_CFG_2, RG_HDMITX21_DRV_IMP_D2_EN1, impedance);
+ mtk_phy_update_field(regs + HDMI_1_CFG_2, RG_HDMITX21_DRV_IMP_CLK_EN1, impedance);
+
+ return 0;
+}
+
+static int mtk_hdmi_pll_prepare(struct clk_hw *hw)
+{
+ struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw);
+ void __iomem *regs = hdmi_phy->regs;
+
+ mtk_phy_set_bits(regs + HDMI_1_CFG_6, RG_HDMITX21_TX_POSDIV_EN);
+
+ mtk_phy_set_bits(regs + HDMI_1_CFG_0, RG_HDMITX21_SER_EN);
+ mtk_phy_set_bits(regs + HDMI_1_CFG_6, RG_HDMITX21_D0_DRV_OP_EN);
+ mtk_phy_set_bits(regs + HDMI_1_CFG_6, RG_HDMITX21_D1_DRV_OP_EN);
+ mtk_phy_set_bits(regs + HDMI_1_CFG_6, RG_HDMITX21_D2_DRV_OP_EN);
+ mtk_phy_set_bits(regs + HDMI_1_CFG_6, RG_HDMITX21_CK_DRV_OP_EN);
+
+ mtk_phy_clear_bits(regs + HDMI_1_CFG_6, RG_HDMITX21_FRL_D0_EN);
+ mtk_phy_clear_bits(regs + HDMI_1_CFG_6, RG_HDMITX21_FRL_D1_EN);
+ mtk_phy_clear_bits(regs + HDMI_1_CFG_6, RG_HDMITX21_FRL_D2_EN);
+ mtk_phy_clear_bits(regs + HDMI_1_CFG_6, RG_HDMITX21_FRL_CK_EN);
+
+ mtk_hdmi_pll_drv_setting(hw);
+
+ mtk_phy_clear_bits(regs + HDMI_1_CFG_10, RG_HDMITX21_BG_PWD);
+ mtk_phy_set_bits(regs + HDMI_1_CFG_6, RG_HDMITX21_BIAS_EN);
+ mtk_phy_set_bits(regs + HDMI_1_CFG_3, RG_HDMITX21_CKLDO_EN);
+ mtk_phy_set_bits(regs + HDMI_1_CFG_3, RG_HDMITX21_SLDO_EN);
+
+ mtk_phy_set_bits(regs + HDMI_1_PLL_CFG_4, DA_HDMITXPLL_PWR_ON);
+ usleep_range(5, 10);
+ mtk_phy_clear_bits(regs + HDMI_1_PLL_CFG_4, DA_HDMITXPLL_ISO_EN);
+ usleep_range(5, 10);
+ mtk_phy_clear_bits(regs + HDMI_1_PLL_CFG_2, RG_HDMITXPLL_PWD);
+ usleep_range(30, 50);
+ return 0;
+}
+
+static void mtk_hdmi_pll_unprepare(struct clk_hw *hw)
+{
+ struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw);
+ void __iomem *regs = hdmi_phy->regs;
+
+ mtk_phy_set_bits(regs + HDMI_1_CFG_10, RG_HDMITX21_BG_PWD);
+ mtk_phy_clear_bits(regs + HDMI_1_CFG_6, RG_HDMITX21_BIAS_EN);
+ mtk_phy_clear_bits(regs + HDMI_1_CFG_3, RG_HDMITX21_CKLDO_EN);
+ mtk_phy_clear_bits(regs + HDMI_1_CFG_3, RG_HDMITX21_SLDO_EN);
+
+ mtk_phy_set_bits(regs + HDMI_1_PLL_CFG_2, RG_HDMITXPLL_PWD);
+ usleep_range(10, 20);
+ mtk_phy_set_bits(regs + HDMI_1_PLL_CFG_4, DA_HDMITXPLL_ISO_EN);
+ usleep_range(10, 20);
+ mtk_phy_clear_bits(regs + HDMI_1_PLL_CFG_4, DA_HDMITXPLL_PWR_ON);
+}
+
+static int mtk_hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw);
+
+ dev_dbg(hdmi_phy->dev, "%s: %lu Hz, parent: %lu Hz\n", __func__, rate,
+ parent_rate);
+
+ return mtk_hdmi_pll_calc(hdmi_phy, hw, rate, parent_rate);
+}
+
+static long mtk_hdmi_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw);
+
+ hdmi_phy->pll_rate = rate;
+ return rate;
+}
+
+static unsigned long mtk_hdmi_pll_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw);
+
+ return hdmi_phy->pll_rate;
+}
+
+static const struct clk_ops mtk_hdmi_pll_ops = {
+ .prepare = mtk_hdmi_pll_prepare,
+ .unprepare = mtk_hdmi_pll_unprepare,
+ .set_rate = mtk_hdmi_pll_set_rate,
+ .round_rate = mtk_hdmi_pll_round_rate,
+ .recalc_rate = mtk_hdmi_pll_recalc_rate,
+};
+
+static void vtx_signal_en(struct mtk_hdmi_phy *hdmi_phy, bool on)
+{
+ void __iomem *regs = hdmi_phy->regs;
+
+ if (on)
+ mtk_phy_set_bits(regs + HDMI_1_CFG_0, RG_HDMITX21_DRV_EN);
+ else
+ mtk_phy_clear_bits(regs + HDMI_1_CFG_0, RG_HDMITX21_DRV_EN);
+}
+
+static void mtk_hdmi_phy_enable_tmds(struct mtk_hdmi_phy *hdmi_phy)
+{
+ vtx_signal_en(hdmi_phy, true);
+ usleep_range(100, 150);
+}
+
+static void mtk_hdmi_phy_disable_tmds(struct mtk_hdmi_phy *hdmi_phy)
+{
+ vtx_signal_en(hdmi_phy, false);
+}
+
+static int mtk_hdmi_phy_configure(struct phy *phy, union phy_configure_opts *opts)
+{
+ struct phy_configure_opts_dp *dp_opts = &opts->dp;
+ struct mtk_hdmi_phy *hdmi_phy = phy_get_drvdata(phy);
+ int ret;
+
+ ret = clk_set_rate(hdmi_phy->pll, dp_opts->link_rate);
+
+ if (ret)
+ return ret;
+
+ mtk_phy_tmds_clk_ratio(hdmi_phy, hdmi_phy->tmds_over_340M);
+
+ return ret;
+}
+
+struct mtk_hdmi_phy_conf mtk_hdmi_phy_8195_conf = {
+ .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE,
+ .hdmi_phy_clk_ops = &mtk_hdmi_pll_ops,
+ .hdmi_phy_enable_tmds = mtk_hdmi_phy_enable_tmds,
+ .hdmi_phy_disable_tmds = mtk_hdmi_phy_disable_tmds,
+ .hdmi_phy_configure = mtk_hdmi_phy_configure,
+};
+
+MODULE_AUTHOR("Can Zeng <can.zeng@mediatek.com>");
+MODULE_DESCRIPTION("MediaTek MT8195 HDMI PHY Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/mediatek/phy-mtk-hdmi-mt8195.h b/drivers/phy/mediatek/phy-mtk-hdmi-mt8195.h
new file mode 100644
index 000000000000..22a68dc9550c
--- /dev/null
+++ b/drivers/phy/mediatek/phy-mtk-hdmi-mt8195.h
@@ -0,0 +1,113 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ * Copyright (c) 2022 BayLibre, SAS
+ */
+
+#ifndef _MTK_HDMI_PHY_8195_H
+#define _MTK_HDMI_PHY_8195_H
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/types.h>
+
+#define PCW_DECIMAL_WIDTH 24
+#define PLL_PREDIV 1
+#define PLL_FBKDIV_HS3 1
+
+#define HDMI20_CLK_CFG 0x70
+#define REG_TXC_DIV GENMASK(31, 30)
+
+#define HDMI_1_CFG_0 0x00
+#define RG_HDMITX21_DRV_IBIAS_CLK GENMASK(10, 5)
+#define RG_HDMITX21_DRV_IMP_EN GENMASK(23, 20)
+#define RG_HDMITX21_DRV_EN GENMASK(27, 24)
+#define RG_HDMITX21_SER_EN GENMASK(31, 28)
+
+#define HDMI_1_CFG_1 0x04
+#define RG_HDMITX21_DRV_IBIAS_D0 GENMASK(19, 14)
+#define RG_HDMITX21_DRV_IBIAS_D1 GENMASK(25, 20)
+#define RG_HDMITX21_DRV_IBIAS_D2 GENMASK(31, 26)
+
+#define HDMI_1_CFG_10 0x40
+#define RG_HDMITXPLL_REF_CK_SEL GENMASK(2, 1)
+#define RG_HDMITX21_VREF_SEL BIT(4)
+#define RG_HDMITX21_BIAS_PE_VREF_SELB BIT(10)
+#define RG_HDMITX21_BIAS_PE_BG_VREF_SEL GENMASK(16, 15)
+#define RG_HDMITX21_BG_PWD BIT(20)
+
+#define HDMI_1_CFG_2 0x08
+#define RG_HDMITX21_DRV_IMP_D0_EN1 GENMASK(13, 8)
+#define RG_HDMITX21_DRV_IMP_D1_EN1 GENMASK(19, 14)
+#define RG_HDMITX21_DRV_IMP_D2_EN1 GENMASK(25, 20)
+#define RG_HDMITX21_DRV_IMP_CLK_EN1 GENMASK(31, 26)
+
+#define HDMI_1_CFG_3 0x0c
+#define RG_HDMITX21_CKLDO_EN BIT(3)
+#define RG_HDMITX21_SLDOLPF_EN BIT(7)
+#define RG_HDMITX21_SLDO_EN GENMASK(11, 8)
+
+#define HDMI_1_CFG_6 0x18
+#define RG_HDMITX21_D2_DRV_OP_EN BIT(8)
+#define RG_HDMITX21_D1_DRV_OP_EN BIT(9)
+#define RG_HDMITX21_D0_DRV_OP_EN BIT(10)
+#define RG_HDMITX21_CK_DRV_OP_EN BIT(11)
+#define RG_HDMITX21_FRL_EN BIT(12)
+#define RG_HDMITX21_FRL_CK_EN BIT(13)
+#define RG_HDMITX21_FRL_D0_EN BIT(14)
+#define RG_HDMITX21_FRL_D1_EN BIT(15)
+#define RG_HDMITX21_FRL_D2_EN BIT(16)
+#define RG_HDMITX21_INTR_CAL GENMASK(22, 18)
+#define RG_HDMITX21_TX_POSDIV GENMASK(27, 26)
+#define RG_HDMITX21_TX_POSDIV_EN BIT(28)
+#define RG_HDMITX21_BIAS_EN BIT(29)
+
+#define HDMI_1_CFG_9 0x24
+#define RG_HDMITX21_SLDO_VREF_SEL GENMASK(5, 4)
+
+#define HDMI_1_PLL_CFG_0 0x44
+#define RG_HDMITXPLL_HREN GENMASK(13, 12)
+#define RG_HDMITXPLL_IBAND_FIX_EN BIT(24)
+#define RG_HDMITXPLL_LVR_SEL GENMASK(27, 26)
+#define RG_HDMITXPLL_BP2 BIT(30)
+#define RG_HDMITXPLL_TCL_EN BIT(31)
+
+#define HDMI_1_PLL_CFG_1 0x48
+#define RG_HDMITXPLL_RESERVE_BIT1_0 GENMASK(1, 0)
+#define RG_HDMITXPLL_RESERVE_BIT3_2 GENMASK(3, 2)
+#define RG_HDMITXPLL_RESERVE_BIT12_11 GENMASK(12, 11)
+#define RG_HDMITXPLL_RESERVE_BIT13 BIT(13)
+#define RG_HDMITXPLL_RESERVE_BIT14 BIT(14)
+
+#define HDMI_1_PLL_CFG_2 0x4c
+#define RG_HDMITXPLL_BC GENMASK(28, 27)
+#define RG_HDMITXPLL_IC GENMASK(26, 22)
+#define RG_HDMITXPLL_BR GENMASK(21, 19)
+#define RG_HDMITXPLL_IR GENMASK(18, 14)
+#define RG_HDMITXPLL_BP GENMASK(13, 10)
+#define RG_HDMITXPLL_HIKVCO BIT(29)
+#define RG_HDMITXPLL_PWD BIT(31)
+
+#define HDMI_1_PLL_CFG_3 0x50
+#define RG_HDMITXPLL_FBKDIV_LOW GENMASK(31, 0)
+
+#define HDMI_1_PLL_CFG_4 0x54
+#define DA_HDMITXPLL_ISO_EN BIT(1)
+#define DA_HDMITXPLL_PWR_ON BIT(2)
+#define RG_HDMITXPLL_POSDIV_DIV3_CTRL BIT(21)
+#define RG_HDMITXPLL_POSDIV GENMASK(23, 22)
+#define RG_HDMITXPLL_DIV_CTRL GENMASK(25, 24)
+#define RG_HDMITXPLL_PREDIV GENMASK(29, 28)
+#define RG_HDMITXPLL_FBKDIV_HIGH BIT(31)
+
+#define HDMI_ANA_CTL 0x7c
+#define REG_ANA_HDMI20_FIFO_EN BIT(16)
+
+#define HDMI_CTL_3 0xcc
+#define REG_HDMITXPLL_DIV GENMASK(4, 0)
+#define REG_HDMITX_REF_XTAL_SEL BIT(7)
+#define REG_HDMITX_REF_RESPLL_SEL BIT(9)
+#define REG_PIXEL_CLOCK_SEL BIT(10)
+#define REG_HDMITX_PIXEL_CLOCK BIT(23)
+
+#endif /* MTK_HDMI_PHY_8195_H */
diff --git a/drivers/phy/mediatek/phy-mtk-hdmi.c b/drivers/phy/mediatek/phy-mtk-hdmi.c
index b16d437d6721..d2e824771f9d 100644
--- a/drivers/phy/mediatek/phy-mtk-hdmi.c
+++ b/drivers/phy/mediatek/phy-mtk-hdmi.c
@@ -8,10 +8,12 @@
static int mtk_hdmi_phy_power_on(struct phy *phy);
static int mtk_hdmi_phy_power_off(struct phy *phy);
+static int mtk_hdmi_phy_configure(struct phy *phy, union phy_configure_opts *opts);
static const struct phy_ops mtk_hdmi_phy_dev_ops = {
.power_on = mtk_hdmi_phy_power_on,
.power_off = mtk_hdmi_phy_power_off,
+ .configure = mtk_hdmi_phy_configure,
.owner = THIS_MODULE,
};
@@ -43,6 +45,16 @@ static int mtk_hdmi_phy_power_off(struct phy *phy)
return 0;
}
+static int mtk_hdmi_phy_configure(struct phy *phy, union phy_configure_opts *opts)
+{
+ struct mtk_hdmi_phy *hdmi_phy = phy_get_drvdata(phy);
+
+ if (hdmi_phy->conf->hdmi_phy_configure)
+ return hdmi_phy->conf->hdmi_phy_configure(phy, opts);
+
+ return 0;
+}
+
static const struct phy_ops *
mtk_hdmi_phy_dev_get_ops(const struct mtk_hdmi_phy *hdmi_phy)
{
@@ -149,6 +161,9 @@ static const struct of_device_id mtk_hdmi_phy_match[] = {
{ .compatible = "mediatek,mt8173-hdmi-phy",
.data = &mtk_hdmi_phy_8173_conf,
},
+ { .compatible = "mediatek,mt8195-hdmi-phy",
+ .data = &mtk_hdmi_phy_8195_conf,
+ },
{},
};
MODULE_DEVICE_TABLE(of, mtk_hdmi_phy_match);
diff --git a/drivers/phy/mediatek/phy-mtk-hdmi.h b/drivers/phy/mediatek/phy-mtk-hdmi.h
index c7fa65cff989..fc2ad6a0527f 100644
--- a/drivers/phy/mediatek/phy-mtk-hdmi.h
+++ b/drivers/phy/mediatek/phy-mtk-hdmi.h
@@ -24,6 +24,7 @@ struct mtk_hdmi_phy_conf {
const struct clk_ops *hdmi_phy_clk_ops;
void (*hdmi_phy_enable_tmds)(struct mtk_hdmi_phy *hdmi_phy);
void (*hdmi_phy_disable_tmds)(struct mtk_hdmi_phy *hdmi_phy);
+ int (*hdmi_phy_configure)(struct phy *phy, union phy_configure_opts *opts);
};
struct mtk_hdmi_phy {
@@ -39,10 +40,12 @@ struct mtk_hdmi_phy {
unsigned char drv_imp_d0;
unsigned int ibias;
unsigned int ibias_up;
+ bool tmds_over_340M;
};
struct mtk_hdmi_phy *to_mtk_hdmi_phy(struct clk_hw *hw);
+extern struct mtk_hdmi_phy_conf mtk_hdmi_phy_8195_conf;
extern struct mtk_hdmi_phy_conf mtk_hdmi_phy_8173_conf;
extern struct mtk_hdmi_phy_conf mtk_hdmi_phy_2701_conf;
diff --git a/drivers/phy/mediatek/phy-mtk-mipi-dsi.c b/drivers/phy/mediatek/phy-mtk-mipi-dsi.c
index cf9c386385bb..526c05a4af5e 100644
--- a/drivers/phy/mediatek/phy-mtk-mipi-dsi.c
+++ b/drivers/phy/mediatek/phy-mtk-mipi-dsi.c
@@ -180,10 +180,9 @@ static int mtk_mipi_tx_probe(struct platform_device *pdev)
mipi_tx->pll);
}
-static int mtk_mipi_tx_remove(struct platform_device *pdev)
+static void mtk_mipi_tx_remove(struct platform_device *pdev)
{
of_clk_del_provider(pdev->dev.of_node);
- return 0;
}
static const struct of_device_id mtk_mipi_tx_match[] = {
@@ -199,7 +198,7 @@ MODULE_DEVICE_TABLE(of, mtk_mipi_tx_match);
static struct platform_driver mtk_mipi_tx_driver = {
.probe = mtk_mipi_tx_probe,
- .remove = mtk_mipi_tx_remove,
+ .remove_new = mtk_mipi_tx_remove,
.driver = {
.name = "mediatek-mipi-tx",
.of_match_table = mtk_mipi_tx_match,
diff --git a/drivers/phy/motorola/phy-cpcap-usb.c b/drivers/phy/motorola/phy-cpcap-usb.c
index 2f8210167b77..74333e814221 100644
--- a/drivers/phy/motorola/phy-cpcap-usb.c
+++ b/drivers/phy/motorola/phy-cpcap-usb.c
@@ -692,7 +692,7 @@ out_reg_disable:
return error;
}
-static int cpcap_usb_phy_remove(struct platform_device *pdev)
+static void cpcap_usb_phy_remove(struct platform_device *pdev)
{
struct cpcap_phy_ddata *ddata = platform_get_drvdata(pdev);
int error;
@@ -707,13 +707,11 @@ static int cpcap_usb_phy_remove(struct platform_device *pdev)
usb_remove_phy(&ddata->phy);
cancel_delayed_work_sync(&ddata->detect_work);
regulator_disable(ddata->vusb);
-
- return 0;
}
static struct platform_driver cpcap_usb_phy_driver = {
.probe = cpcap_usb_phy_probe,
- .remove = cpcap_usb_phy_remove,
+ .remove_new = cpcap_usb_phy_remove,
.driver = {
.name = "cpcap-usb-phy",
.of_match_table = of_match_ptr(cpcap_usb_phy_id_table),
diff --git a/drivers/phy/motorola/phy-mapphone-mdm6600.c b/drivers/phy/motorola/phy-mapphone-mdm6600.c
index 3cd4d51c247c..1d567604b650 100644
--- a/drivers/phy/motorola/phy-mapphone-mdm6600.c
+++ b/drivers/phy/motorola/phy-mapphone-mdm6600.c
@@ -634,7 +634,7 @@ cleanup:
return error;
}
-static int phy_mdm6600_remove(struct platform_device *pdev)
+static void phy_mdm6600_remove(struct platform_device *pdev)
{
struct phy_mdm6600 *ddata = platform_get_drvdata(pdev);
struct gpio_desc *reset_gpio = ddata->ctrl_gpios[PHY_MDM6600_RESET];
@@ -653,13 +653,11 @@ static int phy_mdm6600_remove(struct platform_device *pdev)
cancel_delayed_work_sync(&ddata->modem_wake_work);
cancel_delayed_work_sync(&ddata->bootup_work);
cancel_delayed_work_sync(&ddata->status_work);
-
- return 0;
}
static struct platform_driver phy_mdm6600_driver = {
.probe = phy_mdm6600_probe,
- .remove = phy_mdm6600_remove,
+ .remove_new = phy_mdm6600_remove,
.driver = {
.name = "phy-mapphone-mdm6600",
.pm = &phy_mdm6600_pm_ops,
diff --git a/drivers/phy/phy-lgm-usb.c b/drivers/phy/phy-lgm-usb.c
index 309c8f0e0724..410729c7f513 100644
--- a/drivers/phy/phy-lgm-usb.c
+++ b/drivers/phy/phy-lgm-usb.c
@@ -252,13 +252,11 @@ static int phy_probe(struct platform_device *pdev)
return usb_add_phy_dev(phy);
}
-static int phy_remove(struct platform_device *pdev)
+static void phy_remove(struct platform_device *pdev)
{
struct tca_apb *ta = platform_get_drvdata(pdev);
usb_remove_phy(&ta->phy);
-
- return 0;
}
static const struct of_device_id intel_usb_phy_dt_ids[] = {
@@ -273,7 +271,7 @@ static struct platform_driver lgm_phy_driver = {
.of_match_table = intel_usb_phy_dt_ids,
},
.probe = phy_probe,
- .remove = phy_remove,
+ .remove_new = phy_remove,
};
module_platform_driver(lgm_phy_driver);
diff --git a/drivers/phy/qualcomm/phy-qcom-apq8064-sata.c b/drivers/phy/qualcomm/phy-qcom-apq8064-sata.c
index d437a249cd73..8814f4322adf 100644
--- a/drivers/phy/qualcomm/phy-qcom-apq8064-sata.c
+++ b/drivers/phy/qualcomm/phy-qcom-apq8064-sata.c
@@ -243,13 +243,11 @@ static int qcom_apq8064_sata_phy_probe(struct platform_device *pdev)
return 0;
}
-static int qcom_apq8064_sata_phy_remove(struct platform_device *pdev)
+static void qcom_apq8064_sata_phy_remove(struct platform_device *pdev)
{
struct qcom_apq8064_sata_phy *phy = platform_get_drvdata(pdev);
clk_disable_unprepare(phy->cfg_clk);
-
- return 0;
}
static const struct of_device_id qcom_apq8064_sata_phy_of_match[] = {
@@ -260,7 +258,7 @@ MODULE_DEVICE_TABLE(of, qcom_apq8064_sata_phy_of_match);
static struct platform_driver qcom_apq8064_sata_phy_driver = {
.probe = qcom_apq8064_sata_phy_probe,
- .remove = qcom_apq8064_sata_phy_remove,
+ .remove_new = qcom_apq8064_sata_phy_remove,
.driver = {
.name = "qcom-apq8064-sata-phy",
.of_match_table = qcom_apq8064_sata_phy_of_match,
diff --git a/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c b/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c
index 3f265ac2df20..90f8543ba265 100644
--- a/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c
+++ b/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c
@@ -223,16 +223,14 @@ static int eusb2_repeater_probe(struct platform_device *pdev)
return 0;
}
-static int eusb2_repeater_remove(struct platform_device *pdev)
+static void eusb2_repeater_remove(struct platform_device *pdev)
{
struct eusb2_repeater *rptr = platform_get_drvdata(pdev);
if (!rptr)
- return 0;
+ return;
eusb2_repeater_exit(rptr->phy);
-
- return 0;
}
static const struct of_device_id eusb2_repeater_of_match_table[] = {
@@ -246,7 +244,7 @@ MODULE_DEVICE_TABLE(of, eusb2_repeater_of_match_table);
static struct platform_driver eusb2_repeater_driver = {
.probe = eusb2_repeater_probe,
- .remove = eusb2_repeater_remove,
+ .remove_new = eusb2_repeater_remove,
.driver = {
.name = "qcom-eusb2-repeater",
.of_match_table = eusb2_repeater_of_match_table,
diff --git a/drivers/phy/qualcomm/phy-qcom-ipq806x-sata.c b/drivers/phy/qualcomm/phy-qcom-ipq806x-sata.c
index 0fc2a1ed39b3..f0a72b82c770 100644
--- a/drivers/phy/qualcomm/phy-qcom-ipq806x-sata.c
+++ b/drivers/phy/qualcomm/phy-qcom-ipq806x-sata.c
@@ -170,13 +170,11 @@ static int qcom_ipq806x_sata_phy_probe(struct platform_device *pdev)
return 0;
}
-static int qcom_ipq806x_sata_phy_remove(struct platform_device *pdev)
+static void qcom_ipq806x_sata_phy_remove(struct platform_device *pdev)
{
struct qcom_ipq806x_sata_phy *phy = platform_get_drvdata(pdev);
clk_disable_unprepare(phy->cfg_clk);
-
- return 0;
}
static const struct of_device_id qcom_ipq806x_sata_phy_of_match[] = {
@@ -187,7 +185,7 @@ MODULE_DEVICE_TABLE(of, qcom_ipq806x_sata_phy_of_match);
static struct platform_driver qcom_ipq806x_sata_phy_driver = {
.probe = qcom_ipq806x_sata_phy_probe,
- .remove = qcom_ipq806x_sata_phy_remove,
+ .remove_new = qcom_ipq806x_sata_phy_remove,
.driver = {
.name = "qcom-ipq806x-sata-phy",
.of_match_table = qcom_ipq806x_sata_phy_of_match,
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
index c1483e157af4..6850e04c329b 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
@@ -1396,6 +1396,7 @@ static const struct qmp_combo_offsets qmp_combo_offsets_v3 = {
.usb3_serdes = 0x1000,
.usb3_pcs_misc = 0x1a00,
.usb3_pcs = 0x1c00,
+ .usb3_pcs_usb = 0x1f00,
.dp_serdes = 0x2000,
.dp_txa = 0x2200,
.dp_txb = 0x2600,
@@ -1416,22 +1417,6 @@ static const struct qmp_combo_offsets qmp_combo_offsets_v5 = {
.dp_dp_phy = 0x2200,
};
-static const struct qmp_combo_offsets qmp_combo_offsets_v6 = {
- .com = 0x0000,
- .txa = 0x1200,
- .rxa = 0x1400,
- .txb = 0x1600,
- .rxb = 0x1800,
- .usb3_serdes = 0x1000,
- .usb3_pcs_misc = 0x1a00,
- .usb3_pcs = 0x1c00,
- .usb3_pcs_usb = 0x1f00,
- .dp_serdes = 0x2000,
- .dp_txa = 0x2200,
- .dp_txb = 0x2600,
- .dp_dp_phy = 0x2a00,
-};
-
static const struct qmp_phy_cfg sc7180_usb3dpphy_cfg = {
.serdes_tbl = qmp_v3_usb3_serdes_tbl,
.serdes_tbl_num = ARRAY_SIZE(qmp_v3_usb3_serdes_tbl),
@@ -1758,7 +1743,7 @@ static const struct qmp_phy_cfg sm8350_usb3dpphy_cfg = {
};
static const struct qmp_phy_cfg sm8550_usb3dpphy_cfg = {
- .offsets = &qmp_combo_offsets_v6,
+ .offsets = &qmp_combo_offsets_v3,
.serdes_tbl = sm8550_usb3_serdes_tbl,
.serdes_tbl_num = ARRAY_SIZE(sm8550_usb3_serdes_tbl),
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
index 5182aeac43ee..df505279edfd 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
@@ -725,9 +725,6 @@ static const struct qmp_phy_init_tbl sdm845_qhp_pcie_tx_tbl[] = {
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_L0_RSM_START, 0x01),
};
-static const struct qmp_phy_init_tbl sdm845_qhp_pcie_rx_tbl[] = {
-};
-
static const struct qmp_phy_init_tbl sdm845_qhp_pcie_pcs_tbl[] = {
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_PHY_POWER_STATE_CONFIG, 0x3f),
QMP_PHY_INIT_CFG(PCIE_GEN3_QHP_PHY_PCS_TX_RX_CONFIG, 0x50),
@@ -1130,10 +1127,60 @@ static const struct qmp_phy_init_tbl sm8250_qmp_gen3x2_pcie_pcs_misc_tbl[] = {
};
static const struct qmp_phy_init_tbl sdx55_qmp_pcie_serdes_tbl[] = {
- QMP_PHY_INIT_CFG(QSERDES_V4_COM_BG_TIMER, 0x02),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIAS_EN_CLKBUFLR_EN, 0x18),
- QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYS_CLK_CTRL, 0x07),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_IVCO, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP_EN, 0x46),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP_CFG, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_TUNE_MAP, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_HSCLK_SEL, 0x12),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_HSCLK_HS_SWITCH_SEL, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_CORECLK_DIV_MODE0, 0x05),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_CORECLK_DIV_MODE1, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_CMN_MISC1, 0x88),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_CMN_MISC2, 0x03),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_CMN_MODE, 0x17),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_DC_LEVEL_CTRL, 0x0b),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_HSCLK_SEL, 0x22),
+};
+
+static const struct qmp_phy_init_tbl sdx55_qmp_pcie_rc_serdes_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_EN_CENTER, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_PER1, 0x31),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_PER2, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_STEP_SIZE1_MODE0, 0xce),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_STEP_SIZE2_MODE0, 0x0b),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_STEP_SIZE1_MODE1, 0x97),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_STEP_SIZE2_MODE1, 0x0c),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_CLK_ENABLE1, 0x90),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_CLK_EP_DIV_MODE0, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_CLK_EP_DIV_MODE1, 0x10),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_CP_CTRL_MODE0, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_CP_CTRL_MODE1, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_RCTRL_MODE0, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_RCTRL_MODE1, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_CCTRL_MODE0, 0x36),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_CCTRL_MODE1, 0x36),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYSCLK_EN_SEL, 0x08),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP1_MODE0, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP2_MODE0, 0x0d),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP1_MODE1, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP2_MODE1, 0x1a),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_DEC_START_MODE0, 0xc3),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_DEC_START_MODE1, 0xd0),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START3_MODE0, 0x05),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START1_MODE1, 0x55),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START2_MODE1, 0x55),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START3_MODE1, 0x05),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_CLK_SELECT, 0x34),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0xca),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x1e),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE1_MODE1, 0xd8),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE2_MODE1, 0x20),
+};
+
+static const struct qmp_phy_init_tbl sdx55_qmp_pcie_ep_serdes_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_BG_TIMER, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYS_CLK_CTRL, 0x07),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_CP_CTRL_MODE0, 0x0a),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_CP_CTRL_MODE1, 0x0a),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_RCTRL_MODE0, 0x19),
@@ -1141,8 +1188,6 @@ static const struct qmp_phy_init_tbl sdx55_qmp_pcie_serdes_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_CCTRL_MODE0, 0x03),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_CCTRL_MODE1, 0x03),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYSCLK_EN_SEL, 0x00),
- QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP_EN, 0x46),
- QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP_CFG, 0x04),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP1_MODE0, 0x7f),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP2_MODE0, 0x02),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP1_MODE1, 0xff),
@@ -1154,21 +1199,11 @@ static const struct qmp_phy_init_tbl sdx55_qmp_pcie_serdes_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V4_COM_INTEGLOOP_GAIN1_MODE0, 0x01),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_INTEGLOOP_GAIN0_MODE1, 0xfb),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_INTEGLOOP_GAIN1_MODE1, 0x01),
- QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_TUNE_MAP, 0x02),
- QMP_PHY_INIT_CFG(QSERDES_V4_COM_HSCLK_SEL, 0x12),
- QMP_PHY_INIT_CFG(QSERDES_V4_COM_HSCLK_HS_SWITCH_SEL, 0x00),
- QMP_PHY_INIT_CFG(QSERDES_V4_COM_CORECLK_DIV_MODE0, 0x05),
- QMP_PHY_INIT_CFG(QSERDES_V4_COM_CORECLK_DIV_MODE1, 0x04),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_CMN_CONFIG, 0x04),
- QMP_PHY_INIT_CFG(QSERDES_V4_COM_CMN_MISC1, 0x88),
- QMP_PHY_INIT_CFG(QSERDES_V4_COM_CMN_MISC2, 0x03),
- QMP_PHY_INIT_CFG(QSERDES_V4_COM_CMN_MODE, 0x17),
- QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_DC_LEVEL_CTRL, 0x0b),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0x56),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x1d),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE1_MODE1, 0x4b),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE2_MODE1, 0x1f),
- QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_HSCLK_SEL, 0x22),
};
static const struct qmp_phy_init_tbl sdx55_qmp_pcie_tx_tbl[] = {
@@ -1220,10 +1255,151 @@ static const struct qmp_phy_init_tbl sdx55_qmp_pcie_pcs_misc_tbl[] = {
QMP_PHY_INIT_CFG(QPHY_V4_20_PCS_PCIE_G4_RXEQEVAL_TIME, 0x13),
QMP_PHY_INIT_CFG(QPHY_V4_20_PCS_PCIE_G4_EQ_CONFIG2, 0x01),
QMP_PHY_INIT_CFG(QPHY_V4_20_PCS_PCIE_G4_EQ_CONFIG5, 0x02),
+};
+
+static const struct qmp_phy_init_tbl sdx55_qmp_pcie_rc_pcs_misc_tbl[] = {
+ QMP_PHY_INIT_CFG(QPHY_V4_20_PCS_PCIE_ENDPOINT_REFCLK_DRIVE, 0xc1),
+ QMP_PHY_INIT_CFG(QPHY_V4_20_PCS_PCIE_OSC_DTCT_ACTIONS, 0x00),
+};
+
+static const struct qmp_phy_init_tbl sdx55_qmp_pcie_ep_pcs_misc_tbl[] = {
QMP_PHY_INIT_CFG(QPHY_V4_20_PCS_LANE1_INSIG_SW_CTRL2, 0x00),
QMP_PHY_INIT_CFG(QPHY_V4_20_PCS_LANE1_INSIG_MX_CTRL2, 0x00),
};
+static const struct qmp_phy_init_tbl sdx65_qmp_pcie_serdes_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V5_COM_BG_TIMER, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V5_COM_BIAS_EN_CLKBUFLR_EN, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_V5_COM_SYS_CLK_CTRL, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_IVCO, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V5_COM_CP_CTRL_MODE0, 0x27),
+ QMP_PHY_INIT_CFG(QSERDES_V5_COM_CP_CTRL_MODE1, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_RCTRL_MODE0, 0x17),
+ QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_RCTRL_MODE1, 0x19),
+ QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_CCTRL_MODE0, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_CCTRL_MODE1, 0x03),
+ QMP_PHY_INIT_CFG(QSERDES_V5_COM_SYSCLK_EN_SEL, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP_EN, 0x46),
+ QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP_CFG, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP1_MODE0, 0xff),
+ QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP2_MODE0, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP1_MODE1, 0xff),
+ QMP_PHY_INIT_CFG(QSERDES_V5_COM_LOCK_CMP2_MODE1, 0x09),
+ QMP_PHY_INIT_CFG(QSERDES_V5_COM_DEC_START_MODE0, 0x19),
+ QMP_PHY_INIT_CFG(QSERDES_V5_COM_DEC_START_MODE1, 0x28),
+ QMP_PHY_INIT_CFG(QSERDES_V5_COM_INTEGLOOP_GAIN0_MODE0, 0xfb),
+ QMP_PHY_INIT_CFG(QSERDES_V5_COM_INTEGLOOP_GAIN1_MODE0, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V5_COM_INTEGLOOP_GAIN0_MODE1, 0xfb),
+ QMP_PHY_INIT_CFG(QSERDES_V5_COM_INTEGLOOP_GAIN1_MODE1, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V5_COM_VCO_TUNE_MAP, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V5_COM_HSCLK_SEL, 0x12),
+ QMP_PHY_INIT_CFG(QSERDES_V5_COM_HSCLK_HS_SWITCH_SEL, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V5_COM_CORECLK_DIV_MODE0, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V5_COM_CORECLK_DIV_MODE1, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V5_COM_CORE_CLK_EN, 0x60),
+ QMP_PHY_INIT_CFG(QSERDES_V5_COM_CMN_MISC1, 0x88),
+ QMP_PHY_INIT_CFG(QSERDES_V5_COM_CMN_CONFIG, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V5_COM_CMN_MODE, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_V5_COM_CMN_MODE_CONTD, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V5_COM_VCO_DC_LEVEL_CTRL, 0x0f),
+};
+
+static const struct qmp_phy_init_tbl sdx65_qmp_pcie_tx_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_TX_LANE_MODE_1, 0x05),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_TX_LANE_MODE_2, 0xf6),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_TX_LANE_MODE_3, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_TX_VMODE_CTRL1, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_TX_PI_QEC_CTRL, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_TX_RES_CODE_LANE_OFFSET_TX, 0x1a),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_TX_RES_CODE_LANE_OFFSET_RX, 0x0c),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_TX_RCV_DETECT_LVL_2, 0x12),
+};
+
+static const struct qmp_phy_init_tbl sdx65_qmp_pcie_rx_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_AUX_DATA_THRESH_BIN_RATE_0_1, 0x3f),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_DFE_1, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_DFE_2, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_TX_ADAPT_PRE_THRESH1, 0x3e),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_TX_ADAPT_PRE_THRESH2, 0x1e),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_TX_ADAPT_POST_THRESH1, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_TX_ADAPT_POST_THRESH2, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_TX_ADAPT_MAIN_THRESH1, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_TX_ADAPT_MAIN_THRESH2, 0x1d),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_VGA_CAL_CNTRL1, 0x44),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_VGA_CAL_CNTRL2, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_EQU_ADAPTOR_CNTRL2, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4a),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x74),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_SIGDET_ENABLES, 0x1c),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_SIGDET_CNTRL, 0x03),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_SIGDET_DEGLITCH_CNTRL, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B0, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B1, 0xcc),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B2, 0x12),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B3, 0xcc),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B4, 0x64),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B5, 0x4a),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B6, 0x29),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_PHPRE_CTRL, 0x20),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_DCC_CTRL1, 0x0c),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH1_RATE210, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH1_RATE3, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH2_RATE210, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH2_RATE3, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH3_RATE210, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH3_RATE3, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH4_RATE3, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH5_RATE3, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH6_RATE3, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_UCDR_FO_GAIN_RATE2, 0x0c),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_UCDR_FO_GAIN_RATE3, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_UCDR_PI_CONTROLS, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_AUX_DATA_THRESH_BIN_RATE_2_3, 0x37),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_IDAC_SAOFFSET, 0x10),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_DFE_3, 0x05),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_DFE_DAC_ENABLE1, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_DFE_DAC_ENABLE2, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_VGA_CAL_MAN_VAL, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_GM_CAL, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_EQU_ADAPTOR_CNTRL4, 0x0b),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE2_B0, 0xc5),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE2_B1, 0xac),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE2_B2, 0xb6),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE2_B3, 0xc0),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE2_B4, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE2_B5, 0xfb),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE2_B6, 0x0d),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE3_B0, 0xc5),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE3_B1, 0xee),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE3_B2, 0xbf),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE3_B3, 0xa0),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE3_B4, 0x81),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE3_B5, 0xde),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE3_B6, 0x7f),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_DFE_EN_TIMER, 0x28),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_DFE_CTLE_POST_CAL_OFFSET, 0x38),
+};
+
+static const struct qmp_phy_init_tbl sdx65_qmp_pcie_pcs_tbl[] = {
+ QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_G3S2_PRE_GAIN, 0x2e),
+ QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_RX_SIGDET_LVL, 0xaa),
+ QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_EQ_CONFIG2, 0x0d),
+ QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_EQ_CONFIG4, 0x16),
+ QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_EQ_CONFIG5, 0x22),
+};
+
+static const struct qmp_phy_init_tbl sdx65_qmp_pcie_pcs_misc_tbl[] = {
+ QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_PCIE_EQ_CONFIG1, 0x16),
+ QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_PCIE_RX_MARGINING_CONFIG3, 0x28),
+ QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_PCIE_OSC_DTCT_MODE2_CONFIG5, 0x08),
+ QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_PCIE_G4_EQ_CONFIG2, 0x0d),
+ QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_PCIE_G4_EQ_CONFIG5, 0x02),
+ QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_PCIE_G4_PRE_GAIN, 0x2e),
+ QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_LANE1_INSIG_SW_CTRL2, 0x00),
+ QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_LANE1_INSIG_MX_CTRL2, 0x00),
+};
+
static const struct qmp_phy_init_tbl sm8450_qmp_gen3_pcie_serdes_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V5_COM_SYSCLK_EN_SEL, 0x08),
QMP_PHY_INIT_CFG(QSERDES_V5_COM_CLK_SELECT, 0x34),
@@ -2033,8 +2209,6 @@ static const struct qmp_phy_cfg sdm845_qhp_pciephy_cfg = {
.serdes_num = ARRAY_SIZE(sdm845_qhp_pcie_serdes_tbl),
.tx = sdm845_qhp_pcie_tx_tbl,
.tx_num = ARRAY_SIZE(sdm845_qhp_pcie_tx_tbl),
- .rx = sdm845_qhp_pcie_rx_tbl,
- .rx_num = ARRAY_SIZE(sdm845_qhp_pcie_rx_tbl),
.pcs = sdm845_qhp_pcie_pcs_tbl,
.pcs_num = ARRAY_SIZE(sdm845_qhp_pcie_pcs_tbl),
},
@@ -2152,7 +2326,7 @@ static const struct qmp_phy_cfg msm8998_pciephy_cfg = {
};
static const struct qmp_phy_cfg sc8180x_pciephy_cfg = {
- .lanes = 1,
+ .lanes = 2,
.tbls = {
.serdes = sc8180x_qmp_pcie_serdes_tbl,
@@ -2301,6 +2475,21 @@ static const struct qmp_phy_cfg sdx55_qmp_pciephy_cfg = {
.pcs_misc = sdx55_qmp_pcie_pcs_misc_tbl,
.pcs_misc_num = ARRAY_SIZE(sdx55_qmp_pcie_pcs_misc_tbl),
},
+
+ .tbls_rc = &(const struct qmp_phy_cfg_tbls) {
+ .serdes = sdx55_qmp_pcie_rc_serdes_tbl,
+ .serdes_num = ARRAY_SIZE(sdx55_qmp_pcie_rc_serdes_tbl),
+ .pcs_misc = sdx55_qmp_pcie_rc_pcs_misc_tbl,
+ .pcs_misc_num = ARRAY_SIZE(sdx55_qmp_pcie_rc_pcs_misc_tbl),
+ },
+
+ .tbls_ep = &(const struct qmp_phy_cfg_tbls) {
+ .serdes = sdx55_qmp_pcie_ep_serdes_tbl,
+ .serdes_num = ARRAY_SIZE(sdx55_qmp_pcie_ep_serdes_tbl),
+ .pcs_misc = sdx55_qmp_pcie_ep_pcs_misc_tbl,
+ .pcs_misc_num = ARRAY_SIZE(sdx55_qmp_pcie_ep_pcs_misc_tbl),
+ },
+
.clk_list = sdm845_pciephy_clk_l,
.num_clks = ARRAY_SIZE(sdm845_pciephy_clk_l),
.reset_list = sdm845_pciephy_reset_l,
@@ -2309,7 +2498,7 @@ static const struct qmp_phy_cfg sdx55_qmp_pciephy_cfg = {
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
.regs = pciephy_v4_regs_layout,
- .pwrdn_ctrl = SW_PWRDN,
+ .pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
.phy_status = PHYSTATUS_4_20,
};
@@ -2387,6 +2576,35 @@ static const struct qmp_phy_cfg sm8350_qmp_gen3x2_pciephy_cfg = {
.phy_status = PHYSTATUS,
};
+static const struct qmp_phy_cfg sdx65_qmp_pciephy_cfg = {
+ .lanes = 2,
+
+ .offsets = &qmp_pcie_offsets_v6_20,
+
+ .tbls = {
+ .serdes = sdx65_qmp_pcie_serdes_tbl,
+ .serdes_num = ARRAY_SIZE(sdx65_qmp_pcie_serdes_tbl),
+ .tx = sdx65_qmp_pcie_tx_tbl,
+ .tx_num = ARRAY_SIZE(sdx65_qmp_pcie_tx_tbl),
+ .rx = sdx65_qmp_pcie_rx_tbl,
+ .rx_num = ARRAY_SIZE(sdx65_qmp_pcie_rx_tbl),
+ .pcs = sdx65_qmp_pcie_pcs_tbl,
+ .pcs_num = ARRAY_SIZE(sdx65_qmp_pcie_pcs_tbl),
+ .pcs_misc = sdx65_qmp_pcie_pcs_misc_tbl,
+ .pcs_misc_num = ARRAY_SIZE(sdx65_qmp_pcie_pcs_misc_tbl),
+ },
+ .clk_list = sdm845_pciephy_clk_l,
+ .num_clks = ARRAY_SIZE(sdm845_pciephy_clk_l),
+ .reset_list = sdm845_pciephy_reset_l,
+ .num_resets = ARRAY_SIZE(sdm845_pciephy_reset_l),
+ .vreg_list = qmp_phy_vreg_l,
+ .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
+ .regs = pciephy_v5_regs_layout,
+
+ .pwrdn_ctrl = SW_PWRDN,
+ .phy_status = PHYSTATUS_4_20,
+};
+
static const struct qmp_phy_cfg sm8450_qmp_gen3x1_pciephy_cfg = {
.lanes = 1,
@@ -3181,6 +3399,9 @@ static const struct of_device_id qmp_pcie_of_match_table[] = {
.compatible = "qcom,sdx55-qmp-pcie-phy",
.data = &sdx55_qmp_pciephy_cfg,
}, {
+ .compatible = "qcom,sdx65-qmp-gen4x2-pcie-phy",
+ .data = &sdx65_qmp_pciephy_cfg,
+ }, {
.compatible = "qcom,sm8250-qmp-gen3x1-pcie-phy",
.data = &sm8250_qmp_gen3x1_pciephy_cfg,
}, {
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v4_20.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v4_20.h
index af273602998e..ac872a9eff9a 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v4_20.h
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v4_20.h
@@ -6,6 +6,8 @@
#ifndef QCOM_PHY_QMP_PCS_PCIE_V4_20_H_
#define QCOM_PHY_QMP_PCS_PCIE_V4_20_H_
+#define QPHY_V4_20_PCS_PCIE_ENDPOINT_REFCLK_DRIVE 0x01c
+#define QPHY_V4_20_PCS_PCIE_OSC_DTCT_ACTIONS 0x090
#define QPHY_V4_20_PCS_PCIE_EQ_CONFIG1 0x0a0
#define QPHY_V4_20_PCS_PCIE_G3_RXEQEVAL_TIME 0x0f0
#define QPHY_V4_20_PCS_PCIE_G4_RXEQEVAL_TIME 0x0f4
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v5_20.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v5_20.h
index 3d9713d348fe..a3a056741fc7 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v5_20.h
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v5_20.h
@@ -12,8 +12,11 @@
#define QPHY_V5_20_PCS_PCIE_OSC_DTCT_ACTIONS 0x090
#define QPHY_V5_20_PCS_PCIE_EQ_CONFIG1 0x0a0
#define QPHY_V5_20_PCS_PCIE_PRESET_P10_POST 0x0e0
+#define QPHY_V5_20_PCS_PCIE_G4_EQ_CONFIG2 0x0fc
#define QPHY_V5_20_PCS_PCIE_G4_EQ_CONFIG5 0x108
#define QPHY_V5_20_PCS_PCIE_G4_PRE_GAIN 0x15c
#define QPHY_V5_20_PCS_PCIE_RX_MARGINING_CONFIG3 0x184
+#define QPHY_V5_20_PCS_LANE1_INSIG_SW_CTRL2 0xa24
+#define QPHY_V5_20_PCS_LANE1_INSIG_MX_CTRL2 0xa28
#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v5_20.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v5_20.h
index 9a5a20daf62c..f0754b6f9e3a 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v5_20.h
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v5_20.h
@@ -8,6 +8,7 @@
#define QPHY_V5_20_PCS_G3S2_PRE_GAIN 0x170
#define QPHY_V5_20_PCS_RX_SIGDET_LVL 0x188
+#define QPHY_V5_20_PCS_EQ_CONFIG2 0x1d8
#define QPHY_V5_20_PCS_EQ_CONFIG4 0x1e0
#define QPHY_V5_20_PCS_EQ_CONFIG5 0x1e4
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v5_20.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v5_20.h
index 86c01104799e..c7b12c1fb7f5 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v5_20.h
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v5_20.h
@@ -11,6 +11,10 @@
#define QSERDES_V5_20_TX_RES_CODE_LANE_OFFSET_RX 0x34
#define QSERDES_V5_20_TX_LANE_MODE_1 0x78
#define QSERDES_V5_20_TX_LANE_MODE_2 0x7c
+#define QSERDES_V5_20_TX_LANE_MODE_3 0x80
+#define QSERDES_V5_20_TX_RCV_DETECT_LVL_2 0x90
+#define QSERDES_V5_20_TX_VMODE_CTRL1 0xb0
+#define QSERDES_V5_20_TX_PI_QEC_CTRL 0xcc
/* Only for QMP V5_20 PHY - RX registers */
#define QSERDES_V5_20_RX_UCDR_FO_GAIN_RATE2 0x008
@@ -19,16 +23,33 @@
#define QSERDES_V5_20_RX_AUX_DATA_THRESH_BIN_RATE_0_1 0x02c
#define QSERDES_V5_20_RX_AUX_DATA_THRESH_BIN_RATE_2_3 0x030
#define QSERDES_V5_20_RX_RX_IDAC_SAOFFSET 0x07c
+#define QSERDES_V5_20_RX_DFE_1 0x088
+#define QSERDES_V5_20_RX_DFE_2 0x08c
#define QSERDES_V5_20_RX_DFE_3 0x090
#define QSERDES_V5_20_RX_DFE_DAC_ENABLE1 0x0b4
+#define QSERDES_V5_20_RX_TX_ADAPT_PRE_THRESH1 0x0bc
+#define QSERDES_V5_20_RX_TX_ADAPT_PRE_THRESH2 0x0c0
#define QSERDES_V5_20_RX_TX_ADAPT_POST_THRESH1 0x0c4
#define QSERDES_V5_20_RX_TX_ADAPT_POST_THRESH2 0x0c8
+#define QSERDES_V5_20_RX_TX_ADAPT_MAIN_THRESH1 0x0cc
+#define QSERDES_V5_20_RX_TX_ADAPT_MAIN_THRESH2 0x0d0
+#define QSERDES_V5_20_RX_VGA_CAL_CNTRL1 0x0d4
+#define QSERDES_V5_20_RX_VGA_CAL_CNTRL2 0x0d8
#define QSERDES_V5_20_RX_VGA_CAL_MAN_VAL 0x0dc
#define QSERDES_V5_20_RX_GM_CAL 0x0ec
+#define QSERDES_V5_20_RX_RX_EQU_ADAPTOR_CNTRL2 0x100
+#define QSERDES_V5_20_RX_RX_EQU_ADAPTOR_CNTRL3 0x104
#define QSERDES_V5_20_RX_RX_EQU_ADAPTOR_CNTRL4 0x108
+#define QSERDES_V5_20_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1 0x118
+#define QSERDES_V5_20_RX_RX_OFFSET_ADAPTOR_CNTRL2 0x11c
+#define QSERDES_V5_20_RX_SIGDET_ENABLES 0x120
+#define QSERDES_V5_20_RX_SIGDET_CNTRL 0x124
+#define QSERDES_V5_20_RX_SIGDET_DEGLITCH_CNTRL 0x12c
+#define QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B0 0x160
#define QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B1 0x164
#define QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B2 0x168
#define QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B3 0x16c
+#define QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B4 0x170
#define QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B5 0x174
#define QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B6 0x178
#define QSERDES_V5_20_RX_RX_MODE_RATE2_B0 0x17c
@@ -46,7 +67,10 @@
#define QSERDES_V5_20_RX_RX_MODE_RATE3_B5 0x1ac
#define QSERDES_V5_20_RX_RX_MODE_RATE3_B6 0x1b0
#define QSERDES_V5_20_RX_PHPRE_CTRL 0x1b4
+#define QSERDES_V5_20_RX_DFE_DAC_ENABLE2 0x1b8
+#define QSERDES_V5_20_RX_DFE_EN_TIMER 0x1bc
#define QSERDES_V5_20_RX_DFE_CTLE_POST_CAL_OFFSET 0x1c0
+#define QSERDES_V5_20_RX_DCC_CTRL1 0x1c4
#define QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH1_RATE210 0x1f4
#define QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH1_RATE3 0x1f8
#define QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH2_RATE210 0x1fc
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
index 994ddd5d4a81..8c877b668bb9 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
@@ -349,6 +349,36 @@ static const struct qmp_phy_init_tbl sdm845_ufsphy_pcs[] = {
QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_MULTI_LANE_CTRL1, 0x02),
};
+static const struct qmp_phy_init_tbl sm7150_ufsphy_rx[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_LVL, 0x24),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_CNTRL, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_DEGLITCH_CNTRL, 0x1e),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_INTERFACE_MODE, 0x40),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_TERM_BW, 0x5b),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL2, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL3, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL4, 0x1b),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SVS_SO_GAIN_HALF, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SVS_SO_GAIN_QUARTER, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SVS_SO_GAIN, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x5b),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_PI_CONTROLS, 0x81),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_LOW, 0x80),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_MODE_00, 0x59),
+};
+
+static const struct qmp_phy_init_tbl sm7150_ufsphy_pcs[] = {
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_RX_SIGDET_CTRL2, 0x6f),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_TX_LARGE_AMP_DRV_LVL, 0x0f),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_TX_SMALL_AMP_DRV_LVL, 0x02),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_RX_SYM_RESYNC_CTRL, 0x03),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_TX_MID_TERM_CTRL1, 0x43),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_RX_SIGDET_CTRL1, 0x0f),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_RX_MIN_HIBERN8_TIME, 0xff),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_MULTI_LANE_CTRL1, 0x02),
+};
+
static const struct qmp_phy_init_tbl sm8150_ufsphy_serdes[] = {
QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYSCLK_EN_SEL, 0xd9),
QMP_PHY_INIT_CFG(QSERDES_V4_COM_HSCLK_SEL, 0x11),
@@ -823,6 +853,40 @@ static const struct qmp_phy_cfg msm8996_ufsphy_cfg = {
.no_pcs_sw_reset = true,
};
+static const struct qmp_phy_cfg sa8775p_ufsphy_cfg = {
+ .lanes = 2,
+
+ .offsets = &qmp_ufs_offsets,
+
+ .tbls = {
+ .serdes = sm8350_ufsphy_serdes,
+ .serdes_num = ARRAY_SIZE(sm8350_ufsphy_serdes),
+ .tx = sm8350_ufsphy_tx,
+ .tx_num = ARRAY_SIZE(sm8350_ufsphy_tx),
+ .rx = sm8350_ufsphy_rx,
+ .rx_num = ARRAY_SIZE(sm8350_ufsphy_rx),
+ .pcs = sm8350_ufsphy_pcs,
+ .pcs_num = ARRAY_SIZE(sm8350_ufsphy_pcs),
+ },
+ .tbls_hs_b = {
+ .serdes = sm8350_ufsphy_hs_b_serdes,
+ .serdes_num = ARRAY_SIZE(sm8350_ufsphy_hs_b_serdes),
+ },
+ .tbls_hs_g4 = {
+ .tx = sm8350_ufsphy_g4_tx,
+ .tx_num = ARRAY_SIZE(sm8350_ufsphy_g4_tx),
+ .rx = sm8350_ufsphy_g4_rx,
+ .rx_num = ARRAY_SIZE(sm8350_ufsphy_g4_rx),
+ .pcs = sm8350_ufsphy_g4_pcs,
+ .pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs),
+ },
+ .clk_list = sm8450_ufs_phy_clk_l,
+ .num_clks = ARRAY_SIZE(sm8450_ufs_phy_clk_l),
+ .vreg_list = qmp_phy_vreg_l,
+ .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
+ .regs = ufsphy_v5_regs_layout,
+};
+
static const struct qmp_phy_cfg sc8280xp_ufsphy_cfg = {
.lanes = 2,
@@ -911,6 +975,34 @@ static const struct qmp_phy_cfg sm6115_ufsphy_cfg = {
.no_pcs_sw_reset = true,
};
+static const struct qmp_phy_cfg sm7150_ufsphy_cfg = {
+ .lanes = 1,
+
+ .offsets = &qmp_ufs_offsets,
+
+ .tbls = {
+ .serdes = sdm845_ufsphy_serdes,
+ .serdes_num = ARRAY_SIZE(sdm845_ufsphy_serdes),
+ .tx = sdm845_ufsphy_tx,
+ .tx_num = ARRAY_SIZE(sdm845_ufsphy_tx),
+ .rx = sm7150_ufsphy_rx,
+ .rx_num = ARRAY_SIZE(sm7150_ufsphy_rx),
+ .pcs = sm7150_ufsphy_pcs,
+ .pcs_num = ARRAY_SIZE(sm7150_ufsphy_pcs),
+ },
+ .tbls_hs_b = {
+ .serdes = sdm845_ufsphy_hs_b_serdes,
+ .serdes_num = ARRAY_SIZE(sdm845_ufsphy_hs_b_serdes),
+ },
+ .clk_list = sdm845_ufs_phy_clk_l,
+ .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l),
+ .vreg_list = qmp_phy_vreg_l,
+ .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
+ .regs = ufsphy_v3_regs_layout,
+
+ .no_pcs_sw_reset = true,
+};
+
static const struct qmp_phy_cfg sm8150_ufsphy_cfg = {
.lanes = 2,
@@ -1543,6 +1635,9 @@ static const struct of_device_id qmp_ufs_of_match_table[] = {
.compatible = "qcom,msm8998-qmp-ufs-phy",
.data = &sdm845_ufsphy_cfg,
}, {
+ .compatible = "qcom,sa8775p-qmp-ufs-phy",
+ .data = &sa8775p_ufsphy_cfg,
+ }, {
.compatible = "qcom,sc8180x-qmp-ufs-phy",
.data = &sm8150_ufsphy_cfg,
}, {
@@ -1561,6 +1656,9 @@ static const struct of_device_id qmp_ufs_of_match_table[] = {
.compatible = "qcom,sm6350-qmp-ufs-phy",
.data = &sdm845_ufsphy_cfg,
}, {
+ .compatible = "qcom,sm7150-qmp-ufs-phy",
+ .data = &sm7150_ufsphy_cfg,
+ }, {
.compatible = "qcom,sm8150-qmp-ufs-phy",
.data = &sm8150_ufsphy_cfg,
}, {
diff --git a/drivers/phy/renesas/phy-rcar-gen3-pcie.c b/drivers/phy/renesas/phy-rcar-gen3-pcie.c
index 4dc721eb9577..9cf786a7daac 100644
--- a/drivers/phy/renesas/phy-rcar-gen3-pcie.c
+++ b/drivers/phy/renesas/phy-rcar-gen3-pcie.c
@@ -126,11 +126,9 @@ error:
return error;
}
-static int rcar_gen3_phy_pcie_remove(struct platform_device *pdev)
+static void rcar_gen3_phy_pcie_remove(struct platform_device *pdev)
{
pm_runtime_disable(&pdev->dev);
-
- return 0;
};
static struct platform_driver rcar_gen3_phy_driver = {
@@ -139,7 +137,7 @@ static struct platform_driver rcar_gen3_phy_driver = {
.of_match_table = rcar_gen3_phy_pcie_match_table,
},
.probe = rcar_gen3_phy_pcie_probe,
- .remove = rcar_gen3_phy_pcie_remove,
+ .remove_new = rcar_gen3_phy_pcie_remove,
};
module_platform_driver(rcar_gen3_phy_driver);
diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c
index 9de617ca9daa..d4e2ee7e4efb 100644
--- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c
+++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c
@@ -755,7 +755,7 @@ error:
return ret;
}
-static int rcar_gen3_phy_usb2_remove(struct platform_device *pdev)
+static void rcar_gen3_phy_usb2_remove(struct platform_device *pdev)
{
struct rcar_gen3_chan *channel = platform_get_drvdata(pdev);
@@ -763,8 +763,6 @@ static int rcar_gen3_phy_usb2_remove(struct platform_device *pdev)
device_remove_file(&pdev->dev, &dev_attr_role);
pm_runtime_disable(&pdev->dev);
-
- return 0;
};
static struct platform_driver rcar_gen3_phy_usb2_driver = {
@@ -773,7 +771,7 @@ static struct platform_driver rcar_gen3_phy_usb2_driver = {
.of_match_table = rcar_gen3_phy_usb2_match_table,
},
.probe = rcar_gen3_phy_usb2_probe,
- .remove = rcar_gen3_phy_usb2_remove,
+ .remove_new = rcar_gen3_phy_usb2_remove,
};
module_platform_driver(rcar_gen3_phy_usb2_driver);
diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb3.c b/drivers/phy/renesas/phy-rcar-gen3-usb3.c
index f27d6f471629..e2d630edd992 100644
--- a/drivers/phy/renesas/phy-rcar-gen3-usb3.c
+++ b/drivers/phy/renesas/phy-rcar-gen3-usb3.c
@@ -199,11 +199,9 @@ error:
return ret;
}
-static int rcar_gen3_phy_usb3_remove(struct platform_device *pdev)
+static void rcar_gen3_phy_usb3_remove(struct platform_device *pdev)
{
pm_runtime_disable(&pdev->dev);
-
- return 0;
};
static struct platform_driver rcar_gen3_phy_usb3_driver = {
@@ -212,7 +210,7 @@ static struct platform_driver rcar_gen3_phy_usb3_driver = {
.of_match_table = rcar_gen3_phy_usb3_match_table,
},
.probe = rcar_gen3_phy_usb3_probe,
- .remove = rcar_gen3_phy_usb3_remove,
+ .remove_new = rcar_gen3_phy_usb3_remove,
};
module_platform_driver(rcar_gen3_phy_usb3_driver);
diff --git a/drivers/phy/renesas/r8a779f0-ether-serdes.c b/drivers/phy/renesas/r8a779f0-ether-serdes.c
index c5206ef9195b..55b7bdfc10d3 100644
--- a/drivers/phy/renesas/r8a779f0-ether-serdes.c
+++ b/drivers/phy/renesas/r8a779f0-ether-serdes.c
@@ -388,19 +388,17 @@ static int r8a779f0_eth_serdes_probe(struct platform_device *pdev)
return 0;
}
-static int r8a779f0_eth_serdes_remove(struct platform_device *pdev)
+static void r8a779f0_eth_serdes_remove(struct platform_device *pdev)
{
pm_runtime_put(&pdev->dev);
pm_runtime_disable(&pdev->dev);
platform_set_drvdata(pdev, NULL);
-
- return 0;
}
static struct platform_driver r8a779f0_eth_serdes_driver_platform = {
.probe = r8a779f0_eth_serdes_probe,
- .remove = r8a779f0_eth_serdes_remove,
+ .remove_new = r8a779f0_eth_serdes_remove,
.driver = {
.name = "r8a779f0_eth_serdes",
.of_match_table = r8a779f0_eth_serdes_of_table,
diff --git a/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c b/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c
index 75f948bdea6a..98c92d6c482f 100644
--- a/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c
+++ b/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c
@@ -459,13 +459,11 @@ static int rockchip_inno_csidphy_probe(struct platform_device *pdev)
return 0;
}
-static int rockchip_inno_csidphy_remove(struct platform_device *pdev)
+static void rockchip_inno_csidphy_remove(struct platform_device *pdev)
{
struct rockchip_inno_csidphy *priv = platform_get_drvdata(pdev);
pm_runtime_disable(priv->dev);
-
- return 0;
}
static struct platform_driver rockchip_inno_csidphy_driver = {
@@ -474,7 +472,7 @@ static struct platform_driver rockchip_inno_csidphy_driver = {
.of_match_table = rockchip_inno_csidphy_match_id,
},
.probe = rockchip_inno_csidphy_probe,
- .remove = rockchip_inno_csidphy_remove,
+ .remove_new = rockchip_inno_csidphy_remove,
};
module_platform_driver(rockchip_inno_csidphy_driver);
diff --git a/drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c b/drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c
index 2c5847faff63..401b0aabb159 100644
--- a/drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c
+++ b/drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c
@@ -281,11 +281,6 @@ struct inno_mipi_dphy_timing inno_mipi_dphy_timing_table_max_2_5ghz[] = {
{2500000000, 0x15, 0x54, 0x7f, 0x15, 0x6a},
};
-static inline struct inno_dsidphy *hw_to_inno(struct clk_hw *hw)
-{
- return container_of(hw, struct inno_dsidphy, pll.hw);
-}
-
static void phy_update_bits(struct inno_dsidphy *inno,
u8 first, u8 second, u8 mask, u8 val)
{
@@ -755,13 +750,11 @@ static int inno_dsidphy_probe(struct platform_device *pdev)
return 0;
}
-static int inno_dsidphy_remove(struct platform_device *pdev)
+static void inno_dsidphy_remove(struct platform_device *pdev)
{
struct inno_dsidphy *inno = platform_get_drvdata(pdev);
pm_runtime_disable(inno->dev);
-
- return 0;
}
static const struct of_device_id inno_dsidphy_of_match[] = {
@@ -788,7 +781,7 @@ static struct platform_driver inno_dsidphy_driver = {
.of_match_table = of_match_ptr(inno_dsidphy_of_match),
},
.probe = inno_dsidphy_probe,
- .remove = inno_dsidphy_remove,
+ .remove_new = inno_dsidphy_remove,
};
module_platform_driver(inno_dsidphy_driver);
diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
index 80acca4e9e14..1e1563f5fffc 100644
--- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
+++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c
@@ -1246,11 +1246,9 @@ static int inno_hdmi_phy_probe(struct platform_device *pdev)
return PTR_ERR_OR_ZERO(phy_provider);
}
-static int inno_hdmi_phy_remove(struct platform_device *pdev)
+static void inno_hdmi_phy_remove(struct platform_device *pdev)
{
of_clk_del_provider(pdev->dev.of_node);
-
- return 0;
}
static const struct of_device_id inno_hdmi_phy_of_match[] = {
@@ -1266,7 +1264,7 @@ MODULE_DEVICE_TABLE(of, inno_hdmi_phy_of_match);
static struct platform_driver inno_hdmi_phy_driver = {
.probe = inno_hdmi_phy_probe,
- .remove = inno_hdmi_phy_remove,
+ .remove_new = inno_hdmi_phy_remove,
.driver = {
.name = "inno-hdmi-phy",
.of_match_table = inno_hdmi_phy_of_match,
diff --git a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c
index 7b213825fb5d..7b8b001e4f9e 100644
--- a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c
+++ b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c
@@ -63,6 +63,9 @@
#define PHYREG18 0x44
#define PHYREG18_PLL_LOOP 0x32
+#define PHYREG27 0x6C
+#define PHYREG27_RX_TRIM_RK3588 0x4C
+
#define PHYREG32 0x7C
#define PHYREG32_SSC_MASK GENMASK(7, 4)
#define PHYREG32_SSC_DIR_SHIFT 4
@@ -114,7 +117,10 @@ struct rockchip_combphy_grfcfg {
struct combphy_reg con2_for_sata;
struct combphy_reg con3_for_sata;
struct combphy_reg pipe_con0_for_sata;
+ struct combphy_reg pipe_con1_for_sata;
struct combphy_reg pipe_xpcs_phy_ready;
+ struct combphy_reg pipe_pcie1l0_sel;
+ struct combphy_reg pipe_pcie1l1_sel;
};
struct rockchip_combphy_cfg {
@@ -559,11 +565,189 @@ static const struct rockchip_combphy_cfg rk3568_combphy_cfgs = {
.combphy_cfg = rk3568_combphy_cfg,
};
+static int rk3588_combphy_cfg(struct rockchip_combphy_priv *priv)
+{
+ const struct rockchip_combphy_grfcfg *cfg = priv->cfg->grfcfg;
+ unsigned long rate;
+ u32 val;
+
+ switch (priv->type) {
+ case PHY_TYPE_PCIE:
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->con0_for_pcie, true);
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->con1_for_pcie, true);
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->con2_for_pcie, true);
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->con3_for_pcie, true);
+ rockchip_combphy_param_write(priv->pipe_grf, &cfg->pipe_pcie1l0_sel, true);
+ rockchip_combphy_param_write(priv->pipe_grf, &cfg->pipe_pcie1l1_sel, true);
+ break;
+ case PHY_TYPE_USB3:
+ /* Set SSC downward spread spectrum */
+ rockchip_combphy_updatel(priv, PHYREG32_SSC_MASK,
+ PHYREG32_SSC_DOWNWARD << PHYREG32_SSC_DIR_SHIFT,
+ PHYREG32);
+
+ /* Enable adaptive CTLE for USB3.0 Rx. */
+ val = readl(priv->mmio + PHYREG15);
+ val |= PHYREG15_CTLE_EN;
+ writel(val, priv->mmio + PHYREG15);
+
+ /* Set PLL KVCO fine tuning signals. */
+ rockchip_combphy_updatel(priv, PHYREG33_PLL_KVCO_MASK,
+ PHYREG33_PLL_KVCO_VALUE << PHYREG33_PLL_KVCO_SHIFT,
+ PHYREG33);
+
+ /* Enable controlling random jitter. */
+ writel(PHYREG12_PLL_LPF_ADJ_VALUE, priv->mmio + PHYREG12);
+
+ /* Set PLL input clock divider 1/2. */
+ rockchip_combphy_updatel(priv, PHYREG6_PLL_DIV_MASK,
+ PHYREG6_PLL_DIV_2 << PHYREG6_PLL_DIV_SHIFT,
+ PHYREG6);
+
+ writel(PHYREG18_PLL_LOOP, priv->mmio + PHYREG18);
+ writel(PHYREG11_SU_TRIM_0_7, priv->mmio + PHYREG11);
+
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_txcomp_sel, false);
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_txelec_sel, false);
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->usb_mode_set, true);
+ break;
+ case PHY_TYPE_SATA:
+ /* Enable adaptive CTLE for SATA Rx. */
+ val = readl(priv->mmio + PHYREG15);
+ val |= PHYREG15_CTLE_EN;
+ writel(val, priv->mmio + PHYREG15);
+ /*
+ * Set tx_rterm=50ohm and rx_rterm=44ohm for SATA.
+ * 0: 60ohm, 8: 50ohm 15: 44ohm (by step abort 1ohm)
+ */
+ val = PHYREG7_TX_RTERM_50OHM << PHYREG7_TX_RTERM_SHIFT;
+ val |= PHYREG7_RX_RTERM_44OHM << PHYREG7_RX_RTERM_SHIFT;
+ writel(val, priv->mmio + PHYREG7);
+
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->con0_for_sata, true);
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->con1_for_sata, true);
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->con2_for_sata, true);
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->con3_for_sata, true);
+ rockchip_combphy_param_write(priv->pipe_grf, &cfg->pipe_con0_for_sata, true);
+ rockchip_combphy_param_write(priv->pipe_grf, &cfg->pipe_con1_for_sata, true);
+ break;
+ case PHY_TYPE_SGMII:
+ case PHY_TYPE_QSGMII:
+ default:
+ dev_err(priv->dev, "incompatible PHY type\n");
+ return -EINVAL;
+ }
+
+ rate = clk_get_rate(priv->refclk);
+
+ switch (rate) {
+ case REF_CLOCK_24MHz:
+ if (priv->type == PHY_TYPE_USB3 || priv->type == PHY_TYPE_SATA) {
+ /* Set ssc_cnt[9:0]=0101111101 & 31.5KHz. */
+ val = PHYREG15_SSC_CNT_VALUE << PHYREG15_SSC_CNT_SHIFT;
+ rockchip_combphy_updatel(priv, PHYREG15_SSC_CNT_MASK,
+ val, PHYREG15);
+
+ writel(PHYREG16_SSC_CNT_VALUE, priv->mmio + PHYREG16);
+ }
+ break;
+
+ case REF_CLOCK_25MHz:
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_25m, true);
+ break;
+ case REF_CLOCK_100MHz:
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_100m, true);
+ if (priv->type == PHY_TYPE_PCIE) {
+ /* PLL KVCO fine tuning. */
+ val = 4 << PHYREG33_PLL_KVCO_SHIFT;
+ rockchip_combphy_updatel(priv, PHYREG33_PLL_KVCO_MASK,
+ val, PHYREG33);
+
+ /* Enable controlling random jitter. */
+ writel(PHYREG12_PLL_LPF_ADJ_VALUE, priv->mmio + PHYREG12);
+
+ /* Set up rx_trim: PLL LPF C1 85pf R1 1.25kohm */
+ writel(PHYREG27_RX_TRIM_RK3588, priv->mmio + PHYREG27);
+
+ /* Set up su_trim: */
+ writel(PHYREG11_SU_TRIM_0_7, priv->mmio + PHYREG11);
+ } else if (priv->type == PHY_TYPE_SATA) {
+ /* downward spread spectrum +500ppm */
+ val = PHYREG32_SSC_DOWNWARD << PHYREG32_SSC_DIR_SHIFT;
+ val |= PHYREG32_SSC_OFFSET_500PPM << PHYREG32_SSC_OFFSET_SHIFT;
+ rockchip_combphy_updatel(priv, PHYREG32_SSC_MASK, val, PHYREG32);
+ }
+ break;
+ default:
+ dev_err(priv->dev, "Unsupported rate: %lu\n", rate);
+ return -EINVAL;
+ }
+
+ if (priv->ext_refclk) {
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_ext, true);
+ if (priv->type == PHY_TYPE_PCIE && rate == REF_CLOCK_100MHz) {
+ val = PHYREG13_RESISTER_HIGH_Z << PHYREG13_RESISTER_SHIFT;
+ val |= PHYREG13_CKRCV_AMP0;
+ rockchip_combphy_updatel(priv, PHYREG13_RESISTER_MASK, val, PHYREG13);
+
+ val = readl(priv->mmio + PHYREG14);
+ val |= PHYREG14_CKRCV_AMP1;
+ writel(val, priv->mmio + PHYREG14);
+ }
+ }
+
+ if (priv->enable_ssc) {
+ val = readl(priv->mmio + PHYREG8);
+ val |= PHYREG8_SSC_EN;
+ writel(val, priv->mmio + PHYREG8);
+ }
+
+ return 0;
+}
+
+static const struct rockchip_combphy_grfcfg rk3588_combphy_grfcfgs = {
+ /* pipe-phy-grf */
+ .pcie_mode_set = { 0x0000, 5, 0, 0x00, 0x11 },
+ .usb_mode_set = { 0x0000, 5, 0, 0x00, 0x04 },
+ .pipe_rxterm_set = { 0x0000, 12, 12, 0x00, 0x01 },
+ .pipe_txelec_set = { 0x0004, 1, 1, 0x00, 0x01 },
+ .pipe_txcomp_set = { 0x0004, 4, 4, 0x00, 0x01 },
+ .pipe_clk_25m = { 0x0004, 14, 13, 0x00, 0x01 },
+ .pipe_clk_100m = { 0x0004, 14, 13, 0x00, 0x02 },
+ .pipe_rxterm_sel = { 0x0008, 8, 8, 0x00, 0x01 },
+ .pipe_txelec_sel = { 0x0008, 12, 12, 0x00, 0x01 },
+ .pipe_txcomp_sel = { 0x0008, 15, 15, 0x00, 0x01 },
+ .pipe_clk_ext = { 0x000c, 9, 8, 0x02, 0x01 },
+ .pipe_phy_status = { 0x0034, 6, 6, 0x01, 0x00 },
+ .con0_for_pcie = { 0x0000, 15, 0, 0x00, 0x1000 },
+ .con1_for_pcie = { 0x0004, 15, 0, 0x00, 0x0000 },
+ .con2_for_pcie = { 0x0008, 15, 0, 0x00, 0x0101 },
+ .con3_for_pcie = { 0x000c, 15, 0, 0x00, 0x0200 },
+ .con0_for_sata = { 0x0000, 15, 0, 0x00, 0x0129 },
+ .con1_for_sata = { 0x0004, 15, 0, 0x00, 0x0000 },
+ .con2_for_sata = { 0x0008, 15, 0, 0x00, 0x80c1 },
+ .con3_for_sata = { 0x000c, 15, 0, 0x00, 0x0407 },
+ /* pipe-grf */
+ .pipe_con0_for_sata = { 0x0000, 11, 5, 0x00, 0x22 },
+ .pipe_con1_for_sata = { 0x0000, 2, 0, 0x00, 0x2 },
+ .pipe_pcie1l0_sel = { 0x0100, 0, 0, 0x01, 0x0 },
+ .pipe_pcie1l1_sel = { 0x0100, 1, 1, 0x01, 0x0 },
+};
+
+static const struct rockchip_combphy_cfg rk3588_combphy_cfgs = {
+ .grfcfg = &rk3588_combphy_grfcfgs,
+ .combphy_cfg = rk3588_combphy_cfg,
+};
+
static const struct of_device_id rockchip_combphy_of_match[] = {
{
.compatible = "rockchip,rk3568-naneng-combphy",
.data = &rk3568_combphy_cfgs,
},
+ {
+ .compatible = "rockchip,rk3588-naneng-combphy",
+ .data = &rk3588_combphy_cfgs,
+ },
{ },
};
MODULE_DEVICE_TABLE(of, rockchip_combphy_of_match);
diff --git a/drivers/phy/rockchip/phy-rockchip-pcie.c b/drivers/phy/rockchip/phy-rockchip-pcie.c
index 75216091d901..8234b83fdd88 100644
--- a/drivers/phy/rockchip/phy-rockchip-pcie.c
+++ b/drivers/phy/rockchip/phy-rockchip-pcie.c
@@ -119,21 +119,6 @@ static inline void phy_wr_cfg(struct rockchip_pcie_phy *rk_phy,
PHY_CFG_WR_SHIFT));
}
-static inline u32 phy_rd_cfg(struct rockchip_pcie_phy *rk_phy,
- u32 addr)
-{
- u32 val;
-
- regmap_write(rk_phy->reg_base, rk_phy->phy_data->pcie_conf,
- HIWORD_UPDATE(addr,
- PHY_CFG_RD_MASK,
- PHY_CFG_ADDR_SHIFT));
- regmap_read(rk_phy->reg_base,
- rk_phy->phy_data->pcie_status,
- &val);
- return val;
-}
-
static int rockchip_pcie_phy_power_off(struct phy *phy)
{
struct phy_pcie_instance *inst = phy_get_drvdata(phy);
diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c
index 39db8acde61a..8b1667be4915 100644
--- a/drivers/phy/rockchip/phy-rockchip-typec.c
+++ b/drivers/phy/rockchip/phy-rockchip-typec.c
@@ -1194,11 +1194,9 @@ static int rockchip_typec_phy_probe(struct platform_device *pdev)
return 0;
}
-static int rockchip_typec_phy_remove(struct platform_device *pdev)
+static void rockchip_typec_phy_remove(struct platform_device *pdev)
{
pm_runtime_disable(&pdev->dev);
-
- return 0;
}
static const struct of_device_id rockchip_typec_phy_dt_ids[] = {
@@ -1213,7 +1211,7 @@ MODULE_DEVICE_TABLE(of, rockchip_typec_phy_dt_ids);
static struct platform_driver rockchip_typec_phy_driver = {
.probe = rockchip_typec_phy_probe,
- .remove = rockchip_typec_phy_remove,
+ .remove_new = rockchip_typec_phy_remove,
.driver = {
.name = "rockchip-typec-phy",
.of_match_table = rockchip_typec_phy_dt_ids,
diff --git a/drivers/phy/st/phy-miphy28lp.c b/drivers/phy/st/phy-miphy28lp.c
index 068160a34f5c..e30305b77f0d 100644
--- a/drivers/phy/st/phy-miphy28lp.c
+++ b/drivers/phy/st/phy-miphy28lp.c
@@ -9,6 +9,7 @@
#include <linux/platform_device.h>
#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -484,19 +485,11 @@ static inline void miphy28lp_pcie_config_gen(struct miphy28lp_phy *miphy_phy)
static inline int miphy28lp_wait_compensation(struct miphy28lp_phy *miphy_phy)
{
- unsigned long finish = jiffies + 5 * HZ;
u8 val;
/* Waiting for Compensation to complete */
- do {
- val = readb_relaxed(miphy_phy->base + MIPHY_COMP_FSM_6);
-
- if (time_after_eq(jiffies, finish))
- return -EBUSY;
- cpu_relax();
- } while (!(val & COMP_DONE));
-
- return 0;
+ return readb_relaxed_poll_timeout(miphy_phy->base + MIPHY_COMP_FSM_6,
+ val, val & COMP_DONE, 1, 5 * USEC_PER_SEC);
}
@@ -805,7 +798,6 @@ static inline void miphy28lp_configure_usb3(struct miphy28lp_phy *miphy_phy)
static inline int miphy_is_ready(struct miphy28lp_phy *miphy_phy)
{
- unsigned long finish = jiffies + 5 * HZ;
u8 mask = HFC_PLL | HFC_RDY;
u8 val;
@@ -816,21 +808,14 @@ static inline int miphy_is_ready(struct miphy28lp_phy *miphy_phy)
if (miphy_phy->type == PHY_TYPE_SATA)
mask |= PHY_RDY;
- do {
- val = readb_relaxed(miphy_phy->base + MIPHY_STATUS_1);
- if ((val & mask) != mask)
- cpu_relax();
- else
- return 0;
- } while (!time_after_eq(jiffies, finish));
-
- return -EBUSY;
+ return readb_relaxed_poll_timeout(miphy_phy->base + MIPHY_STATUS_1,
+ val, (val & mask) == mask, 1,
+ 5 * USEC_PER_SEC);
}
static int miphy_osc_is_ready(struct miphy28lp_phy *miphy_phy)
{
struct miphy28lp_dev *miphy_dev = miphy_phy->phydev;
- unsigned long finish = jiffies + 5 * HZ;
u32 val;
if (!miphy_phy->osc_rdy)
@@ -839,17 +824,10 @@ static int miphy_osc_is_ready(struct miphy28lp_phy *miphy_phy)
if (!miphy_phy->syscfg_reg[SYSCFG_STATUS])
return -EINVAL;
- do {
- regmap_read(miphy_dev->regmap,
- miphy_phy->syscfg_reg[SYSCFG_STATUS], &val);
-
- if ((val & MIPHY_OSC_RDY) != MIPHY_OSC_RDY)
- cpu_relax();
- else
- return 0;
- } while (!time_after_eq(jiffies, finish));
-
- return -EBUSY;
+ return regmap_read_poll_timeout(miphy_dev->regmap,
+ miphy_phy->syscfg_reg[SYSCFG_STATUS],
+ val, val & MIPHY_OSC_RDY, 1,
+ 5 * USEC_PER_SEC);
}
static int miphy28lp_get_resource_byname(struct device_node *child,
diff --git a/drivers/phy/st/phy-spear1310-miphy.c b/drivers/phy/st/phy-spear1310-miphy.c
index 8871cd186304..292413db7da4 100644
--- a/drivers/phy/st/phy-spear1310-miphy.c
+++ b/drivers/phy/st/phy-spear1310-miphy.c
@@ -246,7 +246,7 @@ static struct platform_driver spear1310_miphy_driver = {
.probe = spear1310_miphy_probe,
.driver = {
.name = "spear1310-miphy",
- .of_match_table = of_match_ptr(spear1310_miphy_of_match),
+ .of_match_table = spear1310_miphy_of_match,
},
};
diff --git a/drivers/phy/st/phy-spear1340-miphy.c b/drivers/phy/st/phy-spear1340-miphy.c
index ed4d0e2df053..c1d9ffa5a311 100644
--- a/drivers/phy/st/phy-spear1340-miphy.c
+++ b/drivers/phy/st/phy-spear1340-miphy.c
@@ -279,7 +279,7 @@ static struct platform_driver spear1340_miphy_driver = {
.driver = {
.name = "spear1340-miphy",
.pm = &spear1340_miphy_pm_ops,
- .of_match_table = of_match_ptr(spear1340_miphy_of_match),
+ .of_match_table = spear1340_miphy_of_match,
},
};
diff --git a/drivers/phy/st/phy-stm32-usbphyc.c b/drivers/phy/st/phy-stm32-usbphyc.c
index 5bb9647b078f..0a8552628cbd 100644
--- a/drivers/phy/st/phy-stm32-usbphyc.c
+++ b/drivers/phy/st/phy-stm32-usbphyc.c
@@ -317,6 +317,9 @@ static int stm32_usbphyc_pll_enable(struct stm32_usbphyc *usbphyc)
stm32_usbphyc_set_bits(pll_reg, PLLEN);
+ /* Wait for maximum lock time */
+ usleep_range(200, 300);
+
return 0;
reg_disable:
@@ -766,7 +769,7 @@ clk_disable:
return ret;
}
-static int stm32_usbphyc_remove(struct platform_device *pdev)
+static void stm32_usbphyc_remove(struct platform_device *pdev)
{
struct stm32_usbphyc *usbphyc = dev_get_drvdata(&pdev->dev);
int port;
@@ -779,8 +782,6 @@ static int stm32_usbphyc_remove(struct platform_device *pdev)
stm32_usbphyc_clk48_unregister(usbphyc);
clk_disable_unprepare(usbphyc->clk);
-
- return 0;
}
static int __maybe_unused stm32_usbphyc_resume(struct device *dev)
@@ -810,7 +811,7 @@ MODULE_DEVICE_TABLE(of, stm32_usbphyc_of_match);
static struct platform_driver stm32_usbphyc_driver = {
.probe = stm32_usbphyc_probe,
- .remove = stm32_usbphyc_remove,
+ .remove_new = stm32_usbphyc_remove,
.driver = {
.of_match_table = stm32_usbphyc_of_match,
.name = "stm32-usbphyc",
diff --git a/drivers/phy/tegra/xusb-tegra186.c b/drivers/phy/tegra/xusb-tegra186.c
index 1aae8535f452..0f60d5d1c167 100644
--- a/drivers/phy/tegra/xusb-tegra186.c
+++ b/drivers/phy/tegra/xusb-tegra186.c
@@ -145,6 +145,8 @@
#define MODE_HS MODE(0)
#define MODE_RST MODE(1)
+#define XUSB_AO_UTMIP_SLEEPWALK_STATUS(x) (0xa0 + (x) * 4)
+
#define XUSB_AO_UTMIP_SLEEPWALK_CFG(x) (0xd0 + (x) * 4)
#define XUSB_AO_UHSIC_SLEEPWALK_CFG(x) (0xf0 + (x) * 4)
#define FAKE_USBOP_VAL BIT(0)
@@ -172,24 +174,30 @@
#define AP_A BIT(4)
#define AN_A BIT(5)
#define HIGHZ_A BIT(6)
+#define MASTER_ENABLE_A BIT(7)
/* phase B */
#define USBOP_RPD_B BIT(8)
#define USBON_RPD_B BIT(9)
#define AP_B BIT(12)
#define AN_B BIT(13)
#define HIGHZ_B BIT(14)
+#define MASTER_ENABLE_B BIT(15)
/* phase C */
#define USBOP_RPD_C BIT(16)
#define USBON_RPD_C BIT(17)
#define AP_C BIT(20)
#define AN_C BIT(21)
#define HIGHZ_C BIT(22)
+#define MASTER_ENABLE_C BIT(23)
/* phase D */
#define USBOP_RPD_D BIT(24)
#define USBON_RPD_D BIT(25)
#define AP_D BIT(28)
#define AN_D BIT(29)
#define HIGHZ_D BIT(30)
+#define MASTER_ENABLE_D BIT(31)
+#define MASTER_ENABLE_B_C_D \
+ (MASTER_ENABLE_B | MASTER_ENABLE_C | MASTER_ENABLE_D)
#define XUSB_AO_UHSIC_SLEEPWALK(x) (0x120 + (x) * 4)
/* phase A */
@@ -417,6 +425,8 @@ static int tegra186_utmi_enable_phy_sleepwalk(struct tegra_xusb_lane *lane,
value |= HIGHZ_A;
value |= AP_A;
value |= AN_B | AN_C | AN_D;
+ if (padctl->soc->supports_lp_cfg_en)
+ value |= MASTER_ENABLE_B_C_D;
break;
case USB_SPEED_LOW:
@@ -424,6 +434,8 @@ static int tegra186_utmi_enable_phy_sleepwalk(struct tegra_xusb_lane *lane,
value |= HIGHZ_A;
value |= AN_A;
value |= AP_B | AP_C | AP_D;
+ if (padctl->soc->supports_lp_cfg_en)
+ value |= MASTER_ENABLE_B_C_D;
break;
default:
@@ -488,6 +500,13 @@ static int tegra186_utmi_disable_phy_sleepwalk(struct tegra_xusb_lane *lane)
value |= WAKE_VAL_NONE;
ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
+ if (padctl->soc->supports_lp_cfg_en) {
+ /* disable the four stages of sleepwalk */
+ value = ao_readl(priv, XUSB_AO_UTMIP_SLEEPWALK(index));
+ value &= ~(MASTER_ENABLE_A | MASTER_ENABLE_B_C_D);
+ ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK(index));
+ }
+
/* power down the line state detectors of the port */
value = ao_readl(priv, XUSB_AO_UTMIP_PAD_CFG(index));
value |= USBOP_VAL_PD | USBON_VAL_PD;
@@ -1673,6 +1692,7 @@ const struct tegra_xusb_padctl_soc tegra234_xusb_padctl_soc = {
.supports_gen2 = true,
.poll_trk_completed = true,
.trk_hw_mode = true,
+ .supports_lp_cfg_en = true,
};
EXPORT_SYMBOL_GPL(tegra234_xusb_padctl_soc);
#endif
diff --git a/drivers/phy/tegra/xusb.c b/drivers/phy/tegra/xusb.c
index 78045bd6c214..b55d4e9f42b5 100644
--- a/drivers/phy/tegra/xusb.c
+++ b/drivers/phy/tegra/xusb.c
@@ -805,6 +805,7 @@ static int tegra_xusb_add_usb2_port(struct tegra_xusb_padctl *padctl,
usb2->base.lane = usb2->base.ops->map(&usb2->base);
if (IS_ERR(usb2->base.lane)) {
err = PTR_ERR(usb2->base.lane);
+ tegra_xusb_port_unregister(&usb2->base);
goto out;
}
@@ -871,6 +872,7 @@ static int tegra_xusb_add_ulpi_port(struct tegra_xusb_padctl *padctl,
ulpi->base.lane = ulpi->base.ops->map(&ulpi->base);
if (IS_ERR(ulpi->base.lane)) {
err = PTR_ERR(ulpi->base.lane);
+ tegra_xusb_port_unregister(&ulpi->base);
goto out;
}
@@ -1267,7 +1269,7 @@ remove:
return err;
}
-static int tegra_xusb_padctl_remove(struct platform_device *pdev)
+static void tegra_xusb_padctl_remove(struct platform_device *pdev)
{
struct tegra_xusb_padctl *padctl = platform_get_drvdata(pdev);
int err;
@@ -1285,8 +1287,6 @@ static int tegra_xusb_padctl_remove(struct platform_device *pdev)
dev_err(&pdev->dev, "failed to assert reset: %d\n", err);
padctl->soc->ops->remove(padctl);
-
- return 0;
}
static __maybe_unused int tegra_xusb_padctl_suspend_noirq(struct device *dev)
@@ -1321,7 +1321,7 @@ static struct platform_driver tegra_xusb_padctl_driver = {
.pm = &tegra_xusb_padctl_pm_ops,
},
.probe = tegra_xusb_padctl_probe,
- .remove = tegra_xusb_padctl_remove,
+ .remove_new = tegra_xusb_padctl_remove,
};
module_platform_driver(tegra_xusb_padctl_driver);
diff --git a/drivers/phy/tegra/xusb.h b/drivers/phy/tegra/xusb.h
index 8bd6cd281119..6e45d194c689 100644
--- a/drivers/phy/tegra/xusb.h
+++ b/drivers/phy/tegra/xusb.h
@@ -434,6 +434,7 @@ struct tegra_xusb_padctl_soc {
bool need_fake_usb3_port;
bool poll_trk_completed;
bool trk_hw_mode;
+ bool supports_lp_cfg_en;
};
struct tegra_xusb_padctl {
diff --git a/drivers/phy/ti/phy-am654-serdes.c b/drivers/phy/ti/phy-am654-serdes.c
index 0be727bb9f79..4ed2d951d3df 100644
--- a/drivers/phy/ti/phy-am654-serdes.c
+++ b/drivers/phy/ti/phy-am654-serdes.c
@@ -842,20 +842,18 @@ clk_err:
return ret;
}
-static int serdes_am654_remove(struct platform_device *pdev)
+static void serdes_am654_remove(struct platform_device *pdev)
{
struct serdes_am654 *am654_phy = platform_get_drvdata(pdev);
struct device_node *node = am654_phy->of_node;
pm_runtime_disable(&pdev->dev);
of_clk_del_provider(node);
-
- return 0;
}
static struct platform_driver serdes_am654_driver = {
.probe = serdes_am654_probe,
- .remove = serdes_am654_remove,
+ .remove_new = serdes_am654_remove,
.driver = {
.name = "phy-am654",
.of_match_table = serdes_am654_id_table,
diff --git a/drivers/phy/ti/phy-da8xx-usb.c b/drivers/phy/ti/phy-da8xx-usb.c
index 83bc0a9afe12..b7a9ef3f4654 100644
--- a/drivers/phy/ti/phy-da8xx-usb.c
+++ b/drivers/phy/ti/phy-da8xx-usb.c
@@ -211,7 +211,7 @@ static int da8xx_usb_phy_probe(struct platform_device *pdev)
return 0;
}
-static int da8xx_usb_phy_remove(struct platform_device *pdev)
+static void da8xx_usb_phy_remove(struct platform_device *pdev)
{
struct da8xx_usb_phy *d_phy = platform_get_drvdata(pdev);
@@ -219,8 +219,6 @@ static int da8xx_usb_phy_remove(struct platform_device *pdev)
phy_remove_lookup(d_phy->usb20_phy, "usb-phy", "musb-da8xx");
phy_remove_lookup(d_phy->usb11_phy, "usb-phy", "ohci-da8xx");
}
-
- return 0;
}
static const struct of_device_id da8xx_usb_phy_ids[] = {
@@ -231,7 +229,7 @@ MODULE_DEVICE_TABLE(of, da8xx_usb_phy_ids);
static struct platform_driver da8xx_usb_phy_driver = {
.probe = da8xx_usb_phy_probe,
- .remove = da8xx_usb_phy_remove,
+ .remove_new = da8xx_usb_phy_remove,
.driver = {
.name = "da8xx-usb-phy",
.of_match_table = da8xx_usb_phy_ids,
diff --git a/drivers/phy/ti/phy-dm816x-usb.c b/drivers/phy/ti/phy-dm816x-usb.c
index fb619908f912..db153a55f4e1 100644
--- a/drivers/phy/ti/phy-dm816x-usb.c
+++ b/drivers/phy/ti/phy-dm816x-usb.c
@@ -257,20 +257,18 @@ clk_unprepare:
return error;
}
-static int dm816x_usb_phy_remove(struct platform_device *pdev)
+static void dm816x_usb_phy_remove(struct platform_device *pdev)
{
struct dm816x_usb_phy *phy = platform_get_drvdata(pdev);
usb_remove_phy(&phy->phy);
pm_runtime_disable(phy->dev);
clk_unprepare(phy->refclk);
-
- return 0;
}
static struct platform_driver dm816x_usb_phy_driver = {
.probe = dm816x_usb_phy_probe,
- .remove = dm816x_usb_phy_remove,
+ .remove_new = dm816x_usb_phy_remove,
.driver = {
.name = "dm816x-usb-phy",
.pm = &dm816x_usb_phy_pm_ops,
diff --git a/drivers/phy/ti/phy-j721e-wiz.c b/drivers/phy/ti/phy-j721e-wiz.c
index 1b83c98a78f0..d91923799df2 100644
--- a/drivers/phy/ti/phy-j721e-wiz.c
+++ b/drivers/phy/ti/phy-j721e-wiz.c
@@ -443,18 +443,17 @@ static int wiz_mode_select(struct wiz *wiz)
int i;
for (i = 0; i < num_lanes; i++) {
- if (wiz->lane_phy_type[i] == PHY_TYPE_DP)
+ if (wiz->lane_phy_type[i] == PHY_TYPE_DP) {
mode = LANE_MODE_GEN1;
- else if (wiz->lane_phy_type[i] == PHY_TYPE_QSGMII)
+ } else if (wiz->lane_phy_type[i] == PHY_TYPE_QSGMII) {
mode = LANE_MODE_GEN2;
- else
- continue;
-
- if (wiz->lane_phy_type[i] == PHY_TYPE_USXGMII) {
+ } else if (wiz->lane_phy_type[i] == PHY_TYPE_USXGMII) {
ret = regmap_field_write(wiz->p0_mac_src_sel[i], 0x3);
ret = regmap_field_write(wiz->p0_rxfclk_sel[i], 0x3);
ret = regmap_field_write(wiz->p0_refclk_sel[i], 0x3);
mode = LANE_MODE_GEN1;
+ } else {
+ continue;
}
ret = regmap_field_write(wiz->p_standard_mode[i], mode);
@@ -1235,6 +1234,8 @@ static int wiz_phy_fullrt_div(struct wiz *wiz, int lane)
if (wiz->lane_phy_type[lane] == PHY_TYPE_PCIE)
return regmap_field_write(wiz->p0_fullrt_div[lane], 0x1);
break;
+
+ case J721E_WIZ_16G:
case J721E_WIZ_10G:
case J7200_WIZ_10G:
case J721S2_WIZ_10G:
@@ -1636,7 +1637,7 @@ err_addr_to_resource:
return ret;
}
-static int wiz_remove(struct platform_device *pdev)
+static void wiz_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *node = dev->of_node;
@@ -1650,13 +1651,11 @@ static int wiz_remove(struct platform_device *pdev)
wiz_clock_cleanup(wiz, node);
pm_runtime_put(dev);
pm_runtime_disable(dev);
-
- return 0;
}
static struct platform_driver wiz_driver = {
.probe = wiz_probe,
- .remove = wiz_remove,
+ .remove_new = wiz_remove,
.driver = {
.name = "wiz",
.of_match_table = wiz_id_table,
diff --git a/drivers/phy/ti/phy-omap-usb2.c b/drivers/phy/ti/phy-omap-usb2.c
index 31a775877f6e..762d3de8b3c5 100644
--- a/drivers/phy/ti/phy-omap-usb2.c
+++ b/drivers/phy/ti/phy-omap-usb2.c
@@ -445,11 +445,9 @@ static int omap_usb2_probe(struct platform_device *pdev)
PTR_ERR(phy->wkupclk));
phy->wkupclk = devm_clk_get(phy->dev, "usb_phy_cm_clk32k");
- if (IS_ERR(phy->wkupclk)) {
- if (PTR_ERR(phy->wkupclk) != -EPROBE_DEFER)
- dev_err(&pdev->dev, "unable to get usb_phy_cm_clk32k\n");
- return PTR_ERR(phy->wkupclk);
- }
+ if (IS_ERR(phy->wkupclk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(phy->wkupclk),
+ "unable to get usb_phy_cm_clk32k\n");
dev_warn(&pdev->dev,
"found usb_phy_cm_clk32k, please fix DTS\n");
@@ -506,19 +504,17 @@ static int omap_usb2_probe(struct platform_device *pdev)
return 0;
}
-static int omap_usb2_remove(struct platform_device *pdev)
+static void omap_usb2_remove(struct platform_device *pdev)
{
struct omap_usb *phy = platform_get_drvdata(pdev);
usb_remove_phy(&phy->phy);
pm_runtime_disable(phy->dev);
-
- return 0;
}
static struct platform_driver omap_usb2_driver = {
.probe = omap_usb2_probe,
- .remove = omap_usb2_remove,
+ .remove_new = omap_usb2_remove,
.driver = {
.name = "omap-usb2",
.of_match_table = omap_usb2_id_table,
diff --git a/drivers/phy/ti/phy-ti-pipe3.c b/drivers/phy/ti/phy-ti-pipe3.c
index f502c36f3be5..507e1552db5e 100644
--- a/drivers/phy/ti/phy-ti-pipe3.c
+++ b/drivers/phy/ti/phy-ti-pipe3.c
@@ -841,7 +841,7 @@ static int ti_pipe3_probe(struct platform_device *pdev)
return PTR_ERR_OR_ZERO(phy_provider);
}
-static int ti_pipe3_remove(struct platform_device *pdev)
+static void ti_pipe3_remove(struct platform_device *pdev)
{
struct ti_pipe3 *phy = platform_get_drvdata(pdev);
@@ -850,8 +850,6 @@ static int ti_pipe3_remove(struct platform_device *pdev)
phy->sata_refclk_enabled = false;
}
pm_runtime_disable(&pdev->dev);
-
- return 0;
}
static int ti_pipe3_enable_clocks(struct ti_pipe3 *phy)
@@ -928,7 +926,7 @@ MODULE_DEVICE_TABLE(of, ti_pipe3_id_table);
static struct platform_driver ti_pipe3_driver = {
.probe = ti_pipe3_probe,
- .remove = ti_pipe3_remove,
+ .remove_new = ti_pipe3_remove,
.driver = {
.name = "ti-pipe3",
.of_match_table = ti_pipe3_id_table,
diff --git a/drivers/phy/ti/phy-twl4030-usb.c b/drivers/phy/ti/phy-twl4030-usb.c
index ac71017a0bc1..da50732625d1 100644
--- a/drivers/phy/ti/phy-twl4030-usb.c
+++ b/drivers/phy/ti/phy-twl4030-usb.c
@@ -787,7 +787,7 @@ static int twl4030_usb_probe(struct platform_device *pdev)
return 0;
}
-static int twl4030_usb_remove(struct platform_device *pdev)
+static void twl4030_usb_remove(struct platform_device *pdev)
{
struct twl4030_usb *twl = platform_get_drvdata(pdev);
int val;
@@ -821,8 +821,6 @@ static int twl4030_usb_remove(struct platform_device *pdev)
/* disable complete OTG block */
twl4030_usb_clear_bits(twl, POWER_CTRL, POWER_CTRL_OTG_ENAB);
-
- return 0;
}
#ifdef CONFIG_OF
@@ -835,7 +833,7 @@ MODULE_DEVICE_TABLE(of, twl4030_usb_id_table);
static struct platform_driver twl4030_usb_driver = {
.probe = twl4030_usb_probe,
- .remove = twl4030_usb_remove,
+ .remove_new = twl4030_usb_remove,
.driver = {
.name = "twl4030_usb",
.pm = &twl4030_usb_pm_ops,
diff --git a/drivers/phy/xilinx/phy-zynqmp.c b/drivers/phy/xilinx/phy-zynqmp.c
index 9be9535ad7ab..8833680923a1 100644
--- a/drivers/phy/xilinx/phy-zynqmp.c
+++ b/drivers/phy/xilinx/phy-zynqmp.c
@@ -8,9 +8,8 @@
* Author: Subbaraya Sundeep <sundeep.lkml@gmail.com>
* Author: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
*
- * This driver is tested for USB, SATA and Display Port currently.
- * Other controllers PCIe and SGMII should also work but that is
- * experimental as of now.
+ * This driver is tested for USB, SGMII, SATA and Display Port currently.
+ * PCIe should also work but that is experimental as of now.
*/
#include <linux/clk.h>
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index dae023d783a2..8df861b1f4a3 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -51,6 +51,18 @@ config PWM_AB8500
To compile this driver as a module, choose M here: the module
will be called pwm-ab8500.
+config PWM_APPLE
+ tristate "Apple SoC PWM support"
+ depends on ARCH_APPLE || COMPILE_TEST
+ help
+ Generic PWM framework driver for PWM controller present on
+ Apple SoCs
+
+ Say Y here if you have an ARM Apple laptop, otherwise say N
+
+ To compile this driver as a module, choose M here: the module
+ will be called pwm-apple.
+
config PWM_ATMEL
tristate "Atmel PWM support"
depends on ARCH_AT91 || COMPILE_TEST
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 7bf1a29f02b8..19899b912e00 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -2,6 +2,7 @@
obj-$(CONFIG_PWM) += core.o
obj-$(CONFIG_PWM_SYSFS) += sysfs.o
obj-$(CONFIG_PWM_AB8500) += pwm-ab8500.o
+obj-$(CONFIG_PWM_APPLE) += pwm-apple.o
obj-$(CONFIG_PWM_ATMEL) += pwm-atmel.o
obj-$(CONFIG_PWM_ATMEL_HLCDC_PWM) += pwm-atmel-hlcdc.o
obj-$(CONFIG_PWM_ATMEL_TCB) += pwm-atmel-tcb.o
diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index 474725714a05..3dacceaef4a9 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -28,17 +28,11 @@
static DEFINE_MUTEX(pwm_lookup_lock);
static LIST_HEAD(pwm_lookup_list);
-/* protects access to pwm_chips, allocated_pwms, and pwm_tree */
+/* protects access to pwm_chips and allocated_pwms */
static DEFINE_MUTEX(pwm_lock);
static LIST_HEAD(pwm_chips);
static DECLARE_BITMAP(allocated_pwms, MAX_PWMS);
-static RADIX_TREE(pwm_tree, GFP_KERNEL);
-
-static struct pwm_device *pwm_to_device(unsigned int pwm)
-{
- return radix_tree_lookup(&pwm_tree, pwm);
-}
/* Called with pwm_lock held */
static int alloc_pwms(unsigned int count)
@@ -59,14 +53,6 @@ static int alloc_pwms(unsigned int count)
/* Called with pwm_lock held */
static void free_pwms(struct pwm_chip *chip)
{
- unsigned int i;
-
- for (i = 0; i < chip->npwm; i++) {
- struct pwm_device *pwm = &chip->pwms[i];
-
- radix_tree_delete(&pwm_tree, pwm->pwm);
- }
-
bitmap_clear(allocated_pwms, chip->base, chip->npwm);
kfree(chip->pwms);
@@ -307,8 +293,6 @@ int pwmchip_add(struct pwm_chip *chip)
pwm->chip = chip;
pwm->pwm = chip->base + i;
pwm->hwpwm = i;
-
- radix_tree_insert(&pwm_tree, pwm->pwm, pwm);
}
list_add(&chip->list, &pwm_chips);
@@ -370,43 +354,6 @@ int devm_pwmchip_add(struct device *dev, struct pwm_chip *chip)
EXPORT_SYMBOL_GPL(devm_pwmchip_add);
/**
- * pwm_request() - request a PWM device
- * @pwm: global PWM device index
- * @label: PWM device label
- *
- * This function is deprecated, use pwm_get() instead.
- *
- * Returns: A pointer to a PWM device or an ERR_PTR()-encoded error code on
- * failure.
- */
-struct pwm_device *pwm_request(int pwm, const char *label)
-{
- struct pwm_device *dev;
- int err;
-
- if (pwm < 0 || pwm >= MAX_PWMS)
- return ERR_PTR(-EINVAL);
-
- mutex_lock(&pwm_lock);
-
- dev = pwm_to_device(pwm);
- if (!dev) {
- dev = ERR_PTR(-EPROBE_DEFER);
- goto out;
- }
-
- err = pwm_device_request(dev, label);
- if (err < 0)
- dev = ERR_PTR(err);
-
-out:
- mutex_unlock(&pwm_lock);
-
- return dev;
-}
-EXPORT_SYMBOL_GPL(pwm_request);
-
-/**
* pwm_request_from_chip() - request a PWM device relative to a PWM chip
* @chip: PWM chip
* @index: per-chip index of the PWM to request
@@ -438,18 +385,6 @@ struct pwm_device *pwm_request_from_chip(struct pwm_chip *chip,
}
EXPORT_SYMBOL_GPL(pwm_request_from_chip);
-/**
- * pwm_free() - free a PWM device
- * @pwm: PWM device
- *
- * This function is deprecated, use pwm_put() instead.
- */
-void pwm_free(struct pwm_device *pwm)
-{
- pwm_put(pwm);
-}
-EXPORT_SYMBOL_GPL(pwm_free);
-
static void pwm_apply_state_debug(struct pwm_device *pwm,
const struct pwm_state *state)
{
@@ -790,7 +725,7 @@ static struct pwm_device *of_pwm_get(struct device *dev, struct device_node *np,
dl = pwm_device_link_add(dev, pwm);
if (IS_ERR(dl)) {
/* of_xlate ended up calling pwm_request_from_chip() */
- pwm_free(pwm);
+ pwm_put(pwm);
pwm = ERR_CAST(dl);
goto put;
}
@@ -1014,7 +949,7 @@ struct pwm_device *pwm_get(struct device *dev, const char *con_id)
dl = pwm_device_link_add(dev, pwm);
if (IS_ERR(dl)) {
- pwm_free(pwm);
+ pwm_put(pwm);
return ERR_CAST(dl);
}
diff --git a/drivers/pwm/pwm-apple.c b/drivers/pwm/pwm-apple.c
new file mode 100644
index 000000000000..a38a62edd713
--- /dev/null
+++ b/drivers/pwm/pwm-apple.c
@@ -0,0 +1,159 @@
+// SPDX-License-Identifier: GPL-2.0 OR MIT
+/*
+ * Driver for the Apple SoC PWM controller
+ *
+ * Copyright The Asahi Linux Contributors
+ *
+ * Limitations:
+ * - The writes to cycle registers are shadowed until a write to
+ * the control register.
+ * - If both OFF_CYCLES and ON_CYCLES are set to 0, the output
+ * is a constant off signal.
+ * - When APPLE_PWM_CTRL is set to 0, the output is constant low
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/math64.h>
+
+#define APPLE_PWM_CTRL 0x00
+#define APPLE_PWM_ON_CYCLES 0x1c
+#define APPLE_PWM_OFF_CYCLES 0x18
+
+#define APPLE_PWM_CTRL_ENABLE BIT(0)
+#define APPLE_PWM_CTRL_MODE BIT(2)
+#define APPLE_PWM_CTRL_UPDATE BIT(5)
+#define APPLE_PWM_CTRL_TRIGGER BIT(9)
+#define APPLE_PWM_CTRL_INVERT BIT(10)
+#define APPLE_PWM_CTRL_OUTPUT_ENABLE BIT(14)
+
+struct apple_pwm {
+ struct pwm_chip chip;
+ void __iomem *base;
+ u64 clkrate;
+};
+
+static inline struct apple_pwm *to_apple_pwm(struct pwm_chip *chip)
+{
+ return container_of(chip, struct apple_pwm, chip);
+}
+
+static int apple_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+ const struct pwm_state *state)
+{
+ struct apple_pwm *fpwm;
+
+ if (state->polarity == PWM_POLARITY_INVERSED)
+ return -EINVAL;
+
+ fpwm = to_apple_pwm(chip);
+ if (state->enabled) {
+ u64 on_cycles, off_cycles;
+
+ on_cycles = mul_u64_u64_div_u64(fpwm->clkrate,
+ state->duty_cycle, NSEC_PER_SEC);
+ if (on_cycles > 0xFFFFFFFF)
+ on_cycles = 0xFFFFFFFF;
+
+ off_cycles = mul_u64_u64_div_u64(fpwm->clkrate,
+ state->period, NSEC_PER_SEC) - on_cycles;
+ if (off_cycles > 0xFFFFFFFF)
+ off_cycles = 0xFFFFFFFF;
+
+ writel(on_cycles, fpwm->base + APPLE_PWM_ON_CYCLES);
+ writel(off_cycles, fpwm->base + APPLE_PWM_OFF_CYCLES);
+ writel(APPLE_PWM_CTRL_ENABLE | APPLE_PWM_CTRL_OUTPUT_ENABLE | APPLE_PWM_CTRL_UPDATE,
+ fpwm->base + APPLE_PWM_CTRL);
+ } else {
+ writel(0, fpwm->base + APPLE_PWM_CTRL);
+ }
+ return 0;
+}
+
+static int apple_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
+ struct pwm_state *state)
+{
+ struct apple_pwm *fpwm;
+ u32 on_cycles, off_cycles, ctrl;
+
+ fpwm = to_apple_pwm(chip);
+
+ ctrl = readl(fpwm->base + APPLE_PWM_CTRL);
+ on_cycles = readl(fpwm->base + APPLE_PWM_ON_CYCLES);
+ off_cycles = readl(fpwm->base + APPLE_PWM_OFF_CYCLES);
+
+ state->enabled = (ctrl & APPLE_PWM_CTRL_ENABLE) && (ctrl & APPLE_PWM_CTRL_OUTPUT_ENABLE);
+ state->polarity = PWM_POLARITY_NORMAL;
+ // on_cycles + off_cycles is 33 bits, NSEC_PER_SEC is 30, there is no overflow
+ state->duty_cycle = DIV64_U64_ROUND_UP((u64)on_cycles * NSEC_PER_SEC, fpwm->clkrate);
+ state->period = DIV64_U64_ROUND_UP(((u64)off_cycles + (u64)on_cycles) *
+ NSEC_PER_SEC, fpwm->clkrate);
+
+ return 0;
+}
+
+static const struct pwm_ops apple_pwm_ops = {
+ .apply = apple_pwm_apply,
+ .get_state = apple_pwm_get_state,
+ .owner = THIS_MODULE,
+};
+
+static int apple_pwm_probe(struct platform_device *pdev)
+{
+ struct apple_pwm *fpwm;
+ struct clk *clk;
+ int ret;
+
+ fpwm = devm_kzalloc(&pdev->dev, sizeof(*fpwm), GFP_KERNEL);
+ if (!fpwm)
+ return -ENOMEM;
+
+ fpwm->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(fpwm->base))
+ return PTR_ERR(fpwm->base);
+
+ clk = devm_clk_get_enabled(&pdev->dev, NULL);
+ if (IS_ERR(clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(clk), "unable to get the clock");
+
+ /*
+ * Uses the 24MHz system clock on all existing devices, can only
+ * happen if the device tree is broken
+ *
+ * This check is done to prevent an overflow in .apply
+ */
+ fpwm->clkrate = clk_get_rate(clk);
+ if (fpwm->clkrate > NSEC_PER_SEC)
+ return dev_err_probe(&pdev->dev, -EINVAL, "pwm clock out of range");
+
+ fpwm->chip.dev = &pdev->dev;
+ fpwm->chip.npwm = 1;
+ fpwm->chip.ops = &apple_pwm_ops;
+
+ ret = devm_pwmchip_add(&pdev->dev, &fpwm->chip);
+ if (ret < 0)
+ return dev_err_probe(&pdev->dev, ret, "unable to add pwm chip");
+
+ return 0;
+}
+
+static const struct of_device_id apple_pwm_of_match[] = {
+ { .compatible = "apple,s5l-fpwm" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, apple_pwm_of_match);
+
+static struct platform_driver apple_pwm_driver = {
+ .probe = apple_pwm_probe,
+ .driver = {
+ .name = "apple-pwm",
+ .of_match_table = apple_pwm_of_match,
+ },
+};
+module_platform_driver(apple_pwm_driver);
+
+MODULE_DESCRIPTION("Apple SoC PWM driver");
+MODULE_LICENSE("Dual MIT/GPL");
diff --git a/drivers/pwm/pwm-atmel-hlcdc.c b/drivers/pwm/pwm-atmel-hlcdc.c
index a43b2babc809..96a709a9d49a 100644
--- a/drivers/pwm/pwm-atmel-hlcdc.c
+++ b/drivers/pwm/pwm-atmel-hlcdc.c
@@ -278,15 +278,13 @@ static int atmel_hlcdc_pwm_probe(struct platform_device *pdev)
return 0;
}
-static int atmel_hlcdc_pwm_remove(struct platform_device *pdev)
+static void atmel_hlcdc_pwm_remove(struct platform_device *pdev)
{
struct atmel_hlcdc_pwm *chip = platform_get_drvdata(pdev);
pwmchip_remove(&chip->chip);
clk_disable_unprepare(chip->hlcdc->periph_clk);
-
- return 0;
}
static const struct of_device_id atmel_hlcdc_pwm_dt_ids[] = {
@@ -301,7 +299,7 @@ static struct platform_driver atmel_hlcdc_pwm_driver = {
.pm = &atmel_hlcdc_pwm_pm_ops,
},
.probe = atmel_hlcdc_pwm_probe,
- .remove = atmel_hlcdc_pwm_remove,
+ .remove_new = atmel_hlcdc_pwm_remove,
};
module_platform_driver(atmel_hlcdc_pwm_driver);
diff --git a/drivers/pwm/pwm-atmel-tcb.c b/drivers/pwm/pwm-atmel-tcb.c
index 2837b4ce8053..4a116dc44f6e 100644
--- a/drivers/pwm/pwm-atmel-tcb.c
+++ b/drivers/pwm/pwm-atmel-tcb.c
@@ -500,7 +500,7 @@ err_slow_clk:
return err;
}
-static int atmel_tcb_pwm_remove(struct platform_device *pdev)
+static void atmel_tcb_pwm_remove(struct platform_device *pdev)
{
struct atmel_tcb_pwm_chip *tcbpwm = platform_get_drvdata(pdev);
@@ -509,8 +509,6 @@ static int atmel_tcb_pwm_remove(struct platform_device *pdev)
clk_disable_unprepare(tcbpwm->slow_clk);
clk_put(tcbpwm->slow_clk);
clk_put(tcbpwm->clk);
-
- return 0;
}
static const struct of_device_id atmel_tcb_pwm_dt_ids[] = {
@@ -564,7 +562,7 @@ static struct platform_driver atmel_tcb_pwm_driver = {
.pm = &atmel_tcb_pwm_pm_ops,
},
.probe = atmel_tcb_pwm_probe,
- .remove = atmel_tcb_pwm_remove,
+ .remove_new = atmel_tcb_pwm_remove,
};
module_platform_driver(atmel_tcb_pwm_driver);
diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c
index cdbc23649032..0c567d9623cd 100644
--- a/drivers/pwm/pwm-atmel.c
+++ b/drivers/pwm/pwm-atmel.c
@@ -511,15 +511,13 @@ unprepare_clk:
return ret;
}
-static int atmel_pwm_remove(struct platform_device *pdev)
+static void atmel_pwm_remove(struct platform_device *pdev)
{
struct atmel_pwm_chip *atmel_pwm = platform_get_drvdata(pdev);
pwmchip_remove(&atmel_pwm->chip);
clk_unprepare(atmel_pwm->clk);
-
- return 0;
}
static struct platform_driver atmel_pwm_driver = {
@@ -528,7 +526,7 @@ static struct platform_driver atmel_pwm_driver = {
.of_match_table = of_match_ptr(atmel_pwm_dt_ids),
},
.probe = atmel_pwm_probe,
- .remove = atmel_pwm_remove,
+ .remove_new = atmel_pwm_remove,
};
module_platform_driver(atmel_pwm_driver);
diff --git a/drivers/pwm/pwm-bcm-iproc.c b/drivers/pwm/pwm-bcm-iproc.c
index 97ec131eb7c1..7d70b6f186a6 100644
--- a/drivers/pwm/pwm-bcm-iproc.c
+++ b/drivers/pwm/pwm-bcm-iproc.c
@@ -239,15 +239,13 @@ static int iproc_pwmc_probe(struct platform_device *pdev)
return ret;
}
-static int iproc_pwmc_remove(struct platform_device *pdev)
+static void iproc_pwmc_remove(struct platform_device *pdev)
{
struct iproc_pwmc *ip = platform_get_drvdata(pdev);
pwmchip_remove(&ip->chip);
clk_disable_unprepare(ip->clk);
-
- return 0;
}
static const struct of_device_id bcm_iproc_pwmc_dt[] = {
@@ -262,7 +260,7 @@ static struct platform_driver iproc_pwmc_driver = {
.of_match_table = bcm_iproc_pwmc_dt,
},
.probe = iproc_pwmc_probe,
- .remove = iproc_pwmc_remove,
+ .remove_new = iproc_pwmc_remove,
};
module_platform_driver(iproc_pwmc_driver);
diff --git a/drivers/pwm/pwm-bcm2835.c b/drivers/pwm/pwm-bcm2835.c
index 50b8594be31d..bdfc2a5ec0d6 100644
--- a/drivers/pwm/pwm-bcm2835.c
+++ b/drivers/pwm/pwm-bcm2835.c
@@ -173,15 +173,13 @@ add_fail:
return ret;
}
-static int bcm2835_pwm_remove(struct platform_device *pdev)
+static void bcm2835_pwm_remove(struct platform_device *pdev)
{
struct bcm2835_pwm *pc = platform_get_drvdata(pdev);
pwmchip_remove(&pc->chip);
clk_disable_unprepare(pc->clk);
-
- return 0;
}
static const struct of_device_id bcm2835_pwm_of_match[] = {
@@ -196,7 +194,7 @@ static struct platform_driver bcm2835_pwm_driver = {
.of_match_table = bcm2835_pwm_of_match,
},
.probe = bcm2835_pwm_probe,
- .remove = bcm2835_pwm_remove,
+ .remove_new = bcm2835_pwm_remove,
};
module_platform_driver(bcm2835_pwm_driver);
diff --git a/drivers/pwm/pwm-berlin.c b/drivers/pwm/pwm-berlin.c
index e157273fd2f7..0c5992a046b2 100644
--- a/drivers/pwm/pwm-berlin.c
+++ b/drivers/pwm/pwm-berlin.c
@@ -250,15 +250,13 @@ static int berlin_pwm_probe(struct platform_device *pdev)
return 0;
}
-static int berlin_pwm_remove(struct platform_device *pdev)
+static void berlin_pwm_remove(struct platform_device *pdev)
{
struct berlin_pwm_chip *bpc = platform_get_drvdata(pdev);
pwmchip_remove(&bpc->chip);
clk_disable_unprepare(bpc->clk);
-
- return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -317,7 +315,7 @@ static SIMPLE_DEV_PM_OPS(berlin_pwm_pm_ops, berlin_pwm_suspend,
static struct platform_driver berlin_pwm_driver = {
.probe = berlin_pwm_probe,
- .remove = berlin_pwm_remove,
+ .remove_new = berlin_pwm_remove,
.driver = {
.name = "berlin-pwm",
.of_match_table = berlin_pwm_match,
diff --git a/drivers/pwm/pwm-brcmstb.c b/drivers/pwm/pwm-brcmstb.c
index 3db3f96edf78..a3faa9a3de7c 100644
--- a/drivers/pwm/pwm-brcmstb.c
+++ b/drivers/pwm/pwm-brcmstb.c
@@ -275,14 +275,12 @@ out_clk:
return ret;
}
-static int brcmstb_pwm_remove(struct platform_device *pdev)
+static void brcmstb_pwm_remove(struct platform_device *pdev)
{
struct brcmstb_pwm *p = platform_get_drvdata(pdev);
pwmchip_remove(&p->chip);
clk_disable_unprepare(p->clk);
-
- return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -310,7 +308,7 @@ static SIMPLE_DEV_PM_OPS(brcmstb_pwm_pm_ops, brcmstb_pwm_suspend,
static struct platform_driver brcmstb_pwm_driver = {
.probe = brcmstb_pwm_probe,
- .remove = brcmstb_pwm_remove,
+ .remove_new = brcmstb_pwm_remove,
.driver = {
.name = "pwm-brcmstb",
.of_match_table = brcmstb_pwm_of_match,
diff --git a/drivers/pwm/pwm-clk.c b/drivers/pwm/pwm-clk.c
index c2a503d684a7..f1da99881adf 100644
--- a/drivers/pwm/pwm-clk.c
+++ b/drivers/pwm/pwm-clk.c
@@ -112,7 +112,7 @@ static int pwm_clk_probe(struct platform_device *pdev)
return 0;
}
-static int pwm_clk_remove(struct platform_device *pdev)
+static void pwm_clk_remove(struct platform_device *pdev)
{
struct pwm_clk_chip *pcchip = platform_get_drvdata(pdev);
@@ -122,8 +122,6 @@ static int pwm_clk_remove(struct platform_device *pdev)
clk_disable(pcchip->clk);
clk_unprepare(pcchip->clk);
-
- return 0;
}
static const struct of_device_id pwm_clk_dt_ids[] = {
@@ -138,7 +136,7 @@ static struct platform_driver pwm_clk_driver = {
.of_match_table = pwm_clk_dt_ids,
},
.probe = pwm_clk_probe,
- .remove = pwm_clk_remove,
+ .remove_new = pwm_clk_remove,
};
module_platform_driver(pwm_clk_driver);
diff --git a/drivers/pwm/pwm-cros-ec.c b/drivers/pwm/pwm-cros-ec.c
index ad18b0ebe3f1..74e863aa1d8d 100644
--- a/drivers/pwm/pwm-cros-ec.c
+++ b/drivers/pwm/pwm-cros-ec.c
@@ -329,14 +329,12 @@ static int cros_ec_pwm_probe(struct platform_device *pdev)
return ret;
}
-static int cros_ec_pwm_remove(struct platform_device *dev)
+static void cros_ec_pwm_remove(struct platform_device *dev)
{
struct cros_ec_pwm_device *ec_pwm = platform_get_drvdata(dev);
struct pwm_chip *chip = &ec_pwm->chip;
pwmchip_remove(chip);
-
- return 0;
}
#ifdef CONFIG_OF
@@ -350,7 +348,7 @@ MODULE_DEVICE_TABLE(of, cros_ec_pwm_of_match);
static struct platform_driver cros_ec_pwm_driver = {
.probe = cros_ec_pwm_probe,
- .remove = cros_ec_pwm_remove,
+ .remove_new = cros_ec_pwm_remove,
.driver = {
.name = "cros-ec-pwm",
.of_match_table = of_match_ptr(cros_ec_pwm_of_match),
diff --git a/drivers/pwm/pwm-hibvt.c b/drivers/pwm/pwm-hibvt.c
index 1b9274c5ad87..b95df1a96127 100644
--- a/drivers/pwm/pwm-hibvt.c
+++ b/drivers/pwm/pwm-hibvt.c
@@ -245,7 +245,7 @@ static int hibvt_pwm_probe(struct platform_device *pdev)
return 0;
}
-static int hibvt_pwm_remove(struct platform_device *pdev)
+static void hibvt_pwm_remove(struct platform_device *pdev)
{
struct hibvt_pwm_chip *pwm_chip;
@@ -258,8 +258,6 @@ static int hibvt_pwm_remove(struct platform_device *pdev)
reset_control_deassert(pwm_chip->rstc);
clk_disable_unprepare(pwm_chip->clk);
-
- return 0;
}
static const struct of_device_id hibvt_pwm_of_match[] = {
@@ -281,7 +279,7 @@ static struct platform_driver hibvt_pwm_driver = {
.of_match_table = hibvt_pwm_of_match,
},
.probe = hibvt_pwm_probe,
- .remove = hibvt_pwm_remove,
+ .remove_new = hibvt_pwm_remove,
};
module_platform_driver(hibvt_pwm_driver);
diff --git a/drivers/pwm/pwm-img.c b/drivers/pwm/pwm-img.c
index 89362afe3c91..326af85888e7 100644
--- a/drivers/pwm/pwm-img.c
+++ b/drivers/pwm/pwm-img.c
@@ -343,7 +343,7 @@ err_pm_disable:
return ret;
}
-static int img_pwm_remove(struct platform_device *pdev)
+static void img_pwm_remove(struct platform_device *pdev)
{
struct img_pwm_chip *imgchip = platform_get_drvdata(pdev);
@@ -352,8 +352,6 @@ static int img_pwm_remove(struct platform_device *pdev)
img_pwm_runtime_suspend(&pdev->dev);
pwmchip_remove(&imgchip->chip);
-
- return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -423,7 +421,7 @@ static struct platform_driver img_pwm_driver = {
.of_match_table = img_pwm_of_match,
},
.probe = img_pwm_probe,
- .remove = img_pwm_remove,
+ .remove_new = img_pwm_remove,
};
module_platform_driver(img_pwm_driver);
diff --git a/drivers/pwm/pwm-imx-tpm.c b/drivers/pwm/pwm-imx-tpm.c
index ed1aad96fff0..5e2b452ee5f2 100644
--- a/drivers/pwm/pwm-imx-tpm.c
+++ b/drivers/pwm/pwm-imx-tpm.c
@@ -381,15 +381,13 @@ static int pwm_imx_tpm_probe(struct platform_device *pdev)
return ret;
}
-static int pwm_imx_tpm_remove(struct platform_device *pdev)
+static void pwm_imx_tpm_remove(struct platform_device *pdev)
{
struct imx_tpm_pwm_chip *tpm = platform_get_drvdata(pdev);
pwmchip_remove(&tpm->chip);
clk_disable_unprepare(tpm->clk);
-
- return 0;
}
static int __maybe_unused pwm_imx_tpm_suspend(struct device *dev)
@@ -432,7 +430,7 @@ static struct platform_driver imx_tpm_pwm_driver = {
.pm = &imx_tpm_pwm_pm,
},
.probe = pwm_imx_tpm_probe,
- .remove = pwm_imx_tpm_remove,
+ .remove_new = pwm_imx_tpm_remove,
};
module_platform_driver(imx_tpm_pwm_driver);
diff --git a/drivers/pwm/pwm-lpc18xx-sct.c b/drivers/pwm/pwm-lpc18xx-sct.c
index 378e1df944dc..b9bf5b366f4b 100644
--- a/drivers/pwm/pwm-lpc18xx-sct.c
+++ b/drivers/pwm/pwm-lpc18xx-sct.c
@@ -449,7 +449,7 @@ disable_pwmclk:
return ret;
}
-static int lpc18xx_pwm_remove(struct platform_device *pdev)
+static void lpc18xx_pwm_remove(struct platform_device *pdev)
{
struct lpc18xx_pwm_chip *lpc18xx_pwm = platform_get_drvdata(pdev);
u32 val;
@@ -461,8 +461,6 @@ static int lpc18xx_pwm_remove(struct platform_device *pdev)
val | LPC18XX_PWM_CTRL_HALT);
clk_disable_unprepare(lpc18xx_pwm->pwm_clk);
-
- return 0;
}
static struct platform_driver lpc18xx_pwm_driver = {
@@ -471,7 +469,7 @@ static struct platform_driver lpc18xx_pwm_driver = {
.of_match_table = lpc18xx_pwm_of_match,
},
.probe = lpc18xx_pwm_probe,
- .remove = lpc18xx_pwm_remove,
+ .remove_new = lpc18xx_pwm_remove,
};
module_platform_driver(lpc18xx_pwm_driver);
diff --git a/drivers/pwm/pwm-lpss-platform.c b/drivers/pwm/pwm-lpss-platform.c
index f350607e28bd..319809aac2c4 100644
--- a/drivers/pwm/pwm-lpss-platform.c
+++ b/drivers/pwm/pwm-lpss-platform.c
@@ -62,10 +62,9 @@ static int pwm_lpss_probe_platform(struct platform_device *pdev)
return 0;
}
-static int pwm_lpss_remove_platform(struct platform_device *pdev)
+static void pwm_lpss_remove_platform(struct platform_device *pdev)
{
pm_runtime_disable(&pdev->dev);
- return 0;
}
static const struct acpi_device_id pwm_lpss_acpi_match[] = {
@@ -83,7 +82,7 @@ static struct platform_driver pwm_lpss_driver_platform = {
.acpi_match_table = pwm_lpss_acpi_match,
},
.probe = pwm_lpss_probe_platform,
- .remove = pwm_lpss_remove_platform,
+ .remove_new = pwm_lpss_remove_platform,
};
module_platform_driver(pwm_lpss_driver_platform);
diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c
index 5cd7b90872c6..5732300eb004 100644
--- a/drivers/pwm/pwm-meson.c
+++ b/drivers/pwm/pwm-meson.c
@@ -418,7 +418,7 @@ static const struct meson_pwm_data pwm_axg_ee_data = {
};
static const char * const pwm_axg_ao_parent_names[] = {
- "aoclk81", "xtal", "fclk_div4", "fclk_div5"
+ "xtal", "axg_ao_clk81", "fclk_div4", "fclk_div5"
};
static const struct meson_pwm_data pwm_axg_ao_data = {
@@ -427,7 +427,7 @@ static const struct meson_pwm_data pwm_axg_ao_data = {
};
static const char * const pwm_g12a_ao_ab_parent_names[] = {
- "xtal", "aoclk81", "fclk_div4", "fclk_div5"
+ "xtal", "g12a_ao_clk81", "fclk_div4", "fclk_div5"
};
static const struct meson_pwm_data pwm_g12a_ao_ab_data = {
@@ -436,7 +436,7 @@ static const struct meson_pwm_data pwm_g12a_ao_ab_data = {
};
static const char * const pwm_g12a_ao_cd_parent_names[] = {
- "xtal", "aoclk81",
+ "xtal", "g12a_ao_clk81",
};
static const struct meson_pwm_data pwm_g12a_ao_cd_data = {
diff --git a/drivers/pwm/pwm-mtk-disp.c b/drivers/pwm/pwm-mtk-disp.c
index 692a06121b28..79e321e96f56 100644
--- a/drivers/pwm/pwm-mtk-disp.c
+++ b/drivers/pwm/pwm-mtk-disp.c
@@ -138,6 +138,19 @@ static int mtk_disp_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
high_width = mul_u64_u64_div_u64(state->duty_cycle, rate, div);
value = period | (high_width << PWM_HIGH_WIDTH_SHIFT);
+ if (mdp->data->bls_debug && !mdp->data->has_commit) {
+ /*
+ * For MT2701, disable double buffer before writing register
+ * and select manual mode and use PWM_PERIOD/PWM_HIGH_WIDTH.
+ */
+ mtk_disp_pwm_update_bits(mdp, mdp->data->bls_debug,
+ mdp->data->bls_debug_mask,
+ mdp->data->bls_debug_mask);
+ mtk_disp_pwm_update_bits(mdp, mdp->data->con0,
+ mdp->data->con0_sel,
+ mdp->data->con0_sel);
+ }
+
mtk_disp_pwm_update_bits(mdp, mdp->data->con0,
PWM_CLKDIV_MASK,
clk_div << PWM_CLKDIV_SHIFT);
@@ -152,17 +165,6 @@ static int mtk_disp_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
mtk_disp_pwm_update_bits(mdp, mdp->data->commit,
mdp->data->commit_mask,
0x0);
- } else {
- /*
- * For MT2701, disable double buffer before writing register
- * and select manual mode and use PWM_PERIOD/PWM_HIGH_WIDTH.
- */
- mtk_disp_pwm_update_bits(mdp, mdp->data->bls_debug,
- mdp->data->bls_debug_mask,
- mdp->data->bls_debug_mask);
- mtk_disp_pwm_update_bits(mdp, mdp->data->con0,
- mdp->data->con0_sel,
- mdp->data->con0_sel);
}
mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, mdp->data->enable_mask,
@@ -194,6 +196,16 @@ static int mtk_disp_pwm_get_state(struct pwm_chip *chip,
return err;
}
+ /*
+ * Apply DISP_PWM_DEBUG settings to choose whether to enable or disable
+ * registers double buffer and manual commit to working register before
+ * performing any read/write operation
+ */
+ if (mdp->data->bls_debug)
+ mtk_disp_pwm_update_bits(mdp, mdp->data->bls_debug,
+ mdp->data->bls_debug_mask,
+ mdp->data->bls_debug_mask);
+
rate = clk_get_rate(mdp->clk_main);
con0 = readl(mdp->base + mdp->data->con0);
con1 = readl(mdp->base + mdp->data->con1);
@@ -260,13 +272,11 @@ static int mtk_disp_pwm_probe(struct platform_device *pdev)
return 0;
}
-static int mtk_disp_pwm_remove(struct platform_device *pdev)
+static void mtk_disp_pwm_remove(struct platform_device *pdev)
{
struct mtk_disp_pwm *mdp = platform_get_drvdata(pdev);
pwmchip_remove(&mdp->chip);
-
- return 0;
}
static const struct mtk_pwm_data mt2701_pwm_data = {
@@ -314,7 +324,7 @@ static struct platform_driver mtk_disp_pwm_driver = {
.of_match_table = mtk_disp_pwm_of_match,
},
.probe = mtk_disp_pwm_probe,
- .remove = mtk_disp_pwm_remove,
+ .remove_new = mtk_disp_pwm_remove,
};
module_platform_driver(mtk_disp_pwm_driver);
diff --git a/drivers/pwm/pwm-omap-dmtimer.c b/drivers/pwm/pwm-omap-dmtimer.c
index fa800fcf31d4..4889fbd8a431 100644
--- a/drivers/pwm/pwm-omap-dmtimer.c
+++ b/drivers/pwm/pwm-omap-dmtimer.c
@@ -441,7 +441,7 @@ err_find_timer_pdev:
return ret;
}
-static int pwm_omap_dmtimer_remove(struct platform_device *pdev)
+static void pwm_omap_dmtimer_remove(struct platform_device *pdev)
{
struct pwm_omap_dmtimer_chip *omap = platform_get_drvdata(pdev);
@@ -455,8 +455,6 @@ static int pwm_omap_dmtimer_remove(struct platform_device *pdev)
put_device(&omap->dm_timer_pdev->dev);
mutex_destroy(&omap->mutex);
-
- return 0;
}
static const struct of_device_id pwm_omap_dmtimer_of_match[] = {
@@ -471,7 +469,7 @@ static struct platform_driver pwm_omap_dmtimer_driver = {
.of_match_table = of_match_ptr(pwm_omap_dmtimer_of_match),
},
.probe = pwm_omap_dmtimer_probe,
- .remove = pwm_omap_dmtimer_remove,
+ .remove_new = pwm_omap_dmtimer_remove,
};
module_platform_driver(pwm_omap_dmtimer_driver);
diff --git a/drivers/pwm/pwm-rcar.c b/drivers/pwm/pwm-rcar.c
index 55f46d09602b..5b5f357c44de 100644
--- a/drivers/pwm/pwm-rcar.c
+++ b/drivers/pwm/pwm-rcar.c
@@ -238,15 +238,13 @@ static int rcar_pwm_probe(struct platform_device *pdev)
return 0;
}
-static int rcar_pwm_remove(struct platform_device *pdev)
+static void rcar_pwm_remove(struct platform_device *pdev)
{
struct rcar_pwm_chip *rcar_pwm = platform_get_drvdata(pdev);
pwmchip_remove(&rcar_pwm->chip);
pm_runtime_disable(&pdev->dev);
-
- return 0;
}
static const struct of_device_id rcar_pwm_of_table[] = {
@@ -257,10 +255,10 @@ MODULE_DEVICE_TABLE(of, rcar_pwm_of_table);
static struct platform_driver rcar_pwm_driver = {
.probe = rcar_pwm_probe,
- .remove = rcar_pwm_remove,
+ .remove_new = rcar_pwm_remove,
.driver = {
.name = "pwm-rcar",
- .of_match_table = of_match_ptr(rcar_pwm_of_table),
+ .of_match_table = rcar_pwm_of_table,
}
};
module_platform_driver(rcar_pwm_driver);
diff --git a/drivers/pwm/pwm-rockchip.c b/drivers/pwm/pwm-rockchip.c
index 7f084eb34092..c1a1f2d864b5 100644
--- a/drivers/pwm/pwm-rockchip.c
+++ b/drivers/pwm/pwm-rockchip.c
@@ -376,7 +376,7 @@ err_clk:
return ret;
}
-static int rockchip_pwm_remove(struct platform_device *pdev)
+static void rockchip_pwm_remove(struct platform_device *pdev)
{
struct rockchip_pwm_chip *pc = platform_get_drvdata(pdev);
@@ -384,8 +384,6 @@ static int rockchip_pwm_remove(struct platform_device *pdev)
clk_unprepare(pc->pclk);
clk_unprepare(pc->clk);
-
- return 0;
}
static struct platform_driver rockchip_pwm_driver = {
@@ -394,7 +392,7 @@ static struct platform_driver rockchip_pwm_driver = {
.of_match_table = rockchip_pwm_dt_ids,
},
.probe = rockchip_pwm_probe,
- .remove = rockchip_pwm_remove,
+ .remove_new = rockchip_pwm_remove,
};
module_platform_driver(rockchip_pwm_driver);
diff --git a/drivers/pwm/pwm-samsung.c b/drivers/pwm/pwm-samsung.c
index 9c5b4f515641..e8828f57ab15 100644
--- a/drivers/pwm/pwm-samsung.c
+++ b/drivers/pwm/pwm-samsung.c
@@ -621,15 +621,13 @@ static int pwm_samsung_probe(struct platform_device *pdev)
return 0;
}
-static int pwm_samsung_remove(struct platform_device *pdev)
+static void pwm_samsung_remove(struct platform_device *pdev)
{
struct samsung_pwm_chip *chip = platform_get_drvdata(pdev);
pwmchip_remove(&chip->chip);
clk_disable_unprepare(chip->base_clk);
-
- return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -676,7 +674,7 @@ static struct platform_driver pwm_samsung_driver = {
.of_match_table = of_match_ptr(samsung_pwm_matches),
},
.probe = pwm_samsung_probe,
- .remove = pwm_samsung_remove,
+ .remove_new = pwm_samsung_remove,
};
module_platform_driver(pwm_samsung_driver);
diff --git a/drivers/pwm/pwm-sifive.c b/drivers/pwm/pwm-sifive.c
index 393a4b97fc19..5b0574f635f6 100644
--- a/drivers/pwm/pwm-sifive.c
+++ b/drivers/pwm/pwm-sifive.c
@@ -313,7 +313,7 @@ disable_clk:
return ret;
}
-static int pwm_sifive_remove(struct platform_device *dev)
+static void pwm_sifive_remove(struct platform_device *dev)
{
struct pwm_sifive_ddata *ddata = platform_get_drvdata(dev);
struct pwm_device *pwm;
@@ -329,8 +329,6 @@ static int pwm_sifive_remove(struct platform_device *dev)
}
clk_unprepare(ddata->clk);
-
- return 0;
}
static const struct of_device_id pwm_sifive_of_match[] = {
@@ -341,7 +339,7 @@ MODULE_DEVICE_TABLE(of, pwm_sifive_of_match);
static struct platform_driver pwm_sifive_driver = {
.probe = pwm_sifive_probe,
- .remove = pwm_sifive_remove,
+ .remove_new = pwm_sifive_remove,
.driver = {
.name = "pwm-sifive",
.of_match_table = pwm_sifive_of_match,
diff --git a/drivers/pwm/pwm-spear.c b/drivers/pwm/pwm-spear.c
index 54c7990967dd..4e1cfd8d7c03 100644
--- a/drivers/pwm/pwm-spear.c
+++ b/drivers/pwm/pwm-spear.c
@@ -247,7 +247,7 @@ static int spear_pwm_probe(struct platform_device *pdev)
return ret;
}
-static int spear_pwm_remove(struct platform_device *pdev)
+static void spear_pwm_remove(struct platform_device *pdev)
{
struct spear_pwm_chip *pc = platform_get_drvdata(pdev);
@@ -255,8 +255,6 @@ static int spear_pwm_remove(struct platform_device *pdev)
/* clk was prepared in probe, hence unprepare it here */
clk_unprepare(pc->clk);
-
- return 0;
}
static const struct of_device_id spear_pwm_of_match[] = {
@@ -273,7 +271,7 @@ static struct platform_driver spear_pwm_driver = {
.of_match_table = spear_pwm_of_match,
},
.probe = spear_pwm_probe,
- .remove = spear_pwm_remove,
+ .remove_new = spear_pwm_remove,
};
module_platform_driver(spear_pwm_driver);
diff --git a/drivers/pwm/pwm-sprd.c b/drivers/pwm/pwm-sprd.c
index bde579a338c2..d43a6fa3f4e0 100644
--- a/drivers/pwm/pwm-sprd.c
+++ b/drivers/pwm/pwm-sprd.c
@@ -280,13 +280,11 @@ static int sprd_pwm_probe(struct platform_device *pdev)
return ret;
}
-static int sprd_pwm_remove(struct platform_device *pdev)
+static void sprd_pwm_remove(struct platform_device *pdev)
{
struct sprd_pwm_chip *spc = platform_get_drvdata(pdev);
pwmchip_remove(&spc->chip);
-
- return 0;
}
static const struct of_device_id sprd_pwm_of_match[] = {
@@ -301,7 +299,7 @@ static struct platform_driver sprd_pwm_driver = {
.of_match_table = sprd_pwm_of_match,
},
.probe = sprd_pwm_probe,
- .remove = sprd_pwm_remove,
+ .remove_new = sprd_pwm_remove,
};
module_platform_driver(sprd_pwm_driver);
diff --git a/drivers/pwm/pwm-sti.c b/drivers/pwm/pwm-sti.c
index 44b1f93256b3..b1d1373648a3 100644
--- a/drivers/pwm/pwm-sti.c
+++ b/drivers/pwm/pwm-sti.c
@@ -669,7 +669,7 @@ static int sti_pwm_probe(struct platform_device *pdev)
return 0;
}
-static int sti_pwm_remove(struct platform_device *pdev)
+static void sti_pwm_remove(struct platform_device *pdev)
{
struct sti_pwm_chip *pc = platform_get_drvdata(pdev);
@@ -677,8 +677,6 @@ static int sti_pwm_remove(struct platform_device *pdev)
clk_unprepare(pc->pwm_clk);
clk_unprepare(pc->cpt_clk);
-
- return 0;
}
static const struct of_device_id sti_pwm_of_match[] = {
@@ -693,7 +691,7 @@ static struct platform_driver sti_pwm_driver = {
.of_match_table = sti_pwm_of_match,
},
.probe = sti_pwm_probe,
- .remove = sti_pwm_remove,
+ .remove_new = sti_pwm_remove,
};
module_platform_driver(sti_pwm_driver);
diff --git a/drivers/pwm/pwm-stm32-lp.c b/drivers/pwm/pwm-stm32-lp.c
index f315fa106be8..bb3a045a7334 100644
--- a/drivers/pwm/pwm-stm32-lp.c
+++ b/drivers/pwm/pwm-stm32-lp.c
@@ -252,7 +252,7 @@ static struct platform_driver stm32_pwm_lp_driver = {
.probe = stm32_pwm_lp_probe,
.driver = {
.name = "stm32-pwm-lp",
- .of_match_table = of_match_ptr(stm32_pwm_lp_of_match),
+ .of_match_table = stm32_pwm_lp_of_match,
.pm = &stm32_pwm_lp_pm_ops,
},
};
diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c
index 21e4a34dfff3..62e397aeb9aa 100644
--- a/drivers/pwm/pwm-stm32.c
+++ b/drivers/pwm/pwm-stm32.c
@@ -207,6 +207,10 @@ static int stm32_pwm_capture(struct pwm_chip *chip, struct pwm_device *pwm,
regmap_write(priv->regmap, TIM_ARR, priv->max_arr);
regmap_write(priv->regmap, TIM_PSC, psc);
+ /* Reset input selector to its default input and disable slave mode */
+ regmap_write(priv->regmap, TIM_TISEL, 0x0);
+ regmap_write(priv->regmap, TIM_SMCR, 0x0);
+
/* Map TI1 or TI2 PWM input to IC1 & IC2 (or TI3/4 to IC3 & IC4) */
regmap_update_bits(priv->regmap,
pwm->hwpwm < 2 ? TIM_CCMR1 : TIM_CCMR2,
@@ -642,7 +646,7 @@ static int stm32_pwm_probe(struct platform_device *pdev)
return 0;
}
-static int stm32_pwm_remove(struct platform_device *pdev)
+static void stm32_pwm_remove(struct platform_device *pdev)
{
struct stm32_pwm *priv = platform_get_drvdata(pdev);
unsigned int i;
@@ -651,8 +655,6 @@ static int stm32_pwm_remove(struct platform_device *pdev)
pwm_disable(&priv->chip.pwms[i]);
pwmchip_remove(&priv->chip);
-
- return 0;
}
static int __maybe_unused stm32_pwm_suspend(struct device *dev)
@@ -699,7 +701,7 @@ MODULE_DEVICE_TABLE(of, stm32_pwm_of_match);
static struct platform_driver stm32_pwm_driver = {
.probe = stm32_pwm_probe,
- .remove = stm32_pwm_remove,
+ .remove_new = stm32_pwm_remove,
.driver = {
.name = "stm32-pwm",
.of_match_table = stm32_pwm_of_match,
diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c
index b973da73e9ab..a8790a8fc53e 100644
--- a/drivers/pwm/pwm-sun4i.c
+++ b/drivers/pwm/pwm-sun4i.c
@@ -477,7 +477,7 @@ err_bus:
return ret;
}
-static int sun4i_pwm_remove(struct platform_device *pdev)
+static void sun4i_pwm_remove(struct platform_device *pdev)
{
struct sun4i_pwm_chip *sun4ichip = platform_get_drvdata(pdev);
@@ -485,8 +485,6 @@ static int sun4i_pwm_remove(struct platform_device *pdev)
clk_disable_unprepare(sun4ichip->bus_clk);
reset_control_assert(sun4ichip->rst);
-
- return 0;
}
static struct platform_driver sun4i_pwm_driver = {
@@ -495,7 +493,7 @@ static struct platform_driver sun4i_pwm_driver = {
.of_match_table = sun4i_pwm_dt_ids,
},
.probe = sun4i_pwm_probe,
- .remove = sun4i_pwm_remove,
+ .remove_new = sun4i_pwm_remove,
};
module_platform_driver(sun4i_pwm_driver);
diff --git a/drivers/pwm/pwm-tegra.c b/drivers/pwm/pwm-tegra.c
index 249dc0193297..5810abf66e2a 100644
--- a/drivers/pwm/pwm-tegra.c
+++ b/drivers/pwm/pwm-tegra.c
@@ -350,7 +350,7 @@ put_pm:
return ret;
}
-static int tegra_pwm_remove(struct platform_device *pdev)
+static void tegra_pwm_remove(struct platform_device *pdev)
{
struct tegra_pwm_chip *pc = platform_get_drvdata(pdev);
@@ -359,8 +359,6 @@ static int tegra_pwm_remove(struct platform_device *pdev)
reset_control_assert(pc->rst);
pm_runtime_force_suspend(&pdev->dev);
-
- return 0;
}
static int __maybe_unused tegra_pwm_runtime_suspend(struct device *dev)
@@ -434,7 +432,7 @@ static struct platform_driver tegra_pwm_driver = {
.pm = &tegra_pwm_pm_ops,
},
.probe = tegra_pwm_probe,
- .remove = tegra_pwm_remove,
+ .remove_new = tegra_pwm_remove,
};
module_platform_driver(tegra_pwm_driver);
diff --git a/drivers/pwm/pwm-tiecap.c b/drivers/pwm/pwm-tiecap.c
index 4701f0c9b921..109449956307 100644
--- a/drivers/pwm/pwm-tiecap.c
+++ b/drivers/pwm/pwm-tiecap.c
@@ -265,11 +265,9 @@ static int ecap_pwm_probe(struct platform_device *pdev)
return 0;
}
-static int ecap_pwm_remove(struct platform_device *pdev)
+static void ecap_pwm_remove(struct platform_device *pdev)
{
pm_runtime_disable(&pdev->dev);
-
- return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -326,7 +324,7 @@ static struct platform_driver ecap_pwm_driver = {
.pm = &ecap_pwm_pm_ops,
},
.probe = ecap_pwm_probe,
- .remove = ecap_pwm_remove,
+ .remove_new = ecap_pwm_remove,
};
module_platform_driver(ecap_pwm_driver);
diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c
index 48ca0ff690ae..bb3959ace6b4 100644
--- a/drivers/pwm/pwm-tiehrpwm.c
+++ b/drivers/pwm/pwm-tiehrpwm.c
@@ -511,7 +511,7 @@ err_clk_unprepare:
return ret;
}
-static int ehrpwm_pwm_remove(struct platform_device *pdev)
+static void ehrpwm_pwm_remove(struct platform_device *pdev)
{
struct ehrpwm_pwm_chip *pc = platform_get_drvdata(pdev);
@@ -520,8 +520,6 @@ static int ehrpwm_pwm_remove(struct platform_device *pdev)
clk_unprepare(pc->tbclk);
pm_runtime_disable(&pdev->dev);
-
- return 0;
}
#ifdef CONFIG_PM_SLEEP
@@ -604,7 +602,7 @@ static struct platform_driver ehrpwm_pwm_driver = {
.pm = &ehrpwm_pwm_pm_ops,
},
.probe = ehrpwm_pwm_probe,
- .remove = ehrpwm_pwm_remove,
+ .remove_new = ehrpwm_pwm_remove,
};
module_platform_driver(ehrpwm_pwm_driver);
diff --git a/drivers/pwm/pwm-vt8500.c b/drivers/pwm/pwm-vt8500.c
index f1ff9940b37c..d2c48fd98706 100644
--- a/drivers/pwm/pwm-vt8500.c
+++ b/drivers/pwm/pwm-vt8500.c
@@ -279,20 +279,18 @@ static int vt8500_pwm_probe(struct platform_device *pdev)
return ret;
}
-static int vt8500_pwm_remove(struct platform_device *pdev)
+static void vt8500_pwm_remove(struct platform_device *pdev)
{
struct vt8500_chip *vt8500 = platform_get_drvdata(pdev);
pwmchip_remove(&vt8500->chip);
clk_unprepare(vt8500->clk);
-
- return 0;
}
static struct platform_driver vt8500_pwm_driver = {
.probe = vt8500_pwm_probe,
- .remove = vt8500_pwm_remove,
+ .remove_new = vt8500_pwm_remove,
.driver = {
.name = "vt8500-pwm",
.of_match_table = vt8500_pwm_dt_ids,
diff --git a/drivers/pwm/pwm-xilinx.c b/drivers/pwm/pwm-xilinx.c
index f7a50fdcd9a5..85153ee90809 100644
--- a/drivers/pwm/pwm-xilinx.c
+++ b/drivers/pwm/pwm-xilinx.c
@@ -292,14 +292,13 @@ static int xilinx_pwm_probe(struct platform_device *pdev)
return 0;
}
-static int xilinx_pwm_remove(struct platform_device *pdev)
+static void xilinx_pwm_remove(struct platform_device *pdev)
{
struct xilinx_pwm_device *xilinx_pwm = platform_get_drvdata(pdev);
pwmchip_remove(&xilinx_pwm->chip);
clk_rate_exclusive_put(xilinx_pwm->priv.clk);
clk_disable_unprepare(xilinx_pwm->priv.clk);
- return 0;
}
static const struct of_device_id xilinx_pwm_of_match[] = {
@@ -310,7 +309,7 @@ MODULE_DEVICE_TABLE(of, xilinx_pwm_of_match);
static struct platform_driver xilinx_pwm_driver = {
.probe = xilinx_pwm_probe,
- .remove = xilinx_pwm_remove,
+ .remove_new = xilinx_pwm_remove,
.driver = {
.name = "xilinx-pwm",
.of_match_table = of_match_ptr(xilinx_pwm_of_match),
diff --git a/drivers/soundwire/Kconfig b/drivers/soundwire/Kconfig
index 2b7795233282..fa71c9a36df7 100644
--- a/drivers/soundwire/Kconfig
+++ b/drivers/soundwire/Kconfig
@@ -18,6 +18,16 @@ if SOUNDWIRE
comment "SoundWire Devices"
+config SOUNDWIRE_AMD
+ tristate "AMD SoundWire Manager driver"
+ select SOUNDWIRE_GENERIC_ALLOCATION
+ depends on ACPI && SND_SOC
+ help
+ SoundWire AMD Manager driver.
+ If you have an AMD platform which has a SoundWire Manager then
+ enable this config option to get the SoundWire support for that
+ device.
+
config SOUNDWIRE_CADENCE
tristate
diff --git a/drivers/soundwire/Makefile b/drivers/soundwire/Makefile
index ca97414ada70..925566ff4272 100644
--- a/drivers/soundwire/Makefile
+++ b/drivers/soundwire/Makefile
@@ -15,12 +15,17 @@ ifdef CONFIG_DEBUG_FS
soundwire-bus-y += debugfs.o
endif
+#AMD driver
+soundwire-amd-y := amd_manager.o
+obj-$(CONFIG_SOUNDWIRE_AMD) += soundwire-amd.o
+
#Cadence Objs
soundwire-cadence-y := cadence_master.o
obj-$(CONFIG_SOUNDWIRE_CADENCE) += soundwire-cadence.o
#Intel driver
-soundwire-intel-y := intel.o intel_auxdevice.o intel_init.o dmi-quirks.o
+soundwire-intel-y := intel.o intel_auxdevice.o intel_init.o dmi-quirks.o \
+ intel_bus_common.o
obj-$(CONFIG_SOUNDWIRE_INTEL) += soundwire-intel.o
#Qualcomm driver
diff --git a/drivers/soundwire/amd_manager.c b/drivers/soundwire/amd_manager.c
new file mode 100644
index 000000000000..9fb7f91ca182
--- /dev/null
+++ b/drivers/soundwire/amd_manager.c
@@ -0,0 +1,1208 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * SoundWire AMD Manager driver
+ *
+ * Copyright 2023 Advanced Micro Devices, Inc.
+ */
+
+#include <linux/completion.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_registers.h>
+#include <linux/pm_runtime.h>
+#include <linux/wait.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "bus.h"
+#include "amd_manager.h"
+
+#define DRV_NAME "amd_sdw_manager"
+
+#define to_amd_sdw(b) container_of(b, struct amd_sdw_manager, bus)
+
+static void amd_enable_sdw_pads(struct amd_sdw_manager *amd_manager)
+{
+ u32 sw_pad_pulldown_val;
+ u32 val;
+
+ mutex_lock(amd_manager->acp_sdw_lock);
+ val = readl(amd_manager->acp_mmio + ACP_SW_PAD_KEEPER_EN);
+ val |= amd_manager->reg_mask->sw_pad_enable_mask;
+ writel(val, amd_manager->acp_mmio + ACP_SW_PAD_KEEPER_EN);
+ usleep_range(1000, 1500);
+
+ sw_pad_pulldown_val = readl(amd_manager->acp_mmio + ACP_PAD_PULLDOWN_CTRL);
+ sw_pad_pulldown_val &= amd_manager->reg_mask->sw_pad_pulldown_mask;
+ writel(sw_pad_pulldown_val, amd_manager->acp_mmio + ACP_PAD_PULLDOWN_CTRL);
+ mutex_unlock(amd_manager->acp_sdw_lock);
+}
+
+static int amd_init_sdw_manager(struct amd_sdw_manager *amd_manager)
+{
+ u32 val;
+ int ret;
+
+ writel(AMD_SDW_ENABLE, amd_manager->mmio + ACP_SW_EN);
+ ret = readl_poll_timeout(amd_manager->mmio + ACP_SW_EN_STATUS, val, val, ACP_DELAY_US,
+ AMD_SDW_TIMEOUT);
+ if (ret)
+ return ret;
+
+ /* SoundWire manager bus reset */
+ writel(AMD_SDW_BUS_RESET_REQ, amd_manager->mmio + ACP_SW_BUS_RESET_CTRL);
+ ret = readl_poll_timeout(amd_manager->mmio + ACP_SW_BUS_RESET_CTRL, val,
+ (val & AMD_SDW_BUS_RESET_DONE), ACP_DELAY_US, AMD_SDW_TIMEOUT);
+ if (ret)
+ return ret;
+
+ writel(AMD_SDW_BUS_RESET_CLEAR_REQ, amd_manager->mmio + ACP_SW_BUS_RESET_CTRL);
+ ret = readl_poll_timeout(amd_manager->mmio + ACP_SW_BUS_RESET_CTRL, val, !val,
+ ACP_DELAY_US, AMD_SDW_TIMEOUT);
+ if (ret) {
+ dev_err(amd_manager->dev, "Failed to reset SoundWire manager instance%d\n",
+ amd_manager->instance);
+ return ret;
+ }
+
+ writel(AMD_SDW_DISABLE, amd_manager->mmio + ACP_SW_EN);
+ return readl_poll_timeout(amd_manager->mmio + ACP_SW_EN_STATUS, val, !val, ACP_DELAY_US,
+ AMD_SDW_TIMEOUT);
+}
+
+static int amd_enable_sdw_manager(struct amd_sdw_manager *amd_manager)
+{
+ u32 val;
+
+ writel(AMD_SDW_ENABLE, amd_manager->mmio + ACP_SW_EN);
+ return readl_poll_timeout(amd_manager->mmio + ACP_SW_EN_STATUS, val, val, ACP_DELAY_US,
+ AMD_SDW_TIMEOUT);
+}
+
+static int amd_disable_sdw_manager(struct amd_sdw_manager *amd_manager)
+{
+ u32 val;
+
+ writel(AMD_SDW_DISABLE, amd_manager->mmio + ACP_SW_EN);
+ /*
+ * After invoking manager disable sequence, check whether
+ * manager has executed clock stop sequence. In this case,
+ * manager should ignore checking enable status register.
+ */
+ val = readl(amd_manager->mmio + ACP_SW_CLK_RESUME_CTRL);
+ if (val)
+ return 0;
+ return readl_poll_timeout(amd_manager->mmio + ACP_SW_EN_STATUS, val, !val, ACP_DELAY_US,
+ AMD_SDW_TIMEOUT);
+}
+
+static void amd_enable_sdw_interrupts(struct amd_sdw_manager *amd_manager)
+{
+ struct sdw_manager_reg_mask *reg_mask = amd_manager->reg_mask;
+ u32 val;
+
+ mutex_lock(amd_manager->acp_sdw_lock);
+ val = readl(amd_manager->acp_mmio + ACP_EXTERNAL_INTR_CNTL(amd_manager->instance));
+ val |= reg_mask->acp_sdw_intr_mask;
+ writel(val, amd_manager->acp_mmio + ACP_EXTERNAL_INTR_CNTL(amd_manager->instance));
+ mutex_unlock(amd_manager->acp_sdw_lock);
+
+ writel(AMD_SDW_IRQ_MASK_0TO7, amd_manager->mmio +
+ ACP_SW_STATE_CHANGE_STATUS_MASK_0TO7);
+ writel(AMD_SDW_IRQ_MASK_8TO11, amd_manager->mmio +
+ ACP_SW_STATE_CHANGE_STATUS_MASK_8TO11);
+ writel(AMD_SDW_IRQ_ERROR_MASK, amd_manager->mmio + ACP_SW_ERROR_INTR_MASK);
+}
+
+static void amd_disable_sdw_interrupts(struct amd_sdw_manager *amd_manager)
+{
+ struct sdw_manager_reg_mask *reg_mask = amd_manager->reg_mask;
+ u32 val;
+
+ mutex_lock(amd_manager->acp_sdw_lock);
+ val = readl(amd_manager->acp_mmio + ACP_EXTERNAL_INTR_CNTL(amd_manager->instance));
+ val &= ~reg_mask->acp_sdw_intr_mask;
+ writel(val, amd_manager->acp_mmio + ACP_EXTERNAL_INTR_CNTL(amd_manager->instance));
+ mutex_unlock(amd_manager->acp_sdw_lock);
+
+ writel(0x00, amd_manager->mmio + ACP_SW_STATE_CHANGE_STATUS_MASK_0TO7);
+ writel(0x00, amd_manager->mmio + ACP_SW_STATE_CHANGE_STATUS_MASK_8TO11);
+ writel(0x00, amd_manager->mmio + ACP_SW_ERROR_INTR_MASK);
+}
+
+static int amd_deinit_sdw_manager(struct amd_sdw_manager *amd_manager)
+{
+ amd_disable_sdw_interrupts(amd_manager);
+ return amd_disable_sdw_manager(amd_manager);
+}
+
+static void amd_sdw_set_frameshape(struct amd_sdw_manager *amd_manager)
+{
+ u32 frame_size;
+
+ frame_size = (amd_manager->rows_index << 3) | amd_manager->cols_index;
+ writel(frame_size, amd_manager->mmio + ACP_SW_FRAMESIZE);
+}
+
+static void amd_sdw_ctl_word_prep(u32 *lower_word, u32 *upper_word, struct sdw_msg *msg,
+ int cmd_offset)
+{
+ u32 upper_data;
+ u32 lower_data = 0;
+ u16 addr;
+ u8 upper_addr, lower_addr;
+ u8 data = 0;
+
+ addr = msg->addr + cmd_offset;
+ upper_addr = (addr & 0xFF00) >> 8;
+ lower_addr = addr & 0xFF;
+
+ if (msg->flags == SDW_MSG_FLAG_WRITE)
+ data = msg->buf[cmd_offset];
+
+ upper_data = FIELD_PREP(AMD_SDW_MCP_CMD_DEV_ADDR, msg->dev_num);
+ upper_data |= FIELD_PREP(AMD_SDW_MCP_CMD_COMMAND, msg->flags + 2);
+ upper_data |= FIELD_PREP(AMD_SDW_MCP_CMD_REG_ADDR_HIGH, upper_addr);
+ lower_data |= FIELD_PREP(AMD_SDW_MCP_CMD_REG_ADDR_LOW, lower_addr);
+ lower_data |= FIELD_PREP(AMD_SDW_MCP_CMD_REG_DATA, data);
+
+ *upper_word = upper_data;
+ *lower_word = lower_data;
+}
+
+static u64 amd_sdw_send_cmd_get_resp(struct amd_sdw_manager *amd_manager, u32 lower_data,
+ u32 upper_data)
+{
+ u64 resp;
+ u32 lower_resp, upper_resp;
+ u32 sts;
+ int ret;
+
+ ret = readl_poll_timeout(amd_manager->mmio + ACP_SW_IMM_CMD_STS, sts,
+ !(sts & AMD_SDW_IMM_CMD_BUSY), ACP_DELAY_US, AMD_SDW_TIMEOUT);
+ if (ret) {
+ dev_err(amd_manager->dev, "SDW%x previous cmd status clear failed\n",
+ amd_manager->instance);
+ return ret;
+ }
+
+ if (sts & AMD_SDW_IMM_RES_VALID) {
+ dev_err(amd_manager->dev, "SDW%x manager is in bad state\n", amd_manager->instance);
+ writel(0x00, amd_manager->mmio + ACP_SW_IMM_CMD_STS);
+ }
+ writel(upper_data, amd_manager->mmio + ACP_SW_IMM_CMD_UPPER_WORD);
+ writel(lower_data, amd_manager->mmio + ACP_SW_IMM_CMD_LOWER_QWORD);
+
+ ret = readl_poll_timeout(amd_manager->mmio + ACP_SW_IMM_CMD_STS, sts,
+ (sts & AMD_SDW_IMM_RES_VALID), ACP_DELAY_US, AMD_SDW_TIMEOUT);
+ if (ret) {
+ dev_err(amd_manager->dev, "SDW%x cmd response timeout occurred\n",
+ amd_manager->instance);
+ return ret;
+ }
+ upper_resp = readl(amd_manager->mmio + ACP_SW_IMM_RESP_UPPER_WORD);
+ lower_resp = readl(amd_manager->mmio + ACP_SW_IMM_RESP_LOWER_QWORD);
+
+ writel(AMD_SDW_IMM_RES_VALID, amd_manager->mmio + ACP_SW_IMM_CMD_STS);
+ ret = readl_poll_timeout(amd_manager->mmio + ACP_SW_IMM_CMD_STS, sts,
+ !(sts & AMD_SDW_IMM_RES_VALID), ACP_DELAY_US, AMD_SDW_TIMEOUT);
+ if (ret) {
+ dev_err(amd_manager->dev, "SDW%x cmd status retry failed\n",
+ amd_manager->instance);
+ return ret;
+ }
+ resp = upper_resp;
+ resp = (resp << 32) | lower_resp;
+ return resp;
+}
+
+static enum sdw_command_response
+amd_program_scp_addr(struct amd_sdw_manager *amd_manager, struct sdw_msg *msg)
+{
+ struct sdw_msg scp_msg = {0};
+ u64 response_buf[2] = {0};
+ u32 upper_data = 0, lower_data = 0;
+ int index;
+
+ scp_msg.dev_num = msg->dev_num;
+ scp_msg.addr = SDW_SCP_ADDRPAGE1;
+ scp_msg.buf = &msg->addr_page1;
+ scp_msg.flags = SDW_MSG_FLAG_WRITE;
+ amd_sdw_ctl_word_prep(&lower_data, &upper_data, &scp_msg, 0);
+ response_buf[0] = amd_sdw_send_cmd_get_resp(amd_manager, lower_data, upper_data);
+ scp_msg.addr = SDW_SCP_ADDRPAGE2;
+ scp_msg.buf = &msg->addr_page2;
+ amd_sdw_ctl_word_prep(&lower_data, &upper_data, &scp_msg, 0);
+ response_buf[1] = amd_sdw_send_cmd_get_resp(amd_manager, lower_data, upper_data);
+
+ for (index = 0; index < 2; index++) {
+ if (response_buf[index] == -ETIMEDOUT) {
+ dev_err_ratelimited(amd_manager->dev,
+ "SCP_addrpage command timeout for Slave %d\n",
+ msg->dev_num);
+ return SDW_CMD_TIMEOUT;
+ } else if (!(response_buf[index] & AMD_SDW_MCP_RESP_ACK)) {
+ if (response_buf[index] & AMD_SDW_MCP_RESP_NACK) {
+ dev_err_ratelimited(amd_manager->dev,
+ "SCP_addrpage NACKed for Slave %d\n",
+ msg->dev_num);
+ return SDW_CMD_FAIL;
+ }
+ dev_dbg_ratelimited(amd_manager->dev, "SCP_addrpage ignored for Slave %d\n",
+ msg->dev_num);
+ return SDW_CMD_IGNORED;
+ }
+ }
+ return SDW_CMD_OK;
+}
+
+static int amd_prep_msg(struct amd_sdw_manager *amd_manager, struct sdw_msg *msg)
+{
+ int ret;
+
+ if (msg->page) {
+ ret = amd_program_scp_addr(amd_manager, msg);
+ if (ret) {
+ msg->len = 0;
+ return ret;
+ }
+ }
+ switch (msg->flags) {
+ case SDW_MSG_FLAG_READ:
+ case SDW_MSG_FLAG_WRITE:
+ break;
+ default:
+ dev_err(amd_manager->dev, "Invalid msg cmd: %d\n", msg->flags);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static enum sdw_command_response amd_sdw_fill_msg_resp(struct amd_sdw_manager *amd_manager,
+ struct sdw_msg *msg, u64 response,
+ int offset)
+{
+ if (response & AMD_SDW_MCP_RESP_ACK) {
+ if (msg->flags == SDW_MSG_FLAG_READ)
+ msg->buf[offset] = FIELD_GET(AMD_SDW_MCP_RESP_RDATA, response);
+ } else {
+ if (response == -ETIMEDOUT) {
+ dev_err_ratelimited(amd_manager->dev, "command timeout for Slave %d\n",
+ msg->dev_num);
+ return SDW_CMD_TIMEOUT;
+ } else if (response & AMD_SDW_MCP_RESP_NACK) {
+ dev_err_ratelimited(amd_manager->dev,
+ "command response NACK received for Slave %d\n",
+ msg->dev_num);
+ return SDW_CMD_FAIL;
+ }
+ dev_err_ratelimited(amd_manager->dev, "command is ignored for Slave %d\n",
+ msg->dev_num);
+ return SDW_CMD_IGNORED;
+ }
+ return SDW_CMD_OK;
+}
+
+static unsigned int _amd_sdw_xfer_msg(struct amd_sdw_manager *amd_manager, struct sdw_msg *msg,
+ int cmd_offset)
+{
+ u64 response;
+ u32 upper_data = 0, lower_data = 0;
+
+ amd_sdw_ctl_word_prep(&lower_data, &upper_data, msg, cmd_offset);
+ response = amd_sdw_send_cmd_get_resp(amd_manager, lower_data, upper_data);
+ return amd_sdw_fill_msg_resp(amd_manager, msg, response, cmd_offset);
+}
+
+static enum sdw_command_response amd_sdw_xfer_msg(struct sdw_bus *bus, struct sdw_msg *msg)
+{
+ struct amd_sdw_manager *amd_manager = to_amd_sdw(bus);
+ int ret, i;
+
+ ret = amd_prep_msg(amd_manager, msg);
+ if (ret)
+ return SDW_CMD_FAIL_OTHER;
+ for (i = 0; i < msg->len; i++) {
+ ret = _amd_sdw_xfer_msg(amd_manager, msg, i);
+ if (ret)
+ return ret;
+ }
+ return SDW_CMD_OK;
+}
+
+static void amd_sdw_fill_slave_status(struct amd_sdw_manager *amd_manager, u16 index, u32 status)
+{
+ switch (status) {
+ case SDW_SLAVE_ATTACHED:
+ case SDW_SLAVE_UNATTACHED:
+ case SDW_SLAVE_ALERT:
+ amd_manager->status[index] = status;
+ break;
+ default:
+ amd_manager->status[index] = SDW_SLAVE_RESERVED;
+ break;
+ }
+}
+
+static void amd_sdw_process_ping_status(u64 response, struct amd_sdw_manager *amd_manager)
+{
+ u64 slave_stat;
+ u32 val;
+ u16 dev_index;
+
+ /* slave status response */
+ slave_stat = FIELD_GET(AMD_SDW_MCP_SLAVE_STAT_0_3, response);
+ slave_stat |= FIELD_GET(AMD_SDW_MCP_SLAVE_STAT_4_11, response) << 8;
+ dev_dbg(amd_manager->dev, "slave_stat:0x%llx\n", slave_stat);
+ for (dev_index = 0; dev_index <= SDW_MAX_DEVICES; ++dev_index) {
+ val = (slave_stat >> (dev_index * 2)) & AMD_SDW_MCP_SLAVE_STATUS_MASK;
+ dev_dbg(amd_manager->dev, "val:0x%x\n", val);
+ amd_sdw_fill_slave_status(amd_manager, dev_index, val);
+ }
+}
+
+static void amd_sdw_read_and_process_ping_status(struct amd_sdw_manager *amd_manager)
+{
+ u64 response;
+
+ mutex_lock(&amd_manager->bus.msg_lock);
+ response = amd_sdw_send_cmd_get_resp(amd_manager, 0, 0);
+ mutex_unlock(&amd_manager->bus.msg_lock);
+ amd_sdw_process_ping_status(response, amd_manager);
+}
+
+static u32 amd_sdw_read_ping_status(struct sdw_bus *bus)
+{
+ struct amd_sdw_manager *amd_manager = to_amd_sdw(bus);
+ u64 response;
+ u32 slave_stat;
+
+ response = amd_sdw_send_cmd_get_resp(amd_manager, 0, 0);
+ /* slave status from ping response */
+ slave_stat = FIELD_GET(AMD_SDW_MCP_SLAVE_STAT_0_3, response);
+ slave_stat |= FIELD_GET(AMD_SDW_MCP_SLAVE_STAT_4_11, response) << 8;
+ dev_dbg(amd_manager->dev, "slave_stat:0x%x\n", slave_stat);
+ return slave_stat;
+}
+
+static int amd_sdw_compute_params(struct sdw_bus *bus)
+{
+ struct sdw_transport_data t_data = {0};
+ struct sdw_master_runtime *m_rt;
+ struct sdw_port_runtime *p_rt;
+ struct sdw_bus_params *b_params = &bus->params;
+ int port_bo, hstart, hstop, sample_int;
+ unsigned int rate, bps;
+
+ port_bo = 0;
+ hstart = 1;
+ hstop = bus->params.col - 1;
+ t_data.hstop = hstop;
+ t_data.hstart = hstart;
+
+ list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) {
+ rate = m_rt->stream->params.rate;
+ bps = m_rt->stream->params.bps;
+ sample_int = (bus->params.curr_dr_freq / rate);
+ list_for_each_entry(p_rt, &m_rt->port_list, port_node) {
+ port_bo = (p_rt->num * 64) + 1;
+ dev_dbg(bus->dev, "p_rt->num=%d hstart=%d hstop=%d port_bo=%d\n",
+ p_rt->num, hstart, hstop, port_bo);
+ sdw_fill_xport_params(&p_rt->transport_params, p_rt->num,
+ false, SDW_BLK_GRP_CNT_1, sample_int,
+ port_bo, port_bo >> 8, hstart, hstop,
+ SDW_BLK_PKG_PER_PORT, 0x0);
+
+ sdw_fill_port_params(&p_rt->port_params,
+ p_rt->num, bps,
+ SDW_PORT_FLOW_MODE_ISOCH,
+ b_params->m_data_mode);
+ t_data.hstart = hstart;
+ t_data.hstop = hstop;
+ t_data.block_offset = port_bo;
+ t_data.sub_block_offset = 0;
+ }
+ sdw_compute_slave_ports(m_rt, &t_data);
+ }
+ return 0;
+}
+
+static int amd_sdw_port_params(struct sdw_bus *bus, struct sdw_port_params *p_params,
+ unsigned int bank)
+{
+ struct amd_sdw_manager *amd_manager = to_amd_sdw(bus);
+ u32 frame_fmt_reg, dpn_frame_fmt;
+
+ dev_dbg(amd_manager->dev, "p_params->num:0x%x\n", p_params->num);
+ switch (amd_manager->instance) {
+ case ACP_SDW0:
+ frame_fmt_reg = sdw0_manager_dp_reg[p_params->num].frame_fmt_reg;
+ break;
+ case ACP_SDW1:
+ frame_fmt_reg = sdw1_manager_dp_reg[p_params->num].frame_fmt_reg;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ dpn_frame_fmt = readl(amd_manager->mmio + frame_fmt_reg);
+ u32p_replace_bits(&dpn_frame_fmt, p_params->flow_mode, AMD_DPN_FRAME_FMT_PFM);
+ u32p_replace_bits(&dpn_frame_fmt, p_params->data_mode, AMD_DPN_FRAME_FMT_PDM);
+ u32p_replace_bits(&dpn_frame_fmt, p_params->bps - 1, AMD_DPN_FRAME_FMT_WORD_LEN);
+ writel(dpn_frame_fmt, amd_manager->mmio + frame_fmt_reg);
+ return 0;
+}
+
+static int amd_sdw_transport_params(struct sdw_bus *bus,
+ struct sdw_transport_params *params,
+ enum sdw_reg_bank bank)
+{
+ struct amd_sdw_manager *amd_manager = to_amd_sdw(bus);
+ u32 dpn_frame_fmt;
+ u32 dpn_sampleinterval;
+ u32 dpn_hctrl;
+ u32 dpn_offsetctrl;
+ u32 dpn_lanectrl;
+ u32 frame_fmt_reg, sample_int_reg, hctrl_dp0_reg;
+ u32 offset_reg, lane_ctrl_ch_en_reg;
+
+ switch (amd_manager->instance) {
+ case ACP_SDW0:
+ frame_fmt_reg = sdw0_manager_dp_reg[params->port_num].frame_fmt_reg;
+ sample_int_reg = sdw0_manager_dp_reg[params->port_num].sample_int_reg;
+ hctrl_dp0_reg = sdw0_manager_dp_reg[params->port_num].hctrl_dp0_reg;
+ offset_reg = sdw0_manager_dp_reg[params->port_num].offset_reg;
+ lane_ctrl_ch_en_reg = sdw0_manager_dp_reg[params->port_num].lane_ctrl_ch_en_reg;
+ break;
+ case ACP_SDW1:
+ frame_fmt_reg = sdw1_manager_dp_reg[params->port_num].frame_fmt_reg;
+ sample_int_reg = sdw1_manager_dp_reg[params->port_num].sample_int_reg;
+ hctrl_dp0_reg = sdw1_manager_dp_reg[params->port_num].hctrl_dp0_reg;
+ offset_reg = sdw1_manager_dp_reg[params->port_num].offset_reg;
+ lane_ctrl_ch_en_reg = sdw1_manager_dp_reg[params->port_num].lane_ctrl_ch_en_reg;
+ break;
+ default:
+ return -EINVAL;
+ }
+ writel(AMD_SDW_SSP_COUNTER_VAL, amd_manager->mmio + ACP_SW_SSP_COUNTER);
+
+ dpn_frame_fmt = readl(amd_manager->mmio + frame_fmt_reg);
+ u32p_replace_bits(&dpn_frame_fmt, params->blk_pkg_mode, AMD_DPN_FRAME_FMT_BLK_PKG_MODE);
+ u32p_replace_bits(&dpn_frame_fmt, params->blk_grp_ctrl, AMD_DPN_FRAME_FMT_BLK_GRP_CTRL);
+ u32p_replace_bits(&dpn_frame_fmt, SDW_STREAM_PCM, AMD_DPN_FRAME_FMT_PCM_OR_PDM);
+ writel(dpn_frame_fmt, amd_manager->mmio + frame_fmt_reg);
+
+ dpn_sampleinterval = params->sample_interval - 1;
+ writel(dpn_sampleinterval, amd_manager->mmio + sample_int_reg);
+
+ dpn_hctrl = FIELD_PREP(AMD_DPN_HCTRL_HSTOP, params->hstop);
+ dpn_hctrl |= FIELD_PREP(AMD_DPN_HCTRL_HSTART, params->hstart);
+ writel(dpn_hctrl, amd_manager->mmio + hctrl_dp0_reg);
+
+ dpn_offsetctrl = FIELD_PREP(AMD_DPN_OFFSET_CTRL_1, params->offset1);
+ dpn_offsetctrl |= FIELD_PREP(AMD_DPN_OFFSET_CTRL_2, params->offset2);
+ writel(dpn_offsetctrl, amd_manager->mmio + offset_reg);
+
+ /*
+ * lane_ctrl_ch_en_reg will be used to program lane_ctrl and ch_mask
+ * parameters.
+ */
+ dpn_lanectrl = readl(amd_manager->mmio + lane_ctrl_ch_en_reg);
+ u32p_replace_bits(&dpn_lanectrl, params->lane_ctrl, AMD_DPN_CH_EN_LCTRL);
+ writel(dpn_lanectrl, amd_manager->mmio + lane_ctrl_ch_en_reg);
+ return 0;
+}
+
+static int amd_sdw_port_enable(struct sdw_bus *bus,
+ struct sdw_enable_ch *enable_ch,
+ unsigned int bank)
+{
+ struct amd_sdw_manager *amd_manager = to_amd_sdw(bus);
+ u32 dpn_ch_enable;
+ u32 lane_ctrl_ch_en_reg;
+
+ switch (amd_manager->instance) {
+ case ACP_SDW0:
+ lane_ctrl_ch_en_reg = sdw0_manager_dp_reg[enable_ch->port_num].lane_ctrl_ch_en_reg;
+ break;
+ case ACP_SDW1:
+ lane_ctrl_ch_en_reg = sdw1_manager_dp_reg[enable_ch->port_num].lane_ctrl_ch_en_reg;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /*
+ * lane_ctrl_ch_en_reg will be used to program lane_ctrl and ch_mask
+ * parameters.
+ */
+ dpn_ch_enable = readl(amd_manager->mmio + lane_ctrl_ch_en_reg);
+ u32p_replace_bits(&dpn_ch_enable, enable_ch->ch_mask, AMD_DPN_CH_EN_CHMASK);
+ if (enable_ch->enable)
+ writel(dpn_ch_enable, amd_manager->mmio + lane_ctrl_ch_en_reg);
+ else
+ writel(0, amd_manager->mmio + lane_ctrl_ch_en_reg);
+ return 0;
+}
+
+static int sdw_master_read_amd_prop(struct sdw_bus *bus)
+{
+ struct amd_sdw_manager *amd_manager = to_amd_sdw(bus);
+ struct fwnode_handle *link;
+ struct sdw_master_prop *prop;
+ u32 quirk_mask = 0;
+ u32 wake_en_mask = 0;
+ u32 power_mode_mask = 0;
+ char name[32];
+
+ prop = &bus->prop;
+ /* Find manager handle */
+ snprintf(name, sizeof(name), "mipi-sdw-link-%d-subproperties", bus->link_id);
+ link = device_get_named_child_node(bus->dev, name);
+ if (!link) {
+ dev_err(bus->dev, "Manager node %s not found\n", name);
+ return -EIO;
+ }
+ fwnode_property_read_u32(link, "amd-sdw-enable", &quirk_mask);
+ if (!(quirk_mask & AMD_SDW_QUIRK_MASK_BUS_ENABLE))
+ prop->hw_disabled = true;
+ prop->quirks = SDW_MASTER_QUIRKS_CLEAR_INITIAL_CLASH |
+ SDW_MASTER_QUIRKS_CLEAR_INITIAL_PARITY;
+
+ fwnode_property_read_u32(link, "amd-sdw-wakeup-enable", &wake_en_mask);
+ amd_manager->wake_en_mask = wake_en_mask;
+ fwnode_property_read_u32(link, "amd-sdw-power-mode", &power_mode_mask);
+ amd_manager->power_mode_mask = power_mode_mask;
+ return 0;
+}
+
+static int amd_prop_read(struct sdw_bus *bus)
+{
+ sdw_master_read_prop(bus);
+ sdw_master_read_amd_prop(bus);
+ return 0;
+}
+
+static const struct sdw_master_port_ops amd_sdw_port_ops = {
+ .dpn_set_port_params = amd_sdw_port_params,
+ .dpn_set_port_transport_params = amd_sdw_transport_params,
+ .dpn_port_enable_ch = amd_sdw_port_enable,
+};
+
+static const struct sdw_master_ops amd_sdw_ops = {
+ .read_prop = amd_prop_read,
+ .xfer_msg = amd_sdw_xfer_msg,
+ .read_ping_status = amd_sdw_read_ping_status,
+};
+
+static int amd_sdw_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct amd_sdw_manager *amd_manager = snd_soc_dai_get_drvdata(dai);
+ struct sdw_amd_dai_runtime *dai_runtime;
+ struct sdw_stream_config sconfig;
+ struct sdw_port_config *pconfig;
+ int ch, dir;
+ int ret;
+
+ dai_runtime = amd_manager->dai_runtime_array[dai->id];
+ if (!dai_runtime)
+ return -EIO;
+
+ ch = params_channels(params);
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ dir = SDW_DATA_DIR_RX;
+ else
+ dir = SDW_DATA_DIR_TX;
+ dev_dbg(amd_manager->dev, "dir:%d dai->id:0x%x\n", dir, dai->id);
+
+ sconfig.direction = dir;
+ sconfig.ch_count = ch;
+ sconfig.frame_rate = params_rate(params);
+ sconfig.type = dai_runtime->stream_type;
+
+ sconfig.bps = snd_pcm_format_width(params_format(params));
+
+ /* Port configuration */
+ pconfig = kzalloc(sizeof(*pconfig), GFP_KERNEL);
+ if (!pconfig) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ pconfig->num = dai->id;
+ pconfig->ch_mask = (1 << ch) - 1;
+ ret = sdw_stream_add_master(&amd_manager->bus, &sconfig,
+ pconfig, 1, dai_runtime->stream);
+ if (ret)
+ dev_err(amd_manager->dev, "add manager to stream failed:%d\n", ret);
+
+ kfree(pconfig);
+error:
+ return ret;
+}
+
+static int amd_sdw_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+ struct amd_sdw_manager *amd_manager = snd_soc_dai_get_drvdata(dai);
+ struct sdw_amd_dai_runtime *dai_runtime;
+ int ret;
+
+ dai_runtime = amd_manager->dai_runtime_array[dai->id];
+ if (!dai_runtime)
+ return -EIO;
+
+ ret = sdw_stream_remove_master(&amd_manager->bus, dai_runtime->stream);
+ if (ret < 0)
+ dev_err(dai->dev, "remove manager from stream %s failed: %d\n",
+ dai_runtime->stream->name, ret);
+ return ret;
+}
+
+static int amd_set_sdw_stream(struct snd_soc_dai *dai, void *stream, int direction)
+{
+ struct amd_sdw_manager *amd_manager = snd_soc_dai_get_drvdata(dai);
+ struct sdw_amd_dai_runtime *dai_runtime;
+
+ dai_runtime = amd_manager->dai_runtime_array[dai->id];
+ if (stream) {
+ /* first paranoia check */
+ if (dai_runtime) {
+ dev_err(dai->dev, "dai_runtime already allocated for dai %s\n", dai->name);
+ return -EINVAL;
+ }
+
+ /* allocate and set dai_runtime info */
+ dai_runtime = kzalloc(sizeof(*dai_runtime), GFP_KERNEL);
+ if (!dai_runtime)
+ return -ENOMEM;
+
+ dai_runtime->stream_type = SDW_STREAM_PCM;
+ dai_runtime->bus = &amd_manager->bus;
+ dai_runtime->stream = stream;
+ amd_manager->dai_runtime_array[dai->id] = dai_runtime;
+ } else {
+ /* second paranoia check */
+ if (!dai_runtime) {
+ dev_err(dai->dev, "dai_runtime not allocated for dai %s\n", dai->name);
+ return -EINVAL;
+ }
+
+ /* for NULL stream we release allocated dai_runtime */
+ kfree(dai_runtime);
+ amd_manager->dai_runtime_array[dai->id] = NULL;
+ }
+ return 0;
+}
+
+static int amd_pcm_set_sdw_stream(struct snd_soc_dai *dai, void *stream, int direction)
+{
+ return amd_set_sdw_stream(dai, stream, direction);
+}
+
+static void *amd_get_sdw_stream(struct snd_soc_dai *dai, int direction)
+{
+ struct amd_sdw_manager *amd_manager = snd_soc_dai_get_drvdata(dai);
+ struct sdw_amd_dai_runtime *dai_runtime;
+
+ dai_runtime = amd_manager->dai_runtime_array[dai->id];
+ if (!dai_runtime)
+ return ERR_PTR(-EINVAL);
+
+ return dai_runtime->stream;
+}
+
+static const struct snd_soc_dai_ops amd_sdw_dai_ops = {
+ .hw_params = amd_sdw_hw_params,
+ .hw_free = amd_sdw_hw_free,
+ .set_stream = amd_pcm_set_sdw_stream,
+ .get_stream = amd_get_sdw_stream,
+};
+
+static const struct snd_soc_component_driver amd_sdw_dai_component = {
+ .name = "soundwire",
+};
+
+static int amd_sdw_register_dais(struct amd_sdw_manager *amd_manager)
+{
+ struct sdw_amd_dai_runtime **dai_runtime_array;
+ struct snd_soc_dai_driver *dais;
+ struct snd_soc_pcm_stream *stream;
+ struct device *dev;
+ int i, num_dais;
+
+ dev = amd_manager->dev;
+ num_dais = amd_manager->num_dout_ports + amd_manager->num_din_ports;
+ dais = devm_kcalloc(dev, num_dais, sizeof(*dais), GFP_KERNEL);
+ if (!dais)
+ return -ENOMEM;
+
+ dai_runtime_array = devm_kcalloc(dev, num_dais,
+ sizeof(struct sdw_amd_dai_runtime *),
+ GFP_KERNEL);
+ if (!dai_runtime_array)
+ return -ENOMEM;
+ amd_manager->dai_runtime_array = dai_runtime_array;
+ for (i = 0; i < num_dais; i++) {
+ dais[i].name = devm_kasprintf(dev, GFP_KERNEL, "SDW%d Pin%d", amd_manager->instance,
+ i);
+ if (!dais[i].name)
+ return -ENOMEM;
+ if (i < amd_manager->num_dout_ports)
+ stream = &dais[i].playback;
+ else
+ stream = &dais[i].capture;
+
+ stream->channels_min = 2;
+ stream->channels_max = 2;
+ stream->rates = SNDRV_PCM_RATE_48000;
+ stream->formats = SNDRV_PCM_FMTBIT_S16_LE;
+
+ dais[i].ops = &amd_sdw_dai_ops;
+ dais[i].id = i;
+ }
+
+ return devm_snd_soc_register_component(dev, &amd_sdw_dai_component,
+ dais, num_dais);
+}
+
+static void amd_sdw_update_slave_status_work(struct work_struct *work)
+{
+ struct amd_sdw_manager *amd_manager =
+ container_of(work, struct amd_sdw_manager, amd_sdw_work);
+ int retry_count = 0;
+
+ if (amd_manager->status[0] == SDW_SLAVE_ATTACHED) {
+ writel(0, amd_manager->mmio + ACP_SW_STATE_CHANGE_STATUS_MASK_0TO7);
+ writel(0, amd_manager->mmio + ACP_SW_STATE_CHANGE_STATUS_MASK_8TO11);
+ }
+
+update_status:
+ sdw_handle_slave_status(&amd_manager->bus, amd_manager->status);
+ /*
+ * During the peripheral enumeration sequence, the SoundWire manager interrupts
+ * are masked. Once the device number programming is done for all peripherals,
+ * interrupts will be unmasked. Read the peripheral device status from ping command
+ * and process the response. This sequence will ensure all peripheral devices enumerated
+ * and initialized properly.
+ */
+ if (amd_manager->status[0] == SDW_SLAVE_ATTACHED) {
+ if (retry_count++ < SDW_MAX_DEVICES) {
+ writel(AMD_SDW_IRQ_MASK_0TO7, amd_manager->mmio +
+ ACP_SW_STATE_CHANGE_STATUS_MASK_0TO7);
+ writel(AMD_SDW_IRQ_MASK_8TO11, amd_manager->mmio +
+ ACP_SW_STATE_CHANGE_STATUS_MASK_8TO11);
+ amd_sdw_read_and_process_ping_status(amd_manager);
+ goto update_status;
+ } else {
+ dev_err_ratelimited(amd_manager->dev,
+ "Device0 detected after %d iterations\n",
+ retry_count);
+ }
+ }
+}
+
+static void amd_sdw_update_slave_status(u32 status_change_0to7, u32 status_change_8to11,
+ struct amd_sdw_manager *amd_manager)
+{
+ u64 slave_stat;
+ u32 val;
+ int dev_index;
+
+ if (status_change_0to7 == AMD_SDW_SLAVE_0_ATTACHED)
+ memset(amd_manager->status, 0, sizeof(amd_manager->status));
+ slave_stat = status_change_0to7;
+ slave_stat |= FIELD_GET(AMD_SDW_MCP_SLAVE_STATUS_8TO_11, status_change_8to11) << 32;
+ dev_dbg(amd_manager->dev, "status_change_0to7:0x%x status_change_8to11:0x%x\n",
+ status_change_0to7, status_change_8to11);
+ if (slave_stat) {
+ for (dev_index = 0; dev_index <= SDW_MAX_DEVICES; ++dev_index) {
+ if (slave_stat & AMD_SDW_MCP_SLAVE_STATUS_VALID_MASK(dev_index)) {
+ val = (slave_stat >> AMD_SDW_MCP_SLAVE_STAT_SHIFT_MASK(dev_index)) &
+ AMD_SDW_MCP_SLAVE_STATUS_MASK;
+ amd_sdw_fill_slave_status(amd_manager, dev_index, val);
+ }
+ }
+ }
+}
+
+static void amd_sdw_process_wake_event(struct amd_sdw_manager *amd_manager)
+{
+ pm_request_resume(amd_manager->dev);
+ writel(0x00, amd_manager->acp_mmio + ACP_SW_WAKE_EN(amd_manager->instance));
+ writel(0x00, amd_manager->mmio + ACP_SW_STATE_CHANGE_STATUS_8TO11);
+}
+
+static void amd_sdw_irq_thread(struct work_struct *work)
+{
+ struct amd_sdw_manager *amd_manager =
+ container_of(work, struct amd_sdw_manager, amd_sdw_irq_thread);
+ u32 status_change_8to11;
+ u32 status_change_0to7;
+
+ status_change_8to11 = readl(amd_manager->mmio + ACP_SW_STATE_CHANGE_STATUS_8TO11);
+ status_change_0to7 = readl(amd_manager->mmio + ACP_SW_STATE_CHANGE_STATUS_0TO7);
+ dev_dbg(amd_manager->dev, "[SDW%d] SDW INT: 0to7=0x%x, 8to11=0x%x\n",
+ amd_manager->instance, status_change_0to7, status_change_8to11);
+ if (status_change_8to11 & AMD_SDW_WAKE_STAT_MASK)
+ return amd_sdw_process_wake_event(amd_manager);
+
+ if (status_change_8to11 & AMD_SDW_PREQ_INTR_STAT) {
+ amd_sdw_read_and_process_ping_status(amd_manager);
+ } else {
+ /* Check for the updated status on peripheral device */
+ amd_sdw_update_slave_status(status_change_0to7, status_change_8to11, amd_manager);
+ }
+ if (status_change_8to11 || status_change_0to7)
+ schedule_work(&amd_manager->amd_sdw_work);
+ writel(0x00, amd_manager->mmio + ACP_SW_STATE_CHANGE_STATUS_8TO11);
+ writel(0x00, amd_manager->mmio + ACP_SW_STATE_CHANGE_STATUS_0TO7);
+}
+
+static void amd_sdw_probe_work(struct work_struct *work)
+{
+ struct amd_sdw_manager *amd_manager = container_of(work, struct amd_sdw_manager,
+ probe_work);
+ struct sdw_master_prop *prop;
+ int ret;
+
+ prop = &amd_manager->bus.prop;
+ if (!prop->hw_disabled) {
+ amd_enable_sdw_pads(amd_manager);
+ ret = amd_init_sdw_manager(amd_manager);
+ if (ret)
+ return;
+ amd_enable_sdw_interrupts(amd_manager);
+ ret = amd_enable_sdw_manager(amd_manager);
+ if (ret)
+ return;
+ amd_sdw_set_frameshape(amd_manager);
+ }
+ /* Enable runtime PM */
+ pm_runtime_set_autosuspend_delay(amd_manager->dev, AMD_SDW_MASTER_SUSPEND_DELAY_MS);
+ pm_runtime_use_autosuspend(amd_manager->dev);
+ pm_runtime_mark_last_busy(amd_manager->dev);
+ pm_runtime_set_active(amd_manager->dev);
+ pm_runtime_enable(amd_manager->dev);
+}
+
+static int amd_sdw_manager_probe(struct platform_device *pdev)
+{
+ const struct acp_sdw_pdata *pdata = pdev->dev.platform_data;
+ struct resource *res;
+ struct device *dev = &pdev->dev;
+ struct sdw_master_prop *prop;
+ struct sdw_bus_params *params;
+ struct amd_sdw_manager *amd_manager;
+ int ret;
+
+ amd_manager = devm_kzalloc(dev, sizeof(struct amd_sdw_manager), GFP_KERNEL);
+ if (!amd_manager)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENOMEM;
+
+ amd_manager->acp_mmio = devm_ioremap(dev, res->start, resource_size(res));
+ if (IS_ERR(amd_manager->mmio)) {
+ dev_err(dev, "mmio not found\n");
+ return PTR_ERR(amd_manager->mmio);
+ }
+ amd_manager->instance = pdata->instance;
+ amd_manager->mmio = amd_manager->acp_mmio +
+ (amd_manager->instance * SDW_MANAGER_REG_OFFSET);
+ amd_manager->acp_sdw_lock = pdata->acp_sdw_lock;
+ amd_manager->cols_index = sdw_find_col_index(AMD_SDW_DEFAULT_COLUMNS);
+ amd_manager->rows_index = sdw_find_row_index(AMD_SDW_DEFAULT_ROWS);
+ amd_manager->dev = dev;
+ amd_manager->bus.ops = &amd_sdw_ops;
+ amd_manager->bus.port_ops = &amd_sdw_port_ops;
+ amd_manager->bus.compute_params = &amd_sdw_compute_params;
+ amd_manager->bus.clk_stop_timeout = 200;
+ amd_manager->bus.link_id = amd_manager->instance;
+
+ switch (amd_manager->instance) {
+ case ACP_SDW0:
+ amd_manager->num_dout_ports = AMD_SDW0_MAX_TX_PORTS;
+ amd_manager->num_din_ports = AMD_SDW0_MAX_RX_PORTS;
+ break;
+ case ACP_SDW1:
+ amd_manager->num_dout_ports = AMD_SDW1_MAX_TX_PORTS;
+ amd_manager->num_din_ports = AMD_SDW1_MAX_RX_PORTS;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ amd_manager->reg_mask = &sdw_manager_reg_mask_array[amd_manager->instance];
+ params = &amd_manager->bus.params;
+ params->max_dr_freq = AMD_SDW_DEFAULT_CLK_FREQ * 2;
+ params->curr_dr_freq = AMD_SDW_DEFAULT_CLK_FREQ * 2;
+ params->col = AMD_SDW_DEFAULT_COLUMNS;
+ params->row = AMD_SDW_DEFAULT_ROWS;
+ prop = &amd_manager->bus.prop;
+ prop->clk_freq = &amd_sdw_freq_tbl[0];
+ prop->mclk_freq = AMD_SDW_BUS_BASE_FREQ;
+
+ ret = sdw_bus_master_add(&amd_manager->bus, dev, dev->fwnode);
+ if (ret) {
+ dev_err(dev, "Failed to register SoundWire manager(%d)\n", ret);
+ return ret;
+ }
+ ret = amd_sdw_register_dais(amd_manager);
+ if (ret) {
+ dev_err(dev, "CPU DAI registration failed\n");
+ sdw_bus_master_delete(&amd_manager->bus);
+ return ret;
+ }
+ dev_set_drvdata(dev, amd_manager);
+ INIT_WORK(&amd_manager->amd_sdw_irq_thread, amd_sdw_irq_thread);
+ INIT_WORK(&amd_manager->amd_sdw_work, amd_sdw_update_slave_status_work);
+ INIT_WORK(&amd_manager->probe_work, amd_sdw_probe_work);
+ /*
+ * Instead of having lengthy probe sequence, use deferred probe.
+ */
+ schedule_work(&amd_manager->probe_work);
+ return 0;
+}
+
+static int amd_sdw_manager_remove(struct platform_device *pdev)
+{
+ struct amd_sdw_manager *amd_manager = dev_get_drvdata(&pdev->dev);
+
+ pm_runtime_disable(&pdev->dev);
+ cancel_work_sync(&amd_manager->probe_work);
+ amd_disable_sdw_interrupts(amd_manager);
+ sdw_bus_master_delete(&amd_manager->bus);
+ return amd_disable_sdw_manager(amd_manager);
+}
+
+static int amd_sdw_clock_stop(struct amd_sdw_manager *amd_manager)
+{
+ u32 val;
+ int ret;
+
+ ret = sdw_bus_prep_clk_stop(&amd_manager->bus);
+ if (ret < 0 && ret != -ENODATA) {
+ dev_err(amd_manager->dev, "prepare clock stop failed %d", ret);
+ return 0;
+ }
+ ret = sdw_bus_clk_stop(&amd_manager->bus);
+ if (ret < 0 && ret != -ENODATA) {
+ dev_err(amd_manager->dev, "bus clock stop failed %d", ret);
+ return 0;
+ }
+
+ ret = readl_poll_timeout(amd_manager->mmio + ACP_SW_CLK_RESUME_CTRL, val,
+ (val & AMD_SDW_CLK_STOP_DONE), ACP_DELAY_US, AMD_SDW_TIMEOUT);
+ if (ret) {
+ dev_err(amd_manager->dev, "SDW%x clock stop failed\n", amd_manager->instance);
+ return 0;
+ }
+
+ amd_manager->clk_stopped = true;
+ if (amd_manager->wake_en_mask)
+ writel(0x01, amd_manager->acp_mmio + ACP_SW_WAKE_EN(amd_manager->instance));
+
+ dev_dbg(amd_manager->dev, "SDW%x clock stop successful\n", amd_manager->instance);
+ return 0;
+}
+
+static int amd_sdw_clock_stop_exit(struct amd_sdw_manager *amd_manager)
+{
+ int ret;
+ u32 val;
+
+ if (amd_manager->clk_stopped) {
+ val = readl(amd_manager->mmio + ACP_SW_CLK_RESUME_CTRL);
+ val |= AMD_SDW_CLK_RESUME_REQ;
+ writel(val, amd_manager->mmio + ACP_SW_CLK_RESUME_CTRL);
+ ret = readl_poll_timeout(amd_manager->mmio + ACP_SW_CLK_RESUME_CTRL, val,
+ (val & AMD_SDW_CLK_RESUME_DONE), ACP_DELAY_US,
+ AMD_SDW_TIMEOUT);
+ if (val & AMD_SDW_CLK_RESUME_DONE) {
+ writel(0, amd_manager->mmio + ACP_SW_CLK_RESUME_CTRL);
+ ret = sdw_bus_exit_clk_stop(&amd_manager->bus);
+ if (ret < 0)
+ dev_err(amd_manager->dev, "bus failed to exit clock stop %d\n",
+ ret);
+ amd_manager->clk_stopped = false;
+ }
+ }
+ if (amd_manager->clk_stopped) {
+ dev_err(amd_manager->dev, "SDW%x clock stop exit failed\n", amd_manager->instance);
+ return 0;
+ }
+ dev_dbg(amd_manager->dev, "SDW%x clock stop exit successful\n", amd_manager->instance);
+ return 0;
+}
+
+static int amd_resume_child_device(struct device *dev, void *data)
+{
+ struct sdw_slave *slave = dev_to_sdw_dev(dev);
+ int ret;
+
+ if (!slave->probed) {
+ dev_dbg(dev, "skipping device, no probed driver\n");
+ return 0;
+ }
+ if (!slave->dev_num_sticky) {
+ dev_dbg(dev, "skipping device, never detected on bus\n");
+ return 0;
+ }
+ ret = pm_request_resume(dev);
+ if (ret < 0) {
+ dev_err(dev, "pm_request_resume failed: %d\n", ret);
+ return ret;
+ }
+ return 0;
+}
+
+static int __maybe_unused amd_pm_prepare(struct device *dev)
+{
+ struct amd_sdw_manager *amd_manager = dev_get_drvdata(dev);
+ struct sdw_bus *bus = &amd_manager->bus;
+ int ret;
+
+ if (bus->prop.hw_disabled) {
+ dev_dbg(bus->dev, "SoundWire manager %d is disabled, ignoring\n",
+ bus->link_id);
+ return 0;
+ }
+ /*
+ * When multiple peripheral devices connected over the same link, if SoundWire manager
+ * device is not in runtime suspend state, observed that device alerts are missing
+ * without pm_prepare on AMD platforms in clockstop mode0.
+ */
+ if (amd_manager->power_mode_mask & AMD_SDW_CLK_STOP_MODE) {
+ ret = pm_request_resume(dev);
+ if (ret < 0) {
+ dev_err(bus->dev, "pm_request_resume failed: %d\n", ret);
+ return 0;
+ }
+ }
+ /* To force peripheral devices to system level suspend state, resume the devices
+ * from runtime suspend state first. Without that unable to dispatch the alert
+ * status to peripheral driver during system level resume as they are in runtime
+ * suspend state.
+ */
+ ret = device_for_each_child(bus->dev, NULL, amd_resume_child_device);
+ if (ret < 0)
+ dev_err(dev, "amd_resume_child_device failed: %d\n", ret);
+ return 0;
+}
+
+static int __maybe_unused amd_suspend(struct device *dev)
+{
+ struct amd_sdw_manager *amd_manager = dev_get_drvdata(dev);
+ struct sdw_bus *bus = &amd_manager->bus;
+ int ret;
+
+ if (bus->prop.hw_disabled) {
+ dev_dbg(bus->dev, "SoundWire manager %d is disabled, ignoring\n",
+ bus->link_id);
+ return 0;
+ }
+
+ if (amd_manager->power_mode_mask & AMD_SDW_CLK_STOP_MODE) {
+ return amd_sdw_clock_stop(amd_manager);
+ } else if (amd_manager->power_mode_mask & AMD_SDW_POWER_OFF_MODE) {
+ /*
+ * As per hardware programming sequence on AMD platforms,
+ * clock stop should be invoked first before powering-off
+ */
+ ret = amd_sdw_clock_stop(amd_manager);
+ if (ret)
+ return ret;
+ return amd_deinit_sdw_manager(amd_manager);
+ }
+ return 0;
+}
+
+static int __maybe_unused amd_suspend_runtime(struct device *dev)
+{
+ struct amd_sdw_manager *amd_manager = dev_get_drvdata(dev);
+ struct sdw_bus *bus = &amd_manager->bus;
+ int ret;
+
+ if (bus->prop.hw_disabled) {
+ dev_dbg(bus->dev, "SoundWire manager %d is disabled,\n",
+ bus->link_id);
+ return 0;
+ }
+ if (amd_manager->power_mode_mask & AMD_SDW_CLK_STOP_MODE) {
+ return amd_sdw_clock_stop(amd_manager);
+ } else if (amd_manager->power_mode_mask & AMD_SDW_POWER_OFF_MODE) {
+ ret = amd_sdw_clock_stop(amd_manager);
+ if (ret)
+ return ret;
+ return amd_deinit_sdw_manager(amd_manager);
+ }
+ return 0;
+}
+
+static int __maybe_unused amd_resume_runtime(struct device *dev)
+{
+ struct amd_sdw_manager *amd_manager = dev_get_drvdata(dev);
+ struct sdw_bus *bus = &amd_manager->bus;
+ int ret;
+ u32 val;
+
+ if (bus->prop.hw_disabled) {
+ dev_dbg(bus->dev, "SoundWire manager %d is disabled, ignoring\n",
+ bus->link_id);
+ return 0;
+ }
+
+ if (amd_manager->power_mode_mask & AMD_SDW_CLK_STOP_MODE) {
+ return amd_sdw_clock_stop_exit(amd_manager);
+ } else if (amd_manager->power_mode_mask & AMD_SDW_POWER_OFF_MODE) {
+ val = readl(amd_manager->mmio + ACP_SW_CLK_RESUME_CTRL);
+ if (val) {
+ val |= AMD_SDW_CLK_RESUME_REQ;
+ writel(val, amd_manager->mmio + ACP_SW_CLK_RESUME_CTRL);
+ ret = readl_poll_timeout(amd_manager->mmio + ACP_SW_CLK_RESUME_CTRL, val,
+ (val & AMD_SDW_CLK_RESUME_DONE), ACP_DELAY_US,
+ AMD_SDW_TIMEOUT);
+ if (val & AMD_SDW_CLK_RESUME_DONE) {
+ writel(0, amd_manager->mmio + ACP_SW_CLK_RESUME_CTRL);
+ amd_manager->clk_stopped = false;
+ }
+ }
+ sdw_clear_slave_status(bus, SDW_UNATTACH_REQUEST_MASTER_RESET);
+ amd_init_sdw_manager(amd_manager);
+ amd_enable_sdw_interrupts(amd_manager);
+ ret = amd_enable_sdw_manager(amd_manager);
+ if (ret)
+ return ret;
+ amd_sdw_set_frameshape(amd_manager);
+ }
+ return 0;
+}
+
+static const struct dev_pm_ops amd_pm = {
+ .prepare = amd_pm_prepare,
+ SET_SYSTEM_SLEEP_PM_OPS(amd_suspend, amd_resume_runtime)
+ SET_RUNTIME_PM_OPS(amd_suspend_runtime, amd_resume_runtime, NULL)
+};
+
+static struct platform_driver amd_sdw_driver = {
+ .probe = &amd_sdw_manager_probe,
+ .remove = &amd_sdw_manager_remove,
+ .driver = {
+ .name = "amd_sdw_manager",
+ .pm = &amd_pm,
+ }
+};
+module_platform_driver(amd_sdw_driver);
+
+MODULE_AUTHOR("Vijendar.Mukunda@amd.com");
+MODULE_DESCRIPTION("AMD SoundWire driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/soundwire/amd_manager.h b/drivers/soundwire/amd_manager.h
new file mode 100644
index 000000000000..5f040151a259
--- /dev/null
+++ b/drivers/soundwire/amd_manager.h
@@ -0,0 +1,258 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.
+ */
+
+#ifndef __AMD_MANAGER_H
+#define __AMD_MANAGER_H
+
+#include <linux/soundwire/sdw_amd.h>
+
+#define SDW_MANAGER_REG_OFFSET 0xc00
+#define AMD_SDW_DEFAULT_ROWS 50
+#define AMD_SDW_DEFAULT_COLUMNS 10
+#define ACP_PAD_PULLDOWN_CTRL 0x0001448
+#define ACP_SW_PAD_KEEPER_EN 0x0001454
+#define ACP_SW0_WAKE_EN 0x0001458
+#define ACP_EXTERNAL_INTR_CNTL0 0x0001a04
+#define ACP_EXTERNAL_INTR_STAT0 0x0001a0c
+#define ACP_EXTERNAL_INTR_CNTL(i) (ACP_EXTERNAL_INTR_CNTL0 + ((i) * 4))
+#define ACP_EXTERNAL_INTR_STAT(i) (ACP_EXTERNAL_INTR_STAT0 + ((i) * 4))
+#define ACP_SW_WAKE_EN(i) (ACP_SW0_WAKE_EN + ((i) * 8))
+
+#define ACP_SW_EN 0x0003000
+#define ACP_SW_EN_STATUS 0x0003004
+#define ACP_SW_FRAMESIZE 0x0003008
+#define ACP_SW_SSP_COUNTER 0x000300c
+#define ACP_SW_AUDIO0_TX_EN 0x0003010
+#define ACP_SW_AUDIO0_TX_EN_STATUS 0x0003014
+#define ACP_SW_AUDIO0_TX_FRAME_FORMAT 0x0003018
+#define ACP_SW_AUDIO0_TX_SAMPLEINTERVAL 0x000301c
+#define ACP_SW_AUDIO0_TX_HCTRL_DP0 0x0003020
+#define ACP_SW_AUDIO0_TX_HCTRL_DP1 0x0003024
+#define ACP_SW_AUDIO0_TX_HCTRL_DP2 0x0003028
+#define ACP_SW_AUDIO0_TX_HCTRL_DP3 0x000302c
+#define ACP_SW_AUDIO0_TX_OFFSET_DP0 0x0003030
+#define ACP_SW_AUDIO0_TX_OFFSET_DP1 0x0003034
+#define ACP_SW_AUDIO0_TX_OFFSET_DP2 0x0003038
+#define ACP_SW_AUDIO0_TX_OFFSET_DP3 0x000303c
+#define ACP_SW_AUDIO0_TX_CHANNEL_ENABLE_DP0 0x0003040
+#define ACP_SW_AUDIO0_TX_CHANNEL_ENABLE_DP1 0x0003044
+#define ACP_SW_AUDIO0_TX_CHANNEL_ENABLE_DP2 0x0003048
+#define ACP_SW_AUDIO0_TX_CHANNEL_ENABLE_DP3 0x000304c
+#define ACP_SW_AUDIO1_TX_EN 0x0003050
+#define ACP_SW_AUDIO1_TX_EN_STATUS 0x0003054
+#define ACP_SW_AUDIO1_TX_FRAME_FORMAT 0x0003058
+#define ACP_SW_AUDIO1_TX_SAMPLEINTERVAL 0x000305c
+#define ACP_SW_AUDIO1_TX_HCTRL 0x0003060
+#define ACP_SW_AUDIO1_TX_OFFSET 0x0003064
+#define ACP_SW_AUDIO1_TX_CHANNEL_ENABLE_DP0 0x0003068
+#define ACP_SW_AUDIO2_TX_EN 0x000306c
+#define ACP_SW_AUDIO2_TX_EN_STATUS 0x0003070
+#define ACP_SW_AUDIO2_TX_FRAME_FORMAT 0x0003074
+#define ACP_SW_AUDIO2_TX_SAMPLEINTERVAL 0x0003078
+#define ACP_SW_AUDIO2_TX_HCTRL 0x000307c
+#define ACP_SW_AUDIO2_TX_OFFSET 0x0003080
+#define ACP_SW_AUDIO2_TX_CHANNEL_ENABLE_DP0 0x0003084
+#define ACP_SW_AUDIO0_RX_EN 0x0003088
+#define ACP_SW_AUDIO0_RX_EN_STATUS 0x000308c
+#define ACP_SW_AUDIO0_RX_FRAME_FORMAT 0x0003090
+#define ACP_SW_AUDIO0_RX_SAMPLEINTERVAL 0x0003094
+#define ACP_SW_AUDIO0_RX_HCTRL_DP0 0x0003098
+#define ACP_SW_AUDIO0_RX_HCTRL_DP1 0x000309c
+#define ACP_SW_AUDIO0_RX_HCTRL_DP2 0x0003100
+#define ACP_SW_AUDIO0_RX_HCTRL_DP3 0x0003104
+#define ACP_SW_AUDIO0_RX_OFFSET_DP0 0x0003108
+#define ACP_SW_AUDIO0_RX_OFFSET_DP1 0x000310c
+#define ACP_SW_AUDIO0_RX_OFFSET_DP2 0x0003110
+#define ACP_SW_AUDIO0_RX_OFFSET_DP3 0x0003114
+#define ACP_SW_AUDIO0_RX_CHANNEL_ENABLE_DP0 0x0003118
+#define ACP_SW_AUDIO0_RX_CHANNEL_ENABLE_DP1 0x000311c
+#define ACP_SW_AUDIO0_RX_CHANNEL_ENABLE_DP2 0x0003120
+#define ACP_SW_AUDIO0_RX_CHANNEL_ENABLE_DP3 0x0003124
+#define ACP_SW_AUDIO1_RX_EN 0x0003128
+#define ACP_SW_AUDIO1_RX_EN_STATUS 0x000312c
+#define ACP_SW_AUDIO1_RX_FRAME_FORMAT 0x0003130
+#define ACP_SW_AUDIO1_RX_SAMPLEINTERVAL 0x0003134
+#define ACP_SW_AUDIO1_RX_HCTRL 0x0003138
+#define ACP_SW_AUDIO1_RX_OFFSET 0x000313c
+#define ACP_SW_AUDIO1_RX_CHANNEL_ENABLE_DP0 0x0003140
+#define ACP_SW_AUDIO2_RX_EN 0x0003144
+#define ACP_SW_AUDIO2_RX_EN_STATUS 0x0003148
+#define ACP_SW_AUDIO2_RX_FRAME_FORMAT 0x000314c
+#define ACP_SW_AUDIO2_RX_SAMPLEINTERVAL 0x0003150
+#define ACP_SW_AUDIO2_RX_HCTRL 0x0003154
+#define ACP_SW_AUDIO2_RX_OFFSET 0x0003158
+#define ACP_SW_AUDIO2_RX_CHANNEL_ENABLE_DP0 0x000315c
+#define ACP_SW_BPT_PORT_EN 0x0003160
+#define ACP_SW_BPT_PORT_EN_STATUS 0x0003164
+#define ACP_SW_BPT_PORT_FRAME_FORMAT 0x0003168
+#define ACP_SW_BPT_PORT_SAMPLEINTERVAL 0x000316c
+#define ACP_SW_BPT_PORT_HCTRL 0x0003170
+#define ACP_SW_BPT_PORT_OFFSET 0x0003174
+#define ACP_SW_BPT_PORT_CHANNEL_ENABLE 0x0003178
+#define ACP_SW_BPT_PORT_FIRST_BYTE_ADDR 0x000317c
+#define ACP_SW_CLK_RESUME_CTRL 0x0003180
+#define ACP_SW_CLK_RESUME_DELAY_CNTR 0x0003184
+#define ACP_SW_BUS_RESET_CTRL 0x0003188
+#define ACP_SW_PRBS_ERR_STATUS 0x000318c
+#define ACP_SW_IMM_CMD_UPPER_WORD 0x0003230
+#define ACP_SW_IMM_CMD_LOWER_QWORD 0x0003234
+#define ACP_SW_IMM_RESP_UPPER_WORD 0x0003238
+#define ACP_SW_IMM_RESP_LOWER_QWORD 0x000323c
+#define ACP_SW_IMM_CMD_STS 0x0003240
+#define ACP_SW_BRA_BASE_ADDRESS 0x0003244
+#define ACP_SW_BRA_TRANSFER_SIZE 0x0003248
+#define ACP_SW_BRA_DMA_BUSY 0x000324c
+#define ACP_SW_BRA_RESP 0x0003250
+#define ACP_SW_BRA_RESP_FRAME_ADDR 0x0003254
+#define ACP_SW_BRA_CURRENT_TRANSFER_SIZE 0x0003258
+#define ACP_SW_STATE_CHANGE_STATUS_0TO7 0x000325c
+#define ACP_SW_STATE_CHANGE_STATUS_8TO11 0x0003260
+#define ACP_SW_STATE_CHANGE_STATUS_MASK_0TO7 0x0003264
+#define ACP_SW_STATE_CHANGE_STATUS_MASK_8TO11 0x0003268
+#define ACP_SW_CLK_FREQUENCY_CTRL 0x000326c
+#define ACP_SW_ERROR_INTR_MASK 0x0003270
+#define ACP_SW_PHY_TEST_MODE_DATA_OFF 0x0003274
+
+#define ACP_DELAY_US 10
+#define AMD_SDW_TIMEOUT 1000
+#define AMD_SDW_DEFAULT_CLK_FREQ 12000000
+
+#define AMD_SDW_MCP_RESP_ACK BIT(0)
+#define AMD_SDW_MCP_RESP_NACK BIT(1)
+#define AMD_SDW_MCP_RESP_RDATA GENMASK(14, 7)
+
+#define AMD_SDW_MCP_CMD_SSP_TAG BIT(31)
+#define AMD_SDW_MCP_CMD_COMMAND GENMASK(14, 12)
+#define AMD_SDW_MCP_CMD_DEV_ADDR GENMASK(11, 8)
+#define AMD_SDW_MCP_CMD_REG_ADDR_HIGH GENMASK(7, 0)
+#define AMD_SDW_MCP_CMD_REG_ADDR_LOW GENMASK(31, 24)
+#define AMD_SDW_MCP_CMD_REG_DATA GENMASK(14, 7)
+#define AMD_SDW_MCP_SLAVE_STAT_0_3 GENMASK(14, 7)
+#define AMD_SDW_MCP_SLAVE_STAT_4_11 GENMASK_ULL(39, 24)
+#define AMD_SDW_MCP_SLAVE_STATUS_MASK GENMASK(1, 0)
+#define AMD_SDW_MCP_SLAVE_STATUS_BITS GENMASK(3, 2)
+#define AMD_SDW_MCP_SLAVE_STATUS_8TO_11 GENMASK_ULL(15, 0)
+#define AMD_SDW_MCP_SLAVE_STATUS_VALID_MASK(x) BIT(((x) * 4))
+#define AMD_SDW_MCP_SLAVE_STAT_SHIFT_MASK(x) (((x) * 4) + 1)
+
+#define AMD_SDW_MASTER_SUSPEND_DELAY_MS 2000
+#define AMD_SDW_QUIRK_MASK_BUS_ENABLE BIT(0)
+
+#define AMD_SDW_IMM_RES_VALID 1
+#define AMD_SDW_IMM_CMD_BUSY 2
+#define AMD_SDW_ENABLE 1
+#define AMD_SDW_DISABLE 0
+#define AMD_SDW_BUS_RESET_CLEAR_REQ 0
+#define AMD_SDW_BUS_RESET_REQ 1
+#define AMD_SDW_BUS_RESET_DONE 2
+#define AMD_SDW_BUS_BASE_FREQ 24000000
+
+#define AMD_SDW0_EXT_INTR_MASK 0x200000
+#define AMD_SDW1_EXT_INTR_MASK 4
+#define AMD_SDW_IRQ_MASK_0TO7 0x77777777
+#define AMD_SDW_IRQ_MASK_8TO11 0x000d7777
+#define AMD_SDW_IRQ_ERROR_MASK 0xff
+#define AMD_SDW_MAX_FREQ_NUM 1
+#define AMD_SDW0_MAX_TX_PORTS 3
+#define AMD_SDW0_MAX_RX_PORTS 3
+#define AMD_SDW1_MAX_TX_PORTS 1
+#define AMD_SDW1_MAX_RX_PORTS 1
+#define AMD_SDW0_MAX_DAI 6
+#define AMD_SDW1_MAX_DAI 2
+#define AMD_SDW_SLAVE_0_ATTACHED 5
+#define AMD_SDW_SSP_COUNTER_VAL 3
+
+#define AMD_DPN_FRAME_FMT_PFM GENMASK(1, 0)
+#define AMD_DPN_FRAME_FMT_PDM GENMASK(3, 2)
+#define AMD_DPN_FRAME_FMT_BLK_PKG_MODE BIT(4)
+#define AMD_DPN_FRAME_FMT_BLK_GRP_CTRL GENMASK(6, 5)
+#define AMD_DPN_FRAME_FMT_WORD_LEN GENMASK(12, 7)
+#define AMD_DPN_FRAME_FMT_PCM_OR_PDM BIT(13)
+#define AMD_DPN_HCTRL_HSTOP GENMASK(3, 0)
+#define AMD_DPN_HCTRL_HSTART GENMASK(7, 4)
+#define AMD_DPN_OFFSET_CTRL_1 GENMASK(7, 0)
+#define AMD_DPN_OFFSET_CTRL_2 GENMASK(15, 8)
+#define AMD_DPN_CH_EN_LCTRL GENMASK(2, 0)
+#define AMD_DPN_CH_EN_CHMASK GENMASK(10, 3)
+#define AMD_SDW_STAT_MAX_RETRY_COUNT 100
+#define AMD_SDW0_PAD_PULLDOWN_CTRL_ENABLE_MASK 0x7f9f
+#define AMD_SDW1_PAD_PULLDOWN_CTRL_ENABLE_MASK 0x7ffa
+#define AMD_SDW0_PAD_PULLDOWN_CTRL_DISABLE_MASK 0x60
+#define AMD_SDW1_PAD_PULLDOWN_CTRL_DISABLE_MASK 5
+#define AMD_SDW0_PAD_KEEPER_EN_MASK 1
+#define AMD_SDW1_PAD_KEEPER_EN_MASK 0x10
+#define AMD_SDW0_PAD_KEEPER_DISABLE_MASK 0x1e
+#define AMD_SDW1_PAD_KEEPER_DISABLE_MASK 0xf
+#define AMD_SDW_PREQ_INTR_STAT BIT(19)
+#define AMD_SDW_CLK_STOP_DONE 1
+#define AMD_SDW_CLK_RESUME_REQ 2
+#define AMD_SDW_CLK_RESUME_DONE 3
+#define AMD_SDW_WAKE_STAT_MASK BIT(16)
+
+static u32 amd_sdw_freq_tbl[AMD_SDW_MAX_FREQ_NUM] = {
+ AMD_SDW_DEFAULT_CLK_FREQ,
+};
+
+struct sdw_manager_dp_reg {
+ u32 frame_fmt_reg;
+ u32 sample_int_reg;
+ u32 hctrl_dp0_reg;
+ u32 offset_reg;
+ u32 lane_ctrl_ch_en_reg;
+};
+
+/*
+ * SDW0 Manager instance registers 6 CPU DAI (3 TX & 3 RX Ports)
+ * whereas SDW1 Manager Instance registers 2 CPU DAI (one TX & one RX port)
+ * Below is the CPU DAI <->Manager port number mapping
+ * i.e SDW0 Pin0 -> port number 0 -> AUDIO0 TX
+ * SDW0 Pin1 -> Port number 1 -> AUDIO1 TX
+ * SDW0 Pin2 -> Port number 2 -> AUDIO2 TX
+ * SDW0 Pin3 -> port number 3 -> AUDIO0 RX
+ * SDW0 Pin4 -> Port number 4 -> AUDIO1 RX
+ * SDW0 Pin5 -> Port number 5 -> AUDIO2 RX
+ * Whereas for SDW1 instance
+ * SDW1 Pin0 -> port number 0 -> AUDIO1 TX
+ * SDW1 Pin1 -> Port number 1 -> AUDIO1 RX
+ * Same mapping should be used for programming DMA controller registers in SoundWire DMA driver.
+ * i.e if AUDIO0 TX channel is selected then we need to use AUDIO0 TX registers for DMA programming
+ * in SoundWire DMA driver.
+ */
+
+static struct sdw_manager_dp_reg sdw0_manager_dp_reg[AMD_SDW0_MAX_DAI] = {
+ {ACP_SW_AUDIO0_TX_FRAME_FORMAT, ACP_SW_AUDIO0_TX_SAMPLEINTERVAL, ACP_SW_AUDIO0_TX_HCTRL_DP0,
+ ACP_SW_AUDIO0_TX_OFFSET_DP0, ACP_SW_AUDIO0_TX_CHANNEL_ENABLE_DP0},
+ {ACP_SW_AUDIO1_TX_FRAME_FORMAT, ACP_SW_AUDIO1_TX_SAMPLEINTERVAL, ACP_SW_AUDIO1_TX_HCTRL,
+ ACP_SW_AUDIO1_TX_OFFSET, ACP_SW_AUDIO1_TX_CHANNEL_ENABLE_DP0},
+ {ACP_SW_AUDIO2_TX_FRAME_FORMAT, ACP_SW_AUDIO2_TX_SAMPLEINTERVAL, ACP_SW_AUDIO2_TX_HCTRL,
+ ACP_SW_AUDIO2_TX_OFFSET, ACP_SW_AUDIO2_TX_CHANNEL_ENABLE_DP0},
+ {ACP_SW_AUDIO0_RX_FRAME_FORMAT, ACP_SW_AUDIO0_RX_SAMPLEINTERVAL, ACP_SW_AUDIO0_RX_HCTRL_DP0,
+ ACP_SW_AUDIO0_RX_OFFSET_DP0, ACP_SW_AUDIO0_RX_CHANNEL_ENABLE_DP0},
+ {ACP_SW_AUDIO1_RX_FRAME_FORMAT, ACP_SW_AUDIO1_RX_SAMPLEINTERVAL, ACP_SW_AUDIO1_RX_HCTRL,
+ ACP_SW_AUDIO1_RX_OFFSET, ACP_SW_AUDIO1_RX_CHANNEL_ENABLE_DP0},
+ {ACP_SW_AUDIO2_RX_FRAME_FORMAT, ACP_SW_AUDIO2_RX_SAMPLEINTERVAL, ACP_SW_AUDIO2_RX_HCTRL,
+ ACP_SW_AUDIO2_RX_OFFSET, ACP_SW_AUDIO2_RX_CHANNEL_ENABLE_DP0},
+};
+
+static struct sdw_manager_dp_reg sdw1_manager_dp_reg[AMD_SDW1_MAX_DAI] = {
+ {ACP_SW_AUDIO1_TX_FRAME_FORMAT, ACP_SW_AUDIO1_TX_SAMPLEINTERVAL, ACP_SW_AUDIO1_TX_HCTRL,
+ ACP_SW_AUDIO1_TX_OFFSET, ACP_SW_AUDIO1_TX_CHANNEL_ENABLE_DP0},
+ {ACP_SW_AUDIO1_RX_FRAME_FORMAT, ACP_SW_AUDIO1_RX_SAMPLEINTERVAL, ACP_SW_AUDIO1_RX_HCTRL,
+ ACP_SW_AUDIO1_RX_OFFSET, ACP_SW_AUDIO1_RX_CHANNEL_ENABLE_DP0}
+};
+
+static struct sdw_manager_reg_mask sdw_manager_reg_mask_array[2] = {
+ {
+ AMD_SDW0_PAD_KEEPER_EN_MASK,
+ AMD_SDW0_PAD_PULLDOWN_CTRL_ENABLE_MASK,
+ AMD_SDW0_EXT_INTR_MASK
+ },
+ {
+ AMD_SDW1_PAD_KEEPER_EN_MASK,
+ AMD_SDW1_PAD_PULLDOWN_CTRL_ENABLE_MASK,
+ AMD_SDW1_EXT_INTR_MASK
+ }
+};
+#endif
diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c
index b6aca59c3130..1ea6a64f8c4a 100644
--- a/drivers/soundwire/bus.c
+++ b/drivers/soundwire/bus.c
@@ -384,45 +384,73 @@ int sdw_fill_msg(struct sdw_msg *msg, struct sdw_slave *slave,
/*
* Read/Write IO functions.
- * no_pm versions can only be called by the bus, e.g. while enumerating or
- * handling suspend-resume sequences.
- * all clients need to use the pm versions
*/
-int sdw_nread_no_pm(struct sdw_slave *slave, u32 addr, size_t count, u8 *val)
+static int sdw_ntransfer_no_pm(struct sdw_slave *slave, u32 addr, u8 flags,
+ size_t count, u8 *val)
{
struct sdw_msg msg;
+ size_t size;
int ret;
- ret = sdw_fill_msg(&msg, slave, addr, count,
- slave->dev_num, SDW_MSG_FLAG_READ, val);
- if (ret < 0)
- return ret;
+ while (count) {
+ // Only handle bytes up to next page boundary
+ size = min_t(size_t, count, (SDW_REGADDR + 1) - (addr & SDW_REGADDR));
- ret = sdw_transfer(slave->bus, &msg);
- if (slave->is_mockup_device)
- ret = 0;
- return ret;
+ ret = sdw_fill_msg(&msg, slave, addr, size, slave->dev_num, flags, val);
+ if (ret < 0)
+ return ret;
+
+ ret = sdw_transfer(slave->bus, &msg);
+ if (ret < 0 && !slave->is_mockup_device)
+ return ret;
+
+ addr += size;
+ val += size;
+ count -= size;
+ }
+
+ return 0;
+}
+
+/**
+ * sdw_nread_no_pm() - Read "n" contiguous SDW Slave registers with no PM
+ * @slave: SDW Slave
+ * @addr: Register address
+ * @count: length
+ * @val: Buffer for values to be read
+ *
+ * Note that if the message crosses a page boundary each page will be
+ * transferred under a separate invocation of the msg_lock.
+ */
+int sdw_nread_no_pm(struct sdw_slave *slave, u32 addr, size_t count, u8 *val)
+{
+ return sdw_ntransfer_no_pm(slave, addr, SDW_MSG_FLAG_READ, count, val);
}
EXPORT_SYMBOL(sdw_nread_no_pm);
+/**
+ * sdw_nwrite_no_pm() - Write "n" contiguous SDW Slave registers with no PM
+ * @slave: SDW Slave
+ * @addr: Register address
+ * @count: length
+ * @val: Buffer for values to be written
+ *
+ * Note that if the message crosses a page boundary each page will be
+ * transferred under a separate invocation of the msg_lock.
+ */
int sdw_nwrite_no_pm(struct sdw_slave *slave, u32 addr, size_t count, const u8 *val)
{
- struct sdw_msg msg;
- int ret;
-
- ret = sdw_fill_msg(&msg, slave, addr, count,
- slave->dev_num, SDW_MSG_FLAG_WRITE, (u8 *)val);
- if (ret < 0)
- return ret;
-
- ret = sdw_transfer(slave->bus, &msg);
- if (slave->is_mockup_device)
- ret = 0;
- return ret;
+ return sdw_ntransfer_no_pm(slave, addr, SDW_MSG_FLAG_WRITE, count, (u8 *)val);
}
EXPORT_SYMBOL(sdw_nwrite_no_pm);
+/**
+ * sdw_write_no_pm() - Write a SDW Slave register with no PM
+ * @slave: SDW Slave
+ * @addr: Register address
+ * @value: Register value
+ */
int sdw_write_no_pm(struct sdw_slave *slave, u32 addr, u8 value)
{
return sdw_nwrite_no_pm(slave, addr, 1, &value);
@@ -495,6 +523,11 @@ int sdw_bwrite_no_pm_unlocked(struct sdw_bus *bus, u16 dev_num, u32 addr, u8 val
}
EXPORT_SYMBOL(sdw_bwrite_no_pm_unlocked);
+/**
+ * sdw_read_no_pm() - Read a SDW Slave register with no PM
+ * @slave: SDW Slave
+ * @addr: Register address
+ */
int sdw_read_no_pm(struct sdw_slave *slave, u32 addr)
{
u8 buf;
@@ -541,14 +574,21 @@ EXPORT_SYMBOL(sdw_update);
* @addr: Register address
* @count: length
* @val: Buffer for values to be read
+ *
+ * This version of the function will take a PM reference to the slave
+ * device.
+ * Note that if the message crosses a page boundary each page will be
+ * transferred under a separate invocation of the msg_lock.
*/
int sdw_nread(struct sdw_slave *slave, u32 addr, size_t count, u8 *val)
{
int ret;
- ret = pm_runtime_resume_and_get(&slave->dev);
- if (ret < 0 && ret != -EACCES)
+ ret = pm_runtime_get_sync(&slave->dev);
+ if (ret < 0 && ret != -EACCES) {
+ pm_runtime_put_noidle(&slave->dev);
return ret;
+ }
ret = sdw_nread_no_pm(slave, addr, count, val);
@@ -565,14 +605,21 @@ EXPORT_SYMBOL(sdw_nread);
* @addr: Register address
* @count: length
* @val: Buffer for values to be written
+ *
+ * This version of the function will take a PM reference to the slave
+ * device.
+ * Note that if the message crosses a page boundary each page will be
+ * transferred under a separate invocation of the msg_lock.
*/
int sdw_nwrite(struct sdw_slave *slave, u32 addr, size_t count, const u8 *val)
{
int ret;
- ret = pm_runtime_resume_and_get(&slave->dev);
- if (ret < 0 && ret != -EACCES)
+ ret = pm_runtime_get_sync(&slave->dev);
+ if (ret < 0 && ret != -EACCES) {
+ pm_runtime_put_noidle(&slave->dev);
return ret;
+ }
ret = sdw_nwrite_no_pm(slave, addr, count, val);
@@ -587,6 +634,9 @@ EXPORT_SYMBOL(sdw_nwrite);
* sdw_read() - Read a SDW Slave register
* @slave: SDW Slave
* @addr: Register address
+ *
+ * This version of the function will take a PM reference to the slave
+ * device.
*/
int sdw_read(struct sdw_slave *slave, u32 addr)
{
@@ -606,6 +656,9 @@ EXPORT_SYMBOL(sdw_read);
* @slave: SDW Slave
* @addr: Register address
* @value: Register value
+ *
+ * This version of the function will take a PM reference to the slave
+ * device.
*/
int sdw_write(struct sdw_slave *slave, u32 addr, u8 value)
{
@@ -1541,9 +1594,10 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
sdw_modify_slave_status(slave, SDW_SLAVE_ALERT);
- ret = pm_runtime_resume_and_get(&slave->dev);
+ ret = pm_runtime_get_sync(&slave->dev);
if (ret < 0 && ret != -EACCES) {
dev_err(&slave->dev, "Failed to resume device: %d\n", ret);
+ pm_runtime_put_noidle(&slave->dev);
return ret;
}
diff --git a/drivers/soundwire/bus.h b/drivers/soundwire/bus.h
index 96927a143796..fda6b24ac2da 100644
--- a/drivers/soundwire/bus.h
+++ b/drivers/soundwire/bus.h
@@ -144,6 +144,13 @@ struct sdw_master_runtime {
struct list_head bus_node;
};
+struct sdw_transport_data {
+ int hstart;
+ int hstop;
+ int block_offset;
+ int sub_block_offset;
+};
+
struct sdw_dpn_prop *sdw_get_slave_dpn_prop(struct sdw_slave *slave,
enum sdw_data_direction direction,
unsigned int port_num);
@@ -158,17 +165,6 @@ int sdw_transfer_defer(struct sdw_bus *bus, struct sdw_msg *msg);
int sdw_fill_msg(struct sdw_msg *msg, struct sdw_slave *slave,
u32 addr, size_t count, u16 dev_num, u8 flags, u8 *buf);
-/* Retrieve and return channel count from channel mask */
-static inline int sdw_ch_mask_to_ch(int ch_mask)
-{
- int c = 0;
-
- for (c = 0; ch_mask; ch_mask >>= 1)
- c += ch_mask & 1;
-
- return c;
-}
-
/* Fill transport parameter data structure */
static inline void sdw_fill_xport_params(struct sdw_transport_params *params,
int port_num, bool grp_ctrl_valid,
@@ -212,5 +208,7 @@ int sdw_bwrite_no_pm_unlocked(struct sdw_bus *bus, u16 dev_num, u32 addr, u8 val
void sdw_clear_slave_status(struct sdw_bus *bus, u32 request);
int sdw_slave_modalias(const struct sdw_slave *slave, char *buf, size_t size);
+void sdw_compute_slave_ports(struct sdw_master_runtime *m_rt,
+ struct sdw_transport_data *t_data);
#endif /* __SDW_BUS_H */
diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
index e835dabb516c..39502bc75712 100644
--- a/drivers/soundwire/cadence_master.c
+++ b/drivers/soundwire/cadence_master.c
@@ -27,32 +27,36 @@ module_param_named(cnds_mcp_int_mask, interrupt_mask, int, 0444);
MODULE_PARM_DESC(cdns_mcp_int_mask, "Cadence MCP IntMask");
#define CDNS_MCP_CONFIG 0x0
-
-#define CDNS_MCP_CONFIG_MCMD_RETRY GENMASK(27, 24)
-#define CDNS_MCP_CONFIG_MPREQ_DELAY GENMASK(20, 16)
-#define CDNS_MCP_CONFIG_MMASTER BIT(7)
#define CDNS_MCP_CONFIG_BUS_REL BIT(6)
-#define CDNS_MCP_CONFIG_SNIFFER BIT(5)
-#define CDNS_MCP_CONFIG_SSPMOD BIT(4)
-#define CDNS_MCP_CONFIG_CMD BIT(3)
-#define CDNS_MCP_CONFIG_OP GENMASK(2, 0)
-#define CDNS_MCP_CONFIG_OP_NORMAL 0
+
+#define CDNS_IP_MCP_CONFIG 0x0 /* IP offset added at run-time */
+
+#define CDNS_IP_MCP_CONFIG_MCMD_RETRY GENMASK(27, 24)
+#define CDNS_IP_MCP_CONFIG_MPREQ_DELAY GENMASK(20, 16)
+#define CDNS_IP_MCP_CONFIG_MMASTER BIT(7)
+#define CDNS_IP_MCP_CONFIG_SNIFFER BIT(5)
+#define CDNS_IP_MCP_CONFIG_CMD BIT(3)
+#define CDNS_IP_MCP_CONFIG_OP GENMASK(2, 0)
+#define CDNS_IP_MCP_CONFIG_OP_NORMAL 0
#define CDNS_MCP_CONTROL 0x4
-#define CDNS_MCP_CONTROL_RST_DELAY GENMASK(10, 8)
#define CDNS_MCP_CONTROL_CMD_RST BIT(7)
#define CDNS_MCP_CONTROL_SOFT_RST BIT(6)
-#define CDNS_MCP_CONTROL_SW_RST BIT(5)
#define CDNS_MCP_CONTROL_HW_RST BIT(4)
-#define CDNS_MCP_CONTROL_CLK_PAUSE BIT(3)
#define CDNS_MCP_CONTROL_CLK_STOP_CLR BIT(2)
-#define CDNS_MCP_CONTROL_CMD_ACCEPT BIT(1)
-#define CDNS_MCP_CONTROL_BLOCK_WAKEUP BIT(0)
-#define CDNS_MCP_CMDCTRL 0x8
+#define CDNS_IP_MCP_CONTROL 0x4 /* IP offset added at run-time */
+
+#define CDNS_IP_MCP_CONTROL_RST_DELAY GENMASK(10, 8)
+#define CDNS_IP_MCP_CONTROL_SW_RST BIT(5)
+#define CDNS_IP_MCP_CONTROL_CLK_PAUSE BIT(3)
+#define CDNS_IP_MCP_CONTROL_CMD_ACCEPT BIT(1)
+#define CDNS_IP_MCP_CONTROL_BLOCK_WAKEUP BIT(0)
-#define CDNS_MCP_CMDCTRL_INSERT_PARITY_ERR BIT(2)
+#define CDNS_IP_MCP_CMDCTRL 0x8 /* IP offset added at run-time */
+
+#define CDNS_IP_MCP_CMDCTRL_INSERT_PARITY_ERR BIT(2)
#define CDNS_MCP_SSPSTAT 0xC
#define CDNS_MCP_FRAME_SHAPE 0x10
@@ -125,8 +129,8 @@ MODULE_PARM_DESC(cdns_mcp_int_mask, "Cadence MCP IntMask");
#define CDNS_MCP_FIFOSTAT 0x7C
#define CDNS_MCP_RX_FIFO_AVAIL GENMASK(5, 0)
-#define CDNS_MCP_CMD_BASE 0x80
-#define CDNS_MCP_RESP_BASE 0x80
+#define CDNS_IP_MCP_CMD_BASE 0x80 /* IP offset added at run-time */
+#define CDNS_IP_MCP_RESP_BASE 0x80 /* IP offset added at run-time */
/* FIFO can hold 8 commands */
#define CDNS_MCP_CMD_LEN 8
#define CDNS_MCP_CMD_WORD_LEN 0x4
@@ -206,6 +210,16 @@ static inline void cdns_writel(struct sdw_cdns *cdns, int offset, u32 value)
writel(value, cdns->registers + offset);
}
+static inline u32 cdns_ip_readl(struct sdw_cdns *cdns, int offset)
+{
+ return cdns_readl(cdns, cdns->ip_offset + offset);
+}
+
+static inline void cdns_ip_writel(struct sdw_cdns *cdns, int offset, u32 value)
+{
+ return cdns_writel(cdns, cdns->ip_offset + offset, value);
+}
+
static inline void cdns_updatel(struct sdw_cdns *cdns,
int offset, u32 mask, u32 val)
{
@@ -216,6 +230,12 @@ static inline void cdns_updatel(struct sdw_cdns *cdns,
cdns_writel(cdns, offset, tmp);
}
+static inline void cdns_ip_updatel(struct sdw_cdns *cdns,
+ int offset, u32 mask, u32 val)
+{
+ cdns_updatel(cdns, cdns->ip_offset + offset, mask, val);
+}
+
static int cdns_set_wait(struct sdw_cdns *cdns, int offset, u32 mask, u32 value)
{
int timeout = 10;
@@ -408,9 +428,9 @@ static int cdns_parity_error_injection(void *data, u64 value)
mutex_lock(&bus->bus_lock);
/* program hardware to inject parity error */
- cdns_updatel(cdns, CDNS_MCP_CMDCTRL,
- CDNS_MCP_CMDCTRL_INSERT_PARITY_ERR,
- CDNS_MCP_CMDCTRL_INSERT_PARITY_ERR);
+ cdns_ip_updatel(cdns, CDNS_IP_MCP_CMDCTRL,
+ CDNS_IP_MCP_CMDCTRL_INSERT_PARITY_ERR,
+ CDNS_IP_MCP_CMDCTRL_INSERT_PARITY_ERR);
/* commit changes */
cdns_updatel(cdns, CDNS_MCP_CONFIG_UPDATE,
@@ -422,9 +442,9 @@ static int cdns_parity_error_injection(void *data, u64 value)
dev_info(cdns->dev, "parity error injection, read: %d\n", ret);
/* program hardware to disable parity error */
- cdns_updatel(cdns, CDNS_MCP_CMDCTRL,
- CDNS_MCP_CMDCTRL_INSERT_PARITY_ERR,
- 0);
+ cdns_ip_updatel(cdns, CDNS_IP_MCP_CMDCTRL,
+ CDNS_IP_MCP_CMDCTRL_INSERT_PARITY_ERR,
+ 0);
/* commit changes */
cdns_updatel(cdns, CDNS_MCP_CONFIG_UPDATE,
@@ -570,10 +590,10 @@ static void cdns_read_response(struct sdw_cdns *cdns)
num_resp = ARRAY_SIZE(cdns->response_buf);
}
- cmd_base = CDNS_MCP_CMD_BASE;
+ cmd_base = CDNS_IP_MCP_CMD_BASE;
for (i = 0; i < num_resp; i++) {
- cdns->response_buf[i] = cdns_readl(cdns, cmd_base);
+ cdns->response_buf[i] = cdns_ip_readl(cdns, cmd_base);
cmd_base += CDNS_MCP_CMD_WORD_LEN;
}
}
@@ -592,7 +612,7 @@ _cdns_xfer_msg(struct sdw_cdns *cdns, struct sdw_msg *msg, int cmd,
cdns->msg_count = count;
}
- base = CDNS_MCP_CMD_BASE;
+ base = CDNS_IP_MCP_CMD_BASE;
addr = msg->addr + offset;
for (i = 0; i < count; i++) {
@@ -605,7 +625,7 @@ _cdns_xfer_msg(struct sdw_cdns *cdns, struct sdw_msg *msg, int cmd,
data |= msg->buf[i + offset];
data |= FIELD_PREP(CDNS_MCP_CMD_SSP_TAG, msg->ssp_sync);
- cdns_writel(cdns, base, data);
+ cdns_ip_writel(cdns, base, data);
base += CDNS_MCP_CMD_WORD_LEN;
}
@@ -653,10 +673,10 @@ cdns_program_scp_addr(struct sdw_cdns *cdns, struct sdw_msg *msg)
data[0] |= msg->addr_page1;
data[1] |= msg->addr_page2;
- base = CDNS_MCP_CMD_BASE;
- cdns_writel(cdns, base, data[0]);
+ base = CDNS_IP_MCP_CMD_BASE;
+ cdns_ip_writel(cdns, base, data[0]);
base += CDNS_MCP_CMD_WORD_LEN;
- cdns_writel(cdns, base, data[1]);
+ cdns_ip_writel(cdns, base, data[1]);
time = wait_for_completion_timeout(&cdns->tx_complete,
msecs_to_jiffies(CDNS_TX_TIMEOUT));
@@ -1033,6 +1053,7 @@ update_status:
void sdw_cdns_check_self_clearing_bits(struct sdw_cdns *cdns, const char *string,
bool initial_delay, int reset_iterations)
{
+ u32 ip_mcp_control;
u32 mcp_control;
u32 mcp_config_update;
int i;
@@ -1040,6 +1061,12 @@ void sdw_cdns_check_self_clearing_bits(struct sdw_cdns *cdns, const char *string
if (initial_delay)
usleep_range(1000, 1500);
+ ip_mcp_control = cdns_ip_readl(cdns, CDNS_IP_MCP_CONTROL);
+
+ /* the following bits should be cleared immediately */
+ if (ip_mcp_control & CDNS_IP_MCP_CONTROL_SW_RST)
+ dev_err(cdns->dev, "%s failed: IP_MCP_CONTROL_SW_RST is not cleared\n", string);
+
mcp_control = cdns_readl(cdns, CDNS_MCP_CONTROL);
/* the following bits should be cleared immediately */
@@ -1047,10 +1074,9 @@ void sdw_cdns_check_self_clearing_bits(struct sdw_cdns *cdns, const char *string
dev_err(cdns->dev, "%s failed: MCP_CONTROL_CMD_RST is not cleared\n", string);
if (mcp_control & CDNS_MCP_CONTROL_SOFT_RST)
dev_err(cdns->dev, "%s failed: MCP_CONTROL_SOFT_RST is not cleared\n", string);
- if (mcp_control & CDNS_MCP_CONTROL_SW_RST)
- dev_err(cdns->dev, "%s failed: MCP_CONTROL_SW_RST is not cleared\n", string);
if (mcp_control & CDNS_MCP_CONTROL_CLK_STOP_CLR)
dev_err(cdns->dev, "%s failed: MCP_CONTROL_CLK_STOP_CLR is not cleared\n", string);
+
mcp_config_update = cdns_readl(cdns, CDNS_MCP_CONFIG_UPDATE);
if (mcp_config_update & CDNS_MCP_CONFIG_UPDATE_BIT)
dev_err(cdns->dev, "%s failed: MCP_CONFIG_UPDATE_BIT is not cleared\n", string);
@@ -1327,34 +1353,39 @@ int sdw_cdns_init(struct sdw_cdns *cdns)
CDNS_MCP_CONTROL_CMD_RST);
/* Set cmd accept mode */
- cdns_updatel(cdns, CDNS_MCP_CONTROL, CDNS_MCP_CONTROL_CMD_ACCEPT,
- CDNS_MCP_CONTROL_CMD_ACCEPT);
+ cdns_ip_updatel(cdns, CDNS_IP_MCP_CONTROL, CDNS_IP_MCP_CONTROL_CMD_ACCEPT,
+ CDNS_IP_MCP_CONTROL_CMD_ACCEPT);
/* Configure mcp config */
val = cdns_readl(cdns, CDNS_MCP_CONFIG);
+ /* Disable auto bus release */
+ val &= ~CDNS_MCP_CONFIG_BUS_REL;
+
+ cdns_writel(cdns, CDNS_MCP_CONFIG, val);
+
+ /* Configure IP mcp config */
+ val = cdns_ip_readl(cdns, CDNS_IP_MCP_CONFIG);
+
/* enable bus operations with clock and data */
- val &= ~CDNS_MCP_CONFIG_OP;
- val |= CDNS_MCP_CONFIG_OP_NORMAL;
+ val &= ~CDNS_IP_MCP_CONFIG_OP;
+ val |= CDNS_IP_MCP_CONFIG_OP_NORMAL;
/* Set cmd mode for Tx and Rx cmds */
- val &= ~CDNS_MCP_CONFIG_CMD;
+ val &= ~CDNS_IP_MCP_CONFIG_CMD;
/* Disable sniffer mode */
- val &= ~CDNS_MCP_CONFIG_SNIFFER;
-
- /* Disable auto bus release */
- val &= ~CDNS_MCP_CONFIG_BUS_REL;
+ val &= ~CDNS_IP_MCP_CONFIG_SNIFFER;
if (cdns->bus.multi_link)
/* Set Multi-master mode to take gsync into account */
- val |= CDNS_MCP_CONFIG_MMASTER;
+ val |= CDNS_IP_MCP_CONFIG_MMASTER;
/* leave frame delay to hardware default of 0x1F */
/* leave command retry to hardware default of 0 */
- cdns_writel(cdns, CDNS_MCP_CONFIG, val);
+ cdns_ip_writel(cdns, CDNS_IP_MCP_CONFIG, val);
/* changes will be committed later */
return 0;
@@ -1584,9 +1615,9 @@ int sdw_cdns_clock_stop(struct sdw_cdns *cdns, bool block_wake)
* in clock stop state
*/
if (block_wake)
- cdns_updatel(cdns, CDNS_MCP_CONTROL,
- CDNS_MCP_CONTROL_BLOCK_WAKEUP,
- CDNS_MCP_CONTROL_BLOCK_WAKEUP);
+ cdns_ip_updatel(cdns, CDNS_IP_MCP_CONTROL,
+ CDNS_IP_MCP_CONTROL_BLOCK_WAKEUP,
+ CDNS_IP_MCP_CONTROL_BLOCK_WAKEUP);
list_for_each_entry(slave, &cdns->bus.slaves, node) {
if (slave->status == SDW_SLAVE_ATTACHED ||
@@ -1659,18 +1690,18 @@ int sdw_cdns_clock_restart(struct sdw_cdns *cdns, bool bus_reset)
return ret;
}
- cdns_updatel(cdns, CDNS_MCP_CONTROL,
- CDNS_MCP_CONTROL_BLOCK_WAKEUP, 0);
+ cdns_ip_updatel(cdns, CDNS_IP_MCP_CONTROL,
+ CDNS_IP_MCP_CONTROL_BLOCK_WAKEUP, 0);
- cdns_updatel(cdns, CDNS_MCP_CONTROL, CDNS_MCP_CONTROL_CMD_ACCEPT,
- CDNS_MCP_CONTROL_CMD_ACCEPT);
+ cdns_ip_updatel(cdns, CDNS_IP_MCP_CONTROL, CDNS_IP_MCP_CONTROL_CMD_ACCEPT,
+ CDNS_IP_MCP_CONTROL_CMD_ACCEPT);
if (!bus_reset) {
/* enable bus operations with clock and data */
- cdns_updatel(cdns, CDNS_MCP_CONFIG,
- CDNS_MCP_CONFIG_OP,
- CDNS_MCP_CONFIG_OP_NORMAL);
+ cdns_ip_updatel(cdns, CDNS_IP_MCP_CONFIG,
+ CDNS_IP_MCP_CONFIG_OP,
+ CDNS_IP_MCP_CONFIG_OP_NORMAL);
ret = cdns_config_update(cdns);
if (ret < 0) {
diff --git a/drivers/soundwire/cadence_master.h b/drivers/soundwire/cadence_master.h
index dec0b4f993c1..27c56274217f 100644
--- a/drivers/soundwire/cadence_master.h
+++ b/drivers/soundwire/cadence_master.h
@@ -84,7 +84,6 @@ struct sdw_cdns_stream_config {
* @bus: Bus handle
* @stream_type: Stream type
* @link_id: Master link id
- * @hw_params: hw_params to be applied in .prepare step
* @suspended: status set when suspended, to be used in .prepare
* @paused: status set in .trigger, to be used in suspend
* @direction: stream direction
@@ -96,7 +95,6 @@ struct sdw_cdns_dai_runtime {
struct sdw_bus *bus;
enum sdw_stream_type stream_type;
int link_id;
- struct snd_pcm_hw_params *hw_params;
bool suspended;
bool paused;
int direction;
@@ -107,6 +105,7 @@ struct sdw_cdns_dai_runtime {
* @dev: Linux device
* @bus: Bus handle
* @instance: instance number
+ * @ip_offset: version-dependent offset to access IP_MCP registers and fields
* @response_buf: SoundWire response buffer
* @tx_complete: Tx completion
* @ports: Data ports
@@ -122,6 +121,8 @@ struct sdw_cdns {
struct sdw_bus bus;
unsigned int instance;
+ u32 ip_offset;
+
/*
* The datasheet says the RX FIFO AVAIL can be 2 entries more
* than the FIFO capacity, so allow for this.
diff --git a/drivers/soundwire/dmi-quirks.c b/drivers/soundwire/dmi-quirks.c
index 7969881f126d..58ea013fa918 100644
--- a/drivers/soundwire/dmi-quirks.c
+++ b/drivers/soundwire/dmi-quirks.c
@@ -73,6 +73,23 @@ static const struct adr_remap hp_omen_16[] = {
{}
};
+/*
+ * Intel NUC M15 LAPRC510 and LAPRC710
+ */
+static const struct adr_remap intel_rooks_county[] = {
+ /* rt711-sdca on link0 */
+ {
+ 0x000020025d071100ull,
+ 0x000030025d071101ull
+ },
+ /* rt1316-sdca on link2 */
+ {
+ 0x000120025d071100ull,
+ 0x000230025d131601ull
+ },
+ {}
+};
+
static const struct dmi_system_id adr_remap_quirk_table[] = {
/* TGL devices */
{
@@ -99,6 +116,14 @@ static const struct dmi_system_id adr_remap_quirk_table[] = {
.driver_data = (void *)intel_tgl_bios,
},
{
+ /* quirk used for NUC15 'Rooks County' LAPRC510 and LAPRC710 skews */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Intel(R) Client Systems"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "LAPRC"),
+ },
+ .driver_data = (void *)intel_rooks_county,
+ },
+ {
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A3E")
diff --git a/drivers/soundwire/generic_bandwidth_allocation.c b/drivers/soundwire/generic_bandwidth_allocation.c
index f7c66083a4dd..325c475b6a66 100644
--- a/drivers/soundwire/generic_bandwidth_allocation.c
+++ b/drivers/soundwire/generic_bandwidth_allocation.c
@@ -6,6 +6,7 @@
*
*/
+#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
@@ -28,15 +29,8 @@ struct sdw_group {
unsigned int *rates;
};
-struct sdw_transport_data {
- int hstart;
- int hstop;
- int block_offset;
- int sub_block_offset;
-};
-
-static void sdw_compute_slave_ports(struct sdw_master_runtime *m_rt,
- struct sdw_transport_data *t_data)
+void sdw_compute_slave_ports(struct sdw_master_runtime *m_rt,
+ struct sdw_transport_data *t_data)
{
struct sdw_slave_runtime *s_rt = NULL;
struct sdw_port_runtime *p_rt;
@@ -54,7 +48,7 @@ static void sdw_compute_slave_ports(struct sdw_master_runtime *m_rt,
slave_total_ch = 0;
list_for_each_entry(p_rt, &s_rt->port_list, port_node) {
- ch = sdw_ch_mask_to_ch(p_rt->ch_mask);
+ ch = hweight32(p_rt->ch_mask);
sdw_fill_xport_params(&p_rt->transport_params,
p_rt->num, false,
@@ -85,6 +79,7 @@ static void sdw_compute_slave_ports(struct sdw_master_runtime *m_rt,
}
}
}
+EXPORT_SYMBOL(sdw_compute_slave_ports);
static void sdw_compute_master_ports(struct sdw_master_runtime *m_rt,
struct sdw_group_params *params,
diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
index 2651767272c7..238acf5c97a9 100644
--- a/drivers/soundwire/intel.c
+++ b/drivers/soundwire/intel.c
@@ -19,38 +19,6 @@
#include "bus.h"
#include "intel.h"
-
-enum intel_pdi_type {
- INTEL_PDI_IN = 0,
- INTEL_PDI_OUT = 1,
- INTEL_PDI_BD = 2,
-};
-
-#define cdns_to_intel(_cdns) container_of(_cdns, struct sdw_intel, cdns)
-
-/*
- * Read, write helpers for HW registers
- */
-static inline int intel_readl(void __iomem *base, int offset)
-{
- return readl(base + offset);
-}
-
-static inline void intel_writel(void __iomem *base, int offset, int value)
-{
- writel(value, base + offset);
-}
-
-static inline u16 intel_readw(void __iomem *base, int offset)
-{
- return readw(base + offset);
-}
-
-static inline void intel_writew(void __iomem *base, int offset, u16 value)
-{
- writew(value, base + offset);
-}
-
static int intel_wait_bit(void __iomem *base, int offset, u32 mask, u32 target)
{
int timeout = 10;
@@ -357,6 +325,15 @@ static void intel_shim_wake(struct sdw_intel *sdw, bool wake_enable)
mutex_unlock(sdw->link_res->shim_lock);
}
+static bool intel_check_cmdsync_unlocked(struct sdw_intel *sdw)
+{
+ void __iomem *shim = sdw->link_res->shim;
+ int sync_reg;
+
+ sync_reg = intel_readl(shim, SDW_SHIM_SYNC);
+ return !!(sync_reg & SDW_SHIM_SYNC_CMDSYNC_MASK);
+}
+
static int intel_link_power_up(struct sdw_intel *sdw)
{
unsigned int link_id = sdw->instance;
@@ -507,7 +484,6 @@ static int intel_shim_sync_go_unlocked(struct sdw_intel *sdw)
{
void __iomem *shim = sdw->link_res->shim;
u32 sync_reg;
- int ret;
/* Read SYNC register */
sync_reg = intel_readl(shim, SDW_SHIM_SYNC);
@@ -519,13 +495,9 @@ static int intel_shim_sync_go_unlocked(struct sdw_intel *sdw)
*/
sync_reg |= SDW_SHIM_SYNC_SYNCGO;
- ret = intel_clear_bit(shim, SDW_SHIM_SYNC, sync_reg,
- SDW_SHIM_SYNC_SYNCGO);
-
- if (ret < 0)
- dev_err(sdw->cdns.dev, "SyncGO clear failed: %d\n", ret);
+ intel_writel(shim, SDW_SHIM_SYNC, sync_reg);
- return ret;
+ return 0;
}
static int intel_shim_sync_go(struct sdw_intel *sdw)
@@ -618,13 +590,6 @@ static int intel_pdi_stream_ch_update(struct sdw_intel *sdw,
return 0;
}
-static int intel_pdi_ch_update(struct sdw_intel *sdw)
-{
- intel_pdi_stream_ch_update(sdw, &sdw->cdns.pcm);
-
- return 0;
-}
-
static void
intel_pdi_shim_configure(struct sdw_intel *sdw, struct sdw_cdns_pdi *pdi)
{
@@ -718,63 +683,6 @@ static int intel_free_stream(struct sdw_intel *sdw,
}
/*
- * bank switch routines
- */
-
-static int intel_pre_bank_switch(struct sdw_intel *sdw)
-{
- struct sdw_cdns *cdns = &sdw->cdns;
- struct sdw_bus *bus = &cdns->bus;
-
- /* Write to register only for multi-link */
- if (!bus->multi_link)
- return 0;
-
- intel_shim_sync_arm(sdw);
-
- return 0;
-}
-
-static int intel_post_bank_switch(struct sdw_intel *sdw)
-{
- struct sdw_cdns *cdns = &sdw->cdns;
- struct sdw_bus *bus = &cdns->bus;
- void __iomem *shim = sdw->link_res->shim;
- int sync_reg, ret;
-
- /* Write to register only for multi-link */
- if (!bus->multi_link)
- return 0;
-
- mutex_lock(sdw->link_res->shim_lock);
-
- /* Read SYNC register */
- sync_reg = intel_readl(shim, SDW_SHIM_SYNC);
-
- /*
- * post_bank_switch() ops is called from the bus in loop for
- * all the Masters in the steam with the expectation that
- * we trigger the bankswitch for the only first Master in the list
- * and do nothing for the other Masters
- *
- * So, set the SYNCGO bit only if CMDSYNC bit is set for any Master.
- */
- if (!(sync_reg & SDW_SHIM_SYNC_CMDSYNC_MASK)) {
- ret = 0;
- goto unlock;
- }
-
- ret = intel_shim_sync_go_unlocked(sdw);
-unlock:
- mutex_unlock(sdw->link_res->shim_lock);
-
- if (ret < 0)
- dev_err(sdw->cdns.dev, "Post bank switch failed: %d\n", ret);
-
- return ret;
-}
-
-/*
* DAI routines
*/
@@ -817,7 +725,6 @@ static int intel_hw_params(struct snd_pcm_substream *substream,
dai_runtime->paused = false;
dai_runtime->suspended = false;
dai_runtime->pdi = pdi;
- dai_runtime->hw_params = params;
/* Inform DSP about PDI stream number */
ret = intel_params_stream(sdw, substream->stream, dai, params,
@@ -870,6 +777,11 @@ static int intel_prepare(struct snd_pcm_substream *substream,
}
if (dai_runtime->suspended) {
+ struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
+ struct snd_pcm_hw_params *hw_params;
+
+ hw_params = &rtd->dpcm[substream->stream].hw_params;
+
dai_runtime->suspended = false;
/*
@@ -881,7 +793,7 @@ static int intel_prepare(struct snd_pcm_substream *substream,
*/
/* configure stream */
- ch = params_channels(dai_runtime->hw_params);
+ ch = params_channels(hw_params);
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
dir = SDW_DATA_DIR_RX;
else
@@ -893,7 +805,7 @@ static int intel_prepare(struct snd_pcm_substream *substream,
/* Inform DSP about PDI stream number */
ret = intel_params_stream(sdw, substream->stream, dai,
- dai_runtime->hw_params,
+ hw_params,
sdw->instance,
dai_runtime->pdi->intel_alh_id);
}
@@ -932,7 +844,6 @@ intel_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
return ret;
}
- dai_runtime->hw_params = NULL;
dai_runtime->pdi = NULL;
return 0;
@@ -1088,7 +999,6 @@ static int intel_create_dai(struct sdw_cdns *cdns,
if (num == 0)
return 0;
- /* TODO: Read supported rates/formats from hardware */
for (i = off; i < (off + num); i++) {
dais[i].name = devm_kasprintf(cdns->dev, GFP_KERNEL,
"SDW%d Pin%d",
@@ -1099,15 +1009,11 @@ static int intel_create_dai(struct sdw_cdns *cdns,
if (type == INTEL_PDI_BD || type == INTEL_PDI_OUT) {
dais[i].playback.channels_min = 1;
dais[i].playback.channels_max = max_ch;
- dais[i].playback.rates = SNDRV_PCM_RATE_48000;
- dais[i].playback.formats = SNDRV_PCM_FMTBIT_S16_LE;
}
if (type == INTEL_PDI_BD || type == INTEL_PDI_IN) {
dais[i].capture.channels_min = 1;
dais[i].capture.channels_max = max_ch;
- dais[i].capture.rates = SNDRV_PCM_RATE_48000;
- dais[i].capture.formats = SNDRV_PCM_FMTBIT_S16_LE;
}
dais[i].ops = &intel_pcm_dai_ops;
@@ -1131,7 +1037,7 @@ static int intel_register_dai(struct sdw_intel *sdw)
if (ret)
return ret;
- intel_pdi_ch_update(sdw);
+ intel_pdi_stream_ch_update(sdw, &sdw->cdns.pcm);
/* DAIs are created based on total number of PDIs supported */
num_dai = cdns->pcm.num_pdi;
@@ -1171,205 +1077,6 @@ static int intel_register_dai(struct sdw_intel *sdw)
dais, num_dai);
}
-static int intel_start_bus(struct sdw_intel *sdw)
-{
- struct device *dev = sdw->cdns.dev;
- struct sdw_cdns *cdns = &sdw->cdns;
- struct sdw_bus *bus = &cdns->bus;
- int ret;
-
- ret = sdw_cdns_enable_interrupt(cdns, true);
- if (ret < 0) {
- dev_err(dev, "%s: cannot enable interrupts: %d\n", __func__, ret);
- return ret;
- }
-
- /*
- * follow recommended programming flows to avoid timeouts when
- * gsync is enabled
- */
- if (bus->multi_link)
- intel_shim_sync_arm(sdw);
-
- ret = sdw_cdns_init(cdns);
- if (ret < 0) {
- dev_err(dev, "%s: unable to initialize Cadence IP: %d\n", __func__, ret);
- goto err_interrupt;
- }
-
- ret = sdw_cdns_exit_reset(cdns);
- if (ret < 0) {
- dev_err(dev, "%s: unable to exit bus reset sequence: %d\n", __func__, ret);
- goto err_interrupt;
- }
-
- if (bus->multi_link) {
- ret = intel_shim_sync_go(sdw);
- if (ret < 0) {
- dev_err(dev, "%s: sync go failed: %d\n", __func__, ret);
- goto err_interrupt;
- }
- }
- sdw_cdns_check_self_clearing_bits(cdns, __func__,
- true, INTEL_MASTER_RESET_ITERATIONS);
-
- return 0;
-
-err_interrupt:
- sdw_cdns_enable_interrupt(cdns, false);
- return ret;
-}
-
-static int intel_start_bus_after_reset(struct sdw_intel *sdw)
-{
- struct device *dev = sdw->cdns.dev;
- struct sdw_cdns *cdns = &sdw->cdns;
- struct sdw_bus *bus = &cdns->bus;
- bool clock_stop0;
- int status;
- int ret;
-
- /*
- * An exception condition occurs for the CLK_STOP_BUS_RESET
- * case if one or more masters remain active. In this condition,
- * all the masters are powered on for they are in the same power
- * domain. Master can preserve its context for clock stop0, so
- * there is no need to clear slave status and reset bus.
- */
- clock_stop0 = sdw_cdns_is_clock_stop(&sdw->cdns);
-
- if (!clock_stop0) {
-
- /*
- * make sure all Slaves are tagged as UNATTACHED and
- * provide reason for reinitialization
- */
-
- status = SDW_UNATTACH_REQUEST_MASTER_RESET;
- sdw_clear_slave_status(bus, status);
-
- ret = sdw_cdns_enable_interrupt(cdns, true);
- if (ret < 0) {
- dev_err(dev, "cannot enable interrupts during resume\n");
- return ret;
- }
-
- /*
- * follow recommended programming flows to avoid
- * timeouts when gsync is enabled
- */
- if (bus->multi_link)
- intel_shim_sync_arm(sdw);
-
- /*
- * Re-initialize the IP since it was powered-off
- */
- sdw_cdns_init(&sdw->cdns);
-
- } else {
- ret = sdw_cdns_enable_interrupt(cdns, true);
- if (ret < 0) {
- dev_err(dev, "cannot enable interrupts during resume\n");
- return ret;
- }
- }
-
- ret = sdw_cdns_clock_restart(cdns, !clock_stop0);
- if (ret < 0) {
- dev_err(dev, "unable to restart clock during resume\n");
- goto err_interrupt;
- }
-
- if (!clock_stop0) {
- ret = sdw_cdns_exit_reset(cdns);
- if (ret < 0) {
- dev_err(dev, "unable to exit bus reset sequence during resume\n");
- goto err_interrupt;
- }
-
- if (bus->multi_link) {
- ret = intel_shim_sync_go(sdw);
- if (ret < 0) {
- dev_err(sdw->cdns.dev, "sync go failed during resume\n");
- goto err_interrupt;
- }
- }
- }
- sdw_cdns_check_self_clearing_bits(cdns, __func__, true, INTEL_MASTER_RESET_ITERATIONS);
-
- return 0;
-
-err_interrupt:
- sdw_cdns_enable_interrupt(cdns, false);
- return ret;
-}
-
-static void intel_check_clock_stop(struct sdw_intel *sdw)
-{
- struct device *dev = sdw->cdns.dev;
- bool clock_stop0;
-
- clock_stop0 = sdw_cdns_is_clock_stop(&sdw->cdns);
- if (!clock_stop0)
- dev_err(dev, "%s: invalid configuration, clock was not stopped\n", __func__);
-}
-
-static int intel_start_bus_after_clock_stop(struct sdw_intel *sdw)
-{
- struct device *dev = sdw->cdns.dev;
- struct sdw_cdns *cdns = &sdw->cdns;
- int ret;
-
- ret = sdw_cdns_enable_interrupt(cdns, true);
- if (ret < 0) {
- dev_err(dev, "%s: cannot enable interrupts: %d\n", __func__, ret);
- return ret;
- }
-
- ret = sdw_cdns_clock_restart(cdns, false);
- if (ret < 0) {
- dev_err(dev, "%s: unable to restart clock: %d\n", __func__, ret);
- sdw_cdns_enable_interrupt(cdns, false);
- return ret;
- }
-
- sdw_cdns_check_self_clearing_bits(cdns, "intel_resume_runtime no_quirks",
- true, INTEL_MASTER_RESET_ITERATIONS);
-
- return 0;
-}
-
-static int intel_stop_bus(struct sdw_intel *sdw, bool clock_stop)
-{
- struct device *dev = sdw->cdns.dev;
- struct sdw_cdns *cdns = &sdw->cdns;
- bool wake_enable = false;
- int ret;
-
- if (clock_stop) {
- ret = sdw_cdns_clock_stop(cdns, true);
- if (ret < 0)
- dev_err(dev, "%s: cannot stop clock: %d\n", __func__, ret);
- else
- wake_enable = true;
- }
-
- ret = sdw_cdns_enable_interrupt(cdns, false);
- if (ret < 0) {
- dev_err(dev, "%s: cannot disable interrupts: %d\n", __func__, ret);
- return ret;
- }
-
- ret = intel_link_power_down(sdw);
- if (ret) {
- dev_err(dev, "%s: Link power down failed: %d\n", __func__, ret);
- return ret;
- }
-
- intel_shim_wake(sdw, wake_enable);
-
- return 0;
-}
const struct sdw_intel_hw_ops sdw_intel_cnl_hw_ops = {
.debugfs_init = intel_debugfs_init,
@@ -1391,6 +1098,11 @@ const struct sdw_intel_hw_ops sdw_intel_cnl_hw_ops = {
.pre_bank_switch = intel_pre_bank_switch,
.post_bank_switch = intel_post_bank_switch,
+
+ .sync_arm = intel_shim_sync_arm,
+ .sync_go_unlocked = intel_shim_sync_go_unlocked,
+ .sync_go = intel_shim_sync_go,
+ .sync_check_cmdsync_unlocked = intel_check_cmdsync_unlocked,
};
EXPORT_SYMBOL_NS(sdw_intel_cnl_hw_ops, SOUNDWIRE_INTEL);
diff --git a/drivers/soundwire/intel.h b/drivers/soundwire/intel.h
index de9883313c8f..09d479f2c77b 100644
--- a/drivers/soundwire/intel.h
+++ b/drivers/soundwire/intel.h
@@ -50,6 +50,35 @@ struct sdw_intel {
#endif
};
+enum intel_pdi_type {
+ INTEL_PDI_IN = 0,
+ INTEL_PDI_OUT = 1,
+ INTEL_PDI_BD = 2,
+};
+
+/*
+ * Read, write helpers for HW registers
+ */
+static inline int intel_readl(void __iomem *base, int offset)
+{
+ return readl(base + offset);
+}
+
+static inline void intel_writel(void __iomem *base, int offset, int value)
+{
+ writel(value, base + offset);
+}
+
+static inline u16 intel_readw(void __iomem *base, int offset)
+{
+ return readw(base + offset);
+}
+
+static inline void intel_writew(void __iomem *base, int offset, u16 value)
+{
+ writew(value, base + offset);
+}
+
#define cdns_to_intel(_cdns) container_of(_cdns, struct sdw_intel, cdns)
#define INTEL_MASTER_RESET_ITERATIONS 10
@@ -138,4 +167,42 @@ static inline void sdw_intel_shim_wake(struct sdw_intel *sdw, bool wake_enable)
SDW_INTEL_OPS(sdw, shim_wake)(sdw, wake_enable);
}
+static inline void sdw_intel_sync_arm(struct sdw_intel *sdw)
+{
+ if (SDW_INTEL_CHECK_OPS(sdw, sync_arm))
+ SDW_INTEL_OPS(sdw, sync_arm)(sdw);
+}
+
+static inline int sdw_intel_sync_go_unlocked(struct sdw_intel *sdw)
+{
+ if (SDW_INTEL_CHECK_OPS(sdw, sync_go_unlocked))
+ return SDW_INTEL_OPS(sdw, sync_go_unlocked)(sdw);
+ return -ENOTSUPP;
+}
+
+static inline int sdw_intel_sync_go(struct sdw_intel *sdw)
+{
+ if (SDW_INTEL_CHECK_OPS(sdw, sync_go))
+ return SDW_INTEL_OPS(sdw, sync_go)(sdw);
+ return -ENOTSUPP;
+}
+
+static inline bool sdw_intel_sync_check_cmdsync_unlocked(struct sdw_intel *sdw)
+{
+ if (SDW_INTEL_CHECK_OPS(sdw, sync_check_cmdsync_unlocked))
+ return SDW_INTEL_OPS(sdw, sync_check_cmdsync_unlocked)(sdw);
+ return false;
+}
+
+/* common bus management */
+int intel_start_bus(struct sdw_intel *sdw);
+int intel_start_bus_after_reset(struct sdw_intel *sdw);
+void intel_check_clock_stop(struct sdw_intel *sdw);
+int intel_start_bus_after_clock_stop(struct sdw_intel *sdw);
+int intel_stop_bus(struct sdw_intel *sdw, bool clock_stop);
+
+/* common bank switch routines */
+int intel_pre_bank_switch(struct sdw_intel *sdw);
+int intel_post_bank_switch(struct sdw_intel *sdw);
+
#endif /* __SDW_INTEL_LOCAL_H */
diff --git a/drivers/soundwire/intel_auxdevice.c b/drivers/soundwire/intel_auxdevice.c
index 5021be0f4158..b21e86084f7b 100644
--- a/drivers/soundwire/intel_auxdevice.c
+++ b/drivers/soundwire/intel_auxdevice.c
@@ -358,10 +358,12 @@ static int intel_resume_child_device(struct device *dev, void *data)
}
ret = pm_request_resume(dev);
- if (ret < 0)
+ if (ret < 0) {
dev_err(dev, "%s: pm_request_resume failed: %d\n", __func__, ret);
+ return ret;
+ }
- return ret;
+ return 0;
}
static int __maybe_unused intel_pm_prepare(struct device *dev)
diff --git a/drivers/soundwire/intel_bus_common.c b/drivers/soundwire/intel_bus_common.c
new file mode 100644
index 000000000000..f180e3bea989
--- /dev/null
+++ b/drivers/soundwire/intel_bus_common.c
@@ -0,0 +1,259 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+// Copyright(c) 2015-2023 Intel Corporation. All rights reserved.
+
+#include <linux/acpi.h>
+#include <linux/soundwire/sdw_registers.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_intel.h>
+#include "cadence_master.h"
+#include "bus.h"
+#include "intel.h"
+
+int intel_start_bus(struct sdw_intel *sdw)
+{
+ struct device *dev = sdw->cdns.dev;
+ struct sdw_cdns *cdns = &sdw->cdns;
+ struct sdw_bus *bus = &cdns->bus;
+ int ret;
+
+ ret = sdw_cdns_enable_interrupt(cdns, true);
+ if (ret < 0) {
+ dev_err(dev, "%s: cannot enable interrupts: %d\n", __func__, ret);
+ return ret;
+ }
+
+ /*
+ * follow recommended programming flows to avoid timeouts when
+ * gsync is enabled
+ */
+ if (bus->multi_link)
+ sdw_intel_sync_arm(sdw);
+
+ ret = sdw_cdns_init(cdns);
+ if (ret < 0) {
+ dev_err(dev, "%s: unable to initialize Cadence IP: %d\n", __func__, ret);
+ goto err_interrupt;
+ }
+
+ ret = sdw_cdns_exit_reset(cdns);
+ if (ret < 0) {
+ dev_err(dev, "%s: unable to exit bus reset sequence: %d\n", __func__, ret);
+ goto err_interrupt;
+ }
+
+ if (bus->multi_link) {
+ ret = sdw_intel_sync_go(sdw);
+ if (ret < 0) {
+ dev_err(dev, "%s: sync go failed: %d\n", __func__, ret);
+ goto err_interrupt;
+ }
+ }
+ sdw_cdns_check_self_clearing_bits(cdns, __func__,
+ true, INTEL_MASTER_RESET_ITERATIONS);
+
+ return 0;
+
+err_interrupt:
+ sdw_cdns_enable_interrupt(cdns, false);
+ return ret;
+}
+
+int intel_start_bus_after_reset(struct sdw_intel *sdw)
+{
+ struct device *dev = sdw->cdns.dev;
+ struct sdw_cdns *cdns = &sdw->cdns;
+ struct sdw_bus *bus = &cdns->bus;
+ bool clock_stop0;
+ int status;
+ int ret;
+
+ /*
+ * An exception condition occurs for the CLK_STOP_BUS_RESET
+ * case if one or more masters remain active. In this condition,
+ * all the masters are powered on for they are in the same power
+ * domain. Master can preserve its context for clock stop0, so
+ * there is no need to clear slave status and reset bus.
+ */
+ clock_stop0 = sdw_cdns_is_clock_stop(&sdw->cdns);
+
+ if (!clock_stop0) {
+
+ /*
+ * make sure all Slaves are tagged as UNATTACHED and
+ * provide reason for reinitialization
+ */
+
+ status = SDW_UNATTACH_REQUEST_MASTER_RESET;
+ sdw_clear_slave_status(bus, status);
+
+ ret = sdw_cdns_enable_interrupt(cdns, true);
+ if (ret < 0) {
+ dev_err(dev, "cannot enable interrupts during resume\n");
+ return ret;
+ }
+
+ /*
+ * follow recommended programming flows to avoid
+ * timeouts when gsync is enabled
+ */
+ if (bus->multi_link)
+ sdw_intel_sync_arm(sdw);
+
+ /*
+ * Re-initialize the IP since it was powered-off
+ */
+ sdw_cdns_init(&sdw->cdns);
+
+ } else {
+ ret = sdw_cdns_enable_interrupt(cdns, true);
+ if (ret < 0) {
+ dev_err(dev, "cannot enable interrupts during resume\n");
+ return ret;
+ }
+ }
+
+ ret = sdw_cdns_clock_restart(cdns, !clock_stop0);
+ if (ret < 0) {
+ dev_err(dev, "unable to restart clock during resume\n");
+ goto err_interrupt;
+ }
+
+ if (!clock_stop0) {
+ ret = sdw_cdns_exit_reset(cdns);
+ if (ret < 0) {
+ dev_err(dev, "unable to exit bus reset sequence during resume\n");
+ goto err_interrupt;
+ }
+
+ if (bus->multi_link) {
+ ret = sdw_intel_sync_go(sdw);
+ if (ret < 0) {
+ dev_err(sdw->cdns.dev, "sync go failed during resume\n");
+ goto err_interrupt;
+ }
+ }
+ }
+ sdw_cdns_check_self_clearing_bits(cdns, __func__, true, INTEL_MASTER_RESET_ITERATIONS);
+
+ return 0;
+
+err_interrupt:
+ sdw_cdns_enable_interrupt(cdns, false);
+ return ret;
+}
+
+void intel_check_clock_stop(struct sdw_intel *sdw)
+{
+ struct device *dev = sdw->cdns.dev;
+ bool clock_stop0;
+
+ clock_stop0 = sdw_cdns_is_clock_stop(&sdw->cdns);
+ if (!clock_stop0)
+ dev_err(dev, "%s: invalid configuration, clock was not stopped\n", __func__);
+}
+
+int intel_start_bus_after_clock_stop(struct sdw_intel *sdw)
+{
+ struct device *dev = sdw->cdns.dev;
+ struct sdw_cdns *cdns = &sdw->cdns;
+ int ret;
+
+ ret = sdw_cdns_enable_interrupt(cdns, true);
+ if (ret < 0) {
+ dev_err(dev, "%s: cannot enable interrupts: %d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = sdw_cdns_clock_restart(cdns, false);
+ if (ret < 0) {
+ dev_err(dev, "%s: unable to restart clock: %d\n", __func__, ret);
+ sdw_cdns_enable_interrupt(cdns, false);
+ return ret;
+ }
+
+ sdw_cdns_check_self_clearing_bits(cdns, "intel_resume_runtime no_quirks",
+ true, INTEL_MASTER_RESET_ITERATIONS);
+
+ return 0;
+}
+
+int intel_stop_bus(struct sdw_intel *sdw, bool clock_stop)
+{
+ struct device *dev = sdw->cdns.dev;
+ struct sdw_cdns *cdns = &sdw->cdns;
+ bool wake_enable = false;
+ int ret;
+
+ if (clock_stop) {
+ ret = sdw_cdns_clock_stop(cdns, true);
+ if (ret < 0)
+ dev_err(dev, "%s: cannot stop clock: %d\n", __func__, ret);
+ else
+ wake_enable = true;
+ }
+
+ ret = sdw_cdns_enable_interrupt(cdns, false);
+ if (ret < 0) {
+ dev_err(dev, "%s: cannot disable interrupts: %d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = sdw_intel_link_power_down(sdw);
+ if (ret) {
+ dev_err(dev, "%s: Link power down failed: %d\n", __func__, ret);
+ return ret;
+ }
+
+ sdw_intel_shim_wake(sdw, wake_enable);
+
+ return 0;
+}
+
+/*
+ * bank switch routines
+ */
+
+int intel_pre_bank_switch(struct sdw_intel *sdw)
+{
+ struct sdw_cdns *cdns = &sdw->cdns;
+ struct sdw_bus *bus = &cdns->bus;
+
+ /* Write to register only for multi-link */
+ if (!bus->multi_link)
+ return 0;
+
+ sdw_intel_sync_arm(sdw);
+
+ return 0;
+}
+
+int intel_post_bank_switch(struct sdw_intel *sdw)
+{
+ struct sdw_cdns *cdns = &sdw->cdns;
+ struct sdw_bus *bus = &cdns->bus;
+ int ret = 0;
+
+ /* Write to register only for multi-link */
+ if (!bus->multi_link)
+ return 0;
+
+ mutex_lock(sdw->link_res->shim_lock);
+
+ /*
+ * post_bank_switch() ops is called from the bus in loop for
+ * all the Masters in the steam with the expectation that
+ * we trigger the bankswitch for the only first Master in the list
+ * and do nothing for the other Masters
+ *
+ * So, set the SYNCGO bit only if CMDSYNC bit is set for any Master.
+ */
+ if (sdw_intel_sync_check_cmdsync_unlocked(sdw))
+ ret = sdw_intel_sync_go_unlocked(sdw);
+
+ mutex_unlock(sdw->link_res->shim_lock);
+
+ if (ret < 0)
+ dev_err(sdw->cdns.dev, "Post bank switch failed: %d\n", ret);
+
+ return ret;
+}
diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c
index 335424870290..c296e0bf897b 100644
--- a/drivers/soundwire/qcom.c
+++ b/drivers/soundwire/qcom.c
@@ -28,6 +28,9 @@
#define SWRM_LINK_MANAGER_EE 0x018
#define SWRM_EE_CPU 1
#define SWRM_FRM_GEN_ENABLED BIT(0)
+#define SWRM_VERSION_1_3_0 0x01030000
+#define SWRM_VERSION_1_5_1 0x01050001
+#define SWRM_VERSION_1_7_0 0x01070000
#define SWRM_COMP_HW_VERSION 0x00
#define SWRM_COMP_CFG_ADDR 0x04
#define SWRM_COMP_CFG_IRQ_LEVEL_OR_PULSE_MSK BIT(1)
@@ -351,8 +354,7 @@ static int qcom_swrm_cmd_fifo_wr_cmd(struct qcom_swrm_ctrl *swrm, u8 cmd_data,
/* Its assumed that write is okay as we do not get any status back */
swrm->reg_write(swrm, SWRM_CMD_FIFO_WR_CMD, val);
- /* version 1.3 or less */
- if (swrm->version <= 0x01030000)
+ if (swrm->version <= SWRM_VERSION_1_3_0)
usleep_range(150, 155);
if (cmd_id == SWR_BROADCAST_CMD_ID) {
@@ -695,7 +697,7 @@ static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl)
u32p_replace_bits(&val, SWRM_DEF_CMD_NO_PINGS, SWRM_MCP_CFG_MAX_NUM_OF_CMD_NO_PINGS_BMSK);
ctrl->reg_write(ctrl, SWRM_MCP_CFG_ADDR, val);
- if (ctrl->version >= 0x01070000) {
+ if (ctrl->version >= SWRM_VERSION_1_7_0) {
ctrl->reg_write(ctrl, SWRM_LINK_MANAGER_EE, SWRM_EE_CPU);
ctrl->reg_write(ctrl, SWRM_MCP_BUS_CTRL,
SWRM_MCP_BUS_CLK_START << SWRM_EE_CPU);
@@ -704,8 +706,7 @@ static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl)
}
/* Configure number of retries of a read/write cmd */
- if (ctrl->version > 0x01050001) {
- /* Only for versions >= 1.5.1 */
+ if (ctrl->version >= SWRM_VERSION_1_5_1) {
ctrl->reg_write(ctrl, SWRM_CMD_FIFO_CFG_ADDR,
SWRM_RD_WR_CMD_RETRIES |
SWRM_CONTINUE_EXEC_ON_CMD_IGNORE);
@@ -1217,6 +1218,9 @@ static int qcom_swrm_get_port_config(struct qcom_swrm_ctrl *ctrl)
ctrl->num_dout_ports = val;
nports = ctrl->num_dout_ports + ctrl->num_din_ports;
+ if (nports > QCOM_SDW_MAX_PORTS)
+ return -EINVAL;
+
/* Valid port numbers are from 1-14, so mask out port 0 explicitly */
set_bit(0, &ctrl->dout_port_mask);
set_bit(0, &ctrl->din_port_mask);
@@ -1239,7 +1243,7 @@ static int qcom_swrm_get_port_config(struct qcom_swrm_ctrl *ctrl)
ret = of_property_read_u8_array(np, "qcom,ports-block-pack-mode",
bp_mode, nports);
if (ret) {
- if (ctrl->version <= 0x01030000)
+ if (ctrl->version <= SWRM_VERSION_1_3_0)
memset(bp_mode, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS);
else
return ret;
@@ -1442,7 +1446,7 @@ static int qcom_swrm_probe(struct platform_device *pdev)
pm_runtime_enable(dev);
/* Clk stop is not supported on WSA Soundwire masters */
- if (ctrl->version <= 0x01030000) {
+ if (ctrl->version <= SWRM_VERSION_1_3_0) {
ctrl->clock_stop_not_supported = true;
} else {
ctrl->reg_read(ctrl, SWRM_COMP_MASTER_ID, &val);
@@ -1527,7 +1531,7 @@ static int __maybe_unused swrm_runtime_resume(struct device *dev)
} else {
reset_control_reset(ctrl->audio_cgcr);
- if (ctrl->version >= 0x01070000) {
+ if (ctrl->version >= SWRM_VERSION_1_7_0) {
ctrl->reg_write(ctrl, SWRM_LINK_MANAGER_EE, SWRM_EE_CPU);
ctrl->reg_write(ctrl, SWRM_MCP_BUS_CTRL,
SWRM_MCP_BUS_CLK_START << SWRM_EE_CPU);
diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c
index 8c6da1739e3d..c2191c07442b 100644
--- a/drivers/soundwire/stream.c
+++ b/drivers/soundwire/stream.c
@@ -1369,7 +1369,7 @@ static int _sdw_prepare_stream(struct sdw_stream_runtime *stream,
if (ret < 0) {
dev_err(bus->dev, "Compute params failed: %d\n",
ret);
- return ret;
+ goto restore_params;
}
}
@@ -1389,7 +1389,7 @@ program_params:
ret = do_bank_switch(stream);
if (ret < 0) {
- dev_err(bus->dev, "Bank switch failed: %d\n", ret);
+ pr_err("%s: do_bank_switch failed: %d\n", __func__, ret);
goto restore_params;
}
@@ -1477,7 +1477,7 @@ static int _sdw_enable_stream(struct sdw_stream_runtime *stream)
/* Program params */
ret = sdw_program_params(bus, false);
if (ret < 0) {
- dev_err(bus->dev, "Program params failed: %d\n", ret);
+ dev_err(bus->dev, "%s: Program params failed: %d\n", __func__, ret);
return ret;
}
@@ -1497,7 +1497,7 @@ static int _sdw_enable_stream(struct sdw_stream_runtime *stream)
ret = do_bank_switch(stream);
if (ret < 0) {
- dev_err(bus->dev, "Bank switch failed: %d\n", ret);
+ pr_err("%s: do_bank_switch failed: %d\n", __func__, ret);
return ret;
}
@@ -1567,14 +1567,14 @@ static int _sdw_disable_stream(struct sdw_stream_runtime *stream)
/* Program params */
ret = sdw_program_params(bus, false);
if (ret < 0) {
- dev_err(bus->dev, "Program params failed: %d\n", ret);
+ dev_err(bus->dev, "%s: Program params failed: %d\n", __func__, ret);
return ret;
}
}
ret = do_bank_switch(stream);
if (ret < 0) {
- pr_err("Bank switch failed: %d\n", ret);
+ pr_err("%s: do_bank_switch failed: %d\n", __func__, ret);
return ret;
}
@@ -1664,7 +1664,7 @@ static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream)
/* Program params */
ret = sdw_program_params(bus, false);
if (ret < 0) {
- dev_err(bus->dev, "Program params failed: %d\n", ret);
+ dev_err(bus->dev, "%s: Program params failed: %d\n", __func__, ret);
return ret;
}
}
@@ -1893,7 +1893,8 @@ int sdw_stream_add_master(struct sdw_bus *bus,
m_rt = sdw_master_rt_alloc(bus, stream);
if (!m_rt) {
- dev_err(bus->dev, "Master runtime alloc failed for stream:%s\n", stream->name);
+ dev_err(bus->dev, "%s: Master runtime alloc failed for stream:%s\n",
+ __func__, stream->name);
ret = -ENOMEM;
goto unlock;
}
@@ -2012,7 +2013,8 @@ int sdw_stream_add_slave(struct sdw_slave *slave,
*/
m_rt = sdw_master_rt_alloc(slave->bus, stream);
if (!m_rt) {
- dev_err(&slave->dev, "Master runtime alloc failed for stream:%s\n", stream->name);
+ dev_err(&slave->dev, "%s: Master runtime alloc failed for stream:%s\n",
+ __func__, stream->name);
ret = -ENOMEM;
goto unlock;
}
diff --git a/drivers/thermal/cpuidle_cooling.c b/drivers/thermal/cpuidle_cooling.c
index 6f6daead485e..69f4c0a8dfcc 100644
--- a/drivers/thermal/cpuidle_cooling.c
+++ b/drivers/thermal/cpuidle_cooling.c
@@ -237,9 +237,6 @@ out:
*
* This function is in charge of creating a cooling device per cpuidle
* driver and register it to the thermal framework.
- *
- * Return: zero on success, or negative value corresponding to the
- * error detected in the underlying subsystems.
*/
void cpuidle_cooling_register(struct cpuidle_driver *drv)
{
diff --git a/drivers/thermal/gov_step_wise.c b/drivers/thermal/gov_step_wise.c
index 3d3067804df2..1050fb4d94c2 100644
--- a/drivers/thermal/gov_step_wise.c
+++ b/drivers/thermal/gov_step_wise.c
@@ -21,19 +21,11 @@
* a. if the trend is THERMAL_TREND_RAISING, use higher cooling
* state for this trip point
* b. if the trend is THERMAL_TREND_DROPPING, do nothing
- * c. if the trend is THERMAL_TREND_RAISE_FULL, use upper limit
- * for this trip point
- * d. if the trend is THERMAL_TREND_DROP_FULL, use lower limit
- * for this trip point
* If the temperature is lower than a trip point,
* a. if the trend is THERMAL_TREND_RAISING, do nothing
* b. if the trend is THERMAL_TREND_DROPPING, use lower cooling
* state for this trip point, if the cooling state already
* equals lower limit, deactivate the thermal instance
- * c. if the trend is THERMAL_TREND_RAISE_FULL, do nothing
- * d. if the trend is THERMAL_TREND_DROP_FULL, use lower limit,
- * if the cooling state already equals lower limit,
- * deactivate the thermal instance
*/
static unsigned long get_target_state(struct thermal_instance *instance,
enum thermal_trend trend, bool throttle)
@@ -61,24 +53,16 @@ static unsigned long get_target_state(struct thermal_instance *instance,
return next_target;
}
- switch (trend) {
- case THERMAL_TREND_RAISING:
- if (throttle) {
+ if (throttle) {
+ if (trend == THERMAL_TREND_RAISING)
next_target = clamp((cur_state + 1), instance->lower, instance->upper);
- }
- break;
- case THERMAL_TREND_DROPPING:
- if (cur_state <= instance->lower) {
- if (!throttle)
+ } else {
+ if (trend == THERMAL_TREND_DROPPING) {
+ if (cur_state <= instance->lower)
next_target = THERMAL_NO_TARGET;
- } else {
- if (!throttle) {
+ else
next_target = clamp((cur_state - 1), instance->lower, instance->upper);
- }
}
- break;
- default:
- break;
}
return next_target;
diff --git a/drivers/thermal/intel/Kconfig b/drivers/thermal/intel/Kconfig
index cb7e7697cf1e..ecd7e07eece0 100644
--- a/drivers/thermal/intel/Kconfig
+++ b/drivers/thermal/intel/Kconfig
@@ -103,15 +103,6 @@ config INTEL_TCC_COOLING
on how fast the setting takes effect, and how much the CPU frequency
is reduced.
-config INTEL_MENLOW
- tristate "Thermal Management driver for Intel menlow platform"
- depends on ACPI_THERMAL
- help
- ACPI thermal management enhancement driver on
- Intel Menlow platform.
-
- If unsure, say N.
-
config INTEL_HFI_THERMAL
bool "Intel Hardware Feedback Interface"
depends on NET
diff --git a/drivers/thermal/intel/Makefile b/drivers/thermal/intel/Makefile
index 5d8833c82ab6..182b3411300a 100644
--- a/drivers/thermal/intel/Makefile
+++ b/drivers/thermal/intel/Makefile
@@ -13,5 +13,4 @@ obj-$(CONFIG_INTEL_BXT_PMIC_THERMAL) += intel_bxt_pmic_thermal.o
obj-$(CONFIG_INTEL_PCH_THERMAL) += intel_pch_thermal.o
obj-$(CONFIG_INTEL_TCC_COOLING) += intel_tcc_cooling.o
obj-$(CONFIG_X86_THERMAL_VECTOR) += therm_throt.o
-obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o
obj-$(CONFIG_INTEL_HFI_THERMAL) += intel_hfi.o
diff --git a/drivers/thermal/intel/intel_menlow.c b/drivers/thermal/intel/intel_menlow.c
deleted file mode 100644
index 5a6ad0552311..000000000000
--- a/drivers/thermal/intel/intel_menlow.c
+++ /dev/null
@@ -1,521 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Intel menlow Driver for thermal management extension
- *
- * Copyright (C) 2008 Intel Corp
- * Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
- * Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
- *
- * This driver creates the sys I/F for programming the sensors.
- * It also implements the driver for intel menlow memory controller (hardware
- * id is INT0002) which makes use of the platform specific ACPI methods
- * to get/set bandwidth.
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/acpi.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/pm.h>
-#include <linux/slab.h>
-#include <linux/thermal.h>
-#include <linux/types.h>
-#include <linux/units.h>
-
-MODULE_AUTHOR("Thomas Sujith");
-MODULE_AUTHOR("Zhang Rui");
-MODULE_DESCRIPTION("Intel Menlow platform specific driver");
-MODULE_LICENSE("GPL v2");
-
-/*
- * Memory controller device control
- */
-
-#define MEMORY_GET_BANDWIDTH "GTHS"
-#define MEMORY_SET_BANDWIDTH "STHS"
-#define MEMORY_ARG_CUR_BANDWIDTH 1
-#define MEMORY_ARG_MAX_BANDWIDTH 0
-
-static void intel_menlow_unregister_sensor(void);
-
-/*
- * GTHS returning 'n' would mean that [0,n-1] states are supported
- * In that case max_cstate would be n-1
- * GTHS returning '0' would mean that no bandwidth control states are supported
- */
-static int memory_get_max_bandwidth(struct thermal_cooling_device *cdev,
- unsigned long *max_state)
-{
- struct acpi_device *device = cdev->devdata;
- acpi_handle handle = device->handle;
- unsigned long long value;
- struct acpi_object_list arg_list;
- union acpi_object arg;
- acpi_status status = AE_OK;
-
- arg_list.count = 1;
- arg_list.pointer = &arg;
- arg.type = ACPI_TYPE_INTEGER;
- arg.integer.value = MEMORY_ARG_MAX_BANDWIDTH;
- status = acpi_evaluate_integer(handle, MEMORY_GET_BANDWIDTH,
- &arg_list, &value);
- if (ACPI_FAILURE(status))
- return -EFAULT;
-
- if (!value)
- return -EINVAL;
-
- *max_state = value - 1;
- return 0;
-}
-
-static int memory_get_cur_bandwidth(struct thermal_cooling_device *cdev,
- unsigned long *value)
-{
- struct acpi_device *device = cdev->devdata;
- acpi_handle handle = device->handle;
- unsigned long long result;
- struct acpi_object_list arg_list;
- union acpi_object arg;
- acpi_status status = AE_OK;
-
- arg_list.count = 1;
- arg_list.pointer = &arg;
- arg.type = ACPI_TYPE_INTEGER;
- arg.integer.value = MEMORY_ARG_CUR_BANDWIDTH;
- status = acpi_evaluate_integer(handle, MEMORY_GET_BANDWIDTH,
- &arg_list, &result);
- if (ACPI_FAILURE(status))
- return -EFAULT;
-
- *value = result;
- return 0;
-}
-
-static int memory_set_cur_bandwidth(struct thermal_cooling_device *cdev,
- unsigned long state)
-{
- struct acpi_device *device = cdev->devdata;
- acpi_handle handle = device->handle;
- struct acpi_object_list arg_list;
- union acpi_object arg;
- acpi_status status;
- unsigned long long temp;
- unsigned long max_state;
-
- if (memory_get_max_bandwidth(cdev, &max_state))
- return -EFAULT;
-
- if (state > max_state)
- return -EINVAL;
-
- arg_list.count = 1;
- arg_list.pointer = &arg;
- arg.type = ACPI_TYPE_INTEGER;
- arg.integer.value = state;
-
- status =
- acpi_evaluate_integer(handle, MEMORY_SET_BANDWIDTH, &arg_list,
- &temp);
-
- pr_info("Bandwidth value was %ld: status is %d\n", state, status);
- if (ACPI_FAILURE(status))
- return -EFAULT;
-
- return 0;
-}
-
-static const struct thermal_cooling_device_ops memory_cooling_ops = {
- .get_max_state = memory_get_max_bandwidth,
- .get_cur_state = memory_get_cur_bandwidth,
- .set_cur_state = memory_set_cur_bandwidth,
-};
-
-/*
- * Memory Device Management
- */
-static int intel_menlow_memory_add(struct acpi_device *device)
-{
- int result = -ENODEV;
- struct thermal_cooling_device *cdev;
-
- if (!device)
- return -EINVAL;
-
- if (!acpi_has_method(device->handle, MEMORY_GET_BANDWIDTH))
- goto end;
-
- if (!acpi_has_method(device->handle, MEMORY_SET_BANDWIDTH))
- goto end;
-
- cdev = thermal_cooling_device_register("Memory controller", device,
- &memory_cooling_ops);
- if (IS_ERR(cdev)) {
- result = PTR_ERR(cdev);
- goto end;
- }
-
- device->driver_data = cdev;
- result = sysfs_create_link(&device->dev.kobj,
- &cdev->device.kobj, "thermal_cooling");
- if (result)
- goto unregister;
-
- result = sysfs_create_link(&cdev->device.kobj,
- &device->dev.kobj, "device");
- if (result) {
- sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
- goto unregister;
- }
-
- end:
- return result;
-
- unregister:
- thermal_cooling_device_unregister(cdev);
- return result;
-
-}
-
-static void intel_menlow_memory_remove(struct acpi_device *device)
-{
- struct thermal_cooling_device *cdev;
-
- if (!device)
- return;
-
- cdev = acpi_driver_data(device);
- if (!cdev)
- return;
-
- sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
- sysfs_remove_link(&cdev->device.kobj, "device");
- thermal_cooling_device_unregister(cdev);
-}
-
-static const struct acpi_device_id intel_menlow_memory_ids[] = {
- {"INT0002", 0},
- {"", 0},
-};
-
-static struct acpi_driver intel_menlow_memory_driver = {
- .name = "intel_menlow_thermal_control",
- .ids = intel_menlow_memory_ids,
- .ops = {
- .add = intel_menlow_memory_add,
- .remove = intel_menlow_memory_remove,
- },
-};
-
-/*
- * Sensor control on menlow platform
- */
-
-#define THERMAL_AUX0 0
-#define THERMAL_AUX1 1
-#define GET_AUX0 "GAX0"
-#define GET_AUX1 "GAX1"
-#define SET_AUX0 "SAX0"
-#define SET_AUX1 "SAX1"
-
-struct intel_menlow_attribute {
- struct device_attribute attr;
- struct device *device;
- acpi_handle handle;
- struct list_head node;
-};
-
-static LIST_HEAD(intel_menlow_attr_list);
-static DEFINE_MUTEX(intel_menlow_attr_lock);
-
-/*
- * sensor_get_auxtrip - get the current auxtrip value from sensor
- * @handle: Object handle
- * @index : GET_AUX1/GET_AUX0
- * @value : The address will be fill by the value
- */
-static int sensor_get_auxtrip(acpi_handle handle, int index,
- unsigned long long *value)
-{
- acpi_status status;
-
- if ((index != 0 && index != 1) || !value)
- return -EINVAL;
-
- status = acpi_evaluate_integer(handle, index ? GET_AUX1 : GET_AUX0,
- NULL, value);
- if (ACPI_FAILURE(status))
- return -EIO;
-
- return 0;
-}
-
-/*
- * sensor_set_auxtrip - set the new auxtrip value to sensor
- * @handle: Object handle
- * @index : GET_AUX1/GET_AUX0
- * @value : The value will be set
- */
-static int sensor_set_auxtrip(acpi_handle handle, int index, int value)
-{
- acpi_status status;
- union acpi_object arg = {
- ACPI_TYPE_INTEGER
- };
- struct acpi_object_list args = {
- 1, &arg
- };
- unsigned long long temp;
-
- if (index != 0 && index != 1)
- return -EINVAL;
-
- status = acpi_evaluate_integer(handle, index ? GET_AUX0 : GET_AUX1,
- NULL, &temp);
- if (ACPI_FAILURE(status))
- return -EIO;
- if ((index && value < temp) || (!index && value > temp))
- return -EINVAL;
-
- arg.integer.value = value;
- status = acpi_evaluate_integer(handle, index ? SET_AUX1 : SET_AUX0,
- &args, &temp);
- if (ACPI_FAILURE(status))
- return -EIO;
-
- /* do we need to check the return value of SAX0/SAX1 ? */
-
- return 0;
-}
-
-#define to_intel_menlow_attr(_attr) \
- container_of(_attr, struct intel_menlow_attribute, attr)
-
-static ssize_t aux_show(struct device *dev, struct device_attribute *dev_attr,
- char *buf, int idx)
-{
- struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr);
- unsigned long long value;
- int result;
-
- result = sensor_get_auxtrip(attr->handle, idx, &value);
- if (result)
- return result;
-
- return sprintf(buf, "%lu", deci_kelvin_to_celsius(value));
-}
-
-static ssize_t aux0_show(struct device *dev,
- struct device_attribute *dev_attr, char *buf)
-{
- return aux_show(dev, dev_attr, buf, 0);
-}
-
-static ssize_t aux1_show(struct device *dev,
- struct device_attribute *dev_attr, char *buf)
-{
- return aux_show(dev, dev_attr, buf, 1);
-}
-
-static ssize_t aux_store(struct device *dev, struct device_attribute *dev_attr,
- const char *buf, size_t count, int idx)
-{
- struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr);
- int value;
- int result;
-
- /*Sanity check; should be a positive integer */
- if (!sscanf(buf, "%d", &value))
- return -EINVAL;
-
- if (value < 0)
- return -EINVAL;
-
- result = sensor_set_auxtrip(attr->handle, idx,
- celsius_to_deci_kelvin(value));
- return result ? result : count;
-}
-
-static ssize_t aux0_store(struct device *dev,
- struct device_attribute *dev_attr,
- const char *buf, size_t count)
-{
- return aux_store(dev, dev_attr, buf, count, 0);
-}
-
-static ssize_t aux1_store(struct device *dev,
- struct device_attribute *dev_attr,
- const char *buf, size_t count)
-{
- return aux_store(dev, dev_attr, buf, count, 1);
-}
-
-/* BIOS can enable/disable the thermal user application in dabney platform */
-#define BIOS_ENABLED "\\_TZ.GSTS"
-static ssize_t bios_enabled_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- acpi_status status;
- unsigned long long bios_enabled;
-
- status = acpi_evaluate_integer(NULL, BIOS_ENABLED, NULL, &bios_enabled);
- if (ACPI_FAILURE(status))
- return -ENODEV;
-
- return sprintf(buf, "%s\n", bios_enabled ? "enabled" : "disabled");
-}
-
-static int intel_menlow_add_one_attribute(char *name, umode_t mode, void *show,
- void *store, struct device *dev,
- acpi_handle handle)
-{
- struct intel_menlow_attribute *attr;
- int result;
-
- attr = kzalloc(sizeof(struct intel_menlow_attribute), GFP_KERNEL);
- if (!attr)
- return -ENOMEM;
-
- sysfs_attr_init(&attr->attr.attr); /* That is consistent naming :D */
- attr->attr.attr.name = name;
- attr->attr.attr.mode = mode;
- attr->attr.show = show;
- attr->attr.store = store;
- attr->device = dev;
- attr->handle = handle;
-
- result = device_create_file(dev, &attr->attr);
- if (result) {
- kfree(attr);
- return result;
- }
-
- mutex_lock(&intel_menlow_attr_lock);
- list_add_tail(&attr->node, &intel_menlow_attr_list);
- mutex_unlock(&intel_menlow_attr_lock);
-
- return 0;
-}
-
-static acpi_status intel_menlow_register_sensor(acpi_handle handle, u32 lvl,
- void *context, void **rv)
-{
- acpi_status status;
- acpi_handle dummy;
- struct thermal_zone_device *thermal;
- int result;
-
- result = acpi_bus_get_private_data(handle, (void **)&thermal);
- if (result)
- return 0;
-
- /* _TZ must have the AUX0/1 methods */
- status = acpi_get_handle(handle, GET_AUX0, &dummy);
- if (ACPI_FAILURE(status))
- return (status == AE_NOT_FOUND) ? AE_OK : status;
-
- status = acpi_get_handle(handle, SET_AUX0, &dummy);
- if (ACPI_FAILURE(status))
- return (status == AE_NOT_FOUND) ? AE_OK : status;
-
- result = intel_menlow_add_one_attribute("aux0", 0644,
- aux0_show, aux0_store,
- &thermal->device, handle);
- if (result)
- return AE_ERROR;
-
- status = acpi_get_handle(handle, GET_AUX1, &dummy);
- if (ACPI_FAILURE(status))
- goto aux1_not_found;
-
- status = acpi_get_handle(handle, SET_AUX1, &dummy);
- if (ACPI_FAILURE(status))
- goto aux1_not_found;
-
- result = intel_menlow_add_one_attribute("aux1", 0644,
- aux1_show, aux1_store,
- &thermal->device, handle);
- if (result) {
- intel_menlow_unregister_sensor();
- return AE_ERROR;
- }
-
- /*
- * create the "dabney_enabled" attribute which means the user app
- * should be loaded or not
- */
-
- result = intel_menlow_add_one_attribute("bios_enabled", 0444,
- bios_enabled_show, NULL,
- &thermal->device, handle);
- if (result) {
- intel_menlow_unregister_sensor();
- return AE_ERROR;
- }
-
- return AE_OK;
-
- aux1_not_found:
- if (status == AE_NOT_FOUND)
- return AE_OK;
-
- intel_menlow_unregister_sensor();
- return status;
-}
-
-static void intel_menlow_unregister_sensor(void)
-{
- struct intel_menlow_attribute *pos, *next;
-
- mutex_lock(&intel_menlow_attr_lock);
- list_for_each_entry_safe(pos, next, &intel_menlow_attr_list, node) {
- list_del(&pos->node);
- device_remove_file(pos->device, &pos->attr);
- kfree(pos);
- }
- mutex_unlock(&intel_menlow_attr_lock);
-
- return;
-}
-
-static int __init intel_menlow_module_init(void)
-{
- int result = -ENODEV;
- acpi_status status;
- unsigned long long enable;
-
- if (acpi_disabled)
- return result;
-
- /* Looking for the \_TZ.GSTS method */
- status = acpi_evaluate_integer(NULL, BIOS_ENABLED, NULL, &enable);
- if (ACPI_FAILURE(status) || !enable)
- return -ENODEV;
-
- /* Looking for ACPI device MEM0 with hardware id INT0002 */
- result = acpi_bus_register_driver(&intel_menlow_memory_driver);
- if (result)
- return result;
-
- /* Looking for sensors in each ACPI thermal zone */
- status = acpi_walk_namespace(ACPI_TYPE_THERMAL, ACPI_ROOT_OBJECT,
- ACPI_UINT32_MAX,
- intel_menlow_register_sensor, NULL, NULL, NULL);
- if (ACPI_FAILURE(status)) {
- acpi_bus_unregister_driver(&intel_menlow_memory_driver);
- return -ENODEV;
- }
-
- return 0;
-}
-
-static void __exit intel_menlow_module_exit(void)
-{
- acpi_bus_unregister_driver(&intel_menlow_memory_driver);
- intel_menlow_unregister_sensor();
-}
-
-module_init(intel_menlow_module_init);
-module_exit(intel_menlow_module_exit);
diff --git a/drivers/thermal/intel/intel_pch_thermal.c b/drivers/thermal/intel/intel_pch_thermal.c
index dce50d239357..b3905e34c507 100644
--- a/drivers/thermal/intel/intel_pch_thermal.c
+++ b/drivers/thermal/intel/intel_pch_thermal.c
@@ -127,7 +127,8 @@ static int pch_thermal_get_temp(struct thermal_zone_device *tzd, int *temp)
static void pch_critical(struct thermal_zone_device *tzd)
{
- dev_dbg(&tzd->device, "%s: critical temperature reached\n", tzd->type);
+ dev_dbg(thermal_zone_device(tzd), "%s: critical temperature reached\n",
+ thermal_zone_device_type(tzd));
}
static struct thermal_zone_device_ops tzd_ops = {
diff --git a/drivers/thermal/mediatek/auxadc_thermal.c b/drivers/thermal/mediatek/auxadc_thermal.c
index b6bb9eaafb74..0b5528804bbd 100644
--- a/drivers/thermal/mediatek/auxadc_thermal.c
+++ b/drivers/thermal/mediatek/auxadc_thermal.c
@@ -116,6 +116,10 @@
/* The calibration coefficient of sensor */
#define MT8173_CALIBRATION 165
+/* Valid temperatures range */
+#define MT8173_TEMP_MIN -20000
+#define MT8173_TEMP_MAX 150000
+
/*
* Layout of the fuses providing the calibration data
* These macros could be used for MT8183, MT8173, MT2701, and MT2712.
@@ -689,6 +693,11 @@ static const struct mtk_thermal_data mt7986_thermal_data = {
.version = MTK_THERMAL_V3,
};
+static bool mtk_thermal_temp_is_valid(int temp)
+{
+ return (temp >= MT8173_TEMP_MIN) && (temp <= MT8173_TEMP_MAX);
+}
+
/**
* raw_to_mcelsius_v1 - convert a raw ADC value to mcelsius
* @mt: The thermal controller
@@ -815,6 +824,17 @@ static int mtk_thermal_bank_temperature(struct mtk_thermal_bank *bank)
temp = mt->raw_to_mcelsius(
mt, conf->bank_data[bank->id].sensors[i], raw);
+ /*
+ * Depending on the filt/sen intervals and ADC polling time,
+ * we may need up to 60 milliseconds after initialization: this
+ * will result in the first reading containing an out of range
+ * temperature value.
+ * Validate the reading to both address the aforementioned issue
+ * and to eventually avoid bogus readings during runtime in the
+ * event that the AUXADC gets unstable due to high EMI, etc.
+ */
+ if (!mtk_thermal_temp_is_valid(temp))
+ temp = THERMAL_TEMP_INVALID;
if (temp > max)
max = temp;
@@ -959,14 +979,12 @@ static void mtk_thermal_init_bank(struct mtk_thermal *mt, int num,
static u64 of_get_phys_base(struct device_node *np)
{
- u64 size64;
- const __be32 *regaddr_p;
+ struct resource res;
- regaddr_p = of_get_address(np, 0, &size64, NULL);
- if (!regaddr_p)
+ if (of_address_to_resource(np, 0, &res))
return OF_BAD_ADDR;
- return of_translate_address(np, regaddr_p);
+ return res.start;
}
static int mtk_thermal_extract_efuse_v1(struct mtk_thermal *mt, u32 *buf)
@@ -1186,14 +1204,6 @@ static int mtk_thermal_probe(struct platform_device *pdev)
mt->conf = of_device_get_match_data(&pdev->dev);
- mt->clk_peri_therm = devm_clk_get(&pdev->dev, "therm");
- if (IS_ERR(mt->clk_peri_therm))
- return PTR_ERR(mt->clk_peri_therm);
-
- mt->clk_auxadc = devm_clk_get(&pdev->dev, "auxadc");
- if (IS_ERR(mt->clk_auxadc))
- return PTR_ERR(mt->clk_auxadc);
-
mt->thermal_base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
if (IS_ERR(mt->thermal_base))
return PTR_ERR(mt->thermal_base);
@@ -1212,7 +1222,12 @@ static int mtk_thermal_probe(struct platform_device *pdev)
return -ENODEV;
}
- auxadc_base = of_iomap(auxadc, 0);
+ auxadc_base = devm_of_iomap(&pdev->dev, auxadc, 0, NULL);
+ if (IS_ERR(auxadc_base)) {
+ of_node_put(auxadc);
+ return PTR_ERR(auxadc_base);
+ }
+
auxadc_phys_base = of_get_phys_base(auxadc);
of_node_put(auxadc);
@@ -1228,7 +1243,12 @@ static int mtk_thermal_probe(struct platform_device *pdev)
return -ENODEV;
}
- apmixed_base = of_iomap(apmixedsys, 0);
+ apmixed_base = devm_of_iomap(&pdev->dev, apmixedsys, 0, NULL);
+ if (IS_ERR(apmixed_base)) {
+ of_node_put(apmixedsys);
+ return PTR_ERR(apmixed_base);
+ }
+
apmixed_phys_base = of_get_phys_base(apmixedsys);
of_node_put(apmixedsys);
@@ -1242,16 +1262,18 @@ static int mtk_thermal_probe(struct platform_device *pdev)
if (ret)
return ret;
- ret = clk_prepare_enable(mt->clk_auxadc);
- if (ret) {
+ mt->clk_auxadc = devm_clk_get_enabled(&pdev->dev, "auxadc");
+ if (IS_ERR(mt->clk_auxadc)) {
+ ret = PTR_ERR(mt->clk_auxadc);
dev_err(&pdev->dev, "Can't enable auxadc clk: %d\n", ret);
return ret;
}
- ret = clk_prepare_enable(mt->clk_peri_therm);
- if (ret) {
+ mt->clk_peri_therm = devm_clk_get_enabled(&pdev->dev, "therm");
+ if (IS_ERR(mt->clk_peri_therm)) {
+ ret = PTR_ERR(mt->clk_peri_therm);
dev_err(&pdev->dev, "Can't enable peri clk: %d\n", ret);
- goto err_disable_clk_auxadc;
+ return ret;
}
mtk_thermal_turn_on_buffer(mt, apmixed_base);
@@ -1273,43 +1295,20 @@ static int mtk_thermal_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, mt);
- /* Delay for thermal banks to be ready */
- msleep(30);
-
tzdev = devm_thermal_of_zone_register(&pdev->dev, 0, mt,
&mtk_thermal_ops);
- if (IS_ERR(tzdev)) {
- ret = PTR_ERR(tzdev);
- goto err_disable_clk_peri_therm;
- }
+ if (IS_ERR(tzdev))
+ return PTR_ERR(tzdev);
ret = devm_thermal_add_hwmon_sysfs(&pdev->dev, tzdev);
if (ret)
dev_warn(&pdev->dev, "error in thermal_add_hwmon_sysfs");
return 0;
-
-err_disable_clk_peri_therm:
- clk_disable_unprepare(mt->clk_peri_therm);
-err_disable_clk_auxadc:
- clk_disable_unprepare(mt->clk_auxadc);
-
- return ret;
-}
-
-static int mtk_thermal_remove(struct platform_device *pdev)
-{
- struct mtk_thermal *mt = platform_get_drvdata(pdev);
-
- clk_disable_unprepare(mt->clk_peri_therm);
- clk_disable_unprepare(mt->clk_auxadc);
-
- return 0;
}
static struct platform_driver mtk_thermal_driver = {
.probe = mtk_thermal_probe,
- .remove = mtk_thermal_remove,
.driver = {
.name = "mtk-thermal",
.of_match_table = mtk_thermal_of_match,
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index c5025aca22ee..842f678c1c3e 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -1398,6 +1398,12 @@ int thermal_zone_device_id(struct thermal_zone_device *tzd)
}
EXPORT_SYMBOL_GPL(thermal_zone_device_id);
+struct device *thermal_zone_device(struct thermal_zone_device *tzd)
+{
+ return &tzd->device;
+}
+EXPORT_SYMBOL_GPL(thermal_zone_device);
+
/**
* thermal_zone_device_unregister - removes the registered thermal zone device
* @tz: the thermal zone device to remove
diff --git a/fs/Makefile b/fs/Makefile
index 8d4736fcc766..834f1c3dba46 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -123,7 +123,7 @@ obj-$(CONFIG_9P_FS) += 9p/
obj-$(CONFIG_AFS_FS) += afs/
obj-$(CONFIG_NILFS2_FS) += nilfs2/
obj-$(CONFIG_BEFS_FS) += befs/
-obj-$(CONFIG_HOSTFS) += hostfs/
+obj-y += hostfs/
obj-$(CONFIG_CACHEFILES) += cachefiles/
obj-$(CONFIG_DEBUG_FS) += debugfs/
obj-$(CONFIG_TRACING) += tracefs/
diff --git a/fs/hostfs/Makefile b/fs/hostfs/Makefile
index 587bcd6e50a3..16be592e8085 100644
--- a/fs/hostfs/Makefile
+++ b/fs/hostfs/Makefile
@@ -3,9 +3,11 @@
# Licensed under the GPL
#
-hostfs-objs := hostfs_kern.o hostfs_user.o
+hostfs-objs := hostfs_kern.o
-obj-y :=
+hostfs-builtin-$(CONFIG_HOSTFS) += hostfs_user.o hostfs_user_exp.o
+
+obj-y := $(hostfs-builtin-y) $(hostfs-builtin-m)
obj-$(CONFIG_HOSTFS) += hostfs.o
include $(srctree)/arch/um/scripts/Makefile.rules
diff --git a/fs/hostfs/hostfs_user_exp.c b/fs/hostfs/hostfs_user_exp.c
new file mode 100644
index 000000000000..250c91c55c46
--- /dev/null
+++ b/fs/hostfs/hostfs_user_exp.c
@@ -0,0 +1,28 @@
+#include <linux/module.h>
+#include "hostfs.h"
+
+EXPORT_SYMBOL_GPL(stat_file);
+EXPORT_SYMBOL_GPL(access_file);
+EXPORT_SYMBOL_GPL(open_file);
+EXPORT_SYMBOL_GPL(open_dir);
+EXPORT_SYMBOL_GPL(seek_dir);
+EXPORT_SYMBOL_GPL(read_dir);
+EXPORT_SYMBOL_GPL(read_file);
+EXPORT_SYMBOL_GPL(write_file);
+EXPORT_SYMBOL_GPL(lseek_file);
+EXPORT_SYMBOL_GPL(fsync_file);
+EXPORT_SYMBOL_GPL(replace_file);
+EXPORT_SYMBOL_GPL(close_file);
+EXPORT_SYMBOL_GPL(close_dir);
+EXPORT_SYMBOL_GPL(file_create);
+EXPORT_SYMBOL_GPL(set_attr);
+EXPORT_SYMBOL_GPL(make_symlink);
+EXPORT_SYMBOL_GPL(unlink_file);
+EXPORT_SYMBOL_GPL(do_mkdir);
+EXPORT_SYMBOL_GPL(hostfs_do_rmdir);
+EXPORT_SYMBOL_GPL(do_mknod);
+EXPORT_SYMBOL_GPL(link_file);
+EXPORT_SYMBOL_GPL(hostfs_do_readlink);
+EXPORT_SYMBOL_GPL(rename_file);
+EXPORT_SYMBOL_GPL(rename2_file);
+EXPORT_SYMBOL_GPL(do_statfs);
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
index 81dbb175017e..8038833ff5b0 100644
--- a/fs/proc/proc_sysctl.c
+++ b/fs/proc/proc_sysctl.c
@@ -1575,25 +1575,18 @@ out:
}
/**
- * __register_sysctl_paths - register a sysctl table hierarchy
- * @set: Sysctl tree to register on
- * @path: The path to the directory the sysctl table is in.
+ * register_sysctl_table - register a sysctl table hierarchy
* @table: the top-level table structure
*
* Register a sysctl table hierarchy. @table should be a filled in ctl_table
* array. A completely 0 filled entry terminates the table.
* We are slowly deprecating this call so avoid its use.
- *
- * See __register_sysctl_table for more details.
*/
-struct ctl_table_header *__register_sysctl_paths(
- struct ctl_table_set *set,
- const struct ctl_path *path, struct ctl_table *table)
+struct ctl_table_header *register_sysctl_table(struct ctl_table *table)
{
struct ctl_table *ctl_table_arg = table;
int nr_subheaders = count_subheaders(table);
struct ctl_table_header *header = NULL, **subheaders, **subheader;
- const struct ctl_path *component;
char *new_path, *pos;
pos = new_path = kmalloc(PATH_MAX, GFP_KERNEL);
@@ -1601,11 +1594,6 @@ struct ctl_table_header *__register_sysctl_paths(
return NULL;
pos[0] = '\0';
- for (component = path; component->procname; component++) {
- pos = append_path(new_path, pos, component->procname);
- if (!pos)
- goto out;
- }
while (table->procname && table->child && !table[1].procname) {
pos = append_path(new_path, pos, table->procname);
if (!pos)
@@ -1613,7 +1601,7 @@ struct ctl_table_header *__register_sysctl_paths(
table = table->child;
}
if (nr_subheaders == 1) {
- header = __register_sysctl_table(set, new_path, table);
+ header = __register_sysctl_table(&sysctl_table_root.default_set, new_path, table);
if (header)
header->ctl_table_arg = ctl_table_arg;
} else {
@@ -1627,7 +1615,7 @@ struct ctl_table_header *__register_sysctl_paths(
header->ctl_table_arg = ctl_table_arg;
if (register_leaf_sysctl_tables(new_path, pos, &subheader,
- set, table))
+ &sysctl_table_root.default_set, table))
goto err_register_leaves;
}
@@ -1646,41 +1634,6 @@ err_register_leaves:
header = NULL;
goto out;
}
-
-/**
- * register_sysctl_paths - register a sysctl table hierarchy
- * @path: The path to the directory the sysctl table is in.
- * @table: the top-level table structure
- *
- * Register a sysctl table hierarchy. @table should be a filled in ctl_table
- * array. A completely 0 filled entry terminates the table.
- * We are slowly deprecating this caller so avoid future uses of it.
- *
- * See __register_sysctl_paths for more details.
- */
-struct ctl_table_header *register_sysctl_paths(const struct ctl_path *path,
- struct ctl_table *table)
-{
- return __register_sysctl_paths(&sysctl_table_root.default_set,
- path, table);
-}
-EXPORT_SYMBOL(register_sysctl_paths);
-
-/**
- * register_sysctl_table - register a sysctl table hierarchy
- * @table: the top-level table structure
- *
- * Register a sysctl table hierarchy. @table should be a filled in ctl_table
- * array. A completely 0 filled entry terminates the table.
- *
- * See register_sysctl_paths for more details.
- */
-struct ctl_table_header *register_sysctl_table(struct ctl_table *table)
-{
- static const struct ctl_path null_path[] = { {} };
-
- return register_sysctl_paths(null_path, table);
-}
EXPORT_SYMBOL(register_sysctl_table);
int __register_sysctl_base(struct ctl_table *base_table)
diff --git a/fs/ubifs/compress.c b/fs/ubifs/compress.c
index 3a92e6af69b2..75461777c466 100644
--- a/fs/ubifs/compress.c
+++ b/fs/ubifs/compress.c
@@ -217,7 +217,6 @@ static void compr_exit(struct ubifs_compressor *compr)
{
if (compr->capi_name)
crypto_free_comp(compr->cc);
- return;
}
/**
diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
index 1505539f6fe9..ef0499edc248 100644
--- a/fs/ubifs/dir.c
+++ b/fs/ubifs/dir.c
@@ -358,7 +358,6 @@ static struct inode *create_whiteout(struct inode *dir, struct dentry *dentry)
umode_t mode = S_IFCHR | WHITEOUT_MODE;
struct inode *inode;
struct ubifs_info *c = dir->i_sb->s_fs_info;
- struct fscrypt_name nm;
/*
* Create an inode('nlink = 1') for whiteout without updating journal,
@@ -369,10 +368,6 @@ static struct inode *create_whiteout(struct inode *dir, struct dentry *dentry)
dbg_gen("dent '%pd', mode %#hx in dir ino %lu",
dentry, mode, dir->i_ino);
- err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &nm);
- if (err)
- return ERR_PTR(err);
-
inode = ubifs_new_inode(c, dir, mode, false);
if (IS_ERR(inode)) {
err = PTR_ERR(inode);
@@ -395,7 +390,6 @@ out_inode:
make_bad_inode(inode);
iput(inode);
out_free:
- fscrypt_free_filename(&nm);
ubifs_err(c, "cannot create whiteout file, error %d", err);
return ERR_PTR(err);
}
@@ -492,6 +486,7 @@ static int ubifs_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
unlock_2_inodes(dir, inode);
ubifs_release_budget(c, &req);
+ fscrypt_free_filename(&nm);
return finish_open_simple(file, 0);
diff --git a/fs/ubifs/tnc.c b/fs/ubifs/tnc.c
index 2469f72eeaab..6b7d95b65f4b 100644
--- a/fs/ubifs/tnc.c
+++ b/fs/ubifs/tnc.c
@@ -44,6 +44,33 @@ enum {
NOT_ON_MEDIA = 3,
};
+static void do_insert_old_idx(struct ubifs_info *c,
+ struct ubifs_old_idx *old_idx)
+{
+ struct ubifs_old_idx *o;
+ struct rb_node **p, *parent = NULL;
+
+ p = &c->old_idx.rb_node;
+ while (*p) {
+ parent = *p;
+ o = rb_entry(parent, struct ubifs_old_idx, rb);
+ if (old_idx->lnum < o->lnum)
+ p = &(*p)->rb_left;
+ else if (old_idx->lnum > o->lnum)
+ p = &(*p)->rb_right;
+ else if (old_idx->offs < o->offs)
+ p = &(*p)->rb_left;
+ else if (old_idx->offs > o->offs)
+ p = &(*p)->rb_right;
+ else {
+ ubifs_err(c, "old idx added twice!");
+ kfree(old_idx);
+ }
+ }
+ rb_link_node(&old_idx->rb, parent, p);
+ rb_insert_color(&old_idx->rb, &c->old_idx);
+}
+
/**
* insert_old_idx - record an index node obsoleted since the last commit start.
* @c: UBIFS file-system description object
@@ -69,35 +96,15 @@ enum {
*/
static int insert_old_idx(struct ubifs_info *c, int lnum, int offs)
{
- struct ubifs_old_idx *old_idx, *o;
- struct rb_node **p, *parent = NULL;
+ struct ubifs_old_idx *old_idx;
old_idx = kmalloc(sizeof(struct ubifs_old_idx), GFP_NOFS);
if (unlikely(!old_idx))
return -ENOMEM;
old_idx->lnum = lnum;
old_idx->offs = offs;
+ do_insert_old_idx(c, old_idx);
- p = &c->old_idx.rb_node;
- while (*p) {
- parent = *p;
- o = rb_entry(parent, struct ubifs_old_idx, rb);
- if (lnum < o->lnum)
- p = &(*p)->rb_left;
- else if (lnum > o->lnum)
- p = &(*p)->rb_right;
- else if (offs < o->offs)
- p = &(*p)->rb_left;
- else if (offs > o->offs)
- p = &(*p)->rb_right;
- else {
- ubifs_err(c, "old idx added twice!");
- kfree(old_idx);
- return 0;
- }
- }
- rb_link_node(&old_idx->rb, parent, p);
- rb_insert_color(&old_idx->rb, &c->old_idx);
return 0;
}
@@ -199,23 +206,6 @@ static struct ubifs_znode *copy_znode(struct ubifs_info *c,
__set_bit(DIRTY_ZNODE, &zn->flags);
__clear_bit(COW_ZNODE, &zn->flags);
- ubifs_assert(c, !ubifs_zn_obsolete(znode));
- __set_bit(OBSOLETE_ZNODE, &znode->flags);
-
- if (znode->level != 0) {
- int i;
- const int n = zn->child_cnt;
-
- /* The children now have new parent */
- for (i = 0; i < n; i++) {
- struct ubifs_zbranch *zbr = &zn->zbranch[i];
-
- if (zbr->znode)
- zbr->znode->parent = zn;
- }
- }
-
- atomic_long_inc(&c->dirty_zn_cnt);
return zn;
}
@@ -234,6 +224,42 @@ static int add_idx_dirt(struct ubifs_info *c, int lnum, int dirt)
}
/**
+ * replace_znode - replace old znode with new znode.
+ * @c: UBIFS file-system description object
+ * @new_zn: new znode
+ * @old_zn: old znode
+ * @zbr: the branch of parent znode
+ *
+ * Replace old znode with new znode in TNC.
+ */
+static void replace_znode(struct ubifs_info *c, struct ubifs_znode *new_zn,
+ struct ubifs_znode *old_zn, struct ubifs_zbranch *zbr)
+{
+ ubifs_assert(c, !ubifs_zn_obsolete(old_zn));
+ __set_bit(OBSOLETE_ZNODE, &old_zn->flags);
+
+ if (old_zn->level != 0) {
+ int i;
+ const int n = new_zn->child_cnt;
+
+ /* The children now have new parent */
+ for (i = 0; i < n; i++) {
+ struct ubifs_zbranch *child = &new_zn->zbranch[i];
+
+ if (child->znode)
+ child->znode->parent = new_zn;
+ }
+ }
+
+ zbr->znode = new_zn;
+ zbr->lnum = 0;
+ zbr->offs = 0;
+ zbr->len = 0;
+
+ atomic_long_inc(&c->dirty_zn_cnt);
+}
+
+/**
* dirty_cow_znode - ensure a znode is not being committed.
* @c: UBIFS file-system description object
* @zbr: branch of znode to check
@@ -265,28 +291,32 @@ static struct ubifs_znode *dirty_cow_znode(struct ubifs_info *c,
return zn;
if (zbr->len) {
- err = insert_old_idx(c, zbr->lnum, zbr->offs);
- if (unlikely(err))
- /*
- * Obsolete znodes will be freed by tnc_destroy_cnext()
- * or free_obsolete_znodes(), copied up znodes should
- * be added back to tnc and freed by
- * ubifs_destroy_tnc_subtree().
- */
+ struct ubifs_old_idx *old_idx;
+
+ old_idx = kmalloc(sizeof(struct ubifs_old_idx), GFP_NOFS);
+ if (unlikely(!old_idx)) {
+ err = -ENOMEM;
goto out;
+ }
+ old_idx->lnum = zbr->lnum;
+ old_idx->offs = zbr->offs;
+
err = add_idx_dirt(c, zbr->lnum, zbr->len);
- } else
- err = 0;
+ if (err) {
+ kfree(old_idx);
+ goto out;
+ }
-out:
- zbr->znode = zn;
- zbr->lnum = 0;
- zbr->offs = 0;
- zbr->len = 0;
+ do_insert_old_idx(c, old_idx);
+ }
+
+ replace_znode(c, zn, znode, zbr);
- if (unlikely(err))
- return ERR_PTR(err);
return zn;
+
+out:
+ kfree(zn);
+ return ERR_PTR(err);
}
/**
diff --git a/include/linux/dma/ti-cppi5.h b/include/linux/dma/ti-cppi5.h
index efa2f0309f00..c53c0f6e3b1a 100644
--- a/include/linux/dma/ti-cppi5.h
+++ b/include/linux/dma/ti-cppi5.h
@@ -616,6 +616,7 @@ static inline void *cppi5_hdesc_get_swdata(struct cppi5_host_desc_t *desc)
#define CPPI5_TR_CSF_SUPR_EVT BIT(2)
#define CPPI5_TR_CSF_EOL_ADV_SHIFT (4U)
#define CPPI5_TR_CSF_EOL_ADV_MASK GENMASK(6, 4)
+#define CPPI5_TR_CSF_EOL_ICNT0 BIT(4)
#define CPPI5_TR_CSF_EOP BIT(7)
/**
diff --git a/include/linux/mfd/stm32-timers.h b/include/linux/mfd/stm32-timers.h
index 5f5c43fd69dd..1b94325febb3 100644
--- a/include/linux/mfd/stm32-timers.h
+++ b/include/linux/mfd/stm32-timers.h
@@ -31,6 +31,7 @@
#define TIM_BDTR 0x44 /* Break and Dead-Time Reg */
#define TIM_DCR 0x48 /* DMA control register */
#define TIM_DMAR 0x4C /* DMA register for transfer */
+#define TIM_TISEL 0x68 /* Input Selection */
#define TIM_CR1_CEN BIT(0) /* Counter Enable */
#define TIM_CR1_DIR BIT(4) /* Counter Direction */
diff --git a/include/linux/pwm.h b/include/linux/pwm.h
index 7b7b93b6fb81..04ae1d9073a7 100644
--- a/include/linux/pwm.h
+++ b/include/linux/pwm.h
@@ -309,8 +309,6 @@ struct pwm_chip {
#if IS_ENABLED(CONFIG_PWM)
/* PWM user APIs */
-struct pwm_device *pwm_request(int pwm_id, const char *label);
-void pwm_free(struct pwm_device *pwm);
int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state);
int pwm_adjust_config(struct pwm_device *pwm);
@@ -410,17 +408,6 @@ struct pwm_device *devm_fwnode_pwm_get(struct device *dev,
struct fwnode_handle *fwnode,
const char *con_id);
#else
-static inline struct pwm_device *pwm_request(int pwm_id, const char *label)
-{
- might_sleep();
- return ERR_PTR(-ENODEV);
-}
-
-static inline void pwm_free(struct pwm_device *pwm)
-{
- might_sleep();
-}
-
static inline int pwm_apply_state(struct pwm_device *pwm,
const struct pwm_state *state)
{
diff --git a/include/linux/soundwire/sdw_amd.h b/include/linux/soundwire/sdw_amd.h
new file mode 100644
index 000000000000..ceecad74aef9
--- /dev/null
+++ b/include/linux/soundwire/sdw_amd.h
@@ -0,0 +1,109 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.
+ */
+
+#ifndef __SDW_AMD_H
+#define __SDW_AMD_H
+
+#include <linux/soundwire/sdw.h>
+
+/* AMD pm_runtime quirk definitions */
+
+/*
+ * Force the clock to stop(ClockStopMode0) when suspend callback
+ * is invoked.
+ */
+#define AMD_SDW_CLK_STOP_MODE 1
+
+/*
+ * Stop the bus when runtime suspend/system level suspend callback
+ * is invoked. If set, a complete bus reset and re-enumeration will
+ * be performed when the bus restarts. In-band wake interrupts are
+ * not supported in this mode.
+ */
+#define AMD_SDW_POWER_OFF_MODE 2
+#define ACP_SDW0 0
+#define ACP_SDW1 1
+
+struct acp_sdw_pdata {
+ u16 instance;
+ /* mutex to protect acp common register access */
+ struct mutex *acp_sdw_lock;
+};
+
+struct sdw_manager_reg_mask {
+ u32 sw_pad_enable_mask;
+ u32 sw_pad_pulldown_mask;
+ u32 acp_sdw_intr_mask;
+};
+
+/**
+ * struct sdw_amd_dai_runtime: AMD sdw dai runtime data
+ *
+ * @name: SoundWire stream name
+ * @stream: stream runtime
+ * @bus: Bus handle
+ * @stream_type: Stream type
+ */
+struct sdw_amd_dai_runtime {
+ char *name;
+ struct sdw_stream_runtime *stream;
+ struct sdw_bus *bus;
+ enum sdw_stream_type stream_type;
+};
+
+/**
+ * struct amd_sdw_manager - amd manager driver context
+ * @bus: bus handle
+ * @dev: linux device
+ * @mmio: SoundWire registers mmio base
+ * @acp_mmio: acp registers mmio base
+ * @reg_mask: register mask structure per manager instance
+ * @amd_sdw_irq_thread: SoundWire manager irq workqueue
+ * @amd_sdw_work: peripheral status work queue
+ * @probe_work: SoundWire manager probe workqueue
+ * @acp_sdw_lock: mutex to protect acp share register access
+ * @status: peripheral devices status array
+ * @num_din_ports: number of input ports
+ * @num_dout_ports: number of output ports
+ * @cols_index: Column index in frame shape
+ * @rows_index: Rows index in frame shape
+ * @instance: SoundWire manager instance
+ * @quirks: SoundWire manager quirks
+ * @wake_en_mask: wake enable mask per SoundWire manager
+ * @clk_stopped: flag set to true when clock is stopped
+ * @power_mode_mask: flag interprets amd SoundWire manager power mode
+ * @dai_runtime_array: dai runtime array
+ */
+struct amd_sdw_manager {
+ struct sdw_bus bus;
+ struct device *dev;
+
+ void __iomem *mmio;
+ void __iomem *acp_mmio;
+
+ struct sdw_manager_reg_mask *reg_mask;
+ struct work_struct amd_sdw_irq_thread;
+ struct work_struct amd_sdw_work;
+ struct work_struct probe_work;
+ /* mutex to protect acp common register access */
+ struct mutex *acp_sdw_lock;
+
+ enum sdw_slave_status status[SDW_MAX_DEVICES + 1];
+
+ int num_din_ports;
+ int num_dout_ports;
+
+ int cols_index;
+ int rows_index;
+
+ u32 instance;
+ u32 quirks;
+ u32 wake_en_mask;
+ u32 power_mode_mask;
+ bool clk_stopped;
+
+ struct sdw_amd_dai_runtime **dai_runtime_array;
+};
+#endif
diff --git a/include/linux/soundwire/sdw_intel.h b/include/linux/soundwire/sdw_intel.h
index 91f0dc564fe5..207701aeeb47 100644
--- a/include/linux/soundwire/sdw_intel.h
+++ b/include/linux/soundwire/sdw_intel.h
@@ -309,6 +309,12 @@ struct sdw_intel;
* @shim_wake: enable/disable in-band wake management
* @pre_bank_switch: helper for bus management
* @post_bank_switch: helper for bus management
+ * @sync_arm: helper for multi-link synchronization
+ * @sync_go_unlocked: helper for multi-link synchronization -
+ * shim_lock is assumed to be locked at higher level
+ * @sync_go: helper for multi-link synchronization
+ * @sync_check_cmdsync_unlocked: helper for multi-link synchronization
+ * and bank switch - shim_lock is assumed to be locked at higher level
*/
struct sdw_intel_hw_ops {
void (*debugfs_init)(struct sdw_intel *sdw);
@@ -330,6 +336,11 @@ struct sdw_intel_hw_ops {
int (*pre_bank_switch)(struct sdw_intel *sdw);
int (*post_bank_switch)(struct sdw_intel *sdw);
+
+ void (*sync_arm)(struct sdw_intel *sdw);
+ int (*sync_go_unlocked)(struct sdw_intel *sdw);
+ int (*sync_go)(struct sdw_intel *sdw);
+ bool (*sync_check_cmdsync_unlocked)(struct sdw_intel *sdw);
};
extern const struct sdw_intel_hw_ops sdw_intel_cnl_hw_ops;
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index 780690dc08cd..3d08277959af 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -221,14 +221,8 @@ extern void retire_sysctl_set(struct ctl_table_set *set);
struct ctl_table_header *__register_sysctl_table(
struct ctl_table_set *set,
const char *path, struct ctl_table *table);
-struct ctl_table_header *__register_sysctl_paths(
- struct ctl_table_set *set,
- const struct ctl_path *path, struct ctl_table *table);
struct ctl_table_header *register_sysctl(const char *path, struct ctl_table *table);
struct ctl_table_header *register_sysctl_table(struct ctl_table * table);
-struct ctl_table_header *register_sysctl_paths(const struct ctl_path *path,
- struct ctl_table *table);
-
void unregister_sysctl_table(struct ctl_table_header * table);
extern int sysctl_init_bases(void);
@@ -277,12 +271,6 @@ static inline struct ctl_table_header *register_sysctl_mount_point(const char *p
return NULL;
}
-static inline struct ctl_table_header *register_sysctl_paths(
- const struct ctl_path *path, struct ctl_table *table)
-{
- return NULL;
-}
-
static inline struct ctl_table_header *register_sysctl(const char *path, struct ctl_table *table)
{
return NULL;
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 82ddb32f9876..87837094d549 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -313,6 +313,7 @@ thermal_zone_device_register_with_trips(const char *, struct thermal_trip *, int
void *thermal_zone_device_priv(struct thermal_zone_device *tzd);
const char *thermal_zone_device_type(struct thermal_zone_device *tzd);
int thermal_zone_device_id(struct thermal_zone_device *tzd);
+struct device *thermal_zone_device(struct thermal_zone_device *tzd);
int thermal_zone_bind_cooling_device(struct thermal_zone_device *, int,
struct thermal_cooling_device *,
diff --git a/include/uapi/linux/idxd.h b/include/uapi/linux/idxd.h
index 1d553bedbdb5..606b52e88ce3 100644
--- a/include/uapi/linux/idxd.h
+++ b/include/uapi/linux/idxd.h
@@ -30,6 +30,7 @@ enum idxd_scmd_stat {
IDXD_SCMD_WQ_NO_PRIV = 0x800f0000,
IDXD_SCMD_WQ_IRQ_ERR = 0x80100000,
IDXD_SCMD_WQ_USER_NO_IOMMU = 0x80110000,
+ IDXD_SCMD_DEV_EVL_ERR = 0x80120000,
};
#define IDXD_SCMD_SOFTERR_MASK 0x80000000
@@ -72,12 +73,14 @@ enum dsa_opcode {
DSA_OPCODE_CR_DELTA,
DSA_OPCODE_AP_DELTA,
DSA_OPCODE_DUALCAST,
+ DSA_OPCODE_TRANSL_FETCH,
DSA_OPCODE_CRCGEN = 0x10,
DSA_OPCODE_COPY_CRC,
DSA_OPCODE_DIF_CHECK,
DSA_OPCODE_DIF_INS,
DSA_OPCODE_DIF_STRP,
DSA_OPCODE_DIF_UPDT,
+ DSA_OPCODE_DIX_GEN = 0x17,
DSA_OPCODE_CFLUSH = 0x20,
};
@@ -132,6 +135,8 @@ enum dsa_completion_status {
DSA_COMP_HW_ERR1,
DSA_COMP_HW_ERR_DRB,
DSA_COMP_TRANSLATION_FAIL,
+ DSA_COMP_DRAIN_EVL = 0x26,
+ DSA_COMP_BATCH_EVL_ERR,
};
enum iax_completion_status {
@@ -167,6 +172,7 @@ enum iax_completion_status {
#define DSA_COMP_STATUS_MASK 0x7f
#define DSA_COMP_STATUS_WRITE 0x80
+#define DSA_COMP_STATUS(status) ((status) & DSA_COMP_STATUS_MASK)
struct dsa_hw_desc {
uint32_t pasid:20;
@@ -180,6 +186,8 @@ struct dsa_hw_desc {
uint64_t rdback_addr;
uint64_t pattern;
uint64_t desc_list_addr;
+ uint64_t pattern_lower;
+ uint64_t transl_fetch_addr;
};
union {
uint64_t dst_addr;
@@ -190,6 +198,7 @@ struct dsa_hw_desc {
union {
uint32_t xfer_size;
uint32_t desc_count;
+ uint32_t region_size;
};
uint16_t int_handle;
uint16_t rsvd1;
@@ -244,6 +253,26 @@ struct dsa_hw_desc {
uint16_t dest_app_tag_seed;
};
+ /* Fill */
+ uint64_t pattern_upper;
+
+ /* Translation fetch */
+ struct {
+ uint64_t transl_fetch_res;
+ uint32_t region_stride;
+ };
+
+ /* DIX generate */
+ struct {
+ uint8_t dix_gen_res;
+ uint8_t dest_dif_flags;
+ uint8_t dif_flags;
+ uint8_t dix_gen_res2[13];
+ uint32_t ref_tag_seed;
+ uint16_t app_tag_mask;
+ uint16_t app_tag_seed;
+ };
+
uint8_t op_specific[24];
};
} __attribute__((packed));
@@ -284,8 +313,12 @@ struct dsa_completion_record {
uint8_t result;
uint8_t dif_status;
};
- uint16_t rsvd;
- uint32_t bytes_completed;
+ uint8_t fault_info;
+ uint8_t rsvd;
+ union {
+ uint32_t bytes_completed;
+ uint32_t descs_completed;
+ };
uint64_t fault_addr;
union {
/* common record */
@@ -322,6 +355,14 @@ struct dsa_completion_record {
uint16_t dif_upd_dest_app_tag;
};
+ /* DIX generate */
+ struct {
+ uint64_t dix_gen_res;
+ uint32_t dix_ref_tag;
+ uint16_t dix_app_tag_mask;
+ uint16_t dix_app_tag;
+ };
+
uint8_t op_specific[16];
};
} __attribute__((packed));
@@ -333,7 +374,8 @@ struct dsa_raw_completion_record {
struct iax_completion_record {
volatile uint8_t status;
uint8_t error_code;
- uint16_t rsvd;
+ uint8_t fault_info;
+ uint8_t rsvd;
uint32_t bytes_completed;
uint64_t fault_addr;
uint32_t invalid_flags;
diff --git a/kernel/pid_namespace.c b/kernel/pid_namespace.c
index 46e0d5a3f91f..b43eee07b00c 100644
--- a/kernel/pid_namespace.c
+++ b/kernel/pid_namespace.c
@@ -314,7 +314,6 @@ static struct ctl_table pid_ns_ctl_table[] = {
},
{ }
};
-static struct ctl_path kern_path[] = { { .procname = "kernel", }, { } };
#endif /* CONFIG_CHECKPOINT_RESTORE */
int reboot_pid_ns(struct pid_namespace *pid_ns, int cmd)
@@ -473,7 +472,7 @@ static __init int pid_namespaces_init(void)
pid_ns_cachep = KMEM_CACHE(pid_namespace, SLAB_PANIC | SLAB_ACCOUNT);
#ifdef CONFIG_CHECKPOINT_RESTORE
- register_sysctl_paths(kern_path, pid_ns_ctl_table);
+ register_sysctl_init("kernel", pid_ns_ctl_table);
#endif
register_pid_ns_sysctl_table_vm();
diff --git a/kernel/pid_sysctl.h b/kernel/pid_sysctl.h
index e22d072e1e24..d67a4d45bb42 100644
--- a/kernel/pid_sysctl.h
+++ b/kernel/pid_sysctl.h
@@ -46,10 +46,9 @@ static struct ctl_table pid_ns_ctl_table_vm[] = {
},
{ }
};
-static struct ctl_path vm_path[] = { { .procname = "vm", }, { } };
static inline void register_pid_ns_sysctl_table_vm(void)
{
- register_sysctl_paths(vm_path, pid_ns_ctl_table_vm);
+ register_sysctl("vm", pid_ns_ctl_table_vm);
}
#else
static inline void initialize_memfd_noexec_scope(struct pid_namespace *ns) {}
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
index 793c55a2becb..30d1274f03f6 100644
--- a/kernel/power/hibernate.c
+++ b/kernel/power/hibernate.c
@@ -64,6 +64,7 @@ enum {
static int hibernation_mode = HIBERNATION_SHUTDOWN;
bool freezer_test_done;
+bool snapshot_test;
static const struct platform_hibernation_ops *hibernation_ops;
@@ -687,18 +688,22 @@ static int load_image_and_restore(void)
{
int error;
unsigned int flags;
+ fmode_t mode = FMODE_READ;
+
+ if (snapshot_test)
+ mode |= FMODE_EXCL;
pm_pr_dbg("Loading hibernation image.\n");
lock_device_hotplug();
error = create_basic_memory_bitmaps();
if (error) {
- swsusp_close(FMODE_READ | FMODE_EXCL);
+ swsusp_close(mode);
goto Unlock;
}
error = swsusp_read(&flags);
- swsusp_close(FMODE_READ | FMODE_EXCL);
+ swsusp_close(mode);
if (!error)
error = hibernation_restore(flags & SF_PLATFORM_MODE);
@@ -716,7 +721,6 @@ static int load_image_and_restore(void)
*/
int hibernate(void)
{
- bool snapshot_test = false;
unsigned int sleep_flags;
int error;
@@ -744,6 +748,9 @@ int hibernate(void)
if (error)
goto Exit;
+ /* protected by system_transition_mutex */
+ snapshot_test = false;
+
lock_device_hotplug();
/* Allocate memory management structures */
error = create_basic_memory_bitmaps();
@@ -940,6 +947,8 @@ static int software_resume(void)
*/
mutex_lock_nested(&system_transition_mutex, SINGLE_DEPTH_NESTING);
+ snapshot_test = false;
+
if (swsusp_resume_device)
goto Check_image;
diff --git a/kernel/power/power.h b/kernel/power/power.h
index b4f433943209..b83c8d5e188d 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -59,6 +59,7 @@ asmlinkage int swsusp_save(void);
/* kernel/power/hibernate.c */
extern bool freezer_test_done;
+extern bool snapshot_test;
extern int hibernation_snapshot(int platform_mode);
extern int hibernation_restore(int platform_mode);
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index 36a1df48280c..92e41ed292ad 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -1518,9 +1518,13 @@ int swsusp_check(void)
{
int error;
void *holder;
+ fmode_t mode = FMODE_READ;
+
+ if (snapshot_test)
+ mode |= FMODE_EXCL;
hib_resume_bdev = blkdev_get_by_dev(swsusp_resume_device,
- FMODE_READ | FMODE_EXCL, &holder);
+ mode, &holder);
if (!IS_ERR(hib_resume_bdev)) {
set_blocksize(hib_resume_bdev, PAGE_SIZE);
clear_page(swsusp_header);
@@ -1547,7 +1551,7 @@ int swsusp_check(void)
put:
if (error)
- blkdev_put(hib_resume_bdev, FMODE_READ | FMODE_EXCL);
+ blkdev_put(hib_resume_bdev, mode);
else
pr_debug("Image signature found, resuming\n");
} else {
diff --git a/scripts/check-sysctl-docs b/scripts/check-sysctl-docs
index 8bcb9e26c7bc..edc9a629d79e 100755
--- a/scripts/check-sysctl-docs
+++ b/scripts/check-sysctl-docs
@@ -156,22 +156,6 @@ curtable && /\.procname[\t ]*=[\t ]*".+"/ {
}
}
-/register_sysctl_paths\(.*\)/ {
- match($0, /register_sysctl_paths\(([^)]+), ([^)]+)\)/, tables)
- if (debug) print "Attaching table " tables[2] " to path " tables[1]
- if (paths[tables[1]] == table) {
- for (entry in entries[tables[2]]) {
- printentry(entry)
- }
- }
- split(paths[tables[1]], components, "/")
- if (length(components) > 1 && components[1] == table) {
- # Count the first subdirectory as seen
- seen[components[2]]++
- }
-}
-
-
END {
for (entry in documented) {
if (!seen[entry]) {